diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@ao/noisegen2D.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,627 @@
+% 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
+
+
+