1 ## Copyright (C) 2009, 2010 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{x}, @var{l}, @var{g}] =} care (@var{a}, @var{b}, @var{q}, @var{r})
20 ## @deftypefnx {Function File} {[@var{x}, @var{l}, @var{g}] =} care (@var{a}, @var{b}, @var{q}, @var{r}, @var{s})
21 ## @deftypefnx {Function File} {[@var{x}, @var{l}, @var{g}] =} care (@var{a}, @var{b}, @var{q}, @var{r}, @var{[]}, @var{e})
22 ## @deftypefnx {Function File} {[@var{x}, @var{l}, @var{g}] =} care (@var{a}, @var{b}, @var{q}, @var{r}, @var{s}, @var{e})
23 ## Solve continuous-time algebraic Riccati equation (ARE).
28 ## Real matrix (n-by-n).
30 ## Real matrix (n-by-m).
32 ## Real matrix (n-by-n).
34 ## Real matrix (m-by-m).
36 ## Optional real matrix (n-by-m). If @var{s} is not specified, a zero matrix is assumed.
38 ## Optional descriptor matrix (n-by-n). If @var{e} is not specified, an identity matrix is assumed.
44 ## Unique stabilizing solution of the continuous-time Riccati equation (n-by-n).
46 ## Closed-loop poles (n-by-1).
48 ## Corresponding gain matrix (m-by-n).
55 ## A'X + XA - XB R B'X + Q = 0
58 ## A'X + XA - (XB + S) R (B'X + S') + Q = 0
72 ## A'XE + E'XA - E'XB R B'XE + Q = 0
75 ## A'XE + E'XA - (E'XB + S) R (B'XE + S') + Q = 0
83 ## L = eig (A - B*G, E)
87 ## @strong{Algorithm}@*
88 ## Uses SLICOT SB02OD and SG02AD by courtesy of
89 ## @uref{http://www.slicot.org, NICONET e.V.}
91 ## @seealso{dare, lqr, dlqr, kalman}
94 ## Author: Lukas Reichlin <lukas.reichlin@gmail.com>
95 ## Created: November 2009
98 function [x, l, g] = care (a, b, q, r, s = [], e = [])
100 ## TODO: extract feedback matrix g from SB02OD (and SG02AD)
102 if (nargin < 4 || nargin > 6)
106 if (! is_real_square_matrix (a, q, r))
107 ## error ("care: a, q, r must be real and square");
108 error ("care: %s, %s, %s must be real and square", \
109 inputname (1), inputname (3), inputname (4));
112 if (! is_real_matrix (b) || rows (a) != rows (b))
113 ## error ("care: a and b must have the same number of rows");
114 error ("care: %s and %s must have the same number of rows", \
115 inputname (1), inputname (2));
118 if (columns (r) != columns (b))
119 ## error ("care: b and r must have the same number of columns");
120 error ("care: %s and %s must have the same number of columns", \
121 inputname (2), inputname (4));
124 if (! is_real_matrix (s) && ! size_equal (s, b))
125 ## error ("care: s(%dx%d) must be real and identically dimensioned with b(%dx%d)",
126 ## rows (s), columns (s), rows (b), columns (b));
127 error ("care: %s(%dx%d) must be real and identically dimensioned with %s(%dx%d)", \
128 inputname (5), rows (s), columns (s), inputname (2), rows (b), columns (b));
131 if (! isempty (e) && (! is_real_square_matrix (e) || ! size_equal (e, a)))
132 ## error ("care: a and e must have the same number of rows");
133 error ("care: %s and %s must have the same number of rows", \
134 inputname (1), inputname (6));
137 ## check stabilizability
138 if (! isstabilizable (a, b, e, [], 0))
139 ## error ("care: (a, b) not stabilizable");
140 error ("care: (%s, %s) not stabilizable", \
141 inputname (1), inputname (2));
144 ## check positive semi-definiteness
146 t = zeros (size (b));
153 if (isdefinite (m) < 0)
154 ## error ("care: require [q, s; s.', r] >= 0");
155 error ("care: require [%s, %s; %s.', %s] >= 0", \
156 inputname (3), inputname (5), inputname (5), inputname (4));
159 ## solve the riccati equation
162 [x, l] = slsb02od (a, b, q, r, b, false, false);
163 g = r \ (b.'*x); # gain matrix
165 [x, l] = slsb02od (a, b, q, r, s, false, true);
166 g = r \ (b.'*x + s.'); # gain matrix
170 [x, l] = slsg02ad (a, e, b, q, r, b, false, false);
171 g = r \ (b.'*x*e); # gain matrix
173 [x, l] = slsg02ad (a, e, b, q, r, s, false, true);
174 g = r \ (b.'*x*e + s.'); # gain matrix
181 %!shared x, l, g, xe, le, ge
192 %! [x, l, g] = care (a, b, c.'*c, r);
194 %! xe = [ 0.5895 1.8216
200 %! ge = [ 0.6072 2.9396];
202 %!assert (x, xe, 1e-4);
203 %!assert (l, le, 1e-4);
204 %!assert (g, ge, 1e-4);
206 %!shared x, l, g, xe, le, ge
221 %! [x, l, g] = care (a, b, c.'*c, d.'*d);
223 %! xe = [ 1.7321 1.0000
226 %! le = [-0.8660 + 0.5000i
227 %! -0.8660 - 0.5000i];
229 %! ge = [ 1.0000 1.7321];
231 %!assert (x, xe, 1e-4);
232 %!assert (l, le, 1e-4);
233 %!assert (g, ge, 1e-4);
253 %! x = care (a, b, c.'*c, d.'*d, [], e);
255 %! xe = [ 1.7321 1.0000
258 %!assert (x, xe, 1e-4);