Skip to content

Commit 1f0d16b

Browse files
authored
Merge pull request #2315 from borglab/fix/filters
Various filter changes
2 parents 64643a4 + a41f251 commit 1f0d16b

File tree

15 files changed

+554
-202
lines changed

15 files changed

+554
-202
lines changed

examples/GEKF_Rot3Example.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,16 @@ int main() {
5757

5858
// Timestep, process noise, measurement noise
5959
double dt = 0.1;
60-
Matrix3 Q = Matrix3::Identity() * 0.01;
60+
// Continuous-time process noise (scaled by dt inside predict).
61+
Matrix3 Qc = Matrix3::Identity() * 0.1;
6162
Matrix3 Rm = Matrix3::Identity() * 0.05;
6263

6364
cout << "=== Init ===\nR:\n"
6465
<< ekf.state().matrix() << "\nP:\n"
6566
<< ekf.covariance() << "\n\n";
6667

6768
// Predict using state‐dependent f
68-
ekf.predict(dynamicsSO3, dt, Q);
69+
ekf.predict(dynamicsSO3, dt, Qc);
6970
cout << "--- After predict ---\nR:\n" << ekf.state().matrix() << "\n\n";
7071

7172
// Magnetometer measurement = body‐frame reading of m_world

examples/IEKF_NavstateExample.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ int main() {
5858

5959
// Noise & timestep
6060
double dt = 1.0;
61-
Matrix9 Q = Matrix9::Identity() * 0.01;
62-
Matrix3 R = Matrix3::Identity() * 0.5;
61+
// Continuous-time process noise (scaled by dt inside predict)
62+
Matrix9 Qc = Matrix9::Identity() * 0.01;
63+
Matrix3 R = Matrix3::Identity() * 0.5;
6364

6465
// Two IMU samples [a; ω]
6566
Vector6 imu1;
@@ -77,15 +78,15 @@ int main() {
7778
<< "\n\n";
7879

7980
// --- first predict/update ---
80-
ekf.predict(dynamics(imu1), dt, Q);
81+
ekf.predict(dynamics(imu1), dt, Qc);
8182
cout << "--- After predict 1 ---\nX: " << ekf.state()
8283
<< "\nP: " << ekf.covariance() << "\n\n";
8384
ekf.update(h_gps, z1, R);
8485
cout << "--- After update 1 ---\nX: " << ekf.state()
8586
<< "\nP: " << ekf.covariance() << "\n\n";
8687

8788
// --- second predict/update ---
88-
ekf.predict(dynamics(imu2), dt, Q);
89+
ekf.predict(dynamics(imu2), dt, Qc);
8990
cout << "--- After predict 2 ---\nX: " << ekf.state()
9091
<< "\nP: " << ekf.covariance() << "\n\n";
9192
ekf.update(h_gps, z2, R);

gtsam/geometry/Rot2.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ Vector1 Rot2::Logmap(const Rot2& r, OptionalJacobian<1, 1> H) {
8181
v << r.theta();
8282
return v;
8383
}
84+
85+
/* ************************************************************************* */
86+
Matrix1 Rot2::adjointMap(const Vector1&) {
87+
Matrix1 ad;
88+
ad << 0.0;
89+
return ad;
90+
}
91+
92+
/* ************************************************************************* */
93+
Vector1 Rot2::adjoint(const Vector1&, const Vector1&,
94+
OptionalJacobian<1, 1> Hxi,
95+
OptionalJacobian<1, 1> Hy) {
96+
if (Hxi) *Hxi = Matrix1::Zero();
97+
if (Hy) *Hy = Matrix1::Zero();
98+
return Vector1::Zero();
99+
}
100+
84101
/* ************************************************************************* */
85102
Matrix2 Rot2::Hat(const Vector1& xi) {
86103
Matrix2 X;

gtsam/geometry/Rot2.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ namespace gtsam {
135135
/** Calculate Adjoint map */
136136
Matrix1 AdjointMap() const { return I_1x1; }
137137

138+
/// Lie-algebra adjoint (zero for abelian SO(2)).
139+
static Matrix1 adjointMap(const Vector1&);
140+
141+
/// Apply Lie-algebra adjoint (always zero).
142+
static Vector1 adjoint(const Vector1&, const Vector1&,
143+
OptionalJacobian<1, 1> Hxi = {},
144+
OptionalJacobian<1, 1> Hy = {});
145+
138146
/// Left-trivialized derivative of the exponential map
139147
static Matrix ExpmapDerivative(const Vector& /*v*/) {
140148
return I_1x1;

gtsam/geometry/Rot3.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,19 @@ Matrix3 Rot3::LogmapDerivative(const Vector3& x) {
245245
return SO3::LogmapDerivative(x);
246246
}
247247

248+
/* ************************************************************************* */
249+
Matrix3 Rot3::adjointMap(const Vector3& xi) { return Hat(xi); }
250+
251+
/* ************************************************************************* */
252+
Vector3 Rot3::adjoint(const Vector3& xi, const Vector3& y,
253+
OptionalJacobian<3, 3> Hxi,
254+
OptionalJacobian<3, 3> Hy) {
255+
const Matrix3 ad_xi = adjointMap(xi);
256+
if (Hxi) *Hxi = -Hat(y);
257+
if (Hy) *Hy = ad_xi;
258+
return ad_xi * y;
259+
}
260+
248261
/* ************************************************************************* */
249262
pair<Matrix3, Vector3> RQ(const Matrix3& A, OptionalJacobian<3, 9> H) {
250263
const double x = -atan2(-A(2, 1), A(2, 2));
@@ -319,4 +332,3 @@ Rot3 Rot3::slerp(double t, const Rot3& other) const {
319332
/* ************************************************************************* */
320333

321334
} // namespace gtsam
322-

gtsam/geometry/Rot3.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,14 @@ class GTSAM_EXPORT Rot3 : public LieGroup<Rot3, 3> {
396396
/** Calculate Adjoint map */
397397
Matrix3 AdjointMap() const { return matrix(); }
398398

399+
/// Matrix representation of the Lie-algebra adjoint operator ad_xi on so(3).
400+
static Matrix3 adjointMap(const Vector3& xi);
401+
402+
/// Apply the Lie-algebra adjoint map to y with optional derivatives.
403+
static Vector3 adjoint(const Vector3& xi, const Vector3& y,
404+
OptionalJacobian<3, 3> Hxi = {},
405+
OptionalJacobian<3, 3> Hy = {});
406+
399407
// Chart at origin, depends on compile-time flag ROT3_DEFAULT_COORDINATES_MODE
400408
struct GTSAM_EXPORT ChartAtOrigin {
401409
static Rot3 Retract(const Vector3& v, ChartJacobian H = {});
@@ -599,4 +607,3 @@ template <>
599607
struct traits<const Rot3> : public internal::MatrixLieGroup<Rot3, 3> {};
600608

601609
} // namespace gtsam
602-

gtsam/navigation/InvariantEKF.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ namespace gtsam {
4343
* 2. Prediction via tangent control vector: `predict(const TangentVector& u,
4444
* double dt, const Covariance& Q)`
4545
*
46+
*
47+
* Noise convention mirrors LieGroupEKF:
48+
* - `predict(U, Q)` expects `Q` to be a discrete covariance.
49+
* - `predict(u, dt, Q)` interprets `Q` as continuous-time and scales by `dt`.
50+
*
4651
* The state-dependent prediction methods from LeftLinearEKF are hidden.
4752
* The update step remains the same as in ManifoldEKF/LeftLinearEKF.
4853
* For details on how static and dynamic dimensions are handled, please refer to
@@ -107,7 +112,7 @@ class InvariantEKF : public LeftLinearEKF<G> {
107112
*
108113
* @param u Tangent space control vector.
109114
* @param dt Time interval.
110-
* @param Q Process noise covariance matrix.
115+
* @param Q Continuous-time process noise covariance matrix (scaled by dt).
111116
*/
112117
void predict(const TangentVector& u, double dt, const Covariance& Q) {
113118
G U;
@@ -119,7 +124,7 @@ class InvariantEKF : public LeftLinearEKF<G> {
119124
} else {
120125
U = traits<G>::Expmap(u * dt);
121126
}
122-
predict(U, Q); // Call the group composition predict
127+
predict(U, Q * dt); // Q interpreted as continuous-time; discretize with dt
123128
}
124129

125130
/**

0 commit comments

Comments
 (0)