diff m-toolbox/classes/@matrix/mchNoisegen.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/@matrix/mchNoisegen.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,560 @@
+% MCHNOISEGEN Generates multichannel noise data series given a model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% FUNCTION:    mchNoisegen generates multichannel noise data series given a
+% mutichannel noise generating filter.
+%
+% DESCRIPTION: 
+% 
+%
+% CALL:        out = mchNoisegen(mod, pl)
+%
+% INPUT:
+%         mod: is a matrix containing a multichannel noise generating
+%         filter aiming to generate colored noise from unitary variance
+%         independent white data series. Each element of the multichannel
+%         filter must be a parallel bank of filters as that produced by
+%         matrix/mchNoisegenFilter or ao/Noisegen2D. The filter matrix must
+%         be square.
+% 
+% OUTPUT:
+%         out: is a matrix containg a multichannel colored noise time
+%         series which csd matrix is defined by mod'*mod.
+%
+% HISTORY:     19-10-2009 L Ferraioli
+%              Creation
+%
+% ------------------------------------------------------------------------
+%
+% <a href="matlab:utils.helper.displayMethodInfo('matrix', 'mchNoisegen')">Parameters Description</a>
+%
+% VERSION:     $Id: mchNoisegen.m,v 1.6 2011/04/08 08:56:31 hewitson Exp $
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function varargout = mchNoisegen(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.OMNAME, '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 ltpdauoh objects
+  [mtxs, mtxs_invars] = utils.helper.collect_objects(varargin(:), 'matrix', in_names);
+  [pl, invars] = utils.helper.collect_objects(varargin(:), 'plist');
+  
+  inhists = mtxs.hist;
+  
+  % combine plists
+  pl = parse(pl, getDefaultPlist());
+  pl.getSetRandState();
+  
+  outm = copy(mtxs,nargout);
+  
+  % Get parameters and set params for fit
+  Nsecs       = find(pl, 'nsecs');
+  fs          = find(pl, 'fs');
+  yunit       = find(pl, 'yunits');
+  
+  % total number of data in the series
+  Ntot = round(Nsecs*fs);
+  
+  % chose case for input filter
+  if isa(outm,'matrix') && isa(outm.objs(1),'filterbank')
+    % discrete system
+    sys = 'z';
+    mfil = outm.objs;
+    [nn,mm] = size(mfil);
+    if nn~=mm
+      error('!!! Filter matrix must be square')
+    end
+    % check if filter is a matrix built with noisegen2D
+    fromnsg2D = false;
+    if nn == 2
+      nn11 = numel(mfil(1,1).filters);
+      nn21 = numel(mfil(2,1).filters);
+      if nn11 == nn21
+        % get poles out of the filters
+        pl11 = zeros(nn11,1);
+        pl21 = zeros(nn21,1);
+        for ii=1:nn11
+          pl11(ii) = -1*mfil(1,1).filters(ii).b(2);
+          pl21(ii) = -1*mfil(2,1).filters(ii).b(2);
+        end
+        % check if poles are equal that means they are produced with
+        % noisegen2D
+        if all((pl11-pl21)<eps)
+          fromnsg2D = true;
+        end
+      end  
+    end
+  elseif isa(outm,'matrix') && isa(outm.objs(1),'parfrac')
+    % continuous system
+    sys = 's';
+    mfil = outm.objs;
+    [nn,mm] = size(mfil);
+    if nn~=mm
+      error('!!! Filter matrix must be square')
+    end
+  else
+    error('!!! Input filter must be a ''matrix'' of ''filterbank'' or ''parfrac'' objects.')
+  end
+  
+  % init output
+  out(nn,1) = ao;
+  
+  % switch between input filter type
+  switch sys
+    case 'z' % discrete input filters
+      
+      % init output data
+      o = zeros(nn,Ntot);
+      
+      for zz=1:nn % moving along system dimension
+        
+        % extract residues and poles from input objects
+        % run over matrix dimensions
+        res = [];
+        pls = [];
+        filtsz = [];
+        for jj=1:nn % collect filters coefficients along the columns zz
+          bfil = mfil(jj,zz).filters;
+          filtsz = [filtsz; numel(bfil)];
+          for kk=1:numel(bfil)
+            num = bfil(kk).a;
+            den = bfil(kk).b;
+            res = [res; num(1)];
+            pls = [pls; -1*den(2)];
+          end
+        end
+        
+        % rescaling residues to get the correct result for univariate psd
+        res = res.*sqrt(fs/2);
+        
+        
+%         Nrs = numel(res);
+%         % get covariance matrix
+%         R = zeros(Nrs);
+%         for aa=1:Nrs
+%           for bb=1:Nrs
+%             R(aa,bb) = (res(aa)*conj(res(bb)))/(1-pls(aa)*conj(pls(bb)));
+%           end
+%         end
+%         
+%         % avoiding problems caused by roundoff errors
+%         HH = triu(R,0); % get upper triangular part of R
+%         HH1 = triu(R,1); % get upper triangular part of R above principal diagonal
+%         HH2 = HH1'; % do transpose conjugate
+%         R = HH + HH2; % reconstruct R in order to be really hermitian
+%         
+%         % get singular value decomposition of R
+%         [U,S,V] = svd(R,0);
+%         
+%         % conversion matrix
+%         A = V*sqrt(S);
+%         
+%         % generate unitary variance gaussian random noise
+%         %ns = randn(Nrs,Ntot);
+%         ns = randn(Nrs,1);
+%         
+%         % get correlated starting data points
+%         cns = A*ns;
+%         
+%         % need to correct for roundoff errors
+%         % cleaning up results for numerical approximations
+%         idx = imag(pls(:,1))==0;
+%         cns(idx) = real(cns(idx));
+%         
+%         % cleaning up results for numerical roundoff errors
+%         % states associated to complex conjugate poles must be complex
+%         % conjugate
+%         idxi = imag(pls(:,1))~=0;
+%         icns = cns(idxi);
+%         for jj = 1:2:numel(icns)
+%           icns(jj+1,1) = conj(icns(jj,1));
+%         end
+%         cns(idxi) = icns;
+        
+        cns = getinitz(res,pls,filtsz,fromnsg2D);
+        
+        y = zeros(sum(filtsz),2);
+        rnoise = zeros(sum(filtsz),1);
+        rns = randn(1,Ntot);
+        %rns = utils.math.blwhitenoise(Ntot,fs,1/Nsecs,fs/2);
+        %rns = rns.'; % willing to work with raw
+        
+        y(:,1) = cns;
+        
+        % start recurrence
+        for xx = 2:Ntot+1
+          rnoise(:,1) = rns(xx-1);
+          y(:,2) = pls.*y(:,1) + res.*rnoise;
+          idxr = 0;
+          for kk=1:nn
+            o(kk,xx-1) = o(kk,xx-1) + sum(y(idxr+1:idxr+filtsz(kk),2));
+            idxr = idxr+filtsz(kk);
+          end
+          y(:,1) = y(:,2);
+        end
+        
+      end
+      
+      clear rns
+      
+      % build output ao
+      for dd=1:nn
+        out(dd,1) = ao(tsdata(o(dd,:),fs));
+        out(dd,1).setYunits(unit(yunit));
+      end
+      
+      outm = matrix(out);
+      
+    case 's' % continuous input filters
+      
+      o = zeros(nn,Ntot);
+      
+      T = 1/fs; % sampling period
+      
+      for zz=1:nn % moving along system dimension
+        
+        % extract residues and poles from input objects
+        % run over matrix dimensions
+        res = [];
+        pls = [];
+        filtsz = [];
+        for jj=1:nn % collect filters coefficients along the columns zz
+          bfil = mfil(jj,zz);
+          filtsz = [filtsz; numel(bfil.res)];
+          res = [res; bfil.res];
+          pls = [pls; bfil.poles];
+        end
+        
+        % rescaling residues to get the correct result for univariate psd
+        res = res.*sqrt(fs/2);
+        
+        Nrs = numel(res);
+        
+        % get covariance matrix for innovation
+        Ri = zeros(Nrs);
+        for aa=1:Nrs
+          for bb=1:Nrs
+            Ri(aa,bb) = (res(aa)*conj(res(bb)))*(exp((pls(aa) + conj(pls(bb)))*T)-1)/(pls(aa) + conj(pls(bb)));
+          end
+        end
+        
+        % avoiding problems caused by roundoff errors
+        HH = triu(Ri,0); % get upper triangular part of R
+        HH1 = triu(Ri,1); % get upper triangular part of R above principal diagonal
+        HH2 = HH1'; % do transpose conjugate
+        Ri = HH + HH2; % reconstruct R in order to be really hermitian
+        
+        % get singular value decomposition of R
+        [Ui,Si,Vi] = svd(Ri,0);
+
+        % conversion matrix for innovation
+        Ai = Vi*sqrt(Si);
+        
+        % get covariance matrix for initial state
+        Rx = zeros(Nrs);
+        for aa=1:Nrs
+          for bb=1:Nrs
+            Rx(aa,bb) = -1*(res(aa)*conj(res(bb)))/(pls(aa) + conj(pls(bb)));
+          end
+        end
+        
+        % avoiding problems caused by roundoff errors
+        HH = triu(Rx,0); % get upper triangular part of R
+        HH1 = triu(Rx,1); % get upper triangular part of R above principal diagonal
+        HH2 = HH1'; % do transpose conjugate
+        Rx = HH + HH2; % reconstruct R in order to be really hermitian
+        
+        % get singular value decomposition of R
+        [Ux,Sx,Vx] = svd(Rx,0);
+
+        % conversion matrix for initial state
+        Ax = Vx*sqrt(Sx);
+        
+        % generate unitary variance gaussian random noise
+        %ns = randn(Nrs,Ntot);
+        ns = randn(Nrs,1);
+
+        % get correlated starting data points
+        cns = Ax*ns;
+        
+        % need to correct for roundoff errors
+        % cleaning up results for numerical approximations
+        idx = imag(pls(:,1))==0;
+        cns(idx) = real(cns(idx));
+        
+        % cleaning up results for numerical roundoff errors
+        % states associated to complex conjugate poles must be complex
+        % conjugate
+        idxi = imag(pls(:,1))~=0;
+        icns = cns(idxi);
+        for jj = 1:2:numel(icns)
+          icns(jj+1,1) = conj(icns(jj,1));
+        end
+        cns(idxi) = icns;
+        
+        y = zeros(sum(filtsz),2);
+        rnoise = zeros(sum(filtsz),1);
+        rns = randn(1,Ntot);
+        %rns = utils.math.blwhitenoise(Ntot,fs,1/Nsecs,fs/2);
+        %rns = rns.'; % willing to work with raw
+        
+        y(:,1) = cns;
+        
+        % start recurrence
+        for xx = 2:Ntot+1
+%           innov = Ai*randn(sum(filtsz),1);
+          rnoise(:,1) = rns(xx-1);
+          innov = Ai*rnoise;
+          % need to correct for roundoff errors
+          % cleaning up results for numerical approximations
+          innov(idx) = real(innov(idx));
+
+          % cleaning up results for numerical roundoff errors
+          % states associated to complex conjugate poles must be complex
+          % conjugate
+          iinnov = innov(idxi);
+          for jj = 1:2:numel(iinnov)
+            iinnov(jj+1,1) = conj(iinnov(jj,1));
+          end
+          innov(idxi) = iinnov;
+                   
+          y(:,2) = diag(exp(pls.*T))*y(:,1) + innov;
+          
+          idxr = 0;
+          for kk=1:nn
+            o(kk,xx-1) = o(kk,xx-1) + sum(y(idxr+1:idxr+filtsz(kk),2));
+            idxr = idxr+filtsz(kk);
+          end
+          y(:,1) = y(:,2);
+        end
+        
+      end
+      
+%       clear rns
+      
+      % build output ao
+      for dd=1:nn
+        out(dd,1) = ao(tsdata(o(dd,:),fs));
+        out(dd,1).setYunits(unit(yunit));
+      end
+      
+      outm = matrix(out);
+      
+  end
+  
+  % set output
+  varargout{1} = outm;
+  
+
+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, 'matrix', 'ltpda', utils.const.categories.sigproc, '$Id: mchNoisegen.m,v 1.6 2011/04/08 08:56:31 hewitson Exp $', sets, pl);
+  ii.setArgsmin(1);
+  ii.setOutmin(1);
+  ii.setOutmax(1);
+end
+
+%--------------------------------------------------------------------------
+% Get Default Plist
+%--------------------------------------------------------------------------
+function plout = getDefaultPlist()
+  persistent pl;  
+  if exist('pl', 'var')==0 || isempty(pl)
+    pl = buildplist();
+  end
+  plout = pl;  
+end
+
+function pl = buildplist()
+  
+  pl = plist();
+  
+  % Nsecs
+  p = param({'nsecs', 'Number of seconds in the desired noise data series.'}, {1, {1}, paramValue.OPTIONAL});
+  pl.append(p);
+  
+  % Fs
+  p = param({'fs', 'The sampling frequency of the noise data series.'}, {1, {1}, paramValue.OPTIONAL});
+  pl.append(p);
+  
+  % Yunits
+  p = param({'yunits','Unit on Y axis.'},  paramValue.STRING_VALUE(''));
+  pl.append(p);
+  
+end
+
+%--------------------------------------------------------------------------
+% Local function
+% Estimate init values for the z domain case
+%--------------------------------------------------------------------------
+function cns = getinitz(res,pls,filtsz,fromnsg2D)
+
+  if fromnsg2D % init in the case of filters produced with noisegen2D
+    % divide in 2 the problem
+    res1 = res(1:filtsz(1));
+    res2 = res(filtsz(1)+1:filtsz(2));
+    pls1 = pls(1:filtsz(1));
+    pls2 = pls(filtsz(1)+1:filtsz(2));
+    
+    %%% the first series %%%
+    Nrs = numel(res1);
+    % get covariance matrix
+    R = zeros(Nrs);
+    for aa=1:Nrs
+      for bb=1:Nrs
+        R(aa,bb) = (res1(aa)*conj(res1(bb)))/(1-pls1(aa)*conj(pls1(bb)));
+      end
+    end
+
+    % avoiding problems caused by roundoff errors
+    HH = triu(R,0); % get upper triangular part of R
+    HH1 = triu(R,1); % get upper triangular part of R above principal diagonal
+    HH2 = HH1'; % do transpose conjugate
+    R = HH + HH2; % reconstruct R in order to be really hermitian
+
+    % get singular value decomposition of R
+    [U,S,V] = svd(R,0);
+
+    % conversion matrix
+    A = V*sqrt(S);
+
+    % generate unitary variance gaussian random noise
+    %ns = randn(Nrs,Ntot);
+    ns = randn(Nrs,1);
+
+    % get correlated starting data points
+    cns1 = A*ns;
+
+    % need to correct for roundoff errors
+    % cleaning up results for numerical approximations
+    idx = imag(pls1(:,1))==0;
+    cns1(idx) = real(cns1(idx));
+
+    % cleaning up results for numerical roundoff errors
+    % states associated to complex conjugate poles must be complex
+    % conjugate
+    idxi = imag(pls1(:,1))~=0;
+    icns1 = cns1(idxi);
+    for jj = 1:2:numel(icns1)
+      icns1(jj+1,1) = conj(icns1(jj,1));
+    end
+    cns1(idxi) = icns1;
+    
+    %%% the second series %%%
+    Nrs = numel(res2);
+    % get covariance matrix
+    R = zeros(Nrs);
+    for aa=1:Nrs
+      for bb=1:Nrs
+        R(aa,bb) = (res2(aa)*conj(res2(bb)))/(1-pls2(aa)*conj(pls2(bb)));
+      end
+    end
+
+    % avoiding problems caused by roundoff errors
+    HH = triu(R,0); % get upper triangular part of R
+    HH1 = triu(R,1); % get upper triangular part of R above principal diagonal
+    HH2 = HH1'; % do transpose conjugate
+    R = HH + HH2; % reconstruct R in order to be really hermitian
+
+    % get singular value decomposition of R
+    [U,S,V] = svd(R,0);
+
+    % conversion matrix
+    A = V*sqrt(S);
+
+    % generate unitary variance gaussian random noise
+    %ns = randn(Nrs,Ntot);
+    ns = randn(Nrs,1);
+
+    % get correlated starting data points
+    cns2 = A*ns;
+
+    % need to correct for roundoff errors
+    % cleaning up results for numerical approximations
+    idx = imag(pls2(:,1))==0;
+    cns2(idx) = real(cns2(idx));
+
+    % cleaning up results for numerical roundoff errors
+    % states associated to complex conjugate poles must be complex
+    % conjugate
+    idxi = imag(pls2(:,1))~=0;
+    icns2 = cns2(idxi);
+    for jj = 1:2:numel(icns2)
+      icns2(jj+1,1) = conj(icns2(jj,1));
+    end
+    cns2(idxi) = icns2;
+    
+    %%% combine results %%%
+    cns = [cns1;cns2];
+    
+  else % init in the case of filters produced with matrix constructor
+    
+    Nrs = numel(res);
+    % get covariance matrix
+    R = zeros(Nrs);
+    for aa=1:Nrs
+      for bb=1:Nrs
+        R(aa,bb) = (res(aa)*conj(res(bb)))/(1-pls(aa)*conj(pls(bb)));
+      end
+    end
+
+    % avoiding problems caused by roundoff errors
+    HH = triu(R,0); % get upper triangular part of R
+    HH1 = triu(R,1); % get upper triangular part of R above principal diagonal
+    HH2 = HH1'; % do transpose conjugate
+    R = HH + HH2; % reconstruct R in order to be really hermitian
+
+    % get singular value decomposition of R
+    [U,S,V] = svd(R,0);
+
+    % conversion matrix
+    A = V*sqrt(S);
+
+    % generate unitary variance gaussian random noise
+    %ns = randn(Nrs,Ntot);
+    ns = randn(Nrs,1);
+
+    % get correlated starting data points
+    cns = A*ns;
+
+    % need to correct for roundoff errors
+    % cleaning up results for numerical approximations
+    idx = imag(pls(:,1))==0;
+    cns(idx) = real(cns(idx));
+
+    % cleaning up results for numerical roundoff errors
+    % states associated to complex conjugate poles must be complex
+    % conjugate
+    idxi = imag(pls(:,1))~=0;
+    icns = cns(idxi);
+    for jj = 1:2:numel(icns)
+      icns(jj+1,1) = conj(icns(jj,1));
+    end
+    cns(idxi) = icns;
+    
+  end
+
+end