RIT VEXU Core API
Loading...
Searching...
No Matches
dare_solver.h
1#pragma once
2
3#include "core/utils/math/eigen_interface.h"
4
36template <int STATES, int INPUTS>
37EMat<STATES, STATES> DARE(
38 const EMat<STATES, STATES> &A, const EMat<STATES, INPUTS> &B, const EMat<STATES, STATES> &Q,
39 const EMat<INPUTS, INPUTS> &R
40) {
41 const Eigen::LLT<EMat<INPUTS, INPUTS>> R_llt = R.llt();
42 using StateMatrix = EMat<STATES, STATES>;
43
44 // Implements SDA algorithm on p. 5 of [1] (initial A, G, H are from (4)).
45 //
46 // [1] E. K.-W. Chu, H.-Y. Fan, W.-W. Lin & C.-S. Wang "Structure-Preserving
47 // Algorithms for Periodic Discrete-Time Algebraic Riccati Equations",
48 // International Journal of Control, 77:8, 767-788, 2004.
49 // DOI: 10.1080/00207170410001714988
50
51 // A₀ = A
52 // G₀ = BR⁻¹Bᵀ
53 // H₀ = Q
54
55 StateMatrix A_k = A;
56 StateMatrix G_k = B * R_llt.solve(B.transpose());
57 StateMatrix H_k;
58 StateMatrix H_k1 = Q;
59
60
61
62 do {
63 H_k = H_k1;
64
65 // W = I + GₖHₖ
66 StateMatrix W = StateMatrix::Identity(H_k.rows(), H_k.cols()) + G_k * H_k;
67
68 auto W_solver = W.lu();
69
70 // Solve WV₁ = Aₖ for V₁
71 StateMatrix V_1 = W_solver.solve(A_k);
72
73 // Solve V₂Wᵀ = Gₖ for V₂
74 //
75 // We want to put V₂Wᵀ = Gₖ into Ax = b form so we can solve it more
76 // efficiently.
77 //
78 // V₂Wᵀ = Gₖ
79 // (V₂Wᵀ)ᵀ = Gₖᵀ
80 // WV₂ᵀ = Gₖᵀ
81 //
82 // The solution of Ax = b can be found via x = A.solve(b).
83 //
84 // V₂ᵀ = W.solve(Gₖᵀ)
85 // V₂ = W.solve(Gₖᵀ)ᵀ
86 StateMatrix V_2 = W_solver.solve(G_k.transpose()).transpose();
87
88 // Gₖ₊₁ = Gₖ + AₖV₂Aₖᵀ
89 // Hₖ₊₁ = Hₖ + V₁ᵀHₖAₖ
90 // Aₖ₊₁ = AₖV₁
91 G_k += A_k * V_2 * A_k.transpose();
92 H_k1 = H_k + V_1.transpose() * H_k * A_k;
93 A_k *= V_1;
94
95
96 // while |Hₖ₊₁ − Hₖ| > ε |Hₖ₊₁|
97 } while ((H_k1 - H_k).norm() > 1e-10 * H_k1.norm());
98
99 return H_k1;
100}