Resurgence (PY2022)
Codebase for the Husky Robotics 2021-2022 rover Resurgence
Loading...
Searching...
No Matches
ExtendedKalmanFilter.h
1#pragma once
2
3#include "KalmanFilterBase.h"
4#include "StateSpaceUtil.h"
5
6#include <Eigen/Core>
7#include <Eigen/LU>
8
9namespace filters {
10
28template <int stateDim, int inputDim, int outputDim, int processNoiseDim, int outputNoiseDim>
29class ExtendedKalmanFilter : public KalmanFilterBase<stateDim, inputDim> {
30public:
34 using statefunc_t = std::function<state_t(
35 const state_t&, const input_t&, const Eigen::Matrix<double, processNoiseDim, 1>&)>;
36 using outputfunc_t = std::function<output_t(
37 const state_t&, const Eigen::Matrix<double, outputNoiseDim, 1>&)>;
38 using processnoise_t = Eigen::Matrix<double, processNoiseDim, 1>;
39 using outputnoise_t = Eigen::Matrix<double, outputNoiseDim, 1>;
40
50 ExtendedKalmanFilter(const statefunc_t& stateFunc, const outputfunc_t& outputFunc,
53 double dt)
54 : stateFunc(stateFunc), outputFunc(outputFunc), Q(processNoise), R(outputNoise),
55 dt(dt) {}
56
57 void predict(const Eigen::Matrix<double, inputDim, 1>& input) override {
59 getStateFuncJacobianX(stateFunc, this->xHat, input);
61 Q.get(this->xHat, input);
62
64 getStateFuncJacobianW(stateFunc, this->xHat, input);
65
66 this->xHat = stateFunc(this->xHat, input, processnoise_t::Zero());
67 this->P = F * this->P * F.transpose() + L * processNoise * L.transpose();
68 }
69
79 getOutputFuncJacobianX(outputFunc, this->xHat); // output matrix
80
82 R.get(this->xHat, measurement);
84 getOutputFuncJacobianV(outputFunc, this->xHat);
86 H * this->P * H.transpose() +
87 M * outputNoise * M.transpose(); // residual covariance
88 // near-optimal kalman gain
90 S.transpose().colPivHouseholderQr().solve(H * this->P.transpose()).transpose();
91 output_t y = measurement -
92 outputFunc(this->xHat, outputnoise_t::Zero()); // measurement residual
93
94 this->xHat = this->xHat + K * y;
95 this->P = (Eigen::Matrix<double, stateDim, stateDim>::Identity() - K * H) * this->P;
96 }
97
103 std::function<Eigen::Matrix<double, stateDim, stateDim>(const state_t&, const input_t&,
104 const processnoise_t&)>
111 std::function<Eigen::Matrix<double, stateDim, processNoiseDim>(
112 const state_t&, const input_t&, const processnoise_t&)>
119 std::function<Eigen::Matrix<double, outputDim, stateDim>(const state_t&,
120 const outputnoise_t&)>
127 std::function<Eigen::Matrix<double, outputDim, outputNoiseDim>(const state_t&,
128 const outputnoise_t&)>
130
131private:
132 statefunc_t stateFunc;
133 outputfunc_t outputFunc;
134 // process noise and measurement noise covariance matrices
137 double dt;
138 static constexpr double epsilon = 1e-5;
139
141 getStateFuncJacobianX(const statefunc_t& f, const state_t& x, const input_t& u) const {
142 processnoise_t w = processnoise_t::Zero();
143 // If we have an analytic solution, use that
144 if (stateFuncJacobianX) {
145 return stateFuncJacobianX(x, u, w);
146 } else {
148 for (int i = 0; i < stateDim; i++) {
149 state_t delta = state_t::Zero();
150 delta[i] = epsilon;
151 state_t derivative = (f(x + delta, u, w) - f(x - delta, u, w)) / (2 * epsilon);
152 jacobian.col(i) = derivative;
153 }
154 return jacobian;
155 }
156 }
157
159 getStateFuncJacobianW(const statefunc_t& f, const state_t& x, const input_t& u) const {
160 processnoise_t w = processnoise_t::Zero();
161 // If we have an analytic solution, use that
162 if (stateFuncJacobianW) {
163 return stateFuncJacobianW(x, u, w);
164 } else {
166 for (int i = 0; i < processNoiseDim; i++) {
167 processnoise_t delta = processnoise_t::Zero();
168 delta[i] = epsilon;
169 state_t derivative = (f(x, u, w + delta) - f(x, u, w - delta)) / (2 * epsilon);
170 jacobian.col(i) = derivative;
171 }
172 return jacobian;
173 }
174 }
175
176 Eigen::Matrix<double, outputDim, stateDim> getOutputFuncJacobianX(const outputfunc_t& f,
177 const state_t& x) const {
178 outputnoise_t v = outputnoise_t::Zero();
179 // If we have an analytic solution, use that
181 return outputFuncJacobianX(x, v);
182 } else {
183 Eigen::Matrix<double, outputDim, stateDim> jacobian;
184 for (int i = 0; i < stateDim; i++) {
186 delta[i] = epsilon;
187 output_t derivative = (f(x + delta, v) - f(x - delta, v)) / (2 * epsilon);
188 jacobian.col(i) = derivative;
189 }
190 return jacobian;
191 }
192 }
193
194 Eigen::Matrix<double, outputDim, outputNoiseDim>
195 getOutputFuncJacobianV(const outputfunc_t& f, const state_t& x) const {
196 outputnoise_t v = outputnoise_t::Zero();
197 // If we have an analytic solution, use that
199 return outputFuncJacobianV(x, v);
200 } else {
201 Eigen::Matrix<double, outputDim, outputNoiseDim> jacobian;
202 for (int i = 0; i < outputNoiseDim; i++) {
203 outputnoise_t delta = outputnoise_t::Zero();
204 delta[i] = epsilon;
205 output_t derivative = (f(x, v + delta) - f(x, v - delta)) / (2 * epsilon);
206 jacobian.col(i) = derivative;
207 }
208 return jacobian;
209 }
210 }
211};
212
213} // namespace filters
static const ConstantReturnType Zero()
TransposeReturnType transpose()
static const IdentityReturnType Identity()
std::function< Eigen::Matrix< double, stateDim, stateDim >(const state_t &, const input_t &, const processnoise_t &)> stateFuncJacobianX
Set this to provide an analytic solution to df/dx.
Definition ExtendedKalmanFilter.h:105
void correct(const Eigen::Matrix< double, outputDim, 1 > &measurement)
Correct the state estimate with measurement data.
Definition ExtendedKalmanFilter.h:77
std::function< Eigen::Matrix< double, outputDim, outputNoiseDim >(const state_t &, const outputnoise_t &)> outputFuncJacobianV
Set this to provide an analytic solution to dh/dv.
Definition ExtendedKalmanFilter.h:129
std::function< Eigen::Matrix< double, outputDim, stateDim >(const state_t &, const outputnoise_t &)> outputFuncJacobianX
Set this to provide an analytic solution to dh/dx.
Definition ExtendedKalmanFilter.h:121
std::function< Eigen::Matrix< double, stateDim, processNoiseDim >(const state_t &, const input_t &, const processnoise_t &)> stateFuncJacobianW
Set this to provide an analytic solution to df/dw.
Definition ExtendedKalmanFilter.h:113
void predict(const Eigen::Matrix< double, inputDim, 1 > &input) override
Use the model to predict the next system state, given the current inputs.
Definition ExtendedKalmanFilter.h:57
ExtendedKalmanFilter(const statefunc_t &stateFunc, const outputfunc_t &outputFunc, const statespace::NoiseCovMat< stateDim, processNoiseDim, inputDim > &processNoise, const statespace::NoiseCovMat< stateDim, outputNoiseDim, outputDim > &outputNoise, double dt)
Create a new discrete-time EKF.
Definition ExtendedKalmanFilter.h:50
Represents a square noise covariance matrix.
Definition StateSpaceUtil.h:249
uint32_t v