CRbound = MIMO_ML_CRboundPhysicalParam(CRbound, Seln, wscale, ModelVar); Output parameters CRbound = Cramer-Rao bound of the estimated physical model parameters, and the estimated plant model CRbound = struct('A', [], 'AvecB', [], 'vecB', [], 'res', [], 'poles', []) See Input parameters for the definition of the structure Input parameters CRbound = Cramer-Rao bound of the estimated normalised model parameters, the estimated plant model, and the estimated noise model CRbound = struct('A', [], 'AcecB', [], 'vecB', [], 'res', [], 'poles', []) CRbound.A = FreeParam.A x FreeParam.A CRbound.A(i,j) = covariance between coefficients a(i-1) and a(j-1) CRbound.AvecB = FreeParam.A x FreeParam.B CRbound.AvecB(i,j) = covariance between free coefficients a(i-1) and vecB(j) CRbound.vecB = FreeParam.B x FreeParam.B CRbound.vecB(i,j) = covariance between vecB(i) and vecB(j) where vecB = permute(B, [3, 1, 2]); vecB = vecB(:) CRbound.res = struct{'all', 'sv', 'lsv', 'rsv'} CRbound.res.all = covariance matrix of (vec(Res))re; where ()re puts the real and imaginary parts of the matrix on top of each other; vec() stacks the columns of the matrix on top of each other; and Res is a residue matrix of the ny x nu transfer function matrix G = B/A; size: (2*ny*nu) x (2*ny*nu) x na CRbound.res.sv = variance singular values of the residues; size: min(ny, nu) x na CRbound.res.lsv = covariance left singular vectors of the residues [real(ur); imag(ur)]; size: 2*ny x 2*ny x min(ny, nu) x na CRbound.res.rsv = covariance right singular vectors of the residues [real(vr); imag(vr)]; size: 2*nu x 2*nu x min(ny, nu) x na CRbound.poles = struct{'root', 'all', 'damp', 'freq', 'time'} CRbound.poles.root = cov((root)re); where ()re stacks the real and imaginary part of the root on top of each other; ; size 2 x 2 x number of roots CRbound.poles.all = Cov(roots.all) = cov((roots)re); where the real and imaginary parts of the vector roots are stacked on top of each other; size 2*(number of roots) x 2*(number of roots) CRbound.poles.damp = variance damping complex roots; entry is NaN for real roots CRbound.poles.freq = variance frequency complex roots; entry is NaN for real roots CRbound.poles.time = variance time constant real roots; entry is NaN for complex roots Seln = struct('A', [], 'B', []) Seln.A = 1 x (OrderA+1) Seln.A(r) = 1 if coeff. a(r-1) is unknown Seln.A(r) = 0 if coeff. a(r-1) = 0 Seln.B = ny x nu x (OrderB+1) Seln.B(i,j,r) = 1 if coeff. b(i,j,r-1) is unknown Seln.B(i,j,r) = 0 if coeff. b(i,j,r-1) = 0 wscale = angular the frequency scaling ModelVar = contains the information about the model to be identified struct('Transient', [], 'PlantPlane', [], 'Struct', [], 'RecipPlant', []) ModelVar.Transient = 1 then the initial conditions of the plant are estimated ModelVar.PlantPlane = plane of the plant model 's': continuous-time; 'w': sqrt(s)-domain 'z': discrete-time; '': plane not defined ModelVar.Struct = model structure 'EIV': errors-in-variables (noisy input-output data) 'OE': generalised output error (known input, noisy output) ModelVar.RecipPlant = 1 if plant model is reciprocal: G(i,j) = G(j,i) Copyright (c) Rik Pintelon, Vrije Universiteit Brussel - dept. ELEC, November 2009 All rights reserved. Software can be used freely for non-commercial applications only. Version 6 October 2011
0001 function CRbound = MIMO_ML_CRboundPhysicalParam(CRbound, Seln, wscale, ModelVar); 0002 % 0003 % CRbound = MIMO_ML_CRboundPhysicalParam(CRbound, Seln, wscale, ModelVar); 0004 % 0005 % 0006 % Output parameters 0007 % 0008 % CRbound = Cramer-Rao bound of the estimated physical model parameters, and the estimated plant model 0009 % CRbound = struct('A', [], 'AvecB', [], 'vecB', [], 'res', [], 'poles', []) 0010 % See Input parameters for the definition of the structure 0011 % 0012 % 0013 % Input parameters 0014 % 0015 % CRbound = Cramer-Rao bound of the estimated normalised model parameters, the estimated plant model, and the estimated noise model 0016 % CRbound = struct('A', [], 'AcecB', [], 'vecB', [], 'res', [], 'poles', []) 0017 % CRbound.A = FreeParam.A x FreeParam.A 0018 % CRbound.A(i,j) = covariance between coefficients a(i-1) 0019 % and a(j-1) 0020 % CRbound.AvecB = FreeParam.A x FreeParam.B 0021 % CRbound.AvecB(i,j) = covariance between free coefficients 0022 % a(i-1) and vecB(j) 0023 % CRbound.vecB = FreeParam.B x FreeParam.B 0024 % CRbound.vecB(i,j) = covariance between vecB(i) and vecB(j) 0025 % where vecB = permute(B, [3, 1, 2]); 0026 % vecB = vecB(:) 0027 % CRbound.res = struct{'all', 'sv', 'lsv', 'rsv'} 0028 % CRbound.res.all = covariance matrix of (vec(Res))re; where ()re puts the real 0029 % and imaginary parts of the matrix on top of each other; vec() 0030 % stacks the columns of the matrix on top of each other; and Res 0031 % is a residue matrix of the ny x nu transfer function matrix G = B/A; 0032 % size: (2*ny*nu) x (2*ny*nu) x na 0033 % CRbound.res.sv = variance singular values of the residues; 0034 % size: min(ny, nu) x na 0035 % CRbound.res.lsv = covariance left singular vectors of the residues [real(ur); imag(ur)]; 0036 % size: 2*ny x 2*ny x min(ny, nu) x na 0037 % CRbound.res.rsv = covariance right singular vectors of the residues [real(vr); imag(vr)]; 0038 % size: 2*nu x 2*nu x min(ny, nu) x na 0039 % CRbound.poles = struct{'root', 'all', 'damp', 'freq', 'time'} 0040 % CRbound.poles.root = cov((root)re); where ()re stacks the real and imaginary part of the root 0041 % on top of each other; ; size 2 x 2 x number of roots 0042 % CRbound.poles.all = Cov(roots.all) = cov((roots)re); where the real and imaginary parts of 0043 % the vector roots are stacked on top of each other; 0044 % size 2*(number of roots) x 2*(number of roots) 0045 % CRbound.poles.damp = variance damping complex roots; entry is NaN for real roots 0046 % CRbound.poles.freq = variance frequency complex roots; entry is NaN for real roots 0047 % CRbound.poles.time = variance time constant real roots; entry is NaN for complex roots 0048 % 0049 % Seln = struct('A', [], 'B', []) 0050 % Seln.A = 1 x (OrderA+1) 0051 % Seln.A(r) = 1 if coeff. a(r-1) is unknown 0052 % Seln.A(r) = 0 if coeff. a(r-1) = 0 0053 % Seln.B = ny x nu x (OrderB+1) 0054 % Seln.B(i,j,r) = 1 if coeff. b(i,j,r-1) is unknown 0055 % Seln.B(i,j,r) = 0 if coeff. b(i,j,r-1) = 0 0056 % 0057 % wscale = angular the frequency scaling 0058 % 0059 % ModelVar = contains the information about the model to be identified 0060 % struct('Transient', [], 'PlantPlane', [], 'Struct', [], 'RecipPlant', []) 0061 % ModelVar.Transient = 1 then the initial conditions of the plant are estimated 0062 % ModelVar.PlantPlane = plane of the plant model 0063 % 's': continuous-time; 0064 % 'w': sqrt(s)-domain 0065 % 'z': discrete-time; 0066 % '': plane not defined 0067 % ModelVar.Struct = model structure 0068 % 'EIV': errors-in-variables (noisy input-output data) 0069 % 'OE': generalised output error (known input, noisy output) 0070 % ModelVar.RecipPlant = 1 if plant model is reciprocal: G(i,j) = G(j,i) 0071 % 0072 % 0073 % Copyright (c) Rik Pintelon, Vrije Universiteit Brussel - dept. ELEC, November 2009 0074 % All rights reserved. 0075 % Software can be used freely for non-commercial applications only. 0076 % Version 6 October 2011 0077 % 0078 0079 0080 %%%%%%%%%%%%%%%%%%%%%%%%%% 0081 % Plant model parameters % 0082 %%%%%%%%%%%%%%%%%%%%%%%%%% 0083 0084 if ~strcmp(ModelVar.PlantPlane, 'z') 0085 0086 na = size(Seln.A, 2) - 1; 0087 nb = size(Seln.B, 3) - 1; 0088 nu = size(Seln.B, 2); 0089 ny = size(Seln.B, 1); 0090 nn = max(na, nb) + 1; 0091 Scale = ones(nn, 1); 0092 for ii = 1:nn 0093 Scale(ii) = wscale^(ii-1); 0094 end % for ii 0095 Scale = Scale * Scale.'; 0096 0097 % scaling CR-bound coefficients matrix polynomial B 0098 nb_all = sum(sum(sum(Seln.B))); 0099 ScaleMat = zeros(nb_all, nb_all); 0100 OffsetRow = 0; 0101 for ll = 1:nu 0102 for kk = 1:ny 0103 nrow = sum(Seln.B(kk,ll,:)); 0104 OffsetColumn = 0; 0105 for jj = 1:nu 0106 for ii = 1:ny 0107 ncolumn = sum(Seln.B(ii,jj,:)); 0108 ScaleMat(OffsetRow+1:OffsetRow+nrow, OffsetColumn+1:OffsetColumn+ncolumn) = ... 0109 Scale(Seln.B(kk,ll,:) == 1, Seln.B(ii,jj,:) == 1); 0110 OffsetColumn = OffsetColumn + ncolumn; 0111 end % ii row index 0112 end % jj column index 0113 OffsetRow = OffsetRow + nrow; 0114 end % kk row index 0115 end %ll column index 0116 CRbound.vecB = CRbound.vecB ./ ScaleMat; 0117 0118 % scaling CR-bound coefficients A-polynomial 0119 CRbound.A = CRbound.A ./ Scale(Seln.A==1, Seln.A==1); 0120 0121 % scaling CR-bound covariance A- and B-coefficients 0122 na_all = sum(Seln.A); 0123 ScaleMat = zeros(na_all, nb_all); 0124 OffsetColumn = 0; 0125 for jj = 1:nu 0126 for ii = 1:ny 0127 ncolumn = sum(Seln.B(ii,jj,:)); 0128 ScaleMat(:, OffsetColumn+1:OffsetColumn+ncolumn) = Scale(Seln.A == 1, Seln.B(ii,jj,:) == 1); 0129 OffsetColumn = OffsetColumn + ncolumn; 0130 end % ii row index 0131 end % jj column index 0132 CRbound.AvecB = CRbound.AvecB ./ ScaleMat; 0133 0134 switch ModelVar.PlantPlane 0135 case 's' 0136 wscale2 = wscale; 0137 case 'w' 0138 % poles are squared in sqrt(s)-domain before calculating 0139 % the resonance frequencies and damping ratios 0140 wscale2 = wscale^2; 0141 end % if 0142 0143 % scaling CR-bound of the poles, frequency, and time 0144 % constants, but not the damping because it has no units 0145 CRbound.poles.all = CRbound.poles.all * (wscale^2); 0146 CRbound.poles.root = CRbound.poles.root * (wscale^2); 0147 CRbound.poles.freq = CRbound.poles.freq * (wscale2^2); 0148 CRbound.poles.time = CRbound.poles.time / (wscale2^2); 0149 0150 % scaling CR-bound of the residue matrices and the singular values, 0151 % but not the left and right singular vectors because they have no units 0152 CRbound.res.all = CRbound.res.all * (wscale^2); 0153 CRbound.res.sv = CRbound.res.sv * (wscale^2); 0154 0155 end % if not z-domain 0156