@@ -579,7 +579,7 @@ template<typename T, bool with_gyro_bias, bool with_accel_bias>
579
579
void Kalman3D_Wave<T, with_gyro_bias, with_accel_bias>::time_update(
580
580
Vector3 const & gyr, T Ts)
581
581
{
582
- // ===== Mean propagation (unchanged) =====
582
+ // ===== Mean propagation =====
583
583
Vector3 gyro_bias;
584
584
if constexpr (with_gyro_bias) {
585
585
gyro_bias = xext.template segment <3 >(3 );
@@ -588,10 +588,12 @@ void Kalman3D_Wave<T, with_gyro_bias, with_accel_bias>::time_update(
588
588
}
589
589
last_gyr_bias_corrected = gyr - gyro_bias;
590
590
591
+ // Δθ = ω Ts → quaternion increment
591
592
Eigen::Quaternion<T> dq = quat_from_delta_theta ((last_gyr_bias_corrected * Ts).eval ());
592
593
qref = qref * dq;
593
594
qref.normalize ();
594
595
596
+ // Build F, Q
595
597
MatrixNX F_a_ext;
596
598
MatrixNX Q_a_ext;
597
599
assembleExtendedFandQ (Vector3::Zero (), Ts, F_a_ext, Q_a_ext);
@@ -611,82 +613,75 @@ void Kalman3D_Wave<T, with_gyro_bias, with_accel_bias>::time_update(
611
613
xext.template segment <3 >(OFF_S) = x_lin_next.template segment <3 >(6 );
612
614
xext.template segment <3 >(OFF_AW) = x_lin_next.template segment <3 >(9 );
613
615
614
- // ===== Covariance propagation (block-wise, complete ) =====
615
- constexpr int NA = BASE_N; // attitude (+ gyro bias if enabled )
616
+ // ===== Covariance propagation (block-wise exact ) =====
617
+ constexpr int NA = BASE_N; // attitude (+ gyro bias)
616
618
constexpr int NL = 12 ; // [v p S a_w]
617
619
constexpr int NC = with_accel_bias ? 3 : 0 ;
618
620
619
- // Blocks of F and Q we actually need
621
+ // F and Q blocks
620
622
const Eigen::Matrix<T,NA,NA> F_AA = F_a_ext.template block <NA,NA>(0 ,0 );
621
623
const Eigen::Matrix<T,NL,NL> F_LL = F_a_ext.template block <NL,NL>(OFF_V, OFF_V);
622
624
Eigen::Matrix<T,NC,NC> F_CC;
623
- if constexpr (with_accel_bias) {
624
- F_CC.setIdentity (); // accel bias is RW ⇒ F = I
625
- }
625
+ if constexpr (with_accel_bias) F_CC.setIdentity ();
626
626
627
627
const Eigen::Matrix<T,NA,NA> Q_AA = Q_a_ext.template block <NA,NA>(0 ,0 );
628
628
const Eigen::Matrix<T,NL,NL> Q_LL = Q_a_ext.template block <NL,NL>(OFF_V, OFF_V);
629
629
Eigen::Matrix<T,NC,NC> Q_CC;
630
- if constexpr (with_accel_bias) {
631
- Q_CC = Q_a_ext.template block <NC,NC>(OFF_BA, OFF_BA);
632
- }
630
+ if constexpr (with_accel_bias) Q_CC = Q_a_ext.template block <NC,NC>(OFF_BA, OFF_BA);
633
631
634
- // Take needed P blocks (read-only views)
632
+ // Old P blocks
635
633
const Eigen::Matrix<T,NA,NA> P_AA = Pext.template block <NA,NA>(0 ,0 );
636
634
const Eigen::Matrix<T,NL,NL> P_LL = Pext.template block <NL,NL>(OFF_V, OFF_V);
637
-
638
635
Eigen::Matrix<T,NA,NL> P_AL = Pext.template block <NA,NL>(0 , OFF_V);
636
+
637
+ Eigen::Matrix<T,NC,NC> P_CC;
639
638
Eigen::Matrix<T,NA,NC> P_AC;
640
639
Eigen::Matrix<T,NL,NC> P_LC;
641
- Eigen::Matrix<T,NC,NC> P_CC;
642
640
if constexpr (with_accel_bias) {
641
+ P_CC = Pext.template block <NC,NC>(OFF_BA, OFF_BA);
643
642
P_AC = Pext.template block <NA,NC>(0 , OFF_BA);
644
643
P_LC = Pext.template block <NL,NC>(OFF_V, OFF_BA);
645
- P_CC = Pext.template block <NC,NC>(OFF_BA, OFF_BA);
646
644
}
647
645
648
- // ---- propagate diagonal blocks ----
646
+ // Diagonal block updates
649
647
Eigen::Matrix<T,NA,NA> P_AA_new = F_AA * P_AA * F_AA.transpose () + Q_AA;
650
648
Eigen::Matrix<T,NL,NL> P_LL_new = F_LL * P_LL * F_LL.transpose () + Q_LL;
651
649
652
650
Eigen::Matrix<T,NC,NC> P_CC_new;
653
651
if constexpr (with_accel_bias) {
654
- // F_CC = I, so: P_CC' = P_CC + Q_CC
655
- P_CC_new = P_CC + Q_CC;
652
+ P_CC_new = P_CC + Q_CC; // F_CC = I
656
653
}
657
654
658
- // ---- propagate cross blocks (because F is block-diagonal) ----
655
+ // Cross blocks
659
656
Eigen::Matrix<T,NA,NL> P_AL_new = F_AA * P_AL * F_LL.transpose ();
660
-
661
657
Eigen::Matrix<T,NA,NC> P_AC_new;
662
658
Eigen::Matrix<T,NL,NC> P_LC_new;
663
659
if constexpr (with_accel_bias) {
664
- // F_CC = I
665
660
P_AC_new = F_AA * P_AC;
666
661
P_LC_new = F_LL * P_LC;
667
662
}
668
663
669
- // ---- write back (and enforce symmetry) ----
670
- Pext.template block <NA,NA>(0 ,0 ) = P_AA_new;
671
- Pext.template block <NL,NL>(OFF_V, OFF_V) = P_LL_new;
672
- Pext.template block <NA,NL>(0 , OFF_V) = P_AL_new;
673
- Pext.template block <NL,NA>(OFF_V, 0 ) = P_AL_new.transpose ();
664
+ // Write back
665
+ Pext.template block <NA,NA>(0 ,0 ) = P_AA_new;
666
+ Pext.template block <NL,NL>(OFF_V,OFF_V) = P_LL_new;
667
+ Pext.template block <NA,NL>(0 ,OFF_V) = P_AL_new;
668
+ Pext.template block <NL,NA>(OFF_V,0 ) = P_AL_new.transpose ();
674
669
675
670
if constexpr (with_accel_bias) {
676
- Pext.template block <NC,NC>(OFF_BA, OFF_BA) = P_CC_new;
677
- Pext.template block <NA,NC>(0 , OFF_BA) = P_AC_new;
678
- Pext.template block <NC,NA>(OFF_BA, 0 ) = P_AC_new.transpose ();
679
- Pext.template block <NL,NC>(OFF_V, OFF_BA) = P_LC_new;
680
- Pext.template block <NC,NL>(OFF_BA, OFF_V) = P_LC_new.transpose ();
671
+ Pext.template block <NC,NC>(OFF_BA,OFF_BA) = P_CC_new;
672
+ Pext.template block <NA,NC>(0 ,OFF_BA) = P_AC_new;
673
+ Pext.template block <NC,NA>(OFF_BA,0 ) = P_AC_new.transpose ();
674
+ Pext.template block <NL,NC>(OFF_V,OFF_BA) = P_LC_new;
675
+ Pext.template block <NC,NL>(OFF_BA,OFF_V) = P_LC_new.transpose ();
681
676
}
682
677
683
- // Final symmetry clean-up
678
+ // Enforce symmetry
684
679
Pext = T (0.5 ) * (Pext + Pext.transpose ());
685
680
686
- // Keep mirror of the base block (for your accessors)
681
+ // Mirror base block
687
682
Pbase = Pext.topLeftCorner (NA, NA);
688
683
689
- // ===== periodic pseudo-measurement on S (unchanged) =====
684
+ // ===== periodic pseudo-measurement =====
690
685
if (++pseudo_update_counter_ >= PSEUDO_UPDATE_PERIOD) {
691
686
applyIntegralZeroPseudoMeas ();
692
687
pseudo_update_counter_ = 0 ;
0 commit comments