Brick
Toggle main menu visibility
Loading...
Searching...
No Matches
dare_solver.h
1
#pragma once
2
3
#include "core/math/eigen_interface.h"
4
5
/**
6
* Copyright (c) FIRST and other WPILib contributors.
7
*
8
* Computes the unique stabilizing solution X to the discrete-time algebraic
9
* Riccati equation:
10
*
11
* AᵀXA − X − AᵀXB(BᵀXB + R)⁻¹BᵀXA + Q = 0
12
*
13
* This internal function skips expensive precondition checks for increased
14
* performance. The solver may hang if any of the following occur:
15
* <ul>
16
* <li>Q isn't symmetric positive semidefinite</li>
17
* <li>R isn't symmetric positive definite</li>
18
* <li>The (A, B) pair isn't stabilizable</li>
19
* <li>The (A, C) pair where Q = CᵀC isn't detectable</li>
20
* </ul>
21
* Only use this function if you're sure the preconditions are met.
22
*
23
* This algorithm is taken directly from WPILib. The version that I wrote was
24
* slower, unsurprisingly, so we will use theirs instead.
25
*
26
* This is also the algorithm used by Drake, an advanced robotics library.
27
*
28
* @tparam STATES Number of STATES.
29
* @tparam INPUTS Number of INPUTS.
30
* @param A The system matrix.
31
* @param B The input matrix.
32
* @param Q The state cost matrix.
33
* @param R_llt The LLT decomposition of the input cost matrix.
34
* @return Solution to the DARE.
35
*/
36
template
<
int
STATES,
int
INPUTS>
37
constexpr
EMat<STATES, STATES> DARE(
const
EMat<STATES, STATES>& A,
const
EMat<STATES, INPUTS>& B,
38
const
EMat<STATES, STATES>& Q,
const
EMat<INPUTS, INPUTS>& R) {
39
const
Eigen::LLT<EMat<INPUTS, INPUTS>> R_llt = R.llt();
40
using
StateMatrix = EMat<STATES, STATES>;
41
42
/*
43
* Implements SDA algorithm on p. 5 of [1] (initial A, G, H are from (4)).
44
*
45
* [1] E. K.-W. Chu, H.-Y. Fan, W.-W. Lin & C.-S. Wang "Structure-Preserving
46
* Algorithms for Periodic Discrete-Time Algebraic Riccati Equations",
47
* International Journal of Control, 77:8, 767-788, 2004.
48
* DOI: 10.1080/00207170410001714988
49
*
50
* A₀ = A
51
* G₀ = BR⁻¹Bᵀ
52
* H₀ = Q
53
*/
54
StateMatrix A_k = A;
55
StateMatrix G_k = B * R_llt.solve(B.transpose());
56
StateMatrix H_k;
57
StateMatrix H_k1 = Q;
58
59
do
{
60
H_k = H_k1;
61
62
// W = I + GₖHₖ
63
StateMatrix W = StateMatrix::Identity(H_k.rows(), H_k.cols()) + G_k * H_k;
64
65
auto
W_solver = W.lu();
66
67
// Solve WV₁ = Aₖ for V₁
68
StateMatrix V_1 = W_solver.solve(A_k);
69
/*
70
* Solve V₂Wᵀ = Gₖ for V₂
71
*
72
* We want to put V₂Wᵀ = Gₖ into Ax = b form so we can solve it more
73
* efficiently.
74
*
75
* V₂Wᵀ = Gₖ
76
* (V₂Wᵀ)ᵀ = Gₖᵀ
77
* WV₂ᵀ = Gₖᵀ
78
*
79
* The solution of Ax = b can be found via x = A.solve(b).
80
*
81
* V₂ᵀ = W.solve(Gₖᵀ)
82
* V₂ = W.solve(Gₖᵀ)ᵀ
83
*/
84
StateMatrix V_2 = W_solver.solve(G_k.transpose()).transpose();
85
/*
86
* Gₖ₊₁ = Gₖ + AₖV₂Aₖᵀ
87
* Hₖ₊₁ = Hₖ + V₁ᵀHₖAₖ
88
* Aₖ₊₁ = AₖV₁
89
*/
90
G_k += A_k * V_2 * A_k.transpose();
91
H_k1 = H_k + V_1.transpose() * H_k * A_k;
92
A_k *= V_1;
93
94
// while |Hₖ₊₁ − Hₖ| > ε |Hₖ₊₁|
95
}
while
((H_k1 - H_k).norm() > 1e-10 * H_k1.norm());
96
97
return
H_k1;
98
}
core
math
systems
dare_solver.h
Generated by
1.18.0