gtsam
Loading...
Searching...
No Matches
EquivariantFilter.h
Go to the documentation of this file.
1
11
12#pragma once
13
15#include <gtsam/base/Matrix.h>
16#include <gtsam/base/Vector.h>
19
20namespace gtsam {
21
49template <typename M, typename Symmetry>
50class EquivariantFilter : public ManifoldEKF<M> {
51 public:
52 using Base = ManifoldEKF<M>;
53
54 // Manifold traits
55 static constexpr int DimM = Base::Dim;
56 using TangentM = typename Base::TangentVector;
57 using MatrixM = typename Base::Jacobian;
58 using CovarianceM = typename Base::Covariance;
59
60 // Group traits
61 using G = typename Symmetry::Group;
62 static constexpr int DimG = traits<G>::dimension;
63 using TangentG = typename traits<G>::TangentVector;
64
65 // Cross-dimension helpers
66 using MatrixMG = Eigen::Matrix<double, DimM, DimG>;
67 using MatrixGM = Eigen::Matrix<double, DimG, DimM>;
68
69 private:
70 M xi_ref_; // Origin (reference) state on the manifold
71 typename Symmetry::Orbit act_on_ref_; // Orbit of the reference state
72 MatrixMG Dphi0_; // Differential of state action at identity
73 MatrixGM InnovationLift_; // Innovation lift matrix ((Dphi0)^+)
74
75 G g_; // Group element estimate
76
77 protected:
78
86
88 void resetReferenceAndGroup(const M& xi_ref, const CovarianceM& P,
89 const G& g) {
90 xi_ref_ = xi_ref;
91 g_ = g;
92
93 // Recompute Dphi0 and innovation lift matrix from current reference state
94 act_on_ref_ = typename Symmetry::Orbit(xi_ref_);
95 const G identity_at_g = traits<G>::Compose(g_.inverse(), g_);
96 act_on_ref_(identity_at_g, &Dphi0_);
97 InnovationLift_ = Dphi0_.completeOrthogonalDecomposition().pseudoInverse();
98
99 if constexpr (DimM == Eigen::Dynamic) {
100 this->n_ = traits<M>::GetDimension(xi_ref_);
101 this->I_ = MatrixM::Identity(this->n_, this->n_);
102 }
103 this->P_ = P;
104 this->X_ = act_on_ref_(g_);
105 }
106
108 const M& referenceState() const { return xi_ref_; }
109
114 template <typename Lift, typename InputOrbit>
115 TangentG liftAtOrigin(const InputOrbit& psi_u,
116 OptionalJacobian<DimG, DimM> D_lift = {}) const {
117 Lift lift_u_origin(psi_u(g_.inverse()));
118 return lift_u_origin(xi_ref_, D_lift);
119 }
120
127 void propagate(const TangentG& increment, const MatrixM& Phi,
128 const CovarianceM& Qd) {
129 const G step = traits<G>::Expmap(increment);
130 const G g_next = Symmetry::type == ActionType::Left
131 ? traits<G>::Compose(step, g_)
132 : traits<G>::Compose(g_, step);
133 Base::predict(act_on_ref_(g_next), Phi, Qd);
134 g_ = g_next;
135 }
136
141 void applyCorrection(const TangentG& delta_x) {
142 const G step = traits<G>::Expmap(delta_x);
143 g_ = Symmetry::type == ActionType::Left
144 ? traits<G>::Compose(g_, step)
145 : traits<G>::Compose(step, g_);
146 this->X_ = act_on_ref_(g_);
147 }
148
149 public:
157 EquivariantFilter(const M& xi_ref, const CovarianceM& Sigma,
158 const G& X0 = traits<G>::Identity())
159 : Base(xi_ref, Sigma), xi_ref_(xi_ref), act_on_ref_(xi_ref), g_(X0) {
160 // Compute differential of action phi at identity (Dphi0)
161 const G identity_at_g = traits<G>::Compose(g_.inverse(), g_);
162 act_on_ref_(identity_at_g, &Dphi0_);
163
164 // Precompute the Innovation Lift matrix (pseudo-inverse of Dphi0)
165 InnovationLift_ = Dphi0_.completeOrthogonalDecomposition().pseudoInverse();
166 this->X_ = act_on_ref_(g_);
167 }
168
170 using Base::state;
171
173 const typename Base::Covariance& errorCovariance() const { return this->P_; }
174
183 MatrixM actionDifferential() const {
184 MatrixM J;
185 if constexpr (MatrixM::RowsAtCompileTime == Eigen::Dynamic) {
186 J.resize(this->n_, this->n_);
187 }
188 const typename Symmetry::Diffeomorphism action_at_g(g_);
189 action_at_g(xi_ref_, &J);
190 return J;
191 }
192
202 CovarianceM covariance() const {
203 const MatrixM J = actionDifferential();
204 return J * this->P_ * J.transpose();
205 }
206
208 const G& groupEstimate() const { return g_; }
209
237 template <typename Lift, typename InputOrbit>
238 MatrixM computeErrorDynamicsMatrix(const InputOrbit& psi_u) const {
239 MatrixGM D_lift;
240 liftAtOrigin<Lift>(psi_u, &D_lift);
241 return Dphi0_ * D_lift;
242 }
243
251 template <size_t K = 1>
252 MatrixM transitionMatrix(const MatrixM& A, double dt) const {
253 if constexpr (K == 1) {
254 return this->I_ + A * dt;
255 } else {
256 return MatrixM(expm(A * dt, K));
257 }
258 }
259
282 template <size_t K = 1, typename Lift, typename InputOrbit>
283 void predict(const Lift& lift_u, const InputOrbit& psi_u, const MatrixM& Qc,
284 double dt) {
285 const MatrixM A = computeErrorDynamicsMatrix<Lift>(psi_u);
286 predictWithJacobian<K>(lift_u, A, Qc, dt);
287 }
288
312 template <size_t K = 1, typename Lift>
313 void predictWithJacobian(const Lift& lift_u, const MatrixM& A,
314 const MatrixM& Qc, double dt) {
315 const TangentG Lambda = lift_u(this->state());
316 propagate(Lambda * dt, transitionMatrix<K>(A, dt), CovarianceM(Qc * dt));
317 }
318
335 template <typename Lift>
336 void predictWithTransition(const Lift& lift_u, const MatrixM& Phi,
337 const CovarianceM& Qd, double dt) {
338 propagate(lift_u(this->state()) * dt, Phi, Qd);
339 }
340
353 template <typename Measurement>
354 void update(
355 const Measurement& prediction,
356 const Eigen::Matrix<double, traits<Measurement>::dimension, DimM>& H,
357 const Measurement& z,
358 const Eigen::Matrix<double, traits<Measurement>::dimension,
360 static constexpr int MeasDim = traits<Measurement>::dimension;
361
362 // Innovation: y = h(x_pred) - z. In tangent space: local(z, h(x_pred))
363 // NOTE: we use the `z_hat - z` sign convention, NOT `z - z_hat`.
364 typename traits<Measurement>::TangentVector innovation =
365 traits<Measurement>::Local(z, prediction);
366
367 // Kalman Gain: K = P H^T S^-1
368 // K will be Eigen::Matrix<double, Dim, MeasDim>
369 Eigen::Matrix<double, DimM, MeasDim> K = this->KalmanGain(H, R);
370
371 // Correction in Manifold tangent space
372 // K matches dimensions with innovation, so result is TangentM
373 TangentM delta_xi = -K * innovation;
374
375 // Lift correction to Group tangent space
376 TangentG delta_x = InnovationLift_ * delta_xi;
377 applyCorrection(delta_x);
378
379 // Update covariance on Manifold using Joseph form
380 this->JosephUpdate(K, H, R);
381 }
382
384 template <typename Z, typename Func>
385 void update(Func&& h, const Z& z,
386 const Eigen::Matrix<double, traits<Z>::dimension,
388 static_assert(IsManifold<Z>::value,
389 "Template parameter Z must be a GTSAM Manifold.");
390
391 Matrix H(traits<Z>::GetDimension(z), this->n_);
392 Z prediction = h(this->X_, H);
393 update<Z>(prediction, H, z, R);
394 }
395
397 void updateWithVector(const gtsam::Vector& prediction, const Matrix& H,
398 const gtsam::Vector& z, const Matrix& R) {
399 this->validateInputs(prediction, H, z, R);
400 update<Vector>(prediction, H, z, R);
401 }
402
404 template <typename InnovationLiftFn>
405 void updateWithVector(const gtsam::Vector& prediction, const Matrix& H,
406 const gtsam::Vector& z, const Matrix& R,
407 InnovationLiftFn&& innovationLift) {
408 this->validateInputs(prediction, H, z, R);
409
410 const gtsam::Vector innovation = traits<Vector>::Local(z, prediction);
411 const Matrix K = this->KalmanGain(H, R);
412 const TangentM delta_xi = -K * innovation;
413 const TangentG delta_x = innovationLift(delta_xi);
414
415 applyCorrection(delta_x);
416 this->JosephUpdate(K, H, R);
417 }
418};
419
420} // namespace gtsam
typedef and functions to augment Eigen's MatrixXd
Group action concept and CRTP base class.
typedef and functions to augment Eigen's VectorXd
Extended Kalman Filter base class on a generic manifold M.
A non-templated config holding any types of Manifold-group elements.
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
MatrixM computeErrorDynamicsMatrix(const InputOrbit &psi_u) const
Compute the error dynamics matrix A (Automatic).
Definition EquivariantFilter.h:238
void predict(const Lift &lift_u, const InputOrbit &psi_u, const MatrixM &Qc, double dt)
Propagate the filter state (Automatic).
Definition EquivariantFilter.h:283
EquivariantFilter(const M &xi_ref, const CovarianceM &Sigma, const G &X0=traits< G >::Identity())
Initialize the Equivariant Filter.
Definition EquivariantFilter.h:157
const M & state() const
State on the manifold M is given by the base class.
Definition ManifoldEKF.h:92
void update(Func &&h, const Z &z, const Eigen::Matrix< double, traits< Z >::dimension, traits< Z >::dimension > &R)
Same API as ManifoldEKF for measurement update with model function.
Definition EquivariantFilter.h:385
void propagate(const TangentG &increment, const MatrixM &Phi, const CovarianceM &Qd)
Advance using a lift evaluated at the current estimate and propagate covariance with an already-discr...
Definition EquivariantFilter.h:127
void updateWithVector(const gtsam::Vector &prediction, const Matrix &H, const gtsam::Vector &z, const Matrix &R)
Same API as ManifoldEKF for measurement update with vector inputs.
Definition EquivariantFilter.h:397
void update(const Measurement &prediction, const Eigen::Matrix< double, traits< Measurement >::dimension, DimM > &H, const Measurement &z, const Eigen::Matrix< double, traits< Measurement >::dimension, traits< Measurement >::dimension > &R)
Measurement update: Corrects the state and covariance using a pre-calculated predicted measurement an...
Definition EquivariantFilter.h:354
CovarianceM covariance() const
Covariance in the tangent space at the current state.
Definition EquivariantFilter.h:202
MatrixM transitionMatrix(const MatrixM &A, double dt) const
Discretize continuous-time error dynamics δ̇ = A δ over dt.
Definition EquivariantFilter.h:252
const M & referenceState() const
Access current reference state used as the EqF chart origin.
Definition EquivariantFilter.h:108
TangentG liftAtOrigin(const InputOrbit &psi_u, OptionalJacobian< DimG, DimM > D_lift={}) const
Evaluate the lift at the reference with input u_origin = psi_u(X^-1).
Definition EquivariantFilter.h:115
MatrixM actionDifferential() const
Differential of the group action at the reference state.
Definition EquivariantFilter.h:183
void predictWithJacobian(const Lift &lift_u, const MatrixM &A, const MatrixM &Qc, double dt)
Propagate the filter state (Explicit).
Definition EquivariantFilter.h:313
void applyCorrection(const TangentG &delta_x)
Apply an innovation correction, which lives in error coordinates at the reference state,...
Definition EquivariantFilter.h:141
void predictWithTransition(const Lift &lift_u, const MatrixM &Phi, const CovarianceM &Qd, double dt)
Propagate with an already-discretized transition and process noise.
Definition EquivariantFilter.h:336
void updateWithVector(const gtsam::Vector &prediction, const Matrix &H, const gtsam::Vector &z, const Matrix &R, InnovationLiftFn &&innovationLift)
Vector measurement update using a custom innovation lift delta_x=f(delta_xi).
Definition EquivariantFilter.h:405
const G & groupEstimate() const
Definition EquivariantFilter.h:208
void resetReferenceAndGroup(const M &xi_ref, const CovarianceM &P, const G &g)
Synchronization hooks for derived filters with dynamic runtime structure.
Definition EquivariantFilter.h:88
const Base::Covariance & errorCovariance() const
errorCovariance that returns P_, on the equivariant filter error
Definition EquivariantFilter.h:173
auto KalmanGain(const HMatrix &H, const RMatrix &R) const
Kalman gain K = P H^T S^-1.
Definition ManifoldEKF.h:130
Eigen::Matrix< double, Dim, Dim > Covariance
Covariance matrix type (P, Q).
Definition ManifoldEKF.h:58
void validateInputs(const gtsam::Vector &prediction, const Matrix &H, const gtsam::Vector &z, const Matrix &R)
Validate inputs to update.
Definition ManifoldEKF.h:255
const M & state() const
Definition ManifoldEKF.h:92
Jacobian I_
Identity matrix sized to the state dimension.
Definition ManifoldEKF.h:286
static constexpr int Dim
Compile-time dimension of the manifold M.
Definition ManifoldEKF.h:53
M X_
Manifold state estimate.
Definition ManifoldEKF.h:284
Eigen::Matrix< double, Dim, Dim > Jacobian
State transition Jacobian type (F).
Definition ManifoldEKF.h:60
ManifoldEKF(const M &X0, const Covariance &P0)
Constructor: initialize with state and covariance.
Definition ManifoldEKF.h:67
void JosephUpdate(const GainMatrix &K, const HMatrix &H, const RMatrix &R)
Joseph-form covariance update in the current tangent space using a precomputed gain.
Definition ManifoldEKF.h:138
Covariance P_
Covariance (Eigen::Matrix<double, Dim, Dim>).
Definition ManifoldEKF.h:285
typename traits< M >::TangentVector TangentVector
Tangent vector type for the manifold M.
Definition ManifoldEKF.h:56
size_t n_
Runtime tangent space dimension of M.
Definition ManifoldEKF.h:287
void predict(const M &X_next, const Jacobian &F, const Covariance &Q)
Basic predict step: Updates state and covariance given the predicted next state and the state transit...
Definition ManifoldEKF.h:114