Mercurial > hg > ltpda
comparison m-toolbox/classes/@matrix/modelselect.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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
2 % | |
3 % modelselect.m - method to compute the Bayes Factor using | |
4 % reverse jump mcmc algorithm | |
5 % | |
6 % call - Bxy = modelselect(out,pl) | |
7 % | |
8 % inputs - out: matrix objects with measured outputs | |
9 % pl: parameter list | |
10 % | |
11 % outputs - Bxy: an array of AOs containing the evolution | |
12 % of the Bayes factors. (comparing each model | |
13 % with each other) | |
14 % | |
15 % | |
16 % <a href="matlab:utils.helper.displayMethodInfo('matrix','modelselect')">Parameters Description</a> | |
17 % | |
18 % N. Karnesis 27/09/2011 | |
19 % | |
20 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
21 | |
22 function varargout = modelselect(varargin) | |
23 | |
24 % Check if this is a call for parameters | |
25 if utils.helper.isinfocall(varargin{:}) | |
26 varargout{1} = getInfo(varargin{3}); | |
27 return | |
28 end | |
29 | |
30 import utils.const.* | |
31 utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename); | |
32 | |
33 % Method can not be used as a modifier | |
34 if nargout == 0 | |
35 error('### mcmc cannot be used as a modifier. Please give an output variable.'); | |
36 end | |
37 | |
38 % Collect input variable names | |
39 in_names = cell(size(varargin)); | |
40 for ii = 1:nargin,in_names{ii} = inputname(ii);end | |
41 | |
42 % Collect all AOs smodels and plists | |
43 [mtxs, mtxs_invars] = utils.helper.collect_objects(varargin(:), 'matrix', in_names); | |
44 pl = utils.helper.collect_objects(varargin(:), 'plist', in_names); | |
45 | |
46 % Combine plists | |
47 pl = parse(pl, getDefaultPlist); | |
48 | |
49 % Get parameters | |
50 N = find(pl, 'N'); | |
51 Tc = find(pl,'Tc'); | |
52 xi = find(pl,'heat'); | |
53 param = find(pl,'FitParams'); | |
54 cvar = find(pl, 'cov'); | |
55 rng = find(pl,'range'); | |
56 flim = find(pl,'frequencies'); | |
57 fsout = find(pl,'fsout'); | |
58 search = find(pl,'search'); | |
59 xo = find(pl,'x0'); | |
60 mtxin = find(pl,'input'); | |
61 mdlin = find(pl,'models'); | |
62 mdlFreqDependent = find(pl,'modelFreqDependent'); | |
63 nse = find(pl,'noise'); | |
64 jumps = find(pl,'jumps'); | |
65 parplot = find(pl,'plot'); | |
66 debug = find(pl,'debug'); | |
67 outModel = find(pl,'outModel'); | |
68 inModel = find(pl,'inModel1'); | |
69 outNames = find(pl,'outNames'); | |
70 inNames = find(pl,'inNames'); | |
71 anneal = find(pl,'anneal'); | |
72 DeltaL = find(pl,'DeltaL'); | |
73 SNR0 = find(pl,('SNR0')); | |
74 | |
75 nummodels = numel(mdlin); | |
76 | |
77 % Decide on a deep copy or a modify | |
78 in = copy(mtxin, nargout); | |
79 out = copy(mtxs, nargout); | |
80 for k = 1:nummodels | |
81 mdl(k) = copy(mdlin{1,k}, nargout); | |
82 nparam(k) = numel(param{1,k}); | |
83 % lighten the model | |
84 mdl(k).clearHistory; | |
85 if isa(mdl(k), 'ssm') | |
86 mdl(k).clearNumParams; | |
87 mdl(k).clearAllUnits; | |
88 mdl(k).params.simplify; | |
89 end | |
90 end | |
91 | |
92 | |
93 | |
94 % Check input parameters | |
95 if isempty(rng) | |
96 error('### Please define a search range ''range'''); | |
97 end | |
98 if isempty(param) | |
99 error('### Please define the parameters ''param'''); | |
100 end | |
101 if size(mdl(1)) ~= size(nse) | |
102 error('### Parameters ''model'' and ''noise'' must be the same dimension'); | |
103 end | |
104 if size(in) ~= size(out) | |
105 error('### Number of input and output experiments must be the same'); | |
106 end | |
107 | |
108 | |
109 % Get range for parameters | |
110 for jj = 1:nummodels | |
111 for i = 1:numel(param{1,jj}) | |
112 rang{1,jj}(:,i) = rng{1,jj}{i}'; | |
113 end | |
114 end | |
115 % Get number of experiments | |
116 nexp = numel(in); | |
117 | |
118 switch class(mdl) | |
119 case 'matrix' | |
120 % Check model sizes | |
121 for k = 1:nummodels | |
122 if (isempty(outModel) && isempty(inModel)) | |
123 if (~(numel(in(1).objs) == mdl(k).ncols) || ~(numel(out(1).objs) == mdl(k).nrows)) | |
124 error('Check model or input/output sizes'); | |
125 end | |
126 elseif isempty(inModel) | |
127 if (~(numel(in(1).objs) == mdl(k).ncols) || ~(size(outModel,2) == mdl(k).nrows) || ~(size(outModel,1) == numel(out(1).objs))) | |
128 error('Check model or input/output sizes'); | |
129 end | |
130 elseif isempty(outModel) | |
131 if (~(numel(in(1).objs) == size(inModel,2)) || ~(size(inModel,1) == mdl(k).ncols) || ~(numel(out(1).objs) == mdl(k).nrows)) | |
132 error('Check model or input/output sizes'); | |
133 end | |
134 else | |
135 if (~(numel(in(1).objs) == size(inModel,2)) || ~(size(inModel,1) == mdl(k).ncols) || ~(size(outModel,2) == mdl(k).nrows) || ~(numel(out(1).objs) == size(outModel,1))) | |
136 error('Check model or input/output sizes'); | |
137 end | |
138 end | |
139 end | |
140 case 'ssm' | |
141 inNames = find(pl,'inNames'); | |
142 outNames = find(pl,'outNames'); | |
143 if( (numel(inNames) ~= numel(in(1).objs)) || numel(outNames) ~= numel(out(1).objs)) | |
144 error('Check model inNames and outNames, they do not match with the input objects') | |
145 end | |
146 otherwise | |
147 error('### Model must be either from the ''matrix'' or the ''ssm'' class. Please check the inputs') | |
148 end | |
149 | |
150 | |
151 | |
152 %%%%%%%%%%%%%%%%%%%%%%%%%%%% Frequency domain pre-process %%%%%%%%%%%%%%%%%%%%%%%% | |
153 | |
154 utils.helper.msg(msg.IMPORTANT, 'Computing frequency domain objects', mfilename('class'), mfilename); | |
155 for k = 1:nexp | |
156 | |
157 if((numel(out(1).objs) == 2) && (numel(in(1).objs) == 2)) % previous code done by miquel | |
158 % optional resampling (not matrix/resample method yet) | |
159 if ~isempty(fsout) | |
160 for i = 1:numel(in(k).objs(:)) | |
161 in(k).objs(i).resample(plist('fsout',fsout)); | |
162 out(k).objs(i).resample(plist('fsout',fsout)); | |
163 end | |
164 end | |
165 | |
166 % fft | |
167 fin(k) = fft(in(k)); | |
168 fout(k) = fft(out(k)); | |
169 | |
170 Nsamples = length(fin(k).getObjectAtIndex(1).x); | |
171 fs = fin(k).getObjectAtIndex(1).fs; | |
172 | |
173 | |
174 if (isempty(outModel)) | |
175 % Get rid of fft f =0, reduce frequency range if needed | |
176 if ~isempty(flim) | |
177 fin(k) = split(fin(k),plist('frequencies',[flim(1) flim(end)])); | |
178 fout(k) = split(fout(k),plist('frequencies',[flim(1) flim(end)])); | |
179 end | |
180 elseif (~isempty(outModel)) | |
181 % Get rid of fft f =0, reduce frequency range if needed | |
182 if ~isempty(flim) | |
183 fin(k) = split(fin(k),plist('frequencies',[flim(1) flim(end)])); | |
184 fout(k) = split(fout(k),plist('frequencies',[flim(1) flim(end)])); | |
185 if(~isempty(outModel)) | |
186 for lll=1:size(outModel,1) | |
187 for kkk=1:size(outModel,2) | |
188 outModel(lll,kkk) = split(outModel(lll,kkk),plist('frequencies',[flim(1) flim(end)])); | |
189 end | |
190 end | |
191 end | |
192 if(~isempty(inModel)) | |
193 inModel = split(inModel,plist('frequencies',[flim(1) flim(end)])); | |
194 end | |
195 end | |
196 end | |
197 | |
198 % use signal fft to get frequency vector. Take into account signal | |
199 % could be empty or set to zero | |
200 | |
201 % 1st channel | |
202 if all(fin(k).getObjectAtIndex(1,1).y == 0) || isempty(fin(k).getObjectAtIndex(1,1).y) | |
203 i1 = ao(plist('type','fsdata','xvals',0,'yvals',0)); | |
204 % rebuild input with new zeroed signal | |
205 fin(k) = matrix(i1,fin(k).getObjectAtIndex(2,1),plist('shape',[2 1])); | |
206 else | |
207 freqs = fin(k).getObjectAtIndex(1,1).x; | |
208 end | |
209 % 2nd channel | |
210 if all(fin(k).getObjectAtIndex(2,1).y == 0) || isempty(fin(k).getObjectAtIndex(2,1).y) | |
211 i2 = ao(plist('type','fsdata','xvals',0,'yvals',0)); | |
212 % rebuild input with new zeroed signal | |
213 fin(k) = matrix(fin(k).getObjectAtIndex(1,1),i2,plist('shape',[2 1])); | |
214 else | |
215 freqs = fin(k).getObjectAtIndex(2,1).x; | |
216 end | |
217 | |
218 % Compute psd | |
219 n1 = Nsamples*fs/2*psd(nse(k).getObjectAtIndex(1,1), pl); | |
220 n2 = Nsamples*fs/2*psd(nse(k).getObjectAtIndex(2,1), pl); | |
221 n12 = Nsamples*fs/2*cpsd(nse(k).getObjectAtIndex(1,1),nse(k).getObjectAtIndex(2,1), pl); | |
222 | |
223 % interpolate noise to fft frequencies | |
224 S11 = interp(n1,plist('vertices',freqs)); | |
225 S12 = interp(n12,plist('vertices',freqs)); | |
226 S22 = interp(n2,plist('vertices',freqs)); | |
227 S21 = conj(S12); | |
228 % build cross-spectrum matrix | |
229 mnse(k) = matrix(S11,S21,S12,S22,plist('shape',[2 2])); | |
230 | |
231 elseif((numel(out(1).objs) == 1) && (numel(in(1).objs) == 1)) | |
232 % optional resampling (not matrix/resample method yet) | |
233 if ~isempty(fsout) | |
234 for i = 1:numel(in(k).objs(:)) | |
235 in(k).objs(i).resample(plist('fsout',fsout)); | |
236 out(k).objs(i).resample(plist('fsout',fsout)); | |
237 end | |
238 end | |
239 | |
240 % fft | |
241 fin(k) = fft(in(k)); | |
242 fout(k) = fft(out(k)); | |
243 | |
244 Nsamples = length(fin(k).getObjectAtIndex(1).x); | |
245 fs = fin(k).getObjectAtIndex(1).fs; | |
246 | |
247 | |
248 if (isempty(outModel)) | |
249 % Get rid of fft f =0, reduce frequency range if needed | |
250 if ~isempty(flim) | |
251 fin(k) = split(fin(k),plist('frequencies',[flim(1) flim(end)])); | |
252 fout(k) = split(fout(k),plist('frequencies',[flim(1) flim(end)])); | |
253 end | |
254 elseif (~isempty(outModel)) | |
255 % Get rid of fft f =0, reduce frequency range if needed | |
256 if ~isempty(flim) | |
257 fin(k) = split(fin(k),plist('frequencies',[flim(1) flim(end)])); | |
258 fout(k) = split(fout(k),plist('frequencies',[flim(1) flim(end)])); | |
259 if(~isempty(outModel)) | |
260 for lll=1:size(outModel,1) | |
261 for kkk=1:size(outModel,2) | |
262 outModel(lll,kkk) = split(outModel(lll,kkk),plist('frequencies',[flim(1) flim(end)])); | |
263 end | |
264 end | |
265 end | |
266 if(~isempty(inModel)) | |
267 inModel = split(inModel,plist('frequencies',[flim(1) flim(end)])); | |
268 end | |
269 end | |
270 end | |
271 | |
272 % use signal fft to get frequency vector. Take into account signal | |
273 % could be empty or set to zero | |
274 | |
275 % 1st and only channel | |
276 if all(fin(k).getObjectAtIndex(1,1).y == 0) || isempty(fin(k).getObjectAtIndex(1,1).y) | |
277 i1 = ao(plist('type','fsdata','xvals',0,'yvals',0)); | |
278 % rebuild input with new zeroed signal | |
279 fin(k) = matrix(i1,fin(k).getObjectAtIndex(2,1),plist('shape',[2 1])); | |
280 else | |
281 freqs = fin(k).getObjectAtIndex(1,1).x; | |
282 end | |
283 | |
284 % Compute psd | |
285 n1 = Nsamples*fs/2*psd(nse(k).getObjectAtIndex(1,1), pl); | |
286 | |
287 % interpolate noise to fft frequencies | |
288 S11 = interp(n1,plist('vertices',freqs)); | |
289 | |
290 % build cross-spectrum matrix | |
291 mnse(k) = matrix(S11); | |
292 | |
293 else | |
294 error('### Sorry, implemented only for 2 inputs - 2 outputs and 1 input - 1 output only...') | |
295 end | |
296 | |
297 switch class(mdl) | |
298 | |
299 case 'matrix' | |
300 for jj = 1:nummodels | |
301 for i = 1:numel(mdl(jj).objs) | |
302 if (mdlFreqDependent) | |
303 % set Xvals | |
304 mdl(jj).objs(i).setXvals(freqs); | |
305 % set alias | |
306 mdl(jj).objs(i).assignalias(mdl(jj).objs(i),plist('xvals',freqs)); | |
307 else | |
308 mdl(jj).objs(i).setXvals(1); | |
309 end | |
310 end | |
311 end | |
312 case 'ssm' | |
313 if k < 2 | |
314 for jj = 1:nummodels | |
315 mdl(jj).clearNumParams; | |
316 spl = plist('set', 'for bode', ... | |
317 'outputs', outNames, ... | |
318 'inputs', inNames); | |
319 % first optimise our model for the case in hand | |
320 mdl(jj).reorganize(spl); | |
321 % make it lighter | |
322 mdl(jj).optimiseForFitting(); | |
323 end | |
324 end | |
325 end | |
326 % add lines to the matrix of models. Each line corresponds to one | |
327 % experiment | |
328 mmdl(k,:) = mdl; | |
329 end | |
330 | |
331 [Bxy LogLambda] = utils.math.rjsample(mmdl,fin,fout,mnse,cvar,N,rang,param,Tc,xi,xo,search,jumps,parplot,debug,inNames,outNames,anneal,SNR0,DeltaL,inModel,outModel); | |
332 | |
333 % Set output | |
334 numfactors = 0; | |
335 for gg = 1:(nummodels) | |
336 for dd = gg+1:(nummodels) | |
337 numfactors = numfactors + 1; | |
338 BayesFactor(numfactors) = ao(Bxy{gg,dd}); | |
339 BayesFactor(numfactors).setName(sprintf('B%d%d',gg,dd)); | |
340 BayesFactor(numfactors).procinfo = plist('Likelihoods',LogLambda); | |
341 end | |
342 end | |
343 | |
344 output = {BayesFactor}; | |
345 varargout = output(1:nargout); | |
346 | |
347 | |
348 end | |
349 | |
350 | |
351 %-------------------------------------------------------------------------- | |
352 % Get Info Object | |
353 %-------------------------------------------------------------------------- | |
354 function ii = getInfo(varargin) | |
355 if nargin == 1 && strcmpi(varargin{1}, 'None') | |
356 sets = {}; | |
357 pl = []; | |
358 else | |
359 sets = {'Default'}; | |
360 pl = getDefaultPlist; | |
361 end | |
362 % Build info object | |
363 ii = minfo(mfilename, 'ao', 'ltpda', utils.const.categories.sigproc, '$Id: mcmc.m,v 1.33 2011/07/31 17:38:34 nikos Exp $', sets, pl); | |
364 end | |
365 | |
366 %-------------------------------------------------------------------------- | |
367 % Get Default Plist | |
368 %-------------------------------------------------------------------------- | |
369 function plout = getDefaultPlist() | |
370 persistent pl; | |
371 if exist('pl', 'var')==0 || isempty(pl) | |
372 pl = buildplist(); | |
373 end | |
374 plout = pl; | |
375 end | |
376 | |
377 function pl = buildplist() | |
378 pl = plist(); | |
379 | |
380 % inNames | |
381 p = param({'inNames','Input names. Used for ssm models'}, paramValue.EMPTY_STRING); | |
382 pl.append(p); | |
383 | |
384 % outNames | |
385 p = param({'outNames','Output names. Usde for ssm models'}, paramValue.EMPTY_STRING); | |
386 pl.append(p); | |
387 | |
388 %Model | |
389 p = param({'model','An array input of models.'}, paramValue.EMPTY_STRING); | |
390 pl.append(p); | |
391 | |
392 % Param | |
393 p = param({'FitParams','A cell array of evaluated parameters for each model.'}, paramValue.EMPTY_DOUBLE); | |
394 pl.append(p); | |
395 | |
396 % Input | |
397 p = param({'input','A matrix array of input signals.'}, paramValue.EMPTY_STRING); | |
398 pl.append(p); | |
399 | |
400 pl = plist.MCH_FIT_PLIST; | |
401 | |
402 % N | |
403 p = param({'N','number of samples of the chain.'}, paramValue.DOUBLE_VALUE(1000)); | |
404 pl.append(p); | |
405 | |
406 % Sigma | |
407 p = param({'cov','Cell array containing the covariances of the gaussian jumping distribution for each model.'}, paramValue.DOUBLE_VALUE(1e-4)); | |
408 pl.append(p); | |
409 | |
410 % Noise | |
411 p = param({'noise','A matrix array of noise spectrum (PSD) used to compute the likelihood.'}, paramValue.EMPTY_STRING); | |
412 pl.append(p); | |
413 | |
414 % Search | |
415 p = param({'modelFreqDependent','Set to true to use frequency dependent s models, set to false when using constant models'}, paramValue.TRUE_FALSE); | |
416 pl.append(p); | |
417 | |
418 % Search | |
419 p = param({'search','Set to true to use bigger jumps in parameter space during annealing and cool down.'}, paramValue.TRUE_FALSE); | |
420 pl.append(p); | |
421 | |
422 % Frequencies | |
423 p = param({'frequencies','Range of frequencies where the analysis is performed. If an array, only first and last are used'}, paramValue.EMPTY_DOUBLE); | |
424 pl.append(p); | |
425 | |
426 % Resample | |
427 p = param({'fsout','Desired sampling frequency to resample the input time series'}, paramValue.EMPTY_DOUBLE); | |
428 pl.append(p); | |
429 | |
430 % heat | |
431 p = param({'heat','The heat index flattening likelihood surface during annealing.'}, paramValue.DOUBLE_VALUE(1)); | |
432 pl.append(p); | |
433 | |
434 % Tc | |
435 p = param({'Tc','An array of two values setting the initial and final value for the cooling down.'}, paramValue.EMPTY_STRING); | |
436 pl.append(p); | |
437 | |
438 % initial values | |
439 p = param({'x0','The proposed initial values (cell array again).'}, paramValue.EMPTY_DOUBLE); | |
440 pl.append(p); | |
441 | |
442 % ranges | |
443 p = param({'range','ranges'}, paramValue.EMPTY_DOUBLE); | |
444 pl.append(p); | |
445 | |
446 % jumps | |
447 p = param({'jumps','An array of four numbers setting the rescaling of the covariance matrix during the search phase.',... | |
448 'The first value is the one applied by default, the following thhree apply just when the chain sample is',... | |
449 'mod(10), mod(25) and mod(100) respectively.'}, paramValue.EMPTY_DOUBLE); | |
450 pl.append(p); | |
451 | |
452 % heat | |
453 p = param({'plot','If set equal to one, the evolution of the Bayes factor is plotted every 500 steps.'}, paramValue.EMPTY_DOUBLE); | |
454 pl.append(p); | |
455 | |
456 % debug | |
457 p = param({'debug','Set to true to get debug information of the MCMC process.'}, paramValue.FALSE_TRUE); | |
458 pl.append(p); | |
459 | |
460 % outModel | |
461 p = param({'outModel','Output model. Still under test'}, paramValue.EMPTY_STRING); | |
462 pl.append(p); | |
463 | |
464 p = param({'anneal',['Choose type of annealing during sampling. Default value is ',... | |
465 'simulated annealing. Choose "thermo" for annealing with a thermostat.',... | |
466 ' SNR is computed and if it is larger than a fixed value SNR0 (provided also in the plist), ',... | |
467 'then the chains are heated by a factor of (SNR(1)/SNR0)^2. Choosing "simple" ',... | |
468 'the deviation of the loglikelihood of every 10 points in the chains is stored. If this deviation ',... | |
469 'is larger or smaller than two fixed values the chains are cooled or heated respectively.']}, {1, {'simul','thermo', 'simple'}, paramValue.SINGLE}); | |
470 pl.append(p); | |
471 | |
472 p = param({'SNR0','Fixed value for thermostated annealing.'}, {1, {200}, paramValue.OPTIONAL}); | |
473 pl.append(p); | |
474 | |
475 p = param({'DeltaL',['Deviation of Loglikelihood for 10 points of the chains. Used for',... | |
476 'the "simple" choice of annealing with a thermostat.']}, {1, {[100 600 2 3]}, paramValue.OPTIONAL}); | |
477 pl.append(p); | |
478 | |
479 | |
480 end | |
481 | |
482 |