diff m-toolbox/classes/@ao/noisegen1D.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/noisegen1D.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,413 @@
+% NOISEGEN1D generates colored noise from white noise.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: noisegen1D can work in two different modes:
+% 
+% ------------------------------------------------------------------------
+% 1) Generates colored noise from white noise with a given spectrum. The
+% function constructs a coloring filter through a fitting procedure to the
+% model provided. If no model is provided an error is prompted. The colored
+% noise provided has one-sided psd corresponding to the input model.
+% 
+% This mode correspond to the 'Default' set for the method (see the list of
+% parameters).
+%
+% ALGORITHM:
+%            1) Fit a set of partial fraction z-domain filters using
+%               utils.math.psd2tf
+%            2) Convert to array of MIIR filters
+%            3) Filter time-series in parallel
+%
+% CALL:         b = noisegen1D(a, pl)
+% 
+% INPUT:
+%               - a is a white noise time-series analysis object or a
+%               vector of analysis objects
+%               - pl is a plist with the input parameters
+% 
+% OUTPUT:
+% 
+%               - b Colored time-series AOs. The coloring filters used
+%               are stored in the objects procinfo field under the
+%               parameter 'Filt'.
+% 
+% ------------------------------------------------------------------------
+% 
+% 2) Generates noise coloring filters for given input psd models. 
+% 
+% This mode correspond to the 'Filter' set for the method (see the list of
+% parameters).
+%
+% ALGORITHM:
+%            1) Fit a set of partial fraction z-domain filters
+%            2) Convert to array of MIIR filters
+%
+% CALL:         fil = noisegen1D(psd, pl)
+% 
+% INPUT:
+%               - psd is a fsdata analysis object representing the desired
+%               model for the power spectral density of the colored noise
+%               - pl is a plist with the input parameters
+% 
+% OUTPUT:
+% 
+%               - fil is a filterbank parallel object which elements are
+%               miir filters. Filters are initialized to avoid startup
+%               transients.
+%
+% ------------------------------------------------------------------------
+%
+% <a href="matlab:utils.helper.displayMethodInfo('ao', 'noisegen1D')">Parameters Description</a>
+%
+% VERSION:     $Id: noisegen1D.m,v 1.30 2011/04/08 08:56:15 hewitson Exp $
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function varargout = noisegen1D(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 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();
+  
+  switch lower(setpar)
+    case 'default'
+      % Extract necessary parameters
+      model = find(pl, 'model');
+    case 'filter'
+      fs     = find(pl,'fs');
+      Iunits = find(pl, 'Iunits');
+      Ounits = find(pl, 'Ounits');
+      
+      % init filter objects
+      fil = filterbank.initObjectWithSize(size(bs,1),size(bs,2));
+  end
+  
+  % start building input structure for psd2tf
+  params.idtp = 1;
+  params.Nmaxiter = find(pl, 'MaxIter');
+  params.minorder = find(pl, 'MinOrder');
+  params.maxorder = find(pl, 'MaxOrder');
+  params.spolesopt = find(pl, 'PoleType');
+  params.weightparam = find(pl, 'Weights');
+  params.spy = find(pl, 'Disp');
+  
+  % 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.usesym = 0;
+  params.dterm = 0; % it is better to fit without dterm
+  
+  % Loop over input AOs
+  for jj=1:numel(bs)
+    
+    switch lower(setpar)
+      case 'default'
+        if ~isa(bs(jj).data, 'tsdata')
+          warning('!!! %s expects ao/tsdata objects. Skipping AO %s', mfilename, ao_invars{jj});
+        else      
+          %-------------- Colored noise from white noise
+
+          % 1) If we have no model gives an error
+          if(isempty(model))
+            error('!!! Input a model for the desired PSD')
+          end
+
+          % 2) Noise Generation
+
+          params.fs = bs(jj).fs;
+
+          % call psd2tf
+          [res, poles, dterm, mresp, rdl] = ...
+            utils.math.psd2tf(model.y,[],[],[],model.x,params);
+          
+          % get init state
+          Zi = utils.math.getinitstate(res,poles,1,'mtd','svd');
+
+          % 3) Convert to MIIR filters
+          % add yunits, taking them from plist or, if empty, from input object
+          Iunits = as(jj).yunits;
+          Ounits = find(pl, 'yunits');
+          if eq(unit(Ounits), unit(''))
+            Ounits = as(jj).yunits;
+          end
+          pfilts = [];
+          for kk=1:numel(res)
+            ft = miir(res(kk), [ 1 -poles(kk)], bs(jj).fs);
+            ft.setIunits(Iunits);
+            ft.setOunits(Ounits);
+            ft.setHistout(Zi(kk)); 
+            % build parallel bank of filters
+            pfilts = [pfilts ft];
+          end
+
+          % 4) Filter data
+          bs(jj).filter(pfilts);
+
+          % 5) Output data            
+          % add history
+          bs(jj).addHistory(getInfo('None'), pl, [ao_invars(:)], [inhists(:)]);
+          % name for this object
+          bs(jj).setName(sprintf('noisegen1D(%s)', ao_invars{jj}));
+          % Collect the filters into procinfo
+          bs(jj).procinfo = plist('filter', pfilts);
+      
+        end
+      case 'filter'
+        
+        params.fs = fs;
+
+        % call psd2tf
+        [res, poles, dterm, mresp, rdl] = ...
+          utils.math.psd2tf(bs(jj).y,[],[],[],bs(jj).x,params);
+
+        % get init state
+        Zi = utils.math.getinitstate(res,poles,1,'mtd','svd');
+        
+        % build miir
+        pfilts = [];
+        for kk=1:numel(res)
+          ft = miir(res(kk), [ 1 -poles(kk)], fs);
+          ft.setIunits(Iunits);
+          ft.setOunits(Ounits);
+          ft.setHistout(Zi(kk)); 
+          % build parallel bank of filters
+          pfilts = [pfilts ft];
+        end
+        
+        % build output filterbanks
+        fil(jj) = filterbank(plist('filters',pfilts,'type','parallel'));
+        fil(jj).setName(sprintf('noisegen1D(%s)',ao_invars{jj}));
+        fil(jj).addHistory(getInfo('None'), pl, [ao_invars(:)], [inhists(:)]);
+    end
+  end
+  
+  % switch output
+  switch lower(setpar)
+    
+    case 'default'
+      % Set output
+      if nargout > 1 && 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'
+      
+      % Set output
+      if nargout > 1 && nargout == numel(bs)
+        % List of outputs
+        for ii = 1:numel(fil)
+          varargout{ii} = fil.index(ii);
+        end
+      else
+        % Single output
+        varargout{1} = fil;
+      end
+      
+  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: noisegen1D.m,v 1.30 2011/04/08 08:56:15 hewitson Exp $', sets, pl);
+
+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'
+      % Yunits
+      p = param({'yunits',['Unit on Y axis. <br>' ...
+        'If left empty, it will take the y-units from the input object']},  paramValue.STRING_VALUE(''));
+      pl.append(p);
+
+      % Model
+      p = param({'model', 'A frequency-series AO describing the model psd'}, paramValue.EMPTY_DOUBLE);
+      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);
+    
+end
+
+