- 3.0.2 optimal control module.
CARE-impl.hpp
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
8 namespace ct {
9 namespace optcon {
10 
11 template <size_t STATE_DIM, size_t CONTROL_DIM>
13 {
14  // we have to find the optimal work size of schur reordering
17 
18  int SELECT[2 * STATE_DIM];
19  int N = 2 * STATE_DIM;
20  double WR[T.ColsAtCompileTime];
21  double WI[T.ColsAtCompileTime];
22  int MS;
23  double S;
24  double SEP;
25  double WORKDUMMY[1];
26  int LWORK = -1;
27  int IWORKQUERY[1];
28  int LIWORK = -1;
29  int INFO = 0;
30  int TCols = schur_matrix_t::ColsAtCompileTime;
31 
32 #ifdef CT_USE_LAPACK
33  dtrsen_("N", "V", &SELECT[0], &TCols, T.data(), &N, U.data(), &N, &WR[0], &WI[0], &MS, &S, &SEP, WORKDUMMY, &LWORK,
34  &IWORKQUERY[0], &LIWORK, &INFO);
35 
36  LWORK_ = WORKDUMMY[0] + 32;
37  LIWORK_ = IWORKQUERY[0] + 32;
38 
39  WORK_.resize(LWORK_);
40  IWORK_.resize(LIWORK_);
41 
42  if (INFO != 0)
43  {
44  std::cout << "Lapack invocation of dtrsen failed!" << std::endl;
45  exit(-1);
46  }
47 #endif
48 }
49 
50 template <size_t STATE_DIM, size_t CONTROL_DIM>
52  const control_matrix_t& R,
53  const state_matrix_t& A,
54  const control_gain_matrix_t& B,
55  state_matrix_t& P,
56  bool RisDiagonal,
57  control_matrix_t& R_inverse,
58  bool useIterativeSolver)
59 {
60  if (RisDiagonal)
61  {
62  R_inverse.setZero();
63  R_inverse.diagonal().noalias() = R.diagonal().cwiseInverse();
64  }
65  else
66  {
67  R_inverse.noalias() = R.inverse();
68  }
69 
71  M << A, -B * R_inverse * B.transpose(), -Q, -A.transpose();
72 
73  if (useIterativeSolver)
74  return solveSchurIterative(M, P);
75  else
76  return solveSchurDirect(M, P);
77 }
78 
79 template <size_t STATE_DIM, size_t CONTROL_DIM>
81  const state_matrix_t& Q,
82  const control_matrix_t& R,
83  const state_matrix_t& A,
84  const control_gain_matrix_t& B,
85  const bool RisDiagonal,
86  const bool useIterativeSolver)
87 {
89  control_matrix_t Rinv;
90 
91  solve(Q, R, A, B, P, RisDiagonal, Rinv, useIterativeSolver);
92 
93  return P;
94 }
95 
96 template <size_t STATE_DIM, size_t CONTROL_DIM>
98  state_matrix_t& P,
99  double epsilon,
100  int maxIterations)
101 {
102  bool converged = false;
103 
104  schur_matrix_t Mlocal = M;
105 
106  int iterations = 0;
107  while (!converged)
108  {
109  if (iterations > maxIterations)
110  return false;
111 
112  schur_matrix_t Mdiff = Mlocal - Mlocal.inverse();
113 
114  schur_matrix_t Mnew = Mlocal - 0.5 * Mdiff;
115 
116  converged = Mnew.isApprox(Mlocal, epsilon);
117 
118  Mlocal = Mnew;
119 
120  iterations++;
121  }
122 
123  /* break down W and extract W11 W12 W21 W22 (what is the size of these?) */
124  state_matrix_t M11(Mlocal.template block<STATE_DIM, STATE_DIM>(0, 0));
125  state_matrix_t M12(Mlocal.template block<STATE_DIM, STATE_DIM>(0, STATE_DIM));
126  state_matrix_t M21(Mlocal.template block<STATE_DIM, STATE_DIM>(STATE_DIM, 0));
127  state_matrix_t M22(Mlocal.template block<STATE_DIM, STATE_DIM>(STATE_DIM, STATE_DIM));
128 
129  /* find M and N using the elements of W */
130  factor_matrix_t U;
131  factor_matrix_t V;
132 
133  U.template block<STATE_DIM, STATE_DIM>(0, 0) = M12;
134  U.template block<STATE_DIM, STATE_DIM>(STATE_DIM, 0) = M22 + state_matrix_t::Identity();
135 
136  V.template block<STATE_DIM, STATE_DIM>(0, 0) = M11 + state_matrix_t::Identity();
137  V.template block<STATE_DIM, STATE_DIM>(STATE_DIM, 0) = M21;
138 
139 
140  /* Solve for S from the equation MS=N */
141  FullPivLU_.compute(U);
142 
143  P = FullPivLU_.solve(-V);
144 
145  return true;
146 }
147 
148 template <size_t STATE_DIM, size_t CONTROL_DIM>
150 {
151 #ifdef CT_USE_LAPACK
152  const bool computeU = true;
153  schur_.compute(M, computeU);
154 
155  if (schur_.info() != Eigen::Success)
156  {
157  throw std::runtime_error(
158  "LQR Schur computation failed. Most likely problem is set up wrongly or not solvable.");
159  }
160 
161  schur_matrix_t U(schur_.matrixU());
162  schur_matrix_t T(schur_.matrixT());
163 
164  int SELECT[2 * STATE_DIM];
165  double WR[2 * STATE_DIM];
166  double WI[2 * STATE_DIM];
167  int MS;
168  double S;
169  double SEP;
170  int INFO = 0;
171  int N = 2 * STATE_DIM;
172 
173  for (size_t i = 0; i < 2 * STATE_DIM; i++)
174  {
175  // check if last row or eigenvalue is complex (2x2 block)
176  if (i == (2 * STATE_DIM - 1) || std::abs(T(i + 1, i)) < 1e-12)
177  {
178  SELECT[i] = static_cast<int>(T(i, i) < 0);
179  }
180  else
181  {
182  // we have a complex block
183  SELECT[i] = static_cast<int>((T(i, i) + T(i + 1, i + 1)) / 2.0 < 0);
184  SELECT[i + 1] = SELECT[i];
185  i++;
186  }
187  }
188 
189  dtrsen_("N", "V", &SELECT[0], &N, T.data(), &N, U.data(), &N, &WR[0], &WI[0], &MS, &S, &SEP, WORK_.data(), &LWORK_,
190  IWORK_.data(), &LIWORK_, &INFO);
191 
192  const state_matrix_t& U11 = U.template block<STATE_DIM, STATE_DIM>(0, 0);
193  const state_matrix_t& U21 = U.template block<STATE_DIM, STATE_DIM>(STATE_DIM, 0);
194 
195  // solve here for better numerical properties
196  P.noalias() = U21 * U11.inverse();
197 
198  if (INFO != 0)
199  {
200  return false;
201  }
202 
203  return true;
204 #else
205  throw std::runtime_error(
206  "solveSchurDirect() in CARE can only be used if the lapack library is installed on your system.");
207 #endif
208 }
209 
210 
211 } // namespace optcon
212 } // namespace ct
state_matrix_t computeSteadyStateRiccatiMatrix(const state_matrix_t &Q, const control_matrix_t &R, const state_matrix_t &A, const control_gain_matrix_t &B, const bool RisDiagonal=false, const bool useIterativeSolver=false)
Definition: CARE-impl.hpp:80
CARE()
Definition: CARE-impl.hpp:12
Continuous-Time Algebraic Riccati Equation.
Definition: CARE.hpp:46
Eigen::Matrix< double, 2 *STATE_DIM, 2 *STATE_DIM > schur_matrix_t
Definition: CARE.hpp:57
Eigen::Matrix< double, CONTROL_DIM, CONTROL_DIM > control_matrix_t
Definition: CARE.hpp:52
for i
Definition: mpc_unittest_plotting.m:14
bool solve(const state_matrix_t &Q, const control_matrix_t &R, const state_matrix_t &A, const control_gain_matrix_t &B, state_matrix_t &P, bool RisDiagonal, control_matrix_t &R_inverse, bool useIterativeSolver=false)
Definition: CARE-impl.hpp:51
Eigen::Matrix< double, STATE_DIM, CONTROL_DIM > control_gain_matrix_t
Definition: CARE.hpp:54
WR
Eigen::Matrix< double, nStates, nStates > state_matrix_t
Eigen::Matrix< double, 2 *STATE_DIM, STATE_DIM > factor_matrix_t
Definition: CARE.hpp:58