comparison m-toolbox/classes/+utils/@math/csd2tf2.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 % CSD2TF Input cross spectral density matrix and output stable transfer function
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %
4 % DESCRIPTION:
5 %
6 % Input cross spectral density (csd) and output corresponding
7 % stable functions. Identification can be performed for a simple system
8 % (one psd) or for a N dimensional system. Discrete transfer functions are
9 % output in partial fraction expansion:
10 %
11 % r1 rN
12 % f(z) = ----------- + ... + ----------- + d
13 % 1-p1*z^{-1} 1-pN*z^{-1}
14 %
15 % System identification is performed in frequency domain, the order of
16 % the model function is automatically chosen by the algorithm on the
17 % base of the input tolerance condition.
18 % In the case of simple systems the square root of the psd is fitted
19 % and then the model is stabilized by the application of an all-pass
20 % function.
21 % In the case of two dimensional systems, transfer functions frequency
22 % response is calculated by the eigendecomposition of the
23 % cross-spectral matrix. Then models are identified by fitting
24 % in frequency domain.
25 %
26 % CALL:
27 % out = csd2tf(csd,f,params)
28 %
29 % INPUT:
30 %
31 % - csd is the cross spectral density matrix. It is in general a
32 % [n,n,m] dimensional matrix. Where n is the dimension of the system
33 % and m is the number of frequencies
34 % - f: is the corresponding frequencies vector in Hz (of length m)
35 % - params: is a struct of identification options, the possible values
36 % are:
37 %
38 % params.TargetDomain = 'z' --> Perform z domain identification.
39 % Function output are residues and poles of a discrete system.
40 % params.TargetDomain = 's' --> Perform s domain identification.
41 % Function output are residues and poles of a continuous system.
42 %
43 % params.fullauto = 0 --> Perform a fitting loop as far as the number
44 % of iteration reach Nmaxiter. The order of the fitting function will
45 % be that specified in params.minorder. If params.dterm is setted to
46 % 1 the function will fit only with direct term.
47 % params.fullauto = 1 --> Parform a full automatic search for the
48 % transfer function order. The fitting procedure will stop when the
49 % stopping condition defined in params.ctp is satisfied. Default
50 % value.
51 %
52 % - params.Nmaxiter = # set the maximum number of fitting steps
53 % performed for each trial function order. Default is 50
54 %
55 % - params.minorder = # set the minimum possible function order.
56 % Default is 2
57 %
58 % - params.maxorder = # set the maximum possible function order.
59 % Default is 25
60 %
61 % params.spolesopt = 1 --> use real starting poles
62 % params.spolesopt = 2 --> generates complex conjugates poles of the
63 % type \alfa e^{j\pi\theta} with \theta = linspace(0,pi,N/2+1).
64 % params.spolesopt = 3 --> generates complex conjugates poles of the
65 % type \alfa e^{j\pi\theta} with \theta = linspace(0,pi,N/2+2).
66 % Default option.
67 %
68 % - params.weightparam = 0 --> use external weights
69 % - params.weightparam = 1 equal weights (one) for each point
70 % - params.weightparam = 2 weight with the inverse of absolute value
71 % of fitting data
72 % - params.weightparam = 3 weight with square root of the inverse of
73 % absolute value of fitting data
74 % - params.weightparam = 4 weight with the inverse of the square mean
75 % spread
76 %
77 % params.extweights = [] --> A vector of externally provided weights.
78 % It has to be of the same size of input data.
79 %
80 % - params.plot = 0 --> no plot during fit iteration
81 % - params.plot = 1 --> plot results at each fitting steps. default
82 % value.
83 %
84 % - params.ctp = 'chival' --> check if the value of the Mean Squared
85 % Error is lower than 10^(-1*lsrcond).
86 % - params.ctp = 'chivar' --> check if the value of the Mean Squared
87 % Error is lower than 10^(-1*lsrcond) and if the relative variation of mean
88 % squared error is lower than 10^(-1*msevar).
89 % - params.ctp = 'lrs' --> check if the log difference between data and
90 % residuals is point by point larger than the value indicated in
91 % lsrcond. This mean that residuals are lsrcond order of magnitudes
92 % lower than data.
93 % - params.ctp = 'lrsmse' --> check if the log difference between data
94 % and residuals is larger than the value indicated in lsrcond and if
95 % the relative variation of mean squared error is lower than
96 % 10^(-1*msevar).
97 %
98 % - params.lrscond = # --> set conditioning value for point to point
99 % log residuals difference (params.ctp = 'lsr') and mean log residual
100 % difference (params.ctp = 'mlsrvar'). Default is 2. See help for
101 % stopfit.m for further remarks.
102 %
103 % - params.msevar = # --> set conditioning value for root mean squared
104 % error variation. This allow to check that the relative variation of
105 % mean squared error is lower than 10^(-1*msevar).Default is 7. See
106 % help for stopfit.m for further remarks.
107 %
108 % - params.fs set the sampling frequency (Hz). Default is 1 Hz
109 %
110 % params.dterm = 0 --> Try to fit without direct term
111 % params.dterm = 1 --> Try to fit with and without direct term
112 %
113 % params.spy = 0 --> Do not display the iteration progression
114 % params.spy = 1 --> Display the iteration progression
115 %
116 % params.usesym = 0 --> perform double-precision calculation for
117 % poles stabilization
118 % params.usesym = 1 --> perform symbolic math toolbox calculation for
119 % poles stabilization
120 %
121 %
122 % OUTPUT:
123 %
124 % - ostruct is a struct with the fields:
125 % - ostruct(n).res --> is the vector of residues.
126 % - ostruct(n).poles --> is the vector of poles.
127 % - ostruct(n).dterm --> is the vector of direct terms.
128 % - ostruct(n).mresp --> is the vector of tfs models responses.
129 % - ostruct(n).rdl --> is the vector of fit residuals.
130 % - ostruct(n).mse --> is the vector of mean squared errors.
131 %
132 %
133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 %
135 % VERSION: $Id: csd2tf2.m,v 1.1 2009/10/16 17:16:54 luigi Exp $
136 %
137 % HISTORY: 22-04-2009 L Ferraioli
138 % Creation
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 function ostruct = csd2tf2(csd,f,params)
141
142 utils.helper.msg(utils.const.msg.MNAME, 'running %s/%s', mfilename('class'), mfilename);
143
144 % Collect inputs
145
146 % Default input struct
147 defaultparams = struct('TargetDomain','z','Nmaxiter',50, 'minorder',2,...
148 'maxorder',25, 'spolesopt',2, 'weightparam',1, 'plot',0,...
149 'ctp','chival','lrscond',2,'msevar',2,...
150 'fs',1,'dterm',0, 'spy',0, 'fullauto',1,...
151 'extweights', [],'usesym',1);
152
153 names = {'TargetDomain','Nmaxiter','minorder','maxorder','spolesopt',...
154 'weightparam','plot','stopfitcond',...
155 'ctp','lrscond','msevar',...
156 'fs','dterm','spy','fullauto','extweights',...
157 'usesym'};
158
159 % collecting input and default params
160 if ~isempty(params)
161 for jj=1:length(names)
162 if isfield(params, names(jj)) && ~isempty(params.(names{1,jj}))
163 defaultparams.(names{1,jj}) = params.(names{1,jj});
164 end
165 end
166 end
167
168 % default values for input variables
169 target = defaultparams.TargetDomain; % target domain for system identification, can be 'z' or 's'
170 Nmaxiter = defaultparams.Nmaxiter; % Number of max iteration in the fitting loop
171 minorder = defaultparams.minorder; % Minimum model order
172 maxorder = defaultparams.maxorder; % Maximum model order
173 spolesopt = defaultparams.spolesopt; % 0, Fit with no complex starting poles (complex poles can be found as fit output). 1 fit with comples starting poles
174 weightparam = defaultparams.weightparam; % Weight 1./abs(y). Admitted values are 0, 1, 2, 3
175 checking = defaultparams.plot; % Never polt. Admitted values are 0 (No polt ever), 1 (plot at the end), 2 (plot at each step)
176 ctp = defaultparams.ctp;
177 lrscond = defaultparams.lrscond;
178 msevar = defaultparams.msevar;
179 fs = defaultparams.fs; % sampling frequency
180 idt = defaultparams.dterm;
181 spy = defaultparams.spy;
182 autosearch = defaultparams.fullauto;
183 extweights = defaultparams.extweights;
184 usesym = defaultparams.usesym; % method of calculation for the all pass filter
185
186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 % Checking inputs
188
189 [a,b] = size(f);
190 if a < b % shifting to column
191 f = f.';
192 end
193
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 % switching between inputs
196
197 clear dim
198 % cecking for dimensionality
199 [nn,mm,kk] = size(csd);
200 if kk == 1
201 dim = '1dim';
202 utils.helper.msg(utils.const.msg.PROC1, ' Performing one dimesional identification on psd ')
203 if nn < mm % shift to column
204 csd = csd.';
205 end
206 else
207 dim ='ndim';
208 utils.helper.msg(utils.const.msg.PROC1, ' Performing N dimesional identification on csd ')
209 end
210
211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
212 % system identification
213
214 switch dim
215 case '1dim'
216
217 utils.helper.msg(utils.const.msg.PROC1, ' Performing z-domain identification ')
218 itf = abs(sqrt(csd)); % input data
219
220 switch target % switch between z-domain and s-domain
221 case 'z'
222 % Fitting params
223 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
224 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
225 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
226 'stabfit',0,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
227
228 % Fitting
229 utils.helper.msg(utils.const.msg.PROC1, ' Fitting absolute TF value with unstable model ')
230 [res,poles,dterm,mresp,rdl,msei] = utils.math.autodfit(itf,f,fs,params);
231
232 if usesym
233 % all pass filtering for poles stabilization
234 allpoles.poles = poles;
235 ntf = utils.math.pfallpsymz2(allpoles,mresp,f,fs);
236 else
237 % all pass filtering for poles stabilization
238 ntf = utils.math.pfallpz2(poles,mresp,f,fs);
239 end
240
241 % Fitting params
242 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
243 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
244 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
245 'stabfit',1,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
246
247 utils.helper.msg(utils.const.msg.PROC1, ' Fitting TF with stable model ')
248 [res,poles,dterm,mresp,rdl,msef] = utils.math.autodfit(ntf,f,fs,params);
249
250 % Output data switching between output type
251 utils.helper.msg(utils.const.msg.PROC1, ' Output z-domain model ')
252
253 case 's'
254 % Fitting params
255 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
256 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
257 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
258 'stabfit',0,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
259
260 % Fitting
261 utils.helper.msg(utils.const.msg.PROC1, ' Fitting absolute TF value with unstable model ')
262 [res,poles,dterm,mresp,rdl,msei] = utils.math.autocfit(itf,f,params);
263
264 if usesym
265 % all pass filtering for poles stabilization
266 allpoles.poles = poles;
267 ntf = utils.math.pfallpsyms2(allpoles,mresp,f);
268 else
269 % all pass filtering for poles stabilization
270 ntf = utils.math.pfallps2(poles,mresp,f);
271 end
272
273 % Fitting params
274 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
275 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
276 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
277 'stabfit',1,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
278
279 utils.helper.msg(utils.const.msg.PROC1, ' Fitting TF with stable model ')
280 [res,poles,dterm,mresp,rdl,msef] = utils.math.autocfit(ntf,f,params);
281
282 % Output data switching between output type
283 utils.helper.msg(utils.const.msg.PROC1, ' Output s-domain model ')
284
285 end
286
287 ostruct = struct();
288
289 ostruct.res = res;
290 ostruct.poles = poles;
291 ostruct.dterm = dterm;
292 ostruct.mresp = mresp;
293 ostruct.rdl = rdl;
294 ostruct.mse = msei;
295
296 case 'ndim'
297 % switching between continuous and discrete type identification
298
299 % utils.helper.msg(utils.const.msg.PROC1, ' Performing z-domain identification on 2dim system, z-domain output ')
300 tf = utils.math.ndeigcsd(csd,'OTP','TF','MTD','PAP'); % input data
301
302 [nn,mm,kk] = size(tf);
303
304 % % Shifting to columns
305 % [a,b] = size(tf11);
306 % if a<b
307 % tf11 = tf11.';
308 % end
309 % [a,b] = size(tf12);
310 % if a<b
311 % tf12 = tf12.';
312 % end
313 % [a,b] = size(tf21);
314 % if a<b
315 % tf21 = tf21.';
316 % end
317 % [a,b] = size(tf22);
318 % if a<b
319 % tf22 = tf22.';
320 % end
321 %
322 % % Collecting tfs
323 % f1 = [tf11 tf21];
324 % f2 = [tf12 tf22];
325
326 %%% System identification
327
328 % init output
329 ostruct = struct();
330 idx = 1;
331
332 for dd = 1:mm
333 fun = squeeze(tf(1,dd,:));
334 % willing to work with columns
335 [a,b] = size(fun);
336 if a<b
337 fun = fun.';
338 end
339 for ff = 2:nn
340 tfun = squeeze(tf(ff,dd,:));
341 % willing to work with columns
342 [a,b] = size(tfun);
343 if a<b
344 tfun = tfun.';
345 end
346 fun = [fun tfun];
347 end
348
349 switch target % switch between z-domain and s-domain
350 case 'z'
351 for pp = 1:size(fun,2)
352
353 % Fitting with unstable poles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
355 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
356 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
357 'stabfit',0,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
358
359 % Fitting
360 utils.helper.msg(utils.const.msg.PROC1, ' Fitting with unstable common poles ')
361 [res,poles,dterm,tmresp,trdl,tmsei] = utils.math.autodfit(fun(:,pp),f,fs,params);
362
363 allpoles(pp).poles = poles;
364 mresp(:,pp) = tmresp;
365 rdl(:,pp) = trdl;
366 msei(:,pp) = tmsei;
367
368 end
369
370 if usesym
371 % Poles stabilization %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372 utils.helper.msg(utils.const.msg.PROC1, ' All pass filtering')
373 nfun = utils.math.pfallpsymz2(allpoles,mresp,f,fs);
374 else
375 % Poles stabilization %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 utils.helper.msg(utils.const.msg.PROC1, ' All pass filtering')
377 nfun = utils.math.pfallpz2(allpoles,mresp,f,fs);
378 end
379
380 clear poles
381
382 % Fitting with stable poles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383
384 for zz = 1:size(fun,2)
385
386 % Fitting params
387 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
388 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
389 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
390 'stabfit',1,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
391
392 % Fitting
393 utils.helper.msg(utils.const.msg.PROC1, ' Fitting with stable common poles ')
394 [res,poles,dterm,tmresp,trdl,tmsef] = utils.math.autodfit(nfun(:,zz),f,fs,params);
395
396
397 % Output stable model %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398
399 ostruct(idx).res = res;
400 ostruct(idx).poles = poles;
401 ostruct(idx).dterm = dterm;
402 ostruct(idx).mresp = mresp(:,zz);
403 ostruct(idx).rdl = rdl(:,zz);
404 ostruct(idx).mse = msei(:,zz);
405
406 idx = idx + 1;
407
408 end
409
410 case 's'
411 for pp = 1:size(fun,2)
412
413 % Fitting with unstable poles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
415 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
416 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
417 'stabfit',0,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
418
419 % Fitting
420 utils.helper.msg(utils.const.msg.PROC1, ' Fitting with unstable common poles ')
421 [res,poles,dterm,tmresp,trdl,tmsei] = utils.math.autocfit(fun(:,pp),f,params);
422
423 allpoles(pp).poles = poles;
424 mresp(:,pp) = tmresp;
425 rdl(:,pp) = trdl;
426 msei(:,pp) = tmsei;
427
428 end
429
430 if usesym
431 % Poles stabilization %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432 utils.helper.msg(utils.const.msg.PROC1, ' All pass filtering')
433 nfun = utils.math.pfallpsyms2(allpoles,mresp,f);
434 else
435 % Poles stabilization %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436 utils.helper.msg(utils.const.msg.PROC1, ' All pass filtering')
437 nfun = utils.math.pfallps2(allpoles,mresp,f);
438 end
439
440 clear poles
441
442 % Fitting with stable poles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443
444 for zz = 1:size(fun,2)
445
446 % Fitting params
447 params = struct('spolesopt',spolesopt, 'Nmaxiter',Nmaxiter, 'minorder',minorder,...
448 'maxorder',maxorder, 'weightparam',weightparam, 'plot',checking,...
449 'ctp',ctp,'lrscond',lrscond,'msevar',msevar,...
450 'stabfit',1,'dterm',idt,'spy',spy,'fullauto',autosearch,'extweights',extweights);
451
452 % Fitting
453 utils.helper.msg(utils.const.msg.PROC1, ' Fitting with stable common poles ')
454 [res,poles,dterm,tmresp,trdl,tmsef] = utils.math.autocfit(nfun(:,zz),f,params);
455
456
457 % Output stable model %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458
459 ostruct(idx).res = res;
460 ostruct(idx).poles = poles;
461 ostruct(idx).dterm = dterm;
462 ostruct(idx).mresp = mresp(:,zz);
463 ostruct(idx).rdl = rdl(:,zz);
464 ostruct(idx).mse = msei(:,zz);
465
466 idx = idx + 1;
467
468 end
469
470 end
471
472
473
474
475 end
476
477 end
478 end
479
480 % END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%