Mercurial > hg > ltpda
comparison m-toolbox/classes/+utils/@math/autocfit.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 % AUTOCFIT performs a fitting loop to identify model order and parameters. | |
2 % | |
3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
4 % DESCRIPTION: | |
5 % | |
6 % Perform a fitting loop to automatically identify model order and | |
7 % parameters in s-domain. Model identification is performed by 'vcfit' | |
8 % function. Output is a s-domain model expanded in partial fractions: | |
9 % | |
10 % r1 rN | |
11 % f(s) = ------- + ... + ------- + d | |
12 % s - p1 s - pN | |
13 % | |
14 % The function attempt to perform first the identification of a model | |
15 % with d = 0, then if the operation do not succeed, it try the | |
16 % identification with d different from zero. | |
17 % Identification loop stop when the stop condition is reached. Six | |
18 % stop criteria are available: | |
19 % | |
20 % Mean Squared Error | |
21 % Check if the normalized mean squared error is lower than the value | |
22 % specified in lrscond: | |
23 % mse < 10^(-1*lrsvarcond) | |
24 % | |
25 % Mean Squared Error and variation | |
26 % Check if the normalized mean squared error is lower than the value specified in | |
27 % lrscond and that the relative variation of the mean squared error is lower | |
28 % than the value provided. | |
29 % Checking algorithm is: | |
30 % mse < 10^(-1*lrsvarcond) | |
31 % Dmse < 10^(-1*msevar) | |
32 % | |
33 % Log Residuals difference | |
34 % Check if the minimum of the logarithmic difference between data and | |
35 % residuals is larger than a specified value. ie. if the conditioning | |
36 % value is 2, the function ensures that the difference between data and | |
37 % residuals is at lest 2 order of magnitude lower than data itsleves. | |
38 % Checking algorithm is: | |
39 % lsr = log10(abs(y))-log10(abs(rdl)); | |
40 % min(lsr) > lrscond; | |
41 % | |
42 % Log Residuals difference and Root Mean Squared Error | |
43 % Check if the log difference between data and residuals is in | |
44 % larger than the value indicated in lsrcond and that the variation of | |
45 % the root mean squared error is lower than 10^(-1*msevar). | |
46 % Checking algorithm is: | |
47 % lsr = log10(abs(y))-log10(abs(rdl)); | |
48 % (lsr > lrscond) && (mse < 10^(-1*lrsvarcond)); | |
49 % | |
50 % Residuals Spectral Flatness | |
51 % In case of a fit on noisy data, the residuals from a good fit are | |
52 % expected to be as much as possible similar to a white noise. This | |
53 % property can be used to test the accuracy of a fit procedure. In | |
54 % particular it can be tested that the spectral flatness coefficient of | |
55 % the residuals is larger than a certain qiantity sf such that 0<sf<1. | |
56 % | |
57 % Residuals Spectral Flatness and root mean squared error | |
58 % Check that the spectral flatness coefficient of the residuals is | |
59 % larger than a certain qiantity sf such that 0<sf<1 and that the | |
60 % variation of the root mean squared error is lower than | |
61 % 10^(-1*msevar). | |
62 % | |
63 % Once the loop iteration stops the parameters giving best Mean Square | |
64 % Error are output. | |
65 % | |
66 % CALL: | |
67 % | |
68 % [res,poles,dterm,mresp,rdl,mse] = autocfit(y,f,params) | |
69 % | |
70 % INPUT: | |
71 % | |
72 % - y are the data to be fitted. They represent the frequency response | |
73 % of a certain process. | |
74 % - f is the frequency vector in Hz | |
75 % - params is a struct containing identification parameters | |
76 % | |
77 % params.spolesopt = 0 --> use external starting poles | |
78 % params.spolesopt = 1 --> use real starting poles | |
79 % params.spolesopt = 2 --> use logspaced complex starting poles. | |
80 % Default option | |
81 % params.spolesopt = 3 --> use linspaced complex starting poles. | |
82 % | |
83 % params.extpoles = [] --> a vector with the starting poles. | |
84 % Providing a fixed set of starting poles fixes the function order so | |
85 % params.minorder and params.maxorder will be internally set to the | |
86 % poles vector length. | |
87 % | |
88 % params.fullauto = 0 --> Perform a fitting loop as far as the number | |
89 % of iteration reach Nmaxiter. The order of the fitting function will | |
90 % be that specified in params.minorder. If params.dterm is setted to | |
91 % 1 the function will fit only with direct term. | |
92 % params.fullauto = 1 --> Parform a full automatic search for the | |
93 % transfer function order. The fitting procedure will stop when the | |
94 % stopping condition defined in params.ctp is satisfied. Default | |
95 % value. | |
96 % | |
97 % params.Nmaxiter = # --> Number of maximum iteration per model order | |
98 % parformed. Default is 50. | |
99 % | |
100 % params.minorder = # --> Minimum model trial order. Default is 2. | |
101 % | |
102 % params.maxorder = # --> Maximum model trial order. Default is 25. | |
103 % | |
104 % params.weightparam = 0 --> use external weights | |
105 % params.weightparam = 1 --> fit with equal weights (one) for each | |
106 % data point. | |
107 % params.weightparam = 2 --> weight fit with the inverse of absolute | |
108 % value of data. Default value. | |
109 % params.weightparam = 3 --> weight fit with the square root of the | |
110 % inverse of absolute value of data. | |
111 % params.weightparam = 4 --> weight fit with inverse of the square | |
112 % mean spread | |
113 % | |
114 % params.extweights = [] --> A vector of externally provided weights. | |
115 % It has to be of the same size of input data. | |
116 % | |
117 % params.plot = 0 --> no plot during fit iteration | |
118 % params.plot = 1 --> plot results at each fitting steps. default | |
119 % value. | |
120 % | |
121 % params.ctp = 'lrs' --> check if the log difference between data and | |
122 % residuals is point by point larger than the value indicated in | |
123 % lsrcond. This mean that residuals are lsrcond order of magnitudes | |
124 % lower than data. | |
125 % params.ctp = 'lrsmse' --> check if the log difference between data | |
126 % and residuals is larger than the value indicated in lsrcond and if | |
127 % the variation of root mean squared error is lower than | |
128 % 10^(-1*msevar). | |
129 % params.ctp = 'rft' --> check that the residuals spectral flatness | |
130 % coefficient is lerger than the value provided in lsrcond. In this | |
131 % case lsrcond must be such that 0<lsrcond<1. | |
132 % params.ctp = 'rftmse' --> check that the residuals spectral flatness | |
133 % coefficient is lerger than the value provided in lsrcond and if | |
134 % the variation of root mean squared error is lower than | |
135 % 10^(-1*msevar). In this case lsrcond must be such that | |
136 % 0<lsrcond<1. | |
137 % | |
138 % params.lrscond = # --> set conditioning value for point to point | |
139 % log residuals difference (params.ctp = 'lsr' and params.ctp = | |
140 % 'lrsmse') or set conditioning value for residuals spectral | |
141 % flateness (params.ctp = 'rft' and params.ctp = 'rftmse'). In the | |
142 % last case params.lrscond must be set to 0<lrscond<1. | |
143 % Default is 2. See help for stopfit.m for further remarks. | |
144 % | |
145 % params.msevar = # --> set conditioning value for root mean squared | |
146 % error variation. This allow to check that the variation of root | |
147 % mean squared error is lower than 10^(-1*msevar).Default is 7. See | |
148 % help for stopfit.m for further remarks. | |
149 % | |
150 % params.stabfit = 0 --> Fit without forcing poles stability. Default | |
151 % value. | |
152 % params.stabfit = 1 --> Fit forcing poles stability | |
153 % | |
154 % params.dterm = 0 --> Try to fit without direct term | |
155 % params.dterm = 1 --> Try to fit with and without direct term | |
156 % | |
157 % params.spy = 0 --> Do not display the iteration progression | |
158 % params.spy = 1 --> Display the iteration progression | |
159 % | |
160 % OUTPUT: | |
161 % | |
162 % - res is the vector with model residues r | |
163 % - poles is the vector with model poles p | |
164 % - dterm is the model direct term d | |
165 % - mresp is the model frequency response calculated at the input | |
166 % frequencies | |
167 % - rdl are the residuals between data and model, at the input | |
168 % frequencies | |
169 % - mse magnitude squared error progression | |
170 % | |
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
172 % VERSION: $Id: autocfit.m,v 1.22 2010/01/27 17:56:11 luigi Exp $ | |
173 % | |
174 % HISTORY: 08-10-2008 L Ferraioli | |
175 % Creation | |
176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
178 | |
179 function [res,poles,dterm,mresp,rdl,mse] = autocfit(y,f,params) | |
180 | |
181 utils.helper.msg(utils.const.msg.MNAME, 'running %s/%s', mfilename('class'), mfilename); | |
182 | |
183 % Default input struct | |
184 defaultparams = struct('spolesopt',1, 'Nmaxiter',30, 'minorder',2,... | |
185 'maxorder',25, 'weightparam',1, 'plot',1,... | |
186 'ctp','chival','lrscond',2,'msevar',2,... | |
187 'stabfit',0,'dterm',0,'spy',0,'fullauto',1,'extweights', [],... | |
188 'extpoles', []); | |
189 | |
190 names = {'spolesopt','Nmaxiter','minorder',... | |
191 'maxorder','weightparam','plot',... | |
192 'ctp','lrscond','msevar',... | |
193 'stabfit','dterm','spy','fullauto','extweights','extpoles'}; | |
194 | |
195 % collecting input and default params | |
196 if ~isempty(params) | |
197 for jj=1:length(names) | |
198 if isfield(params, names(jj)) && ~isempty(params.(names{1,jj})) | |
199 defaultparams.(names{1,jj}) = params.(names{1,jj}); | |
200 end | |
201 end | |
202 end | |
203 | |
204 % collecting input params | |
205 spolesopt = defaultparams.spolesopt; | |
206 Nmaxiter = defaultparams.Nmaxiter; | |
207 minorder = defaultparams.minorder; | |
208 maxorder = defaultparams.maxorder; | |
209 weightparam = defaultparams.weightparam; | |
210 check = defaultparams.plot; | |
211 stabfit = defaultparams.stabfit; | |
212 ctp = defaultparams.ctp; | |
213 lrscond = defaultparams.lrscond; | |
214 msevar = defaultparams.msevar; | |
215 idt = defaultparams.dterm; | |
216 spy = defaultparams.spy; | |
217 autosearch = defaultparams.fullauto; | |
218 extweights = defaultparams.extweights; | |
219 extpoles = defaultparams.extpoles; | |
220 | |
221 if check == 1 | |
222 fitin.plot = 1; | |
223 fitin.ploth = figure; % opening new figure window | |
224 else | |
225 fitin.plot = 0; | |
226 end | |
227 | |
228 if stabfit % fit with stable poles only | |
229 fitin.stable = 1; | |
230 else % fit without restrictions | |
231 fitin.stable = 0; | |
232 end | |
233 | |
234 % Colum vector are preferred | |
235 [a,b] = size(y); | |
236 if a < b % shifting to column | |
237 y = y.'; | |
238 end | |
239 [Nx,Ny] = size(y); | |
240 | |
241 [a,b] = size(f); | |
242 if a < b % shifting to column | |
243 f = f.'; | |
244 end | |
245 | |
246 % in case of externally provided poles | |
247 if ~isempty(extpoles) | |
248 spolesopt = 0; | |
249 end | |
250 if spolesopt == 0 % in case of external poles | |
251 % Colum vector are preferred | |
252 [a,b] = size(extpoles); | |
253 if a < b % shifting to column | |
254 extpoles = extpoles.'; | |
255 end | |
256 [Npls,b] = size(extpoles); | |
257 minorder = Npls; | |
258 maxorder = Npls; | |
259 end | |
260 | |
261 if weightparam == 0 % in case of external weights | |
262 % Colum vector are preferred | |
263 [a,b] = size(extweights); | |
264 if a < b % shifting to column | |
265 extweights = extweights.'; | |
266 end | |
267 end | |
268 | |
269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
270 % Importing package | |
271 import utils.math.* | |
272 | |
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
274 % Fitting | |
275 | |
276 % decide to fit with or without direct term according to the input | |
277 % options | |
278 if autosearch | |
279 if idt % full auto identification | |
280 dterm_off = 1; | |
281 dterm_on = 1; | |
282 else % auto ident without dterm | |
283 dterm_off = 1; | |
284 dterm_on = 0; | |
285 end | |
286 else | |
287 if idt % fit only with dterm | |
288 dterm_off = 0; | |
289 dterm_on = 1; | |
290 else % fit without dterm | |
291 dterm_off = 1; | |
292 dterm_on = 0; | |
293 end | |
294 end | |
295 | |
296 ext = zeros(Ny,1); | |
297 | |
298 % starting banana mse | |
299 bmse = inf; | |
300 cmse = inf; | |
301 | |
302 if dterm_off | |
303 utils.helper.msg(utils.const.msg.PROC1, ' Try fitting without direct term ') | |
304 fitin.dterm = 0; | |
305 | |
306 % Weighting coefficients | |
307 if weightparam == 0 | |
308 % using external weigths | |
309 utils.helper.msg(utils.const.msg.PROC1, ' Using external weights... ') | |
310 weight = extweights; | |
311 else | |
312 weight = utils.math.wfun(y,weightparam); | |
313 end | |
314 | |
315 % Do not perform the loop if autosearch is setted to false | |
316 if autosearch | |
317 order_vect = minorder:maxorder; | |
318 else | |
319 order_vect = minorder:minorder; | |
320 end | |
321 | |
322 for N = order_vect | |
323 | |
324 if spy | |
325 utils.helper.msg(utils.const.msg.PROC1, ['Actual_Order' num2str(N)]) | |
326 end | |
327 | |
328 % Starting poles | |
329 if spolesopt == 0 % in case of external poles | |
330 utils.helper.msg(utils.const.msg.PROC1, ' Using external poles... ') | |
331 spoles = extpoles; | |
332 else % internally calculated starting poles | |
333 pparams = struct('spolesopt',spolesopt, 'type','CONT', 'pamp', 0.01); | |
334 spoles = utils.math.startpoles(N,f,pparams); | |
335 end | |
336 | |
337 % Fitting | |
338 M = 2*N; | |
339 if M > Nmaxiter | |
340 M = Nmaxiter; | |
341 elseif not(autosearch) | |
342 M = Nmaxiter; | |
343 end | |
344 | |
345 clear mlr | |
346 | |
347 for hh = 1:M | |
348 [res,spoles,dterm,mresp,rdl,mse] = utils.math.vcfit(y,f,spoles,weight,fitin); % Fitting | |
349 | |
350 % decide to store the best result based on mse | |
351 %fprintf('iteration = %d, order = %d \n',hh,N) | |
352 if norm(mse)<cmse | |
353 %fprintf('nice job \n') | |
354 bres = res; | |
355 bpoles = spoles; | |
356 bdterm = dterm; | |
357 bmresp = mresp; | |
358 brdl = rdl; | |
359 bmse = mse; | |
360 cmse = norm(mse); | |
361 end | |
362 | |
363 if spy | |
364 utils.helper.msg(utils.const.msg.PROC1, ['Iter' num2str(hh)]) | |
365 end | |
366 | |
367 % ext = zeros(Ny,1); | |
368 if autosearch | |
369 for kk = 1:Ny | |
370 % Stop condition checking | |
371 mlr(hh,kk) = mse(:,kk); | |
372 % decide between stop conditioning | |
373 if strcmpi(ctp,'lrs') | |
374 yd = y(:,kk); % input data | |
375 elseif strcmpi(ctp,'lrsmse') | |
376 yd = y(:,kk); % input data | |
377 elseif strcmpi(ctp,'rft') | |
378 yd = mresp(:,kk); % model response | |
379 elseif strcmpi(ctp,'rftmse') | |
380 yd = mresp(:,kk); % model response | |
381 elseif strcmpi(ctp,'chival') | |
382 yd = y(:,kk); % model response | |
383 elseif strcmpi(ctp,'chivar') | |
384 yd = y(:,kk); % model response | |
385 else | |
386 error('!!! Unable to identify appropiate stop condition. See function help for admitted values'); | |
387 end | |
388 [next,msg] = utils.math.stopfit(yd,rdl(:,kk),mlr(:,kk),ctp,lrscond,msevar); | |
389 ext(kk,1) = next; | |
390 end | |
391 else | |
392 for kk = 1:Ny | |
393 % storing mse progression | |
394 mlr(hh,kk) = mse(:,kk); | |
395 end | |
396 end | |
397 | |
398 if all(ext) | |
399 utils.helper.msg(utils.const.msg.PROC1, msg) | |
400 break | |
401 end | |
402 | |
403 end | |
404 if all(ext) | |
405 break | |
406 end | |
407 | |
408 end | |
409 end | |
410 | |
411 if dterm_on | |
412 if ~all(ext) % fit with direct term only if the fit without does not give acceptable results (in full auto mode) | |
413 utils.helper.msg(utils.const.msg.PROC1, ' Try fitting with direct term ') | |
414 fitin.dterm = 1; | |
415 | |
416 if autosearch | |
417 order_vect = minorder:maxorder; | |
418 else | |
419 order_vect = minorder:minorder; | |
420 end | |
421 | |
422 for N = order_vect | |
423 | |
424 if spy | |
425 utils.helper.msg(utils.const.msg.PROC1, ['Actual_Order' num2str(N)]) | |
426 end | |
427 | |
428 % Starting poles | |
429 if spolesopt == 0 % in case of external poles | |
430 utils.helper.msg(utils.const.msg.PROC1, ' Using external poles... ') | |
431 spoles = extpoles; | |
432 else % internally calculated starting poles | |
433 pparams = struct('spolesopt',spolesopt, 'type','CONT', 'pamp', 0.01); | |
434 spoles = utils.math.startpoles(N,f,pparams); | |
435 end | |
436 | |
437 % Fitting | |
438 M = 2*N; | |
439 if M > Nmaxiter | |
440 M = Nmaxiter; | |
441 elseif not(autosearch) | |
442 M = Nmaxiter; | |
443 end | |
444 | |
445 clear mlr | |
446 | |
447 for hh = 1:M | |
448 [res,spoles,dterm,mresp,rdl,mse] = utils.math.vcfit(y,f,spoles,weight,fitin); % Fitting | |
449 | |
450 % decide to store the best result based on mse | |
451 if norm(mse)<cmse | |
452 bres = res; | |
453 bpoles = spoles; | |
454 bdterm = dterm; | |
455 bmresp = mresp; | |
456 brdl = rdl; | |
457 bmse = mse; | |
458 cmse = norm(mse); | |
459 end | |
460 | |
461 if spy | |
462 utils.helper.msg(utils.const.msg.PROC1, ['Iter' num2str(hh)]) | |
463 end | |
464 | |
465 ext = zeros(Ny,1); | |
466 if autosearch | |
467 for kk = 1:Ny | |
468 % Stop condition checking | |
469 mlr(hh,kk) = mse(:,kk); | |
470 % decide between stop conditioning | |
471 if strcmpi(ctp,'lrs') | |
472 yd = y(:,kk); % input data | |
473 elseif strcmpi(ctp,'lrsmse') | |
474 yd = y(:,kk); % input data | |
475 elseif strcmpi(ctp,'rft') | |
476 yd = mresp(:,kk); % model response | |
477 elseif strcmpi(ctp,'rftmse') | |
478 yd = mresp(:,kk); % model response | |
479 elseif strcmpi(ctp,'chival') | |
480 yd = y(:,kk); % model response | |
481 elseif strcmpi(ctp,'chivar') | |
482 yd = y(:,kk); % model response | |
483 else | |
484 error('!!! Unable to identify appropiate stop condition. See function help for admitted values'); | |
485 end | |
486 [next,msg] = utils.math.stopfit(yd,rdl(:,kk),mlr(:,kk),ctp,lrscond,msevar); | |
487 ext(kk,1) = next; | |
488 end | |
489 else | |
490 for kk = 1:Ny | |
491 % storing mse progression | |
492 mlr(hh,kk) = mse(:,kk); | |
493 end | |
494 end | |
495 | |
496 if all(ext) | |
497 utils.helper.msg(utils.const.msg.PROC1, msg) | |
498 break | |
499 end | |
500 | |
501 end | |
502 if all(ext) | |
503 break | |
504 end | |
505 | |
506 end | |
507 | |
508 end | |
509 end | |
510 | |
511 poles = bpoles; | |
512 clear mse | |
513 mse = mlr(:,:); | |
514 | |
515 res = bres; | |
516 dterm = bdterm; | |
517 mresp = bmresp; | |
518 rdl = brdl; | |
519 mse = bmse; | |
520 | |
521 if all(ext) == 0 | |
522 utils.helper.msg(utils.const.msg.PROC1, ' Fitting iteration completed without reaching the prescribed accuracy. Try changing Nmaxiter or maxorder or accuracy requirements ') | |
523 else | |
524 utils.helper.msg(utils.const.msg.PROC1, ' Fitting iteration completed successfully ') | |
525 end |