Skip to content

Commit 2c84e0c

Browse files
committed
make manifold preintegration jac and cov consistent
1 parent 4735755 commit 2c84e0c

File tree

7 files changed

+47
-49
lines changed

7 files changed

+47
-49
lines changed

gtsam/navigation/CombinedImuFactor.h

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -193,25 +193,6 @@ class GTSAM_EXPORT PreintegratedCombinedMeasurementsT : public PreintegrationTyp
193193
// For backward compatibility:
194194
using PreintegratedCombinedMeasurements = PreintegratedCombinedMeasurementsT<DefaultPreintegrationType>;
195195

196-
// Manifold combined preintegration: convert preintMeasCov() (defined in the
197-
// “transported” coordinate convention) into the residual covariance convention
198-
// used by the factor, by rotating the dp/dv blocks with dR.
199-
inline Eigen::Matrix<double, 15, 15> combinedImuFactorResidualCov(
200-
const gtsam::PreintegratedCombinedMeasurementsT<gtsam::ManifoldPreintegration>& pim) {
201-
const Eigen::Matrix<double, 15, 15> Sigma = pim.preintMeasCov();
202-
203-
const gtsam::Matrix3 R = pim.deltaRij().matrix();
204-
205-
Eigen::Matrix<double, 15, 15> J = Eigen::Matrix<double, 15, 15>::Identity();
206-
J.block<3,3>(3,3) = R; // dp
207-
J.block<3,3>(6,6) = R; // dv
208-
209-
Eigen::Matrix<double, 15, 15> Sigma_out;
210-
Sigma_out.noalias() = J * Sigma * J.transpose();
211-
return Sigma_out;
212-
}
213-
214-
// Fallback for other Combined PIM types.
215196
template <class PIM>
216197
inline Eigen::Matrix<double, 15, 15> combinedImuFactorResidualCov(const PIM& pim) {
217198
return pim.preintMeasCov();

gtsam/navigation/ImuFactor.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,19 @@ void PreintegratedImuMeasurementsT<PreintegrationType>::integrateMeasurement(
6969
Matrix93 B, C; // Jacobian of state wrpt accel bias and omega bias respectively.
7070
PreintegrationType::update(measuredAcc, measuredOmega, dt, &A, &B, &C);
7171

72-
// For ManifoldPreintegration, the perturbation on deltaXij is dX1, the right perturbation of the NavState manifold (as validated by the unit tests on NavState::retract).
7372
// For TangentPreintegration, the perturbation on deltaXij is dX2, the 3D perturbation of the rotation tangent space +
74-
// 3D perturbation of the translation part + 3D perturbation of the velocity part (as validated by the matrix A_k in the ImuFactor.pdf).
73+
// 3D perturbation of the translation part + 3D perturbation of the velocity part,
74+
// as validated by the matrix A_k in the ImuFactor.pdf and the unit test on preintegrated_H_biasAcc()
75+
76+
// For ManifoldPreintegration, for covariance propagation, the perturbation on deltaXij is dX1,
77+
// the right perturbation of the NavState manifold, as validated by the unit tests on NavState::retract);
78+
// for jacobian computation, the perturbation on deltaXij is dX2 defined above, as validated by the unit test on delPdelBiasAcc().
79+
7580
// For ImuFactor or CombinedImuFactor, the residual is defined by PreintegrationBase::computeError and
7681
// its perturbation is coincident to dX2 (up to a right Jacobian of a small angle ~ identity).
7782
// So for TangentPreintegration, the covariance of the residual equals to the preintMeasCov of TangentPreintegration.
7883
// But for ManifoldPreintegration, we need to rotate the position and velocity blocks of the preintMeasCov to get the residual cov.
84+
// Otherwise, we can update the cov propagation of manifold preintegration to make it use dX2.
7985

8086
// first order covariance propagation:
8187
// as in [2] we consider a first order propagation that can be seen as a

gtsam/navigation/ImuFactor.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -173,24 +173,6 @@ class GTSAM_EXPORT PreintegratedImuMeasurementsT: public PreintegrationType {
173173
// controls which class PreintegratedImuMeasurements uses):
174174
using PreintegratedImuMeasurements = PreintegratedImuMeasurementsT<DefaultPreintegrationType>;
175175

176-
// Manifold 9D: map Sigma -> "residual covariance" by rotating dp/dv blocks with dR.
177-
inline gtsam::Matrix9 imuFactorResidualCov(
178-
const gtsam::PreintegratedImuMeasurementsT<gtsam::ManifoldPreintegration>& pim) {
179-
const gtsam::Matrix9 Sigma = pim.preintMeasCov();
180-
181-
const gtsam::Matrix3 R = pim.deltaRij().matrix();
182-
183-
// J is 9x9: identity except dp/dv blocks rotated by dR.
184-
gtsam::Matrix9 J = gtsam::Matrix9::Identity();
185-
J.block<3,3>(3,3) = R; // dp
186-
J.block<3,3>(6,6) = R; // dv
187-
188-
gtsam::Matrix9 noting;
189-
noting.noalias() = J * Sigma * J.transpose();
190-
return noting;
191-
}
192-
193-
// Fallback for other PIM types.
194176
template <class PIM>
195177
inline gtsam::Matrix9 imuFactorResidualCov(const PIM& pim) {
196178
return pim.preintMeasCov();

gtsam/navigation/ManifoldPreintegration.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,27 @@ void ManifoldPreintegration::update(const Vector3& measuredAcc,
7878

7979
// Do update
8080
deltaTij_ += dt;
81-
deltaXij_ = deltaXij_.update(acc, omega, dt, A, B, C); // functional
81+
82+
// Let's denote the right perturbation dXn on the NavState X_ij's manifold, i.e.,
83+
// dXn = [\delta \phi_ij, \delta p_ij, \delta v_ij] where R_ij = \hat{R}_ij Exp(\delta \phi_ij)
84+
// p_ij = \hat{p}_ij + R_ij \delta p_{ij} and v_ij = \hat{v}_ij + R_ij \delta v_{ij}.
85+
// The error state dXt of the preint X_ij is actually defined as
86+
// dXt = [\delta \phi_ij, \delta p_ij, \delta v_ij] where R_ij = \hat{R}_ij Exp(\delta \phi_ij)
87+
// p_ij = \hat{p}_ij + \delta p_{ij} and v_ij = \hat{v}_ij + \delta v_{ij}.
88+
// So to propagate the X_ij's covariance, we need to transform the transition matrix A.
89+
// from NavState.update(), An = \frac{\delta X^n_j}{\delta X^n_{j-1}}, and transform it to
90+
// At = \frac{\delta X^t_j}{\delta X^t_{j-1}} = \frac{\delta X^t_j}{\delta X^n_j} * An * \frac{\delta X^n_{j-1}}{\delta X^t_{j-1}}
91+
Matrix9 D_dXn_dXt_jm1 = Matrix9::Identity();
92+
D_dXn_dXt_jm1.block<3, 3>(3, 3).noalias() = deltaXij_.rotation().matrix().transpose();
93+
D_dXn_dXt_jm1.block<3, 3>(6, 6) = D_dXn_dXt_jm1.block<3, 3>(3, 3);
94+
Matrix9 An;
95+
deltaXij_ = deltaXij_.update(acc, omega, dt, &An, B, C); // functional
96+
Matrix9 D_dXt_dXn_j = Matrix9::Identity();
97+
D_dXt_dXn_j.block<3, 3>(3, 3).noalias() = deltaXij_.rotation().matrix();
98+
D_dXt_dXn_j.block<3, 3>(6, 6) = D_dXt_dXn_j.block<3, 3>(3, 3);
99+
*A = D_dXt_dXn_j * An * D_dXn_dXt_jm1;
100+
*B = D_dXt_dXn_j * *B;
101+
*C = D_dXt_dXn_j * *C;
82102

83103
if (p().body_P_sensor) {
84104
// More complicated derivatives in case of non-trivial sensor pose

gtsam/navigation/tests/imuFactorTesting.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,14 @@ struct ImuSimConfig {
131131
inline std::shared_ptr<gtsam::PreintegrationParams> MakeParamsU(const ImuSimConfig& cfg) {
132132
auto p = gtsam::PreintegrationParams::MakeSharedU(cfg.g);
133133
const Eigen::Matrix3d I = Eigen::Matrix3d::Identity();
134-
p->gyroscopeCovariance = (cfg.sigma_g_c * cfg.sigma_g_c) * I;
135-
p->accelerometerCovariance = (cfg.sigma_a_c * cfg.sigma_a_c) * I;
134+
double cov_g_c = cfg.sigma_g_c * cfg.sigma_g_c;
135+
double cov_a_c = cfg.sigma_a_c * cfg.sigma_a_c;
136+
p->gyroscopeCovariance = cov_g_c * I;
137+
p->accelerometerCovariance = cov_a_c * I;
138+
p->gyroscopeCovariance(0, 0) *= 10000;
139+
p->gyroscopeCovariance(1, 1) *= 100;
140+
p->accelerometerCovariance(0, 0) *= 10000;
141+
p->accelerometerCovariance(1, 1) *= 100;
136142
p->integrationCovariance = 1e-12 * I;
137143
p->use2ndOrderCoriolis = false;
138144
return p;

gtsam/navigation/tests/testCombinedImuFactor.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,14 @@ MakeParamsU_Combined(const ImuSimConfig& cfg) {
321321
gtsam::Vector3(0.0, 0.0, -cfg.g));
322322

323323
const gtsam::Matrix3 I = gtsam::Matrix3::Identity();
324-
p->gyroscopeCovariance = (cfg.sigma_g_c * cfg.sigma_g_c) * I;
325-
p->accelerometerCovariance = (cfg.sigma_a_c * cfg.sigma_a_c) * I;
324+
double cov_g_c = cfg.sigma_g_c * cfg.sigma_g_c;
325+
double cov_a_c = cfg.sigma_a_c * cfg.sigma_a_c;
326+
p->gyroscopeCovariance = cov_g_c * I;
327+
p->accelerometerCovariance = cov_a_c * I;
328+
p->gyroscopeCovariance(0, 0) *= 10000;
329+
p->gyroscopeCovariance(1, 1) *= 100;
330+
p->accelerometerCovariance(0, 0) *= 10000;
331+
p->accelerometerCovariance(1, 1) *= 100;
326332
p->integrationCovariance = 1e-12 * I;
327333

328334
// Turn off bias random walk so we can compare to 9D EKF (no bias state)
@@ -381,10 +387,7 @@ static inline Maps15Nav BuildMaps15Nav_Manifold(
381387
m.G.block<3,3>(12,12) = -I;
382388

383389
// ---- covG: covariance-error definition ----
384-
// like 9D manifold: first 9 injected as identity in nav error coords
385-
m.covG.setIdentity();
386-
m.covG.block<3,3>(9,9) = -I;
387-
m.covG.block<3,3>(12,12) = -I;
390+
m.covG = m.G;
388391

389392
return m;
390393
}

gtsam/navigation/tests/testImuFactor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ static inline Maps9 BuildMaps9_Manifold(
925925
m.G.block<3,3>(3,3) = A;
926926
m.G.block<3,3>(6,6) = A;
927927

928-
m.covG.setIdentity();
928+
m.covG = m.G;
929929

930930
m.G_inv = m.G.transpose(); // because blocks are I/A and A is orthonormal
931931
m.covG_inv = m.covG; // Identity

0 commit comments

Comments
 (0)