- 3.0.2 optimal control module.
UnscentedKalmanFilter-impl.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
8 namespace ct {
9 namespace optcon {
10 
11 template <typename _MatrixType, int _UpLo>
12 Cholesky<_MatrixType, _UpLo>::Cholesky() : Eigen::LLT<_MatrixType, _UpLo>()
13 {
14 }
15 
16 template <typename _MatrixType, int _UpLo>
17 Cholesky<_MatrixType, _UpLo>::Cholesky(const _MatrixType& m) : Eigen::LLT<_MatrixType, _UpLo>(m)
18 {
19 }
20 
21 template <typename _MatrixType, int _UpLo>
23 {
24  this->m_matrix.setIdentity();
25  this->m_isInitialized = true;
26  return *this;
27 }
28 
29 template <typename _MatrixType, int _UpLo>
31 {
32  eigen_assert(this->m_isInitialized && "LLT is not initialized.");
33  return this->m_matrix.isIdentity();
34 }
35 
36 template <typename _MatrixType, int _UpLo>
37 template <typename Derived>
38 Cholesky<_MatrixType, _UpLo>& Cholesky<_MatrixType, _UpLo>::setL(const Eigen::MatrixBase<Derived>& matrix)
39 {
40  this->m_matrix = matrix.template triangularView<Eigen::Lower>();
41  this->m_isInitialized = true;
42  return *this;
43 }
44 
45 template <typename _MatrixType, int _UpLo>
46 template <typename Derived>
47 Cholesky<_MatrixType, _UpLo>& Cholesky<_MatrixType, _UpLo>::setU(const Eigen::MatrixBase<Derived>& matrix)
48 {
49  this->m_matrix = matrix.template triangularView<Eigen::Upper>().adjoint();
50  this->m_isInitialized = true;
51  return *this;
52 }
53 
54 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
58  const state_vector_t& x0,
59  SCALAR alpha,
60  SCALAR beta,
61  SCALAR kappa,
63  : Base(f, h, x0), alpha_(alpha), beta_(beta), kappa_(kappa), P_(P0)
64 {
65 }
66 
67 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
72  : Base(f, h, ukf_settings.x0),
73  alpha_(ukf_settings.alpha),
74  beta_(ukf_settings.beta),
75  kappa_(ukf_settings.kappa),
76  P_(ukf_settings.P0)
77 {
78 }
79 
80 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
82  const ct::core::Time& dt,
83  const ct::core::Time& t) -> const state_vector_t&
84 {
85  if (!computeSigmaPoints())
86  throw std::runtime_error("UnscentedKalmanFilter : Numerical error.");
87 
88  this->x_est_ = computeStatePrediction(u, dt, t);
89 
90  computeCovarianceFromSigmaPoints<STATE_DIM>(
91  this->x_est_, sigmaStatePoints_, this->f_->computeDerivativeNoise(this->x_est_, u, dt, t), P_);
92 
93  return this->x_est_;
94 }
95 
96 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
98  const ct::core::Time& dt,
99  const ct::core::Time& t) -> const state_vector_t&
100 {
101  SigmaPoints<OUTPUT_DIM> sigmaMeasurementPoints;
102 
103  // Predict measurement (and corresponding sigma points)
105 
106  // Compute innovation covariance
108  computeCovarianceFromSigmaPoints<OUTPUT_DIM>(
109  y, sigmaMeasurementPoints, this->h_->computeDerivativeNoise(this->x_est_, t), P);
110 
111  Eigen::Matrix<SCALAR, STATE_DIM, OUTPUT_DIM> K;
112  computeKalmanGain(y, sigmaMeasurementPoints, P, K);
113 
114  // Update state
115  this->x_est_ += K * (z - y);
116 
117  // Update state covariance
118  updateStateCovariance(K, P);
119 
120  return this->x_est_;
121 }
122 
123 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
125 {
126  // Get square root of covariance
128  llt.compute(P_);
129  if (llt.info() != Eigen::Success)
130  return false;
131 
132  Eigen::Matrix<SCALAR, STATE_DIM, STATE_DIM> _S = llt.matrixL().toDenseMatrix();
133 
134  // Set left "block" (first column)
135  this->sigmaStatePoints_.template leftCols<1>() = this->x_est_;
136  // Set center block with x + gamma_ * S
137  this->sigmaStatePoints_.template block<STATE_DIM, STATE_DIM>(0, 1) = (gamma_ * _S).colwise() + this->x_est_;
138  // Set right block with x - gamma_ * S
139  this->sigmaStatePoints_.template rightCols<STATE_DIM>() = (-gamma_ * _S).colwise() + this->x_est_;
140 
141  return true;
142 }
143 
144 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
145 template <size_t SIZE>
147  const Eigen::Matrix<SCALAR, SIZE, 1>& mean,
148  const SigmaPoints<SIZE>& sigmaPoints,
149  const Covariance<SIZE>& noiseCov,
150  Covariance<SIZE>& cov)
151 {
152  SigmaPoints<SIZE> W = this->sigmaWeights_c_.transpose().template replicate<SIZE, 1>();
153  SigmaPoints<SIZE> tmp = (sigmaPoints.colwise() - mean);
154  cov = tmp.cwiseProduct(W) * tmp.transpose() + noiseCov;
155 
156  return true;
157 }
158 
159 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
162  const SigmaPoints<OUTPUT_DIM>& sigmaMeasurementPoints,
163  const Covariance<OUTPUT_DIM>& P_yy,
164  Eigen::Matrix<SCALAR, STATE_DIM, OUTPUT_DIM>& K)
165 {
166  SigmaPoints<STATE_DIM> W = this->sigmaWeights_c_.transpose().template replicate<STATE_DIM, 1>();
167  Eigen::Matrix<SCALAR, STATE_DIM, OUTPUT_DIM> P_xy =
168  (sigmaStatePoints_.colwise() - this->x_est_).cwiseProduct(W).eval() *
169  (sigmaMeasurementPoints.colwise() - y).transpose();
170 
171  K = P_xy * P_yy.inverse();
172  return true;
173 }
174 
175 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
177  const Eigen::Matrix<SCALAR, STATE_DIM, OUTPUT_DIM>& K,
178  const Covariance<OUTPUT_DIM>& P)
179 {
180  P_ -= K * P * K.transpose();
181  return true;
182 }
183 
184 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
187  const ct::core::Time& dt,
188  const ct::core::Time& t) -> const state_vector_t
189 {
190  // Pass each sigma point through non-linear state transition function
192 
193  // Compute predicted state from predicted sigma points
194  return computePredictionFromSigmaPoints<STATE_DIM>(sigmaStatePoints_);
195 }
196 
197 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
200  SigmaPoints<OUTPUT_DIM>& sigmaMeasurementPoints,
201  const ct::core::Time& t)
202 {
203  // Predict measurements for each sigma point
204  computeSigmaPointMeasurements(sigmaMeasurementPoints, t);
205 
206  // Predict measurement from sigma measurement points
207  return computePredictionFromSigmaPoints<OUTPUT_DIM>(sigmaMeasurementPoints);
208 }
209 
210 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
212 
213 {
214  SCALAR L = SCALAR(STATE_DIM);
215  lambda_ = alpha_ * alpha_ * (L + kappa_) - L;
216  gamma_ = std::sqrt(L + lambda_);
217 
218  // Make sure L != -lambda_ to avoid division by zero
219  assert(std::abs(L + lambda_) > 1e-6);
220 
221  // Make sure L != -kappa_ to avoid division by zero
222  assert(std::abs(L + kappa_) > 1e-6);
223 
224  SCALAR W_m_0 = lambda_ / (L + lambda_);
225  SCALAR W_c_0 = W_m_0 + (SCALAR(1) - alpha_ * alpha_ + beta_);
226  SCALAR W_i = SCALAR(1) / (SCALAR(2) * alpha_ * alpha_ * (L + kappa_));
227 
228  // Make sure W_i > 0 to avoid square-root of negative number
229  assert(W_i > SCALAR(0));
230 
231  sigmaWeights_m_[0] = W_m_0;
232  sigmaWeights_c_[0] = W_c_0;
233 
234  for (int i = 1; i < SigmaPointCount; ++i)
235  {
236  sigmaWeights_m_[i] = W_i;
237  sigmaWeights_c_[i] = W_i;
238  }
239 }
240 
241 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
244  const ct::core::Time& dt,
245  const ct::core::Time& t)
246 {
247  for (size_t i = 0; i < SigmaPointCount; ++i)
248  {
249  sigmaStatePoints_.col(i) = this->f_->computeDynamics(sigmaStatePoints_.col(i), u, dt, t);
250  }
251 }
252 
253 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
255  SigmaPoints<OUTPUT_DIM>& sigmaMeasurementPoints,
256  const ct::core::Time& t)
257 {
258  for (size_t i = 0; i < SigmaPointCount; ++i)
259  {
260  sigmaMeasurementPoints.col(i) = this->h_->computeMeasurement(sigmaStatePoints_.col(i), t);
261  }
262 }
263 
264 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t OUTPUT_DIM, typename SCALAR>
265 template <size_t DIM>
267  const SigmaPoints<DIM>& sigmaPoints) -> state_vector_t
268 {
269  // Use efficient matrix x vector computation
270  return sigmaPoints * sigmaWeights_m_;
271 }
272 
273 } // namespace optcon
274 } // namespace ct
UnscentedKalmanFilter(std::shared_ptr< SystemModelBase< STATE_DIM, CONTROL_DIM, SCALAR >> f, std::shared_ptr< LinearMeasurementModel< OUTPUT_DIM, STATE_DIM, SCALAR >> h, const state_vector_t &x0=state_vector_t::Zero(), SCALAR alpha=SCALAR(1.0), SCALAR beta=SCALAR(2.0), SCALAR kappa=SCALAR(0.0), const ct::core::StateMatrix< STATE_DIM, SCALAR > &P0=ct::core::StateMatrix< STATE_DIM, SCALAR >::Identity())
Constructor.
Definition: UnscentedKalmanFilter-impl.h:55
Cholesky & setU(const Eigen::MatrixBase< Derived > &matrix)
Set upper triangular part of the decomposition.
bool computeCovarianceFromSigmaPoints(const Eigen::Matrix< SCALAR, SIZE, 1 > &mean, const SigmaPoints< SIZE > &sigmaPoints, const Covariance< SIZE > &noiseCov, Covariance< SIZE > &cov)
Estimate covariance from sigma points and noise covariance.
Definition: UnscentedKalmanFilter-impl.h:146
bool computeSigmaPoints()
Compute sigma points from current state and covariance estimates.
Definition: UnscentedKalmanFilter-impl.h:124
bool isIdentity() const
Check whether the decomposed matrix is the identity matrix.
Definition: UnscentedKalmanFilter-impl.h:30
const state_vector_t & predict(const control_vector_t &u, const ct::core::Time &dt, const ct::core::Time &t) override
Estimator predict method.
Definition: UnscentedKalmanFilter-impl.h:81
std::shared_ptr< SystemModelBase< STATE_DIM, CONTROL_DIM, SCALAR > > f_
System model for propagating the system.
Definition: EstimatorBase.h:64
void computeSigmaPointTransition(const ct::core::ControlVector< CONTROL_DIM, SCALAR > &u, const ct::core::Time &dt, const ct::core::Time &t)
Propagate sigma points through the system dynamics. Using CTSystemModel here will not provide a desir...
Definition: UnscentedKalmanFilter-impl.h:242
ct::core::ControlVector< control_dim > u
Definition: LoadFromFileTest.cpp:21
bool computeKalmanGain(const ct::core::OutputVector< OUTPUT_DIM, SCALAR > &y, const SigmaPoints< OUTPUT_DIM > &sigmaMeasurementPoints, const Covariance< OUTPUT_DIM > &P_yy, Eigen::Matrix< SCALAR, STATE_DIM, OUTPUT_DIM > &K)
Compute the Kalman Gain using sigma points..
Definition: UnscentedKalmanFilter-impl.h:160
std::shared_ptr< LinearMeasurementModel< OUTPUT_DIM, STATE_DIM, SCALAR > > h_
Observation model used to calculate the output error.
Definition: EstimatorBase.h:67
Cholesky square root decomposition of a symmetric positive-definite matrix.
Definition: UnscentedKalmanFilter.h:22
clear all close all load ct GNMSLog0 mat reformat t
Definition: gnmsPlot.m:6
static constexpr size_t SigmaPointCount
Definition: UnscentedKalmanFilter.h:74
const double dt
Definition: LQOCSolverTiming.cpp:18
ct::core::OutputVector< OUTPUT_DIM, SCALAR > computeMeasurementPrediction(SigmaPoints< OUTPUT_DIM > &sigmaMeasurementPoints, const ct::core::Time &t=0)
Predict the next measurement.
Definition: UnscentedKalmanFilter-impl.h:199
void computeWeights()
Compute weights of sigma points.
Definition: UnscentedKalmanFilter-impl.h:211
Linear Measurement Model is an interface for linear measurement models most commonly used in practice...
Definition: LinearMeasurementModel.h:23
const state_vector_t & update(const output_vector_t &y, const ct::core::Time &dt, const ct::core::Time &t) override
Estimator update method.
Definition: UnscentedKalmanFilter-impl.h:97
CppAD::AD< CppAD::cg::CG< double > > SCALAR
Eigen::Matrix< SCALAR, SIZE, SigmaPointCount > SigmaPoints
Definition: UnscentedKalmanFilter.h:77
for i
Definition: mpc_unittest_plotting.m:14
state_vector_t x_est_
State estimate.
Definition: EstimatorBase.h:70
bool updateStateCovariance(const Eigen::Matrix< SCALAR, STATE_DIM, OUTPUT_DIM > &K, const Covariance< OUTPUT_DIM > &P)
Compute the Kalman Gain using sigma points..
Definition: UnscentedKalmanFilter-impl.h:176
void computeSigmaPointMeasurements(SigmaPoints< OUTPUT_DIM > &sigmaMeasurementPoints, const ct::core::Time &t=0)
Predict measurements of sigma points.
Definition: UnscentedKalmanFilter-impl.h:254
Cholesky()
Constructor.
Definition: UnscentedKalmanFilter-impl.h:12
Cholesky & setL(const Eigen::MatrixBase< Derived > &matrix)
Set lower triangular part of the decomposition.
System model is an interface that encapsulates the integrator to be able to propagate the system...
Definition: SystemModelBase.h:21
const state_vector_t computeStatePrediction(const ct::core::ControlVector< CONTROL_DIM, SCALAR > &u, const ct::core::Time &dt, const ct::core::Time &t=0)
Update state covariance from Kalman gain and sigma points.
Definition: UnscentedKalmanFilter-impl.h:185
Estimator base.
Definition: EstimatorBase.h:21
StateVector< state_dim > x0
Definition: ConstrainedNLOCTest.cpp:14
Settings for setting up an UnscentedKF.
Definition: FilterSettings.h:182
state_vector_t computePredictionFromSigmaPoints(const SigmaPoints< DIM > &sigmaPoints)
Make a prediction based on sigma points.
Eigen::Matrix< SCALAR, SIZE, SIZE > Covariance
Definition: UnscentedKalmanFilter.h:80
Cholesky & setIdentity()
Set decomposition to identity.
Definition: UnscentedKalmanFilter-impl.h:22
double Time