comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:f0afece42f48
1 % CRB computes the inverse of the Fisher Matrix
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %
4 % DESCRIPTION: CRB computes the inverse of the Fisher Matrix
5 %
6 % CALL: bs = crb(in,pl)
7 %
8 % INPUTS: in - matrix objects with input signals to the system
9 % model - symbolic models containing the transfer function model
10 %
11 % pl - parameter list
12 %
13 % OUTPUTS: bs - covariance matrix AO
14 %
15 % <a href="matlab:utils.helper.displayMethodInfo('matrix', 'crb')">Parameters Description</a>
16 %
17 % VERSION: $Id: crb.m,v 1.17 2011/10/07 08:19:55 miquel Exp $
18 %
19 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20
21 function varargout = crb(varargin)
22
23 % Check if this is a call for parameters
24 if utils.helper.isinfocall(varargin{:})
25 varargout{1} = getInfo(varargin{3});
26 return
27 end
28
29 import utils.const.*
30 utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename);
31
32 % Method can not be used as a modifier
33 if nargout == 0
34 error('### crb cannot be used as a modifier. Please give an output variable.');
35 end
36
37 % Collect input variable names
38 in_names = cell(size(varargin));
39 for ii = 1:nargin,in_names{ii} = inputname(ii);end
40
41 % Collect all AOs smodels and plists
42 [mtxs, mtxs_invars] = utils.helper.collect_objects(varargin(:), 'matrix', in_names);
43 pl = utils.helper.collect_objects(varargin(:), 'plist', in_names);
44
45 % Combine plists
46 pl = parse(pl, getDefaultPlist);
47
48 % get params
49 params = find(pl,'FitParams');
50 numparams = find(pl,'paramsValues');
51 mdl = find(pl,'model');
52 mtxns = find(pl,'noise');
53 outModel = find(pl,'outModel');
54 bmdl = find(pl,'built-in');
55 f1 = find(pl,'f1');
56 f2 = find(pl,'f2');
57 pseudoinv = find(pl,'pinv');
58 tol = find(pl,'tol');
59 outNames = find(pl,'outNames');
60 inNames = find(pl,'inNames');
61
62 % Decide on a deep copy or a modify
63 in = copy(mtxs, nargout);
64 n = copy(mtxns, nargout);
65
66 % Get number of experiments
67 nexp = numel(in);
68
69 % fft
70 fin = fft(in);
71
72 % N should get before spliting, in order to convert correctly from psd to
73 % fft
74 N = length(fin(1).getObjectAtIndex(1).x);
75
76 % Get rid of fft f =0, reduce frequency range if needed
77 if ~isempty(f1) && ~isempty(f2)
78 fin = split(fin,plist('frequencies',[f1 f2]));
79 end
80
81 FMall = zeros(numel(params),numel(params));
82 % loop over experiments
83 for k = 1:nexp
84
85 utils.helper.msg(msg.IMPORTANT, sprintf('Analysis of experiment #%d',k), mfilename('class'), mfilename);
86
87 if (((numel(n(1).objs)) == 1) && (numel(in(1).objs) == 1))
88
89 % use signal fft to get frequency vector.
90 i1 = fin(k).getObjectAtIndex(1,1);
91 freqs = i1.x;
92
93 FisMat = utils.math.fisher_1x1(i1,n(k),mdl,params,numparams,freqs,N,pl,inNames,outNames);
94 % store Fisher Matrix for this run
95 FM{k} = FisMat;
96 % adding up
97 FMall = FMall + FisMat;
98
99 elseif (((numel(n(1).objs)) == 2) && (numel(in(1).objs) == 2))
100 % use signal fft to get frequency vector. Take into account signal
101 % could be empty or set to zero
102 % 1st channel
103 if all(fin(k).getObjectAtIndex(1,1).y == 0) || isempty(fin(k).getObjectAtIndex(1,1).y)
104 i1 = ao(plist('type','fsdata','xvals',0,'yvals',0));
105 else
106 i1 = fin(k).getObjectAtIndex(1,1);
107 freqs = i1.x;
108 end
109 % 2nd channel
110 if all(fin(k).getObjectAtIndex(2,1).y == 0) || isempty(fin(k).getObjectAtIndex(2,1).y)
111 i2 = ao(plist('type','fsdata','xvals',0,'yvals',0));
112 else
113 i2 = fin(k).getObjectAtIndex(2,1);
114 freqs = i2.x;
115 end
116
117 FisMat = utils.math.fisher_2x2(i1,i2,n(k),mdl,params,numparams,freqs,N,pl,inNames,outNames);
118 % store Fisher Matrix for this run
119 FM{k} = FisMat;
120 % adding up
121 FMall = FMall + FisMat;
122
123 elseif ((numel(n(1).objs) == 3) && (numel(in.objs) == 4) && ~isempty(outModel))
124 % this is only valid for the magnetic model, where we have 4 inputs
125 % (corresponding to the 4 conformator waveforms) and 3 outputs
126 % (corresponding to IFO.x12, IFO.eta1 and IFO.phi1). And there is a
127 % contribution of an outModel converting the conformator waveforms
128 % into forces and torques.
129
130
131 % For other cases not implemented yet.
132
133 % use signal fft to get frequency vector. Take into account signal
134 % could be empty or set to zero
135 % 1st channel
136 freqs = fin.getObjectAtIndex(1,1).x;
137
138 for ii = 1:numel(n.objs)
139 for jj = ii:numel(n.objs)
140 % Compute psd
141 if (ii==jj)
142 spec(ii,jj) = psd(n(k).getObjectAtIndex(ii), pl);
143 S2(ii,jj) = interp(spec(ii,jj),plist('vertices',freqs,'method','linear'));
144 else
145 spec(ii,jj) = cpsd(n(k).getObjectAtIndex(ii),n(k).getObjectAtIndex(jj),pl);
146 S2(ii,jj) = interp(spec(ii,jj),plist('vertices',freqs,'method','linear'));
147 S2(jj,ii) = conj(S2(ii,jj));
148 end
149 end
150 end
151
152 S = matrix(S2,plist('shape',[numel(n.objs) numel(n.objs)]));
153
154 % get some parameters used below
155 fs = S.getObjectAtIndex(1,1).fs;
156
157
158 if(~isempty(outModel))
159 for lll=1:size(outModel,1)
160 for kkk=1:size(outModel,2)
161 outModel(lll,kkk) = split(outModel(lll,kkk),plist('frequencies',[f1 f2]));
162 end
163 end
164 end
165
166 % Avoid numerical differentiation (faster for the magnetic case)
167 Param{1} = [ 1 0 0 0;
168 0 0 0 0;
169 0 0 0 0;];
170 Param{2} = [ 0 1 0 0;
171 0 0 0 0;
172 0 0 0 0;];
173 Param{3} = [ 0 0 0 0;
174 0 0 1 0;
175 0 0 0 0;];
176 Param{4} = [ 0 0 0 0;
177 0 0 0 0;
178 0 0 0 1;];
179
180 % scaling of PSD
181 % PSD = 2/(N*fs) * FFT *conj(FFT)
182 for j = 1: numel(S.objs)
183 % spectra to variance
184 C(:,j) = (N*fs/2)*S.objs(j).data.getY;
185 end
186
187 detm = (C(:,1).*C(:,5).*C(:,9) + ...
188 C(:,2).*C(:,6).*C(:,7) + ...
189 C(:,3).*C(:,4).*C(:,8) -...
190 C(:,7).*C(:,5).*C(:,3) -...
191 C(:,8).*C(:,6).*C(:,1) -...
192 C(:,9).*C(:,4).*C(:,2));
193
194 InvS11 = (C(:,5).*C(:,9) - C(:,8).*C(:,6))./detm;
195 InvS12 = -(C(:,4).*C(:,9) - C(:,7).*C(:,6))./detm;
196 InvS13 = (C(:,4).*C(:,8) - C(:,7).*C(:,5))./detm;
197 InvS21 = -(C(:,2).*C(:,9) - C(:,8).*C(:,3))./detm;
198 InvS22 = (C(:,1).*C(:,9) - C(:,7).*C(:,3))./detm;
199 InvS23 = -(C(:,1).*C(:,8) - C(:,7).*C(:,2))./detm;
200 InvS31 = (C(:,2).*C(:,6) - C(:,5).*C(:,3))./detm;
201 InvS32 = -(C(:,1).*C(:,6) - C(:,4).*C(:,3))./detm;
202 InvS33 = (C(:,1).*C(:,5) - C(:,4).*C(:,2))./detm;
203
204 for pp = 1:length(params)
205 for ll = 1:size(outModel,1)
206 for kk = 1:size(Param{pp},2)
207 % index convention: H(1,1)->h(1) H(2,1)->h(2) H(1,2)->h(3) H(2,2)->h(4)
208 tmp = 0;
209 for innerIndex = 1:size(outModel,2)
210 tmp = tmp + outModel(ll,innerIndex).y * Param{pp}(innerIndex,kk);
211 end
212 h{pp}(:,(kk-1)*size(outModel,1) + ll) = tmp;
213 end
214 end
215
216 end
217
218 for kk = 1:numel(in.objs)
219 inV(:,kk) = fin.objs(kk).data.getY;
220 end
221
222
223 % compute Fisher Matrix
224 for i =1:length(params)
225 for j =1:length(params)
226
227 for ll = 1:size(outModel,1)
228 tmp = 0;
229 for kk = 1:size(Param{1},2)
230 tmp = tmp + h{i}(:,(kk-1)*size(outModel,1) + ll).*inV(:,kk);
231 end
232 v{i}(:,ll) = tmp;
233 end
234
235
236 for ll = 1:size(outModel,1)
237 tmp = 0;
238 for kk = 1:size(Param{1},2)
239 tmp = tmp + h{j}(:,(kk-1)*size(outModel,1) + ll).*inV(:,kk);
240 end
241 v{j}(:,ll) = tmp;
242 end
243
244 v1v1 = conj(v{i}(:,1)).*v{j}(:,1);
245 v1v2 = conj(v{i}(:,1)).*v{j}(:,2);
246 v1v3 = conj(v{i}(:,1)).*v{j}(:,3);
247 v2v1 = conj(v{i}(:,2)).*v{j}(:,1);
248 v2v2 = conj(v{i}(:,2)).*v{j}(:,2);
249 v2v3 = conj(v{i}(:,2)).*v{j}(:,3);
250 v3v1 = conj(v{i}(:,3)).*v{j}(:,1);
251 v3v2 = conj(v{i}(:,3)).*v{j}(:,2);
252 v3v3 = conj(v{i}(:,3)).*v{j}(:,3);
253
254 FisMat(i,j) = sum(real(InvS11.*v1v1 +...
255 InvS12.*v1v2 +...
256 InvS13.*v1v3 +...
257 InvS21.*v2v1 +...
258 InvS22.*v2v2 +...
259 InvS23.*v2v3 +...
260 InvS31.*v3v1 +...
261 InvS32.*v3v2 +...
262 InvS33.*v3v3));
263 end
264 end
265 % store Fisher Matrix for this run
266 FM{k} = FisMat;
267 % adding up
268 FMall = FMall + FisMat;
269 else
270 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)');
271 end
272
273
274 end
275
276 % inverse is the optimal covariance matrix
277 if pseudoinv && isempty(tol)
278 cov = pinv(FMall);
279 elseif pseudoinv
280 cov = pinv(FMall,tol);
281 else
282 cov = FMall\eye(size(FMall));
283 end
284
285
286 % create AO
287 out = ao(cov);
288 % Fisher Matrix in the procinfo
289 out.setProcinfo(plist('FisMat',FM));
290
291 varargout{1} = out;
292 end
293
294
295 %--------------------------------------------------------------------------
296 % Get Info Object
297 %--------------------------------------------------------------------------
298 function ii = getInfo(varargin)
299 if nargin == 1 && strcmpi(varargin{1}, 'None')
300 sets = {};
301 pls = [];
302 else
303 sets = {'Default'};
304 pls = getDefaultPlist;
305 end
306 % Build info object
307 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);
308 end
309
310 %--------------------------------------------------------------------------
311 % Get Default Plist
312 %--------------------------------------------------------------------------
313 function plout = getDefaultPlist()
314 persistent pl;
315 if exist('pl', 'var')==0 || isempty(pl)
316 pl = buildplist();
317 end
318 plout = pl;
319 end
320
321 function pl = buildplist()
322 pl = plist.WELCH_PLIST;
323 pset(pl,'Navs',1)
324
325 p = plist({'f1', 'Initial frequency for the analysis'}, paramValue.EMPTY_DOUBLE);
326 pl.append(p);
327
328 p = plist({'f2', 'Final frequency for the analysis'}, paramValue.EMPTY_DOUBLE);
329 pl.append(p);
330
331 p = plist({'FitParamas', 'Parameters of the model'}, paramValue.EMPTY_STRING);
332 pl.append(p);
333
334 p = plist({'model','An array of matrix models'}, paramValue.EMPTY_STRING);
335 pl.append(p);
336
337 p = plist({'noise','An array of matrices with the cross-spectrum matrices'}, paramValue.EMPTY_STRING);
338 pl.append(p);
339
340 p = plist({'built-in','Symbolic models of the system as a string of built-in models'}, paramValue.EMPTY_STRING);
341 pl.append(p);
342
343 p = plist({'frequencies','Array of start/sop frequencies where the analysis is performed'}, paramValue.EMPTY_STRING);
344 pl.append(p);
345
346 p = plist({'pinv','Use the Penrose-Moore pseudoinverse'}, paramValue.TRUE_FALSE);
347 pl.append(p);
348
349 p = plist({'tol','Tolerance for the Penrose-Moore pseudoinverse'}, paramValue.EMPTY_DOUBLE);
350 pl.append(p);
351
352 p = plist({'step','Numerical differentiation step for ssm models'}, paramValue.EMPTY_DOUBLE);
353 pl.append(p);
354
355 p = plist({'ngrid','Number of points in the grid to compute the optimal differentiation step for ssm models'}, paramValue.EMPTY_DOUBLE);
356 pl.append(p);
357
358 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);
359 pl.append(p);
360 end