|
17 | 17 | #include <CppUnitLite/TestHarness.h> |
18 | 18 | #include <gtsam/base/Testable.h> |
19 | 19 | #include <gtsam/base/numericalDerivative.h> |
| 20 | +#include <gtsam/geometry/Gal3.h> |
20 | 21 | #include <gtsam/inference/Symbol.h> |
21 | 22 | #include <gtsam/linear/GaussianFactorGraph.h> |
22 | 23 | #include <gtsam/linear/HessianFactor.h> |
@@ -86,25 +87,44 @@ TEST(NavStateImuEKF, DynamicsJacobian) { |
86 | 87 | /* ************************************************************************* */ |
87 | 88 | TEST(NavStateImuEKF, PredictMatchesExplicitIntegration) { |
88 | 89 | using namespace nontrivial_navstate_example; |
89 | | - double dt = 0.02; |
90 | | - |
91 | | - // Explicit integration as per Derek's code (from raw inputs) |
92 | | - Rot3 dR = Rot3::Expmap(omega_b * dt); |
93 | | - Rot3 R_new = R0.compose(dR); // R_new = R * dR |
94 | | - Vector3 a_world = R0 * f_b + params->n_gravity; |
95 | | - Vector3 v_new = v0 + a_world * dt; |
96 | | - Point3 p_new = p0 + v0 * dt + a_world * (0.5 * dt * dt); |
97 | | - NavState X_explicit(R_new, p_new, v_new); |
| 90 | + double dt = 10; |
| 91 | + |
| 92 | + // Explicit integration from paper |
| 93 | + const Vector3 phi_b = omega_b * dt; |
| 94 | + const so3::DexpFunctor local(phi_b); |
| 95 | + const Matrix3 J_l = local.Jacobian().left(); |
| 96 | + const Matrix3 N_l = local.Gamma().left(); |
| 97 | + |
| 98 | + const NavState U{Rot3::Expmap(phi_b), // R_new |
| 99 | + N_l * f_b * dt * dt, // p_new |
| 100 | + J_l * f_b * dt}; // v_new |
| 101 | + |
| 102 | + // Check against static IMU function: |
| 103 | + const NavState U_static = NavStateImuEKF::IMU(omega_b, f_b, dt); |
| 104 | + EXPECT(assert_equal(U, U_static, 1e-9)); |
| 105 | + |
| 106 | + // Check against Gal3::Expmap |
| 107 | + Vector10 xi; |
| 108 | + xi << omega_b, f_b, Vector3::Zero(), 1.0; |
| 109 | + const Gal3 T = Gal3::Expmap(xi * dt); |
| 110 | + const NavState U_gal3{T.rotation(), T.position(), T.velocity()}; |
| 111 | + EXPECT(assert_equal(U_gal3, U, 1e-9)); |
| 112 | + |
| 113 | + // Explicit integration, combined with gravity and v0 * dt boost |
| 114 | + const Vector3& g_n = params->n_gravity; |
| 115 | + const Rot3 R_new = R0 * U.attitude(); |
| 116 | + const Vector3 v_new = v0 + g_n * dt + R0 * U.velocity(); |
| 117 | + const Point3 p_new = p0 + g_n * (0.5 * dt * dt) + v0 * dt + R0 * U.position(); |
| 118 | + const NavState X_explicit(R_new, p_new, v_new); |
98 | 119 |
|
99 | 120 | // Increment-based integration should match exactly |
100 | 121 | auto params = PreintegrationParams::MakeSharedU(9.81); |
101 | 122 | NavStateImuEKF ekf(X0, I_9x9 * 1e-3, params); |
102 | | - NavState X_inc = |
103 | | - NavStateImuEKF::Dynamics(params->n_gravity, X0, omega_b, f_b, dt); |
104 | | - EXPECT(assert_equal(X_explicit, X_inc, 1e-12)); |
| 123 | + NavState X_next = NavStateImuEKF::Dynamics(g_n, X0, omega_b, f_b, dt); |
| 124 | + EXPECT(assert_equal(X_explicit, X_next, 1e-12)); |
105 | 125 | } |
106 | 126 |
|
107 | | -/* ************************************************************************* */ |
| 127 | +/* ***************************************************************************/ |
108 | 128 | // Check Jacobian for world-position measurement h(X)=position(X). |
109 | 129 | TEST(NavStateImuEKF, PositionMeasurementJacobian) { |
110 | 130 | using namespace nontrivial_navstate_example; |
@@ -215,62 +235,8 @@ TEST(NavStateImuEKF, PositionUpdateSanity) { |
215 | 235 | } |
216 | 236 |
|
217 | 237 | /* ************************************************************************* */ |
218 | | -NavState oldNavStateImuDynamics(const NavState& X, const Vector3& omega_b, |
219 | | - const Vector3& f_b, double dt, |
220 | | - const Vector3& n_gravity, |
221 | | - OptionalJacobian<9, 9> H = {}) { |
222 | | - // Rotation and velocity |
223 | | - const Rot3& R = X.attitude(); |
224 | | - Matrix3 D_vb_R, D_vb_v, D_gb_R; |
225 | | - const Vector3& v_n = X.velocity(); // Has D_v_v = R ! |
226 | | - const Vector3 v_body = |
227 | | - R.unrotate(v_n, H ? &D_vb_R : nullptr, H ? &D_vb_v : nullptr); |
228 | | - const Vector3 g_body = R.unrotate(n_gravity, H ? &D_gb_R : nullptr); |
229 | | - const Vector3 a_b_total = f_b + g_body; |
230 | | - |
231 | | - // Construct increment directly as group element with body-frame p/v |
232 | | - // increments |
233 | | - const Rot3 dR = Rot3::Expmap(omega_b * dt); |
234 | | - const double dt2 = 0.5 * dt * dt; |
235 | | - const Vector3 dp_body = v_body * dt + a_b_total * dt2; |
236 | | - const Vector3 dv_body = a_b_total * dt; |
237 | | - NavState U(dR, dp_body, dv_body); |
238 | | - |
239 | | - if (H) { |
240 | | - Matrix3 dRt = dR.transpose(); // Jacobian of NavState::Create |
241 | | - H->setZero(); |
242 | | - // position: |
243 | | - H->template block<3, 3>(3, 0) = dRt * (D_vb_R * dt + D_gb_R * dt2); |
244 | | - const Matrix3 D_v_v = R.matrix(); // Jacobian of velocity() |
245 | | - H->template block<3, 3>(3, 6) = dRt * D_vb_v * D_v_v * dt; |
246 | | - // velocity: |
247 | | - H->template block<3, 3>(6, 0) = dRt * D_gb_R * dt; |
248 | | - } |
249 | | - |
250 | | - return U; |
251 | | -} |
252 | | - |
253 | | -TEST(NavStateImuEKF, WPhiU_matches_navStateImuDynamics) { |
254 | | - using namespace nontrivial_navstate_example; |
255 | | - |
256 | | - const double dt = 1e-2; // 10 ms |
257 | | - const Vector3 n_gravity(0, 0, -9.81); |
258 | | - |
259 | | - // Expected state from oldNavStateImuDynamics |
260 | | - Matrix9 D_U_X0, D_X_X0, D_X_U; |
261 | | - NavState U = oldNavStateImuDynamics(X0, omega_b, f_b, dt, n_gravity, D_U_X0); |
262 | | - NavState X_old = X0.compose(U, D_X_X0, D_X_U); |
263 | | - |
264 | | - // Check New dynamics function |
265 | | - Matrix9 A_ekf; |
266 | | - NavState X_ekf = |
267 | | - NavStateImuEKF::Dynamics(n_gravity, X0, omega_b, f_b, dt, A_ekf); |
268 | | - |
269 | | - CHECK(assert_equal(X_old, X_ekf)); |
270 | | - CHECK(assert_equal<Matrix>(D_X_X0 + D_X_U * D_U_X0, A_ekf)); |
271 | | -} |
272 | | - |
273 | 238 | int main() { |
274 | 239 | TestResult tr; |
275 | 240 | return TestRegistry::runAllTests(tr); |
276 | 241 | } |
| 242 | +/* ************************************************************************* */ |
0 commit comments