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