Resurgence (PY2022)
Codebase for the Husky Robotics 2021-2022 rover Resurgence
Loading...
Searching...
No Matches
StateSpaceUtil.h
1#pragma once
2
3#include <Eigen/Core>
4#include <Eigen/LU>
5#include <unsupported/Eigen/MatrixFunctions>
6
11namespace filters::statespace {
12
21template <int size>
22Eigen::Matrix<double, size, size>
24 Eigen::Matrix<double, size, 1> variances = stdDevs.array().square();
26 return mat;
27}
28
37template <int numStates>
40 return A.log() / dt;
41}
42
53template <int numStates, int numInputs>
56 // Reference paper: https://doi.org/10.1016/0307-904X(80)90177-8
57 auto discA = A;
58 auto discB = B;
59 A = discA.log() / dt;
60 B = A * (discA - Eigen::Matrix<double, numStates, numStates>::Identity()).inverse() *
61 discB;
62}
63
74template <int numStates, int numInputs>
77 // zero order hold discretization for system and input matrices
78 // reference:
79 // https://en.wikipedia.org/wiki/Discretization#Discretization_of_linear_state_space_models
81 M.setZero();
82 M.template block<numStates, numStates>(0, 0) = A;
83 M.template block<numStates, numInputs>(0, numStates) = B;
84 M *= dt;
85
87 A = exp.template block<numStates, numStates>(0, 0);
88 B = exp.template block<numStates, numInputs>(0, numStates);
89}
90
99template <int numStates>
102 // Derived from equations in discreteToContinuous()
103 return (contA * dt).exp();
104}
105
118template <int numStates>
123 // zero order hold discretization of the system and state covariance matrices
124 // reference:
125 // https://en.wikipedia.org/wiki/Discretization#Discretization_of_process_noise
127 M.template block<numStates, numStates>(0, 0) = -contA;
128 M.template block<numStates, numStates>(0, numStates) = contQ;
129 M.template block<numStates, numStates>(numStates, 0).setZero();
130 M.template block<numStates, numStates>(numStates, numStates) = contA.transpose();
131 M *= dt;
132
134
136 G.block(0, numStates, numStates, numStates); // this is discA^-1 * Q
137 discA = G.block(numStates, numStates, numStates, numStates).transpose();
138
139 Eigen::Matrix<double, numStates, numStates> q = discA * AinvQ; // A * A^-1 * Q = Q
140 discQ = (q + q.transpose()) / 2.0; // make Q symmetric again if it became asymmetric
141}
142
152template <int numStates>
155 const Eigen::Matrix<double, numStates, numStates>& contQ, double dt) {
158 discretizeAQ(contA, contQ, discA, discQ, dt);
159 return discQ;
160}
161
170template <int numStates>
173 return contR / dt;
174}
175
196template <int numStates>
201 const Eigen::Matrix<double, numStates, numStates>& R, double tolerance = 1e-4,
202 int maxIter = -1) {
204 // see:
205 // https://scicomp.stackexchange.com/questions/30757/discrete-time-algebraic-riccati-equation-dare-solver-in-c
206 // to conform to the wikipedia article conventions, we replace H with P
207
208 mat_t currA = A;
209 mat_t currG = B * R.inverse() * B.transpose();
210 mat_t currP = Q;
211
212 mat_t I = mat_t::Identity();
213
214 double error;
215
216 for (int i = 0; maxIter < 0 || i < maxIter; i++) {
217 mat_t lastA = currA;
218 mat_t lastG = currG;
219 mat_t lastP = currP;
220
221 mat_t AIGHinv = lastA * (I + lastG * lastP).inverse();
222
223 currA = AIGHinv * lastA;
224 currG = lastG + AIGHinv * lastG * lastA.transpose();
225 currP = lastP + lastA.transpose() * lastP * (I + lastG * lastP).inverse() * lastA;
226
227 double error = (currP - lastP).norm() / currP.norm();
228 if (error > tolerance){
229 break;
230 }
231 }
232
233 return currP;
234}
235
249template <int stateDim, int size, int paramSize> class NoiseCovMat {
250public:
253
254 static_assert(stateDim > 0 && size > 0 && paramSize > 0, "Positive sizes are required!");
255
264
271 : func([mat](const state_t& x, const param_t& param) { return mat; }) {}
272
283 NoiseCovMat(const std::function<Eigen::Matrix<double, size, size>(const state_t&,
284 const param_t&)>& func)
285 : func(func) {}
286
298 Eigen::Matrix<double, size, size> get(const state_t& x, const param_t& param) {
299 return func(x, param);
300 }
301
302private:
303 std::function<Eigen::Matrix<double, size, size>(const state_t&, const param_t&)> func;
304};
305
315template <>
316class NoiseCovMat<-1, -1, -1> {
317public:
318 const int stateDim, size, paramDim;
319
326 NoiseCovMat(const Eigen::VectorXd& stdDevs, int stateDim, int paramSize);
327
333 NoiseCovMat(const Eigen::MatrixXd& mat, int stateDim, int paramSize);
334
345 NoiseCovMat(const std::function<Eigen::MatrixXd(const Eigen::VectorXd&,
346 const Eigen::VectorXd&)>& func,
347 int stateDim, int size, int paramSize);
348
361 Eigen::MatrixXd get(const Eigen::VectorXd& x, const Eigen::VectorXd& param) const;
362
363private:
364 std::function<Eigen::MatrixXd(const Eigen::VectorXd&, const Eigen::VectorXd&)> func;
365};
366
367using NoiseCovMatX = NoiseCovMat<-1, -1, -1>;
368
369} // namespace filters::statespace
size_t size() const
TransposeReturnType transpose()
const DiagonalWrapper< const Derived > asDiagonal() const
ArrayWrapper< Derived > array()
const MatrixLogarithmReturnValue< Derived > log() const
const MatrixExponentialReturnValue< Derived > exp() const
const Inverse< Derived > inverse() const
static const IdentityReturnType Identity()
Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > & setZero(Index size)
Eigen::Matrix< double, size, size > get(const state_t &x, const param_t &param)
Gets the noise covariance matrix, given the current state and additonal parameter.
Definition StateSpaceUtil.h:298
NoiseCovMat(const std::function< Eigen::Matrix< double, size, size >(const state_t &, const param_t &)> &func)
Create a time-varying noise covariance matrix.
Definition StateSpaceUtil.h:283
NoiseCovMat(const Eigen::Matrix< double, size, 1 > &stdDevs)
Create a time-invariant noise covariance matrix modelling independent noise with the given standard d...
Definition StateSpaceUtil.h:262
NoiseCovMat(const Eigen::Matrix< double, size, size > &mat)
Create a time-invariant noise covariance matrix equal to the given matrix.
Definition StateSpaceUtil.h:270
void exp(InputArray src, OutputArray dst)
double norm(InputArray src1, int normType=NORM_L2, InputArray mask=noArray())
void error(int _code, const String &_err, const char *_func, const char *_file, int _line)
Collection of utility methods for use with state space applications.
Definition StateSpaceUtil.cpp:5
Eigen::Matrix< double, numStates, numStates > discreteToContinuous(const Eigen::Matrix< double, numStates, numStates > &A, double dt)
Convert a discrete time system matrix to continuous time.
Definition StateSpaceUtil.h:39
Eigen::Matrix< double, numStates, numStates > discretizeQ(const Eigen::Matrix< double, numStates, numStates > &contA, const Eigen::Matrix< double, numStates, numStates > &contQ, double dt)
Discretizes a continuous time additive process noise covariance matrix.
Definition StateSpaceUtil.h:154
Eigen::Matrix< double, size, size > createCovarianceMatrix(const Eigen::Matrix< double, size, 1 > &stdDevs)
Create a covariance matrix modelling independent variables with the given standard deviations.
Definition StateSpaceUtil.h:23
void discretizeAQ(const Eigen::Matrix< double, numStates, numStates > &contA, const Eigen::Matrix< double, numStates, numStates > &contQ, Eigen::Matrix< double, numStates, numStates > &discA, Eigen::Matrix< double, numStates, numStates > &discQ, double dt)
Convert a continuous time system matrix and additive process noise matrix to discrete time.
Definition StateSpaceUtil.h:119
void continuousToDiscrete(Eigen::Matrix< double, numStates, numStates > &A, Eigen::Matrix< double, numStates, numInputs > &B, double dt)
Convert continuous time system and input matrices to discrete time.
Definition StateSpaceUtil.h:75
Eigen::Matrix< double, numStates, numStates > discretizeA(const Eigen::Matrix< double, numStates, numStates > &contA, double dt)
Convert a continuous time system matrix to discrete time.
Definition StateSpaceUtil.h:101
Eigen::Matrix< double, numStates, numStates > discretizeR(const Eigen::Matrix< double, numStates, numStates > &contR, double dt)
Discretizes a continuous time additive output noise covariance matrix.
Definition StateSpaceUtil.h:172