-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathriccati_solver.cpp
103 lines (85 loc) · 3.1 KB
/
riccati_solver.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
// solvers for Algebraic Riccati equation
// - Iteration (continuous)
// - Iteration (discrete)
// - Arimoto-Potter
//
// author: Horibe Takamasa
*/
#include <riccati_solver.h>
bool solveRiccatiIterationC(const Eigen::MatrixXd &A, const Eigen::MatrixXd &B,
const Eigen::MatrixXd &Q, const Eigen::MatrixXd &R,
Eigen::MatrixXd &P, const double dt,
const double &tolerance,
const uint iter_max) {
P = Q; // initialize
Eigen::MatrixXd P_next;
Eigen::MatrixXd AT = A.transpose();
Eigen::MatrixXd BT = B.transpose();
Eigen::MatrixXd Rinv = R.inverse();
double diff;
for (uint i = 0; i < iter_max; ++i) {
P_next = P + (P * A + AT * P - P * B * Rinv * BT * P + Q) * dt;
diff = fabs((P_next - P).maxCoeff());
P = P_next;
if (diff < tolerance) {
std::cout << "iteration mumber = " << i << std::endl;
return true;
}
}
return false; // over iteration limit
}
bool solveRiccatiIterationD(const Eigen::MatrixXd &Ad,
const Eigen::MatrixXd &Bd, const Eigen::MatrixXd &Q,
const Eigen::MatrixXd &R, Eigen::MatrixXd &P,
const double &tolerance,
const uint iter_max) {
P = Q; // initialize
Eigen::MatrixXd P_next;
Eigen::MatrixXd AdT = Ad.transpose();
Eigen::MatrixXd BdT = Bd.transpose();
Eigen::MatrixXd Rinv = R.inverse();
double diff;
for (uint i = 0; i < iter_max; ++i) {
// -- discrete solver --
P_next = AdT * P * Ad -
AdT * P * Bd * (R + BdT * P * Bd).inverse() * BdT * P * Ad + Q;
diff = fabs((P_next - P).maxCoeff());
P = P_next;
if (diff < tolerance) {
std::cout << "iteration mumber = " << i << std::endl;
return true;
}
}
return false; // over iteration limit
}
bool solveRiccatiArimotoPotter(const Eigen::MatrixXd &A,
const Eigen::MatrixXd &B,
const Eigen::MatrixXd &Q,
const Eigen::MatrixXd &R, Eigen::MatrixXd &P) {
const uint dim_x = A.rows();
const uint dim_u = B.cols();
// set Hamilton matrix
Eigen::MatrixXd Ham = Eigen::MatrixXd::Zero(2 * dim_x, 2 * dim_x);
Ham << A, -B * R.inverse() * B.transpose(), -Q, -A.transpose();
// calc eigenvalues and eigenvectors
Eigen::EigenSolver<Eigen::MatrixXd> Eigs(Ham);
// check eigen values
// std::cout << "eigen values:\n" << Eigs.eigenvalues() << std::endl;
// std::cout << "eigen vectors:\n" << Eigs.eigenvectors() << std::endl;
// extract stable eigenvectors into 'eigvec'
Eigen::MatrixXcd eigvec = Eigen::MatrixXcd::Zero(2 * dim_x, dim_x);
int j = 0;
for (int i = 0; i < 2 * dim_x; ++i) {
if (Eigs.eigenvalues()[i].real() < 0.) {
eigvec.col(j) = Eigs.eigenvectors().block(0, i, 2 * dim_x, 1);
++j;
}
}
// calc P with stable eigen vector matrix
Eigen::MatrixXcd Vs_1, Vs_2;
Vs_1 = eigvec.block(0, 0, dim_x, dim_x);
Vs_2 = eigvec.block(dim_x, 0, dim_x, dim_x);
P = (Vs_2 * Vs_1.inverse()).real();
return true;
}