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