1 ## Copyright (C) 2011 Lukas F. Reichlin
3 ## This file is part of LTI Syncope.
5 ## LTI Syncope is free software: you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation, either version 3 of the License, or
8 ## (at your option) any later version.
10 ## LTI Syncope is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ## GNU General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with LTI Syncope. If not, see <http://www.gnu.org/licenses/>.
19 ## @deftypefn{Function File} {[@var{Kr}, @var{info}] =} cfconred (@var{G}, @var{F}, @var{L}, @dots{})
20 ## @deftypefnx{Function File} {[@var{Kr}, @var{info}] =} cfconred (@var{G}, @var{F}, @var{L}, @var{ncr}, @dots{})
21 ## @deftypefnx{Function File} {[@var{Kr}, @var{info}] =} cfconred (@var{G}, @var{F}, @var{L}, @var{opt}, @dots{})
22 ## @deftypefnx{Function File} {[@var{Kr}, @var{info}] =} cfconred (@var{G}, @var{F}, @var{L}, @var{ncr}, @var{opt}, @dots{})
24 ## Reduction of state-feedback-observer based controller by coprime factorization (CF).
25 ## Given a plant @var{G}, state feedback gain @var{F} and full observer gain @var{L},
26 ## determine a reduced order controller @var{Kr}.
31 ## LTI model of the open-loop plant (A,B,C,D).
32 ## It has m inputs, p outputs and n states.
34 ## Stabilizing state feedback matrix (m-by-n).
36 ## Stabilizing observer gain matrix (n-by-p).
38 ## The desired order of the resulting reduced order controller @var{Kr}.
39 ## If not specified, @var{ncr} is chosen automatically according
40 ## to the description of key @var{'order'}.
42 ## Optional pairs of keys and values. @code{"key1", value1, "key2", value2}.
44 ## Optional struct with keys as field names.
45 ## Struct @var{opt} can be created directly or
46 ## by command @command{options}. @code{opt.key1 = value1, opt.key2 = value2}.
52 ## State-space model of reduced order controller.
54 ## Struct containing additional information.
57 ## The Hankel singular values of the extended system?!?.
58 ## The @var{n} Hankel singular values are ordered decreasingly.
60 ## The order of the obtained reduced order controller @var{Kr}.
64 ## @strong{Option Keys and Values}
66 ## @item 'order', 'ncr'
67 ## The desired order of the resulting reduced order controller @var{Kr}.
68 ## If not specified, @var{ncr} is chosen automatically such that states with
69 ## Hankel singular values @var{info.hsv} > @var{tol1} are retained.
72 ## Order reduction approach to be used as follows:
74 ## @item 'sr-bta', 'b'
75 ## Use the square-root Balance & Truncate method.
76 ## @item 'bfsr-bta', 'f'
77 ## Use the balancing-free square-root Balance & Truncate method. Default method.
78 ## @item 'sr-spa', 's'
79 ## Use the square-root Singular Perturbation Approximation method.
80 ## @item 'bfsr-spa', 'p'
81 ## Use the balancing-free square-root Singular Perturbation Approximation method.
85 ## Specifies whether left or right coprime factorization is
86 ## to be used as follows:
89 ## Use left coprime factorization. Default method.
91 ## Use right coprime factorization.
95 ## Specifies whether @var{F} and @var{L} are fed back positively or negatively:
98 ## A+BK and A+LC are both Hurwitz matrices.
100 ## A-BK and A-LC are both Hurwitz matrices. Default value.
104 ## If @var{'order'} is not specified, @var{tol1} contains the tolerance for
105 ## determining the order of the reduced system.
106 ## For model reduction, the recommended value of @var{tol1} is
107 ## c*info.hsv(1), where c lies in the interval [0.00001, 0.001].
108 ## Default value is n*eps*info.hsv(1).
109 ## If @var{'order'} is specified, the value of @var{tol1} is ignored.
112 ## The tolerance for determining the order of a minimal
113 ## realization of the coprime factorization controller.
115 ## If not specified, n*eps*info.hsv(1) is chosen.
117 ## @item 'equil', 'scale'
118 ## Boolean indicating whether equilibration (scaling) should be
119 ## performed on system @var{G} prior to order reduction.
120 ## Default value is true if @code{G.scaled == false} and
121 ## false if @code{G.scaled == true}.
122 ## Note that for @acronym{MIMO} models, proper scaling of both inputs and outputs
123 ## is of utmost importance. The input and output scaling can @strong{not}
124 ## be done by the equilibration option or the @command{prescale} command
125 ## because these functions perform state transformations only.
126 ## Furthermore, signals should not be scaled simply to a certain range.
127 ## For all inputs (or outputs), a certain change should be of the same
128 ## importance for the model.
131 ## @strong{Algorithm}@*
132 ## Uses SLICOT SB16BD by courtesy of
133 ## @uref{http://www.slicot.org, NICONET e.V.}
136 ## Author: Lukas Reichlin <lukas.reichlin@gmail.com>
137 ## Created: December 2011
140 function [Kr, info] = cfconred (G, F, L, varargin)
146 if (! isa (G, "lti"))
147 error ("cfconred: first argument must be an LTI system");
150 if (! is_real_matrix (F))
151 error ("cfconred: second argument must be a real matrix");
154 if (! is_real_matrix (L))
155 error ("cfconred: third argument must be a real matrix");
158 if (nargin > 3) # cfconred (G, F, L, ...)
159 if (is_real_scalar (varargin{1})) # cfconred (G, F, L, nr)
160 varargin = horzcat (varargin(2:end), {"order"}, varargin(1));
162 if (isstruct (varargin{1})) # cfconred (G, F, L, opt, ...), cfconred (G, F, L, nr, opt, ...)
163 varargin = horzcat (__opt2cell__ (varargin{1}), varargin(2:end));
165 ## order placed at the end such that nr from cfconred (G, F, L, nr, ...)
166 ## and cfconred (G, F, L, nr, opt, ...) overrides possible nr's from
167 ## key/value-pairs and inside opt struct (later keys override former keys,
168 ## nr > key/value > opt)
171 nkv = numel (varargin); # number of keys and values
174 error ("cfconred: keys and values must come in pairs");
177 [a, b, c, d, tsam, scaled] = ssdata (G);
185 if (mf != m || nf != n)
186 error ("cfconred: dimensions of state-feedback matrix (%dx%d) and plant (%dx%d, %d states) don't match", \
190 if (nl != n || pl != p)
191 error ("cfconred: dimensions of observer matrix (%dx%d) and plant (%dx%d, %d states) don't match", \
199 jobmr = 2; # balancing-free BTA
200 equil = scaled; # equil: 0 means "S", 1 means "N"
203 negfb = true; # A-BK, A-LC Hurwitz
206 ## handle keys and values
208 key = lower (varargin{k});
211 case {"order", "ncr", "nr"}
212 [ncr, ordsel] = __modred_check_order__ (val, n);
215 tol1 = __modred_check_tol__ (val, "tol1");
218 tol2 = __modred_check_tol__ (val, "tol2");
221 switch (lower (val(1)))
227 error ("cfconred: '%s' is an invalid coprime factorization", val);
230 case "method" # approximation method
231 switch (tolower (val))
232 case {"sr-bta", "b"} # 'B': use the square-root Balance & Truncate method
234 case {"bfsr-bta", "f"} # 'F': use the balancing-free square-root Balance & Truncate method
236 case {"sr-spa", "s"} # 'S': use the square-root Singular Perturbation Approximation method
238 case {"bfsr-spa", "p"} # 'P': use the balancing-free square-root Singular Perturbation Approximation method
241 error ("cfconred: '%s' is an invalid approach", val);
244 case {"equil", "equilibrate", "equilibration", "scale", "scaling"}
245 equil = __modred_check_equil__ (val);
248 negfb = __conred_check_feedback_sign__ (val);
251 warning ("cfconred: invalid property name '%s' ignored", key);
256 ## A - B*F --> A + B*F ; A - L*C --> A + L*C
262 ## perform model order reduction
263 [acr, bcr, ccr, dcr, ncr, hsv] = slsb16bd (a, b, c, d, dt, equil, ncr, ordsel, jobd, jobmr, \
264 F, L, jobcf, tol1, tol2);
266 ## assemble reduced order controller
267 Kr = ss (acr, bcr, ccr, dcr, tsam);
269 ## assemble info struct
270 info = struct ("ncr", ncr, "hsv", hsv);
275 %!shared Mo, Me, Info, HSVe
276 %! A = [ 0 1.0000 0 0 0 0 0 0
278 %! 0 0 -0.0150 0.7650 0 0 0 0
279 %! 0 0 -0.7650 -0.0150 0 0 0 0
280 %! 0 0 0 0 -0.0280 1.4100 0 0
281 %! 0 0 0 0 -1.4100 -0.0280 0 0
282 %! 0 0 0 0 0 0 -0.0400 1.850
283 %! 0 0 0 0 0 0 -1.8500 -0.040 ];
294 %! C = [ -.996 -.105 0.261 .009 -.001 -.043 0.002 -0.026 ];
298 %! G = ss (A, B, C, D); % "scaled", false
300 %! F = [ 4.4721e-002 6.6105e-001 4.6986e-003 3.6014e-001 1.0325e-001 -3.7541e-002 -4.2685e-002 3.2873e-002 ];
311 %! [Kr, Info] = cfconred (G, F, L, 4, "method", "bfsr-bta", "cf", "left", "feedback", "+");
312 %! [Ao, Bo, Co, Do] = ssdata (Kr);
314 %! Ae = [ 0.5946 -0.7336 0.1914 -0.3368
315 %! 0.5960 -0.0184 -0.1088 0.0207
316 %! 1.2253 0.2043 0.1009 -1.4948
317 %! -0.0330 -0.0243 1.3440 0.0035 ];
324 %! Ce = [ 0.3534 0.0274 0.0337 -0.0320 ];
328 %! HSVe = [ 4.9078 4.8745 3.8455 3.7811 1.2289 1.1785 0.5176 0.1148 ].';
330 %! Mo = [Ao, Bo; Co, Do];
331 %! Me = [Ae, Be; Ce, De];
333 %!assert (Mo, Me, 1e-4);
334 %!assert (Info.hsv, HSVe, 1e-4);