Fix IMU covariance whitening with nonzero Coriolis - #2806
Merged
Merged
Conversation
Only predict the nominal endpoint attitude when nonzero Coriolis requires it, and guard parameter access in both ordinary and Combined covariance conversions. Preserve gravity-factor constructor validation for parameterless PIMs. Add covariance regression coverage across all four backends and null-parameter checks through the Python wrapper.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With nonzero
omegaCoriolis, IMU prediction already converts transported velocity back to physical velocity, but the residual covariance omitted the corresponding conversion into the body-frame error coordinates. This PR applies that conversion to ordinary and Combined IMU-factor whitening across all four preintegration backends.Provenance and behavior
This omission was found while auditing the rotating-Earth covariance/NEES path following #2774. The rotating predictor uses
v_bar = v + omega × p, then projects back to physicalv. Covariance previously stopped before that projection. The missing Jacobian block isH(v,p) = -Rᵀ[omega]×R: it both expresses the navigation-frame rotation rate in the endpoint body frame and carries position uncertainty into physical velocity uncertainty. This is more than a rotation of the covariance axes.Apply
H P Hᵀafter the existing backend-chart conversion, retaining the Combined factor's bias-sign convention and navigation–bias cross-covariances. Raw preintegration covariance, mean prediction, and nonlinear residuals are unchanged. WhenomegaCoriolisis unset or zero, the additional conversion is identity.The new
residualCovarianceAt(predictedAttitude)accessor and factor constructor overloads let callers freeze whitening at their nominal endpoint attitude. With nonzeroomegaCoriolis, the recommended argument ispim.predict(nominalState_i, nominalBias_i).attitude(). Existing constructors remain available and use prediction from identity atbiasHat(); this fallback can give different whitening for a differently oriented initial state. Whitening stays fixed during optimization. The shared interface exposes the accessor and constructors in Python and MATLAB, and the NEES helper calls the wrapped C++ accessor directly.Evidence
RotatingMeasurementSensitivityindependently differentiates the complete integrate/predict/Logmap path with respect to each accelerometer and gyroscope sample, then propagates the sample-noise covariance through those numerical derivatives. Its reference does not use the covariance conversion or its analytic Jacobian. It covers all four backends, zero/Earth/exaggerated frame rates, and identity/rotated initial states, and explicitly checks that the former covariance fails the same nonzero-rate comparison.An additional before/after probe uses only the existing
residualCovariance()API. The same source was compiled against the original headers atd56360ce6and the fixed headers, holding integration and prediction code constant. Relative Frobenius covariance error against the numerical reference was:The rates have norms 0, 7.295e-5, and 0.539 rad/s; the last deliberately amplifies the defect. Zero-rate results are identical before and after. These are deterministic covariance discrepancies, not Monte Carlo NEES improvements. They establish the omitted first-order transformation directly.
The Galilean regression additionally checks the inverse-lift Jacobian numerically, full 15D cross-covariances, covariance symmetry/positive semidefiniteness, fixed whitening, and factor Jacobians at finite residuals.
Experiment context: NEES notebook and Logmap results report.
Validation
testGalileanImuFactor,testImuFactorCovariance,testImuFactor, andtestCombinedImuFactorpass on the updated develop base.python-testtarget encountered one stale, deleted-sourceMatrixWeightedLocalizationExampletest referring to an absent dataset; running the current source tests passes.testRotatingImuCovariancepasses actual accessor and constructor/whitening calls, including unset, zero, and nonzeroomegaCoriolis.git diff --checkpasses.