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}] =} dare (@var{a}, @var{b}, @var{q}, @var{r})
20 ## @deftypefnx {Function File} {[@var{x}, @var{l}, @var{g}] =} dare (@var{a}, @var{b}, @var{q}, @var{r}, @var{s})
21 ## @deftypefnx {Function File} {[@var{x}, @var{l}, @var{g}] =} dare (@var{a}, @var{b}, @var{q}, @var{r}, @var{[]}, @var{e})
22 ## @deftypefnx {Function File} {[@var{x}, @var{l}, @var{g}] =} dare (@var{a}, @var{b}, @var{q}, @var{r}, @var{s}, @var{e})
23 ## Solve discrete-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 discrete-time Riccati equation (n-by-n).
46 ## Closed-loop poles (n-by-1).
48 ## Corresponding gain matrix (m-by-n).
55 ## A'XA - X - A'XB (B'XB + R) B'XA + Q = 0
58 ## A'XA - X - (A'XB + S) (B'XB + R) (B'XA + S') + Q = 0
61 ## G = (B'XB + R) B'XA
64 ## G = (B'XB + R) (B'XA + S')
72 ## A'XA - E'XE - A'XB (B'XB + R) B'XA + Q = 0
75 ## A'XA - E'XE - (A'XB + S) (B'XB + R) (B'XA + S') + Q = 0
78 ## G = (B'XB + R) B'XA
81 ## G = (B'XB + R) (B'XA + S')
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{care, lqr, dlqr, kalman}
94 ## Author: Lukas Reichlin <lukas.reichlin@gmail.com>
95 ## Created: October 2009
98 function [x, l, g] = dare (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 ("dare: a, q, r must be real and square");
108 error ("dare: %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 ("dare: a and b must have the same number of rows");
114 error ("dare: %s and %s must have the same number of rows", \
115 inputname (1), inputname (2));
118 if (columns (r) != columns (b))
119 ## error ("dare: b and r must have the same number of columns");
120 error ("dare: %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 ("dare: s(%dx%d) must be real and identically dimensioned with b(%dx%d)",
126 ## rows (s), columns (s), rows (b), columns (b));
127 error ("dare: %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 ("dare: a and e must have the same number of rows");
133 error ("dare: %s and %s must have the same number of rows", \
134 inputname (1), inputname (6));
137 ## check stabilizability
138 if (! isstabilizable (a, b, e, [], 1))
139 ## error ("dare: (a, b) not stabilizable");
140 error ("dare: (%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 ("dare: require [q, s; s.', r] >= 0");
155 error ("dare: 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, true, false);
163 g = (r + b.'*x*b) \ (b.'*x*a); # gain matrix
165 [x, l] = slsb02od (a, b, q, r, s, true, true);
166 g = (r + b.'*x*b) \ (b.'*x*a + s.'); # gain matrix
170 [x, l] = slsg02ad (a, e, b, q, r, b, true, false);
171 g = (r + b.'*x*b) \ (b.'*x*a); # gain matrix
173 [x, l] = slsg02ad (a, e, b, q, r, s, true, true);
174 g = (r + b.'*x*b) \ (b.'*x*a + s.'); # gain matrix
181 %!shared x, l, g, xe, le, ge
192 %! [x, l, g] = dare (a, b, c.'*c, r);
194 %! xe = [ 1.5354 1.2623
200 %! ge = [ 0.4092 1.7283];
202 %!assert (x, xe, 1e-4);
203 %!assert (sort (l), sort (le), 1e-4);
204 %!assert (g, ge, 1e-4);
206 ## TODO: add more tests (nonempty s and/or e)