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