Mercurial > hg > ltpda
view m-toolbox/classes/@ao/noisegen2D.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 source
% NOISEGEN2D generates cross correleted colored noise from white noise. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % DESCRIPTION: noisegen2D can work in two different modes: % % ------------------------------------------------------------------------ % % 1) Generates colored noise from white noise with a given cross spectrum. % This mode correspond to the 'Default' set for the method (see the % list of parameters). % % The coloring filter is constructed by a fitting procedure to the models % provided. If no model is provided an error is prompted. The % cross-spectral matrix is assumed to be frequency by frequency of the % type: % % / csd11(f) csd12(f) \ % CSD(f) = | | % \ csd21(f) csd22(f) / % % Note: The function output colored noise data with one-sided % csd corresponding to the model provided. % % ALGORITHM: % 1) Fit a set of partial fraction z-domain filters % 2) Convert to array of MIIR filters % 3) Filter time-series in parallel % The filtering process is: % b(1) = Filt11(a(1)) + Filt12(a(2)) % b(2) = Filt21(a(1)) + Filt22(a(2)) % % % CALL: b = noisegen2D(a, pl) % returns colored time-series AOs % b = noisegen2D(a, pl) % [b1,b2] = noisegen2D(a1, a2, pl) % [b1,b2,...,bn] = noisegen2D(a1,a2,...,an, pl); % Note: this method cannot be used as a modifier, the % call a.noisegen2D(pl) is forbidden % % INPUT: % % - a is at least a couple of time series analysis objects % - pl is a parameter list, see the list of accepted % parameters below % % OUTPUT: % % - b are a couple of colored time-series AOs. The coloring % filters used are stored in the objects procinfo field under % the parameters: % - b(1): 'Filt11' and 'Filt12' % - b(2): 'Filt21' and 'Filt22' % ------------------------------------------------------------------------ % % 2) Generates coloring filter % This mode correspond to the 'Filter' set for the method (see the % list of parameters). % % The coloring filter is constructed by a fitting procedure to the models % provided. The cross-spectral matrix is assumed to be frequency by % frequency of the type: % % / csd11(f) csd12(f) \ % CSD(f) = | | % \ csd21(f) csd22(f) / % % ALGORITHM: % 1) Fit a set of partial fraction z-domain filters % 2) Convert to array of MIIR filters % % % CALL: fil = noisegen2D(csd11,csd12,csd21,csd22, pl) % fil = noisegen2D(csd11,csd12,csd22, pl) % Note: this method cannot be used as a modifier, the % call a.noisegen2D(pl) is forbidden % % INPUT: % % - csd11, csd12, csd21,csd22 are the terms of the % cross-spectral matrix. They must be frequency series % analysis objects. % - pl is a parameter list, see the list of accepted % parameters below % % OUTPUT: % % - fil is a matrix object which represent a two dimensional % filter. The elements of fil are filterbanks parallel % objects of miir filters. Filters are initialized to % avoid startup transients. % % ------------------------------------------------------------------------ % % <a href="matlab:utils.helper.displayMethodInfo('ao', 'noisegen2D')">Parameters Description</a> % % VERSION: $Id: noisegen2D.m,v 1.34 2011/04/08 08:56:13 hewitson Exp $ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function varargout = noisegen2D(varargin) % Check if this is a call for parameters if utils.helper.isinfocall(varargin{:}) varargout{1} = getInfo(varargin{3}); return end import utils.const.* 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] = utils.helper.collect_objects(varargin(:), 'ao', in_names); pl = utils.helper.collect_objects(varargin(:), 'plist', in_names); % Decide on a deep copy or a modify bs = copy(as, nargout); inhists = [as.hist]; % combine plists % define input/output combinations. Different combination are % 1) input tsdata and csd# into the plist, output are colored tsdata % 2) input fsdata, output is a coloring filter (in a matrix) if isempty(pl) % no model input, get model from input setpar = 'Filter'; elseif numel(as)==3 && isa(as(1).data,'fsdata') % get model from input setpar = 'Filter'; elseif numel(as)==4 && isa(as(1).data,'fsdata') % get model from input setpar = 'Filter'; else % get model from plist, output tsdata, back compatibility mode setpar = 'Default'; end pl = parse(pl, getDefaultPlist(setpar)); pl.getSetRandState(); if nargout == 0 error('### noisegen2D cannot be used as a modifier. Please give an output variable.'); end % Check the number of input AOs if numel(bs)==1 error('!!! One input AO! At least two independent white noise time series or three frequency series are needed'); end switch lower(setpar) case 'default' % back compatibility mode % this copy will be used for data filtering cs = copy(as, nargout); % Extract necessary model parameters csd11 = find(pl, 'csd11'); csd12 = find(pl, 'csd12'); csd21 = find(pl, 'csd21'); csd22 = find(pl, 'csd22'); if ~isempty(csd12) && isempty(csd21) csd21 = conj(csd12); elseif ~isempty(csd21) && isempty(csd12) csd12 = conj(csd21); elseif isempty(csd12) && isempty(csd21) error('!!! One of the parameters ''csd12'' or ''csd21'' must be not empty!') end % Checks that the input AOs come in pairs odc = 0; if rem(numel(as),2) warning('The input AOs must come in pairs! Skipping AO %s during calculation', ao_invars{end}); odc = 1; end % Loop over input AOs to check for non time series objects fsv = zeros(numel(bs),1); for jj=1:numel(bs) if ~isa(bs(jj).data, 'tsdata') error('!!! %s expects ao/tsdata objects. ', mfilename); end fsv(jj,1) = bs(jj).fs; % collecting sampling frequencies end % Check that input Aos have the same sampling frequency if any(diff(fsv)) error('!!! Sampling frequency must be the same for all input objects') end case 'filter' % get models from inputs if numel(bs)==3 csd11 = bs(1); csd12 = bs(2); csd21 = conj(csd12); csd22 = bs(3); elseif numel(bs)==2 error('!!! A number of fsdata ao between 3 and 4 must be given as input') else csd11 = bs(1); csd12 = bs(2); csd21 = bs(3); csd22 = bs(4); end fsv = find(pl,'fs'); Iunits = find(pl, 'Iunits'); Ounits = find(pl, 'Ounits'); otherwise error('!!! Something with the input is going wrong! Check function help for details on how input data properly') end % ---------------------------------- % 1) - Fitting the models to identify the innovation filters % Build input structure for psd2tf params = struct(); params.idtp = 1; params.Nmaxiter = find(pl, 'MaxIter'); params.minorder = find(pl, 'MinOrder'); params.maxorder = find(pl, 'MaxOrder'); params.spolesopt = find(pl, 'PoleType'); params.usesym = find(pl, 'UseSym'); params.spy = find(pl, 'Disp'); % check for weights wobj = find(pl, 'Weights'); if isa(wobj,'ao') warning('Using externally provided weights.') params.weightparam = 0; % check external weights dimensions if numel(wobj)~= 4 erro('!!! Provide a weight for each CSD element') end for ii=1:4 twobj = wobj.index(ii).y; % willing to work with columns [aaw,bbw] = size(twobj); if aaw<bbw twobj = twobj.'; end wobj2(:,ii) = twobj; end params.extweights = wobj2; else params.weightparam = wobj; end % Tolerance for MSE Value lrscond = find(pl, 'FITTOL'); % give an error for strange values of lrscond if lrscond<0 error('!!! Negative values for FITTOL are not allowed !!!') end % handling data lrscond = -1*log10(lrscond); % give a warning for strange values of lrscond if lrscond<0 warning('You are searching for a MSE lower than %s', num2str(10^(-1*lrscond))) end params.lrscond = lrscond; % Tolerance for the MSE relative variation msevar = find(pl, 'MSEVARTOL'); % handling data msevar = -1*log10(msevar); % give a warning for strange values of msevar if msevar<0 warning('You are searching for MSE relative variation lower than %s', num2str(10^(-1*msevar))) end params.msevar = msevar; if isempty(params.msevar) params.ctp = 'chival'; else params.ctp = 'chivar'; end if(find(pl, 'plot')) params.plot = 1; else params.plot = 0; end params.fs = fsv(1,1); params.dterm = 0; % it is better to fit without direct term % call psd2tf ostruct = utils.math.psd2tf(csd11.y,csd12.y,csd21.y,csd22.y,csd11.x,params); % ---------------------------------- % 2) - Convert into MIIR filters fs = fsv(1,1); % get init states for coloring filters mres13 = [ostruct(1).res ostruct(3).res]; mres24 = [ostruct(2).res ostruct(4).res]; mpoles13 = [ostruct(1).poles ostruct(3).poles]; mpoles24 = [ostruct(4).poles ostruct(4).poles]; % initialize filters to cope with starting transients % Zi1 = zeros(numel(mres13(:,1)),1); % Zi3 = Zi1; Zi = utils.math.getinitstate(mres13,mpoles13,1,'mtd','svd'); Zi1 = Zi(1:numel(mres13(:,1))); Zi3 = Zi(numel(mres13(:,1))+1:2*numel(mres13(:,1))); % Zi2 = zeros(numel(mres24(:,1)),1); % Zi4 = Zi2; Zi = utils.math.getinitstate(mres24,mpoles24,1,'mtd','svd'); Zi2 = Zi(1:numel(mres24(:,1))); Zi4 = Zi(numel(mres24(:,1))+1:2*numel(mres24(:,1))); % --- filter 1 --- res = mres13(:,1); poles = mpoles13(:,1); % construct a struct array of miir filters vectors pfilts1 = []; for kk=1:numel(res) ft = miir(res(kk), [ 1 -poles(kk)], fs); ft.setHistout(Zi1(kk)); pfilts1 = [pfilts1 ft]; end % --- filter 2 --- res = mres24(:,1); poles = mpoles24(:,1); % construct a struct array of miir filters vectors pfilts2 = []; for kk=1:numel(res) ft = miir(res(kk), [ 1 -poles(kk)], fs); ft.setHistout(Zi2(kk)); pfilts2 = [pfilts2 ft]; end % --- filter 3 --- res = mres13(:,2); poles = mpoles13(:,2); % construct a struct array of miir filters vectors pfilts3 = []; for kk=1:numel(res) ft = miir(res(kk), [ 1 -poles(kk)], fs); ft.setHistout(Zi3(kk)); pfilts3 = [pfilts3 ft]; end % --- filter 4 --- res = mres24(:,2); poles = mpoles24(:,2); % construct a struct array of miir filters vectors pfilts4 = []; for kk=1:numel(res) ft = miir(res(kk), [ 1 -poles(kk)], fs); ft.setHistout(Zi4(kk)); pfilts4 = [pfilts4 ft]; end % switch between output options switch lower(setpar) case 'default' % ---------------------------------- % 3) Filtering data for jj = 1:2:numel(bs)-1-odc % add yunits, taking them from plist or, if empty, from input objects Iunits1 = bs(jj).yunits; Iunits2 = bs(jj+1).yunits; Ounits = find(pl, 'yunits'); switch class(Ounits) case 'cell' Ounits1 = Ounits{1}; Ounits2 = Ounits{2}; case 'unit' Ounits1 = Ounits(1); Ounits2 = Ounits(2); otherwise error('### Bad format for unit container. Supporting vector or cell array'); end if eq(unit(Ounits1), unit('')) && eq(unit(Ounits2), unit('')) Ounits1 = bs(jj).yunits; Ounits2 = bs(jj+1).yunits; end pfilts1.setIunits(Iunits1); pfilts1.setOunits(Ounits1); pfilts2.setIunits(Iunits2); pfilts2.setOunits(Ounits1); pfilts3.setIunits(Iunits1); pfilts3.setOunits(Ounits2); pfilts4.setIunits(Iunits2); pfilts4.setOunits(Ounits2); bs(jj) = filter(cs(jj), pfilts1) + filter(cs(jj+1), pfilts2); bs(jj+1) = filter(cs(jj), pfilts3) + filter(cs(jj+1), pfilts4); % ----------------------------------- % 4) Output data % name for this objects bs(jj).name = sprintf('noisegen2D(%s)_c1', [ao_invars{jj} ao_invars{jj+1}]); bs(jj+1).name = sprintf('noisegen2D(%s)_c2', [ao_invars{jj} ao_invars{jj+1}]); % Collect the filters into procinfo bs(jj).procinfo = plist('Filt11', pfilts1,'Filt12', pfilts2); bs(jj+1).procinfo = plist('Filt21', pfilts3,'Filt22', pfilts4); % add history bs(jj).addHistory(getInfo('None'), pl, [ao_invars(:)], [inhists(:)]); bs(jj+1).addHistory(getInfo('None'), pl, [ao_invars(:)], [inhists(:)]); end % Set output if nargout == numel(bs) % List of outputs for ii = 1:numel(bs) varargout{ii} = bs.index(ii); end else % Single output varargout{1} = bs; end case 'filter' pfilts1.setIunits(Iunits); pfilts1.setOunits(Ounits); pfilts2.setIunits(Iunits); pfilts2.setOunits(Ounits); pfilts3.setIunits(Iunits); pfilts3.setOunits(Ounits); pfilts4.setIunits(Iunits); pfilts4.setOunits(Ounits); fil11 = filterbank(plist('filters',pfilts1,'type','parallel')); fil11.setName('filter 11'); fil12 = filterbank(plist('filters',pfilts2,'type','parallel')); fil12.setName('filter 12'); fil21 = filterbank(plist('filters',pfilts3,'type','parallel')); fil21.setName('filter 21'); fil22 = filterbank(plist('filters',pfilts4,'type','parallel')); fil22.setName('filter 22'); fil = matrix(plist('objs',[fil11,fil21,fil12,fil22],'shape',[2 2])); fil.setName(sprintf('noisegen2D(%s)',ao_invars{:})); fil.addHistory(getInfo('None'), pl, [ao_invars(:)], [inhists(:)]); % Single output varargout{1} = fil; end end %-------------------------------------------------------------------------- % Get Info Object %-------------------------------------------------------------------------- function ii = getInfo(varargin) if nargin == 1 && strcmpi(varargin{1}, 'None') sets = {}; pl = []; elseif nargin == 1 && ~isempty(varargin{1}) && ischar(varargin{1}) sets{1} = varargin{1}; pl = getDefaultPlist(sets{1}); else sets = SETS(); % get plists pl(size(sets)) = plist; for kk = 1:numel(sets) pl(kk) = getDefaultPlist(sets{kk}); end end % Build info object ii = minfo(mfilename, 'ao', 'ltpda', utils.const.categories.sigproc, '$Id: noisegen2D.m,v 1.34 2011/04/08 08:56:13 hewitson Exp $', sets, pl); ii.setArgsmin(2); ii.setOutmin(1); ii.setModifier(false); end %-------------------------------------------------------------------------- % Defintion of Sets %-------------------------------------------------------------------------- function out = SETS() out = {... 'Default', ... 'Filter' ... }; end %-------------------------------------------------------------------------- % Get Default Plist %-------------------------------------------------------------------------- function plout = getDefaultPlist(set) persistent pl; persistent lastset; if exist('pl', 'var')==0 || isempty(pl) || ~strcmp(lastset, set) pl = buildplist(set); lastset = set; end plout = pl; end function pl = buildplist(set) pl = plist(); switch lower(set) case 'default' % CSD11 p = param({'csd11', 'A frequency-series AO describing the model csd11'}, paramValue.EMPTY_DOUBLE); pl.append(p); % CSD12 p = param({'csd12', 'A frequency-series AO describing the model csd12'}, paramValue.EMPTY_DOUBLE); pl.append(p); % CSD21 p = param({'csd21', 'A frequency-series AO describing the model csd21'}, paramValue.EMPTY_DOUBLE); pl.append(p); % CSD22 p = param({'csd22', 'A frequency-series AO describing the model csd22'}, paramValue.EMPTY_DOUBLE); pl.append(p); % Yunits p = param({'yunits',['Unit on Y axis. <br>' ... 'If left empty, it will take the y-units from the input objects']}, {'',''}); pl.append(p); case 'filter' % Fs p = param({'fs','The sampling frequency to design for.'}, paramValue.DOUBLE_VALUE(1)); pl.append(p); % Iunits p = param({'iunits','The input units of the filter.'}, paramValue.EMPTY_STRING); pl.append(p); % Ounits p = param({'ounits','The output units of the filter.'}, paramValue.EMPTY_STRING); pl.append(p); end % MaxIter p = param({'MaxIter', 'Maximum number of iterations in fit routine.'}, paramValue.DOUBLE_VALUE(30)); pl.append(p); % PoleType p = param({'PoleType', ['Choose the pole type for fitting:<ol>'... '<li>use real starting poles</li>' ... '<li>generates complex conjugate poles of the<br>'... 'type <tt>a.*exp(theta*pi*j)</tt><br>'... 'with <tt>theta = linspace(0,pi,N/2+1)</tt></li>'... '<li>generates complex conjugate poles of the type<br>'... '<tt>a.*exp(theta*pi*j)</tt><br>'... 'with <tt>theta = linspace(0,pi,N/2+2)</tt></li></ol>']}, {3, {1,2,3}, paramValue.SINGLE}); pl.append(p); % MinOrder p = param({'MinOrder', 'Minimum order to fit with.'}, paramValue.DOUBLE_VALUE(2)); pl.append(p); % MaxOrder p = param({'MaxOrder', 'Maximum order to fit with.'}, paramValue.DOUBLE_VALUE(25)); pl.append(p); % Weights p = param({'Weights', ['Choose weighting for the fit:<ol>'... '<li>equal weights for each point</li>'... '<li>weight with <tt>1/abs(model)</tt></li>'... '<li>weight with <tt>1/abs(model).^2</tt></li>'... '<li>weight with inverse of the square mean spread<br>'... 'of the model</li></ol>']}, paramValue.DOUBLE_VALUE(3)); pl.append(p); % Plot p = param({'Plot', 'Plot results of each fitting step.'}, paramValue.FALSE_TRUE); pl.append(p); % Disp p = param({'Disp', 'Display the progress of the fitting iteration.'}, paramValue.FALSE_TRUE); pl.append(p); % MSEVARTOL p = param({'MSEVARTOL', ['Mean Squared Error Variation - Check if the<br>'... 'realtive variation of the mean squared error is<br>'... 'smaller than the value specified. This<br>'... 'option is useful for finding the minimum of Chi-squared.']}, ... paramValue.DOUBLE_VALUE(1e-2)); pl.append(p); % FITTOL p = param({'FITTOL', ['Mean Squared Error Value - Check if the mean<br>'... 'squared error value is lower than the value<br>'... 'specified.']}, paramValue.DOUBLE_VALUE(1e-2)); pl.append(p); % UseSym p = param({'UseSym', ['Use symbolic calculation in eigen-decomposition.<ul>'... '<li>0 - perform double-precision calculation in the<br>'... 'eigendecomposition procedure to identify 2-Dim<br>'... 'systems and for poles stabilization</li>'... '<li>1 - uses symbolic math toolbox variable precision<br>'... 'arithmetic in the eigen-decomposition for 2-Dim<br>'... 'system identification and double-precison for<br>'... 'poles stabilization</li>'... '<li>2 - uses symbolic math toolbox variable precision<br>'... 'arithmetic in the eigen-decomposition for 2-Dim<br>'... 'system identification and for poles stabilization.']}, {1, {0,1,2}, paramValue.SINGLE}); pl.append(p); end