Brick
Loading...
Searching...
No Matches
kalman_filter.h
1#pragma once
2
3#include "core/math/eigen_interface.h"
4#include "core/math/systems/linear_system.h"
5
6/**
7 * Kalman filters combine predictions from a model and measurements to estimate
8 * a system's true state.
9 *
10 * Each call of predict moves the state forward in time according to the matrix A,
11 * and the covariance has white noise Q added.
12 *
13 * Each call of correct applies a measurement which moves the state more toward
14 * the true state, and it reduces the state covariance.
15 *
16 * To read more about Kalman filters read:
17 * https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python
18 *
19 * @tparam STATES Dimension of the state vector.
20 * @tparam INPUTS Dimension of the control input vector.
21 * @tparam OUTPUTS Dimension of the measurement vector.
22 */
23template <int STATES, int INPUTS, int OUTPUTS>
25 public:
26 using StateVector = EVec<STATES>;
27 using InputVector = EVec<INPUTS>;
28 using OutputVector = EVec<OUTPUTS>;
29
30 using StateMatrix = EMat<STATES, STATES>;
31 using InputMatrix = EMat<STATES, INPUTS>;
32
33 /**
34 * Constructs a Kalman filter.
35 *
36 * @param plant The linear system the filter tracks.
37 * @param state_stddevs The standard deviations of the states.
38 * @param measurement_stddevs The standard deviations of the measurements.
39 */
41 LinearSystem<STATES, INPUTS, OUTPUTS>& plant, const StateVector& state_stddevs,
42 const OutputVector& measurement_stddevs
43 )
45 plant.A(), plant.B(), plant.C(), plant.D(), state_stddevs, measurement_stddevs
46 ) {}
47
48 /**
49 * Constructs a Kalman filter.
50 *
51 * @param A The state matrix.
52 * @param B The input matrix.
53 * @param C The measurement matrix.
54 * @param D The feedthrough matrix.
55 * @param state_stddevs The standard deviations of the states.
56 * @param measurement_stddevs The standard deviations of the measurements.
57 */
59 const StateMatrix& A, const InputMatrix& B, const EMat<OUTPUTS, STATES>& C,
60 const EMat<OUTPUTS, INPUTS>& D, const StateVector& state_stddevs,
61 const OutputVector& measurement_stddevs
62 ) {
63 A_ = A;
64 B_ = B;
65 C_ = C;
66 D_ = D;
67
68 Q_ = state_stddevs.asDiagonal();
69 Q_ = Q_ * Q_.transpose();
70 R_ = measurement_stddevs.asDiagonal();
71 R_ = R_ * R_.transpose();
72
73 reset();
74 }
75
76 /// Returns the covariance matrix P.
77 StateMatrix P() const { return P_; }
78
79 /**
80 * Set the current covariance matrix P.
81 *
82 * @param P The covariance matrix P.
83 */
84 void set_P(const StateMatrix& P) { P_ = P; }
85
86 /// Returns the current state estimate x-hat.
87 const StateVector& xhat() const { return xhat_; }
88
89 /**
90 * Returns one element of the current state estimate x-hat.
91 *
92 * @param i Row of x-hat.
93 */
94 double xhat(int i) const { return xhat_(i); }
95
96 /// Set the current state estimate x-hat.
97 void set_xhat(const StateVector& xhat) { xhat_ = xhat; }
98
99 /**
100 * Set one element of the current state estimate x-hat.
101 *
102 * @param i Row of x-hat.
103 */
104 void set_xhat(int i, double value) { xhat_(i) = value; }
105
106 /// Resets the filter.
107 void reset() {
108 xhat_.setZero();
109 P_.setZero();
110 }
111
112 /**
113 * Projects the state into the future by dt seconds with control input u.
114 *
115 * @param u The control input.
116 * @param dt The timestep in seconds.
117 */
118 void predict(const InputVector& u, const double& dt) {
119 // Q is discrete sqrt(process noise)
120 EMat<STATES, STATES> Q = Q_ * dt;
121 auto [A, B] = discretize_AB(A_, B_, dt);
122
123 // Compute prior mean
124 xhat_ = A * xhat_ + B * u;
125
126 // Compute prior covariance
127 P_ = A * P_ * A.transpose() + Q;
128 }
129
130 /**
131 * Correct the state estimate using the measurements in y.
132 *
133 * @param y The vector of measurements.
134 * @param u The control input used in the last predict step.
135 */
136 void correct(const OutputVector& y, const InputVector& u) { correct<OUTPUTS>(y, u, C_, D_, R_); }
137
138 /**
139 * Correct the state estimate using the measurements in y, and custom
140 * measurement noise matrix. This is useful for when the noise in the
141 * measurements vary.
142 *
143 * @param y The vector of measurements.
144 * @param u The control input used in the last predict step.
145 * @param R The measurement noise matrix to use for this step.
146 */
147 void correct(const OutputVector& y, const InputVector& u, const EMat<OUTPUTS, OUTPUTS>& R) {
148 correct<OUTPUTS>(y, u, C_, D_, R);
149 }
150
151 /**
152 * Correct the state estimate using the measurements in y, custom measurement
153 * and feedthrough matrices, and custom measurement measurement noise.
154 * This is useful for when a different set of measurements are being applied
155 * than what the plant defines.
156 *
157 * @param y The vector of measurements.
158 * @param u The control input used in the last predict step.
159 * @param C The measurement matrix to use for this step.
160 * @param D The feedthrough matrix to use for this step.
161 * @param R The measurement noise matrix to use for this step.
162 */
163 template <int ROWS>
165 const EVec<ROWS>& y, const InputVector& u, const EMat<ROWS, STATES>& C,
166 const EMat<ROWS, INPUTS>& D, const EMat<ROWS, ROWS>& R
167 ) {
168 /*
169 * Compute the innovation covariance
170 *
171 * Py = CPCᵀ + R
172 *
173 */
174 EMat<ROWS, ROWS> Py = C * P_ * C.transpose() + R;
175 /*
176 * Compute the optimal Kalamn gain
177 *
178 * K = (Py \ CPᵀ)ᵀ
179 *
180 */
181 EMat<STATES, ROWS> K = Py.transpose().ldlt().solve(C * P_.transpose()).transpose();
182 /*
183 * Compute the posterior mean
184 *
185 * x̂ = x̂ + K(y - (Cx̂ + Du))
186 *
187 */
188 xhat_ += K * (y - (C * xhat_ + D * u));
189 /*
190 * Compute the posterior covariance using the Joseph form update equation
191 *
192 * P = (I - KC)P(I - KC)ᵀ + KRKᵀ
193 *
194 */
195 P_ = (EMat<STATES, STATES>::Identity() - K * C) * P_ *
196 (EMat<STATES, STATES>::Identity() - K * C).transpose() +
197 K * R * K.transpose();
198 }
199
200 private:
201 StateVector xhat_;
202 StateMatrix P_;
203
204 StateMatrix Q_;
205 EMat<OUTPUTS, OUTPUTS> R_;
206
207 StateMatrix A_;
208 EMat<STATES, INPUTS> B_;
209 EMat<OUTPUTS, STATES> C_;
210 EMat<OUTPUTS, INPUTS> D_;
211
212 double dt_;
213};
214
215// allow using both names
216template <int STATES, int INPUTS, int OUTPUTS>
Definition kalman_filter.h:24
StateMatrix P() const
Returns the covariance matrix P.
Definition kalman_filter.h:77
void set_P(const StateMatrix &P)
Definition kalman_filter.h:84
const StateVector & xhat() const
Returns the current state estimate x-hat.
Definition kalman_filter.h:87
void correct(const OutputVector &y, const InputVector &u)
Definition kalman_filter.h:136
double xhat(int i) const
Definition kalman_filter.h:94
void reset()
Resets the filter.
Definition kalman_filter.h:107
KalmanFilter(const StateMatrix &A, const InputMatrix &B, const EMat< OUTPUTS, STATES > &C, const EMat< OUTPUTS, INPUTS > &D, const StateVector &state_stddevs, const OutputVector &measurement_stddevs)
Definition kalman_filter.h:58
void set_xhat(int i, double value)
Definition kalman_filter.h:104
void set_xhat(const StateVector &xhat)
Set the current state estimate x-hat.
Definition kalman_filter.h:97
KalmanFilter(LinearSystem< STATES, INPUTS, OUTPUTS > &plant, const StateVector &state_stddevs, const OutputVector &measurement_stddevs)
Definition kalman_filter.h:40
void correct(const EVec< ROWS > &y, const InputVector &u, const EMat< ROWS, STATES > &C, const EMat< ROWS, INPUTS > &D, const EMat< ROWS, ROWS > &R)
Definition kalman_filter.h:164
void correct(const OutputVector &y, const InputVector &u, const EMat< OUTPUTS, OUTPUTS > &R)
Definition kalman_filter.h:147
void predict(const InputVector &u, const double &dt)
Definition kalman_filter.h:118
Definition linear_system.h:16