Gyroscope Calibration
| This documentation was generated with the assistance of AI. Please report any inaccuracies. |
The com.irurueta.navigation.inertial.calibration.gyroscope package (86 classes) estimates gyroscope
bias , the scale-factor/cross-coupling matrix , and the
g-dependent cross-bias matrix (extra bias driven by the specific force the
accelerometer senses — typically from mass unbalance in the sensing element):
Algorithm families
| Family | Reference used | Solves for | Needs a turntable? |
|---|---|---|---|
|
Full position/orientation/velocity/angular-rate frame known at each measurement (linear + non-linear least-squares variants, as with the accelerometer’s equivalent families) |
+ + (or just the latter two if bias is known) |
No, but requires precise external ground truth for angular rate. |
|
IMU mounted flat on a turntable spinning at a known, constant rate; turntable fast enough that Earth rotation is negligible, slow enough to be measured accurately. |
+ + (or just the latter two if bias is known) |
Yes. |
|
[imu-tk] Tedaldi, Pretto, Menegatti — no turntable, no known frame: the IMU sits at a roughly fixed Earth location; several sequences of motion (each bracketed by a static period) are captured, and the gravity direction sensed during each static bracket stands in for ground truth. |
+ + (or just the latter two if bias is known) |
No. |
AccelerometerDependentGyroscopeCalibrator is the common interface marking calibrators that also need
(already-calibrated) accelerometer measurements, because g-dependent bias estimation requires knowing the
true specific force.
KnownFrame example
Each measurement pairs a BodyKinematics sample with the known ECEF frame (position, orientation, velocity)
at which it was taken. KnownFrameGyroscopeNonLinearLeastSquaresCalibrator refines an initial
, and guess through non-linear least squares:
// each measurement bundles a body kinematics sample with the known frame it was taken at
final Collection<StandardDeviationFrameBodyKinematics> measurements = new ArrayList<>();
// ...
measurements.add(new StandardDeviationFrameBodyKinematics(measuredKinematics, ecefFrame, ecefFrame,
timeIntervalSeconds, specificForceStandardDeviation, angularRateStandardDeviation));
// initial bg, Mg, Gg guesses close to the expected solution
final Matrix initialBias = new Matrix(3, 1);
final Matrix initialMg = new Matrix(3, 3);
final Matrix initialGg = new Matrix(3, 3);
final var calibrator = new KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(measurements, false, initialBias,
initialMg, initialGg, this);
calibrator.calibrate();
final Matrix estimatedBg = calibrator.getEstimatedBiasesAsMatrix();
final Matrix estimatedMg = calibrator.getEstimatedMg();
final Matrix estimatedGg = calibrator.getEstimatedGg();
Turntable example
Measurements only need position (the turntable’s fixed location) plus the known, constant rotation rate — no per-measurement orientation is required, since the turntable enforces it:
final NEDPosition position = new NEDPosition(latitude, longitude, height);
final double rotationRate = Constants.EARTH_ROTATION_RATE; // rad/s
final double timeInterval = TurntableGyroscopeCalibrator.DEFAULT_TIME_INTERVAL; // seconds
final Collection<StandardDeviationBodyKinematics> measurements = new ArrayList<>();
// ...
measurements.add(new StandardDeviationBodyKinematics(measuredKinematics, specificForceStandardDeviation,
angularRateStandardDeviation));
final Matrix initialBias = new Matrix(3, 1);
final Matrix initialMg = new Matrix(3, 3);
final Matrix initialGg = new Matrix(3, 3);
final var calibrator = new TurntableGyroscopeCalibrator(position, rotationRate, timeInterval, measurements,
true, false, initialBias, initialMg, initialGg);
calibrator.calibrate();
final Matrix estimatedBg = calibrator.getEstimatedBiasesAsMatrix();
final Matrix estimatedMg = calibrator.getEstimatedMg();
final Matrix estimatedGg = calibrator.getEstimatedGg();
The "Easy" calibrator: no turntable required
EasyGyroscopeCalibrator / KnownBiasEasyGyroscopeCalibrator implement the gyroscope half of
[imu-tk]: the same static-interval philosophy as
the accelerometer’s KnownGravityNorm family, extended to the
gyroscope by integrating the angular rate between two static brackets and comparing the integrated
rotation against the attitude change implied by gravity direction before and after:
Each BodyKinematicsSequence (see Calibration Data Model) supplies one such
motion-bracketed-by-statics sample; the interval
detector/generator pipeline is what produces these sequences from a raw sensor stream in the first
place. At least 7 sequences are needed (10 without a common z-axis assumption; 16/19 if g-dependent
bias is also estimated).
Easy example
Each sequence carries the specific-force readings from the static brackets before/after, plus the timed angular-rate samples captured in between:
final List<BodyKinematicsSequence<StandardDeviationTimedBodyKinematics>> sequences = new ArrayList<>();
// ...
final var sequence = new BodyKinematicsSequence<StandardDeviationTimedBodyKinematics>();
sequence.setBeforeMeanSpecificForceCoordinates(beforeMeanFx, beforeMeanFy, beforeMeanFz);
sequence.setAfterMeanSpecificForceCoordinates(afterMeanFx, afterMeanFy, afterMeanFz);
final List<StandardDeviationTimedBodyKinematics> items = new ArrayList<>();
// ...
items.add(new StandardDeviationTimedBodyKinematics(measuredKinematics, timestampSeconds,
specificForceStandardDeviation, angularRateStandardDeviation));
sequence.setItems(items);
sequences.add(sequence);
// known accelerometer bias/cross-coupling, needed because bg-dependent bias
// requires the true specific force
final Matrix initialBias = new Matrix(3, 1);
final Matrix initialMg = new Matrix(3, 3);
final Matrix initialGg = new Matrix(3, 3);
final Matrix accelerometerBias = new Matrix(3, 1);
final Matrix accelerometerMa = new Matrix(3, 3);
final var calibrator = new EasyGyroscopeCalibrator(sequences, true, false, initialBias, initialMg,
initialGg, accelerometerBias, accelerometerMa);
calibrator.calibrate();
final Matrix estimatedBg = calibrator.getEstimatedBiasesAsMatrix();
final Matrix estimatedMg = calibrator.getEstimatedMg();
final Matrix estimatedGg = calibrator.getEstimatedGg();
Quaternion step integrators
Integrating angular rate over a dynamic interval means numerically solving the quaternion kinematic differential equation
QuaternionStepIntegrator defines this as a strategy interface, with QuaternionIntegrator driving it
step-by-step across a sequence. Six schemes are available (selected via QuaternionStepIntegratorType),
trading off accuracy against computational cost:
| Integrator | Reference |
|---|---|
|
First-order Euler method — cheapest, least accurate. |
|
Midpoint method — second-order. |
|
Classic 4th-order Runge-Kutta (RK4) — most accurate of the six, at the highest computational cost. |
|
Y. S. Suh, "Orientation estimation using a quaternion-based indirect Kalman filter with adaptive estimation of external acceleration," 2010 ([suh2010]). |
|
N. Trawny, "Indirect Kalman Filter for 3D Attitude Estimation," 2005 ([trawny2005]). |
|
S. Yuan, "Quaternion-based Unscented Kalman Filter for Real-time," 2015 ([yuan2015]). |
EasyGyroscopeCalibrator uses one of these (configurable) to integrate each dynamic interval before
comparing it against the static-interval gravity readings.
Integrating a sequence directly
QuaternionStepIntegrator.create(type) builds the strategy for one scheme; QuaternionIntegrator
drives it step-by-step across an entire BodyKinematicsSequence to obtain the final attitude:
// integrate a whole sequence in one call, choosing the RK4 scheme
final Quaternion initialAttitude = new Quaternion(); // identity
final Quaternion finalAttitude = QuaternionIntegrator.integrateGyroSequenceAndReturnNew(sequence,
initialAttitude, QuaternionStepIntegratorType.RUNGE_KUTTA);
// or drive a single integration step manually
final QuaternionStepIntegrator stepIntegrator =
QuaternionStepIntegrator.create(QuaternionStepIntegratorType.RUNGE_KUTTA);
final Quaternion result = new Quaternion();
stepIntegrator.integrate(initialAttitude, previousWx, previousWy, previousWz, currentWx, currentWy,
currentWz, dt, result);
Where to go next
-
Accelerometer Calibration — the accelerometer’s parallel known-frame / known-norm structure.
-
Static/Dynamic Interval Detection and Measurement Generation — how
BodyKinematicsSequenceinputs are produced from a raw sensor stream. -
reference.adoc#bibliography — bibliography, including the Tedaldi et al. paper and its imu_tk reference implementation.