Mercurial > hg > ltpda
view m-toolbox/classes/@matrix/mchNoisegen.m @ 44:409a22968d5e default
Add unit tests
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Tue, 06 Dec 2011 18:42:11 +0100 |
parents | f0afece42f48 |
children |
line wrap: on
line source
% 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