gtsam
Loading...
Searching...
No Matches
ABC.h
Go to the documentation of this file.
1
34
35#pragma once
36
38#include <gtsam/base/Matrix.h>
42#include <gtsam/base/Vector.h>
46#include <gtsam/geometry/Rot3.h>
47#include <gtsam/geometry/Unit3.h>
48
49#include <iostream>
50#include <string>
51#include <vector>
52
53namespace gtsam {
54namespace abc {
55
57inline Vector6 toInputVector(const Vector3& w) {
58 return (Vector6() << w, Z_3x1).finished();
59}
60
62template <size_t N>
64
65//========================================================================
66// State Manifold
67//========================================================================
68
73template <size_t N>
74struct State {
75 Rot3 R; // Attitude rotation matrix R
76 Vector3 b; // Gyroscope bias b
77 Calibrations<N> S; // Sensor calibrations S
78
79 static constexpr int dimension = 6 + 3 * static_cast<int>(N);
80 using TangentVector = Eigen::Matrix<double, dimension, 1>;
81
83 State(const Rot3& R = Rot3(), const Vector3& b = Z_3x1,
85 : R(R), b(b), S(S) {}
86
88 static State identity() { return State(Rot3(), Z_3x1, Calibrations<N>()); }
89
95 TangentVector localCoordinates(const State<N>& other) const {
96 TangentVector eps(dimension);
97
98 // First 3 elements - attitude
99 eps.template head<3>() = R.logmap(other.R);
100 // Next 3 elements - bias
101 eps.template segment<3>(3) = other.b - b;
102
103 // Remaining elements - calibrations
104 eps.template segment<3 * N>(6) = S.logmap(other.S);
105
106 return eps;
107 }
108
114 State retract(const TangentVector& v) const {
115 Rot3 newR = R.expmap(v.template head<3>());
116 Vector3 newB = b + v.template segment<3>(3);
117 typename Calibrations<N>::TangentVector deltaS;
118 deltaS = v.template segment<3 * N>(6);
119 Calibrations<N> newS = S.expmap(deltaS);
120 return State(newR, newB, newS);
121 }
122
123 void print(const std::string& s = "") const {
124 if (!s.empty()) std::cout << s << " ";
125 std::cout << "State<" << N << ">" << std::endl;
126 R.print(" R");
127 std::cout << " b: " << b.transpose() << std::endl;
128 for (size_t i = 0; i < N; ++i) {
129 const std::string label = " S[" + std::to_string(i) + "]";
130 S[i].print(label);
131 }
132 }
133
134 bool equals(const State<N>& other, double tol = 1e-9) const {
135 if (!R.equals(other.R, tol)) return false;
136 if (!equal_with_abs_tol(b, other.b, tol)) return false;
137 return traits<Calibrations<N>>::Equals(S, other.S, tol);
138 }
139};
140
141//========================================================================
142// Symmetry Group
143//========================================================================
144
149template <size_t n>
151
153template <size_t N>
154auto asTriple = [](const Group<N>& g)
155 -> std::tuple<const Rot3&, const Vector3&, const Calibrations<N>&> {
156 return std::tie(g.first.rotation(), g.first.translation(), g.second);
157};
158
159//========================================================================
160// Group Actions on State, Input, and Output Manifolds
161//========================================================================
162
169template <size_t N>
170struct Symmetry : public GroupAction<Symmetry<N>, Group<N>, State<N>> {
171 using M = State<N>;
172 using G = gtsam::abc::Group<N>;
173 static constexpr ActionType type = ActionType::Right;
174
180 M operator()(const M& xi, const G& g,
183 auto [A, a, B] = asTriple<N>(g);
184 const Rot3 new_R = xi.R * A;
185 Matrix3 skew_p, At; // derivatives of unrotate
186 const Point3 p = xi.b - a;
187 const Vector3 new_b =
188 A.unrotate(p, Hg ? &skew_p : nullptr, (Hg || Hm) ? &At : nullptr);
189 Calibrations<N> new_S;
190 Rot3 invA = A.inverse(); // derivative is (- A)
191 for (size_t i = 0; i < N; i++) {
192 Rot3 SB = xi.S[i].compose(B[i]); // derivative in B[i] is identity
193 new_S[i] = invA.compose(SB); // derivative in invA is SB^{-1}.
194 }
195
196 if (Hm) {
197 Hm->setZero();
198
199 // d(R*A)/dR: right-multiplication by A maps a tangent vector δθ to
200 // Ad_{A^{-1}} δθ = Aᵀ δθ.
201 Hm->template block<3, 3>(0, 0) = At;
202
203 // d(At*(b - a))/db = At.
204 Hm->template block<3, 3>(3, 3) = At;
205
206 // d(At * S[i] * B[i]) / dS[i] = Ad_{B[i]^{-1}} on so(3), which is just
207 // multiplication by B[i]ᵀ in vector form.
208 for (size_t i = 0; i < N; ++i) {
209 const size_t row = 6 + 3 * i;
210 Hm->template block<3, 3>(row, row) = B[i].transpose();
211 }
212 }
213 if (Hg) {
214 Hg->setZero();
215 // Rotation block: δθ maps directly to the state's rotational tangent.
216 Hg->template block<3, 3>(0, 0) = I_3x3;
217
218 // Bias block:
219 Hg->template block<3, 3>(3, 0) = skew_p;
220 Hg->template block<3, 3>(3, 3) = -I_3x3; // - At * A (from translation()
221
222 // Calibration blocks:
223 Matrix3 A_matrix = A.matrix();
224 for (size_t i = 0; i < N; ++i) {
225 Rot3 SB = xi.S[i].compose(B[i]);
226 const size_t row = 6 + 3 * i;
227 const size_t col = 6 + 3 * i;
228 Hg->template block<3, 3>(row, 0) = -SB.transpose() * A_matrix;
229 Hg->template block<3, 3>(row, col) = I_3x3;
230 }
231 }
232 return {new_R, new_b, new_S};
233 }
234
235 struct Orbit : public group_action::Orbit<Symmetry<N>> {
237 using Base::Base; // Inherit constructors
238 };
239};
240
250template <size_t N>
251inline typename State<N>::TangentVector dynamics(const Vector3& omega,
252 const State<N>& xi) {
253 typename State<N>::TangentVector xi_dot;
254 xi_dot.setZero();
255 xi_dot.template head<3>() = omega - xi.b;
256 // Remaining components are already zero.
257 return xi_dot;
258}
259
267template <size_t N>
268struct Lift {
269 using M = State<N>;
270 using G = Group<N>;
271
272 explicit Lift(const Vector6& u) : u_(u) {}
273
274 typename G::TangentVector operator()(
275 const M& xi, OptionalJacobian<G::dimension, M::dimension> H = {}) const {
276 typename G::TangentVector L;
277 Vector3 w = u_.head<3>(); // w = omega
278 Vector3 corrected_w = w - xi.b;
279 L.template head<3>() = corrected_w;
280 L.template segment<3>(3) = -Rot3::Hat(w) * xi.b;
281 if (H) {
282 H->setZero();
283 // corrected_w / xi:
284 H->template block<3, 3>(0, 3) = -I_3x3;
285
286 // next segment:
287 H->template block<3, 3>(3, 3) = -Rot3::Hat(w);
288 }
289 for (size_t i = 0; i < N; i++) {
290 DenseIndex k = 6 + 3 * i;
291 Vector3 v_i = xi.S[i].unrotate(corrected_w);
292 L.template segment<3>(k) = v_i;
293 if (H) {
294 H->template block<3, 3>(k, 3) = -xi.S[i].transpose();
295 H->template block<3, 3>(k, k) = Rot3::Hat(v_i);
296 }
297 }
298
299 return L;
300 }
301
302 private:
303 Vector6 u_;
304};
305
313template <size_t N>
314struct InputAction : public GroupAction<InputAction<N>, Group<N>, Vector6> {
315 using G = Group<N>;
316 static constexpr ActionType type = ActionType::Right;
317
318 Vector6 operator()(const Vector6& u, const G& X) const {
319 const Rot3& A = X.first.rotation();
320 const Vector3& a = X.first.translation();
321 Vector6 result;
322 result.head<3>() = A.unrotate(u.head<3>() - a);
323 result.tail<3>() = Z_3x1;
324 return result;
325 }
326};
327
328// Embed a 6x6 Sigma into full DimU by appending small calibration noise.
329template <size_t N>
330inline Matrix inputProcessNoise(const Matrix& Sigma6) {
331 std::vector<Matrix> blocks{Sigma6};
332 blocks.insert(blocks.end(), N, 1e-9 * I_3x3);
333 return gtsam::diag(blocks);
334}
335
337template <size_t N>
338inline Matrix stateMatrixA(const typename InputAction<N>::Orbit& psi_u,
339 const Group<N>& X_hat) {
340 const Vector6 u0 = psi_u(X_hat.inverse()); // ψ_u(X)^ω (omega, 0)
341 Matrix3 W0 = Rot3::Hat(u0.template head<3>());
342
343 Matrix A1 = Matrix::Zero(6, 6);
344 A1.block<3, 3>(0, 3) = -I_3x3;
345 A1.block<3, 3>(3, 3) = W0;
346
347 std::vector<Matrix> blocks{A1};
348 blocks.insert(blocks.end(), N, W0);
349 return gtsam::diag(blocks);
350}
351
353template <size_t N>
354inline Matrix inputMatrixB(const Group<N>& g) {
355 const Rot3& A = g.first.rotation();
356 const Calibrations<N>& B = g.second;
357 const Matrix3 A_matrix = A.matrix();
358 Matrix B1 = gtsam::diag({A_matrix, A_matrix});
359 Matrix B2(3 * N, 3 * N);
360 B2.setZero();
361 for (size_t i = 0; i < N; ++i) {
362 B2.block<3, 3>(3 * i, 3 * i) = B[i].matrix();
363 }
364 return gtsam::diag({B1, B2});
365}
366
372template <size_t N>
373struct OutputAction : public GroupAction<OutputAction<N>, Group<N>, Vector3> {
374 using G = Group<N>;
375 static constexpr ActionType type = ActionType::Right;
376
377 explicit OutputAction(int index = -1) : index_(index) {}
378
379 Vector3 operator()(const Vector3& y, const G& X,
380 OptionalJacobian<3, 3> H_y = {},
381 OptionalJacobian<3, G::dimension> H_X = {}) const {
382 if (H_X) H_X->setZero();
383 auto [A, a, B] = asTriple<N>(X);
384 if (index_ == -1) {
385 Matrix3 H_rot;
386 Vector3 res = A.unrotate(y, H_X ? &H_rot : nullptr, H_y);
387 if (H_X) H_X->template block<3, 3>(0, 0) = H_rot;
388 return res;
389 } else {
390 Matrix3 H_rot;
391 Vector3 res = B[index_].unrotate(y, H_X ? &H_rot : nullptr, H_y);
392 if (H_X) H_X->template block<3, 3>(0, 6 + 3 * index_) = H_rot;
393 return res;
394 }
395 }
396
397 int index_;
398};
399
401template <size_t N>
402inline Matrix measurementMatrixC(const Unit3& d, int index) {
403 Matrix Cc = Matrix::Zero(3, 3 * N);
404
405 Matrix3 wedge_d = Rot3::Hat(d.unitVector());
406 if (index >= 0) {
407 Cc.block<3, 3>(0, 3 * index) = wedge_d;
408 }
409
410 Matrix temp(3, 6 + 3 * N);
411 temp.block<3, 3>(0, 0) = wedge_d;
412 temp.block<3, 3>(0, 3) = Matrix3::Zero();
413 temp.block(0, 6, 3, 3 * N) = Cc;
414
415 return wedge_d * temp;
416}
417
418template <size_t N>
420 using M = State<N>;
421
423 Innovation(const Unit3& y, const Unit3& d, int index)
424 : y_(y), d_(d), xi_ref_(M::identity()), index_(index) {}
425
426 Innovation(const Unit3& y, const Unit3& d, int index, const M& xi_ref)
427 : y_(y), d_(d), xi_ref_(xi_ref), index_(index) {}
428
429 Vector3 operator()(const M& xi_hat,
431 // Recover A and B_i from (xi_ref_, xi_hat) using the symmetry formulas:
432 // R_hat = R0 * A, S_hat[i] = Aᵀ * S0[i] * B[i]
433 const Rot3 R0 = xi_ref_.R;
434 const Rot3 R_hat = xi_hat.R;
435 const Rot3 A = R0.inverse() * R_hat;
436
437 Vector3 transformed_y;
438 if (index_ == -1) {
439 // Uncalibrated sensor: transformed_y = A * y.
440 transformed_y = A.rotate(y_.unitVector());
441 } else {
442 // Calibrated sensor i: B_i = S0[i]^{-1} * A * S_hat[i]
443 const Rot3& S0i = xi_ref_.S[index_];
444 const Rot3& Shati = xi_hat.S[index_];
445 const Rot3 Bi = S0i.inverse() * A * Shati;
446 transformed_y = Bi.rotate(y_.unitVector());
447 }
448
449 if (H) {
450 *H = measurementMatrixC<N>(d_, index_);
451 }
452
453 const Matrix3 wedge_d = Rot3::Hat(d_.unitVector());
454 return -wedge_d * transformed_y;
455 }
456
457 Unit3 y_; // measured direction
458 Unit3 d_; // reference direction
459 M xi_ref_; // reference state on the manifold
460 int index_;
461};
462
463template <size_t N>
464inline Matrix3 outputMatrixD(const Group<N>& X_hat, int index) {
465 auto [A, a, B] = asTriple<N>(X_hat);
466 if (index >= 0) {
467 return B[index].matrix();
468 } else {
469 return A.matrix();
470 }
471}
472
473} // namespace abc
474
475template <size_t N>
476struct traits<abc::State<N>> : public internal::Manifold<abc::State<N>> {};
477
478template <size_t N>
479struct traits<const abc::State<N>> : public internal::Manifold<abc::State<N>> {
480};
481
482} // namespace gtsam
Base class and basic functions for Matrix Lie groups.
Group product of two Lie Groups.
typedef and functions to augment Eigen's MatrixXd
Macros for Matrix constants to avoid excessive template instantiation.
Macros for Vector constants to avoid excessive template instantiation.
Group action concept and CRTP base class.
typedef and functions to augment Eigen's VectorXd
3D Point
3D Pose manifold SO(3) x R^3 and group SE(3)
3D rotation represented as a rotation matrix or quaternion
Matrix measurementMatrixC(const Unit3 &d, int index)
Compute the measurement matrix C(φ_y).
Definition ABC.h:402
State< N >::TangentVector dynamics(const Vector3 &omega, const State< N > &xi)
Continuous-time dynamics on the manifold M = SO(3) x R^3 x SO(3)^N, as in Eq.
Definition ABC.h:251
Matrix stateMatrixA(const typename InputAction< N >::Orbit &psi_u, const Group< N > &X_hat)
Compute the state matrix A(X_hat).
Definition ABC.h:338
Vector6 toInputVector(const Vector3 &w)
Convert a measured angular velocity ω into the mathematical input (ω, 0).
Definition ABC.h:57
ProductLieGroup< Pose3, Calibrations< n > > Group
Symmetry group G = Pose3 × Calibrations<n>.
Definition ABC.h:150
Matrix inputMatrixB(const Group< N > &g)
Compute the input matrix B(X_hat).
Definition ABC.h:354
PowerLieGroup< Rot3, static_cast< int >(N)> Calibrations
Bundle of calibration rotations modeled as a Lie group.
Definition ABC.h:63
auto asTriple
Unpack g into A, a, and B.
Definition ABC.h:154
Global functions in a separate testing namespace.
Definition chartTesting.h:28
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition types.h:49
Vector3 Point3
As of GTSAM 4, in order to make GTSAM more lean, it is now possible to just typedef Point3 to Vector3...
Definition Point3.h:38
void print(const Matrix &A, const string &s, ostream &stream)
print without optional string, must specify cout yourself
Definition Matrix.cpp:143
ActionType
Enum to specify whether the action is a Left or Right action.
Definition GroupAction.h:30
Matrix diag(const std::vector< Matrix > &Hs)
Create a matrix with submatrices along its diagonal.
Definition Matrix.cpp:194
bool equal_with_abs_tol(const Eigen::DenseBase< MATRIX > &A, const Eigen::DenseBase< MATRIX > &B, double tol=1e-9)
equals with a tolerance
Definition Matrix.h:81
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
Orbit: The map g -> m, defined by fixing m0.
Definition GroupAction.h:45
GroupAction CRTP base class.
Definition GroupAction.h:236
Class expmap(const TangentVector &v) const
expmap as required by manifold concept Applies exponential map to v and composes with *this
Definition Lie.h:155
Both ManifoldTraits and Testable.
Definition Manifold.h:156
OptionalJacobian is an Eigen::Ref like class that can take be constructed using either a fixed size o...
Definition OptionalJacobian.h:40
Direct product Lie group G × H.
Definition ProductLieGroup.h:69
ProductLieGroup inverse() const
Group inverse.
Definition ProductLieGroup-inl.h:57
Template to construct the N-fold power of a Lie group Represents the group G^N = G x G x ....
Definition ProductLieGroup.h:452
Rot3 is a 3D rotation represented as a rotation matrix if the preprocessor symbol GTSAM_USE_QUATERNIO...
Definition Rot3.h:65
static Matrix3 Hat(const Vector3 &xi)
Hat maps from tangent vector to Lie algebra.
Definition Rot3.h:421
Represents a 3D point on a unit sphere.
Definition Unit3.h:44
Vector3 unitVector(OptionalJacobian< 3, 2 > H={}) const
Return unit-norm Vector.
Definition Unit3.cpp:151
Minimal state manifold for the biased attitude system: ξ = (R, b, S).
Definition ABC.h:74
State(const Rot3 &R=Rot3(), const Vector3 &b=Z_3x1, const Calibrations< N > &S=Calibrations< N >())
Constructor.
Definition ABC.h:83
TangentVector localCoordinates(const State< N > &other) const
Compute Local coordinates in the state relative to another state.
Definition ABC.h:95
static State identity()
Identity function.
Definition ABC.h:88
State retract(const TangentVector &v) const
Retract from tangent space back to the manifold.
Definition ABC.h:114
Right action φ_ξ(X) = (R A, Aᵀ(b − a), Aᵀ C B) on the state manifold.
Definition ABC.h:170
M operator()(const M &xi, const G &g, OptionalJacobian< M::dimension, M::dimension > Hm={}, OptionalJacobian< M::dimension, G::dimension > Hg={}) const
Implements group actions on the states.
Definition ABC.h:180
Encodes the partially applied input action ψ_u(X) = Aᵀ(ω − a), used to compute A(X,...
Definition ABC.h:314
Innovation(const Unit3 &y, const Unit3 &d, int index)
Innovation ν = d×(ŷ) where ŷ is the predicted measurement under φ/ρ.
Definition ABC.h:423