Mercurial > hg > ltpda
diff m-toolbox/classes/@ao/spsd.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m-toolbox/classes/@ao/spsd.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,221 @@ +% SPSD implements the smoothed (binned) PSD algorithm for analysis objects. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DESCRIPTION: SPSD implements the smoothed PSD algorithm for analysis objects. +% +% CALL: bs = spsd(a1,a2,a3,...,pl) +% bs = spsd(as,pl) +% bs = as.spsd(pl) +% +% INPUTS: aN - input analysis objects +% as - input analysis objects array +% pl - input parameter list +% +% OUTPUTS: bs - array of analysis objects, one for each input +% +% <a href="matlab:utils.helper.displayMethodInfo('ao', 'spsd')">Parameters Description</a> +% +% VERSION: $Id: spsd.m,v 1.21 2011/07/11 10:43:35 adrien Exp $ +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function varargout = spsd(varargin) + + import utils.const.* + + % Check if this is a call for parameters + if utils.helper.isinfocall(varargin{:}) + varargout{1} = getInfo(varargin{3}); + return + end + + utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename); + + % Collect input variable names + in_names = cell(size(varargin)); + for ii = 1:nargin,in_names{ii} = inputname(ii);end + + % Collect all AOs and plists + [as, ao_invars, rest] = utils.helper.collect_objects(varargin(:), 'ao', in_names); + [pl, pl_invars, rest] = utils.helper.collect_objects(rest(:), 'plist', in_names); + + % Decide on a deep copy or a modify + bs = copy(as, nargout); + + % Combine plists + pl = combine(pl, plist(rest(:)), getDefaultPlist); + + inhists = []; + + %% Go through each input AO + for jj = 1 : numel(bs) + % gather the input history objects + inhists = [inhists bs(jj).hist]; %#ok<AGROW> + + % check this is a time-series object + if ~isa(bs(jj).data, 'tsdata') + warning('!!! spsd requires tsdata (time-series) inputs. Skipping AO %s', ao_invars{jj}); %#ok<WNTAG> + else + + % Check the time range. + time_range = find(pl, 'times'); + if ~isempty(time_range) + bs(jj) = split(bs(jj), plist('method', 'times', 'times', time_range)); + end + % Check the length of the object + if bs(jj).len <= 0 + error('### The object is empty! Please revise your settings ...'); + end + + % pl = utils.helper.process_spectral_options(pl, 'log'); + pl = pl.combine(getDefaultPlist()); + + % getting data + y = bs(jj).y; + + % Window function + Win = find(pl, 'Win'); + nfft = length(y); + Win = ao( combine(plist('win', Win , 'length', nfft), pl) ); + + % detrend + order = find(pl,'order'); + if ~(order < 0) + y = ltpda_polyreg(y, order).'; + else + y = reshape(y, 1, nfft); + end + + % computing PSD + window = Win.data.y; + window = window/norm(window)*sqrt(nfft); + yASD = real(fft(y.*window, nfft)).^2 + imag(fft(y.*window, nfft)).^2; + pow = [yASD(1) yASD(2:floor(nfft/2))*2]; + pow = pow / ( bs(jj).data.fs * nfft); + Freqs = linspace(0, bs(jj).data.fs/2, nfft/2); + + % smoothing PSD + if ~isempty(find(pl,'frequencies')) + error('the option "frequencies" is deprecated, frequencies are "removed" by default') + end + [Freqs, pow, nFreqs, nDofs] = ltpda_spsd(Freqs, pow, find(pl,'linCoef'), find(pl,'logCoef') ); + % create new output fsdata + scale = find(pl, 'Scale'); + switch lower(scale) + case 'asd' + fsd = fsdata(Freqs, sqrt(pow), bs(jj).data.fs); + fsd.setYunits(bs(jj).data.yunits / unit('Hz^0.5')); + % stdDev = 0.5 * sqrt( pow ./ nDofs ); % linear approximation of the sqrt of a distribution + % approximation knowing the STD of the PSD + % STD assuming amplitude samples are independent, Chi^1_2 distibuted + % (with both variables of powe expectancy pow/2), and of different + % magnitude + stdDev = 2 * sqrt(pow./nDofs) .* ( nDofs - 2*exp( 2*(gammaln((nDofs+1)/2)-gammaln(nDofs/2)) ) ); % std of the chi_2N^1 + case 'psd' + fsd = fsdata(Freqs, pow, bs(jj).data.fs); + fsd.setYunits(bs(jj).data.yunits.^2/unit('Hz')); + % STD assuming power samples are independent, Chi^2_2 distibuted + % (with both variables of expectancy pow/2), and of different + % magnitude + stdDev = sqrt(2) * (pow./nDofs) .* sqrt(2*nDofs); % std of the chi_2N^2 + otherwise + error(['### Unknown scaling:' scale]); + end + + fsd.setXunits('Hz'); + fsd.setDx(nFreqs*Freqs(2)/2); + fsd.setEnbw(1);% WARNING HERE!!! + fsd.setT0(bs(jj).data.t0); + % make output analysis object + bs(jj).data = fsd; + % set name + bs(jj).name = ['SPSD(', ao_invars{jj}, ') ' upper(scale)]; + % Add standard deviation + bs(jj).data.dy = stdDev; + % Add history + bs(jj).addHistory(getInfo('None'), pl, ao_invars(jj), inhists(jj)); + + end % End tsdata if/else + end % End AO loop + + %% Set output + if nargout == numel(bs) + % List of outputs + for ii = 1:numel(bs) + varargout{ii} = bs(ii); + end + else + % Single output + varargout{1} = bs; + end + +end + + +%-------------------------------------------------------------------------- +% Get Info Object +%-------------------------------------------------------------------------- +function ii = getInfo(varargin) + if nargin == 1 && strcmpi(varargin{1}, 'None') + sets = {}; + pl = []; + else + sets = {'Default'}; + pl = getDefaultPlist; + end + % Build info object + ii = minfo(mfilename, 'ao', 'ltpda', utils.const.categories.sigproc, '$Id: spsd.m,v 1.21 2011/07/11 10:43:35 adrien Exp $', sets, pl); +end + +%-------------------------------------------------------------------------- +% Get Default Plist +%-------------------------------------------------------------------------- +function pl = getDefaultPlist() + + % Plist for Welch-based, log-scale spaced spectral estimators. + pl = plist; + + % Win + p = param({'Win',['the window to be applied to the data to remove the ', ... + 'discontinuities at edges of segments. [default: taken from user prefs] <br>', ... + 'Only the design parameters of the window object are used. Enter either: <ul>', ... + '<li> a specwin window object OR</li>', ... + '<li> a string value containing the window name</li></ul>', ... + 'e.g., <tt>plist(''Win'', ''Kaiser'', ''psll'', 200)</tt>']}, paramValue.WINDOW); + pl.append(p); + + % Psll + p = param({'Psll',['the peak sidelobe level for Kaiser windows.<br>', ... + 'Note: it is ignored for all other windows']}, paramValue.DOUBLE_VALUE(200)); + pl.append(p); + + % Psll + p = param({'levelOrder','the contracting order for levelledHanning window'}, paramValue.DOUBLE_VALUE(2)); + pl.append(p); + + % Order + p = param({'Order',['order of segment detrending:<ul>', ... + '<li>-1 - no detrending</li>', ... + '<li>0 - subtract mean</li>', ... + '<li>1 - subtract linear fit</li>', ... + '<li>N - subtract fit of polynomial, order N</li></ul>']}, paramValue.DETREND_ORDER); + p.val.setValIndex(2); + pl.append(p); + + % Times + p = param({'Times','time range. If not empty, sets the restricted interval to analyze'}, paramValue.DOUBLE_VALUE([])); + pl.append(p); + + % Scale + p = param({'Scale',['scaling of output. Choose from:<ul>', ... + '<li>PSD - Power Spectral Density</li>', ... + '<li>ASD - Amplitude (linear) Spectral Density</li>'... + ]}, {1, {'PSD', 'ASD', 'PS', 'AS'}, paramValue.SINGLE}); + pl.append(p); + + p = param( {'lincoef', 'Linear scale smoothing coefficent (freq. bins)'}, 1); + pl.append(p); + + p = param( {'logcoef', ['Logarithmic scale smoothing coefficent<br>', 'Best compromise for both axes is 2/3']}, 2/3); + pl.append(p); +end