testInvariantEKF.cpp
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
3  * Atlanta, Georgia 30332-0415
4  * All Rights Reserved
5  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
6  *
7  * See LICENSE for the license information
8  * -------------------------------------------------------------------------- */
9 
19 #include <gtsam/base/Testable.h>
21 #include <gtsam/geometry/Pose2.h>
23 
24 #include <iostream>
25 
26 using namespace std;
27 using namespace gtsam;
28 
29 // Create a 2D GPS measurement function that returns the predicted measurement h
30 // and Jacobian H. The predicted measurement h is the translation of the state X.
31 // (Copied from IEKF_SE2Example.cpp)
33  return X.translation(H);
34 }
35 
36 
37 TEST(IEKF_Pose2, PredictUpdateSequence) {
38  // GIVEN: Initial state, covariance, noises, motions, measurements
39  // (from IEKF_SE2Example.cpp)
40  Pose2 X0(0.0, 0.0, 0.0);
41  Matrix3 P0 = Matrix3::Identity() * 0.1;
42 
43  Matrix3 Q = (Vector3(0.05, 0.05, 0.001)).asDiagonal();
44  Matrix2 R = I_2x2 * 0.01;
45 
46  Pose2 U1(1.0, 1.0, 0.5), U2(1.0, 1.0, 0.0);
47 
48  Vector2 z1, z2;
49  z1 << 1.0, 0.0;
50  z2 << 1.0, 1.0;
51 
52  // Create the filter
53  InvariantEKF<Pose2> ekf(X0, P0);
54  EXPECT(assert_equal(X0, ekf.state()));
56 
57  // --- First Prediction ---
58  ekf.predict(U1, Q);
59 
60  // Calculate expected state and covariance
61  Pose2 X1_expected = X0.compose(U1);
62  Matrix3 Ad_U1_inv = U1.inverse().AdjointMap();
63  Matrix3 P1_expected = Ad_U1_inv * P0 * Ad_U1_inv.transpose() + Q;
64 
65  // Verify
66  EXPECT(assert_equal(X1_expected, ekf.state(), 1e-9));
67  EXPECT(assert_equal(P1_expected, ekf.covariance(), 1e-9));
68 
69 
70  // --- First Update ---
71  ekf.update(h_gps, z1, R);
72 
73  // Calculate expected state and covariance (manual Kalman steps)
74  Matrix H1; // H = dh/dlocal(X) -> 2x3
75  Vector2 z_pred1 = h_gps(X1_expected, H1);
76  Vector2 y1 = z_pred1 - z1; // Innovation
77  Matrix S1 = H1 * P1_expected * H1.transpose() + R;
78  Matrix K1 = P1_expected * H1.transpose() * S1.inverse(); // Gain (3x2)
79  Vector3 delta_xi1 = -K1 * y1; // Correction (tangent space)
80  Pose2 X1_updated_expected = X1_expected.retract(delta_xi1);
81  Matrix3 I_KH1 = Matrix3::Identity() - K1 * H1;
82  Matrix3 P1_updated_expected = I_KH1 * P1_expected; // Standard form P = (I-KH)P
83 
84  // Verify
85  EXPECT(assert_equal(X1_updated_expected, ekf.state(), 1e-9));
86  EXPECT(assert_equal(P1_updated_expected, ekf.covariance(), 1e-9));
87 
88 
89  // --- Second Prediction ---
90  ekf.predict(U2, Q);
91 
92  // Calculate expected state and covariance
93  Pose2 X2_expected = X1_updated_expected.compose(U2);
94  Matrix3 Ad_U2_inv = U2.inverse().AdjointMap();
95  Matrix3 P2_expected = Ad_U2_inv * P1_updated_expected * Ad_U2_inv.transpose() + Q;
96 
97  // Verify
98  EXPECT(assert_equal(X2_expected, ekf.state(), 1e-9));
99  EXPECT(assert_equal(P2_expected, ekf.covariance(), 1e-9));
100 
101 
102  // --- Second Update ---
103  ekf.update(h_gps, z2, R);
104 
105  // Calculate expected state and covariance (manual Kalman steps)
106  Matrix H2; // 2x3
107  Vector2 z_pred2 = h_gps(X2_expected, H2);
108  Vector2 y2 = z_pred2 - z2; // Innovation
109  Matrix S2 = H2 * P2_expected * H2.transpose() + R;
110  Matrix K2 = P2_expected * H2.transpose() * S2.inverse(); // Gain (3x2)
111  Vector3 delta_xi2 = -K2 * y2; // Correction (tangent space)
112  Pose2 X2_updated_expected = X2_expected.retract(delta_xi2);
113  Matrix3 I_KH2 = Matrix3::Identity() - K2 * H2;
114  Matrix3 P2_updated_expected = I_KH2 * P2_expected; // Standard form
115 
116  // Verify
117  EXPECT(assert_equal(X2_updated_expected, ekf.state(), 1e-9));
118  EXPECT(assert_equal(P2_updated_expected, ekf.covariance(), 1e-9));
119 
120 }
121 
122 // Define simple dynamics and measurement for a 2x2 Matrix state
124  Matrix f(const Matrix& p, const Vector& vTangent, double dt) {
125  return traits<Matrix>::Retract(p, vTangent * dt);
126  }
127  double h(const Matrix& p, OptionalJacobian<-1, -1> H = {}) {
128  if (H) {
129  H->resize(1, p.size());
130  (*H) << 1.0, 0.0, 0.0, 1.0; // Assuming 2x2
131  }
132  return p(0, 0) + p(1, 1); // trace !
133  }
134 } // namespace exampleDynamicMatrix
135 
136 TEST(InvariantEKF_DynamicMatrix, PredictAndUpdate) {
137  // --- Setup ---
138  Matrix p0Matrix = (Matrix(2, 2) << 1.0, 2.0, 3.0, 4.0).finished();
139  Matrix p0Covariance = I_4x4 * 0.01;
140  Vector velocityTangent = (Vector(4) << 0.5, 0.1, -0.1, -0.5).finished();
141  double dt = 0.1;
142  Matrix Q = I_4x4 * 0.001;
143  Matrix R = Matrix::Identity(1, 1) * 0.005;
144 
145  InvariantEKF<Matrix> ekf(p0Matrix, p0Covariance);
146  EXPECT_LONGS_EQUAL(4, ekf.state().size());
147  EXPECT_LONGS_EQUAL(4, ekf.dimension());
148 
149  // --- Predict ---
150  ekf.predict(velocityTangent, dt, Q);
151 
152  // Verification for Predict
153  Matrix pPredictedExpected = exampleDynamicMatrix::f(p0Matrix, velocityTangent, dt);
154  Matrix pCovariancePredictedExpected = p0Covariance + Q;
155  EXPECT(assert_equal(pPredictedExpected, ekf.state(), 1e-9));
156  EXPECT(assert_equal(pCovariancePredictedExpected, ekf.covariance(), 1e-9));
157 
158  // --- Update ---
159  // Use the state after prediction for the update step
160  Matrix pStateBeforeUpdate = ekf.state();
161  Matrix pCovarianceBeforeUpdate = ekf.covariance();
162 
163  double zTrue = exampleDynamicMatrix::h(pStateBeforeUpdate);
164  double zObserved = zTrue - 0.03; // Simulated measurement with some error
165 
166  ekf.update(exampleDynamicMatrix::h, zObserved, R);
167 
168  // Verification for Update (Manual Kalman Steps)
169  Matrix H(1, 4);
170  double zPredictionManual = exampleDynamicMatrix::h(pStateBeforeUpdate, H);
171  double innovationY_tangent = zObserved - zPredictionManual;
172  Matrix S = H * pCovarianceBeforeUpdate * H.transpose() + R;
173  Matrix kalmanGainK = pCovarianceBeforeUpdate * H.transpose() * S.inverse();
174  Vector deltaXiTangent = kalmanGainK * innovationY_tangent;
175  Matrix pUpdatedExpected = traits<Matrix>::Retract(pStateBeforeUpdate, deltaXiTangent);
176  Matrix I_KH = I_4x4 - kalmanGainK * H;
177  Matrix pUpdatedCovarianceExpected = I_KH * pCovarianceBeforeUpdate * I_KH.transpose() + kalmanGainK * R * kalmanGainK.transpose();
178 
179  EXPECT(assert_equal(pUpdatedExpected, ekf.state(), 1e-9));
180  EXPECT(assert_equal(pUpdatedCovarianceExpected, ekf.covariance(), 1e-9));
181 }
182 
183 
184 int main() {
185  TestResult tr;
186  return TestRegistry::runAllTests(tr);
187 }
gtsam::Pose2::inverse
Pose2 inverse() const
inverse
Definition: Pose2.cpp:202
TestRegistry::runAllTests
static int runAllTests(TestResult &result)
Definition: TestRegistry.cpp:27
H
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size set set xzeroaxis lt lw set x2zeroaxis lt lw set yzeroaxis lt lw set y2zeroaxis lt lw set tics in set ticslevel set tics set mxtics default set mytics default set mx2tics default set my2tics default set xtics border mirror norotate autofreq set ytics border mirror norotate autofreq set ztics border nomirror norotate autofreq set nox2tics set noy2tics set timestamp bottom norotate set rrange[*:*] noreverse nowriteback set trange[*:*] noreverse nowriteback set urange[*:*] noreverse nowriteback set vrange[*:*] noreverse nowriteback set xlabel matrix size set x2label set timefmt d m y n H
Definition: gnuplot_common_settings.hh:74
S1
static double S1[]
Definition: shichi.c:61
Pose2.h
2D Pose
main
int main()
Definition: testInvariantEKF.cpp:184
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
exampleDynamicMatrix::h
double h(const Matrix &p, OptionalJacobian<-1, -1 > H={})
Definition: testInvariantEKF.cpp:127
EXPECT_LONGS_EQUAL
#define EXPECT_LONGS_EQUAL(expected, actual)
Definition: Test.h:154
Testable.h
Concept check for values that can be used in unit tests.
EXPECT
#define EXPECT(condition)
Definition: Test.h:150
TestHarness.h
Eigen::PermutationBase::transpose
InverseReturnType transpose() const
Definition: PermutationMatrix.h:191
z1
Point2 z1
Definition: testTriangulationFactor.cpp:45
gtsam::LieGroup::compose
Class compose(const Class &g) const
Definition: Lie.h:48
dt
const double dt
Definition: testVelocityConstraint.cpp:15
gtsam::Matrix
Eigen::MatrixXd Matrix
Definition: base/Matrix.h:39
X
#define X
Definition: icosphere.cpp:20
gtsam::Vector3
Eigen::Vector3d Vector3
Definition: Vector.h:44
h
const double h
Definition: testSimpleHelicopter.cpp:19
K2
static const Cal3Bundler K2(625, 1e-3, 1e-3)
gtsam::Vector
Eigen::VectorXd Vector
Definition: Vector.h:39
Q
Quaternion Q
Definition: testQuaternion.cpp:27
ceres::Matrix
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > Matrix
Definition: gtsam/3rdparty/ceres/eigen.h:42
y1
double y1(double x)
Definition: j1.c:199
numericalDerivative.h
Some functions to compute numerical derivatives.
gtsam::ManifoldEKF< G >::covariance
const Covariance & covariance() const
Definition: ManifoldEKF.h:111
h_gps
Vector2 h_gps(const Pose2 &X, OptionalJacobian< 2, 3 > H={})
Definition: testInvariantEKF.cpp:32
gtsam::ManifoldEKF< G >::state
const G & state() const
Definition: ManifoldEKF.h:108
gtsam::Symmetric
Symmetric group.
Definition: testGroup.cpp:27
gtsam::ManifoldEKF< G >::dimension
int dimension() const
Definition: ManifoldEKF.h:114
Vector2
Definition: test_operator_overloading.cpp:18
gtsam::ManifoldEKF< G >::update
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)
Definition: ManifoldEKF.h:152
gtsam::InvariantEKF
Left-Invariant Extended Kalman Filter on a Lie group G.
Definition: InvariantEKF.h:50
K1
static Cal3_S2::shared_ptr K1(new Cal3_S2(fov, w, h))
gtsam::Rot2::transpose
Matrix2 transpose() const
Definition: Rot2.cpp:107
TestResult
Definition: TestResult.h:26
Eigen::Quaternion
The quaternion class used to represent 3D orientations and rotations.
Definition: ForwardDeclarations.h:293
gtsam
traits
Definition: ABC.h:17
InvariantEKF.h
Left-Invariant Extended Kalman Filter implementation.
gtsam::traits
Definition: Group.h:36
gtsam::OptionalJacobian
Definition: OptionalJacobian.h:38
std
Definition: BFloat16.h:88
p
float * p
Definition: Tutorial_Map_using.cpp:9
gtsam::assert_equal
bool assert_equal(const Matrix &expected, const Matrix &actual, double tol)
Definition: Matrix.cpp:41
gtsam::LieGroup::retract
Class retract(const TangentVector &v) const
retract as required by manifold concept: applies v at *this
Definition: Lie.h:131
gtsam::Symmetric::inverse
Symmetric inverse() const
Definition: testGroup.cpp:49
gtsam::Pose2::AdjointMap
Matrix3 AdjointMap() const
Definition: Pose2.cpp:127
P0
static double P0[5]
Definition: ndtri.c:59
gtsam::InvariantEKF::predict
void predict(const G &U, const Covariance &Q)
Definition: InvariantEKF.h:79
exampleDynamicMatrix::f
Matrix f(const Matrix &p, const Vector &vTangent, double dt)
Definition: testInvariantEKF.cpp:124
exampleDynamicMatrix
Definition: testInvariantEKF.cpp:123
ceres::Vector
Eigen::Matrix< double, Eigen::Dynamic, 1 > Vector
Definition: gtsam/3rdparty/ceres/eigen.h:38
R
Rot2 R(Rot2::fromAngle(0.1))
S
DiscreteKey S(1, 2)
TEST
TEST(IEKF_Pose2, PredictUpdateSequence)
Definition: testInvariantEKF.cpp:37
gtsam::Pose2
Definition: Pose2.h:39
z2
static const Unit3 z2
Definition: testRotateFactor.cpp:46


gtsam
Author(s):
autogenerated on Wed May 28 2025 03:06:38