@@ -56,6 +56,120 @@ bool ManifoldPreintegration::equals(const ManifoldPreintegration& other,
5656 && equal_with_abs_tol (delVdelBiasOmega_, other.delVdelBiasOmega_ , tol);
5757}
5858
59+ NavState ManifoldPreintegration::UpdatePreintegrated (
60+ const Eigen::Vector3d& a_body,
61+ const Eigen::Vector3d& w_body,
62+ double dt,
63+ const NavState& X, // (R,p,v)
64+ gtsam::OptionalJacobian<9 ,9 > A_t, // dXt_{k+1} / dXt_k
65+ gtsam::OptionalJacobian<9 ,3 > B_t, // dXt_{k+1} / d a_body
66+ gtsam::OptionalJacobian<9 ,3 > C_t) { // dXt_{k+1} / d w_body
67+
68+ // Let's denote the right perturbation dXn on the NavState X_ij's manifold, i.e.,
69+ // dXn = [\delta \phi_ij, \delta p_ij, \delta v_ij] where R_ij = \hat{R}_ij Exp(\delta \phi_ij)
70+ // p_ij = \hat{p}_ij + R_ij \delta p_{ij} and v_ij = \hat{v}_ij + R_ij \delta v_{ij}.
71+ // The error state dXt of the preint X_ij is actually defined as
72+ // dXt = [\delta \phi_ij, \delta p_ij, \delta v_ij] where R_ij = \hat{R}_ij Exp(\delta \phi_ij)
73+ // p_ij = \hat{p}_ij + \delta p_{ij} and v_ij = \hat{v}_ij + \delta v_{ij}.
74+ // So to propagate the X_ij's covariance, we need to transform the transition matrix A.
75+ // from NavState.update(), An = \frac{\delta X^n_j}{\delta X^n_{j-1}}, and transform it to
76+ // 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}}
77+
78+ const double dt2 = dt * dt;
79+ const double dt22 = 0.5 * dt2;
80+
81+ const gtsam::Rot3& R = X.rotation ();
82+ const Eigen::Matrix3d Rm = R.matrix ();
83+
84+ // Rotation increment
85+ const Eigen::Vector3d phi = w_body * dt;
86+
87+ Eigen::Matrix3d Dexp; // not used directly here, but cheap to compute
88+ const gtsam::Rot3 dR = gtsam::Rot3::Expmap (phi, (A_t || C_t) ? &Dexp : nullptr );
89+ const gtsam::Rot3 Rn = R.compose (dR);
90+
91+ // a_nav uses OLD R (matching typical preintegration / NavState.update structure)
92+ const Eigen::Vector3d a_nav = R.rotate (a_body);
93+
94+ const gtsam::Point3 pn = X.position () + X.v () * dt + a_nav * dt22;
95+ const Eigen::Vector3d vn = X.v () + a_nav * dt;
96+
97+ NavState Xn (Rn, pn, vn);
98+
99+ if (A_t) {
100+ A_t->setZero ();
101+
102+ // dphi+ = dR^T * dphi (right-perturbation transport)
103+ A_t->block <3 ,3 >(0 ,0 ) = dR.transpose ().matrix ();
104+
105+ // dp+ = dp + dt dv + (d/dphi)(0.5*R*a*dt^2)*dphi
106+ // dv+ = dv + (d/dphi)(R*a*dt)*dphi
107+ //
108+ // Right perturbation: R Exp(dphi) a ≈ R (I + [dphi]x) a
109+ // so δ(R a) = R (dphi x a) = - R [a]x dphi
110+ const Eigen::Matrix3d a_skew = skewSymmetric (a_body);
111+ A_t->block <3 ,3 >(3 ,0 ) = -Rm * a_skew * dt22;
112+ A_t->block <3 ,3 >(6 ,0 ) = -Rm * a_skew * dt;
113+
114+ // world-additive p,v parts
115+ A_t->block <3 ,3 >(3 ,3 ) = Eigen::Matrix3d::Identity ();
116+ A_t->block <3 ,3 >(3 ,6 ) = Eigen::Matrix3d::Identity () * dt;
117+ A_t->block <3 ,3 >(6 ,6 ) = Eigen::Matrix3d::Identity ();
118+ }
119+
120+ if (B_t) {
121+ B_t->setZero ();
122+ // dp+ / da = 0.5 * R * dt^2, dv+ / da = R * dt
123+ B_t->block <3 ,3 >(3 ,0 ) = Rm * dt22;
124+ B_t->block <3 ,3 >(6 ,0 ) = Rm * dt;
125+ }
126+
127+ if (C_t) {
128+ C_t->setZero ();
129+ // dphi+ / dw = invJr(phi) * dt
130+ so3::DexpFunctor local (phi);
131+ const Eigen::Matrix3d invJr = local.InvJacobian ().right ();
132+ C_t->block <3 ,3 >(0 ,0 ) = invJr * dt;
133+ }
134+
135+ return Xn;
136+ }
137+
138+ NavState ManifoldPreintegration::UpdatePreintegratedSlow (
139+ const Eigen::Vector3d& a_body,
140+ const Eigen::Vector3d& w_body,
141+ double dt,
142+ const NavState& X,
143+ gtsam::OptionalJacobian<9 ,9 > A,
144+ gtsam::OptionalJacobian<9 ,3 > B,
145+ gtsam::OptionalJacobian<9 ,3 > C) {
146+ const Eigen::Matrix3d Rm = X.rotation ().matrix ();
147+
148+ Matrix9 D_dXn_dXt_jm1 = Matrix9::Identity ();
149+ D_dXn_dXt_jm1.block <3 ,3 >(3 ,3 ) = Rm.transpose ();
150+ D_dXn_dXt_jm1.block <3 ,3 >(6 ,6 ) = Rm.transpose ();
151+
152+ Matrix9 An;
153+ Matrix93 Bn, Cn;
154+
155+ NavState Xn = X.update (a_body, w_body, dt,
156+ A ? &An : nullptr ,
157+ B ? &Bn : nullptr ,
158+ C ? &Cn : nullptr );
159+
160+ const Eigen::Matrix3d Rnm = Xn.rotation ().matrix ();
161+
162+ Matrix9 D_dXt_dXn_j = Matrix9::Identity ();
163+ D_dXt_dXn_j.block <3 ,3 >(3 ,3 ) = Rnm;
164+ D_dXt_dXn_j.block <3 ,3 >(6 ,6 ) = Rnm;
165+
166+ if (A) *A = D_dXt_dXn_j * An * D_dXn_dXt_jm1;
167+ if (B) *B = D_dXt_dXn_j * Bn;
168+ if (C) *C = D_dXt_dXn_j * Cn;
169+
170+ return Xn;
171+ }
172+
59173// ------------------------------------------------------------------------------
60174void ManifoldPreintegration::update (const Vector3& measuredAcc,
61175 const Vector3& measuredOmega, const double dt, Matrix9* A, Matrix93* B,
@@ -78,27 +192,7 @@ void ManifoldPreintegration::update(const Vector3& measuredAcc,
78192
79193 // Do update
80194 deltaTij_ += dt;
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;
195+ deltaXij_ = UpdatePreintegrated (acc, omega, dt, deltaXij_, A, B, C);
102196
103197 if (p ().body_P_sensor ) {
104198 // More complicated derivatives in case of non-trivial sensor pose
0 commit comments