Mercurial > hg > ltpda
diff m-toolbox/classes/@ao/crbound.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/crbound.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,410 @@ +% CRBOUND computes the inverse of the Fisher Matrix +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DESCRIPTION: CRBOUND computes the Cramer-Rao lowe bound for parametric +% model given the input signals and the noise. The method +% accepts 2D (2 input/2 output) models and 1D models +% (1 input/1 output) and (2 input/1 output) +% +% CALL: bs = crbound(in,noise,pl) +% +% INPUTS: in - analysis objects with input signals to the system +% (x1) if 1 input +% (x2) if 2 input +% noise - analysis objects with measured noise +% (x1) if 1 input: S11 +% (x4) if 2 input: (S11,S12,S21,S22) +% model - symbolic model (smodel) containing the evaluated +% transfer function models +% (x1) if 1 input/1 output +% (x2) if 2 input/1 output +% (x4) if 2 input/2 output +% pl - parameter list +% +% OUTPUTS: bs - covariance matrix AO +% +% <a href="matlab:utils.helper.displayMethodInfo('ao', 'crbound')">Parameters Description</a> +% +% VERSION: $Id: crbound.m,v 1.13 2011/04/08 08:56:17 hewitson Exp $ +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function varargout = crbound(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('### crbound 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 + [as, ao_invars] = utils.helper.collect_objects(varargin(:), 'ao', in_names); + pl = utils.helper.collect_objects(varargin(:), 'plist', in_names); + % Combine plists + pl = parse(pl, getDefaultPlist); + + % get params + params = find(pl,'params'); + numparams = find(pl,'paramsValues'); + mdl2 = find(pl,'models'); + bmdl = find(pl,'built-in'); + f1 = find(pl,'f1'); + f2 = find(pl,'f2'); + freqs = find(pl,'frequencies'); + pseudoinv = find(pl,'pinv'); + tol = find(pl,'tol'); + % ninputs = find(pl,'Ninputs'); + + + % Decide on a deep copy or a modify + bs = copy(as, nargout); + if ~isempty(mdl2) + mdl = copy(mdl2, nargout); + end + + if numel(bs) == 2 + % implementing here for 1D + in(1) = bs(1); + n(1) = bs(2); + + + + % fft + i1 = fft(in(1)); + Nsamples = length(i1.x); + if ~isempty(f1) && ~isempty(f2) + i1 = split(i1,plist('frequencies',[f1 f2])); + elseif ~isempty(freqs) + i1 = split(i1,plist('frequencies',freqs)); + i1 = join(i1); + end + + % get frequency vector + f = i1.x; + + if ~isempty(mdl) + % get model + h(1) = mdl; + h(1).setXvals(f); + else + error('### One model should be introduced, please check the help.') + end + + elseif numel(bs) == 3 + if numel(mdl) == 2 + in(1) = bs(1); + in(2) = bs(2); + n(1) = bs(3); + + % fft + i1 = fft(in(1)); + Nsamples = length(i1.x); + i2 = fft(in(2)); + + % Get rid of fft f =0, reduce frequency range if needed + if ~isempty(f1) && ~isempty(f2) + i1 = split(i1,plist('frequencies',[f1 f2])); + i2 = split(i2,plist('frequencies',[f1 f2])); + elseif ~isempty(freqs) + i1 = split(i1,plist('frequencies',freqs)); + i1 = join(i1); + i2 = split(i2,plist('frequencies',freqs)); + i2 = join(i2); + end + + % get frequency vector + f = i1.x; + + if ~isempty(mdl) + % compute built-in matrix + h(1) = mdl(1); + h(1).setXvals(f); + h(2) = mdl(2); + h(2).setXvals(f); + else + error('### One model should be introduced, please check the help.') + end + elseif numel(mdl) == 1 + error('Check the model or use crbound with the matrix class') + end + % Get input objects + elseif numel(bs) == 4 + in(1) = bs(1); + in(2) = bs(2); + n(1) = bs(3); + n(2) = bs(4); + + % fft + i1 = fft(in(1)); + Nsamples = length(i1.x); + i2 = fft(in(2)); + + % Get rid of fft f =0, reduce frequency range if needed + if ~isempty(f1) && ~isempty(f2) + i1 = split(i1,plist('frequencies',[f1 f2])); + i2 = split(i2,plist('frequencies',[f1 f2])); + elseif ~isempty(freqs) + i1 = split(i1,plist('frequencies',freqs)); + i1 = join(i1); + i2 = split(i2,plist('frequencies',freqs)); + i2 = join(i2); + end + + % get frequency vector + f = i1.x; + + if ~isempty(bmdl) + % compute built-in smodels + for i = 1:4 + if strcmp(bmdl{i},'0'); + h(i) = smodel('0'); + h(i).setXvar('f'); + h(i).setXvals(f); + else + h(i) = smodel(plist('built-in',bmdl{i},'f',f)); + % set all params to all models. It is not true but harmless + for k = 1:numel(params) + vecparams(k) = {numparams(k)*ones(size(f))}; + end + h(i).setParams(params,vecparams); + end + end + elseif ~isempty(mdl) + % compute built-in matrix + h(1) = mdl{1}; + h(1).setXvals(f); + h(2) = mdl{2}; + h(2).setXvals(f); + h(3) = mdl{3}; + h(3).setXvals(f); + h(4) = mdl{4}; + h(4).setXvals(f); + end + + else + error('### The number of input in crbound objects is not correct, please check the help.') + end + + % Set params + for i = 1:numel(h) + h(i).setParams(params,numparams); + end + + if numel(bs) == 2 + % Compute psd + n1 = psd(n(1), pl); + + % interpolate to fft frequencies + S11 = interp(n1,plist('vertices',f)); + + for i = 1:length(params) + utils.helper.msg(msg.IMPORTANT, sprintf('computing symbolic differentiation with respect %s',params{i}), mfilename('class'), mfilename); + % differentiate symbolically + dH11 = diff(h(1),params{i}); + % evaluate + d11(i) = eval(dH11); + end + + % get some parameters used below + fs = S11.fs; +% N = len(S11); + Navs = find(pl,'Navs'); + + % scaling of PSD + % PSD = 2/(N*fs) * FFT *conj(FFT) + C11 = Nsamples*fs/2.*S11.y; + + InvS11 = 1./C11; + + % compute Fisher Matrix + for i =1:length(params) + for j =1:length(params) + v1v1 = conj(d11(i).y.*i1.y).*(d11(j).y.*i1.y); + + FisMat(i,j) = sum(real(InvS11.*v1v1)); + end + end + + elseif numel(bs) == 3 + + if numel(mdl) == 2 + % Compute psd + n1 = psd(n(1), pl); + + % interpolate to fft frequencies + S11 = interp(n1,plist('vertices',f)); + + for i = 1:length(params) + utils.helper.msg(msg.IMPORTANT, sprintf('computing symbolic differentiation with respect %s',params{i}), mfilename('class'), mfilename); + % differentiate symbolically + dH11 = diff(h(1),params{i}); + dH12 = diff(h(2),params{i}); + + % evaluate + d11(i) = eval(dH11); + d12(i) = eval(dH12); + end + + % get some parameters used below + fs = S11.fs; +% N = len(S11); + Navs = find(pl,'Navs'); + + % scaling of PSD + % PSD = 2/(N*fs) * FFT *conj(FFT) + C11 = Nsamples*fs/2.*S11.y; + + % compute elements of inverse cross-spectrum matrix + InvS11 = 1./C11; + + % compute Fisher Matrix + for i =1:length(params) + for j =1:length(params) + v1v1 = conj(d11(i).y.*i1.y + d12(i).y.*i2.y).*(d11(j).y.*i1.y + d12(j).y.*i2.y); + + FisMat(i,j) = sum(real(InvS11.*v1v1)); + end + end + + elseif numel(mdl) == 1 + error('Please check model sizes') + end + + + elseif numel(bs) == 4 + + % Compute psd + n1 = psd(n(1), pl); + n2 = psd(n(2), pl); + n12 = cpsd(n(1),n(2), pl); + + % interpolate to fft frequencies + S11 = interp(n1,plist('vertices',f)); + S12 = interp(n12,plist('vertices',f)); + S22 = interp(n2,plist('vertices',f)); + S21 = conj(S12); + + for i = 1:length(params) + utils.helper.msg(msg.IMPORTANT, sprintf('computing symbolic differentiation with respect %s',params{i}), mfilename('class'), mfilename); + % differentiate symbolically + dH11 = diff(h(1),params{i}); + dH12 = diff(h(2),params{i}); + dH21 = diff(h(3),params{i}); + dH22 = diff(h(4),params{i}); + % evaluate + d11(i) = eval(dH11); + d12(i) = eval(dH12); + d21(i) = eval(dH21); + d22(i) = eval(dH22); + end + + % get some parameters used below + fs = S11.fs; +% N = len(S11); + Navs = find(pl,'Navs'); + + % scaling of PSD + % PSD = 2/(N*fs) * FFT *conj(FFT) + C11 = Nsamples*fs/2.*S11.y; + C22 = Nsamples*fs/2.*S22.y; + C12 = Nsamples*fs/2.*S12.y; + C21 = Nsamples*fs/2.*S21.y; + + % compute elements of inverse cross-spectrum matrix + InvS11 = (C22./(C11.*C22 - C12.*C21)); + InvS22 = (C11./(C11.*C22 - C12.*C21)); + InvS12 = (C21./(C11.*C22 - C12.*C21)); + InvS21 = (C12./(C11.*C22 - C12.*C21)); + + % compute Fisher Matrix + for i =1:length(params) + for j =1:length(params) + + v1v1 = conj(d11(i).y.*i1.y + d12(i).y.*i2.y).*(d11(j).y.*i1.y + d12(j).y.*i2.y); + v2v2 = conj(d21(i).y.*i1.y + d22(i).y.*i2.y).*(d21(j).y.*i1.y + d22(j).y.*i2.y); + v1v2 = conj(d11(i).y.*i1.y + d12(i).y.*i2.y).*(d21(j).y.*i1.y + d22(j).y.*i2.y); + v2v1 = conj(d21(i).y.*i1.y + d22(i).y.*i2.y).*(d11(j).y.*i1.y + d12(j).y.*i2.y); + + FisMat(i,j) = sum(real(InvS11.*v1v1 + InvS22.*v2v2 - InvS12.*v1v2 - InvS21.*v2v1)); + end + end + + end + + % inverse is the optimal covariance matrix + if pseudoinv && isempty(tol) + cov = pinv(FisMat); + elseif pseudoinv + cov = pinv(FisMat,tol); + else + cov = FisMat\eye(size(FisMat)); + end + + % create AO + out = ao(cov); + % Fisher Matrix in the procinfo + out.setProcinfo(plist('FisMat',FisMat)); + + 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: crbound.m,v 1.13 2011/04/08 08:56:17 hewitson 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({'params', 'Parameters of the model'}, paramValue.EMPTY_STRING); + pl.append(p); + + p = plist({'models','Symbolic models of the system'}, 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); + +end