Mercurial > hg > ltpda
diff m-toolbox/classes/@matrix/crb.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/crb.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,360 @@ +% CRB computes the inverse of the Fisher Matrix +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DESCRIPTION: CRB computes the inverse of the Fisher Matrix +% +% CALL: bs = crb(in,pl) +% +% INPUTS: in - matrix objects with input signals to the system +% model - symbolic models containing the transfer function model +% +% pl - parameter list +% +% OUTPUTS: bs - covariance matrix AO +% +% <a href="matlab:utils.helper.displayMethodInfo('matrix', 'crb')">Parameters Description</a> +% +% VERSION: $Id: crb.m,v 1.17 2011/10/07 08:19:55 miquel Exp $ +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function varargout = crb(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); + +% Method can not be used as a modifier +if nargout == 0 + error('### crb cannot be used as a modifier. Please give an output variable.'); +end + +% Collect input variable names +in_names = cell(size(varargin)); +for ii = 1:nargin,in_names{ii} = inputname(ii);end + +% Collect all AOs smodels and plists +[mtxs, mtxs_invars] = utils.helper.collect_objects(varargin(:), 'matrix', in_names); +pl = utils.helper.collect_objects(varargin(:), 'plist', in_names); + +% Combine plists +pl = parse(pl, getDefaultPlist); + +% get params +params = find(pl,'FitParams'); +numparams = find(pl,'paramsValues'); +mdl = find(pl,'model'); +mtxns = find(pl,'noise'); +outModel = find(pl,'outModel'); +bmdl = find(pl,'built-in'); +f1 = find(pl,'f1'); +f2 = find(pl,'f2'); +pseudoinv = find(pl,'pinv'); +tol = find(pl,'tol'); +outNames = find(pl,'outNames'); +inNames = find(pl,'inNames'); + +% Decide on a deep copy or a modify +in = copy(mtxs, nargout); +n = copy(mtxns, nargout); + +% Get number of experiments +nexp = numel(in); + +% fft +fin = fft(in); + +% N should get before spliting, in order to convert correctly from psd to +% fft +N = length(fin(1).getObjectAtIndex(1).x); + +% Get rid of fft f =0, reduce frequency range if needed +if ~isempty(f1) && ~isempty(f2) + fin = split(fin,plist('frequencies',[f1 f2])); +end + +FMall = zeros(numel(params),numel(params)); +% loop over experiments +for k = 1:nexp + + utils.helper.msg(msg.IMPORTANT, sprintf('Analysis of experiment #%d',k), mfilename('class'), mfilename); + + if (((numel(n(1).objs)) == 1) && (numel(in(1).objs) == 1)) + + % use signal fft to get frequency vector. + i1 = fin(k).getObjectAtIndex(1,1); + freqs = i1.x; + + FisMat = utils.math.fisher_1x1(i1,n(k),mdl,params,numparams,freqs,N,pl,inNames,outNames); + % store Fisher Matrix for this run + FM{k} = FisMat; + % adding up + FMall = FMall + FisMat; + + elseif (((numel(n(1).objs)) == 2) && (numel(in(1).objs) == 2)) + % use signal fft to get frequency vector. Take into account signal + % could be empty or set to zero + % 1st channel + if all(fin(k).getObjectAtIndex(1,1).y == 0) || isempty(fin(k).getObjectAtIndex(1,1).y) + i1 = ao(plist('type','fsdata','xvals',0,'yvals',0)); + else + i1 = fin(k).getObjectAtIndex(1,1); + freqs = i1.x; + end + % 2nd channel + if all(fin(k).getObjectAtIndex(2,1).y == 0) || isempty(fin(k).getObjectAtIndex(2,1).y) + i2 = ao(plist('type','fsdata','xvals',0,'yvals',0)); + else + i2 = fin(k).getObjectAtIndex(2,1); + freqs = i2.x; + end + + FisMat = utils.math.fisher_2x2(i1,i2,n(k),mdl,params,numparams,freqs,N,pl,inNames,outNames); + % store Fisher Matrix for this run + FM{k} = FisMat; + % adding up + FMall = FMall + FisMat; + + elseif ((numel(n(1).objs) == 3) && (numel(in.objs) == 4) && ~isempty(outModel)) + % this is only valid for the magnetic model, where we have 4 inputs + % (corresponding to the 4 conformator waveforms) and 3 outputs + % (corresponding to IFO.x12, IFO.eta1 and IFO.phi1). And there is a + % contribution of an outModel converting the conformator waveforms + % into forces and torques. + + + % For other cases not implemented yet. + + % use signal fft to get frequency vector. Take into account signal + % could be empty or set to zero + % 1st channel + freqs = fin.getObjectAtIndex(1,1).x; + + for ii = 1:numel(n.objs) + for jj = ii:numel(n.objs) + % Compute psd + if (ii==jj) + spec(ii,jj) = psd(n(k).getObjectAtIndex(ii), pl); + S2(ii,jj) = interp(spec(ii,jj),plist('vertices',freqs,'method','linear')); + else + spec(ii,jj) = cpsd(n(k).getObjectAtIndex(ii),n(k).getObjectAtIndex(jj),pl); + S2(ii,jj) = interp(spec(ii,jj),plist('vertices',freqs,'method','linear')); + S2(jj,ii) = conj(S2(ii,jj)); + end + end + end + + S = matrix(S2,plist('shape',[numel(n.objs) numel(n.objs)])); + + % get some parameters used below + fs = S.getObjectAtIndex(1,1).fs; + + + if(~isempty(outModel)) + for lll=1:size(outModel,1) + for kkk=1:size(outModel,2) + outModel(lll,kkk) = split(outModel(lll,kkk),plist('frequencies',[f1 f2])); + end + end + end + + % Avoid numerical differentiation (faster for the magnetic case) + Param{1} = [ 1 0 0 0; + 0 0 0 0; + 0 0 0 0;]; + Param{2} = [ 0 1 0 0; + 0 0 0 0; + 0 0 0 0;]; + Param{3} = [ 0 0 0 0; + 0 0 1 0; + 0 0 0 0;]; + Param{4} = [ 0 0 0 0; + 0 0 0 0; + 0 0 0 1;]; + + % scaling of PSD + % PSD = 2/(N*fs) * FFT *conj(FFT) + for j = 1: numel(S.objs) + % spectra to variance + C(:,j) = (N*fs/2)*S.objs(j).data.getY; + end + + detm = (C(:,1).*C(:,5).*C(:,9) + ... + C(:,2).*C(:,6).*C(:,7) + ... + C(:,3).*C(:,4).*C(:,8) -... + C(:,7).*C(:,5).*C(:,3) -... + C(:,8).*C(:,6).*C(:,1) -... + C(:,9).*C(:,4).*C(:,2)); + + InvS11 = (C(:,5).*C(:,9) - C(:,8).*C(:,6))./detm; + InvS12 = -(C(:,4).*C(:,9) - C(:,7).*C(:,6))./detm; + InvS13 = (C(:,4).*C(:,8) - C(:,7).*C(:,5))./detm; + InvS21 = -(C(:,2).*C(:,9) - C(:,8).*C(:,3))./detm; + InvS22 = (C(:,1).*C(:,9) - C(:,7).*C(:,3))./detm; + InvS23 = -(C(:,1).*C(:,8) - C(:,7).*C(:,2))./detm; + InvS31 = (C(:,2).*C(:,6) - C(:,5).*C(:,3))./detm; + InvS32 = -(C(:,1).*C(:,6) - C(:,4).*C(:,3))./detm; + InvS33 = (C(:,1).*C(:,5) - C(:,4).*C(:,2))./detm; + + for pp = 1:length(params) + for ll = 1:size(outModel,1) + for kk = 1:size(Param{pp},2) + % index convention: H(1,1)->h(1) H(2,1)->h(2) H(1,2)->h(3) H(2,2)->h(4) + tmp = 0; + for innerIndex = 1:size(outModel,2) + tmp = tmp + outModel(ll,innerIndex).y * Param{pp}(innerIndex,kk); + end + h{pp}(:,(kk-1)*size(outModel,1) + ll) = tmp; + end + end + + end + + for kk = 1:numel(in.objs) + inV(:,kk) = fin.objs(kk).data.getY; + end + + + % compute Fisher Matrix + for i =1:length(params) + for j =1:length(params) + + for ll = 1:size(outModel,1) + tmp = 0; + for kk = 1:size(Param{1},2) + tmp = tmp + h{i}(:,(kk-1)*size(outModel,1) + ll).*inV(:,kk); + end + v{i}(:,ll) = tmp; + end + + + for ll = 1:size(outModel,1) + tmp = 0; + for kk = 1:size(Param{1},2) + tmp = tmp + h{j}(:,(kk-1)*size(outModel,1) + ll).*inV(:,kk); + end + v{j}(:,ll) = tmp; + end + + v1v1 = conj(v{i}(:,1)).*v{j}(:,1); + v1v2 = conj(v{i}(:,1)).*v{j}(:,2); + v1v3 = conj(v{i}(:,1)).*v{j}(:,3); + v2v1 = conj(v{i}(:,2)).*v{j}(:,1); + v2v2 = conj(v{i}(:,2)).*v{j}(:,2); + v2v3 = conj(v{i}(:,2)).*v{j}(:,3); + v3v1 = conj(v{i}(:,3)).*v{j}(:,1); + v3v2 = conj(v{i}(:,3)).*v{j}(:,2); + v3v3 = conj(v{i}(:,3)).*v{j}(:,3); + + FisMat(i,j) = sum(real(InvS11.*v1v1 +... + InvS12.*v1v2 +... + InvS13.*v1v3 +... + InvS21.*v2v1 +... + InvS22.*v2v2 +... + InvS23.*v2v3 +... + InvS31.*v3v1 +... + InvS32.*v3v2 +... + InvS33.*v3v3)); + end + end + % store Fisher Matrix for this run + FM{k} = FisMat; + % adding up + FMall = FMall + FisMat; + else + error('Implemented cases: 2 inputs / 2outputs (TN3045 analysis), and 4 inputs / 3 outpus (magnetic complete analysis model. Other cases have not been implemented yet. Sorry for the inconvenience)'); + end + + +end + +% inverse is the optimal covariance matrix +if pseudoinv && isempty(tol) + cov = pinv(FMall); +elseif pseudoinv + cov = pinv(FMall,tol); +else + cov = FMall\eye(size(FMall)); +end + + +% create AO +out = ao(cov); +% Fisher Matrix in the procinfo +out.setProcinfo(plist('FisMat',FM)); + +varargout{1} = out; +end + + +%-------------------------------------------------------------------------- +% Get Info Object +%-------------------------------------------------------------------------- +function ii = getInfo(varargin) +if nargin == 1 && strcmpi(varargin{1}, 'None') + sets = {}; + pls = []; +else + sets = {'Default'}; + pls = getDefaultPlist; +end +% Build info object +ii = minfo(mfilename, 'ao', 'ltpda', utils.const.categories.sigproc, '$Id: crb.m,v 1.17 2011/10/07 08:19:55 miquel Exp $', sets, pls); +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.WELCH_PLIST; +pset(pl,'Navs',1) + +p = plist({'f1', 'Initial frequency for the analysis'}, paramValue.EMPTY_DOUBLE); +pl.append(p); + +p = plist({'f2', 'Final frequency for the analysis'}, paramValue.EMPTY_DOUBLE); +pl.append(p); + +p = plist({'FitParamas', 'Parameters of the model'}, paramValue.EMPTY_STRING); +pl.append(p); + +p = plist({'model','An array of matrix models'}, paramValue.EMPTY_STRING); +pl.append(p); + +p = plist({'noise','An array of matrices with the cross-spectrum matrices'}, paramValue.EMPTY_STRING); +pl.append(p); + +p = plist({'built-in','Symbolic models of the system as a string of built-in models'}, paramValue.EMPTY_STRING); +pl.append(p); + +p = plist({'frequencies','Array of start/sop frequencies where the analysis is performed'}, paramValue.EMPTY_STRING); +pl.append(p); + +p = plist({'pinv','Use the Penrose-Moore pseudoinverse'}, paramValue.TRUE_FALSE); +pl.append(p); + +p = plist({'tol','Tolerance for the Penrose-Moore pseudoinverse'}, paramValue.EMPTY_DOUBLE); +pl.append(p); + +p = plist({'step','Numerical differentiation step for ssm models'}, paramValue.EMPTY_DOUBLE); +pl.append(p); + +p = plist({'ngrid','Number of points in the grid to compute the optimal differentiation step for ssm models'}, paramValue.EMPTY_DOUBLE); +pl.append(p); + +p = plist({'stepRanges','An array with upper and lower values for the parameters ranges. To be used to compute the optimal differentiation step for ssm models.'}, paramValue.EMPTY_DOUBLE); +pl.append(p); +end