View Javadoc
1   /*
2    * Copyright (C) 2020 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.navigation.inertial.calibration.gyroscope;
17  
18  import com.irurueta.algebra.AlgebraException;
19  import com.irurueta.algebra.Matrix;
20  import com.irurueta.algebra.Utils;
21  import com.irurueta.algebra.WrongSizeException;
22  import com.irurueta.navigation.LockedException;
23  import com.irurueta.navigation.NotReadyException;
24  import com.irurueta.navigation.frames.CoordinateTransformation;
25  import com.irurueta.navigation.frames.ECEFPosition;
26  import com.irurueta.navigation.frames.ECEFVelocity;
27  import com.irurueta.navigation.frames.FrameType;
28  import com.irurueta.navigation.frames.InvalidSourceAndDestinationFrameTypeException;
29  import com.irurueta.navigation.frames.NEDFrame;
30  import com.irurueta.navigation.frames.NEDPosition;
31  import com.irurueta.navigation.frames.NEDVelocity;
32  import com.irurueta.navigation.frames.converters.ECEFtoNEDPositionVelocityConverter;
33  import com.irurueta.navigation.frames.converters.NEDtoECEFFrameConverter;
34  import com.irurueta.navigation.frames.converters.NEDtoECEFPositionVelocityConverter;
35  import com.irurueta.navigation.geodesic.Constants;
36  import com.irurueta.navigation.inertial.BodyKinematics;
37  import com.irurueta.navigation.inertial.calibration.AccelerationFixer;
38  import com.irurueta.navigation.inertial.calibration.AngularSpeedTriad;
39  import com.irurueta.navigation.inertial.calibration.CalibrationException;
40  import com.irurueta.navigation.inertial.calibration.StandardDeviationBodyKinematics;
41  import com.irurueta.navigation.inertial.estimators.ECEFKinematicsEstimator;
42  import com.irurueta.numerical.EvaluationException;
43  import com.irurueta.numerical.GradientEstimator;
44  import com.irurueta.numerical.fitting.FittingException;
45  import com.irurueta.numerical.fitting.LevenbergMarquardtMultiDimensionFitter;
46  import com.irurueta.numerical.fitting.LevenbergMarquardtMultiDimensionFunctionEvaluator;
47  import com.irurueta.statistics.MaxIterationsExceededException;
48  import com.irurueta.units.Acceleration;
49  import com.irurueta.units.AccelerationConverter;
50  import com.irurueta.units.AccelerationUnit;
51  import com.irurueta.units.AngularSpeed;
52  import com.irurueta.units.AngularSpeedConverter;
53  import com.irurueta.units.AngularSpeedUnit;
54  import com.irurueta.units.Time;
55  import com.irurueta.units.TimeConverter;
56  import com.irurueta.units.TimeUnit;
57  
58  import java.util.Collection;
59  
60  /**
61   * Estimates gyroscope cross couplings and scaling factors
62   * along with G-dependent cross biases introduced on the gyroscope by the
63   * specific forces sensed by the accelerometer.
64   * <p>
65   * This calibrator assumes that the IMU is placed flat on a turntable spinning
66   * at constant speed, but absolute orientation or position of IMU is unknown.
67   * Turntable must rotate fast enough so that Earth rotation effects can be
68   * neglected, bus slow enough so that gyroscope readings can be properly made.
69   * <p>
70   * To use this calibrator at least 7 measurements are needed when common
71   * z-axis is assumed and G-dependent cross biases are ignored, otherwise
72   * at least 10 measurements are required when common z-axis is not assumed.
73   * If G-dependent cross biases are being estimated, then at least 16
74   * measurements are needed when common z-axis is assumed, otherwise at
75   * least 19 measurements are required when common z-axis is not assumed.
76   * <p>
77   * Measured gyroscope angular rates is assumed to follow the model shown below:
78   * <pre>
79   *     Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
80   * </pre>
81   * Where:
82   * - Ωmeas is the measured gyroscope angular rates. This is a 3x1 vector.
83   * - bg is the gyroscope bias. Ideally, on a perfect gyroscope, this should be a
84   * 3x1 zero vector.
85   * - I is the 3x3 identity matrix.
86   * - Mg is the 3x3 matrix containing cross-couplings and scaling factors. Ideally, on
87   * a perfect gyroscope, this should be a 3x3 zero matrix.
88   * - Ωtrue is ground-truth gyroscope angular rates.
89   * - Gg is the G-dependent cross biases introduced by the specific forces sensed
90   * by the accelerometer. Ideally, on a perfect gyroscope, this should be a 3x3
91   * zero matrix.
92   * - ftrue is ground-truth specific force. This is a 3x1 vector.
93   * - w is measurement noise. This is a 3x1 vector.
94   */
95  public class KnownBiasTurntableGyroscopeCalibrator implements GyroscopeNonLinearCalibrator,
96          KnownBiasGyroscopeCalibrator, UnorderedStandardDeviationBodyKinematicsGyroscopeCalibrator,
97          AccelerometerDependentGyroscopeCalibrator {
98  
99      /**
100      * Indicates whether by default a common z-axis is assumed for both the accelerometer
101      * and gyroscope.
102      */
103     public static final boolean DEFAULT_USE_COMMON_Z_AXIS = true;
104 
105     /**
106      * Indicates that by default G-dependent cross biases introduced
107      * by the accelerometer on the gyroscope are estimated.
108      */
109     public static final boolean DEFAULT_ESTIMATE_G_DEPENDENT_CROSS_BIASES = true;
110 
111     /**
112      * Number of unknowns when common z-axis is assumed for both the accelerometer
113      * and gyroscope when G-dependent cross biases are being estimated.
114      */
115     public static final int COMMON_Z_AXIS_UNKNOWNS_AND_CROSS_BIASES = 15;
116 
117     /**
118      * Number of unknowns for the general case when G-dependent cross
119      * biases are being estimated.
120      */
121     public static final int GENERAL_UNKNOWNS_AND_CROSS_BIASES = 18;
122 
123     /**
124      * Number of unknowns when common z-axis is assumed for both
125      * the accelerometer and gyroscope when G-dependent cross biases
126      * are not being estimated.
127      */
128     public static final int COMMON_Z_AXIS_UNKNOWNS = 6;
129 
130     /**
131      * Number of unknowns for the general case when G-dependent cross
132      * biases are not being estimated.
133      */
134     public static final int GENERAL_UNKNOWNS = 9;
135 
136     /**
137      * Required minimum number of measurements when common z-axis is assumed
138      * and G-dependent cross biases are being estimated.
139      */
140     public static final int MINIMUM_MEASUREMENTS_COMMON_Z_AXIS_AND_CROSS_BIASES =
141             COMMON_Z_AXIS_UNKNOWNS_AND_CROSS_BIASES + 1;
142 
143     /**
144      * Required minimum number of measurements for the general case and
145      * G-dependent cross biases are being estimated.
146      */
147     public static final int MINIMUM_MEASUREMENTS_GENERAL_AND_CROSS_BIASES =
148             GENERAL_UNKNOWNS_AND_CROSS_BIASES + 1;
149 
150     /**
151      * Required minimum number of measurements when common z-axis is assumed
152      * and G-dependent cross biases are being ignored.
153      */
154     public static final int MINIMUM_MEASUREMENTS_COMMON_Z_AXIS = COMMON_Z_AXIS_UNKNOWNS + 1;
155 
156     /**
157      * Required minimum number of measurements for the general case and
158      * G-dependent cross biases are being ignored.
159      */
160     public static final int MINIMUM_MEASUREMENTS_GENERAL = GENERAL_UNKNOWNS + 1;
161 
162     /**
163      * Default turntable rotation rate.
164      */
165     public static final double DEFAULT_TURNTABLE_ROTATION_RATE = Constants.EARTH_ROTATION_RATE;
166 
167     /**
168      * Default time interval between measurements expressed in seconds (s).
169      * This is a typical value when we have 50 samples per second.
170      */
171     public static final double DEFAULT_TIME_INTERVAL = 0.02;
172 
173     /**
174      * Levenberg-Marquardt fitter to find a non-linear solution.
175      */
176     private final LevenbergMarquardtMultiDimensionFitter fitter = new LevenbergMarquardtMultiDimensionFitter();
177 
178     /**
179      * Known x-coordinate of accelerometer bias to be used to fix measured
180      * specific force and find cross biases introduced by the accelerometer.
181      * This is expressed in meters per squared second (m/s^2).
182      */
183     private double accelerometerBiasX;
184 
185     /**
186      * Known y-coordinate of accelerometer bias to be used to fix measured
187      * specific force and find cross biases introduced by the accelerometer.
188      * This is expressed in meters per squared second (m/s^2).
189      */
190     private double accelerometerBiasY;
191 
192     /**
193      * Known z-coordinate of accelerometer bias to be used to fix measured
194      * specific force and find cross biases introduced by the accelerometer.
195      * This is expressed in meters per squared second (m/s^2).
196      */
197     private double accelerometerBiasZ;
198 
199     /**
200      * Known accelerometer x scaling factor to be used to fix measured
201      * specific force and find cross biases introduced by the accelerometer.
202      */
203     private double accelerometerSx;
204 
205     /**
206      * Known accelerometer y scaling factor to be used to fix measured
207      * specific force and find cross biases introduced by the accelerometer.
208      */
209     private double accelerometerSy;
210 
211     /**
212      * Known accelerometer z scaling factor to be used to fix measured
213      * specific force and find cross biases introduced by the accelerometer.
214      */
215     private double accelerometerSz;
216 
217     /**
218      * Known accelerometer x-y cross coupling error to be used to fix measured
219      * specific force and find cross biases introduced by the accelerometer.
220      */
221     private double accelerometerMxy;
222 
223     /**
224      * Know accelerometer x-z cross coupling error to be used to fix measured
225      * specific force and find cross biases introduced by the accelerometer.
226      */
227     private double accelerometerMxz;
228 
229     /**
230      * Known accelerometer y-x cross coupling error to be used to fix measured
231      * specific force and find cross biases introduced by the accelerometer.
232      */
233     private double accelerometerMyx;
234 
235     /**
236      * Known accelerometer y-z cross coupling error to be used to fix measured
237      * specific force and find cross biases introduced by the accelerometer.
238      */
239     private double accelerometerMyz;
240 
241     /**
242      * Known accelerometer z-x cross coupling error to be used to fix measured
243      * specific force and find cross biases introduced by the accelerometer.
244      */
245     private double accelerometerMzx;
246 
247     /**
248      * Known accelerometer z-y cross coupling error to be used to fix measured
249      * specific force and find cross biases introduced by the accelerometer.
250      */
251     private double accelerometerMzy;
252 
253     /**
254      * Known x-coordinate of gyroscope bias.
255      * This is expressed in radians per second (rad/s).
256      */
257     private double biasX;
258 
259     /**
260      * Known y-coordinate of gyroscope bias.
261      * This is expressed in radians per second (rad/s).
262      */
263     private double biasY;
264 
265     /**
266      * Known z-coordinate of gyroscope bias.
267      * This is expressed in radians per second (rad/s).
268      */
269     private double biasZ;
270 
271     /**
272      * Initial gyroscope x scaling factor.
273      */
274     private double initialSx;
275 
276     /**
277      * Initial gyroscope y scaling factor.
278      */
279     private double initialSy;
280 
281     /**
282      * Initial gyroscope z scaling factor.
283      */
284     private double initialSz;
285 
286     /**
287      * Initial gyroscope x-y cross coupling error.
288      */
289     private double initialMxy;
290 
291     /**
292      * Initial gyroscope x-z cross coupling error.
293      */
294     private double initialMxz;
295 
296     /**
297      * Initial gyroscope y-x cross coupling error.
298      */
299     private double initialMyx;
300 
301     /**
302      * Initial gyroscope y-z cross coupling error.
303      */
304     private double initialMyz;
305 
306     /**
307      * Initial gyroscope z-x cross coupling error.
308      */
309     private double initialMzx;
310 
311     /**
312      * Initial gyroscope z-y cross coupling error.
313      */
314     private double initialMzy;
315 
316     /**
317      * Initial G-dependent cross biases introduced on the gyroscope by the
318      * specific forces sensed by the accelerometer.
319      */
320     private Matrix initialGg;
321 
322     /**
323      * Constant rotation rate at which the turntable is spinning.
324      * This is expressed in radians per second (rad/s).
325      */
326     private double turntableRotationRate = DEFAULT_TURNTABLE_ROTATION_RATE;
327 
328     /**
329      * Time interval between measurements being captured expressed in
330      * second (s).
331      */
332     private double timeInterval = DEFAULT_TIME_INTERVAL;
333 
334     /**
335      * Contains a collection of body kinematics measurements taken at
336      * a given position with different unknown orientations and containing
337      * the standard deviations of accelerometer and gyroscope measurements.
338      */
339     private Collection<StandardDeviationBodyKinematics> measurements;
340 
341     /**
342      * Position where body kinematics measures have been taken.
343      */
344     private ECEFPosition position;
345 
346     /**
347      * This flag indicates whether z-axis is assumed to be common for accelerometer
348      * and gyroscope.
349      * When enabled, this eliminates 3 variables from Mg matrix.
350      */
351     private boolean commonAxisUsed = DEFAULT_USE_COMMON_Z_AXIS;
352 
353     /**
354      * This flag indicates whether G-dependent cross biases are being
355      * estimated or not.
356      * When enabled, this adds 9 variables from Gg matrix.
357      */
358     private boolean estimateGDependentCrossBiases = DEFAULT_ESTIMATE_G_DEPENDENT_CROSS_BIASES;
359 
360     /**
361      * Listener to handle events raised by this calibrator.
362      */
363     private KnownBiasTurntableGyroscopeCalibratorListener listener;
364 
365     /**
366      * Estimated gyroscope scale factors and cross coupling errors.
367      * This is the product of matrix Tg containing cross coupling errors and Kg
368      * containing scaling factors.
369      * So that:
370      * <pre>
371      *     Mg = [sx    mxy  mxz] = Tg*Kg
372      *          [myx   sy   myz]
373      *          [mzx   mzy  sz ]
374      * </pre>
375      * Where:
376      * <pre>
377      *     Kg = [sx 0   0 ]
378      *          [0  sy  0 ]
379      *          [0  0   sz]
380      * </pre>
381      * and
382      * <pre>
383      *     Tg = [1          -alphaXy    alphaXz ]
384      *          [alphaYx    1           -alphaYz]
385      *          [-alphaZx   alphaZy     1       ]
386      * </pre>
387      * Hence:
388      * <pre>
389      *     Mg = [sx    mxy  mxz] = Tg*Kg =  [sx             -sy * alphaXy   sz * alphaXz ]
390      *          [myx   sy   myz]            [sx * alphaYx   sy              -sz * alphaYz]
391      *          [mzx   mzy  sz ]            [-sx * alphaZx  sy * alphaZy    sz           ]
392      * </pre>
393      * This instance allows any 3x3 matrix however, typically alphaYx, alphaZx and alphaZy
394      * are considered to be zero if the gyroscope z-axis is assumed to be the same
395      * as the body z-axis. When this is assumed, myx = mzx = mzy = 0 and the Mg matrix
396      * becomes upper diagonal:
397      * <pre>
398      *     Mg = [sx    mxy  mxz]
399      *          [0     sy   myz]
400      *          [0     0    sz ]
401      * </pre>
402      * Values of this matrix are unit-less.
403      */
404     private Matrix estimatedMg;
405 
406     /**
407      * Estimated G-dependent cross biases introduced on the gyroscope by the
408      * specific forces sensed by the accelerometer.
409      * This instance allows any 3x3 matrix.
410      */
411     private Matrix estimatedGg;
412 
413     /**
414      * Estimated covariance matrix for estimated parameters.
415      */
416     private Matrix estimatedCovariance;
417 
418     /**
419      * Estimated chi square value.
420      */
421     private double estimatedChiSq;
422 
423     /**
424      * Estimated degrees of freedom of chi square value. Degrees of freedom is equal to the number of sampled data
425      * minus the number of estimated parameters.
426      */
427     private int estimatedChiSqDegreesOfFreedom;
428 
429     /**
430      * Estimated reduced chi square value. This is equal to estimated chi square value divided by its degrees of
431      * freedom. Ideally this value should be close to 1.0.
432      */
433     private double estimatedReducedChiSq;
434 
435     /**
436      * Estimated mean square error respect to provided measurements.
437      */
438     private double estimatedMse;
439 
440     /**
441      * Estimated probability of finding a smaller chi square value expressed as a value between 0.0 and 1.0. The smaller
442      * the found chi square value is, the better the fit of the estimated parameters to the actual parameter. Thus, the
443      * smaller the chance of finding a smaller chi square value, then the better the estimated fit is.
444      */
445     private double estimatedP;
446 
447     /**
448      * Estimated measure of quality of estimated fit as a value between 0.0 and 1.0. The larger the quality value is,
449      * the better the fit that has been estimated.
450      */
451     private double estimatedQ;
452 
453     /**
454      * Indicates whether calibrator is running.
455      */
456     private boolean running;
457 
458     /**
459      * Internally holds x-coordinate of measured angular rate during calibration.
460      */
461     private double measAngularRateX;
462 
463     /**
464      * Internally holds y-coordinate of measured angular rate during calibration.
465      */
466     private double measAngularRateY;
467 
468     /**
469      * Internally holds z-coordinate of measured angular rate during calibration.
470      */
471     private double measAngularRateZ;
472 
473     /**
474      * Internally holds x-coordinate of measured specific force during calibration.
475      */
476     private double fmeasX;
477 
478     /**
479      * Internally holds y-coordinate of measured specific force during calibration.
480      */
481     private double fmeasY;
482 
483     /**
484      * Internally holds z-coordinate of measured specific force during calibration.
485      */
486     private double fmeasZ;
487 
488     /**
489      * Internally holds measured angular rate during calibration expressed as
490      * a column matrix.
491      */
492     private Matrix measAngularRate;
493 
494     /**
495      * Internally holds measured specific force during calibration expressed as
496      * a column matrix.
497      */
498     private Matrix fmeas;
499 
500     /**
501      * Internally holds cross-coupling errors during calibration.
502      */
503     private Matrix m;
504 
505     /**
506      * Internally holds inverse of cross-coupling errors during calibration.
507      */
508     private Matrix invM;
509 
510     /**
511      * Internally holds biases during calibration.
512      */
513     private Matrix b;
514 
515     /**
516      * Internally hold g-dependent cross biases during calibration.
517      */
518     private Matrix g;
519 
520     /**
521      * Internally holds computed true angular rate during calibration.
522      */
523     private Matrix trueAngularRate;
524 
525     /**
526      * Internally holds computed true specific force during calibration.
527      */
528     private Matrix ftrue;
529 
530     /**
531      * Internally holds accelerometer bias during calibration.
532      */
533     private Matrix ba;
534 
535     /**
536      * Internally holds accelerometer scaling and cross coupling errors
537      * during calibration.
538      */
539     private Matrix ma;
540 
541     /**
542      * Internally holds angular rate bias due to g-dependent cross biases
543      */
544     private Matrix tmp;
545 
546     /**
547      * Acceleration fixer.
548      */
549     private final AccelerationFixer accelerationFixer = new AccelerationFixer();
550 
551     /**
552      * Constructor.
553      */
554     public KnownBiasTurntableGyroscopeCalibrator() {
555         try {
556             initialGg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
557         } catch (final WrongSizeException ignore) {
558             // never happens
559         }
560     }
561 
562     /**
563      * Constructor.
564      *
565      * @param position              position where body kinematics measures
566      *                              have been taken.
567      * @param turntableRotationRate constant rotation rate at which the
568      *                              turntable is spinning. Must be
569      *                              expressed in radians per second (rad/s).
570      * @param timeInterval          time interval between measurements being
571      *                              captured expressed in seconds (s).
572      * @param measurements          collection of body kinematics
573      *                              measurements with standard deviations
574      *                              taken at the same position with zero
575      *                              velocity and unknown different
576      *                              orientations.
577      * @param bias                  known gyroscope bias. This must be 3x1
578      *                              and is expressed in radians per second
579      *                              (rad/s).
580      * @param initialMg             initial gyroscope scale factors and
581      *                              cross coupling errors matrix. Must
582      *                              be 3x3.
583      * @param initialGg             initial gyroscope G-dependent cross
584      *                              biases introduced on the gyroscope by
585      *                              the specific forces sensed by the
586      *                              accelerometer. Must be 3x3.
587      * @throws IllegalArgumentException if any of the provided values does
588      *                                  not have proper size or if either
589      *                                  turntable rotation rate or
590      *                                  time interval is zero or negative.
591      */
592     public KnownBiasTurntableGyroscopeCalibrator(
593             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
594             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
595             final Matrix initialGg) {
596         this();
597         this.position = position;
598         this.measurements = measurements;
599         try {
600             setTurntableRotationRate(turntableRotationRate);
601             setTimeInterval(timeInterval);
602             setBias(bias);
603             setInitialMg(initialMg);
604             setInitialGg(initialGg);
605         } catch (final LockedException ignore) {
606             // never happens
607         }
608     }
609 
610     /**
611      * Constructor.
612      *
613      * @param position              position where body kinematics measures
614      *                              have been taken.
615      * @param turntableRotationRate constant rotation rate at which the
616      *                              turntable is spinning. Must be
617      *                              expressed in radians per second (rad/s).
618      * @param timeInterval          time interval between measurements being
619      *                              captured expressed in seconds (s).
620      * @param measurements          collection of body kinematics
621      *                              measurements with standard deviations
622      *                              taken at the same position with zero
623      *                              velocity and unknown different
624      *                              orientations.
625      * @param bias                  known gyroscope bias. This must be 3x1
626      *                              and is expressed in radians per second
627      *                              (rad/s).
628      * @param initialMg             initial gyroscope scale factors and
629      *                              cross coupling errors matrix. Must
630      *                              be 3x3.
631      * @param initialGg             initial gyroscope G-dependent cross
632      *                              biases introduced on the gyroscope by
633      *                              the specific forces sensed by the
634      *                              accelerometer. Must be 3x3.
635      * @param listener              listener to handle events raised by this
636      *                              calibrator.
637      * @throws IllegalArgumentException if any of the provided values does
638      *                                  not have proper size or if either
639      *                                  turntable rotation rate or
640      *                                  time interval is zero or negative.
641      */
642     public KnownBiasTurntableGyroscopeCalibrator(
643             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
644             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
645             final Matrix initialGg, final KnownBiasTurntableGyroscopeCalibratorListener listener) {
646         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
647         this.listener = listener;
648     }
649 
650     /**
651      * Constructor.
652      *
653      * @param position              position where body kinematics measures
654      *                              have been taken.
655      * @param turntableRotationRate constant rotation rate at which the
656      *                              turntable is spinning. Must be
657      *                              expressed in radians per second (rad/s).
658      * @param timeInterval          time interval between measurements being
659      *                              captured expressed in seconds (s).
660      * @param measurements          collection of body kinematics
661      *                              measurements with standard deviations
662      *                              taken at the same position with zero
663      *                              velocity and unknown different
664      *                              orientations.
665      * @param bias                  known gyroscope bias. This must have
666      *                              length 3 and is expressed in radians
667      *                              per second (rad/s).
668      * @param initialMg             initial gyroscope scale factors and
669      *                              cross coupling errors matrix. Must
670      *                              be 3x3.
671      * @param initialGg             initial gyroscope G-dependent cross
672      *                              biases introduced on the gyroscope by
673      *                              the specific forces sensed by the
674      *                              accelerometer. Must be 3x3.
675      * @throws IllegalArgumentException if any of the provided values does
676      *                                  not have proper size or if either
677      *                                  turntable rotation rate or
678      *                                  time interval is zero or negative.
679      */
680     public KnownBiasTurntableGyroscopeCalibrator(
681             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
682             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias, final Matrix initialMg,
683             final Matrix initialGg) {
684         this();
685         this.position = position;
686         this.measurements = measurements;
687         try {
688             setTurntableRotationRate(turntableRotationRate);
689             setTimeInterval(timeInterval);
690             setBias(bias);
691             setInitialMg(initialMg);
692             setInitialGg(initialGg);
693         } catch (final LockedException ignore) {
694             // never happens
695         }
696     }
697 
698     /**
699      * Constructor.
700      *
701      * @param position              position where body kinematics measures
702      *                              have been taken.
703      * @param turntableRotationRate constant rotation rate at which the
704      *                              turntable is spinning. Must be
705      *                              expressed in radians per second (rad/s).
706      * @param timeInterval          time interval between measurements being
707      *                              captured expressed in seconds (s).
708      * @param measurements          collection of body kinematics
709      *                              measurements with standard deviations
710      *                              taken at the same position with zero
711      *                              velocity and unknown different
712      *                              orientations.
713      * @param bias                  known gyroscope bias. This must have
714      *                              length 3 and is expressed in radians
715      *                              per second (rad/s).
716      * @param initialMg             initial gyroscope scale factors and
717      *                              cross coupling errors matrix. Must
718      *                              be 3x3.
719      * @param initialGg             initial gyroscope G-dependent cross
720      *                              biases introduced on the gyroscope by
721      *                              the specific forces sensed by the
722      *                              accelerometer. Must be 3x3.
723      * @param listener              listener to handle events raised by
724      *                              this calibrator.
725      * @throws IllegalArgumentException if any of the provided values does
726      *                                  not have proper size or if either
727      *                                  turntable rotation rate or
728      *                                  time interval is zero or negative.
729      */
730     public KnownBiasTurntableGyroscopeCalibrator(
731             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
732             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias, final Matrix initialMg,
733             final Matrix initialGg, final KnownBiasTurntableGyroscopeCalibratorListener listener) {
734         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
735         this.listener = listener;
736     }
737 
738     /**
739      * Constructor.
740      *
741      * @param position              position where body kinematics measures
742      *                              have been taken.
743      * @param turntableRotationRate constant rotation rate at which the
744      *                              turntable is spinning. Must be
745      *                              expressed in radians per second (rad/s).
746      * @param timeInterval          time interval between measurements being
747      *                              captured expressed in seconds (s).
748      * @param measurements          collection of body kinematics
749      *                              measurements with standard deviations
750      *                              taken at the same position with zero
751      *                              velocity and unknown different
752      *                              orientations.
753      * @param bias                  known gyroscope bias. This must have
754      *                              length 3 and is expressed in radians per
755      *                              second (rad/s).
756      * @param initialMg             initial gyroscope scale factors and
757      *                              cross coupling errors matrix. Must
758      *                              be 3x3.
759      * @param initialGg             initial gyroscope G-dependent cross
760      *                              biases introduced on the gyroscope by
761      *                              the specific forces sensed by the
762      *                              accelerometer. Must be 3x3.
763      * @param accelerometerBias     known accelerometer bias. This must
764      *                              have length 3 and is expressed in
765      *                              meters per squared second
766      *                              (m/s^2).
767      * @param accelerometerMa       known accelerometer scale factors and
768      *                              cross coupling matrix. Must be 3x3.
769      * @throws IllegalArgumentException if any of the provided values does
770      *                                  not have proper size or if either
771      *                                  turntable rotation rate or
772      *                                  time interval is zero or negative.
773      */
774     public KnownBiasTurntableGyroscopeCalibrator(
775             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
776             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias, final Matrix initialMg,
777             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa) {
778         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
779         try {
780             setAccelerometerBias(accelerometerBias);
781             setAccelerometerMa(accelerometerMa);
782         } catch (final LockedException ignore) {
783             // never happens
784         }
785     }
786 
787     /**
788      * Constructor.
789      *
790      * @param position              position where body kinematics measures
791      *                              have been taken.
792      * @param turntableRotationRate constant rotation rate at which the
793      *                              turntable is spinning. Must be
794      *                              expressed in radians per second (rad/s).
795      * @param timeInterval          time interval between measurements being
796      *                              captured expressed in seconds (s).
797      * @param measurements          collection of body kinematics
798      *                              measurements with standard deviations
799      *                              taken at the same position with zero
800      *                              velocity and unknown different
801      *                              orientations.
802      * @param bias                  known gyroscope bias. This must have
803      *                              length 3 and is expressed in radians per
804      *                              second (rad/s).
805      * @param initialMg             initial gyroscope scale factors and
806      *                              cross coupling errors matrix. Must
807      *                              be 3x3.
808      * @param initialGg             initial gyroscope G-dependent cross
809      *                              biases introduced on the gyroscope by
810      *                              the specific forces sensed by the
811      *                              accelerometer. Must be 3x3.
812      * @param accelerometerBias     known accelerometer bias. This must
813      *                              have length 3 and is expressed in
814      *                              meters per squared second (m/s^2).
815      * @param accelerometerMa       known accelerometer scale factors and
816      *                              cross coupling matrix. Must be 3x3.
817      * @param listener              listener to handle events raised by
818      *                              this calibrator.
819      * @throws IllegalArgumentException if any of the provided values does
820      *                                  not have proper size or if either
821      *                                  turntable rotation rate or
822      *                                  time interval is zero or negative.
823      */
824     public KnownBiasTurntableGyroscopeCalibrator(
825             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
826             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias, final Matrix initialMg,
827             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa,
828             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
829         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg, accelerometerBias,
830                 accelerometerMa);
831         this.listener = listener;
832     }
833 
834     /**
835      * Constructor.
836      *
837      * @param position              position where body kinematics measures
838      *                              have been taken.
839      * @param turntableRotationRate constant rotation rate at which the
840      *                              turntable is spinning. Must be
841      *                              expressed in radians per second (rad/s).
842      * @param timeInterval          time interval between measurements being
843      *                              captured expressed in seconds (s).
844      * @param measurements          collection of body kinematics
845      *                              measurements with standard deviations
846      *                              taken at the same position with zero
847      *                              velocity and unknown different
848      *                              orientations.
849      * @param bias                  known gyroscope bias. This must be 3x1
850      *                              and is expressed in radians per second
851      *                              (rad/s).
852      * @param initialMg             initial gyroscope scale factors and
853      *                              cross coupling errors matrix. Must
854      *                              be 3x3.
855      * @param initialGg             initial gyroscope G-dependent cross
856      *                              biases introduced on the gyroscope by
857      *                              the specific forces sensed by the
858      *                              accelerometer. Must be 3x3.
859      * @param accelerometerBias     known accelerometer bias. This must
860      *                              have length 3 and is expressed in
861      *                              meters per squared second
862      *                              (m/s^2).
863      * @param accelerometerMa       known accelerometer scale factors and
864      *                              cross coupling matrix. Must be 3x3.
865      * @throws IllegalArgumentException if any of the provided values does
866      *                                  not have proper size or if either
867      *                                  turntable rotation rate or
868      *                                  time interval is zero or negative.
869      */
870     public KnownBiasTurntableGyroscopeCalibrator(
871             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
872             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
873             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa) {
874         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
875         try {
876             setAccelerometerBias(accelerometerBias);
877             setAccelerometerMa(accelerometerMa);
878         } catch (final LockedException ignore) {
879             // never happens
880         }
881     }
882 
883     /**
884      * Constructor.
885      *
886      * @param position              position where body kinematics measures
887      *                              have been taken.
888      * @param turntableRotationRate constant rotation rate at which the
889      *                              turntable is spinning. Must be
890      *                              expressed in radians per second (rad/s).
891      * @param timeInterval          time interval between measurements being
892      *                              captured expressed in seconds (s).
893      * @param measurements          collection of body kinematics
894      *                              measurements with standard deviations
895      *                              taken at the same position with zero
896      *                              velocity and unknown different
897      *                              orientations.
898      * @param bias                  known gyroscope bias. This must be 3x1
899      *                              and is expressed in radians per second
900      *                              (rad/s).
901      * @param initialMg             initial gyroscope scale factors and
902      *                              cross coupling errors matrix. Must
903      *                              be 3x3.
904      * @param initialGg             initial gyroscope G-dependent cross
905      *                              biases introduced on the gyroscope by
906      *                              the specific forces sensed by the
907      *                              accelerometer. Must be 3x3.
908      * @param accelerometerBias     known accelerometer bias. This must
909      *                              have length 3 and is expressed in
910      *                              meters per squared second (m/s^2).
911      * @param accelerometerMa       known accelerometer scale factors and
912      *                              cross coupling matrix. Must be 3x3.
913      * @param listener              listener to handle events raised by
914      *                              this calibrator.
915      * @throws IllegalArgumentException if any of the provided values does
916      *                                  not have proper size or if either
917      *                                  turntable rotation rate or
918      *                                  time interval is zero or negative.
919      */
920     public KnownBiasTurntableGyroscopeCalibrator(
921             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
922             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
923             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa,
924             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
925         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg, accelerometerBias,
926                 accelerometerMa);
927         this.listener = listener;
928     }
929 
930     /**
931      * Constructor.
932      *
933      * @param position                      position where body kinematics
934      *                                      measures have been taken.
935      * @param turntableRotationRate         constant rotation rate at which
936      *                                      the turntable is spinning. Must
937      *                                      be expressed in radians per
938      *                                      second (rad/s).
939      * @param timeInterval                  time interval between measurements
940      *                                      being captured expressed in
941      *                                      seconds (s).
942      * @param measurements                  collection of body kinematics
943      *                                      measurements with standard
944      *                                      deviations taken at the same
945      *                                      position with zero velocity
946      *                                      and unknown different
947      *                                      orientations.
948      * @param commonAxisUsed                indicates whether z-axis is
949      *                                      assumed to be common for
950      *                                      accelerometer and gyroscope.
951      * @param estimateGDependentCrossBiases true if G-dependent cross biases
952      *                                      will be estimated, false
953      *                                      otherwise.
954      * @param bias                          known gyroscope bias. This must
955      *                                      be 3x1 and is expressed in
956      *                                      radians per second (rad/s).
957      * @param initialMg                     initial gyroscope scale factors
958      *                                      and cross coupling errors matrix.
959      *                                      Must be 3x3.
960      * @param initialGg                     initial gyroscope G-dependent
961      *                                      cross biases introduced on the
962      *                                      gyroscope by the specific
963      *                                      forces sensed by the
964      *                                      accelerometer. Must be 3x3.
965      * @throws IllegalArgumentException if any of the provided values does
966      *                                  not have proper size or if either
967      *                                  turntable rotation rate or
968      *                                  time interval is zero or negative.
969      */
970     public KnownBiasTurntableGyroscopeCalibrator(
971             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
972             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
973             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
974             final Matrix initialGg) {
975         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
976         this.commonAxisUsed = commonAxisUsed;
977         this.estimateGDependentCrossBiases = estimateGDependentCrossBiases;
978     }
979 
980     /**
981      * Constructor.
982      *
983      * @param position                      position where body kinematics
984      *                                      measures have been taken.
985      * @param turntableRotationRate         constant rotation rate at which
986      *                                      the turntable is spinning. Must
987      *                                      be expressed in radians per
988      *                                      second (rad/s).
989      * @param timeInterval                  time interval between measurements
990      *                                      being captured expressed in
991      *                                      seconds (s).
992      * @param measurements                  collection of body kinematics
993      *                                      measurements with standard
994      *                                      deviations taken at the same
995      *                                      position with zero velocity and
996      *                                      unknown different orientations.
997      * @param commonAxisUsed                indicates whether z-axis is
998      *                                      assumed to be common for
999      *                                      accelerometer and gyroscope.
1000      * @param estimateGDependentCrossBiases true if G-dependent cross
1001      *                                      biases will be estimated, false
1002      *                                      otherwise.
1003      * @param bias                          known gyroscope bias. This must
1004      *                                      be 3x1 and is expressed in
1005      *                                      radians per second (rad/s).
1006      * @param initialMg                     initial gyroscope scale factors
1007      *                                      and cross coupling errors
1008      *                                      matrix. Must be 3x3.
1009      * @param initialGg                     initial gyroscope G-dependent
1010      *                                      cross biases introduced on the
1011      *                                      gyroscope by the specific
1012      *                                      forces sensed by the
1013      *                                      accelerometer. Must be 3x3.
1014      * @param listener                      listener to handle events
1015      *                                      raised by this calibrator.
1016      * @throws IllegalArgumentException if any of the provided values does
1017      *                                  not have proper size or if either
1018      *                                  turntable rotation rate or
1019      *                                  time interval is zero or negative.
1020      */
1021     public KnownBiasTurntableGyroscopeCalibrator(
1022             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
1023             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1024             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
1025             final Matrix initialGg, final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1026         this(position, turntableRotationRate, timeInterval, measurements, commonAxisUsed, estimateGDependentCrossBiases,
1027                 bias, initialMg, initialGg);
1028         this.listener = listener;
1029     }
1030 
1031     /**
1032      * Constructor.
1033      *
1034      * @param position                      position where body kinematics
1035      *                                      measures have been taken.
1036      * @param turntableRotationRate         constant rotation rate at which
1037      *                                      the turntable is spinning. Must
1038      *                                      be expressed in radians per
1039      *                                      second (rad/s).
1040      * @param timeInterval                  time interval between measurements
1041      *                                      being captured expressed in
1042      *                                      seconds (s).
1043      * @param measurements                  collection of body kinematics
1044      *                                      measurements with standard
1045      *                                      deviations taken at the same
1046      *                                      position with zero velocity
1047      *                                      and unknown different
1048      *                                      orientations.
1049      * @param commonAxisUsed                indicates whether z-axis is
1050      *                                      assumed to be common for
1051      *                                      accelerometer and gyroscope.
1052      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1053      *                                      will be estimated, false
1054      *                                      otherwise.
1055      * @param bias                          known gyroscope bias. This must
1056      *                                      have length 3 and is expressed
1057      *                                      in radians per second (rad/s).
1058      * @param initialMg                     initial gyroscope scale factors
1059      *                                      and cross coupling errors matrix.
1060      *                                      Must be 3x3.
1061      * @param initialGg                     initial gyroscope G-dependent
1062      *                                      cross biases introduced on the
1063      *                                      gyroscope by the specific forces
1064      *                                      sensed by the accelerometer.
1065      *                                      Must be 3x3.
1066      * @throws IllegalArgumentException if any of the provided values does
1067      *                                  not have proper size or if either
1068      *                                  turntable rotation rate or
1069      *                                  time interval is zero or negative.
1070      */
1071     public KnownBiasTurntableGyroscopeCalibrator(
1072             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
1073             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1074             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
1075             final Matrix initialGg) {
1076         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
1077         this.commonAxisUsed = commonAxisUsed;
1078         this.estimateGDependentCrossBiases = estimateGDependentCrossBiases;
1079     }
1080 
1081     /**
1082      * Constructor.
1083      *
1084      * @param position                      position where body kinematics
1085      *                                      measures have been taken.
1086      * @param turntableRotationRate         constant rotation rate at which
1087      *                                      the turntable is spinning. Must
1088      *                                      be expressed in radians per
1089      *                                      second (rad/s).
1090      * @param timeInterval                  time interval between measurements
1091      *                                      being captured expressed in
1092      *                                      seconds (s).
1093      * @param measurements                  collection of body kinematics
1094      *                                      measurements with standard
1095      *                                      deviations taken at the same
1096      *                                      position with zero velocity
1097      *                                      and unknown different
1098      *                                      orientations.
1099      * @param commonAxisUsed                indicates whether z-axis is
1100      *                                      assumed to be common for
1101      *                                      accelerometer and gyroscope.
1102      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1103      *                                      will be estimated, false
1104      *                                      otherwise.
1105      * @param bias                          known gyroscope bias. This must
1106      *                                      have length 3 and is expressed
1107      *                                      in radians per second (rad/s).
1108      * @param initialMg                     initial gyroscope scale factors
1109      *                                      and cross coupling errors
1110      *                                      matrix. Must be 3x3.
1111      * @param initialGg                     initial gyroscope G-dependent
1112      *                                      cross biases introduced on the
1113      *                                      gyroscope by the specific forces
1114      *                                      sensed by the accelerometer.
1115      *                                      Must be 3x3.
1116      * @param listener                      listener to handle events raised
1117      *                                      by this calibrator.
1118      * @throws IllegalArgumentException if any of the provided values does
1119      *                                  not have proper size or if either
1120      *                                  turntable rotation rate or
1121      *                                  time interval is zero or negative.
1122      */
1123     public KnownBiasTurntableGyroscopeCalibrator(
1124             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
1125             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1126             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
1127             final Matrix initialGg, final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1128         this(position, turntableRotationRate, timeInterval, measurements, commonAxisUsed, estimateGDependentCrossBiases,
1129                 bias, initialMg, initialGg);
1130         this.listener = listener;
1131     }
1132 
1133     /**
1134      * Constructor.
1135      *
1136      * @param position                      position where body kinematics
1137      *                                      measures have been taken.
1138      * @param turntableRotationRate         constant rotation rate at which
1139      *                                      the turntable is spinning. Must
1140      *                                      be expressed in radians per
1141      *                                      second (rad/s).
1142      * @param timeInterval                  time interval between measurements
1143      *                                      being captured expressed in
1144      *                                      seconds (s).
1145      * @param measurements                  collection of body kinematics
1146      *                                      measurements with standard
1147      *                                      deviations taken at the same
1148      *                                      position with zero velocity
1149      *                                      and unknown different
1150      *                                      orientations.
1151      * @param commonAxisUsed                indicates whether z-axis is
1152      *                                      assumed to be common for
1153      *                                      accelerometer and gyroscope.
1154      * @param estimateGDependentCrossBiases true if G-dependent cross
1155      *                                      biases will be estimated,
1156      *                                      false otherwise.
1157      * @param bias                          known gyroscope bias. This must
1158      *                                      have length 3 and is expressed
1159      *                                      in radians per second (rad/s).
1160      * @param initialMg                     initial gyroscope scale factors
1161      *                                      and cross coupling errors
1162      *                                      matrix. Must be 3x3.
1163      * @param initialGg                     initial gyroscope G-dependent
1164      *                                      cross biases introduced on the
1165      *                                      gyroscope by the specific forces
1166      *                                      sensed by the accelerometer.
1167      *                                      Must be 3x3.
1168      * @param accelerometerBias             known accelerometer bias. This
1169      *                                      must have length 3 and is
1170      *                                      expressed in meters per squared
1171      *                                      second (m/s^2).
1172      * @param accelerometerMa               known accelerometer scale factors
1173      *                                      and cross coupling matrix. Must
1174      *                                      be 3x3.
1175      * @throws IllegalArgumentException if any of the provided values does
1176      *                                  not have proper size or if either
1177      *                                  turntable rotation rate or
1178      *                                  time interval is zero or negative.
1179      */
1180     public KnownBiasTurntableGyroscopeCalibrator(
1181             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
1182             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1183             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
1184             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa) {
1185         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg, accelerometerBias,
1186                 accelerometerMa);
1187         this.commonAxisUsed = commonAxisUsed;
1188         this.estimateGDependentCrossBiases = estimateGDependentCrossBiases;
1189     }
1190 
1191     /**
1192      * Constructor.
1193      *
1194      * @param position                      position where body kinematics
1195      *                                      measures have been taken.
1196      * @param turntableRotationRate         constant rotation rate at which
1197      *                                      the turntable is spinning. Must
1198      *                                      be expressed in radians per
1199      *                                      second (rad/s).
1200      * @param timeInterval                  time interval between measurements
1201      *                                      being captured expressed in
1202      *                                      seconds (s).
1203      * @param measurements                  collection of body kinematics
1204      *                                      measurements with standard
1205      *                                      deviations taken at the same
1206      *                                      position with zero velocity
1207      *                                      and unknown different
1208      *                                      orientations.
1209      * @param commonAxisUsed                indicates whether z-axis is
1210      *                                      assumed to be common for
1211      *                                      accelerometer and gyroscope.
1212      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1213      *                                      will be estimated, false
1214      *                                      otherwise.
1215      * @param bias                          known gyroscope bias. This must
1216      *                                      have length 3 and is expressed
1217      *                                      in radians per second (rad/s).
1218      * @param initialMg                     initial gyroscope scale factors
1219      *                                      and cross coupling errors matrix.
1220      *                                      Must be 3x3.
1221      * @param initialGg                     initial gyroscope G-dependent
1222      *                                      cross biases introduced on the
1223      *                                      gyroscope by the specific forces
1224      *                                      sensed by the accelerometer. Must
1225      *                                      be 3x3.
1226      * @param accelerometerBias             known accelerometer bias. This
1227      *                                      must have length 3 and is
1228      *                                      expressed in meters per squared
1229      *                                      second (m/s^2).
1230      * @param accelerometerMa               known accelerometer scale factors
1231      *                                      and cross coupling matrix. Must
1232      *                                      be 3x3.
1233      * @param listener                      listener to handle events raised
1234      *                                      by this calibrator.
1235      * @throws IllegalArgumentException if any of the provided values does
1236      *                                  not have proper size or if either
1237      *                                  turntable rotation rate or
1238      *                                  time interval is zero or negative.
1239      */
1240     public KnownBiasTurntableGyroscopeCalibrator(
1241             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
1242             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1243             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
1244             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa,
1245             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1246         this(position, turntableRotationRate, timeInterval, measurements, commonAxisUsed, estimateGDependentCrossBiases,
1247                 bias, initialMg, initialGg, accelerometerBias, accelerometerMa);
1248         this.listener = listener;
1249     }
1250 
1251     /**
1252      * Constructor.
1253      *
1254      * @param position                      position where body kinematics
1255      *                                      measures have been taken.
1256      * @param turntableRotationRate         constant rotation rate at which
1257      *                                      the turntable is spinning. Must
1258      *                                      be expressed in radians per
1259      *                                      second (rad/s).
1260      * @param timeInterval                  time interval between measurements
1261      *                                      being captured expressed in
1262      *                                      seconds (s).
1263      * @param measurements                  collection of body kinematics
1264      *                                      measurements with standard
1265      *                                      deviations taken at the same
1266      *                                      position with zero velocity and
1267      *                                      unknown different orientations.
1268      * @param commonAxisUsed                indicates whether z-axis is
1269      *                                      assumed to be common for
1270      *                                      accelerometer and gyroscope.
1271      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1272      *                                      will be estimated, false
1273      *                                      otherwise.
1274      * @param bias                          known gyroscope bias. This must
1275      *                                      be 3x1 and is expressed in
1276      *                                      radians per second (rad/s).
1277      * @param initialMg                     initial gyroscope scale factors
1278      *                                      and cross coupling errors matrix.
1279      *                                      Must be 3x3.
1280      * @param initialGg                     initial gyroscope G-dependent
1281      *                                      cross biases introduced on the
1282      *                                      gyroscope by the specific forces
1283      *                                      sensed by the accelerometer. Must
1284      *                                      be 3x3.
1285      * @param accelerometerBias             known accelerometer bias. This
1286      *                                      must have length 3 and is
1287      *                                      expressed in meters per squared
1288      *                                      second (m/s^2).
1289      * @param accelerometerMa               known accelerometer scale factors
1290      *                                      and cross coupling matrix. Must
1291      *                                      be 3x3.
1292      * @throws IllegalArgumentException if any of the provided values does
1293      *                                  not have proper size or if either
1294      *                                  turntable rotation rate or
1295      *                                  time interval is zero or negative.
1296      */
1297     public KnownBiasTurntableGyroscopeCalibrator(
1298             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
1299             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1300             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
1301             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa) {
1302         this(position, turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg, accelerometerBias,
1303                 accelerometerMa);
1304         this.commonAxisUsed = commonAxisUsed;
1305         this.estimateGDependentCrossBiases = estimateGDependentCrossBiases;
1306     }
1307 
1308     /**
1309      * Constructor.
1310      *
1311      * @param position                      position where body kinematics
1312      *                                      measures have been taken.
1313      * @param turntableRotationRate         constant rotation rate at which
1314      *                                      the turntable is spinning. Must
1315      *                                      be expressed in radians per
1316      *                                      second (rad/s).
1317      * @param timeInterval                  time interval between measurements
1318      *                                      being captured expressed in
1319      *                                      seconds (s).
1320      * @param measurements                  collection of body kinematics
1321      *                                      measurements with standard
1322      *                                      deviations taken at the same
1323      *                                      position with zero velocity and
1324      *                                      unknown different orientations.
1325      * @param commonAxisUsed                indicates whether z-axis is
1326      *                                      assumed to be common for
1327      *                                      accelerometer and gyroscope.
1328      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1329      *                                      will be estimated, false
1330      *                                      otherwise.
1331      * @param bias                          known gyroscope bias. This must
1332      *                                      be 3x1 and is expressed in
1333      *                                      radians per second (rad/s).
1334      * @param initialMg                     initial gyroscope scale factors
1335      *                                      and cross coupling errors matrix.
1336      *                                      Must be 3x3.
1337      * @param initialGg                     initial gyroscope G-dependent
1338      *                                      cross biases introduced on the
1339      *                                      gyroscope by the specific forces
1340      *                                      sensed by the accelerometer. Must
1341      *                                      be 3x3.
1342      * @param accelerometerBias             known accelerometer bias. This
1343      *                                      must have length 3 and is
1344      *                                      expressed in meters per squared
1345      *                                      second (m/s^2).
1346      * @param accelerometerMa               known accelerometer scale factors
1347      *                                      and cross coupling matrix. Must
1348      *                                      be 3x3.
1349      * @param listener                      listener to handle events raised
1350      *                                      by this calibrator.
1351      * @throws IllegalArgumentException if any of the provided values does
1352      *                                  not have proper size or if either
1353      *                                  turntable rotation rate or
1354      *                                  time interval is zero or negative.
1355      */
1356     public KnownBiasTurntableGyroscopeCalibrator(
1357             final ECEFPosition position, final double turntableRotationRate, final double timeInterval,
1358             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1359             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
1360             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa,
1361             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1362         this(position, turntableRotationRate, timeInterval, measurements, commonAxisUsed, estimateGDependentCrossBiases,
1363                 bias, initialMg, initialGg, accelerometerBias, accelerometerMa);
1364         this.listener = listener;
1365     }
1366 
1367     /**
1368      * Constructor.
1369      *
1370      * @param position              position where body kinematics measures
1371      *                              have been taken.
1372      * @param turntableRotationRate constant rotation rate at which the
1373      *                              turntable is spinning. Must be
1374      *                              expressed in radians per second (rad/s).
1375      * @param timeInterval          time interval between measurements being
1376      *                              captured expressed in seconds (s).
1377      * @param measurements          collection of body kinematics
1378      *                              measurements with standard deviations
1379      *                              taken at the same position with zero
1380      *                              velocity and unknown different
1381      *                              orientations.
1382      * @param bias                  known gyroscope bias. This must be 3x1
1383      *                              and is expressed in radians per second
1384      *                              (rad/s).
1385      * @param initialMg             initial gyroscope scale factors and
1386      *                              cross coupling errors matrix. Must
1387      *                              be 3x3.
1388      * @param initialGg             initial gyroscope G-dependent cross
1389      *                              biases introduced on the gyroscope by
1390      *                              the specific forces sensed by the
1391      *                              accelerometer. Must be 3x3.
1392      * @throws IllegalArgumentException if any of the provided values does
1393      *                                  not have proper size or if either
1394      *                                  turntable rotation rate or
1395      *                                  time interval is zero or negative.
1396      */
1397     public KnownBiasTurntableGyroscopeCalibrator(
1398             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1399             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
1400             final Matrix initialGg) {
1401         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
1402     }
1403 
1404     /**
1405      * Constructor.
1406      *
1407      * @param position              position where body kinematics measures
1408      *                              have been taken.
1409      * @param turntableRotationRate constant rotation rate at which the
1410      *                              turntable is spinning. Must be
1411      *                              expressed in radians per second (rad/s).
1412      * @param timeInterval          time interval between measurements being
1413      *                              captured expressed in seconds (s).
1414      * @param measurements          collection of body kinematics
1415      *                              measurements with standard deviations
1416      *                              taken at the same position with zero
1417      *                              velocity and unknown different
1418      *                              orientations.
1419      * @param bias                  known gyroscope bias. This must be 3x1
1420      *                              and is expressed in radians per second
1421      *                              (rad/s).
1422      * @param initialMg             initial gyroscope scale factors and
1423      *                              cross coupling errors matrix. Must
1424      *                              be 3x3.
1425      * @param initialGg             initial gyroscope G-dependent cross
1426      *                              biases introduced on the gyroscope by
1427      *                              the specific forces sensed by the
1428      *                              accelerometer. Must be 3x3.
1429      * @param listener              listener to handle events raised by this
1430      *                              calibrator.
1431      * @throws IllegalArgumentException if any of the provided values does
1432      *                                  not have proper size or if either
1433      *                                  turntable rotation rate or
1434      *                                  time interval is zero or negative.
1435      */
1436     public KnownBiasTurntableGyroscopeCalibrator(
1437             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1438             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
1439             final Matrix initialGg, final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1440         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg,
1441                 listener);
1442     }
1443 
1444     /**
1445      * Constructor.
1446      *
1447      * @param position              position where body kinematics measures
1448      *                              have been taken.
1449      * @param turntableRotationRate constant rotation rate at which the
1450      *                              turntable is spinning. Must be
1451      *                              expressed in radians per second (rad/s).
1452      * @param timeInterval          time interval between measurements being
1453      *                              captured expressed in seconds (s).
1454      * @param measurements          collection of body kinematics
1455      *                              measurements with standard deviations
1456      *                              taken at the same position with zero
1457      *                              velocity and unknown different
1458      *                              orientations.
1459      * @param bias                  known gyroscope bias. This must have
1460      *                              length 3 and is expressed in radians
1461      *                              per second (rad/s).
1462      * @param initialMg             initial gyroscope scale factors and
1463      *                              cross coupling errors matrix. Must
1464      *                              be 3x3.
1465      * @param initialGg             initial gyroscope G-dependent cross
1466      *                              biases introduced on the gyroscope by
1467      *                              the specific forces sensed by the
1468      *                              accelerometer. Must be 3x3.
1469      * @throws IllegalArgumentException if any of the provided values does
1470      *                                  not have proper size or if either
1471      *                                  turntable rotation rate or
1472      *                                  time interval is zero or negative.
1473      */
1474     public KnownBiasTurntableGyroscopeCalibrator(
1475             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1476             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias, final Matrix initialMg,
1477             final Matrix initialGg) {
1478         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg);
1479     }
1480 
1481     /**
1482      * Constructor.
1483      *
1484      * @param position              position where body kinematics measures
1485      *                              have been taken.
1486      * @param turntableRotationRate constant rotation rate at which the
1487      *                              turntable is spinning. Must be
1488      *                              expressed in radians per second (rad/s).
1489      * @param timeInterval          time interval between measurements being
1490      *                              captured expressed in seconds (s).
1491      * @param measurements          collection of body kinematics
1492      *                              measurements with standard deviations
1493      *                              taken at the same position with zero
1494      *                              velocity and unknown different
1495      *                              orientations.
1496      * @param bias                  known gyroscope bias. This must have
1497      *                              length 3 and is expressed in radians
1498      *                              per second (rad/s).
1499      * @param initialMg             initial gyroscope scale factors and
1500      *                              cross coupling errors matrix. Must
1501      *                              be 3x3.
1502      * @param initialGg             initial gyroscope G-dependent cross
1503      *                              biases introduced on the gyroscope by
1504      *                              the specific forces sensed by the
1505      *                              accelerometer. Must be 3x3.
1506      * @param listener              listener to handle events raised by
1507      *                              this calibrator.
1508      * @throws IllegalArgumentException if any of the provided values does
1509      *                                  not have proper size or if either
1510      *                                  turntable rotation rate or
1511      *                                  time interval is zero or negative.
1512      */
1513     public KnownBiasTurntableGyroscopeCalibrator(
1514             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1515             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias,
1516             final Matrix initialMg, final Matrix initialGg,
1517             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1518         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg,
1519                 listener);
1520     }
1521 
1522     /**
1523      * Constructor.
1524      *
1525      * @param position              position where body kinematics measures
1526      *                              have been taken.
1527      * @param turntableRotationRate constant rotation rate at which the
1528      *                              turntable is spinning. Must be
1529      *                              expressed in radians per second (rad/s).
1530      * @param timeInterval          time interval between measurements being
1531      *                              captured expressed in seconds (s).
1532      * @param measurements          collection of body kinematics
1533      *                              measurements with standard deviations
1534      *                              taken at the same position with zero
1535      *                              velocity and unknown different
1536      *                              orientations.
1537      * @param bias                  known gyroscope bias. This must have
1538      *                              length 3 and is expressed in radians per
1539      *                              second (rad/s).
1540      * @param initialMg             initial gyroscope scale factors and
1541      *                              cross coupling errors matrix. Must
1542      *                              be 3x3.
1543      * @param initialGg             initial gyroscope G-dependent cross
1544      *                              biases introduced on the gyroscope by
1545      *                              the specific forces sensed by the
1546      *                              accelerometer. Must be 3x3.
1547      * @param accelerometerBias     known accelerometer bias. This must
1548      *                              have length 3 and is expressed in
1549      *                              meters per squared second
1550      *                              (m/s^2).
1551      * @param accelerometerMa       known accelerometer scale factors and
1552      *                              cross coupling matrix. Must be 3x3.
1553      * @throws IllegalArgumentException if any of the provided values does
1554      *                                  not have proper size or if either
1555      *                                  turntable rotation rate or
1556      *                                  time interval is zero or negative.
1557      */
1558     public KnownBiasTurntableGyroscopeCalibrator(
1559             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1560             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias, final Matrix initialMg,
1561             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa) {
1562         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg,
1563                 accelerometerBias, accelerometerMa);
1564     }
1565 
1566     /**
1567      * Constructor.
1568      *
1569      * @param position              position where body kinematics measures
1570      *                              have been taken.
1571      * @param turntableRotationRate constant rotation rate at which the
1572      *                              turntable is spinning. Must be
1573      *                              expressed in radians per second (rad/s).
1574      * @param timeInterval          time interval between measurements being
1575      *                              captured expressed in seconds (s).
1576      * @param measurements          collection of body kinematics
1577      *                              measurements with standard deviations
1578      *                              taken at the same position with zero
1579      *                              velocity and unknown different
1580      *                              orientations.
1581      * @param bias                  known gyroscope bias. This must have
1582      *                              length 3 and is expressed in radians per
1583      *                              second (rad/s).
1584      * @param initialMg             initial gyroscope scale factors and
1585      *                              cross coupling errors matrix. Must
1586      *                              be 3x3.
1587      * @param initialGg             initial gyroscope G-dependent cross
1588      *                              biases introduced on the gyroscope by
1589      *                              the specific forces sensed by the
1590      *                              accelerometer. Must be 3x3.
1591      * @param accelerometerBias     known accelerometer bias. This must
1592      *                              have length 3 and is expressed in
1593      *                              meters per squared second (m/s^2).
1594      * @param accelerometerMa       known accelerometer scale factors and
1595      *                              cross coupling matrix. Must be 3x3.
1596      * @param listener              listener to handle events raised by
1597      *                              this calibrator.
1598      * @throws IllegalArgumentException if any of the provided values does
1599      *                                  not have proper size or if either
1600      *                                  turntable rotation rate or
1601      *                                  time interval is zero or negative.
1602      */
1603     public KnownBiasTurntableGyroscopeCalibrator(
1604             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1605             final Collection<StandardDeviationBodyKinematics> measurements, final double[] bias, final Matrix initialMg,
1606             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa,
1607             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1608         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg,
1609                 accelerometerBias, accelerometerMa, listener);
1610     }
1611 
1612     /**
1613      * Constructor.
1614      *
1615      * @param position              position where body kinematics measures
1616      *                              have been taken.
1617      * @param turntableRotationRate constant rotation rate at which the
1618      *                              turntable is spinning. Must be
1619      *                              expressed in radians per second (rad/s).
1620      * @param timeInterval          time interval between measurements being
1621      *                              captured expressed in seconds (s).
1622      * @param measurements          collection of body kinematics
1623      *                              measurements with standard deviations
1624      *                              taken at the same position with zero
1625      *                              velocity and unknown different
1626      *                              orientations.
1627      * @param bias                  known gyroscope bias. This must be 3x1
1628      *                              and is expressed in radians per second
1629      *                              (rad/s).
1630      * @param initialMg             initial gyroscope scale factors and
1631      *                              cross coupling errors matrix. Must
1632      *                              be 3x3.
1633      * @param initialGg             initial gyroscope G-dependent cross
1634      *                              biases introduced on the gyroscope by
1635      *                              the specific forces sensed by the
1636      *                              accelerometer. Must be 3x3.
1637      * @param accelerometerBias     known accelerometer bias. This must
1638      *                              have length 3 and is expressed in
1639      *                              meters per squared second
1640      *                              (m/s^2).
1641      * @param accelerometerMa       known accelerometer scale factors and
1642      *                              cross coupling matrix. Must be 3x3.
1643      * @throws IllegalArgumentException if any of the provided values does
1644      *                                  not have proper size or if either
1645      *                                  turntable rotation rate or
1646      *                                  time interval is zero or negative.
1647      */
1648     public KnownBiasTurntableGyroscopeCalibrator(
1649             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1650             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
1651             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa) {
1652         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg,
1653                 accelerometerBias, accelerometerMa);
1654     }
1655 
1656     /**
1657      * Constructor.
1658      *
1659      * @param position              position where body kinematics measures
1660      *                              have been taken.
1661      * @param turntableRotationRate constant rotation rate at which the
1662      *                              turntable is spinning. Must be
1663      *                              expressed in radians per second (rad/s).
1664      * @param timeInterval          time interval between measurements being
1665      *                              captured expressed in seconds (s).
1666      * @param measurements          collection of body kinematics
1667      *                              measurements with standard deviations
1668      *                              taken at the same position with zero
1669      *                              velocity and unknown different
1670      *                              orientations.
1671      * @param bias                  known gyroscope bias. This must be 3x1
1672      *                              and is expressed in radians per second
1673      *                              (rad/s).
1674      * @param initialMg             initial gyroscope scale factors and
1675      *                              cross coupling errors matrix. Must
1676      *                              be 3x3.
1677      * @param initialGg             initial gyroscope G-dependent cross
1678      *                              biases introduced on the gyroscope by
1679      *                              the specific forces sensed by the
1680      *                              accelerometer. Must be 3x3.
1681      * @param accelerometerBias     known accelerometer bias. This must
1682      *                              have length 3 and is expressed in
1683      *                              meters per squared second (m/s^2).
1684      * @param accelerometerMa       known accelerometer scale factors and
1685      *                              cross coupling matrix. Must be 3x3.
1686      * @param listener              listener to handle events raised by
1687      *                              this calibrator.
1688      * @throws IllegalArgumentException if any of the provided values does
1689      *                                  not have proper size or if either
1690      *                                  turntable rotation rate or
1691      *                                  time interval is zero or negative.
1692      */
1693     public KnownBiasTurntableGyroscopeCalibrator(
1694             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1695             final Collection<StandardDeviationBodyKinematics> measurements, final Matrix bias, final Matrix initialMg,
1696             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa,
1697             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1698         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, bias, initialMg, initialGg,
1699                 accelerometerBias, accelerometerMa, listener);
1700     }
1701 
1702     /**
1703      * Constructor.
1704      *
1705      * @param position                      position where body kinematics
1706      *                                      measures have been taken.
1707      * @param turntableRotationRate         constant rotation rate at which
1708      *                                      the turntable is spinning. Must
1709      *                                      be expressed in radians per
1710      *                                      second (rad/s).
1711      * @param timeInterval                  time interval between measurements
1712      *                                      being captured expressed in
1713      *                                      seconds (s).
1714      * @param measurements                  collection of body kinematics
1715      *                                      measurements with standard
1716      *                                      deviations taken at the same
1717      *                                      position with zero velocity
1718      *                                      and unknown different
1719      *                                      orientations.
1720      * @param commonAxisUsed                indicates whether z-axis is
1721      *                                      assumed to be common for
1722      *                                      accelerometer and gyroscope.
1723      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1724      *                                      will be estimated, false
1725      *                                      otherwise.
1726      * @param bias                          known gyroscope bias. This must
1727      *                                      be 3x1 and is expressed in
1728      *                                      radians per second (rad/s).
1729      * @param initialMg                     initial gyroscope scale factors
1730      *                                      and cross coupling errors matrix.
1731      *                                      Must be 3x3.
1732      * @param initialGg                     initial gyroscope G-dependent
1733      *                                      cross biases introduced on the
1734      *                                      gyroscope by the specific
1735      *                                      forces sensed by the
1736      *                                      accelerometer. Must be 3x3.
1737      * @throws IllegalArgumentException if any of the provided values does
1738      *                                  not have proper size or if either
1739      *                                  turntable rotation rate or
1740      *                                  time interval is zero or negative.
1741      */
1742     public KnownBiasTurntableGyroscopeCalibrator(
1743             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1744             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1745             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
1746             final Matrix initialGg) {
1747         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
1748                 estimateGDependentCrossBiases, bias, initialMg, initialGg);
1749     }
1750 
1751     /**
1752      * Constructor.
1753      *
1754      * @param position                      position where body kinematics
1755      *                                      measures have been taken.
1756      * @param turntableRotationRate         constant rotation rate at which
1757      *                                      the turntable is spinning. Must
1758      *                                      be expressed in radians per
1759      *                                      second (rad/s).
1760      * @param timeInterval                  time interval between measurements
1761      *                                      being captured expressed in
1762      *                                      seconds (s).
1763      * @param measurements                  collection of body kinematics
1764      *                                      measurements with standard
1765      *                                      deviations taken at the same
1766      *                                      position with zero velocity and
1767      *                                      unknown different orientations.
1768      * @param commonAxisUsed                indicates whether z-axis is
1769      *                                      assumed to be common for
1770      *                                      accelerometer and gyroscope.
1771      * @param estimateGDependentCrossBiases true if G-dependent cross
1772      *                                      biases will be estimated, false
1773      *                                      otherwise.
1774      * @param bias                          known gyroscope bias. This must
1775      *                                      be 3x1 and is expressed in
1776      *                                      radians per second (rad/s).
1777      * @param initialMg                     initial gyroscope scale factors
1778      *                                      and cross coupling errors
1779      *                                      matrix. Must be 3x3.
1780      * @param initialGg                     initial gyroscope G-dependent
1781      *                                      cross biases introduced on the
1782      *                                      gyroscope by the specific
1783      *                                      forces sensed by the
1784      *                                      accelerometer. Must be 3x3.
1785      * @param listener                      listener to handle events
1786      *                                      raised by this calibrator.
1787      * @throws IllegalArgumentException if any of the provided values does
1788      *                                  not have proper size or if either
1789      *                                  turntable rotation rate or
1790      *                                  time interval is zero or negative.
1791      */
1792     public KnownBiasTurntableGyroscopeCalibrator(
1793             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1794             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1795             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
1796             final Matrix initialGg, final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1797         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
1798                 estimateGDependentCrossBiases, bias, initialMg, initialGg, listener);
1799     }
1800 
1801     /**
1802      * Constructor.
1803      *
1804      * @param position                      position where body kinematics
1805      *                                      measures have been taken.
1806      * @param turntableRotationRate         constant rotation rate at which
1807      *                                      the turntable is spinning. Must
1808      *                                      be expressed in radians per
1809      *                                      second (rad/s).
1810      * @param timeInterval                  time interval between measurements
1811      *                                      being captured expressed in
1812      *                                      seconds (s).
1813      * @param measurements                  collection of body kinematics
1814      *                                      measurements with standard
1815      *                                      deviations taken at the same
1816      *                                      position with zero velocity
1817      *                                      and unknown different
1818      *                                      orientations.
1819      * @param commonAxisUsed                indicates whether z-axis is
1820      *                                      assumed to be common for
1821      *                                      accelerometer and gyroscope.
1822      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1823      *                                      will be estimated, false
1824      *                                      otherwise.
1825      * @param bias                          known gyroscope bias. This must
1826      *                                      have length 3 and is expressed
1827      *                                      in radians per second (rad/s).
1828      * @param initialMg                     initial gyroscope scale factors
1829      *                                      and cross coupling errors matrix.
1830      *                                      Must be 3x3.
1831      * @param initialGg                     initial gyroscope G-dependent
1832      *                                      cross biases introduced on the
1833      *                                      gyroscope by the specific forces
1834      *                                      sensed by the accelerometer.
1835      *                                      Must be 3x3.
1836      * @throws IllegalArgumentException if any of the provided values does
1837      *                                  not have proper size or if either
1838      *                                  turntable rotation rate or
1839      *                                  time interval is zero or negative.
1840      */
1841     public KnownBiasTurntableGyroscopeCalibrator(
1842             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1843             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1844             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
1845             final Matrix initialGg) {
1846         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
1847                 estimateGDependentCrossBiases, bias, initialMg, initialGg);
1848     }
1849 
1850     /**
1851      * Constructor.
1852      *
1853      * @param position                      position where body kinematics
1854      *                                      measures have been taken.
1855      * @param turntableRotationRate         constant rotation rate at which
1856      *                                      the turntable is spinning. Must
1857      *                                      be expressed in radians per
1858      *                                      second (rad/s).
1859      * @param timeInterval                  time interval between measurements
1860      *                                      being captured expressed in
1861      *                                      seconds (s).
1862      * @param measurements                  collection of body kinematics
1863      *                                      measurements with standard
1864      *                                      deviations taken at the same
1865      *                                      position with zero velocity
1866      *                                      and unknown different
1867      *                                      orientations.
1868      * @param commonAxisUsed                indicates whether z-axis is
1869      *                                      assumed to be common for
1870      *                                      accelerometer and gyroscope.
1871      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1872      *                                      will be estimated, false
1873      *                                      otherwise.
1874      * @param bias                          known gyroscope bias. This must
1875      *                                      have length 3 and is expressed
1876      *                                      in radians per second (rad/s).
1877      * @param initialMg                     initial gyroscope scale factors
1878      *                                      and cross coupling errors
1879      *                                      matrix. Must be 3x3.
1880      * @param initialGg                     initial gyroscope G-dependent
1881      *                                      cross biases introduced on the
1882      *                                      gyroscope by the specific forces
1883      *                                      sensed by the accelerometer.
1884      *                                      Must be 3x3.
1885      * @param listener                      listener to handle events raised
1886      *                                      by this calibrator.
1887      * @throws IllegalArgumentException if any of the provided values does
1888      *                                  not have proper size or if either
1889      *                                  turntable rotation rate or
1890      *                                  time interval is zero or negative.
1891      */
1892     public KnownBiasTurntableGyroscopeCalibrator(
1893             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1894             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1895             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
1896             final Matrix initialGg, final KnownBiasTurntableGyroscopeCalibratorListener listener) {
1897         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
1898                 estimateGDependentCrossBiases, bias, initialMg, initialGg, listener);
1899     }
1900 
1901     /**
1902      * Constructor.
1903      *
1904      * @param position                      position where body kinematics
1905      *                                      measures have been taken.
1906      * @param turntableRotationRate         constant rotation rate at which
1907      *                                      the turntable is spinning. Must
1908      *                                      be expressed in radians per
1909      *                                      second (rad/s).
1910      * @param timeInterval                  time interval between measurements
1911      *                                      being captured expressed in
1912      *                                      seconds (s).
1913      * @param measurements                  collection of body kinematics
1914      *                                      measurements with standard
1915      *                                      deviations taken at the same
1916      *                                      position with zero velocity
1917      *                                      and unknown different
1918      *                                      orientations.
1919      * @param commonAxisUsed                indicates whether z-axis is
1920      *                                      assumed to be common for
1921      *                                      accelerometer and gyroscope.
1922      * @param estimateGDependentCrossBiases true if G-dependent cross
1923      *                                      biases will be estimated,
1924      *                                      false otherwise.
1925      * @param bias                          known gyroscope bias. This must
1926      *                                      have length 3 and is expressed
1927      *                                      in radians per second (rad/s).
1928      * @param initialMg                     initial gyroscope scale factors
1929      *                                      and cross coupling errors
1930      *                                      matrix. Must be 3x3.
1931      * @param initialGg                     initial gyroscope G-dependent
1932      *                                      cross biases introduced on the
1933      *                                      gyroscope by the specific forces
1934      *                                      sensed by the accelerometer.
1935      *                                      Must be 3x3.
1936      * @param accelerometerBias             known accelerometer bias. This
1937      *                                      must have length 3 and is
1938      *                                      expressed in meters per squared
1939      *                                      second (m/s^2).
1940      * @param accelerometerMa               known accelerometer scale factors
1941      *                                      and cross coupling matrix. Must
1942      *                                      be 3x3.
1943      * @throws IllegalArgumentException if any of the provided values does
1944      *                                  not have proper size or if either
1945      *                                  turntable rotation rate or
1946      *                                  time interval is zero or negative.
1947      */
1948     public KnownBiasTurntableGyroscopeCalibrator(
1949             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
1950             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
1951             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
1952             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa) {
1953         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
1954                 estimateGDependentCrossBiases, bias, initialMg, initialGg, accelerometerBias, accelerometerMa);
1955     }
1956 
1957     /**
1958      * Constructor.
1959      *
1960      * @param position                      position where body kinematics
1961      *                                      measures have been taken.
1962      * @param turntableRotationRate         constant rotation rate at which
1963      *                                      the turntable is spinning. Must
1964      *                                      be expressed in radians per
1965      *                                      second (rad/s).
1966      * @param timeInterval                  time interval between measurements
1967      *                                      being captured expressed in
1968      *                                      seconds (s).
1969      * @param measurements                  collection of body kinematics
1970      *                                      measurements with standard
1971      *                                      deviations taken at the same
1972      *                                      position with zero velocity
1973      *                                      and unknown different
1974      *                                      orientations.
1975      * @param commonAxisUsed                indicates whether z-axis is
1976      *                                      assumed to be common for
1977      *                                      accelerometer and gyroscope.
1978      * @param estimateGDependentCrossBiases true if G-dependent cross biases
1979      *                                      will be estimated, false
1980      *                                      otherwise.
1981      * @param bias                          known gyroscope bias. This must
1982      *                                      have length 3 and is expressed
1983      *                                      in radians per second (rad/s).
1984      * @param initialMg                     initial gyroscope scale factors
1985      *                                      and cross coupling errors matrix.
1986      *                                      Must be 3x3.
1987      * @param initialGg                     initial gyroscope G-dependent
1988      *                                      cross biases introduced on the
1989      *                                      gyroscope by the specific forces
1990      *                                      sensed by the accelerometer. Must
1991      *                                      be 3x3.
1992      * @param accelerometerBias             known accelerometer bias. This
1993      *                                      must have length 3 and is
1994      *                                      expressed in meters per squared
1995      *                                      second (m/s^2).
1996      * @param accelerometerMa               known accelerometer scale factors
1997      *                                      and cross coupling matrix. Must
1998      *                                      be 3x3.
1999      * @param listener                      listener to handle events raised
2000      *                                      by this calibrator.
2001      * @throws IllegalArgumentException if any of the provided values does
2002      *                                  not have proper size or if either
2003      *                                  turntable rotation rate or
2004      *                                  time interval is zero or negative.
2005      */
2006     public KnownBiasTurntableGyroscopeCalibrator(
2007             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
2008             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
2009             final boolean estimateGDependentCrossBiases, final double[] bias, final Matrix initialMg,
2010             final Matrix initialGg, final double[] accelerometerBias, final Matrix accelerometerMa,
2011             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
2012         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
2013                 estimateGDependentCrossBiases, bias, initialMg, initialGg, accelerometerBias, accelerometerMa,
2014                 listener);
2015     }
2016 
2017     /**
2018      * Constructor.
2019      *
2020      * @param position                      position where body kinematics
2021      *                                      measures have been taken.
2022      * @param turntableRotationRate         constant rotation rate at which
2023      *                                      the turntable is spinning. Must
2024      *                                      be expressed in radians per
2025      *                                      second (rad/s).
2026      * @param timeInterval                  time interval between measurements
2027      *                                      being captured expressed in
2028      *                                      seconds (s).
2029      * @param measurements                  collection of body kinematics
2030      *                                      measurements with standard
2031      *                                      deviations taken at the same
2032      *                                      position with zero velocity and
2033      *                                      unknown different orientations.
2034      * @param commonAxisUsed                indicates whether z-axis is
2035      *                                      assumed to be common for
2036      *                                      accelerometer and gyroscope.
2037      * @param estimateGDependentCrossBiases true if G-dependent cross biases
2038      *                                      will be estimated, false
2039      *                                      otherwise.
2040      * @param bias                          known gyroscope bias. This must
2041      *                                      be 3x1 and is expressed in
2042      *                                      radians per second (rad/s).
2043      * @param initialMg                     initial gyroscope scale factors
2044      *                                      and cross coupling errors matrix.
2045      *                                      Must be 3x3.
2046      * @param initialGg                     initial gyroscope G-dependent
2047      *                                      cross biases introduced on the
2048      *                                      gyroscope by the specific forces
2049      *                                      sensed by the accelerometer. Must
2050      *                                      be 3x3.
2051      * @param accelerometerBias             known accelerometer bias. This
2052      *                                      must have length 3 and is
2053      *                                      expressed in meters per squared
2054      *                                      second (m/s^2).
2055      * @param accelerometerMa               known accelerometer scale factors
2056      *                                      and cross coupling matrix. Must
2057      *                                      be 3x3.
2058      * @throws IllegalArgumentException if any of the provided values does
2059      *                                  not have proper size or if either
2060      *                                  turntable rotation rate or
2061      *                                  time interval is zero or negative.
2062      */
2063     public KnownBiasTurntableGyroscopeCalibrator(
2064             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
2065             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
2066             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
2067             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa) {
2068         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
2069                 estimateGDependentCrossBiases, bias, initialMg, initialGg, accelerometerBias, accelerometerMa);
2070     }
2071 
2072     /**
2073      * Constructor.
2074      *
2075      * @param position                      position where body kinematics
2076      *                                      measures have been taken.
2077      * @param turntableRotationRate         constant rotation rate at which
2078      *                                      the turntable is spinning. Must
2079      *                                      be expressed in radians per
2080      *                                      second (rad/s).
2081      * @param timeInterval                  time interval between measurements
2082      *                                      being captured expressed in
2083      *                                      seconds (s).
2084      * @param measurements                  collection of body kinematics
2085      *                                      measurements with standard
2086      *                                      deviations taken at the same
2087      *                                      position with zero velocity and
2088      *                                      unknown different orientations.
2089      * @param commonAxisUsed                indicates whether z-axis is
2090      *                                      assumed to be common for
2091      *                                      accelerometer and gyroscope.
2092      * @param estimateGDependentCrossBiases true if G-dependent cross biases
2093      *                                      will be estimated, false
2094      *                                      otherwise.
2095      * @param bias                          known gyroscope bias. This must
2096      *                                      be 3x1 and is expressed in
2097      *                                      radians per second (rad/s).
2098      * @param initialMg                     initial gyroscope scale factors
2099      *                                      and cross coupling errors matrix.
2100      *                                      Must be 3x3.
2101      * @param initialGg                     initial gyroscope G-dependent
2102      *                                      cross biases introduced on the
2103      *                                      gyroscope by the specific forces
2104      *                                      sensed by the accelerometer. Must
2105      *                                      be 3x3.
2106      * @param accelerometerBias             known accelerometer bias. This
2107      *                                      must have length 3 and is
2108      *                                      expressed in meters per squared
2109      *                                      second (m/s^2).
2110      * @param accelerometerMa               known accelerometer scale factors
2111      *                                      and cross coupling matrix. Must
2112      *                                      be 3x3.
2113      * @param listener                      listener to handle events raised
2114      *                                      by this calibrator.
2115      * @throws IllegalArgumentException if any of the provided values does
2116      *                                  not have proper size or if either
2117      *                                  turntable rotation rate or
2118      *                                  time interval is zero or negative.
2119      */
2120     public KnownBiasTurntableGyroscopeCalibrator(
2121             final NEDPosition position, final double turntableRotationRate, final double timeInterval,
2122             final Collection<StandardDeviationBodyKinematics> measurements, final boolean commonAxisUsed,
2123             final boolean estimateGDependentCrossBiases, final Matrix bias, final Matrix initialMg,
2124             final Matrix initialGg, final Matrix accelerometerBias, final Matrix accelerometerMa,
2125             final KnownBiasTurntableGyroscopeCalibratorListener listener) {
2126         this(convertPosition(position), turntableRotationRate, timeInterval, measurements, commonAxisUsed,
2127                 estimateGDependentCrossBiases, bias, initialMg, initialGg, accelerometerBias, accelerometerMa,
2128                 listener);
2129     }
2130 
2131     /**
2132      * Gets known x-coordinate of accelerometer bias to be used to fix
2133      * measured specific force and find cross biases introduced by the
2134      * accelerometer.
2135      * This is expressed in meters per squared second (m/s^2).
2136      *
2137      * @return known x-coordinate of accelerometer bias.
2138      */
2139     @Override
2140     public double getAccelerometerBiasX() {
2141         return accelerometerBiasX;
2142     }
2143 
2144     /**
2145      * Sets known x-coordinate of accelerometer bias to be used to fix
2146      * measured specific force and find cross biases introduced by the
2147      * accelerometer.
2148      * This is expressed in meters per squared second (m/s^2).
2149      *
2150      * @param accelerometerBiasX known x-coordinate of accelerometer bias.
2151      * @throws LockedException if calibrator is currently running.
2152      */
2153     @Override
2154     public void setAccelerometerBiasX(final double accelerometerBiasX) throws LockedException {
2155         if (running) {
2156             throw new LockedException();
2157         }
2158         this.accelerometerBiasX = accelerometerBiasX;
2159     }
2160 
2161     /**
2162      * Gets known y-coordinate of accelerometer bias to be used to fix
2163      * measured specific force and find cross biases introduced by the
2164      * accelerometer.
2165      * This is expressed in meters per squared second (m/s^2).
2166      *
2167      * @return known y-coordinate of accelerometer bias.
2168      */
2169     @Override
2170     public double getAccelerometerBiasY() {
2171         return accelerometerBiasY;
2172     }
2173 
2174     /**
2175      * Sets known y-coordinate of accelerometer bias to be used to fix
2176      * measured specific force and find cross biases introduced by the
2177      * accelerometer.
2178      * This is expressed in meters per squared second (m/s^2).
2179      *
2180      * @param accelerometerBiasY known y-coordinate of accelerometer bias.
2181      * @throws LockedException if calibrator is currently running.
2182      */
2183     @Override
2184     public void setAccelerometerBiasY(final double accelerometerBiasY) throws LockedException {
2185         if (running) {
2186             throw new LockedException();
2187         }
2188         this.accelerometerBiasY = accelerometerBiasY;
2189     }
2190 
2191     /**
2192      * Gets known z-coordinate of accelerometer bias to be used to fix
2193      * measured specific force and find cross biases introduced by the
2194      * accelerometer.
2195      * This is expressed in meters per squared second (m/s^2).
2196      *
2197      * @return known z-coordinate of accelerometer bias.
2198      */
2199     @Override
2200     public double getAccelerometerBiasZ() {
2201         return accelerometerBiasZ;
2202     }
2203 
2204     /**
2205      * Sets known z-coordinate of accelerometer bias to be used to fix
2206      * measured specific force and find cross biases introduced by the
2207      * accelerometer.
2208      * This is expressed in meters per squared second (m/s^2).
2209      *
2210      * @param accelerometerBiasZ known z-coordinate of accelerometer bias.
2211      * @throws LockedException if calibrator is currently running.
2212      */
2213     @Override
2214     public void setAccelerometerBiasZ(final double accelerometerBiasZ) throws LockedException {
2215         if (running) {
2216             throw new LockedException();
2217         }
2218         this.accelerometerBiasZ = accelerometerBiasZ;
2219     }
2220 
2221     /**
2222      * Gets known x-coordinate of accelerometer bias to be used to fix
2223      * measured specific force and find cross biases introduced by the
2224      * accelerometer.
2225      *
2226      * @return known x-coordinate of accelerometer bias.
2227      */
2228     @Override
2229     public Acceleration getAccelerometerBiasXAsAcceleration() {
2230         return new Acceleration(accelerometerBiasX, AccelerationUnit.METERS_PER_SQUARED_SECOND);
2231     }
2232 
2233     /**
2234      * Gets known x-coordinate of accelerometer bias to be used to fix
2235      * measured specific force and find cross biases introduced by the
2236      * accelerometer.
2237      *
2238      * @param result instance where result data will be stored.
2239      */
2240     @Override
2241     public void getAccelerometerBiasXAsAcceleration(final Acceleration result) {
2242         result.setValue(accelerometerBiasX);
2243         result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
2244     }
2245 
2246     /**
2247      * Sets known x-coordinate of accelerometer bias to be used to fix
2248      * measured specific force and find cross biases introduced by the
2249      * accelerometer.
2250      *
2251      * @param accelerometerBiasX x-coordinate of accelerometer bias.
2252      * @throws LockedException if calibrator is currently running.
2253      */
2254     @Override
2255     public void setAccelerometerBiasX(final Acceleration accelerometerBiasX) throws LockedException {
2256         if (running) {
2257             throw new LockedException();
2258         }
2259         this.accelerometerBiasX = convertAcceleration(accelerometerBiasX);
2260     }
2261 
2262     /**
2263      * Gets known y-coordinate of accelerometer bias to be used to fix
2264      * measured specific force and find cross biases introduced by the
2265      * accelerometer.
2266      *
2267      * @return known y-coordinate of accelerometer bias.
2268      */
2269     @Override
2270     public Acceleration getAccelerometerBiasYAsAcceleration() {
2271         return new Acceleration(accelerometerBiasY, AccelerationUnit.METERS_PER_SQUARED_SECOND);
2272     }
2273 
2274     /**
2275      * Gets known y-coordinate of accelerometer bias to be used to fix
2276      * measured specific force and find cross biases introduced by the
2277      * accelerometer.
2278      *
2279      * @param result instance where result data will be stored.
2280      */
2281     @Override
2282     public void getAccelerometerBiasYAsAcceleration(final Acceleration result) {
2283         result.setValue(accelerometerBiasY);
2284         result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
2285     }
2286 
2287     /**
2288      * Sets known y-coordinate of accelerometer bias to be used to fix
2289      * measured specific force and find cross biases introduced by the
2290      * accelerometer.
2291      *
2292      * @param accelerometerBiasY y-coordinate of accelerometer bias.
2293      * @throws LockedException if calibrator is currently running.
2294      */
2295     @Override
2296     public void setAccelerometerBiasY(final Acceleration accelerometerBiasY) throws LockedException {
2297         if (running) {
2298             throw new LockedException();
2299         }
2300         this.accelerometerBiasY = convertAcceleration(accelerometerBiasY);
2301     }
2302 
2303     /**
2304      * Gets known z-coordinate of accelerometer bias to be used to fix
2305      * measured specific force and find cross biases introduced by the
2306      * accelerometer.
2307      *
2308      * @return known z-coordinate of accelerometer bias.
2309      */
2310     @Override
2311     public Acceleration getAccelerometerBiasZAsAcceleration() {
2312         return new Acceleration(accelerometerBiasZ, AccelerationUnit.METERS_PER_SQUARED_SECOND);
2313     }
2314 
2315     /**
2316      * Gets known z-coordinate of accelerometer bias to be used to fix
2317      * measured specific force and find cross biases introduced by the
2318      * accelerometer.
2319      *
2320      * @param result instance where result data will be stored.
2321      */
2322     @Override
2323     public void getAccelerometerBiasZAsAcceleration(final Acceleration result) {
2324         result.setValue(accelerometerBiasZ);
2325         result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
2326     }
2327 
2328     /**
2329      * Sets known z-coordinate of accelerometer bias to be used to fix
2330      * measured specific force and find cross biases introduced by the
2331      * accelerometer.
2332      *
2333      * @param accelerometerBiasZ z-coordinate of accelerometer bias.
2334      * @throws LockedException if calibrator is currently running.
2335      */
2336     @Override
2337     public void setAccelerometerBiasZ(final Acceleration accelerometerBiasZ) throws LockedException {
2338         if (running) {
2339             throw new LockedException();
2340         }
2341         this.accelerometerBiasZ = convertAcceleration(accelerometerBiasZ);
2342     }
2343 
2344     /**
2345      * Sets known accelerometer bias to be used to fix measured specific
2346      * force and find cross biases introduced by the accelerometer.
2347      * This is expressed in meters per squared second (m/s^2).
2348      *
2349      * @param accelerometerBiasX x-coordinate of accelerometer bias.
2350      * @param accelerometerBiasY y-coordinate of accelerometer bias.
2351      * @param accelerometerBiasZ z-coordinate of accelerometer bias.
2352      * @throws LockedException if calibrator is currently running.
2353      */
2354     @Override
2355     public void setAccelerometerBias(
2356             final double accelerometerBiasX, final double accelerometerBiasY, final double accelerometerBiasZ)
2357             throws LockedException {
2358         if (running) {
2359             throw new LockedException();
2360         }
2361 
2362         this.accelerometerBiasX = accelerometerBiasX;
2363         this.accelerometerBiasY = accelerometerBiasY;
2364         this.accelerometerBiasZ = accelerometerBiasZ;
2365     }
2366 
2367     /**
2368      * Sets known accelerometer bias to be used to fix measured specific
2369      * force and find cross biases introduced by the accelerometer.
2370      *
2371      * @param accelerometerBiasX x-coordinate of accelerometer bias.
2372      * @param accelerometerBiasY y-coordinate of accelerometer bias.
2373      * @param accelerometerBiasZ z-coordinate of accelerometer bias.
2374      * @throws LockedException if calibrator is currently running.
2375      */
2376     @Override
2377     public void setAccelerometerBias(
2378             final Acceleration accelerometerBiasX, final Acceleration accelerometerBiasY,
2379             final Acceleration accelerometerBiasZ) throws LockedException {
2380         if (running) {
2381             throw new LockedException();
2382         }
2383 
2384         this.accelerometerBiasX = convertAcceleration(accelerometerBiasX);
2385         this.accelerometerBiasY = convertAcceleration(accelerometerBiasY);
2386         this.accelerometerBiasZ = convertAcceleration(accelerometerBiasZ);
2387     }
2388 
2389     /**
2390      * Gets known accelerometer bias to be used to fix measured specific
2391      * force and find cross biases introduced by the accelerometer.
2392      * This is expressed in meters per squared second (m/s^2).
2393      *
2394      * @return known accelerometer bias.
2395      */
2396     @Override
2397     public double[] getAccelerometerBias() {
2398         final var result = new double[BodyKinematics.COMPONENTS];
2399         getAccelerometerBias(result);
2400         return result;
2401     }
2402 
2403     /**
2404      * Gets known accelerometer bias to be used to fix measured specific
2405      * force and find cross biases introduced by the accelerometer.
2406      * This is expressed in meters per squared second (m/s^2).
2407      *
2408      * @param result instance where result data will be copied to.
2409      * @throws IllegalArgumentException if provided array does not have
2410      *                                  length 3.
2411      */
2412     @Override
2413     public void getAccelerometerBias(final double[] result) {
2414         if (result.length != BodyKinematics.COMPONENTS) {
2415             throw new IllegalArgumentException();
2416         }
2417 
2418         result[0] = accelerometerBiasX;
2419         result[1] = accelerometerBiasY;
2420         result[2] = accelerometerBiasZ;
2421     }
2422 
2423     /**
2424      * Sets known accelerometer bias to be used to fix measured specific
2425      * force and find cross biases introduced by the accelerometer.
2426      * This is expressed in meters per squared second (m/s^2).
2427      *
2428      * @param accelerometerBias known accelerometer bias.
2429      * @throws LockedException          if calibrator is currently running.
2430      * @throws IllegalArgumentException if provided array does not have
2431      *                                  length 3.
2432      */
2433     @Override
2434     public void setAccelerometerBias(final double[] accelerometerBias) throws LockedException {
2435         if (running) {
2436             throw new LockedException();
2437         }
2438 
2439         if (accelerometerBias.length != BodyKinematics.COMPONENTS) {
2440             throw new IllegalArgumentException();
2441         }
2442 
2443         accelerometerBiasX = accelerometerBias[0];
2444         accelerometerBiasY = accelerometerBias[1];
2445         accelerometerBiasZ = accelerometerBias[2];
2446     }
2447 
2448     /**
2449      * Gets known accelerometer bias to be used to fix measured specific
2450      * force and find cross biases introduced by the accelerometer.
2451      * This is expressed in meters per squared second (m/s^2).
2452      *
2453      * @return known accelerometer bias.
2454      */
2455     @Override
2456     public Matrix getAccelerometerBiasAsMatrix() {
2457         Matrix result;
2458         try {
2459             result = new Matrix(BodyKinematics.COMPONENTS, 1);
2460             getAccelerometerBiasAsMatrix(result);
2461         } catch (final WrongSizeException ignore) {
2462             // never happens
2463             result = null;
2464         }
2465         return result;
2466     }
2467 
2468     /**
2469      * Gets known accelerometer bias to be used to fix measured specific
2470      * force and find cross biases introduced by the accelerometer.
2471      * This is expressed in meters per squared second (m/s^2).
2472      *
2473      * @param result instance where result data will be copied to.
2474      * @throws IllegalArgumentException if provided matrix is not 3x1.
2475      */
2476     @Override
2477     public void getAccelerometerBiasAsMatrix(final Matrix result) {
2478         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != 1) {
2479             throw new IllegalArgumentException();
2480         }
2481         result.setElementAtIndex(0, accelerometerBiasX);
2482         result.setElementAtIndex(1, accelerometerBiasY);
2483         result.setElementAtIndex(2, accelerometerBiasZ);
2484     }
2485 
2486     /**
2487      * Sets known accelerometer bias to be used to fix measured specific
2488      * force and find cross biases introduced by the accelerometer.
2489      * This is expressed in meters per squared second (m/s^2).
2490      *
2491      * @param accelerometerBias known accelerometer bias. Must be 3x1.
2492      * @throws LockedException          if calibrator is currently running.
2493      * @throws IllegalArgumentException if provided matrix is not 3x1.
2494      */
2495     @Override
2496     public void setAccelerometerBias(final Matrix accelerometerBias) throws LockedException {
2497         if (running) {
2498             throw new LockedException();
2499         }
2500         if (accelerometerBias.getRows() != BodyKinematics.COMPONENTS || accelerometerBias.getColumns() != 1) {
2501             throw new IllegalArgumentException();
2502         }
2503 
2504         accelerometerBiasX = accelerometerBias.getElementAtIndex(0);
2505         accelerometerBiasY = accelerometerBias.getElementAtIndex(1);
2506         accelerometerBiasZ = accelerometerBias.getElementAtIndex(2);
2507     }
2508 
2509     /**
2510      * Gets known accelerometer x scaling factor to be used to fix measured
2511      * specific force and find cross biases introduced by the accelerometer.
2512      *
2513      * @return known accelerometer x scaling factor.
2514      */
2515     @Override
2516     public double getAccelerometerSx() {
2517         return accelerometerSx;
2518     }
2519 
2520     /**
2521      * Sets known accelerometer x scaling factor to be used to fix measured
2522      * specific force and find cross biases introduced by the accelerometer.
2523      *
2524      * @param accelerometerSx known accelerometer x scaling factor.
2525      * @throws LockedException if calibrator is currently running.
2526      */
2527     @Override
2528     public void setAccelerometerSx(final double accelerometerSx) throws LockedException {
2529         if (running) {
2530             throw new LockedException();
2531         }
2532         this.accelerometerSx = accelerometerSx;
2533     }
2534 
2535     /**
2536      * Gets known accelerometer y scaling factor to be used to fix measured
2537      * specific force and find cross biases introduced by the accelerometer.
2538      *
2539      * @return known accelerometer y scaling factor.
2540      */
2541     @Override
2542     public double getAccelerometerSy() {
2543         return accelerometerSy;
2544     }
2545 
2546     /**
2547      * Sets known accelerometer y scaling factor to be used to fix measured
2548      * specific force and find cross biases introduced by the accelerometer.
2549      *
2550      * @param accelerometerSy known accelerometer y scaling factor.
2551      * @throws LockedException if calibrator is currently running.
2552      */
2553     @Override
2554     public void setAccelerometerSy(final double accelerometerSy) throws LockedException {
2555         if (running) {
2556             throw new LockedException();
2557         }
2558         this.accelerometerSy = accelerometerSy;
2559     }
2560 
2561     /**
2562      * Gets known accelerometer z scaling factor to be used to fix measured
2563      * specific force and find cross biases introduced by the accelerometer.
2564      *
2565      * @return known accelerometer z scaling factor.
2566      */
2567     @Override
2568     public double getAccelerometerSz() {
2569         return accelerometerSz;
2570     }
2571 
2572     /**
2573      * Sets known accelerometer z scaling factor to be used to fix measured
2574      * specific force and find cross biases introduced by the accelerometer.
2575      *
2576      * @param accelerometerSz known accelerometer z scaling factor.
2577      * @throws LockedException if calibrator is currently running.
2578      */
2579     @Override
2580     public void setAccelerometerSz(final double accelerometerSz) throws LockedException {
2581         if (running) {
2582             throw new LockedException();
2583         }
2584         this.accelerometerSz = accelerometerSz;
2585     }
2586 
2587     /**
2588      * Gets known accelerometer x-y cross coupling error to be used to fix
2589      * measured specific force and find cross biases introduced by the
2590      * accelerometer.
2591      *
2592      * @return known accelerometer x-y cross coupling error.
2593      */
2594     @Override
2595     public double getAccelerometerMxy() {
2596         return accelerometerMxy;
2597     }
2598 
2599     /**
2600      * Sets known accelerometer x-y cross coupling error to be used to fix
2601      * measured specific force and find cross biases introduced by the
2602      * accelerometer.
2603      *
2604      * @param accelerometerMxy known accelerometer x-y cross coupling error.
2605      * @throws LockedException if calibrator is currently running.
2606      */
2607     @Override
2608     public void setAccelerometerMxy(final double accelerometerMxy) throws LockedException {
2609         if (running) {
2610             throw new LockedException();
2611         }
2612         this.accelerometerMxy = accelerometerMxy;
2613     }
2614 
2615     /**
2616      * Gets known accelerometer x-z cross coupling error to be used to fix
2617      * measured specific force and find cross biases introduced by the
2618      * accelerometer.
2619      *
2620      * @return known accelerometer x-z cross coupling error.
2621      */
2622     @Override
2623     public double getAccelerometerMxz() {
2624         return accelerometerMxz;
2625     }
2626 
2627     /**
2628      * Sets known accelerometer x-z cross coupling error to be used to fix
2629      * measured specific force and find cross biases introduced by the
2630      * accelerometer.
2631      *
2632      * @param accelerometerMxz known accelerometer x-z cross coupling error.
2633      * @throws LockedException if calibrator is currently running.
2634      */
2635     @Override
2636     public void setAccelerometerMxz(final double accelerometerMxz) throws LockedException {
2637         if (running) {
2638             throw new LockedException();
2639         }
2640         this.accelerometerMxz = accelerometerMxz;
2641     }
2642 
2643     /**
2644      * Gets known accelerometer y-x cross coupling error to be used to fix
2645      * measured specific force and find cross biases introduced by the
2646      * accelerometer.
2647      *
2648      * @return known accelerometer y-x cross coupling error.
2649      */
2650     @Override
2651     public double getAccelerometerMyx() {
2652         return accelerometerMyx;
2653     }
2654 
2655     /**
2656      * Sets known accelerometer y-x cross coupling error to be used to fix
2657      * measured specific force and find cross biases introduced by the
2658      * accelerometer.
2659      *
2660      * @param accelerometerMyx known accelerometer y-x cross coupling
2661      *                         error.
2662      * @throws LockedException if calibrator is currently running.
2663      */
2664     @Override
2665     public void setAccelerometerMyx(final double accelerometerMyx) throws LockedException {
2666         if (running) {
2667             throw new LockedException();
2668         }
2669         this.accelerometerMyx = accelerometerMyx;
2670     }
2671 
2672     /**
2673      * Gets known accelerometer y-z cross coupling error to be used to fix
2674      * measured specific force and find cross biases introduced by the
2675      * accelerometer.
2676      *
2677      * @return known accelerometer y-z cross coupling error.
2678      */
2679     @Override
2680     public double getAccelerometerMyz() {
2681         return accelerometerMyz;
2682     }
2683 
2684     /**
2685      * Sets known accelerometer y-z cross coupling error to be used to fix
2686      * measured specific force and find cross biases introduced by the
2687      * accelerometer.
2688      *
2689      * @param accelerometerMyz known accelerometer y-z cross coupling
2690      *                         error.
2691      * @throws LockedException if calibrator is currently running.
2692      */
2693     @Override
2694     public void setAccelerometerMyz(final double accelerometerMyz) throws LockedException {
2695         if (running) {
2696             throw new LockedException();
2697         }
2698         this.accelerometerMyz = accelerometerMyz;
2699     }
2700 
2701     /**
2702      * Gets known accelerometer z-x cross coupling error to be used to fix
2703      * measured specific force and find cross biases introduced by the
2704      * accelerometer.
2705      *
2706      * @return known accelerometer z-x cross coupling error.
2707      */
2708     @Override
2709     public double getAccelerometerMzx() {
2710         return accelerometerMzx;
2711     }
2712 
2713     /**
2714      * Sets known accelerometer z-x cross coupling error to be used to fix
2715      * measured specific force and find cross biases introduced by the
2716      * accelerometer.
2717      *
2718      * @param accelerometerMzx known accelerometer z-x cross coupling
2719      *                         error.
2720      * @throws LockedException if calibrator is currently running.
2721      */
2722     @Override
2723     public void setAccelerometerMzx(final double accelerometerMzx) throws LockedException {
2724         if (running) {
2725             throw new LockedException();
2726         }
2727         this.accelerometerMzx = accelerometerMzx;
2728     }
2729 
2730     /**
2731      * Gets known accelerometer z-y cross coupling error to be used to fix
2732      * measured specific force and find cross biases introduced by the
2733      * accelerometer.
2734      *
2735      * @return known accelerometer z-y cross coupling error.
2736      */
2737     @Override
2738     public double getAccelerometerMzy() {
2739         return accelerometerMzy;
2740     }
2741 
2742     /**
2743      * Sets known accelerometer z-y cross coupling error to be used to fix
2744      * measured specific force and find cross biases introduced by the
2745      * accelerometer.
2746      *
2747      * @param accelerometerMzy known accelerometer z-y cross coupling
2748      *                         error.
2749      * @throws LockedException if calibrator is currently running.
2750      */
2751     @Override
2752     public void setAccelerometerMzy(final double accelerometerMzy) throws LockedException {
2753         if (running) {
2754             throw new LockedException();
2755         }
2756         this.accelerometerMzy = accelerometerMzy;
2757     }
2758 
2759     /**
2760      * Sets known accelerometer scaling factors to be used to fix measured
2761      * specific force and find cross biases introduced by the
2762      * accelerometer.
2763      *
2764      * @param accelerometerSx known accelerometer x scaling factor.
2765      * @param accelerometerSy known accelerometer y scaling factor.
2766      * @param accelerometerSz known accelerometer z scaling factor.
2767      * @throws LockedException if calibrator is currently running.
2768      */
2769     @Override
2770     public void setAccelerometerScalingFactors(
2771             final double accelerometerSx, final double accelerometerSy, final double accelerometerSz)
2772             throws LockedException {
2773         if (running) {
2774             throw new LockedException();
2775         }
2776         this.accelerometerSx = accelerometerSx;
2777         this.accelerometerSy = accelerometerSy;
2778         this.accelerometerSz = accelerometerSz;
2779     }
2780 
2781     /**
2782      * Sets known accelerometer cross coupling errors to be used to fix
2783      * measured specific force and find cross biases introduced by the
2784      * accelerometer.
2785      *
2786      * @param accelerometerMxy known accelerometer x-y cross coupling
2787      *                         error.
2788      * @param accelerometerMxz known accelerometer x-z cross coupling
2789      *                         error.
2790      * @param accelerometerMyx known accelerometer y-x cross coupling
2791      *                         error.
2792      * @param accelerometerMyz known accelerometer y-z cross coupling
2793      *                         error.
2794      * @param accelerometerMzx known accelerometer z-x cross coupling
2795      *                         error.
2796      * @param accelerometerMzy known accelerometer z-y cross coupling
2797      *                         error.
2798      * @throws LockedException if calibrator is currently running.
2799      */
2800     @Override
2801     public void setAccelerometerCrossCouplingErrors(
2802             final double accelerometerMxy, final double accelerometerMxz,
2803             final double accelerometerMyx, final double accelerometerMyz,
2804             final double accelerometerMzx, final double accelerometerMzy) throws LockedException {
2805         if (running) {
2806             throw new LockedException();
2807         }
2808         this.accelerometerMxy = accelerometerMxy;
2809         this.accelerometerMxz = accelerometerMxz;
2810         this.accelerometerMyx = accelerometerMyx;
2811         this.accelerometerMyz = accelerometerMyz;
2812         this.accelerometerMzx = accelerometerMzx;
2813         this.accelerometerMzy = accelerometerMzy;
2814     }
2815 
2816     /**
2817      * Sets known accelerometer scaling factors and cross coupling errors
2818      * to be used to fix measured specific force and find cross biases
2819      * introduced by the accelerometer.
2820      *
2821      * @param accelerometerSx  known accelerometer x scaling factor.
2822      * @param accelerometerSy  known accelerometer y scaling factor.
2823      * @param accelerometerSz  known accelerometer z scaling factor.
2824      * @param accelerometerMxy known accelerometer x-y cross coupling
2825      *                         error.
2826      * @param accelerometerMxz known accelerometer x-z cross coupling
2827      *                         error.
2828      * @param accelerometerMyx known accelerometer y-x cross coupling
2829      *                         error.
2830      * @param accelerometerMyz known accelerometer y-z cross coupling
2831      *                         error.
2832      * @param accelerometerMzx known accelerometer z-x cross coupling
2833      *                         error.
2834      * @param accelerometerMzy known accelerometer z-y cross coupling
2835      *                         error.
2836      * @throws LockedException if calibrator is currently running.
2837      */
2838     @Override
2839     public void setAccelerometerScalingFactorsAndCrossCouplingErrors(
2840             final double accelerometerSx, final double accelerometerSy, final double accelerometerSz,
2841             final double accelerometerMxy, final double accelerometerMxz, final double accelerometerMyx,
2842             final double accelerometerMyz, final double accelerometerMzx, final double accelerometerMzy)
2843             throws LockedException {
2844         if (running) {
2845             throw new LockedException();
2846         }
2847         setAccelerometerScalingFactors(accelerometerSx, accelerometerSy, accelerometerSz);
2848         setAccelerometerCrossCouplingErrors(accelerometerMxy, accelerometerMxz, accelerometerMyx,
2849                 accelerometerMyz, accelerometerMzx, accelerometerMzy);
2850     }
2851 
2852     /**
2853      * Gets known accelerometer scale factors and cross coupling
2854      * errors matrix.
2855      *
2856      * @return known accelerometer scale factors and cross coupling
2857      * errors matrix.
2858      */
2859     @Override
2860     public Matrix getAccelerometerMa() {
2861         Matrix result;
2862         try {
2863             result = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
2864             getAccelerometerMa(result);
2865         } catch (final WrongSizeException ignore) {
2866             // never happens
2867             result = null;
2868         }
2869         return result;
2870     }
2871 
2872     /**
2873      * Gets known accelerometer scale factors and cross coupling
2874      * errors matrix.
2875      *
2876      * @param result instance where data will be stored.
2877      * @throws IllegalArgumentException if provided matrix is not 3x3.
2878      */
2879     @Override
2880     public void getAccelerometerMa(final Matrix result) {
2881         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != BodyKinematics.COMPONENTS) {
2882             throw new IllegalArgumentException();
2883         }
2884         result.setElementAtIndex(0, accelerometerSx);
2885         result.setElementAtIndex(1, accelerometerMyx);
2886         result.setElementAtIndex(2, accelerometerMzx);
2887 
2888         result.setElementAtIndex(3, accelerometerMxy);
2889         result.setElementAtIndex(4, accelerometerSy);
2890         result.setElementAtIndex(5, accelerometerMzy);
2891 
2892         result.setElementAtIndex(6, accelerometerMxz);
2893         result.setElementAtIndex(7, accelerometerMyz);
2894         result.setElementAtIndex(8, accelerometerSz);
2895     }
2896 
2897     /**
2898      * Sets known accelerometer scale factors and cross coupling
2899      * errors matrix.
2900      *
2901      * @param accelerometerMa known accelerometer scale factors and
2902      *                        cross coupling errors matrix. Must be 3x3.
2903      * @throws LockedException          if calibrator is currently running.
2904      * @throws IllegalArgumentException if provided matrix is not 3x3.
2905      */
2906     @Override
2907     public void setAccelerometerMa(final Matrix accelerometerMa) throws LockedException {
2908         if (running) {
2909             throw new LockedException();
2910         }
2911         if (accelerometerMa.getRows() != BodyKinematics.COMPONENTS
2912                 || accelerometerMa.getColumns() != BodyKinematics.COMPONENTS) {
2913             throw new IllegalArgumentException();
2914         }
2915 
2916         accelerometerSx = accelerometerMa.getElementAtIndex(0);
2917         accelerometerMyx = accelerometerMa.getElementAtIndex(1);
2918         accelerometerMzx = accelerometerMa.getElementAtIndex(2);
2919 
2920         accelerometerMxy = accelerometerMa.getElementAtIndex(3);
2921         accelerometerSy = accelerometerMa.getElementAtIndex(4);
2922         accelerometerMzy = accelerometerMa.getElementAtIndex(5);
2923 
2924         accelerometerMxz = accelerometerMa.getElementAtIndex(6);
2925         accelerometerMyz = accelerometerMa.getElementAtIndex(7);
2926         accelerometerSz = accelerometerMa.getElementAtIndex(8);
2927     }
2928 
2929     /**
2930      * Gets known x-coordinate of gyroscope bias.
2931      * This is expressed in radians per second (rad/s).
2932      *
2933      * @return known x-coordinate of gyroscope bias.
2934      */
2935     @Override
2936     public double getBiasX() {
2937         return biasX;
2938     }
2939 
2940     /**
2941      * Sets known x-coordinate of gyroscope bias.
2942      * This is expressed in radians per second (rad/s).
2943      *
2944      * @param biasX known x-coordinate of gyroscope bias.
2945      * @throws LockedException if calibrator is currently running.
2946      */
2947     @Override
2948     public void setBiasX(final double biasX) throws LockedException {
2949         if (running) {
2950             throw new LockedException();
2951         }
2952         this.biasX = biasX;
2953     }
2954 
2955     /**
2956      * Gets known y-coordinate of gyroscope bias.
2957      * This is expressed in radians per second (rad/s).
2958      *
2959      * @return known y-coordinate of gyroscope bias.
2960      */
2961     @Override
2962     public double getBiasY() {
2963         return biasY;
2964     }
2965 
2966     /**
2967      * Sets known y-coordinate of gyroscope bias.
2968      * This is expressed in radians per second (rad/s).
2969      *
2970      * @param biasY known y-coordinate of gyroscope bias.
2971      * @throws LockedException if calibrator is currently running.
2972      */
2973     @Override
2974     public void setBiasY(final double biasY) throws LockedException {
2975         if (running) {
2976             throw new LockedException();
2977         }
2978         this.biasY = biasY;
2979     }
2980 
2981     /**
2982      * Gets known z-coordinate of gyroscope bias.
2983      * This is expressed in radians per second (rad/s).
2984      *
2985      * @return known z-coordinate of gyroscope bias.
2986      */
2987     @Override
2988     public double getBiasZ() {
2989         return biasZ;
2990     }
2991 
2992     /**
2993      * Sets known z-coordinate of gyroscope bias.
2994      * This is expressed in radians per second (rad/s).
2995      *
2996      * @param biasZ known z-coordinate of gyroscope bias.
2997      * @throws LockedException if calibrator is currently running.
2998      */
2999     @Override
3000     public void setBiasZ(final double biasZ) throws LockedException {
3001         if (running) {
3002             throw new LockedException();
3003         }
3004         this.biasZ = biasZ;
3005     }
3006 
3007     /**
3008      * Gets known x-coordinate of gyroscope bias.
3009      *
3010      * @return known x-coordinate of gyroscope bias.
3011      */
3012     @Override
3013     public AngularSpeed getBiasAngularSpeedX() {
3014         return new AngularSpeed(biasX, AngularSpeedUnit.RADIANS_PER_SECOND);
3015     }
3016 
3017     /**
3018      * Gets known x-coordinate of gyroscope bias.
3019      *
3020      * @param result instance where result data will be stored.
3021      */
3022     @Override
3023     public void getBiasAngularSpeedX(final AngularSpeed result) {
3024         result.setValue(biasX);
3025         result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3026     }
3027 
3028     /**
3029      * Sets known x-coordinate of gyroscope bias.
3030      *
3031      * @param biasX known x-coordinate of gyroscope bias.
3032      * @throws LockedException if calibrator is currently running.
3033      */
3034     @Override
3035     public void setBiasX(final AngularSpeed biasX) throws LockedException {
3036         if (running) {
3037             throw new LockedException();
3038         }
3039         this.biasX = convertAngularSpeed(biasX);
3040     }
3041 
3042     /**
3043      * Gets known y-coordinate of gyroscope bias.
3044      *
3045      * @return known y-coordinate of gyroscope bias.
3046      */
3047     @Override
3048     public AngularSpeed getBiasAngularSpeedY() {
3049         return new AngularSpeed(biasY, AngularSpeedUnit.RADIANS_PER_SECOND);
3050     }
3051 
3052     /**
3053      * Gets known y-coordinate of gyroscope bias.
3054      *
3055      * @param result instance where result data will be stored.
3056      */
3057     @Override
3058     public void getBiasAngularSpeedY(final AngularSpeed result) {
3059         result.setValue(biasY);
3060         result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3061     }
3062 
3063     /**
3064      * Sets known y-coordinate of gyroscope bias to be used to find a
3065      * solution.
3066      *
3067      * @param biasY known y-coordinate of gyroscope bias.
3068      * @throws LockedException if calibrator is currently running.
3069      */
3070     @Override
3071     public void setBiasY(final AngularSpeed biasY) throws LockedException {
3072         if (running) {
3073             throw new LockedException();
3074         }
3075         this.biasY = convertAngularSpeed(biasY);
3076     }
3077 
3078     /**
3079      * Gets known z-coordinate of gyroscope bias to be used to find a
3080      * solution.
3081      *
3082      * @return known z-coordinate of gyroscope bias.
3083      */
3084     @Override
3085     public AngularSpeed getBiasAngularSpeedZ() {
3086         return new AngularSpeed(biasZ, AngularSpeedUnit.RADIANS_PER_SECOND);
3087     }
3088 
3089     /**
3090      * Gets known z-coordinate of gyroscope bias.
3091      *
3092      * @param result instance where result data will be stored.
3093      */
3094     @Override
3095     public void getBiasAngularSpeedZ(final AngularSpeed result) {
3096         result.setValue(biasZ);
3097         result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3098     }
3099 
3100     /**
3101      * Sets known z-coordinate of gyroscope bias.
3102      *
3103      * @param biasZ known z-coordinate of gyroscope bias.
3104      * @throws LockedException if calibrator is currently running.
3105      */
3106     @Override
3107     public void setBiasZ(final AngularSpeed biasZ) throws LockedException {
3108         if (running) {
3109             throw new LockedException();
3110         }
3111         this.biasZ = convertAngularSpeed(biasZ);
3112     }
3113 
3114     /**
3115      * Sets known bias coordinates of gyroscope expressed in radians
3116      * per second (rad/s).
3117      *
3118      * @param biasX known x-coordinate of gyroscope bias.
3119      * @param biasY known y-coordinate of gyroscope bias.
3120      * @param biasZ known z-coordinate of gyroscope bias.
3121      * @throws LockedException if calibrator is currently running.
3122      */
3123     @Override
3124     public void setBiasCoordinates(
3125             final double biasX, final double biasY, final double biasZ) throws LockedException {
3126         if (running) {
3127             throw new LockedException();
3128         }
3129         this.biasX = biasX;
3130         this.biasY = biasY;
3131         this.biasZ = biasZ;
3132     }
3133 
3134     /**
3135      * Sets known bias coordinates of gyroscope.
3136      *
3137      * @param biasX known x-coordinate of gyroscope bias.
3138      * @param biasY known y-coordinate of gyroscope bias.
3139      * @param biasZ known z-coordinate of gyroscope bias.
3140      * @throws LockedException if calibrator is currently running.
3141      */
3142     @Override
3143     public void setBiasCoordinates(
3144             final AngularSpeed biasX, final AngularSpeed biasY, final AngularSpeed biasZ) throws LockedException {
3145         if (running) {
3146             throw new LockedException();
3147         }
3148         this.biasX = convertAngularSpeed(biasX);
3149         this.biasY = convertAngularSpeed(biasY);
3150         this.biasZ = convertAngularSpeed(biasZ);
3151     }
3152 
3153     /**
3154      * Gets known gyroscope bias.
3155      *
3156      * @return known gyroscope bias.
3157      */
3158     public AngularSpeedTriad getBiasAsTriad() {
3159         return new AngularSpeedTriad(AngularSpeedUnit.RADIANS_PER_SECOND, biasX, biasY, biasZ);
3160     }
3161 
3162     /**
3163      * Gets known gyroscope bias.
3164      *
3165      * @param result instance where result will be stored.
3166      */
3167     public void getBiasAsTriad(final AngularSpeedTriad result) {
3168         result.setValueCoordinatesAndUnit(biasX, biasY, biasZ, AngularSpeedUnit.RADIANS_PER_SECOND);
3169     }
3170 
3171     /**
3172      * Sets known gyroscope bias.
3173      *
3174      * @param bias gyroscope bias to be set.
3175      * @throws LockedException if calibrator is currently running.
3176      */
3177     public void setBias(final AngularSpeedTriad bias) throws LockedException {
3178         if (running) {
3179             throw new LockedException();
3180         }
3181 
3182         biasX = convertAngularSpeed(bias.getValueX(), bias.getUnit());
3183         biasY = convertAngularSpeed(bias.getValueY(), bias.getUnit());
3184         biasZ = convertAngularSpeed(bias.getValueZ(), bias.getUnit());
3185     }
3186 
3187     /**
3188      * Gets initial x scaling factor of gyroscope.
3189      *
3190      * @return initial x scaling factor of gyroscope.
3191      */
3192     @Override
3193     public double getInitialSx() {
3194         return initialSx;
3195     }
3196 
3197     /**
3198      * Sets initial x scaling factor of gyroscope.
3199      *
3200      * @param initialSx initial x scaling factor of gyroscope.
3201      * @throws LockedException if calibrator is currently running.
3202      */
3203     @Override
3204     public void setInitialSx(final double initialSx) throws LockedException {
3205         if (running) {
3206             throw new LockedException();
3207         }
3208         this.initialSx = initialSx;
3209     }
3210 
3211     /**
3212      * Gets initial y scaling factor of gyroscope.
3213      *
3214      * @return initial y scaling factor of gyroscope.
3215      */
3216     @Override
3217     public double getInitialSy() {
3218         return initialSy;
3219     }
3220 
3221     /**
3222      * Sets initial y scaling factor of gyroscope.
3223      *
3224      * @param initialSy initial y scaling factor of gyroscope.
3225      * @throws LockedException if calibrator is currently running.
3226      */
3227     @Override
3228     public void setInitialSy(final double initialSy) throws LockedException {
3229         if (running) {
3230             throw new LockedException();
3231         }
3232         this.initialSy = initialSy;
3233     }
3234 
3235     /**
3236      * Gets initial z scaling factor of gyroscope.
3237      *
3238      * @return initial z scaling factor of gyroscope.
3239      */
3240     @Override
3241     public double getInitialSz() {
3242         return initialSz;
3243     }
3244 
3245     /**
3246      * Sets initial z scaling factor of gyroscope.
3247      *
3248      * @param initialSz initial z scaling factor of gyroscope.
3249      * @throws LockedException if calibrator is currently running.
3250      */
3251     @Override
3252     public void setInitialSz(final double initialSz) throws LockedException {
3253         if (running) {
3254             throw new LockedException();
3255         }
3256         this.initialSz = initialSz;
3257     }
3258 
3259     /**
3260      * Gets initial x-y cross coupling error of gyroscope.
3261      *
3262      * @return initial x-y cross coupling error of gyroscope.
3263      */
3264     @Override
3265     public double getInitialMxy() {
3266         return initialMxy;
3267     }
3268 
3269     /**
3270      * Sets initial x-y cross coupling error of gyroscope.
3271      *
3272      * @param initialMxy initial x-y cross coupling error of gyroscope.
3273      * @throws LockedException if calibrator is currently running.
3274      */
3275     @Override
3276     public void setInitialMxy(final double initialMxy) throws LockedException {
3277         if (running) {
3278             throw new LockedException();
3279         }
3280         this.initialMxy = initialMxy;
3281     }
3282 
3283     /**
3284      * Gets initial x-z cross coupling error of gyroscope.
3285      *
3286      * @return initial x-z cross coupling error of gyroscope.
3287      */
3288     @Override
3289     public double getInitialMxz() {
3290         return initialMxz;
3291     }
3292 
3293     /**
3294      * Sets initial x-z cross coupling error of gyroscope.
3295      *
3296      * @param initialMxz initial x-z cross coupling error of gyroscope.
3297      * @throws LockedException if calibrator is currently running.
3298      */
3299     @Override
3300     public void setInitialMxz(final double initialMxz) throws LockedException {
3301         if (running) {
3302             throw new LockedException();
3303         }
3304         this.initialMxz = initialMxz;
3305     }
3306 
3307     /**
3308      * Gets initial y-x cross coupling error of gyroscope.
3309      *
3310      * @return initial y-x cross coupling error of gyroscope.
3311      */
3312     @Override
3313     public double getInitialMyx() {
3314         return initialMyx;
3315     }
3316 
3317     /**
3318      * Sets initial y-x cross coupling error of gyroscope.
3319      *
3320      * @param initialMyx initial y-x cross coupling error of gyroscope.
3321      * @throws LockedException if calibrator is currently running.
3322      */
3323     @Override
3324     public void setInitialMyx(final double initialMyx) throws LockedException {
3325         if (running) {
3326             throw new LockedException();
3327         }
3328         this.initialMyx = initialMyx;
3329     }
3330 
3331     /**
3332      * Gets initial y-z cross coupling error of gyroscope.
3333      *
3334      * @return initial y-z cross coupling error of gyroscope.
3335      */
3336     @Override
3337     public double getInitialMyz() {
3338         return initialMyz;
3339     }
3340 
3341     /**
3342      * Sets initial y-z cross coupling error of gyroscope.
3343      *
3344      * @param initialMyz initial y-z cross coupling error of gyroscope.
3345      * @throws LockedException if calibrator is currently running.
3346      */
3347     @Override
3348     public void setInitialMyz(final double initialMyz) throws LockedException {
3349         if (running) {
3350             throw new LockedException();
3351         }
3352         this.initialMyz = initialMyz;
3353     }
3354 
3355     /**
3356      * Gets initial z-x cross coupling error of gyroscope.
3357      *
3358      * @return initial z-x cross coupling error of gyroscope.
3359      */
3360     @Override
3361     public double getInitialMzx() {
3362         return initialMzx;
3363     }
3364 
3365     /**
3366      * Sets initial z-x cross coupling error of gyroscope.
3367      *
3368      * @param initialMzx initial z-x cross coupling error of gyroscope.
3369      * @throws LockedException if calibrator is currently running.
3370      */
3371     @Override
3372     public void setInitialMzx(final double initialMzx) throws LockedException {
3373         if (running) {
3374             throw new LockedException();
3375         }
3376         this.initialMzx = initialMzx;
3377     }
3378 
3379     /**
3380      * Gets initial z-y cross coupling error of gyroscope.
3381      *
3382      * @return initial z-y cross coupling error of gyroscope.
3383      */
3384     @Override
3385     public double getInitialMzy() {
3386         return initialMzy;
3387     }
3388 
3389     /**
3390      * Sets initial z-y cross coupling error of gyroscope.
3391      *
3392      * @param initialMzy initial z-y cross coupling error of gyroscope.
3393      * @throws LockedException if calibrator is currently running.
3394      */
3395     @Override
3396     public void setInitialMzy(final double initialMzy) throws LockedException {
3397         if (running) {
3398             throw new LockedException();
3399         }
3400         this.initialMzy = initialMzy;
3401     }
3402 
3403     /**
3404      * Sets initial scaling factors of gyroscope.
3405      *
3406      * @param initialSx initial x scaling factor of gyroscope.
3407      * @param initialSy initial y scaling factor of gyroscope.
3408      * @param initialSz initial z scaling factor of gyroscope.
3409      * @throws LockedException if calibrator is currently running.
3410      */
3411     @Override
3412     public void setInitialScalingFactors(
3413             final double initialSx, final double initialSy, final double initialSz) throws LockedException {
3414         if (running) {
3415             throw new LockedException();
3416         }
3417         this.initialSx = initialSx;
3418         this.initialSy = initialSy;
3419         this.initialSz = initialSz;
3420     }
3421 
3422     /**
3423      * Sets initial cross coupling errors of gyroscope.
3424      *
3425      * @param initialMxy initial x-y cross coupling error of gyroscope.
3426      * @param initialMxz initial x-z cross coupling error of gyroscope.
3427      * @param initialMyx initial y-x cross coupling error of gyroscope.
3428      * @param initialMyz initial y-z cross coupling error of gyroscope.
3429      * @param initialMzx initial z-x cross coupling error of gyroscope.
3430      * @param initialMzy initial z-y cross coupling error of gyroscope.
3431      * @throws LockedException if calibrator is currently running.
3432      */
3433     @Override
3434     public void setInitialCrossCouplingErrors(
3435             final double initialMxy, final double initialMxz, final double initialMyx,
3436             final double initialMyz, final double initialMzx, final double initialMzy) throws LockedException {
3437         if (running) {
3438             throw new LockedException();
3439         }
3440         this.initialMxy = initialMxy;
3441         this.initialMxz = initialMxz;
3442         this.initialMyx = initialMyx;
3443         this.initialMyz = initialMyz;
3444         this.initialMzx = initialMzx;
3445         this.initialMzy = initialMzy;
3446     }
3447 
3448     /**
3449      * Sets initial scaling factors and cross coupling errors of
3450      * gyroscope.
3451      *
3452      * @param initialSx  initial x scaling factor of gyroscope.
3453      * @param initialSy  initial y scaling factor of gyroscope.
3454      * @param initialSz  initial z scaling factor of gyroscope.
3455      * @param initialMxy initial x-y cross coupling error of gyroscope.
3456      * @param initialMxz initial x-z cross coupling error of gyroscope.
3457      * @param initialMyx initial y-x cross coupling error of gyroscope.
3458      * @param initialMyz initial y-z cross coupling error of gyroscope.
3459      * @param initialMzx initial z-x cross coupling error of gyroscope.
3460      * @param initialMzy initial z-y cross coupling error of gyroscope.
3461      * @throws LockedException if calibrator is currently running.
3462      */
3463     @Override
3464     public void setInitialScalingFactorsAndCrossCouplingErrors(
3465             final double initialSx, final double initialSy, final double initialSz,
3466             final double initialMxy, final double initialMxz, final double initialMyx,
3467             final double initialMyz, final double initialMzx, final double initialMzy) throws LockedException {
3468         if (running) {
3469             throw new LockedException();
3470         }
3471         setInitialScalingFactors(initialSx, initialSy, initialSz);
3472         setInitialCrossCouplingErrors(initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
3473     }
3474 
3475     /**
3476      * Gets known gyroscope bias as an array.
3477      * Array values are expressed in radians per second (rad/s).
3478      *
3479      * @return array containing coordinates of gyroscope bias.
3480      */
3481     @Override
3482     public double[] getBias() {
3483         final var result = new double[BodyKinematics.COMPONENTS];
3484         getBias(result);
3485         return result;
3486     }
3487 
3488     /**
3489      * Gets known gyroscope bias as an array.
3490      * Array values are expressed in radians per second (rad/s).
3491      *
3492      * @param result instance where result data will be copied to.
3493      * @throws IllegalArgumentException if provided array does not have length 3.
3494      */
3495     @Override
3496     public void getBias(final double[] result) {
3497         if (result.length != BodyKinematics.COMPONENTS) {
3498             throw new IllegalArgumentException();
3499         }
3500         result[0] = biasX;
3501         result[1] = biasY;
3502         result[2] = biasZ;
3503     }
3504 
3505     /**
3506      * Sets known gyroscope bias  as an array.
3507      * Array values are expressed in radians per second (rad/s).
3508      *
3509      * @param bias known bias.
3510      * @throws LockedException          if calibrator is currently running.
3511      * @throws IllegalArgumentException if provided array does not have length 3.
3512      */
3513     @Override
3514     public void setBias(final double[] bias) throws LockedException {
3515         if (running) {
3516             throw new LockedException();
3517         }
3518 
3519         if (bias.length != BodyKinematics.COMPONENTS) {
3520             throw new IllegalArgumentException();
3521         }
3522         biasX = bias[0];
3523         biasY = bias[1];
3524         biasZ = bias[2];
3525     }
3526 
3527     /**
3528      * Gets known gyroscope bias as a column matrix.
3529      * Matrix values are expressed in radians per second (rad/s).
3530      *
3531      * @return known gyroscope bias as a column matrix.
3532      */
3533     @Override
3534     public Matrix getBiasAsMatrix() {
3535         Matrix result;
3536         try {
3537             result = new Matrix(BodyKinematics.COMPONENTS, 1);
3538             getBiasAsMatrix(result);
3539         } catch (final WrongSizeException ignore) {
3540             // never happens
3541             result = null;
3542         }
3543         return result;
3544     }
3545 
3546     /**
3547      * Gets known gyroscope bias as a column matrix.
3548      * Matrix values are expressed in radians per second (rad/s).
3549      *
3550      * @param result instance where result data will be copied to.
3551      * @throws IllegalArgumentException if provided matrix is not 3x1.
3552      */
3553     @Override
3554     public void getBiasAsMatrix(final Matrix result) {
3555         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != 1) {
3556             throw new IllegalArgumentException();
3557         }
3558         result.setElementAtIndex(0, biasX);
3559         result.setElementAtIndex(1, biasY);
3560         result.setElementAtIndex(2, biasZ);
3561     }
3562 
3563     /**
3564      * Sets known gyroscope bias as a column matrix.
3565      * Matrix values are expressed in radians per second (rad/s).
3566      *
3567      * @param bias known gyroscope bias.
3568      * @throws LockedException          if calibrator is currently running.
3569      * @throws IllegalArgumentException if provided matrix is not 3x1.
3570      */
3571     @Override
3572     public void setBias(final Matrix bias) throws LockedException {
3573         if (running) {
3574             throw new LockedException();
3575         }
3576         if (bias.getRows() != BodyKinematics.COMPONENTS || bias.getColumns() != 1) {
3577             throw new IllegalArgumentException();
3578         }
3579 
3580         biasX = bias.getElementAtIndex(0);
3581         biasY = bias.getElementAtIndex(1);
3582         biasZ = bias.getElementAtIndex(2);
3583     }
3584 
3585     /**
3586      * Gets initial gyroscope scale factors and cross coupling errors
3587      * matrix.
3588      *
3589      * @return initial gyroscope scale factors and cross coupling errors
3590      * matrix.
3591      */
3592     @Override
3593     public Matrix getInitialMg() {
3594         Matrix result;
3595         try {
3596             result = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
3597             getInitialMg(result);
3598         } catch (final WrongSizeException ignore) {
3599             // never happens
3600             result = null;
3601         }
3602         return result;
3603     }
3604 
3605     /**
3606      * Gets initial gyroscope scale factors and cross coupling errors
3607      * matrix.
3608      *
3609      * @param result instance where data will be stored.
3610      * @throws IllegalArgumentException if provided matrix is not 3x3.
3611      */
3612     @Override
3613     public void getInitialMg(final Matrix result) {
3614         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != BodyKinematics.COMPONENTS) {
3615             throw new IllegalArgumentException();
3616         }
3617         result.setElementAtIndex(0, initialSx);
3618         result.setElementAtIndex(1, initialMyx);
3619         result.setElementAtIndex(2, initialMzx);
3620 
3621         result.setElementAtIndex(3, initialMxy);
3622         result.setElementAtIndex(4, initialSy);
3623         result.setElementAtIndex(5, initialMzy);
3624 
3625         result.setElementAtIndex(6, initialMxz);
3626         result.setElementAtIndex(7, initialMyz);
3627         result.setElementAtIndex(8, initialSz);
3628     }
3629 
3630     /**
3631      * Sets initial gyroscope scale factors and cross coupling errors matrix.
3632      *
3633      * @param initialMg initial scale factors and cross coupling errors matrix.
3634      * @throws IllegalArgumentException if provided matrix is not 3x3.
3635      * @throws LockedException          if calibrator is currently running.
3636      */
3637     @Override
3638     public void setInitialMg(final Matrix initialMg) throws LockedException {
3639         if (running) {
3640             throw new LockedException();
3641         }
3642         if (initialMg.getRows() != BodyKinematics.COMPONENTS || initialMg.getColumns() != BodyKinematics.COMPONENTS) {
3643             throw new IllegalArgumentException();
3644         }
3645 
3646         initialSx = initialMg.getElementAtIndex(0);
3647         initialMyx = initialMg.getElementAtIndex(1);
3648         initialMzx = initialMg.getElementAtIndex(2);
3649 
3650         initialMxy = initialMg.getElementAtIndex(3);
3651         initialSy = initialMg.getElementAtIndex(4);
3652         initialMzy = initialMg.getElementAtIndex(5);
3653 
3654         initialMxz = initialMg.getElementAtIndex(6);
3655         initialMyz = initialMg.getElementAtIndex(7);
3656         initialSz = initialMg.getElementAtIndex(8);
3657     }
3658 
3659     /**
3660      * Gets initial G-dependent cross biases introduced on the gyroscope by the
3661      * specific forces sensed by the accelerometer.
3662      *
3663      * @return a 3x3 matrix containing initial g-dependent cross biases.
3664      */
3665     @Override
3666     public Matrix getInitialGg() {
3667         return new Matrix(initialGg);
3668     }
3669 
3670     /**
3671      * Gets initial G-dependent cross biases introduced on the gyroscope by the
3672      * specific forces sensed by the accelerometer.
3673      *
3674      * @param result instance where data will be stored.
3675      * @throws IllegalArgumentException if provided matrix is not 3x3.
3676      */
3677     @Override
3678     public void getInitialGg(final Matrix result) {
3679         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != BodyKinematics.COMPONENTS) {
3680             throw new IllegalArgumentException();
3681         }
3682 
3683         result.copyFrom(initialGg);
3684     }
3685 
3686     /**
3687      * Sets initial G-dependent cross biases introduced on the gyroscope by the
3688      * specific forces sensed by the accelerometer.
3689      *
3690      * @param initialGg g-dependent cross biases.
3691      * @throws LockedException          if calibrator is currently running.
3692      * @throws IllegalArgumentException if provided matrix is not 3x3.
3693      */
3694     @Override
3695     public void setInitialGg(final Matrix initialGg) throws LockedException {
3696         if (running) {
3697             throw new LockedException();
3698         }
3699 
3700         if (initialGg.getRows() != BodyKinematics.COMPONENTS || initialGg.getColumns() != BodyKinematics.COMPONENTS) {
3701             throw new IllegalArgumentException();
3702         }
3703 
3704         initialGg.copyTo(this.initialGg);
3705     }
3706 
3707     /**
3708      * Gets constant rotation rate at which the turntable is spinning.
3709      * This is expressed in radians per second (rad/s).
3710      *
3711      * @return constant rotation rate of turntable.
3712      */
3713     public double getTurntableRotationRate() {
3714         return turntableRotationRate;
3715     }
3716 
3717     /**
3718      * Sets constant rotation rate at which the turntable is spinning.
3719      * This is expressed in radians per second (rad/s).
3720      *
3721      * @param turntableRotationRate constant rotation rate of turntable.
3722      * @throws LockedException          if calibrator is currently running
3723      * @throws IllegalArgumentException if provided value is zero or
3724      *                                  negative.
3725      */
3726     public void setTurntableRotationRate(final double turntableRotationRate) throws LockedException {
3727         if (running) {
3728             throw new LockedException();
3729         }
3730         if (turntableRotationRate <= 0.0) {
3731             throw new IllegalArgumentException();
3732         }
3733 
3734         this.turntableRotationRate = turntableRotationRate;
3735     }
3736 
3737     /**
3738      * Gets constant rotation rate at which the turntable is spinning.
3739      *
3740      * @return constant rotation rate of turntable.
3741      */
3742     public AngularSpeed getTurntableRotationRateAsAngularSpeed() {
3743         return new AngularSpeed(turntableRotationRate, AngularSpeedUnit.RADIANS_PER_SECOND);
3744     }
3745 
3746     /**
3747      * Gets constant rotation rate at which the turntable is spinning.
3748      *
3749      * @param result instance where result will be stored.
3750      */
3751     public void getTurntableRotationRateAsAngularSpeed(final AngularSpeed result) {
3752         result.setValue(turntableRotationRate);
3753         result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3754     }
3755 
3756     /**
3757      * Sets constant rotation rate at which the turntable is spinning.
3758      *
3759      * @param turntableRotationRate constant rotation rate of turntable.
3760      * @throws LockedException          if calibrator is currently running.
3761      * @throws IllegalArgumentException if provided value is zero or
3762      *                                  negative.
3763      */
3764     public void setTurntableRotationRate(final AngularSpeed turntableRotationRate) throws LockedException {
3765         if (running) {
3766             throw new LockedException();
3767         }
3768         setTurntableRotationRate(convertAngularSpeed(turntableRotationRate));
3769     }
3770 
3771     /**
3772      * Gets time interval between measurements being captured expressed in
3773      * seconds (s).
3774      *
3775      * @return time interval between measurements.
3776      */
3777     public double getTimeInterval() {
3778         return timeInterval;
3779     }
3780 
3781     /**
3782      * Sets time interval between measurements being captured expressed in
3783      * seconds (s).
3784      *
3785      * @param timeInterval time interval between measurements.
3786      * @throws LockedException          if calibrator is currently running.
3787      * @throws IllegalArgumentException if provided value is zero or
3788      *                                  negative.
3789      */
3790     public void setTimeInterval(final double timeInterval) throws LockedException {
3791         if (running) {
3792             throw new LockedException();
3793         }
3794 
3795         if (timeInterval <= 0.0) {
3796             throw new IllegalArgumentException();
3797         }
3798         this.timeInterval = timeInterval;
3799     }
3800 
3801     /**
3802      * Gets time interval between measurements being captured.
3803      *
3804      * @return time interval between measurements.
3805      */
3806     public Time getTimeIntervalAsTime() {
3807         return new Time(timeInterval, TimeUnit.SECOND);
3808     }
3809 
3810     /**
3811      * Gets time interval between measurements being captured.
3812      *
3813      * @param result instance where result will be stored.
3814      */
3815     public void getTimeIntervalAsTime(final Time result) {
3816         result.setValue(timeInterval);
3817         result.setUnit(TimeUnit.SECOND);
3818     }
3819 
3820     /**
3821      * Sets time interval between measurements being captured.
3822      *
3823      * @param timeInterval time interval between measurements.
3824      * @throws LockedException if calibrator is currently running.
3825      */
3826     public void setTimeInterval(final Time timeInterval) throws LockedException {
3827         if (running) {
3828             throw new LockedException();
3829         }
3830         setTimeInterval(convertTime(timeInterval));
3831     }
3832 
3833     /**
3834      * Gets a collection of body kinematics measurements taken at
3835      * a given position with different unknown orientations and containing
3836      * the standard deviations of accelerometer and gyroscope measurements.
3837      *
3838      * @return collection of body kinematics measurements at a known position
3839      * with unknown orientations.
3840      */
3841     @Override
3842     public Collection<StandardDeviationBodyKinematics> getMeasurements() {
3843         return measurements;
3844     }
3845 
3846     /**
3847      * Sets a collection of body kinematics measurements taken at
3848      * a given position with different unknown orientations and containing
3849      * the standard deviations of accelerometer and gyroscope measurements.
3850      *
3851      * @param measurements collection of body kinematics measurements at a
3852      *                     known position with unknown orientations.
3853      * @throws LockedException if calibrator is currently running.
3854      */
3855     @Override
3856     public void setMeasurements(final Collection<StandardDeviationBodyKinematics> measurements) throws LockedException {
3857         if (running) {
3858             throw new LockedException();
3859         }
3860         this.measurements = measurements;
3861     }
3862 
3863     /**
3864      * Gets position where body kinematics measures have been taken expressed in
3865      * ECEF coordinates.
3866      *
3867      * @return position where body kinematics measures have been taken.
3868      */
3869     public ECEFPosition getEcefPosition() {
3870         return position;
3871     }
3872 
3873     /**
3874      * Gets position where body kinematics measures have been taken expressed in
3875      * ECEF coordinates.
3876      *
3877      * @param position position where body kinematics measures have been taken.
3878      * @throws LockedException if calibrator is currently running.
3879      */
3880     public void setPosition(final ECEFPosition position) throws LockedException {
3881         if (running) {
3882             throw new LockedException();
3883         }
3884 
3885         this.position = position;
3886     }
3887 
3888     /**
3889      * Gets position where body kinematics measures have been taken expressed in
3890      * NED coordinates.
3891      *
3892      * @return position where body kinematics measures have been taken or null if
3893      * not available.
3894      */
3895     public NEDPosition getNedPosition() {
3896         final var result = new NEDPosition();
3897         return getNedPosition(result) ? result : null;
3898     }
3899 
3900     /**
3901      * Gets position where body kinematics measures have been taken expressed in
3902      * NED coordinates.
3903      *
3904      * @param result instance where result will be stored.
3905      * @return true if NED position could be computed, false otherwise.
3906      */
3907     public boolean getNedPosition(final NEDPosition result) {
3908         if (position != null) {
3909             final var velocity = new NEDVelocity();
3910             ECEFtoNEDPositionVelocityConverter.convertECEFtoNED(
3911                     position.getX(), position.getY(), position.getZ(), 0.0, 0.0, 0.0, result, velocity);
3912             return true;
3913         } else {
3914             return false;
3915         }
3916     }
3917 
3918     /**
3919      * Sets position where body kinematics measures have been taken expressed in
3920      * NED coordinates.
3921      *
3922      * @param position position where body kinematics measures have been taken.
3923      * @throws LockedException if calibrator is currently running.
3924      */
3925     public void setPosition(final NEDPosition position) throws LockedException {
3926         if (running) {
3927             throw new LockedException();
3928         }
3929 
3930         this.position = convertPosition(position);
3931     }
3932 
3933     /**
3934      * Indicates the type of measurement or sequence used by this calibrator.
3935      *
3936      * @return type of measurement or sequence used by this calibrator.
3937      */
3938     @Override
3939     public GyroscopeCalibratorMeasurementOrSequenceType getMeasurementOrSequenceType() {
3940         return GyroscopeCalibratorMeasurementOrSequenceType.STANDARD_DEVIATION_BODY_KINEMATICS_MEASUREMENT;
3941     }
3942 
3943     /**
3944      * Indicates whether this calibrator requires ordered measurements or sequences
3945      * in a list or not.
3946      *
3947      * @return true if measurements or sequences must be ordered, false otherwise.
3948      */
3949     @Override
3950     public boolean isOrderedMeasurementsOrSequencesRequired() {
3951         return false;
3952     }
3953 
3954     /**
3955      * Indicates whether this calibrator requires quality scores for each
3956      * measurement/sequence or not.
3957      *
3958      * @return true if quality scores are required, false otherwise.
3959      */
3960     @Override
3961     public boolean isQualityScoresRequired() {
3962         return false;
3963     }
3964 
3965     /**
3966      * Indicates whether z-axis is assumed to be common for accelerometer and
3967      * gyroscope.
3968      * When enabled, this eliminates 3 variables from Ma matrix.
3969      *
3970      * @return true if z-axis is assumed to be common for accelerometer and gyroscope,
3971      * false otherwise.
3972      */
3973     @Override
3974     public boolean isCommonAxisUsed() {
3975         return commonAxisUsed;
3976     }
3977 
3978     /**
3979      * Specifies whether z-axis is assumed to be common for accelerometer and
3980      * gyroscope.
3981      * When enabled, this eliminates 3 variables from Ma matrix.
3982      *
3983      * @param commonAxisUsed true if z-axis is assumed to be common for accelerometer
3984      *                       and gyroscope, false otherwise.
3985      * @throws LockedException if calibrator is currently running.
3986      */
3987     @Override
3988     public void setCommonAxisUsed(final boolean commonAxisUsed) throws LockedException {
3989         if (running) {
3990             throw new LockedException();
3991         }
3992 
3993         this.commonAxisUsed = commonAxisUsed;
3994     }
3995 
3996     /**
3997      * Indicates whether G-dependent cross biases are being estimated
3998      * or not.
3999      * When enabled, this adds 9 variables from Gg matrix.
4000      *
4001      * @return true if G-dependent cross biases will be estimated,
4002      * false otherwise.
4003      */
4004     public boolean isGDependentCrossBiasesEstimated() {
4005         return estimateGDependentCrossBiases;
4006     }
4007 
4008     /**
4009      * Specifies whether G-dependent cross biases are being estimated
4010      * or not.
4011      * When enabled, this adds 9 variables from Gg matrix.
4012      *
4013      * @param estimateGDependentCrossBiases true if G-dependent cross
4014      *                                      biases will be estimated,
4015      *                                      false otherwise.
4016      * @throws LockedException if calibrator is currently running.
4017      */
4018     public void setGDependentCrossBiasesEstimated(final boolean estimateGDependentCrossBiases) throws LockedException {
4019         if (running) {
4020             throw new LockedException();
4021         }
4022 
4023         this.estimateGDependentCrossBiases = estimateGDependentCrossBiases;
4024     }
4025 
4026     /**
4027      * Gets listener to handle events raised by this estimator.
4028      *
4029      * @return listener to handle events raised by this estimator.
4030      */
4031     public KnownBiasTurntableGyroscopeCalibratorListener getListener() {
4032         return listener;
4033     }
4034 
4035     /**
4036      * Sets listener to handle events raised by this estimator.
4037      *
4038      * @param listener listener to handle events raised by this estimator.
4039      * @throws LockedException if calibrator is currently running.
4040      */
4041     public void setListener(
4042             final KnownBiasTurntableGyroscopeCalibratorListener listener) throws LockedException {
4043         if (running) {
4044             throw new LockedException();
4045         }
4046 
4047         this.listener = listener;
4048     }
4049 
4050     /**
4051      * Gets minimum number of required measurements.
4052      *
4053      * @return minimum number of required measurements.
4054      */
4055     @Override
4056     public int getMinimumRequiredMeasurementsOrSequences() {
4057         if (commonAxisUsed) {
4058             if (estimateGDependentCrossBiases) {
4059                 return MINIMUM_MEASUREMENTS_COMMON_Z_AXIS_AND_CROSS_BIASES;
4060             } else {
4061                 return MINIMUM_MEASUREMENTS_COMMON_Z_AXIS;
4062             }
4063         } else {
4064             if (estimateGDependentCrossBiases) {
4065                 return MINIMUM_MEASUREMENTS_GENERAL_AND_CROSS_BIASES;
4066             } else {
4067                 return MINIMUM_MEASUREMENTS_GENERAL;
4068             }
4069         }
4070     }
4071 
4072     /**
4073      * Indicates whether calibrator is ready to start.
4074      *
4075      * @return true if calibrator is ready, false otherwise.
4076      */
4077     @Override
4078     public boolean isReady() {
4079         return measurements != null && measurements.size() >= getMinimumRequiredMeasurementsOrSequences();
4080     }
4081 
4082     /**
4083      * Indicates whether calibrator is currently running or not.
4084      *
4085      * @return true if calibrator is running, false otherwise.
4086      */
4087     @Override
4088     public boolean isRunning() {
4089         return running;
4090     }
4091 
4092     /**
4093      * Estimates gyroscope calibration parameters containing bias, scale factors,
4094      * cross-coupling errors and G-dependent coupling.
4095      *
4096      * @throws LockedException      if calibrator is currently running.
4097      * @throws NotReadyException    if calibrator is not ready.
4098      * @throws CalibrationException if estimation fails for numerical reasons.
4099      */
4100     @Override
4101     public void calibrate() throws LockedException, NotReadyException, CalibrationException {
4102         if (running) {
4103             throw new LockedException();
4104         }
4105 
4106         if (!isReady()) {
4107             throw new NotReadyException();
4108         }
4109 
4110         try {
4111             running = true;
4112 
4113             if (listener != null) {
4114                 listener.onCalibrateStart(this);
4115             }
4116 
4117             if (commonAxisUsed) {
4118                 if (estimateGDependentCrossBiases) {
4119                     calibrateCommonAxisAndGDependentCrossBiases();
4120                 } else {
4121                     calibrateCommonAxis();
4122                 }
4123             } else {
4124                 if (estimateGDependentCrossBiases) {
4125                     calibrateGeneralAndGDependentCrossBiases();
4126                 } else {
4127                     calibrateGeneral();
4128                 }
4129             }
4130 
4131             if (listener != null) {
4132                 listener.onCalibrateEnd(this);
4133             }
4134 
4135         } catch (final AlgebraException | FittingException | com.irurueta.numerical.NotReadyException
4136                        | InvalidSourceAndDestinationFrameTypeException e) {
4137             throw new CalibrationException(e);
4138         } finally {
4139             running = false;
4140         }
4141     }
4142 
4143     /**
4144      * Gets estimated gyroscope scale factors and cross coupling errors.
4145      * This is the product of matrix Tg containing cross coupling errors and Kg
4146      * containing scaling factors.
4147      * So that:
4148      * <pre>
4149      *     Mg = [sx    mxy  mxz] = Tg*Kg
4150      *          [myx   sy   myz]
4151      *          [mzx   mzy  sz ]
4152      * </pre>
4153      * Where:
4154      * <pre>
4155      *     Kg = [sx 0   0 ]
4156      *          [0  sy  0 ]
4157      *          [0  0   sz]
4158      * </pre>
4159      * and
4160      * <pre>
4161      *     Tg = [1          -alphaXy    alphaXz ]
4162      *          [alphaYx    1           -alphaYz]
4163      *          [-alphaZx   alphaZy     1       ]
4164      * </pre>
4165      * Hence:
4166      * <pre>
4167      *     Mg = [sx    mxy  mxz] = Tg*Kg =  [sx             -sy * alphaXy   sz * alphaXz ]
4168      *          [myx   sy   myz]            [sx * alphaYx   sy              -sz * alphaYz]
4169      *          [mzx   mzy  sz ]            [-sx * alphaZx  sy * alphaZy    sz           ]
4170      * </pre>
4171      * This instance allows any 3x3 matrix however, typically alphaYx, alphaZx and alphaZy
4172      * are considered to be zero if the gyroscope z-axis is assumed to be the same
4173      * as the body z-axis. When this is assumed, myx = mzx = mzy = 0 and the Mg matrix
4174      * becomes upper diagonal:
4175      * <pre>
4176      *     Mg = [sx    mxy  mxz]
4177      *          [0     sy   myz]
4178      *          [0     0    sz ]
4179      * </pre>
4180      * Values of this matrix are unit-less.
4181      *
4182      * @return estimated gyroscope scale factors and cross coupling errors, or null
4183      * if not available.
4184      */
4185     @Override
4186     public Matrix getEstimatedMg() {
4187         return estimatedMg;
4188     }
4189 
4190     /**
4191      * Gets estimated gyroscope x-axis scale factor.
4192      *
4193      * @return estimated gyroscope x-axis scale factor or null
4194      * if not available.
4195      */
4196     @Override
4197     public Double getEstimatedSx() {
4198         return estimatedMg != null ? estimatedMg.getElementAt(0, 0) : null;
4199     }
4200 
4201     /**
4202      * Gets estimated gyroscope y-axis scale factor.
4203      *
4204      * @return estimated gyroscope y-axis scale factor or null
4205      * if not available.
4206      */
4207     @Override
4208     public Double getEstimatedSy() {
4209         return estimatedMg != null ? estimatedMg.getElementAt(1, 1) : null;
4210     }
4211 
4212     /**
4213      * Gets estimated gyroscope z-axis scale factor.
4214      *
4215      * @return estimated gyroscope z-axis scale factor or null
4216      * if not available.
4217      */
4218     @Override
4219     public Double getEstimatedSz() {
4220         return estimatedMg != null ? estimatedMg.getElementAt(2, 2) : null;
4221     }
4222 
4223     /**
4224      * Gets estimated gyroscope x-y cross-coupling error.
4225      *
4226      * @return estimated gyroscope x-y cross-coupling error or null
4227      * if not available.
4228      */
4229     @Override
4230     public Double getEstimatedMxy() {
4231         return estimatedMg != null ? estimatedMg.getElementAt(0, 1) : null;
4232     }
4233 
4234     /**
4235      * Gets estimated gyroscope x-z cross-coupling error.
4236      *
4237      * @return estimated gyroscope x-z cross-coupling error or null
4238      * if not available.
4239      */
4240     @Override
4241     public Double getEstimatedMxz() {
4242         return estimatedMg != null ? estimatedMg.getElementAt(0, 2) : null;
4243     }
4244 
4245     /**
4246      * Gets estimated gyroscope y-x cross-coupling error.
4247      *
4248      * @return estimated gyroscope y-x cross-coupling error or null
4249      * if not available.
4250      */
4251     @Override
4252     public Double getEstimatedMyx() {
4253         return estimatedMg != null ? estimatedMg.getElementAt(1, 0) : null;
4254     }
4255 
4256     /**
4257      * Gets estimated gyroscope y-z cross-coupling error.
4258      *
4259      * @return estimated gyroscope y-z cross-coupling error or null
4260      * if not available.
4261      */
4262     @Override
4263     public Double getEstimatedMyz() {
4264         return estimatedMg != null ? estimatedMg.getElementAt(1, 2) : null;
4265     }
4266 
4267     /**
4268      * Gets estimated gyroscope z-x cross-coupling error.
4269      *
4270      * @return estimated gyroscope z-x cross-coupling error or null
4271      * if not available.
4272      */
4273     @Override
4274     public Double getEstimatedMzx() {
4275         return estimatedMg != null ? estimatedMg.getElementAt(2, 0) : null;
4276     }
4277 
4278     /**
4279      * Gets estimated gyroscope z-y cross-coupling error.
4280      *
4281      * @return estimated gyroscope z-y cross-coupling error or null
4282      * if not available.
4283      */
4284     @Override
4285     public Double getEstimatedMzy() {
4286         return estimatedMg != null ? estimatedMg.getElementAt(2, 1) : null;
4287     }
4288 
4289     /**
4290      * Gets estimated G-dependent cross biases introduced on the gyroscope by the
4291      * specific forces sensed by the accelerometer.
4292      * This instance allows any 3x3 matrix.
4293      *
4294      * @return estimated G-dependent cross biases.
4295      */
4296     @Override
4297     public Matrix getEstimatedGg() {
4298         return estimatedGg;
4299     }
4300 
4301     /**
4302      * Gets estimated covariance matrix for estimated parameters.
4303      * Diagonal elements of the matrix contains variance for the following
4304      * parameters (following indicated order): sx, sy, sz, mxy, mxz, myx,
4305      * myz, mzx, mzy, gg11, gg21, gg31, gg12, gg22, gg32, gg13, gg23, gg33.
4306      *
4307      * @return estimated covariance matrix for estimated parameters.
4308      */
4309     @Override
4310     public Matrix getEstimatedCovariance() {
4311         return estimatedCovariance;
4312     }
4313 
4314     /**
4315      * Gets estimated chi square value.
4316      *
4317      * @return estimated chi square value.
4318      */
4319     @Override
4320     public double getEstimatedChiSq() {
4321         return estimatedChiSq;
4322     }
4323 
4324     /**
4325      * Gets estimated chi square degrees of freedom. Degrees of freedom is equal to the number of sampled data minus the
4326      * number of estimated parameters.
4327      *
4328      * @return estimated degrees of freedom of chi square value
4329      */
4330     @Override
4331     public int getEstimatedChiSqDegreesOfFreedom() {
4332         return estimatedChiSqDegreesOfFreedom;
4333     }
4334 
4335     /**
4336      * Gets estimated reduced chi square value. This is equal to estimated chi square value divided by its degrees of
4337      * freedom. Ideally this value should be close to 1.0, indicating that fit is optimal.
4338      * A value larger than 1.0 indicates that fit is not good or noise has been underestimated, and a value smaller than
4339      * 1.0 indicates that there is overfitting or noise has been overestimated.
4340      *
4341      * @return estimated reduced chi square value
4342      */
4343     @Override
4344     public double getEstimatedReducedChiSq() {
4345         return estimatedReducedChiSq;
4346     }
4347 
4348     /**
4349      * Gets estimated mean square error respect to provided measurements.
4350      *
4351      * @return estimated mean square error respect to provided measurements.
4352      */
4353     @Override
4354     public double getEstimatedMse() {
4355         return estimatedMse;
4356     }
4357 
4358     /**
4359      * Gets estimated probability of finding a smaller chi square value expressed as a value between 0.0 and 1.0. The
4360      * smaller the found chi square value is, the better the fit of the estimated parameters to the actual parameter.
4361      * Thus, the smaller the chance of finding a smaller chi square value, then the better the estimated fit is.
4362      *
4363      * @return estimated probability of finding a smaller chi square value.
4364      */
4365     @Override
4366     public double getEstimatedP() {
4367         return estimatedP;
4368     }
4369 
4370     /**
4371      * Gets estimated measure of quality of estimated fit as a value between 0.0 and 1.0. The larger the quality value
4372      * is, the better the fit that has been estimated.
4373      *
4374      * @return estimated measure of quality of estimated fit.
4375      */
4376     @Override
4377     public double getEstimatedQ() {
4378         return estimatedQ;
4379     }
4380 
4381     /**
4382      * Internal method to perform calibration when common z-axis is assumed
4383      * for both the accelerometer and gyroscope and when G-dependent cross
4384      * biases are being estimated.
4385      *
4386      * @throws AlgebraException                              if there are numerical errors.
4387      * @throws FittingException                              if no convergence to solution is found.
4388      * @throws com.irurueta.numerical.NotReadyException      if fitter is not ready.
4389      * @throws InvalidSourceAndDestinationFrameTypeException never happens
4390      */
4391     private void calibrateCommonAxisAndGDependentCrossBiases() throws AlgebraException, FittingException,
4392             com.irurueta.numerical.NotReadyException, InvalidSourceAndDestinationFrameTypeException {
4393 
4394         // The gyroscope model is
4395         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
4396 
4397         // Ideally a least squares solution tries to minimize noise component, so:
4398         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue
4399 
4400         // For convergence purposes of the Levenberg-Marquardt algorithm, we
4401         // take common factor M = I + Mg
4402 
4403         // and the gyroscope model can be better expressed as:
4404 
4405         // Ωmeas = M*(Ωtrue + b + G * ftrue)
4406 
4407         // where:
4408         // bg = M*b --> b = M^-1*bg
4409         // Gg = M*G --> G = M^-1*Gg
4410 
4411         // We know that the norm of the true angular rate when the device is in a pixed
4412         // and unknown position and orientation is equal to the Earth rotation rate.
4413         // ||Ωtrue|| = 7.292115E-5 rad/s
4414 
4415         // Hence
4416         // Ωmeas - M*b - M*G*ftrue = M*Ωtrue
4417         // M^-1 * (Ωmeas - M*b - M*G*ftrue) = Ωtrue
4418 
4419         // ||Ωtrue||^2 = (M^-1 * (Ωmeas - M*b - M*G*ftrue))^T*(M^-1 * (Ωmeas - M*b - M*G*ftrue))
4420         // ||Ωtrue||^2 = (Ωmeas - M*b - M*G*ftrue)^T * (M^-1)^T * M^-1 * (Ωmeas - M*b - M*G*ftrue)
4421         // ||Ωtrue||^2 = (Ωmeas - M*b - M*G*ftrue)^T * ||M^-1||^2 * (Ωmeas - M*b - M*G*ftrue)
4422         // ||Ωtrue||^2 = ||Ωmeas - M*b - M*G*ftrue||^2 * ||M^-1||^2
4423 
4424         // Where:
4425 
4426         // b = [bx]
4427         //     [by]
4428         //     [bz]
4429 
4430         // M = [m11 	m12 	m13]
4431         //     [0 		m22 	m23]
4432         //     [0 	 	0 		m33]
4433 
4434         // G = [g11 	g12 	g13]
4435         //     [g21 	g22 	g23]
4436         //     [g31 	g32 	g33]
4437 
4438         // ftrue = [ftruex]
4439         //         [ftruey]
4440         //         [fturez]
4441 
4442         final var gradientEstimator = new GradientEstimator(this::evaluateCommonAxisWitGDependentCrossBiases);
4443 
4444         final var initialM = Matrix.identity(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4445         initialM.add(getInitialMg());
4446 
4447         // Force initial M to be upper diagonal
4448         initialM.setElementAt(1, 0, 0.0);
4449         initialM.setElementAt(2, 0, 0.0);
4450         initialM.setElementAt(2, 1, 0.0);
4451 
4452         final var invInitM = Utils.inverse(initialM);
4453         final var initGg = getInitialGg();
4454         final var initG = invInitM.multiplyAndReturnNew(initGg);
4455 
4456         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiDimensionFunctionEvaluator() {
4457             @Override
4458             public int getNumberOfDimensions() {
4459                 // Input points are measured angular rate coordinates +
4460                 // measured specific force coordinates
4461                 return 2 * BodyKinematics.COMPONENTS;
4462             }
4463 
4464             @Override
4465             public double[] createInitialParametersArray() {
4466                 final var initial = new double[COMMON_Z_AXIS_UNKNOWNS_AND_CROSS_BIASES];
4467 
4468                 // upper diagonal cross coupling errors M
4469                 var k = 0;
4470                 for (var j = 0; j < BodyKinematics.COMPONENTS; j++) {
4471                     for (var i = 0; i < BodyKinematics.COMPONENTS; i++) {
4472                         if (i <= j) {
4473                             initial[k] = initialM.getElementAt(i, j);
4474                             k++;
4475                         }
4476                     }
4477                 }
4478 
4479                 // g-dependent cross biases G
4480                 final var num = BodyKinematics.COMPONENTS * BodyKinematics.COMPONENTS;
4481                 for (int i = 0, j = k; i < num; i++, j++) {
4482                     initial[j] = initG.getElementAtIndex(i);
4483                 }
4484 
4485                 return initial;
4486             }
4487 
4488             @Override
4489             public double evaluate(
4490                     final int i, final double[] point, final double[] params, final double[] derivatives)
4491                     throws EvaluationException {
4492 
4493                 measAngularRateX = point[0];
4494                 measAngularRateY = point[1];
4495                 measAngularRateZ = point[2];
4496 
4497                 fmeasX = point[3];
4498                 fmeasY = point[4];
4499                 fmeasZ = point[5];
4500 
4501                 gradientEstimator.gradient(params, derivatives);
4502 
4503                 return evaluateCommonAxisWitGDependentCrossBiases(params);
4504             }
4505         });
4506 
4507         setInputDataWithGDependentCrossBiases();
4508 
4509         fitter.fit();
4510 
4511         final var result = fitter.getA();
4512 
4513         final var m11 = result[0];
4514 
4515         final var m12 = result[1];
4516         final var m22 = result[2];
4517 
4518         final var m13 = result[3];
4519         final var m23 = result[4];
4520         final var m33 = result[5];
4521 
4522         final var g11 = result[6];
4523         final var g21 = result[7];
4524         final var g31 = result[8];
4525 
4526         final var g12 = result[9];
4527         final var g22 = result[10];
4528         final var g32 = result[11];
4529 
4530         final var g13 = result[12];
4531         final var g23 = result[13];
4532         final var g33 = result[14];
4533 
4534         final var mm = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4535         mm.setElementAtIndex(0, m11);
4536         mm.setElementAtIndex(1, 0.0);
4537         mm.setElementAtIndex(2, 0.0);
4538 
4539         mm.setElementAtIndex(3, m12);
4540         mm.setElementAtIndex(4, m22);
4541         mm.setElementAtIndex(5, 0.0);
4542 
4543         mm.setElementAtIndex(6, m13);
4544         mm.setElementAtIndex(7, m23);
4545         mm.setElementAtIndex(8, m33);
4546 
4547         final var mg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4548         mg.setElementAtIndex(0, g11);
4549         mg.setElementAtIndex(1, g21);
4550         mg.setElementAtIndex(2, g31);
4551 
4552         mg.setElementAtIndex(3, g12);
4553         mg.setElementAtIndex(4, g22);
4554         mg.setElementAtIndex(5, g32);
4555 
4556         mg.setElementAtIndex(6, g13);
4557         mg.setElementAtIndex(7, g23);
4558         mg.setElementAtIndex(8, g33);
4559 
4560         setResult(mm, mg);
4561 
4562         // at this point covariance is expressed in terms of M and G, and must
4563         // be expressed in terms of Mg and Gg.
4564         // We know that:
4565         // Mg = M - I
4566         // Gg = M * G
4567 
4568         // M = [m11  m12  m13]
4569         //     [0    m22  m23]
4570         //     [0    0    m33]
4571 
4572         // G = [g11  g12  g13]
4573         //     [g21  g22  g23]
4574         //     [g31  g32  g33]
4575 
4576         // Mg = [sx  mxy  mxz] = [m11 - 1    m12         m13     ]
4577         //      [myx sy	  myz]   [0          m22 - 1     m23     ]
4578         //      [mzx mzy  sz ]   [0          0           m33 - 1 ]
4579 
4580         // Gg = [gg11  gg12  gg13] = [m11  m12  m13][g11  g12  g13]
4581         //      [gg21  gg22  gg23]   [0    m22  m23][g21  g22  g23]
4582         //      [gg31  gg32  gg33]   [0    0    m33][g31  g32  g33]
4583 
4584         // Defining the linear application:
4585         // F(M, G) = F(m11, m12, m22, m32=0, m13, m23, m33, g11, g21, g31, g12, g22, g32, g13, g23, g33)
4586         // as:
4587         // [sx] =   [m11 - 1]
4588         // [sy]     [m22 - 1]
4589         // [sz]     [m33 - 1]
4590         // [mxy]    [m12]
4591         // [mxz]    [m13]
4592         // [myx]    [0]
4593         // [myz]    [m23]
4594         // [mzx]    [0]
4595         // [mzy]    [0]
4596         // [gg11]   [m11 * g11 + m12 * g21 + m13 * g31]
4597         // [gg21]   [            m22 * g21 + m23 * g31]
4598         // [gg31]   [                        m33 * g31]
4599         // [gg12]   [m11 * g12 + m12 * g22 + m13 * g32]
4600         // [gg22]   [            m22 * g22 + n23 * g32]
4601         // [gg32]   [                        m33 * g32]
4602         // [gg13]   [m11 * g13 + m12 * g23 + m13 * g33]
4603         // [gg23]   [            m22 * g23 + m23 * g33]
4604         // [gg33]   [                        m33 * g33]
4605 
4606         // Then the Jacobian of F(M, G) is:
4607         // J = [1    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4608         //     [0    0    1    0    0    0    0    0    0    0    0    0    0    0    0  ]
4609         //     [0    0    0    0    0    1    0    0    0    0    0    0    0    0    0  ]
4610         //     [0    1    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4611         //     [0    0    0    1    0    0    0    0    0    0    0    0    0    0    0  ]
4612         //     [0    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4613         //     [0    0    0    0    1    0    0    0    0    0    0    0    0    0    0  ]
4614         //     [0    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4615         //     [0    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4616         //     [g11  g21  0    g31  0    0    m11  m12  m13  0    0    0    0    0    0  ]
4617         //     [0    0    g21  0    g31  0    0    m22  m23  0    0    0    0    0    0  ]
4618         //     [0    0    0    0    0    g31  0    0    m33  0    0    0    0    0    0  ]
4619         //     [g12  g22  0    g32  0    0    0    0    0    m11  m12  m13  0    0    0  ]
4620         //     [0    0    g22  0    g32  0    0    0    0    0    m22  m23  0    0    0  ]
4621         //     [0    0    0    0    0    g32  0    0    0    0    0    m33  0    0    0  ]
4622         //     [g13  g23  0    g33  0    0    0    0    0    0    0    0    m11  m12  m13]
4623         //     [0    0    g23  0    g33  0    0    0    0    0    0    0    0    m22  m23]
4624         //     [0    0    0    0    0    g33  0    0    0    0    0    0    0    0    m33]
4625 
4626         // We know that the propagated covariance is J * Cov * J', hence:
4627         final var jacobian = new Matrix(GENERAL_UNKNOWNS_AND_CROSS_BIASES, COMMON_Z_AXIS_UNKNOWNS_AND_CROSS_BIASES);
4628 
4629         jacobian.setElementAt(0, 0, 1.0);
4630         jacobian.setElementAt(1, 2, 1.0);
4631         jacobian.setElementAt(2, 5, 1.0);
4632 
4633         jacobian.setElementAt(3, 1, 1.0);
4634         jacobian.setElementAt(4, 3, 1.0);
4635 
4636         jacobian.setElementAt(6, 4, 1.0);
4637 
4638         jacobian.setElementAt(9, 0, g11);
4639         jacobian.setElementAt(9, 1, g21);
4640         jacobian.setElementAt(9, 3, g31);
4641         jacobian.setElementAt(9, 6, m11);
4642         jacobian.setElementAt(9, 7, m12);
4643         jacobian.setElementAt(9, 8, m13);
4644 
4645         jacobian.setElementAt(10, 2, g21);
4646         jacobian.setElementAt(10, 4, g31);
4647         jacobian.setElementAt(10, 7, m22);
4648         jacobian.setElementAt(10, 8, m23);
4649 
4650         jacobian.setElementAt(11, 5, g31);
4651         jacobian.setElementAt(11, 8, m33);
4652 
4653         jacobian.setElementAt(12, 0, g12);
4654         jacobian.setElementAt(12, 1, g22);
4655         jacobian.setElementAt(12, 3, g32);
4656         jacobian.setElementAt(12, 9, m11);
4657         jacobian.setElementAt(12, 10, m12);
4658         jacobian.setElementAt(12, 11, m13);
4659 
4660         jacobian.setElementAt(13, 2, g22);
4661         jacobian.setElementAt(13, 4, g32);
4662         jacobian.setElementAt(13, 10, m22);
4663         jacobian.setElementAt(13, 11, m23);
4664 
4665         jacobian.setElementAt(14, 5, g32);
4666         jacobian.setElementAt(14, 11, m33);
4667 
4668         jacobian.setElementAt(15, 0, g13);
4669         jacobian.setElementAt(15, 1, g23);
4670         jacobian.setElementAt(15, 3, g33);
4671         jacobian.setElementAt(15, 12, m11);
4672         jacobian.setElementAt(15, 13, m12);
4673         jacobian.setElementAt(15, 14, m13);
4674 
4675         jacobian.setElementAt(16, 2, g23);
4676         jacobian.setElementAt(16, 4, g33);
4677         jacobian.setElementAt(16, 13, m22);
4678         jacobian.setElementAt(16, 14, m23);
4679 
4680         jacobian.setElementAt(17, 5, g33);
4681         jacobian.setElementAt(17, 14, m33);
4682 
4683         final var jacobianTrans = jacobian.transposeAndReturnNew();
4684         jacobian.multiply(estimatedCovariance);
4685         jacobian.multiply(jacobianTrans);
4686         estimatedCovariance = jacobian;
4687     }
4688 
4689     /**
4690      * Internal method to perform general calibration when G-dependent cross
4691      * biases are being estimated.
4692      *
4693      * @throws AlgebraException                              if there are numerical errors.
4694      * @throws FittingException                              if no convergence to solution is found.
4695      * @throws com.irurueta.numerical.NotReadyException      if fitter is not ready.
4696      * @throws InvalidSourceAndDestinationFrameTypeException never happens
4697      */
4698     private void calibrateGeneralAndGDependentCrossBiases() throws AlgebraException, FittingException,
4699             com.irurueta.numerical.NotReadyException, InvalidSourceAndDestinationFrameTypeException {
4700 
4701         // The gyroscope model is
4702         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
4703 
4704         // Ideally a least squares solution tries to minimize noise component, so:
4705         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue
4706 
4707         // For convergence purposes of the Levenberg-Marquardt algorithm, we
4708         // take common factor M = I + Mg
4709 
4710         // and the gyroscope model can be better expressed as:
4711 
4712         // Ωmeas = M*(Ωtrue + b + G * ftrue)
4713 
4714         // where:
4715         // bg = M*b --> b = M^-1*bg
4716         // Gg = M*G --> G = M^-1*Gg
4717 
4718         // We know that the norm of the true angular rate when the device is in a pixed
4719         // and unknown position and orientation is equal to the Earth rotation rate.
4720         // ||Ωtrue|| = 7.292115E-5 rad/s
4721 
4722         // Hence
4723         // Ωmeas - M*b - M*G*ftrue = M*Ωtrue
4724         // M^-1 * (Ωmeas - M*b - M*G*ftrue) = Ωtrue
4725 
4726         // ||Ωtrue||^2 = (M^-1 * (Ωmeas - M*b - M*G*ftrue))^T*(M^-1 * (Ωmeas - M*b - M*G*ftrue))
4727         // ||Ωtrue||^2 = (Ωmeas - M*b - M*G*ftrue)^T * (M^-1)^T * M^-1 * (Ωmeas - M*b - M*G*ftrue)
4728         // ||Ωtrue||^2 = (Ωmeas - M*b - M*G*ftrue)^T * ||M^-1||^2 * (Ωmeas - M*b - M*G*ftrue)
4729         // ||Ωtrue||^2 = ||Ωmeas - M*b - M*G*ftrue||^2 * ||M^-1||^2
4730 
4731         // Where:
4732 
4733         // b = [bx]
4734         //     [by]
4735         //     [bz]
4736 
4737         // M = [m11 	m12 	m13]
4738         //     [m21 	m22 	m23]
4739         //     [m31 	m32 	m33]
4740 
4741         // G = [g11 	g12 	g13]
4742         //     [g21 	g22 	g23]
4743         //     [g31 	g32 	g33]
4744 
4745         // ftrue = [ftruex]
4746         //         [ftruey]
4747         //         [fturez]
4748 
4749         final var gradientEstimator = new GradientEstimator(this::evaluateGeneralWitGDependentCrossBiases);
4750 
4751         final var initialM = Matrix.identity(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4752         initialM.add(getInitialMg());
4753 
4754         final var invInitM = Utils.inverse(initialM);
4755         final var initGg = getInitialGg();
4756         final var initG = invInitM.multiplyAndReturnNew(initGg);
4757 
4758         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiDimensionFunctionEvaluator() {
4759             @Override
4760             public int getNumberOfDimensions() {
4761                 // Input points are measured angular rate coordinates +
4762                 // measured specific force coordinates
4763                 return 2 * BodyKinematics.COMPONENTS;
4764             }
4765 
4766             @Override
4767             public double[] createInitialParametersArray() {
4768                 final var initial = new double[GENERAL_UNKNOWNS_AND_CROSS_BIASES];
4769 
4770                 // cross coupling errors M
4771                 final var num = BodyKinematics.COMPONENTS * BodyKinematics.COMPONENTS;
4772                 for (var i = 0; i < num; i++) {
4773                     initial[i] = initialM.getElementAtIndex(i);
4774                 }
4775 
4776                 // g-dependent cross biases G
4777                 for (int i = 0, j = num; i < num; i++, j++) {
4778                     initial[j] = initG.getElementAtIndex(i);
4779                 }
4780 
4781                 return initial;
4782             }
4783 
4784             @Override
4785             public double evaluate(
4786                     final int i, final double[] point, final double[] params, final double[] derivatives)
4787                     throws EvaluationException {
4788 
4789                 measAngularRateX = point[0];
4790                 measAngularRateY = point[1];
4791                 measAngularRateZ = point[2];
4792 
4793                 fmeasX = point[3];
4794                 fmeasY = point[4];
4795                 fmeasZ = point[5];
4796 
4797                 gradientEstimator.gradient(params, derivatives);
4798 
4799                 return evaluateGeneralWitGDependentCrossBiases(params);
4800             }
4801         });
4802 
4803         setInputDataWithGDependentCrossBiases();
4804 
4805         fitter.fit();
4806 
4807         final var result = fitter.getA();
4808 
4809         final var m11 = result[0];
4810         final var m21 = result[1];
4811         final var m31 = result[2];
4812 
4813         final var m12 = result[3];
4814         final var m22 = result[4];
4815         final var m32 = result[5];
4816 
4817         final var m13 = result[6];
4818         final var m23 = result[7];
4819         final var m33 = result[8];
4820 
4821         final var g11 = result[9];
4822         final var g21 = result[10];
4823         final var g31 = result[11];
4824 
4825         final var g12 = result[12];
4826         final var g22 = result[13];
4827         final var g32 = result[14];
4828 
4829         final var g13 = result[15];
4830         final var g23 = result[16];
4831         final var g33 = result[17];
4832 
4833         final var mm = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4834         mm.setElementAtIndex(0, m11);
4835         mm.setElementAtIndex(1, m21);
4836         mm.setElementAtIndex(2, m31);
4837 
4838         mm.setElementAtIndex(3, m12);
4839         mm.setElementAtIndex(4, m22);
4840         mm.setElementAtIndex(5, m32);
4841 
4842         mm.setElementAtIndex(6, m13);
4843         mm.setElementAtIndex(7, m23);
4844         mm.setElementAtIndex(8, m33);
4845 
4846         final var mg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4847         mg.setElementAtIndex(0, g11);
4848         mg.setElementAtIndex(1, g21);
4849         mg.setElementAtIndex(2, g31);
4850 
4851         mg.setElementAtIndex(3, g12);
4852         mg.setElementAtIndex(4, g22);
4853         mg.setElementAtIndex(5, g32);
4854 
4855         mg.setElementAtIndex(6, g13);
4856         mg.setElementAtIndex(7, g23);
4857         mg.setElementAtIndex(8, g33);
4858 
4859         setResult(mm, mg);
4860 
4861         // at this point covariance is expressed in terms of M and G, and must
4862         // be expressed in terms of Mg and Gg.
4863         // We know that:
4864         // Mg = M - I
4865         // Gg = M * G
4866 
4867         // M = [m11  m12  m13]
4868         //     [m21  m22  m23]
4869         //     [m31  m32  m33]
4870 
4871         // G = [g11  g12  g13]
4872         //     [g21  g22  g23]
4873         //     [g31  g32  g33]
4874 
4875         // Mg = [sx  mxy  mxz] = [m11 - 1    m12         m13     ]
4876         //      [myx sy	  myz]   [m21        m22 - 1     m23     ]
4877         //      [mzx mzy  sz ]   [m31        m32         m33 - 1 ]
4878 
4879         // Gg = [gg11  gg12  gg13] = [m11  m12  m13][g11  g12  g13]
4880         //      [gg21  gg22  gg23]   [m21  m22  m23][g21  g22  g23]
4881         //      [gg31  gg32  gg33]   [m31  m32  m33][g31  g32  g33]
4882 
4883         // Defining the linear application:
4884         // F(M, G) = F(m11, m21, m31, m12, m22, m32, m13, m23, m33, g11, g21, g31, g12, g22, g32, g13, g23, g33)
4885         // as:
4886         // [sx] =   [m11 - 1]
4887         // [sy]     [m22 - 1]
4888         // [sz]     [m33 - 1]
4889         // [mxy]    [m12]
4890         // [mxz]    [m13]
4891         // [myx]    [m21]
4892         // [myz]    [m23]
4893         // [mzx]    [m31]
4894         // [mzy]    [m32]
4895         // [gg11]   [m11 * g11 + m12 * g21 + m13 * g31]
4896         // [gg21]   [m21 * g11 + m22 * g21 + m23 * g31]
4897         // [gg31]   [m31 * g11 + m32 * g21 + m33 * g31]
4898         // [gg12]   [m11 * g12 + m12 * g22 + m13 * g32]
4899         // [gg22]   [m21 * g12 + m22 * g22 + n23 * g32]
4900         // [gg32]   [m31 * g12 + m32 * g22 + m33 * g32]
4901         // [gg13]   [m11 * g13 + m12 * g23 + m13 * g33]
4902         // [gg23]   [m21 * g13 + m22 * g23 + m23 * g33]
4903         // [gg33]   [m31 * g13 + m32 * g23 + m33 * g33]
4904 
4905         // Then the Jacobian of F(M, G) is:
4906         // J = [1    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4907         //     [0    0    0    0    1    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4908         //     [0    0    0    0    0    0    0    0    1    0    0    0    0    0    0    0    0    0  ]
4909         //     [0    0    0    1    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4910         //     [0    0    0    0    0    0    1    0    0    0    0    0    0    0    0    0    0    0  ]
4911         //     [0    1    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4912         //     [0    0    0    0    0    0    0    1    0    0    0    0    0    0    0    0    0    0  ]
4913         //     [0    0    1    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0  ]
4914         //     [0    0    0    0    0    1    0    0    0    0    0    0    0    0    0    0    0    0  ]
4915         //     [g11  0    0    g21  0    0    g31  0    0    m11  m12  m13  0    0    0    0    0    0  ]
4916         //     [0    g11  0    0    g21  0    0    g31  0    m21  m22  m23  0    0    0    0    0    0  ]
4917         //     [0    0    g11  0    0    g21  0    0    g31  m31  m32  m33  0    0    0    0    0    0  ]
4918         //     [g12  0    0    g22  0    0    g32  0    0    0    0    0    m11  m12  m13  0    0    0  ]
4919         //     [0    g12  0    0    g22  0    0    g32  0    0    0    0    m21  m22  m23  0    0    0  ]
4920         //     [0    0    g12  0    0    g22  0    0    g32  0    0    0    m31  m32  m33  0    0    0  ]
4921         //     [g13  0    0    g23  0    0    g33  0    0    0    0    0    0    0    0    m11  m12  m13]
4922         //     [0    g13  0    0    g23  0    0    g33  0    0    0    0    0    0    0    m21  m22  m23]
4923         //     [0    0    g13  0    0    g23  0    0    g33  0    0    0    0    0    0    m31  m32  m33]
4924 
4925         // We know that the propagated covariance is J * Cov * J', hence:
4926         final var jacobian = new Matrix(GENERAL_UNKNOWNS_AND_CROSS_BIASES, GENERAL_UNKNOWNS_AND_CROSS_BIASES);
4927 
4928         jacobian.setElementAt(0, 0, 1.0);
4929         jacobian.setElementAt(1, 4, 1.0);
4930         jacobian.setElementAt(2, 8, 1.0);
4931 
4932         jacobian.setElementAt(3, 3, 1.0);
4933         jacobian.setElementAt(4, 6, 1.0);
4934         jacobian.setElementAt(5, 1, 1.0);
4935 
4936         jacobian.setElementAt(6, 7, 1.0);
4937         jacobian.setElementAt(7, 2, 1.0);
4938         jacobian.setElementAt(8, 5, 1.9);
4939 
4940         jacobian.setElementAt(9, 0, g11);
4941         jacobian.setElementAt(9, 3, g21);
4942         jacobian.setElementAt(9, 6, g31);
4943         jacobian.setElementAt(9, 9, m11);
4944         jacobian.setElementAt(9, 10, m12);
4945         jacobian.setElementAt(9, 11, m13);
4946 
4947         jacobian.setElementAt(10, 1, g11);
4948         jacobian.setElementAt(10, 4, g21);
4949         jacobian.setElementAt(10, 7, g31);
4950         jacobian.setElementAt(10, 9, m21);
4951         jacobian.setElementAt(10, 10, m22);
4952         jacobian.setElementAt(10, 11, m23);
4953 
4954         jacobian.setElementAt(11, 2, g11);
4955         jacobian.setElementAt(11, 5, g21);
4956         jacobian.setElementAt(11, 8, g31);
4957         jacobian.setElementAt(11, 9, m31);
4958         jacobian.setElementAt(11, 10, m32);
4959         jacobian.setElementAt(11, 11, m33);
4960 
4961         jacobian.setElementAt(12, 0, g12);
4962         jacobian.setElementAt(12, 3, g22);
4963         jacobian.setElementAt(12, 6, g32);
4964         jacobian.setElementAt(12, 12, m11);
4965         jacobian.setElementAt(12, 13, m12);
4966         jacobian.setElementAt(12, 14, m13);
4967 
4968         jacobian.setElementAt(13, 1, g12);
4969         jacobian.setElementAt(13, 4, g22);
4970         jacobian.setElementAt(13, 7, g32);
4971         jacobian.setElementAt(13, 12, m21);
4972         jacobian.setElementAt(13, 13, m22);
4973         jacobian.setElementAt(13, 14, m23);
4974 
4975         jacobian.setElementAt(14, 2, g12);
4976         jacobian.setElementAt(14, 5, g22);
4977         jacobian.setElementAt(14, 8, g32);
4978         jacobian.setElementAt(14, 12, m31);
4979         jacobian.setElementAt(14, 13, m32);
4980         jacobian.setElementAt(14, 14, m33);
4981 
4982         jacobian.setElementAt(15, 0, g13);
4983         jacobian.setElementAt(15, 3, g23);
4984         jacobian.setElementAt(15, 6, g33);
4985         jacobian.setElementAt(15, 15, m11);
4986         jacobian.setElementAt(15, 16, m12);
4987         jacobian.setElementAt(15, 17, m13);
4988 
4989         jacobian.setElementAt(16, 1, g13);
4990         jacobian.setElementAt(16, 4, g23);
4991         jacobian.setElementAt(16, 7, g33);
4992         jacobian.setElementAt(16, 15, m21);
4993         jacobian.setElementAt(16, 16, m22);
4994         jacobian.setElementAt(16, 17, m23);
4995 
4996         jacobian.setElementAt(17, 2, g13);
4997         jacobian.setElementAt(17, 5, g23);
4998         jacobian.setElementAt(17, 8, g33);
4999         jacobian.setElementAt(17, 15, m31);
5000         jacobian.setElementAt(17, 16, m32);
5001         jacobian.setElementAt(17, 17, m33);
5002 
5003         final var jacobianTrans = jacobian.transposeAndReturnNew();
5004         jacobian.multiply(estimatedCovariance);
5005         jacobian.multiply(jacobianTrans);
5006         estimatedCovariance = jacobian;
5007     }
5008 
5009     /**
5010      * Internal method to perform calibration when common z-axis is assumed for both
5011      * the accelerometer and gyroscope and G-dependent cross biases are ignored.
5012      *
5013      * @throws AlgebraException                              if there are numerical errors.
5014      * @throws FittingException                              if no convergence to solution is found.
5015      * @throws com.irurueta.numerical.NotReadyException      if fitter is not ready.
5016      * @throws InvalidSourceAndDestinationFrameTypeException never happens.
5017      */
5018     private void calibrateCommonAxis() throws AlgebraException, FittingException,
5019             com.irurueta.numerical.NotReadyException, InvalidSourceAndDestinationFrameTypeException {
5020 
5021         // The gyroscope model is
5022         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
5023 
5024         // Ideally a least squares solution tries to minimize noise component, so:
5025         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue
5026 
5027         // Since G-dependent cross biases are ignored, we can assume that Gg = 0
5028 
5029         // Hence:
5030         // Ωmeas = bg + (I + Mg) * Ωtrue
5031 
5032         // For convergence purposes of the Levenberg-Marquardt algorithm, the
5033         // gyroscope model can be better expressed as:
5034         // Ωmeas = T*K*(Ωtrue + b)
5035         // Ωmeas = M*(Ωtrue + b)
5036         // Ωmeas = M*Ωtrue + M*b
5037 
5038         // where:
5039         // M = I + Mg
5040         // bg = M*b = (I + Mg)*b --> b = M^-1*bg
5041 
5042         // We know that the norm of the true angular rate when the device is in a pixed
5043         // and unknown position and orientation is equal to the Earth rotation rate.
5044         // ||Ωtrue|| = 7.292115E-5 rad/s
5045 
5046         // Hence
5047         // Ωmeas - M*b = M*Ωtrue
5048 
5049         // M^-1 * (Ωmeas - M*b) = Ωtrue
5050 
5051         // ||Ωtrue||^2 = (M^-1 * (Ωmeas - M*b))^T*(M^-1 * (Ωmeas - M*b))
5052         // ||Ωtrue||^2 = (Ωmeas - M*b)^T * (M^-1)^T * M^-1 * (Ωmeas - M*b)
5053         // ||Ωtrue||^2 = (Ωmeas - M*b)^T * ||M^-1||^2 * (Ωmeas - M*b)
5054         // ||Ωtrue||^2 = ||Ωmeas - M*b||^2 * ||M^-1||^2
5055 
5056         // Where:
5057 
5058         // b = [bx]
5059         //     [by]
5060         //     [bz]
5061 
5062         // M = [m11 	m12 	m13]
5063         //     [0 		m22 	m23]
5064         //     [0 	 	0 		m33]
5065 
5066         final var gradientEstimator = new GradientEstimator(this::evaluateCommonAxis);
5067 
5068         final var initialM = Matrix.identity(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5069         initialM.add(getInitialMg());
5070 
5071         // Force initial M to be upper diagonal
5072         initialM.setElementAt(1, 0, 0.0);
5073         initialM.setElementAt(2, 0, 0.0);
5074         initialM.setElementAt(2, 1, 0.0);
5075 
5076         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiDimensionFunctionEvaluator() {
5077             @Override
5078             public int getNumberOfDimensions() {
5079                 // Input points are measured angular rate coordinates
5080                 return BodyKinematics.COMPONENTS;
5081             }
5082 
5083             @Override
5084             public double[] createInitialParametersArray() {
5085                 final var initial = new double[COMMON_Z_AXIS_UNKNOWNS];
5086 
5087                 // upper diagonal cross coupling errors M
5088                 var k = 0;
5089                 for (var j = 0; j < BodyKinematics.COMPONENTS; j++) {
5090                     for (var i = 0; i < BodyKinematics.COMPONENTS; i++) {
5091                         if (i <= j) {
5092                             initial[k] = initialM.getElementAt(i, j);
5093                             k++;
5094                         }
5095                     }
5096                 }
5097 
5098                 return initial;
5099             }
5100 
5101             @Override
5102             public double evaluate(
5103                     final int i, final double[] point, final double[] params, final double[] derivatives)
5104                     throws EvaluationException {
5105 
5106                 measAngularRateX = point[0];
5107                 measAngularRateY = point[1];
5108                 measAngularRateZ = point[2];
5109 
5110                 gradientEstimator.gradient(params, derivatives);
5111 
5112                 return evaluateCommonAxis(params);
5113             }
5114         });
5115 
5116         setInputData();
5117 
5118         fitter.fit();
5119 
5120         final var result = fitter.getA();
5121 
5122         final var m11 = result[0];
5123 
5124         final var m12 = result[1];
5125         final var m22 = result[2];
5126 
5127         final var m13 = result[3];
5128         final var m23 = result[4];
5129         final var m33 = result[5];
5130 
5131         final var mm = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5132         mm.setElementAtIndex(0, m11);
5133         mm.setElementAtIndex(1, 0.0);
5134         mm.setElementAtIndex(2, 0.0);
5135 
5136         mm.setElementAtIndex(3, m12);
5137         mm.setElementAtIndex(4, m22);
5138         mm.setElementAtIndex(5, 0.0);
5139 
5140         mm.setElementAtIndex(6, m13);
5141         mm.setElementAtIndex(7, m23);
5142         mm.setElementAtIndex(8, m33);
5143 
5144         setResult(mm);
5145 
5146         // at this point covariance is expressed in terms of M, and must
5147         // be expressed in terms of Mg.
5148         // We know that:
5149         // Mg = M - I
5150         // Gg = M * G
5151 
5152         // M = [m11  m12  m13]
5153         //     [0    m22  m23]
5154         //     [0    0    m33]
5155 
5156         // G = [g11  g12  g13] = 0
5157         //     [g21  g22  g23]
5158         //     [g31  g32  g33]
5159 
5160         // Mg = [sx  mxy  mxz] = [m11 - 1    m12         m13     ]
5161         //      [myx sy	  myz]   [0          m22 - 1     m23     ]
5162         //      [mzx mzy  sz ]   [0          0           m33 - 1 ]
5163 
5164         // Gg = [gg11  gg12  gg13] = [m11  m12  m13][g11  g12  g13]
5165         //      [gg21  gg22  gg23]   [0    m22  m23][g21  g22  g23]
5166         //      [gg31  gg32  gg33]   [0    0    m33][g31  g32  g33]
5167 
5168         // Defining the linear application:
5169         // F(M) = F(m11, m12, m22, m32=0, m13, m23, m33)
5170         // as:
5171         // [sx] =   [m11 - 1]
5172         // [sy]     [m22 - 1]
5173         // [sz]     [m33 - 1]
5174         // [mxy]    [m12]
5175         // [mxz]    [m13]
5176         // [myx]    [0]
5177         // [myz]    [m23]
5178         // [mzx]    [0]
5179         // [mzy]    [0]
5180         // [gg11]   [0]
5181         // [gg21]   [0]
5182         // [gg31]   [0]
5183         // [gg12]   [0]
5184         // [gg22]   [0]
5185         // [gg32]   [0]
5186         // [gg13]   [0]
5187         // [gg23]   [0]
5188         // [gg33]   [0]
5189 
5190         // Then the Jacobian of F(M) is:
5191         // J = [1    0    0    0    0    0]
5192         //     [0    0    1    0    0    0]
5193         //     [0    0    0    0    0    1]
5194         //     [0    1    0    0    0    0]
5195         //     [0    0    0    1    0    0]
5196         //     [0    0    0    0    0    0]
5197         //     [0    0    0    0    1    0]
5198         //     [0    0    0    0    0    0]
5199         //     [0    0    0    0    0    0]
5200         //     [0    0    0    0    0    0]
5201         //     [0    0    0    0    0    0]
5202         //     [0    0    0    0    0    0]
5203         //     [0    0    0    0    0    0]
5204         //     [0    0    0    0    0    0]
5205         //     [0    0    0    0    0    0]
5206         //     [0    0    0    0    0    0]
5207         //     [0    0    0    0    0    0]
5208         //     [0    0    0    0    0    0]
5209 
5210         // We know that the propagated covariance is J * Cov * J', hence:
5211         final var jacobian = new Matrix(GENERAL_UNKNOWNS_AND_CROSS_BIASES, COMMON_Z_AXIS_UNKNOWNS);
5212 
5213         jacobian.setElementAt(0, 0, 1.0);
5214         jacobian.setElementAt(1, 2, 1.0);
5215         jacobian.setElementAt(2, 5, 1.0);
5216 
5217         jacobian.setElementAt(3, 1, 1.0);
5218         jacobian.setElementAt(4, 3, 1.0);
5219 
5220         jacobian.setElementAt(6, 4, 1.0);
5221 
5222         final var jacobianTrans = jacobian.transposeAndReturnNew();
5223         jacobian.multiply(estimatedCovariance);
5224         jacobian.multiply(jacobianTrans);
5225         estimatedCovariance = jacobian;
5226     }
5227 
5228     /**
5229      * Internal method to perform general calibration when G-dependent cross biases
5230      * are ignored.
5231      *
5232      * @throws AlgebraException                              if there are numerical errors.
5233      * @throws FittingException                              if no convergence to solution is found.
5234      * @throws com.irurueta.numerical.NotReadyException      if fitter is not ready.
5235      * @throws InvalidSourceAndDestinationFrameTypeException never happens.
5236      */
5237     private void calibrateGeneral() throws AlgebraException, FittingException, com.irurueta.numerical.NotReadyException,
5238             InvalidSourceAndDestinationFrameTypeException {
5239 
5240         // The gyroscope model is
5241         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
5242 
5243         // Ideally a least squares solution tries to minimize noise component, so:
5244         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue
5245 
5246         // Since G-dependent cross giases are ignored, we can assume that Gg = 0
5247 
5248         // Hence:
5249         // Ωmeas = bg + (I + Mg) * Ωtrue
5250 
5251         // For convergence purposes of the Levenberg-Marquardt algorithm, the
5252         // gyroscope model can be better expressed as:
5253         // Ωmeas = T*K*(Ωtrue + b)
5254         // Ωmeas = M*(Ωtrue + b)
5255         // Ωmeas = M*Ωtrue + M*b
5256 
5257         // where:
5258         // M = I + Mg
5259         // bg = M*b = (I + Mg)*b --> b = M^-1*bg
5260 
5261         // We know that the norm of the true angular rate when the device is in a pixed
5262         // and unknown position and orientation is equal to the Earth rotation rate.
5263         // ||Ωtrue|| = 7.292115E-5 rad/s
5264 
5265         // Hence
5266         // Ωmeas - M*b = M*Ωtrue
5267 
5268         // M^-1 * (Ωmeas - M*b) = Ωtrue
5269 
5270         // ||Ωtrue||^2 = (M^-1 * (Ωmeas - M*b))^T*(M^-1 * (Ωmeas - M*b))
5271         // ||Ωtrue||^2 = (Ωmeas - M*b)^T * (M^-1)^T * M^-1 * (Ωmeas - M*b)
5272         // ||Ωtrue||^2 = (Ωmeas - M*b)^T * ||M^-1||^2 * (Ωmeas - M*b)
5273         // ||Ωtrue||^2 = ||Ωmeas - M*b||^2 * ||M^-1||^2
5274 
5275         // Where:
5276 
5277         // b = [bx]
5278         //     [by]
5279         //     [bz]
5280 
5281         // M = [m11 	m12 	m13]
5282         //     [m21 	m22 	m23]
5283         //     [m31 	m32 	m33]
5284 
5285         final var gradientEstimator = new GradientEstimator(this::evaluateGeneral);
5286 
5287         final var initialM = Matrix.identity(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5288         initialM.add(getInitialMg());
5289 
5290         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiDimensionFunctionEvaluator() {
5291             @Override
5292             public int getNumberOfDimensions() {
5293                 // Input points are measured angular rate coordinates
5294                 return BodyKinematics.COMPONENTS;
5295             }
5296 
5297             @Override
5298             public double[] createInitialParametersArray() {
5299                 return initialM.toArray();
5300             }
5301 
5302             @Override
5303             public double evaluate(
5304                     final int i, final double[] point, final double[] params, final double[] derivatives)
5305                     throws EvaluationException {
5306 
5307                 measAngularRateX = point[0];
5308                 measAngularRateY = point[1];
5309                 measAngularRateZ = point[2];
5310 
5311                 gradientEstimator.gradient(params, derivatives);
5312 
5313                 return evaluateGeneral(params);
5314             }
5315         });
5316 
5317         setInputData();
5318 
5319         fitter.fit();
5320 
5321         final var result = fitter.getA();
5322 
5323         final var m11 = result[0];
5324         final var m21 = result[1];
5325         final var m31 = result[2];
5326 
5327         final var m12 = result[3];
5328         final var m22 = result[4];
5329         final var m32 = result[5];
5330 
5331         final var m13 = result[6];
5332         final var m23 = result[7];
5333         final var m33 = result[8];
5334 
5335         final var mm = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5336         mm.setElementAtIndex(0, m11);
5337         mm.setElementAtIndex(1, m21);
5338         mm.setElementAtIndex(2, m31);
5339 
5340         mm.setElementAtIndex(3, m12);
5341         mm.setElementAtIndex(4, m22);
5342         mm.setElementAtIndex(5, m32);
5343 
5344         mm.setElementAtIndex(6, m13);
5345         mm.setElementAtIndex(7, m23);
5346         mm.setElementAtIndex(8, m33);
5347 
5348         setResult(mm);
5349 
5350         // at this point covariance is expressed in terms of M, and must
5351         // be expressed in terms of Mg.
5352         // We know that:
5353         // Mg = M - I
5354         // Gg = M * G
5355 
5356         // M = [m11  m12  m13]
5357         //     [m21  m22  m23]
5358         //     [m31  m32  m33]
5359 
5360         // G = [g11  g12  g13] = 0
5361         //     [g21  g22  g23]
5362         //     [g31  g32  g33]
5363 
5364         // Mg = [sx  mxy  mxz] = [m11 - 1    m12         m13     ]
5365         //      [myx sy	  myz]   [m21        m22 - 1     m23     ]
5366         //      [mzx mzy  sz ]   [m31        m32         m33 - 1 ]
5367 
5368         // Gg = [gg11  gg12  gg13] = [m11  m12  m13][g11  g12  g13]
5369         //      [gg21  gg22  gg23]   [m21  m22  m23][g21  g22  g23]
5370         //      [gg31  gg32  gg33]   [m31  m32  m33][g31  g32  g33]
5371 
5372         // Defining the linear application:
5373         // F(M) = F(m11, m21, m31, m12, m22, m32, m13, m23, m33)
5374         // as:
5375         // [sx] =   [m11 - 1]
5376         // [sy]     [m22 - 1]
5377         // [sz]     [m33 - 1]
5378         // [mxy]    [m12]
5379         // [mxz]    [m13]
5380         // [myx]    [m21]
5381         // [myz]    [m23]
5382         // [mzx]    [m31]
5383         // [mzy]    [m32]
5384         // [gg11]   [0]
5385         // [gg21]   [0]
5386         // [gg31]   [0]
5387         // [gg12]   [0]
5388         // [gg22]   [0]
5389         // [gg32]   [0]
5390         // [gg13]   [0]
5391         // [gg23]   [0]
5392         // [gg33]   [0]
5393 
5394         // Then the Jacobian of F(M) is:
5395         // J = [1    0    0    0    0    0    0    0    0]
5396         //     [0    0    0    0    1    0    0    0    0]
5397         //     [0    0    0    0    0    0    0    0    1]
5398         //     [0    0    0    1    0    0    0    0    0]
5399         //     [0    0    0    0    0    0    1    0    0]
5400         //     [0    1    0    0    0    0    0    0    0]
5401         //     [0    0    0    0    0    0    0    1    0]
5402         //     [0    0    1    0    0    0    0    0    0]
5403         //     [0    0    0    0    0    1    0    0    0]
5404         //     [0    0    0    0    0    0    0    0    0]
5405         //     [0    0    0    0    0    0    0    0    0]
5406         //     [0    0    0    0    0    0    0    0    0]
5407         //     [0    0    0    0    0    0    0    0    0]
5408         //     [0    0    0    0    0    0    0    0    0]
5409         //     [0    0    0    0    0    0    0    0    0]
5410         //     [0    0    0    0    0    0    0    0    0]
5411         //     [0    0    0    0    0    0    0    0    0]
5412         //     [0    0    0    0    0    0    0    0    0]
5413 
5414         // We know that the propagated covariance is J * Cov * J', hence:
5415         final var jacobian = new Matrix(GENERAL_UNKNOWNS_AND_CROSS_BIASES, GENERAL_UNKNOWNS);
5416 
5417         jacobian.setElementAt(0, 0, 1.0);
5418         jacobian.setElementAt(1, 4, 1.0);
5419         jacobian.setElementAt(2, 8, 1.0);
5420 
5421         jacobian.setElementAt(3, 3, 1.0);
5422         jacobian.setElementAt(4, 6, 1.0);
5423         jacobian.setElementAt(5, 1, 1.0);
5424 
5425         jacobian.setElementAt(6, 7, 1.0);
5426         jacobian.setElementAt(7, 2, 1.0);
5427         jacobian.setElementAt(8, 5, 1.9);
5428 
5429         final var jacobianTrans = jacobian.transposeAndReturnNew();
5430         jacobian.multiply(estimatedCovariance);
5431         jacobian.multiply(jacobianTrans);
5432         estimatedCovariance = jacobian;
5433     }
5434 
5435     /**
5436      * Sets input data into Levenberg-Marquardt fitter when G-dependent cross biases
5437      * are taken into account.
5438      *
5439      * @throws AlgebraException                              if provided accelerometer cross coupling
5440      *                                                       errors are not valid.
5441      * @throws InvalidSourceAndDestinationFrameTypeException never happens
5442      */
5443     private void setInputDataWithGDependentCrossBiases()
5444             throws AlgebraException, InvalidSourceAndDestinationFrameTypeException {
5445         // compute reference frame at current position
5446         final var nedPosition = getNedPosition();
5447         final var nedC = new CoordinateTransformation(FrameType.BODY_FRAME, FrameType.LOCAL_NAVIGATION_FRAME);
5448         final var nedFrame = new NEDFrame(nedPosition, nedC);
5449         final var ecefFrame = NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(nedFrame);
5450         final var refKinematics = ECEFKinematicsEstimator.estimateKinematicsAndReturnNew(timeInterval, ecefFrame,
5451                 ecefFrame);
5452 
5453         final var refAngularRateX = refKinematics.getAngularRateX();
5454         final var refAngularRateY = refKinematics.getAngularRateY();
5455         final var refAngularRateZ = refKinematics.getAngularRateZ();
5456 
5457         final var w2 = turntableRotationRate * turntableRotationRate;
5458 
5459         final var numMeasurements = measurements.size();
5460         final var x = new Matrix(numMeasurements, 2 * BodyKinematics.COMPONENTS);
5461         final var y = new double[numMeasurements];
5462         final var angularRateStandardDeviations = new double[numMeasurements];
5463         var i = 0;
5464         for (final var measurement : measurements) {
5465             final var measuredKinematics = measurement.getKinematics();
5466 
5467             final var angularRateX = measuredKinematics.getAngularRateX();
5468             final var angularRateY = measuredKinematics.getAngularRateY();
5469             final var angularRateZ = measuredKinematics.getAngularRateZ();
5470 
5471             final var fX = measuredKinematics.getFx();
5472             final var fY = measuredKinematics.getFy();
5473             final var fZ = measuredKinematics.getFz();
5474 
5475             x.setElementAt(i, 0, angularRateX - refAngularRateX);
5476             x.setElementAt(i, 1, angularRateY - refAngularRateY);
5477             x.setElementAt(i, 2, angularRateZ - refAngularRateZ);
5478 
5479             x.setElementAt(i, 3, fX);
5480             x.setElementAt(i, 4, fY);
5481             x.setElementAt(i, 5, fZ);
5482 
5483             y[i] = w2;
5484 
5485             angularRateStandardDeviations[i] = measurement.getAngularRateStandardDeviation();
5486 
5487             i++;
5488         }
5489 
5490         fitter.setInputData(x, y, angularRateStandardDeviations);
5491 
5492         ba = getAccelerometerBiasAsMatrix();
5493         ma = getAccelerometerMa();
5494         accelerationFixer.setBias(ba);
5495         accelerationFixer.setCrossCouplingErrors(ma);
5496     }
5497 
5498     /**
5499      * Sets input data into Levenberg-Marquardt fitter when G-dependent cross biases
5500      * are ignored.
5501      *
5502      * @throws AlgebraException                              if provided accelerometer cross coupling
5503      *                                                       errors are not valid.
5504      * @throws InvalidSourceAndDestinationFrameTypeException never happens.
5505      */
5506     private void setInputData() throws AlgebraException, InvalidSourceAndDestinationFrameTypeException {
5507 
5508         // compute reference frame at current position
5509         final var nedPosition = getNedPosition();
5510         final var nedC = new CoordinateTransformation(FrameType.BODY_FRAME, FrameType.LOCAL_NAVIGATION_FRAME);
5511         final var nedFrame = new NEDFrame(nedPosition, nedC);
5512         final var ecefFrame = NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(nedFrame);
5513         final var refKinematics = ECEFKinematicsEstimator.estimateKinematicsAndReturnNew(timeInterval, ecefFrame,
5514                 ecefFrame);
5515 
5516         final var refAngularRateX = refKinematics.getAngularRateX();
5517         final var refAngularRateY = refKinematics.getAngularRateY();
5518         final var refAngularRateZ = refKinematics.getAngularRateZ();
5519 
5520         final var w2 = turntableRotationRate * turntableRotationRate;
5521 
5522         final var numMeasurements = measurements.size();
5523         final var x = new Matrix(numMeasurements, BodyKinematics.COMPONENTS);
5524         final var y = new double[numMeasurements];
5525         final var angularRateStandardDeviations = new double[numMeasurements];
5526         var i = 0;
5527         for (final var measurement : measurements) {
5528             final var measuredKinematics = measurement.getKinematics();
5529 
5530             final var angularRateX = measuredKinematics.getAngularRateX();
5531             final var angularRateY = measuredKinematics.getAngularRateY();
5532             final var angularRateZ = measuredKinematics.getAngularRateZ();
5533 
5534             x.setElementAt(i, 0, angularRateX - refAngularRateX);
5535             x.setElementAt(i, 1, angularRateY - refAngularRateY);
5536             x.setElementAt(i, 2, angularRateZ - refAngularRateZ);
5537 
5538             y[i] = w2;
5539 
5540             angularRateStandardDeviations[i] = measurement.getAngularRateStandardDeviation();
5541 
5542             i++;
5543         }
5544 
5545         fitter.setInputData(x, y, angularRateStandardDeviations);
5546 
5547         ba = getAccelerometerBiasAsMatrix();
5548         ma = getAccelerometerMa();
5549         accelerationFixer.setBias(ba);
5550         accelerationFixer.setCrossCouplingErrors(ma);
5551     }
5552 
5553     /**
5554      * Converts provided NED position expressed in terms of latitude, longitude and height respect
5555      * mean Earth surface, to position expressed in ECEF coordinates.
5556      *
5557      * @param position NED position to be converted.
5558      * @return converted position expressed in ECEF coordinates.
5559      */
5560     private static ECEFPosition convertPosition(final NEDPosition position) {
5561         final var velocity = new ECEFVelocity();
5562         final var result = new ECEFPosition();
5563         NEDtoECEFPositionVelocityConverter.convertNEDtoECEF(
5564                 position.getLatitude(), position.getLongitude(), position.getHeight(), 0.0, 0.0, 0.0,
5565                 result, velocity);
5566         return result;
5567     }
5568 
5569     /**
5570      * Converts acceleration instance to meters per squared second.
5571      *
5572      * @param acceleration acceleration instance to be converted.
5573      * @return converted value.
5574      */
5575     private static double convertAcceleration(final Acceleration acceleration) {
5576         return AccelerationConverter.convert(acceleration.getValue().doubleValue(), acceleration.getUnit(),
5577                 AccelerationUnit.METERS_PER_SQUARED_SECOND);
5578     }
5579 
5580     /**
5581      * Converts angular speed instance to radians per second (rad/s).
5582      *
5583      * @param value angular speed value.
5584      * @param unit  unit of angular speed value.
5585      * @return converted value.
5586      */
5587     private static double convertAngularSpeed(final double value, final AngularSpeedUnit unit) {
5588         return AngularSpeedConverter.convert(value, unit, AngularSpeedUnit.RADIANS_PER_SECOND);
5589     }
5590 
5591     /**
5592      * Converts angular speed instance to radians per second (rad/s).
5593      *
5594      * @param angularSpeed angular speed instance to be converted.
5595      * @return converted value.
5596      */
5597     private static double convertAngularSpeed(final AngularSpeed angularSpeed) {
5598         return convertAngularSpeed(angularSpeed.getValue().doubleValue(), angularSpeed.getUnit());
5599     }
5600 
5601     /**
5602      * Converts time instance to seconds.
5603      *
5604      * @param time time instance to be converted.
5605      * @return converted value.
5606      */
5607     private static double convertTime(final Time time) {
5608         return TimeConverter.convert(time.getValue().doubleValue(), time.getUnit(), TimeUnit.SECOND);
5609     }
5610 
5611     /**
5612      * Makes proper conversion of internal cross-coupling and g-dependent
5613      * cross bias matrices.
5614      *
5615      * @param m internal scaling and cross-coupling matrix.
5616      * @param g internal g-dependent cross bias matrix.
5617      * @throws AlgebraException if a numerical instability occurs.
5618      */
5619     private void setResult(final Matrix m, final Matrix g) throws AlgebraException {
5620         setResult(m);
5621 
5622         // Gg = M*G
5623         m.multiply(g, estimatedGg);
5624     }
5625 
5626     /**
5627      * Makes proper conversion of internal cross-coupling matrix.
5628      *
5629      * @param m internal scaling and cross-coupling matrix.
5630      * @throws AlgebraException if a numerical instability occurs.
5631      */
5632     private void setResult(final Matrix m) throws AlgebraException {
5633         // Because:
5634         // M = I + Mg
5635 
5636         // Then:
5637         // Mg = M - I
5638 
5639         if (estimatedMg == null) {
5640             estimatedMg = m;
5641         } else {
5642             estimatedMg.copyFrom(m);
5643         }
5644 
5645         for (var i = 0; i < BodyKinematics.COMPONENTS; i++) {
5646             estimatedMg.setElementAt(i, i, estimatedMg.getElementAt(i, i) - 1.0);
5647         }
5648 
5649         if (estimatedGg == null) {
5650             estimatedGg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5651         } else {
5652             estimatedGg.initialize(0.0);
5653         }
5654 
5655         estimatedCovariance = fitter.getCovar();
5656         estimatedChiSq = fitter.getChisq();
5657         estimatedChiSqDegreesOfFreedom = fitter.getChisqDegreesOfFreedom();
5658         estimatedReducedChiSq = fitter.getReducedChisq();
5659         estimatedMse = fitter.getMse();
5660         try {
5661             estimatedP = fitter.getP();
5662             estimatedQ = fitter.getQ();
5663         } catch (final MaxIterationsExceededException ignore) {
5664             // if numerical instabilities arise, we assume worst case (no fit at all)
5665             // probability of finding a smaller chi square value is 1.0
5666             // quality of fit is 0.0
5667             estimatedP = 1.0;
5668             estimatedQ = 0.0;
5669         }
5670     }
5671 
5672     /**
5673      * Computes estimated true angular rate squared norm using current measured
5674      * angular rate and specific force along with provided parameters for the
5675      * general case when G-dependent cross biases are taken into account.
5676      * This method is internally executed during gradient estimation and
5677      * Levenberg-Marquardt fitting needed for calibration computation.
5678      *
5679      * @param params array containing parameters for the general purpose case
5680      *               when G-dependent cross biases are taken into account. Must
5681      *               have length 18.
5682      * @return estimated true angular rate squared norm.
5683      * @throws EvaluationException if there are numerical instabilities.
5684      */
5685     private double evaluateGeneralWitGDependentCrossBiases(final double[] params) throws EvaluationException {
5686         final var m11 = params[0];
5687         final var m21 = params[1];
5688         final var m31 = params[2];
5689 
5690         final var m12 = params[3];
5691         final var m22 = params[4];
5692         final var m32 = params[5];
5693 
5694         final var m13 = params[6];
5695         final var m23 = params[7];
5696         final var m33 = params[8];
5697 
5698         final var g11 = params[9];
5699         final var g21 = params[10];
5700         final var g31 = params[11];
5701 
5702         final var g12 = params[12];
5703         final var g22 = params[13];
5704         final var g32 = params[14];
5705 
5706         final var g13 = params[15];
5707         final var g23 = params[16];
5708         final var g33 = params[17];
5709 
5710         return evaluate(m11, m21, m31, m12, m22, m32, m13, m23, m33, g11, g21, g31, g12, g22, g32, g13, g23, g33);
5711     }
5712 
5713     /**
5714      * Computes estimated true angular rate squared norm using current measured
5715      * angular rate and specific force along with provided parameters when
5716      * common z-axis is assumed and G-dependent cross biases are taken into
5717      * account.
5718      * This method is internally executed during gradient estimation and
5719      * Levenberg-Marquardt fitting needed for calibration computation.
5720      *
5721      * @param params array containing parameters for the general purpose case
5722      *               when G-dependent cross biases are taken into account. Must
5723      *               have length 15.
5724      * @return estimated true angular rate squared norm.
5725      * @throws EvaluationException if there are numerical instabilities.
5726      */
5727     private double evaluateCommonAxisWitGDependentCrossBiases(final double[] params) throws EvaluationException {
5728         final var m11 = params[0];
5729 
5730         final var m12 = params[1];
5731         final var m22 = params[2];
5732 
5733         final var m13 = params[3];
5734         final var m23 = params[4];
5735         final var m33 = params[5];
5736 
5737         final var g11 = params[6];
5738         final var g21 = params[7];
5739         final var g31 = params[8];
5740 
5741         final var g12 = params[9];
5742         final var g22 = params[10];
5743         final var g32 = params[11];
5744 
5745         final var g13 = params[12];
5746         final var g23 = params[13];
5747         final var g33 = params[14];
5748 
5749         return evaluate(m11, 0.0, 0.0, m12, m22, 0.0, m13, m23, m33,
5750                 g11, g21, g31, g12, g22, g32, g13, g23, g33);
5751     }
5752 
5753     /**
5754      * Computes estimated true angular rate squared norm using current measured
5755      * angular rate and provided parameters for the general case when G-dependent
5756      * cross biases are ignored.
5757      * This method is internally executed during gradient estimation and
5758      * Levenberg-Marquardt fitting needed for calibration computation.
5759      *
5760      * @param params array containing current parameters for the general purpose case
5761      *               when G-dependent cross biases are ignored. Must have length 9.
5762      * @return estimated true angular rate squared norm.
5763      * @throws EvaluationException if there are numerical instabilities.
5764      */
5765     private double evaluateGeneral(final double[] params) throws EvaluationException {
5766         final var m11 = params[0];
5767         final var m21 = params[1];
5768         final var m31 = params[2];
5769 
5770         final var m12 = params[3];
5771         final var m22 = params[4];
5772         final var m32 = params[5];
5773 
5774         final var m13 = params[6];
5775         final var m23 = params[7];
5776         final var m33 = params[8];
5777 
5778         return evaluate(m11, m21, m31, m12, m22, m32, m13, m23, m33);
5779     }
5780 
5781     /**
5782      * Computes estimated true angular rate squared norm using current measured
5783      * angular rate and provided parameters when common z-axis is assumed and
5784      * G-dependent cross biases are ignored.
5785      * This method is internally executed during gradient estimation and
5786      * Levenberg-Marquardt fitting needed for calibration computation.
5787      *
5788      * @param params array containing current parameters for the common z-axis case
5789      *               when G-dependent cross biases are ignored. Must have length 6.
5790      * @return estimated true angular rate squared norm.
5791      * @throws EvaluationException if there are numerical instabilities.
5792      */
5793     private double evaluateCommonAxis(final double[] params) throws EvaluationException {
5794         final var m11 = params[0];
5795 
5796         final var m12 = params[1];
5797         final var m22 = params[2];
5798 
5799         final var m13 = params[3];
5800         final var m23 = params[4];
5801         final var m33 = params[5];
5802 
5803         return evaluate(m11, 0.0, 0.0, m12, m22, 0.0, m13, m23, m33);
5804     }
5805 
5806     /**
5807      * Computes estimated true angular rate squared norm using current measured
5808      * angular rate and provided parameters.
5809      * This method is internally executed during gradient estimation and
5810      * Levenberg-Marquardt fitting needed for calibration computation.
5811      *
5812      * @param m11 element 1,1 of cross-coupling error matrix.
5813      * @param m21 element 2,1 of cross-coupling error matrix.
5814      * @param m31 element 3,1 of cross-coupling error matrix.
5815      * @param m12 element 1,2 of cross-coupling error matrix.
5816      * @param m22 element 2,2 of cross-coupling error matrix.
5817      * @param m32 element 3,2 of cross-coupling error matrix.
5818      * @param m13 element 1,3 of cross-coupling error matrix.
5819      * @param m23 element 2,3 of cross-coupling error matrix.
5820      * @param m33 element 3,3 of cross-coupling error matrix.
5821      * @param g11 element 1,1 of g-dependent cross bias matrix.
5822      * @param g21 element 2,1 of g-dependent cross bias matrix.
5823      * @param g31 element 3,1 of g-dependent cross bias matrix.
5824      * @param g12 element 1,2 of g-dependent cross bias matrix.
5825      * @param g22 element 2,2 of g-dependent cross bias matrix.
5826      * @param g32 element 3,2 of g-dependent cross bias matrix.
5827      * @param g13 element 1,3 of g-dependent cross bias matrix.
5828      * @param g23 element 2,3 of g-dependent cross bias matrix.
5829      * @param g33 element 3,3 of g-dependent cross bias matrix.
5830      * @return estimated true angular rate squared norm.
5831      * @throws EvaluationException if there are numerical instabilities.
5832      */
5833     private double evaluate(final double m11, final double m21, final double m31,
5834                             final double m12, final double m22, final double m32,
5835                             final double m13, final double m23, final double m33,
5836                             final double g11, final double g21, final double g31,
5837                             final double g12, final double g22, final double g32,
5838                             final double g13, final double g23, final double g33) throws EvaluationException {
5839 
5840         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue
5841         // Ωmeas = M*(Ωtrue + b + G * ftrue)
5842 
5843         // M = I + Mg
5844         // bg = M*b --> b = M^-1*bg
5845         // Gg = M*G --> G = M^-1*Gg
5846 
5847         // Ωtrue = M^-1 * Ωmeas - b - G*ftrue
5848 
5849         try {
5850             if (measAngularRate == null) {
5851                 measAngularRate = new Matrix(BodyKinematics.COMPONENTS, 1);
5852             }
5853             if (fmeas == null) {
5854                 fmeas = new Matrix(BodyKinematics.COMPONENTS, 1);
5855             }
5856             if (m == null) {
5857                 m = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5858             }
5859             if (invM == null) {
5860                 invM = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5861             }
5862             if (b == null) {
5863                 b = new Matrix(BodyKinematics.COMPONENTS, 1);
5864             }
5865             if (g == null) {
5866                 g = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5867             }
5868             if (trueAngularRate == null) {
5869                 trueAngularRate = new Matrix(BodyKinematics.COMPONENTS, 1);
5870             }
5871             if (ftrue == null) {
5872                 ftrue = new Matrix(BodyKinematics.COMPONENTS, 1);
5873             }
5874             if (tmp == null) {
5875                 tmp = new Matrix(BodyKinematics.COMPONENTS, 1);
5876             }
5877 
5878             measAngularRate.setElementAtIndex(0, measAngularRateX);
5879             measAngularRate.setElementAtIndex(1, measAngularRateY);
5880             measAngularRate.setElementAtIndex(2, measAngularRateZ);
5881 
5882             fmeas.setElementAtIndex(0, fmeasX);
5883             fmeas.setElementAtIndex(1, fmeasY);
5884             fmeas.setElementAtIndex(2, fmeasZ);
5885 
5886             m.setElementAt(0, 0, m11);
5887             m.setElementAt(1, 0, m21);
5888             m.setElementAt(2, 0, m31);
5889 
5890             m.setElementAt(0, 1, m12);
5891             m.setElementAt(1, 1, m22);
5892             m.setElementAt(2, 1, m32);
5893 
5894             m.setElementAt(0, 2, m13);
5895             m.setElementAt(1, 2, m23);
5896             m.setElementAt(2, 2, m33);
5897 
5898             Utils.inverse(m, invM);
5899 
5900             b.setElementAtIndex(0, biasX);
5901             b.setElementAtIndex(1, biasY);
5902             b.setElementAtIndex(2, biasZ);
5903 
5904             g.setElementAt(0, 0, g11);
5905             g.setElementAt(1, 0, g21);
5906             g.setElementAt(2, 0, g31);
5907 
5908             g.setElementAt(0, 1, g12);
5909             g.setElementAt(1, 1, g22);
5910             g.setElementAt(2, 1, g32);
5911 
5912             g.setElementAt(0, 2, g13);
5913             g.setElementAt(1, 2, g23);
5914             g.setElementAt(2, 2, g33);
5915 
5916             getAccelerometerBiasAsMatrix(ba);
5917             getAccelerometerMa(ma);
5918 
5919             // fix measured accelerometer value to obtain true
5920             // specific force
5921             accelerationFixer.fix(fmeas, ftrue);
5922             g.multiply(ftrue, tmp);
5923 
5924             invM.multiply(measAngularRate, trueAngularRate);
5925             trueAngularRate.subtract(b);
5926             trueAngularRate.subtract(tmp);
5927 
5928             final var norm = Utils.normF(trueAngularRate);
5929             return norm * norm;
5930 
5931         } catch (final AlgebraException e) {
5932             throw new EvaluationException(e);
5933         }
5934     }
5935 
5936     /**
5937      * Computes estimated true angular rate squared norm using current measured
5938      * angular rate and provided parameters.
5939      * This method is internally executed during gradient estimation and
5940      * Levenberg-Marquardt fittin needed for calibration computation.
5941      *
5942      * @param m11 element 1,1 of cross-coupling error matrix.
5943      * @param m21 element 2,1 of cross-coupling error matrix.
5944      * @param m31 element 3,1 of cross-coupling error matrix.
5945      * @param m12 element 1,2 of cross-coupling error matrix.
5946      * @param m22 element 2,2 of cross-coupling error matrix.
5947      * @param m32 element 3,2 of cross-coupling error matrix.
5948      * @param m13 element 1,3 of cross-coupling error matrix.
5949      * @param m23 element 2,3 of cross-coupling error matrix.
5950      * @param m33 element 3,3 of cross-coupling error matrix.
5951      * @return estimated true angular rate squared norm.
5952      * @throws EvaluationException if there are numerical instabilities.
5953      */
5954     private double evaluate(final double m11, final double m21, final double m31,
5955                             final double m12, final double m22, final double m32,
5956                             final double m13, final double m23, final double m33) throws EvaluationException {
5957 
5958         // Ωmeas = M*(Ωtrue + b)
5959         // Ωtrue = M^-1 * Ωmeas - b
5960 
5961         try {
5962             if (measAngularRate == null) {
5963                 measAngularRate = new Matrix(BodyKinematics.COMPONENTS, 1);
5964             }
5965             if (m == null) {
5966                 m = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5967             }
5968             if (invM == null) {
5969                 invM = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
5970             }
5971             if (b == null) {
5972                 b = new Matrix(BodyKinematics.COMPONENTS, 1);
5973             }
5974             if (trueAngularRate == null) {
5975                 trueAngularRate = new Matrix(BodyKinematics.COMPONENTS, 1);
5976             }
5977 
5978             measAngularRate.setElementAtIndex(0, measAngularRateX);
5979             measAngularRate.setElementAtIndex(1, measAngularRateY);
5980             measAngularRate.setElementAtIndex(2, measAngularRateZ);
5981 
5982             m.setElementAt(0, 0, m11);
5983             m.setElementAt(1, 0, m21);
5984             m.setElementAt(2, 0, m31);
5985 
5986             m.setElementAt(0, 1, m12);
5987             m.setElementAt(1, 1, m22);
5988             m.setElementAt(2, 1, m32);
5989 
5990             m.setElementAt(0, 2, m13);
5991             m.setElementAt(1, 2, m23);
5992             m.setElementAt(2, 2, m33);
5993 
5994             Utils.inverse(m, invM);
5995 
5996             b.setElementAtIndex(0, biasX);
5997             b.setElementAtIndex(1, biasY);
5998             b.setElementAtIndex(2, biasZ);
5999 
6000             invM.multiply(measAngularRate, trueAngularRate);
6001             trueAngularRate.subtract(b);
6002 
6003             final var norm = Utils.normF(trueAngularRate);
6004             return norm * norm;
6005 
6006         } catch (final AlgebraException e) {
6007             throw new EvaluationException(e);
6008         }
6009     }
6010 }