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