gtsam
Loading...
Searching...
No Matches
LieGroupEKF.h
Go to the documentation of this file.
1/* ----------------------------------------------------------------------------
2
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7
8 * See LICENSE for the license information
9
10 * -------------------------------------------------------------------------- */
11
25
26#pragma once
27
28#include <gtsam/base/Lie.h> // Include for Lie group traits and operations
29#include <gtsam/base/VectorSpace.h>
30#include <gtsam/navigation/ManifoldEKF.h> // Include the base class
31
32#include <functional> // For std::function
33#include <type_traits>
34#include <utility>
35
36namespace gtsam {
37
59template <typename G>
60class LieGroupEKF : public ManifoldEKF<G> {
61 public:
62 using This = LieGroupEKF<G>;
64 static constexpr int Dim = Base::Dim;
65
66 using Jacobian = typename Base::Jacobian;
67 using Covariance = typename Base::Covariance;
69
70 private:
75 template <typename Dynamics>
76 using enable_if_dynamics =
77 std::enable_if_t<!std::is_convertible_v<Dynamics, TangentVector> &&
78 std::is_invocable_r_v<TangentVector, Dynamics, const G&,
80
85 template <typename Control, typename Dynamics>
86 using enable_if_full_dynamics = std::enable_if_t<
87 std::is_invocable_r_v<TangentVector, Dynamics, const G&, const Control&,
89
90 template <typename T, typename = void>
91 struct has_adjoint_map : std::false_type {};
92
93 template <typename T>
94 struct has_adjoint_map<
95 T, std::void_t<decltype(T::adjointMap(
96 std::declval<typename traits<T>::TangentVector>()))>>
97 : std::true_type {};
98
99 public:
105 LieGroupEKF(const G& X0, const Covariance& P0) : Base(X0, P0) {
106 static_assert(IsLieGroup<G>::value,
107 "Template parameter G must be a GTSAM Lie Group");
108 }
109
112 using Base::predict;
113
125 template <size_t K = 1>
127 double dt, const G& U, const Jacobian& Dexp) const {
128 if constexpr (std::is_same_v<G, Matrix>) {
129 (void)xi;
130 (void)U;
131 (void)Dexp;
132 return expm(Df * dt, K);
133 } else {
134 if constexpr (K == 1) {
135 // First-order Lie group transition matrix
136 return traits<G>::Inverse(U).AdjointMap() + Dexp * Df * dt;
137 } else {
138 // Higher-order Lie group transition matrix via matrix exponential.
139 //
140 // GTSAM's LieGroupEKF uses a left-invariant error, i.e. we write the
141 // true state as
142 //
143 // X_true ≈ X_hat * Exp(η),
144 //
145 // and η lives in the tangent space at the identity. Even if the
146 // *global* perturbation is constant, composing the nominal motion X_hat
147 // with Exp(ξ dt) on the right will "drag" η along the group because G
148 // is non-commutative. The Baker–Campbell–Hausdorff expansion shows that
149 // the linearized error dynamics contain an extra term -ad_ξ η coming
150 // from this non-commutativity, where ad_ξ(·) = [ξ, ·] is the Lie
151 // bracket. With this convention, and a dynamics linearization Df =
152 // ∂ξ/∂(local X), the continuous-time error satisfies approximately
153 //
154 // dη/dt ≈ (Df - ad_ξ) η,
155 //
156 // and the corresponding discrete-time transition matrix is
157 //
158 // Φ ≈ expm((Df - ad_ξ) dt).
159 //
160 // This is exactly what we implement below.
161 static_assert(
162 has_adjoint_map<G>::value,
163 "transitionMatrix<K> requires G::adjointMap(xi) when K > 1.");
164 Jacobian ad_xi = G::adjointMap(xi);
165 const Matrix A = Df - ad_xi;
166 return expm(A * dt, K);
167 }
168 }
169 }
170
186 template <size_t K = 1, typename Dynamics,
187 typename = enable_if_dynamics<Dynamics>>
188 G predictMean(Dynamics&& f, double dt,
189 OptionalJacobian<Dim, Dim> Phi = {}) const {
190 if (Phi) {
191 Jacobian Df;
192 TangentVector xi = f(this->X_, &Df);
193 if constexpr (std::is_same_v<G, Matrix>) {
194 *Phi = expm(Df * dt, K);
195 return traits<G>::Retract(this->X_, xi * dt);
196 } else {
197 Jacobian Dexp;
198 G U = traits<G>::Expmap(xi * dt, &Dexp);
199 *Phi = transitionMatrix<K>(xi, Df, dt, U, Dexp);
200 return traits<G>::Compose(this->X_, U);
201 }
202 } else {
203 TangentVector xi = f(this->X_, nullptr);
204 if constexpr (std::is_same_v<G, Matrix>) {
205 return traits<G>::Retract(this->X_, xi * dt);
206 } else {
207 G U = traits<G>::Expmap(xi * dt);
208 return traits<G>::Compose(this->X_, U);
209 }
210 }
211 }
212
226 template <size_t K = 1, typename Dynamics,
227 typename = enable_if_dynamics<Dynamics>>
228 void predict(Dynamics&& f, double dt, const Covariance& Q) {
229 Jacobian Phi;
230 if constexpr (Dim == Eigen::Dynamic) {
231 Phi.resize(this->n_, this->n_);
232 }
233 G X_next = predictMean<K>(std::forward<Dynamics>(f), dt, Phi);
234 predict(X_next, Phi,
235 Q * dt); // Q interpreted as continuous-time; discretize with dt
236 }
237
254 template <size_t K = 1, typename Control, typename Dynamics,
255 typename = enable_if_full_dynamics<Control, Dynamics>>
256 G predictMean(Dynamics&& f, const Control& u, double dt,
257 OptionalJacobian<Dim, Dim> Phi = {}) const {
258 return predictMean<K>(
259 [&](const G& X, OptionalJacobian<Dim, Dim> Df) { return f(X, u, Df); },
260 dt, Phi);
261 }
262
278 template <size_t K = 1, typename Control, typename Dynamics,
279 typename = enable_if_full_dynamics<Control, Dynamics>>
280 void predict(Dynamics&& f, const Control& u, double dt, const Covariance& Q) {
281 return predict<K>(
282 [&](const G& X, OptionalJacobian<Dim, Dim> Df) { return f(X, u, Df); },
283 dt, Q);
284 }
285
305 void predictWithCompose(const G& U, const Jacobian& J_UX,
306 const Covariance& Q) {
307 Jacobian A_local;
308 if constexpr (std::is_same_v<G, Matrix>) {
309 const Matrix& I_n = this->I_;
310 A_local = I_n + J_UX;
311 this->X_ = traits<Matrix>::Retract(this->X_, U);
312 } else {
313 A_local = traits<G>::Inverse(U).AdjointMap() + J_UX;
314 this->X_ = this->X_.compose(U);
315 }
316 this->P_ = A_local * this->P_ * A_local.transpose() + Q;
317 }
318
320 using Base::update;
321
322}; // LieGroupEKF
323
324} // namespace gtsam
Base class and basic functions for Lie types.
Extended Kalman Filter base class on a generic manifold M.
STL namespace.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
Matrix expm(const Matrix &A, size_t K)
Numerical exponential map, naive approach, not industrial strength !
Definition Matrix.cpp:587
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
OptionalJacobian is an Eigen::Ref like class that can take be constructed using either a fixed size o...
Definition OptionalJacobian.h:40
G predictMean(Dynamics &&f, double dt, OptionalJacobian< Dim, Dim > Phi={}) const
Predict mean and Jacobian Phi with state-dependent dynamics: xi = f(X_k, Df) (tangent vector dynamics...
Definition LieGroupEKF.h:188
ManifoldEKF< G > Base
Base class type.
Definition LieGroupEKF.h:63
void predict(Dynamics &&f, const Control &u, double dt, const Covariance &Q)
Predict step with state and control input dynamics: Wraps the dynamics function and calls the state-o...
Definition LieGroupEKF.h:280
G predictMean(Dynamics &&f, const Control &u, double dt, OptionalJacobian< Dim, Dim > Phi={}) const
Predict mean and Jacobian A with state and control input dynamics: Wraps the dynamics function and ca...
Definition LieGroupEKF.h:256
typename Base::TangentVector TangentVector
Tangent vector type.
Definition LieGroupEKF.h:68
void predict(Dynamics &&f, double dt, const Covariance &Q)
Predict step with state-dependent dynamics: Uses predictMean to compute X_{k+1} and Phi,...
Definition LieGroupEKF.h:228
Jacobian transitionMatrix(const TangentVector &xi, const Jacobian &Df, double dt, const G &U, const Jacobian &Dexp) const
Compute the discrete-time transition matrix Φ corresponding to a continuous-time linearization (Df) o...
Definition LieGroupEKF.h:126
typename Base::Jacobian Jacobian
Dim x Dim.
Definition LieGroupEKF.h:66
static constexpr int Dim
Compile-time dimension of G.
Definition LieGroupEKF.h:64
typename Base::Covariance Covariance
Dim x Dim.
Definition LieGroupEKF.h:67
void predictWithCompose(const G &U, const Jacobian &J_UX, const Covariance &Q)
Predict using a precomputed group increment U and its Jacobian J_UX.
Definition LieGroupEKF.h:305
LieGroupEKF(const G &X0, const Covariance &P0)
Constructor: initialize with state and covariance.
Definition LieGroupEKF.h:105
void update(const Measurement &prediction, const Eigen::Matrix< double, traits< Measurement >::dimension, Dim > &H, const Measurement &z, const Eigen::Matrix< double, traits< Measurement >::dimension, traits< Measurement >::dimension > &R, bool performReset=true)
Definition ManifoldEKF.h:156
Eigen::Matrix< double, Dim, Dim > Covariance
Definition ManifoldEKF.h:58
Jacobian I_
Definition ManifoldEKF.h:286
static constexpr int Dim
Definition ManifoldEKF.h:53
G X_
Definition ManifoldEKF.h:284
Eigen::Matrix< double, Dim, Dim > Jacobian
Definition ManifoldEKF.h:60
ManifoldEKF(const G &X0, const Covariance &P0)
Definition ManifoldEKF.h:67
Covariance P_
Definition ManifoldEKF.h:285
typename traits< G >::TangentVector TangentVector
Definition ManifoldEKF.h:56
size_t n_
Definition ManifoldEKF.h:287
void predict(const G &X_next, const Jacobian &F, const Covariance &Q)
Definition ManifoldEKF.h:114