Mercurial > hg > ltpda
diff m-toolbox/classes/@matrix/MultiChannelNoise.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/MultiChannelNoise.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,303 @@ +% MULTICHANNELNOISE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% FUNCTION: MultiChannelNoise +% +% DESCRIPTION: +% +% +% CALL: a = MultiChannelNoise(a, pl) +% +% PARAMETER: +% pl: plist containing Nsecs, fs +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function a = MultiChannelNoise(a, pli) + + VERSION = '$Id: MultiChannelNoise.m,v 1.10 2010/10/29 16:09:13 ingo Exp $'; + + % get AO info + iobj = matrix.getInfo('matrix', 'Multichannel Noise'); + + % Set the method version string in the minfo object + iobj.setMversion([VERSION '-->' iobj.mversion]); + + % Add default values + pl = parse(pli, iobj.plists); + + % Get parameters and set params for fit + Nsecs = find(pl, 'nsecs'); + fs = find(pl, 'fs'); + filter = find(pl, 'model'); + yunit = find(pl, 'yunits'); + + % total number of data in the series + Ntot = round(Nsecs*fs); + + % chose case for input filter + if isa(filter,'matrix') && isa(filter.objs(1),'filterbank') + % discrete system + sys = 'z'; + mfil = filter.objs; + [nn,mm] = size(mfil); + if nn~=mm + error('!!! Filter matrix must be square') + end + elseif isa(filter,'matrix') && isa(filter.objs(1),'parfrac') + % continuous system + sys = 's'; + mfil = filter.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 + + 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; + + 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 + + a = 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 + + a = matrix(out); + + end + + +end + +