@@ -437,15 +437,105 @@ Vector10 Gal3::adjoint(const Vector10& xi, const Vector10& y, OptionalJacobian<1
437437}
438438
439439// ------------------------------------------------------------------------------
440+ static Matrix3 computeQMatrix (const so3::DexpFunctor& dexp, const Vector3& vec) {
441+ Matrix3 vec_hat = skewSymmetric (vec);
442+ Vector4 coeffs;
443+ if (dexp.nearZero ) {
444+ coeffs << 0.5 , 1.0 / 6.0 , 0.0 , 0.0 ;
445+ } else {
446+ coeffs << 0.5 ,
447+ dexp.C ,
448+ (1.0 - 2.0 * dexp.B ) / (2.0 * dexp.theta2 ),
449+ (2.0 * dexp.theta - 3.0 * std::sin (dexp.theta ) + dexp.theta * std::cos (dexp.theta )) / (2.0 * dexp.theta2 * dexp.theta2 * dexp.theta );
450+ }
451+
452+ Matrix3 T1 = vec_hat;
453+ Matrix3 T2 = dexp.W * vec_hat + vec_hat * dexp.W + dexp.W * vec_hat * dexp.W ;
454+ Matrix3 T3 = dexp.WW * vec_hat + vec_hat * dexp.WW - 3.0 * (dexp.W * vec_hat * dexp.W );
455+ Matrix3 T4 = dexp.WW * vec_hat * dexp.W + dexp.W * vec_hat * dexp.WW ;
456+
457+ return coeffs (0 ) * T1 + coeffs (1 ) * T2 + coeffs (2 ) * T3 + coeffs (3 ) * T4;
458+ }
459+
460+ static Matrix3 computeGal3LeftJacobianU1 (const gtsam::so3::DexpFunctor& dexp) {
461+ // move into dexpfunctor?
462+ if (dexp.nearZero ) {
463+ return 0.5 * Matrix3::Identity () + (1.0 / 3.0 ) * dexp.W ;
464+ } else {
465+ return 0.5 * Matrix3::Identity () + (dexp.B - dexp.C ) * dexp.W +
466+ ((0.5 - dexp.A + dexp.B ) / dexp.theta2 ) * dexp.WW ;
467+ }
468+ }
469+
470+ static Matrix3 computeGamma1ThetaNuThetaTau (const so3::DexpFunctor& dexp, const Vector3& nu_vec) {
471+ Matrix3 nu_hat = skewSymmetric (nu_vec);
472+ Vector7 coeffs;
473+ if (dexp.nearZero ) {
474+ coeffs << 1.0 / 6.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ;
475+ } else {
476+ const double tn3 = dexp.theta * dexp.theta2 ;
477+ const double tn4 = dexp.theta2 * dexp.theta2 ;
478+ const double tn5 = dexp.theta * tn4;
479+ const double tn6 = dexp.theta2 * tn4;
480+ const double s = std::sin (dexp.theta );
481+ const double c = std::cos (dexp.theta );
482+
483+ coeffs << 1.0 / 6.0 ,
484+ dexp.E ,
485+ (1.0 - 2.0 * dexp.B ) / (2.0 * dexp.theta2 ),
486+ (tn3 + 6.0 * dexp.theta + 6.0 * dexp.theta * c - 12.0 * s) / (6.0 * tn5),
487+ (12.0 * s - 12.0 * dexp.theta * c - 3.0 * dexp.theta2 * s - tn3) / (6.0 * tn5),
488+ (tn3 - 6.0 * dexp.theta + 6.0 * s) / (6.0 * tn5),
489+ (4.0 + dexp.theta2 + dexp.theta2 * c - 4.0 * dexp.theta * s - 4.0 * c) / (4.0 * tn6);
490+ }
491+
492+ Matrix3 T0 = nu_hat;
493+ Matrix3 T1 = dexp.W * nu_hat;
494+ Matrix3 T2 = nu_hat * dexp.W ;
495+ Matrix3 T3 = dexp.WW * nu_hat;
496+ Matrix3 T4 = dexp.W * nu_hat * dexp.W ;
497+ Matrix3 T5 = nu_hat * dexp.WW ;
498+ Matrix3 T6 = dexp.WW * nu_hat * dexp.W + dexp.W * nu_hat * dexp.WW ;
499+
500+ Matrix3 result = coeffs (0 ) * T0 + coeffs (1 ) * T1 + coeffs (2 ) * T2 + coeffs (3 ) * T3;
501+ result += coeffs (4 ) * T4 + coeffs (5 ) * T5 + coeffs (6 ) * T6;
502+
503+ return result;
504+ }
505+
440506Matrix10 Gal3::ExpmapDerivative (const Vector10& xi) {
441- // Related to the left Jacobian in Equations 31-36, Pages 10-11
442- // NOTE: Using numerical approximation instead of implementing the analytical
443- // expression for the Jacobian. Future work to replace this
444- // with analytical derivative.
445- if (xi.norm () < kSmallAngleThreshold ) return Matrix10::Identity ();
446- std::function<Gal3 (const Vector10&)> fn =
447- [](const Vector10& v) { return Gal3::Expmap (v); };
448- return numericalDerivative11<Gal3, Vector10>(fn, xi, 1e-5 );
507+ Vector minus_xi = -xi;
508+ Vector3 rho_vec = minus_xi.segment <3 >(0 );
509+ Vector3 nu_vec = minus_xi.segment <3 >(3 );
510+ Vector3 theta_vec = minus_xi.segment <3 >(6 );
511+ double t_val = minus_xi (9 );
512+
513+ so3::DexpFunctor dexp (theta_vec);
514+
515+ Matrix10 Jl_minus_xi = Matrix10::Zero ();
516+
517+ // Note: Because dexp is constructed on -theta, dexp.leftJacobian() returns Jr(theta)
518+ Matrix3 right_jacobian = dexp.leftJacobian ();
519+ Jl_minus_xi.block <3 ,3 >(0 ,0 ) = right_jacobian; // ∂ρ/∂ρ block
520+ Jl_minus_xi.block <3 ,3 >(3 ,3 ) = right_jacobian; // ∂ν/∂ν block
521+ Jl_minus_xi.block <3 ,3 >(6 ,6 ) = right_jacobian; // ∂ϕ/∂ϕ block
522+
523+ Jl_minus_xi.block <3 ,3 >(0 ,3 ) = -computeGal3LeftJacobianU1 (dexp) * t_val;
524+ Jl_minus_xi.block <3 ,3 >(3 ,6 ) = computeQMatrix (dexp, nu_vec);
525+ Jl_minus_xi.block <3 ,3 >(0 ,6 ) = computeQMatrix (dexp, rho_vec) - computeGamma1ThetaNuThetaTau (dexp, nu_vec)*t_val;
526+
527+ Matrix3 gamma2;
528+ if (dexp.nearZero ) {
529+ gamma2 = 0.5 * Matrix3::Identity () + 1.0 / 6.0 * dexp.W + (1.0 /24.0 ) * dexp.WW ;
530+ } else {
531+ gamma2 = 0.5 * Matrix3::Identity () + dexp.C * dexp.W + (1.0 - 2.0 * dexp.B ) / (2.0 * dexp.theta2 ) * dexp.WW ;
532+ }
533+
534+ Jl_minus_xi.block <3 ,1 >(0 ,9 ) = gamma2 * nu_vec;
535+
536+ Jl_minus_xi (9 ,9 ) = 1.0 ;
537+
538+ return Jl_minus_xi;
449539}
450540
451541// ------------------------------------------------------------------------------
0 commit comments