View Javadoc
1   /*
2    * Copyright (C) 2022 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.Matrix;
19  import com.irurueta.navigation.LockedException;
20  import com.irurueta.navigation.NotReadyException;
21  import com.irurueta.navigation.inertial.calibration.CalibrationException;
22  import com.irurueta.navigation.inertial.calibration.StandardDeviationBodyMagneticFluxDensity;
23  import com.irurueta.numerical.robust.MSACRobustEstimator;
24  import com.irurueta.numerical.robust.MSACRobustEstimatorListener;
25  import com.irurueta.numerical.robust.RobustEstimator;
26  import com.irurueta.numerical.robust.RobustEstimatorException;
27  import com.irurueta.numerical.robust.RobustEstimatorMethod;
28  
29  import java.util.List;
30  
31  /**
32   * Robustly estimates magnetometer cross couplings and scaling factors using
33   * MSAC algorithm.
34   * <p>
35   * To use this calibrator at least 7 measurements with known magnetic field norm at
36   * an unknown position and instant must be taken at 7 different unknown orientations
37   * when common z-axis is assumed, otherwise at least 10
38   * measurements are required.
39   * <p>
40   * Measured magnetic flux density is assumed to follow the model shown below:
41   * <pre>
42   *     mBmeas = bm + (I + Mm) * mBtrue + w
43   * </pre>
44   * Where:
45   * - mBmeas is the measured magnetic flux density. This is a 3x1 vector.
46   * - bm is magnetometer hard-iron bias. Ideally, on a perfect magnetometer,
47   * this should be a 3x1 zero vector.
48   * - I is the 3x3 identity matrix.
49   * - Mm is the 3x3 soft-iron matrix containing cross-couplings and scaling
50   * factors. Ideally, on a perfect magnetometer, this should be a 3x3 zero
51   * matrix.
52   * - mBtrue is ground-truth magnetic flux density. This is a 3x1 vector.
53   * - w is measurement noise. This is a 3x1 vector.
54   * Notice that this calibrator assumes that all measurements are taken in
55   * a short span of time, where Earth magnetic field can be assumed to be
56   * constant at provided location and instant.
57   */
58  public class MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator extends
59          RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator {
60  
61      /**
62       * Constant defining default threshold to determine whether samples are
63       * inliers or not.
64       */
65      public static final double DEFAULT_THRESHOLD = 1e-9;
66  
67      /**
68       * Minimum value that can be set as threshold.
69       * Threshold must be strictly greater than 0.0.
70       */
71      public static final double MIN_THRESHOLD = 0.0;
72  
73      /**
74       * Threshold to determine whether samples are inliers or not when
75       * testing possible estimation solutions.
76       */
77      private double threshold = DEFAULT_THRESHOLD;
78  
79      /**
80       * Constructor.
81       */
82      public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator() {
83          super();
84      }
85  
86      /**
87       * Constructor.
88       *
89       * @param listener listener to handle events raised by this calibrator.
90       */
91      public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
92              final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
93          super(listener);
94      }
95  
96      /**
97       * Constructor.
98       *
99       * @param measurements list of body magnetic flux density
100      *                     measurements with standard deviation of
101      *                     magnetometer measurements taken at the same
102      *                     position with zero velocity and unknown different
103      *                     orientations.
104      */
105     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
106             final List<StandardDeviationBodyMagneticFluxDensity> measurements) {
107         super(measurements);
108     }
109 
110     /**
111      * Constructor.
112      *
113      * @param commonAxisUsed indicates whether z-axis is assumed to be common
114      *                       for the accelerometer, gyroscope and magnetometer.
115      */
116     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(final boolean commonAxisUsed) {
117         super(commonAxisUsed);
118     }
119 
120     /**
121      * Constructor.
122      *
123      * @param hardIron known hard-iron.
124      * @throws IllegalArgumentException if provided hard-iron array does
125      *                                  not have length 3.
126      */
127     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(final double[] hardIron) {
128         super(hardIron);
129     }
130 
131     /**
132      * Constructor.
133      *
134      * @param hardIron known hard-iron.
135      * @throws IllegalArgumentException if provided hard-iron matrix is not
136      *                                  3x1.
137      */
138     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(final Matrix hardIron) {
139         super(hardIron);
140     }
141 
142     /**
143      * Constructor.
144      *
145      * @param hardIron  known hard-iron.
146      * @param initialMm initial soft-iron matrix containing scale factors
147      *                  and cross coupling errors.
148      * @throws IllegalArgumentException if provided hard-iron matrix is not
149      *                                  3x1 or if soft-iron matrix is not
150      *                                  3x3.
151      */
152     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
153             final Matrix hardIron, final Matrix initialMm) {
154         super(hardIron, initialMm);
155     }
156 
157     /**
158      * Constructor.
159      *
160      * @param measurements list of body magnetic flux density
161      *                     measurements with standard deviation of
162      *                     magnetometer measurements taken at the same
163      *                     position with zero velocity and unknown different
164      *                     orientations.
165      * @param listener     listener to handle events raised by this calibrator.
166      */
167     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
168             final List<StandardDeviationBodyMagneticFluxDensity> measurements,
169             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
170         super(measurements, listener);
171     }
172 
173     /**
174      * Constructor.
175      *
176      * @param measurements   collection of body magnetic flux density
177      *                       measurements with standard deviation of
178      *                       magnetometer measurements taken at the same
179      *                       position with zero velocity and unknown different
180      *                       orientations.
181      * @param commonAxisUsed indicates whether z-axis is assumed to be common
182      *                       for the accelerometer, gyroscope and magnetometer.
183      */
184     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
185             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed) {
186         super(measurements, commonAxisUsed);
187     }
188 
189     /**
190      * Constructor.
191      *
192      * @param measurements   collection of body magnetic flux density
193      *                       measurements with standard deviation of
194      *                       magnetometer measurements taken at the same
195      *                       position with zero velocity and unknown different
196      *                       orientations.
197      * @param commonAxisUsed indicates whether z-axis is assumed to be common
198      *                       for the accelerometer, gyroscope and magnetometer.
199      * @param listener       listener to handle events raised by this calibrator.
200      */
201     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
202             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
203             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
204         super(measurements, commonAxisUsed, listener);
205     }
206 
207     /**
208      * Constructor.
209      *
210      * @param measurements collection of body magnetic flux density
211      *                     measurements with standard deviation of
212      *                     magnetometer measurements taken at the same
213      *                     position with zero velocity and unknown different
214      *                     orientations.
215      * @param hardIron     known hard-iron.
216      * @throws IllegalArgumentException if provided hard-iron array does
217      *                                  not have length 3.
218      */
219     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
220             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final double[] hardIron) {
221         super(measurements, hardIron);
222     }
223 
224     /**
225      * Constructor.
226      *
227      * @param measurements collection of body magnetic flux density
228      *                     measurements with standard deviation of
229      *                     magnetometer measurements taken at the same
230      *                     position with zero velocity and unknown different
231      *                     orientations.
232      * @param hardIron     known hard-iron.
233      * @param listener     listener to handle events raised by this calibrator.
234      * @throws IllegalArgumentException if provided hard-iron array does
235      *                                  not have length 3.
236      */
237     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
238             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final double[] hardIron,
239             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
240         super(measurements, hardIron, listener);
241     }
242 
243     /**
244      * Constructor.
245      *
246      * @param measurements   collection of body magnetic flux density
247      *                       measurements with standard deviation of
248      *                       magnetometer measurements taken at the same
249      *                       position with zero velocity and unknown different
250      *                       orientations.
251      * @param commonAxisUsed indicates whether z-axis is assumed to be common
252      *                       for the accelerometer, gyroscope and magnetometer.
253      * @param hardIron       known hard-iron.
254      * @throws IllegalArgumentException if provided hard-iron array does
255      *                                  not have length 3.
256      */
257     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
258             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
259             final double[] hardIron) {
260         super(measurements, commonAxisUsed, hardIron);
261     }
262 
263     /**
264      * Constructor.
265      *
266      * @param measurements   collection of body magnetic flux density
267      *                       measurements with standard deviation of
268      *                       magnetometer measurements taken at the same
269      *                       position with zero velocity and unknown different
270      *                       orientations.
271      * @param commonAxisUsed indicates whether z-axis is assumed to be common
272      *                       for the accelerometer, gyroscope and magnetometer.
273      * @param hardIron       known hard-iron.
274      * @param listener       listener to handle events raised by this calibrator.
275      * @throws IllegalArgumentException if provided hard-iron array does
276      *                                  not have length 3.
277      */
278     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
279             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
280             final double[] hardIron,
281             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
282         super(measurements, commonAxisUsed, hardIron, listener);
283     }
284 
285     /**
286      * Constructor.
287      *
288      * @param measurements collection of body magnetic flux density
289      *                     measurements with standard deviation of
290      *                     magnetometer measurements taken at the same
291      *                     position with zero velocity and unknown different
292      *                     orientations.
293      * @param hardIron     known hard-iron.
294      * @throws IllegalArgumentException if provided hard-iron matrix is not
295      *                                  3x1.
296      */
297     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
298             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron) {
299         super(measurements, hardIron);
300     }
301 
302     /**
303      * Constructor.
304      *
305      * @param measurements collection of body magnetic flux density
306      *                     measurements with standard deviation of
307      *                     magnetometer measurements taken at the same
308      *                     position with zero velocity and unknown different
309      *                     orientations.
310      * @param hardIron     known hard-iron to find a solution.
311      * @param listener     listener to handle events raised by this calibrator.
312      * @throws IllegalArgumentException if provided hard-iron matrix is not
313      *                                  3x1.
314      */
315     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
316             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron,
317             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
318         super(measurements, hardIron, listener);
319     }
320 
321     /**
322      * Constructor.
323      *
324      * @param measurements   collection of body magnetic flux density
325      *                       measurements with standard deviation of
326      *                       magnetometer measurements taken at the same
327      *                       position with zero velocity and unknown different
328      *                       orientations.
329      * @param commonAxisUsed indicates whether z-axis is assumed to be common
330      *                       for the accelerometer, gyroscope and magnetometer.
331      * @param hardIron       known hard-iron.
332      * @throws IllegalArgumentException if provided hard-iron matrix is not
333      *                                  3x1.
334      */
335     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
336             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
337             final Matrix hardIron) {
338         super(measurements, commonAxisUsed, hardIron);
339     }
340 
341     /**
342      * Constructor.
343      *
344      * @param measurements   collection of body magnetic flux density
345      *                       measurements with standard deviation of
346      *                       magnetometer measurements taken at the same
347      *                       position with zero velocity and unknown different
348      *                       orientations.
349      * @param commonAxisUsed indicates whether z-axis is assumed to be common
350      *                       for the accelerometer, gyroscope and magnetometer.
351      * @param hardIron       known hard-iron.
352      * @param listener       listener to handle events raised by this calibrator.
353      * @throws IllegalArgumentException if provided hard-iron matrix is not
354      *                                  3x1.
355      */
356     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
357             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
358             final Matrix hardIron,
359             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
360         super(measurements, commonAxisUsed, hardIron, listener);
361     }
362 
363     /**
364      * Constructor.
365      *
366      * @param measurements collection of body magnetic flux density
367      *                     measurements with standard deviation of
368      *                     magnetometer measurements taken at the same
369      *                     position with zero velocity and unknown different
370      *                     orientations.
371      * @param hardIron     known hard-iron.
372      * @param initialMm    initial soft-iron matrix containing scale factors
373      *                     and cross coupling errors.
374      * @throws IllegalArgumentException if provided hard-iron matrix is not
375      *                                  3x1 or if soft-iron matrix is not
376      *                                  3x3.
377      */
378     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
379             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron,
380             final Matrix initialMm) {
381         super(measurements, hardIron, initialMm);
382     }
383 
384     /**
385      * Constructor.
386      *
387      * @param measurements collection of body magnetic flux density
388      *                     measurements with standard deviation of
389      *                     magnetometer measurements taken at the same
390      *                     position with zero velocity and unknown different
391      *                     orientations.
392      * @param hardIron     known hard-iron.
393      * @param initialMm    initial soft-iron matrix containing scale factors
394      *                     and cross coupling errors.
395      * @param listener     listener to handle events raised by this calibrator.
396      * @throws IllegalArgumentException if provided hard-iron matrix is not
397      *                                  3x1 or if soft-iron matrix is not
398      *                                  3x3.
399      */
400     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
401             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron,
402             final Matrix initialMm,
403             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
404         super(measurements, hardIron, initialMm, listener);
405     }
406 
407     /**
408      * Constructor.
409      *
410      * @param measurements   collection of body magnetic flux density
411      *                       measurements with standard deviation of
412      *                       magnetometer measurements taken at the same
413      *                       position with zero velocity and unknown different
414      *                       orientations.
415      * @param commonAxisUsed indicates whether z-axis is assumed to be common
416      *                       for the accelerometer, gyroscope and magnetometer.
417      * @param hardIron       known hard-iron.
418      * @param initialMm      initial soft-iron matrix containing scale factors
419      *                       and cross coupling errors.
420      * @throws IllegalArgumentException if provided hard-iron matrix is not
421      *                                  3x1 or if soft-iron matrix is not
422      *                                  3x3.
423      */
424     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
425             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
426             final Matrix hardIron, final Matrix initialMm) {
427         super(measurements, commonAxisUsed, hardIron, initialMm);
428     }
429 
430     /**
431      * Constructor.
432      *
433      * @param measurements   collection of body magnetic flux density
434      *                       measurements with standard deviation of
435      *                       magnetometer measurements taken at the same
436      *                       position with zero velocity and unknown different
437      *                       orientations.
438      * @param commonAxisUsed indicates whether z-axis is assumed to be common
439      *                       for the accelerometer, gyroscope and magnetometer.
440      * @param hardIron       known hard-iron.
441      * @param initialMm      initial soft-iron matrix containing scale factors
442      *                       and cross coupling errors.
443      * @param listener       listener to handle events raised by this calibrator.
444      * @throws IllegalArgumentException if provided hard-iron matrix is not
445      *                                  3x1 or if soft-iron matrix is not
446      *                                  3x3.
447      */
448     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
449             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
450             final Matrix hardIron, final Matrix initialMm,
451             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
452         super(measurements, commonAxisUsed, hardIron, initialMm, listener);
453     }
454 
455     /**
456      * Constructor.
457      *
458      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
459      * @throws IllegalArgumentException if provided magnetic flux norm value is negative.
460      */
461     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
462             final Double groundTruthMagneticFluxDensityNorm) {
463         super(groundTruthMagneticFluxDensityNorm);
464     }
465 
466     /**
467      * Constructor.
468      *
469      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
470      * @param listener                           listener to handle events raised by this calibrator.
471      * @throws IllegalArgumentException if provided magnetic flux norm value is negative.
472      */
473     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
474             final Double groundTruthMagneticFluxDensityNorm,
475             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
476         super(groundTruthMagneticFluxDensityNorm, listener);
477     }
478 
479     /**
480      * Constructor.
481      *
482      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
483      * @param measurements                       collection of body magnetic flux density
484      *                                           measurements with standard deviation of
485      *                                           magnetometer measurements taken at the same
486      *                                           position with zero velocity and unknown different
487      *                                           orientations.
488      * @throws IllegalArgumentException if provided magnetic flux norm value is negative.
489      */
490     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
491             final Double groundTruthMagneticFluxDensityNorm,
492             final List<StandardDeviationBodyMagneticFluxDensity> measurements) {
493         super(groundTruthMagneticFluxDensityNorm, measurements);
494     }
495 
496     /**
497      * Constructor.
498      *
499      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
500      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
501      *                                           for the accelerometer, gyroscope and magnetometer.
502      * @throws IllegalArgumentException if provided magnetic flux norm value is negative.
503      */
504     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
505             final Double groundTruthMagneticFluxDensityNorm, final boolean commonAxisUsed) {
506         super(groundTruthMagneticFluxDensityNorm, commonAxisUsed);
507     }
508 
509     /**
510      * Constructor.
511      *
512      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
513      * @param hardIron                           known hard-iron.
514      * @throws IllegalArgumentException if provided magnetic flux norm value is
515      *                                  negative, or if provided hard-iron array does
516      *                                  not have length 3.
517      */
518     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
519             final Double groundTruthMagneticFluxDensityNorm, final double[] hardIron) {
520         super(groundTruthMagneticFluxDensityNorm, hardIron);
521     }
522 
523     /**
524      * Constructor.
525      *
526      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
527      * @param hardIron                           known hard-iron.
528      * @throws IllegalArgumentException if provided magnetic flux norm value is
529      *                                  negative, or if provided hard-iron matrix is not
530      *                                  3x1.
531      */
532     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
533             final Double groundTruthMagneticFluxDensityNorm, final Matrix hardIron) {
534         super(groundTruthMagneticFluxDensityNorm, hardIron);
535     }
536 
537     /**
538      * Constructor.
539      *
540      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
541      * @param hardIron                           known hard-iron.
542      * @param initialMm                          initial soft-iron matrix containing scale factors
543      *                                           and cross coupling errors.
544      * @throws IllegalArgumentException if provided magnetic flux norm value is
545      *                                  negative, or if provided hard-iron matrix is not
546      *                                  3x1 or if soft-iron matrix is not
547      *                                  3x3.
548      */
549     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
550             final Double groundTruthMagneticFluxDensityNorm, final Matrix hardIron, final Matrix initialMm) {
551         super(groundTruthMagneticFluxDensityNorm, hardIron, initialMm);
552     }
553 
554     /**
555      * Constructor.
556      *
557      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
558      * @param measurements                       collection of body magnetic flux density
559      *                                           measurements with standard deviation of
560      *                                           magnetometer measurements taken at the same
561      *                                           position with zero velocity and unknown different
562      *                                           orientations.
563      * @param listener                           listener to handle events raised by this calibrator.
564      * @throws IllegalArgumentException if provided magnetic flux norm value is negative.
565      */
566     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
567             final Double groundTruthMagneticFluxDensityNorm,
568             final List<StandardDeviationBodyMagneticFluxDensity> measurements,
569             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
570         super(groundTruthMagneticFluxDensityNorm, measurements, listener);
571     }
572 
573     /**
574      * Constructor.
575      *
576      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
577      * @param measurements                       collection of body magnetic flux density
578      *                                           measurements with standard deviation of
579      *                                           magnetometer measurements taken at the same
580      *                                           position with zero velocity and unknown different
581      *                                           orientations.
582      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
583      *                                           for the accelerometer, gyroscope and magnetometer.
584      * @throws IllegalArgumentException if provided magnetic flux norm value is negative.
585      */
586     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
587             final Double groundTruthMagneticFluxDensityNorm,
588             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed) {
589         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed);
590     }
591 
592     /**
593      * Constructor.
594      *
595      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
596      * @param measurements                       collection of body magnetic flux density
597      *                                           measurements with standard deviation of
598      *                                           magnetometer measurements taken at the same
599      *                                           position with zero velocity and unknown different
600      *                                           orientations.
601      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
602      *                                           for the accelerometer, gyroscope and magnetometer.
603      * @param listener                           listener to handle events raised by this calibrator.
604      * @throws IllegalArgumentException if provided magnetic flux norm value is negative.
605      */
606     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
607             final Double groundTruthMagneticFluxDensityNorm,
608             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
609             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
610         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed, listener);
611     }
612 
613     /**
614      * Constructor.
615      *
616      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
617      * @param measurements                       collection of body magnetic flux density
618      *                                           measurements with standard deviation of
619      *                                           magnetometer measurements taken at the same
620      *                                           position with zero velocity and unknown different
621      *                                           orientations.
622      * @param hardIron                           known hard-iron.
623      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
624      *                                  or if provided hard-iron array does not have length 3.
625      */
626     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
627             final Double groundTruthMagneticFluxDensityNorm,
628             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final double[] hardIron) {
629         super(groundTruthMagneticFluxDensityNorm, measurements, hardIron);
630     }
631 
632     /**
633      * Constructor.
634      *
635      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
636      * @param measurements                       collection of body magnetic flux density
637      *                                           measurements with standard deviation of
638      *                                           magnetometer measurements taken at the same
639      *                                           position with zero velocity and unknown different
640      *                                           orientations.
641      * @param hardIron                           known hard-iron.
642      * @param listener                           listener to handle events raised by this calibrator.
643      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
644      *                                  or if provided hard-iron array does not have length 3.
645      */
646     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
647             final Double groundTruthMagneticFluxDensityNorm,
648             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final double[] hardIron,
649             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
650         super(groundTruthMagneticFluxDensityNorm, measurements, hardIron, listener);
651     }
652 
653     /**
654      * Constructor.
655      *
656      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
657      * @param measurements                       collection of body magnetic flux density
658      *                                           measurements with standard deviation of
659      *                                           magnetometer measurements taken at the same
660      *                                           position with zero velocity and unknown different
661      *                                           orientations.
662      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
663      *                                           for the accelerometer, gyroscope and magnetometer.
664      * @param hardIron                           known hard-iron.
665      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
666      *                                  or if provided hard-iron array does not have length 3.
667      */
668     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
669             final Double groundTruthMagneticFluxDensityNorm,
670             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
671             final double[] hardIron) {
672         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed, hardIron);
673     }
674 
675     /**
676      * Constructor.
677      *
678      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
679      * @param measurements                       collection of body magnetic flux density
680      *                                           measurements with standard deviation of
681      *                                           magnetometer measurements taken at the same
682      *                                           position with zero velocity and unknown different
683      *                                           orientations.
684      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
685      *                                           for the accelerometer, gyroscope and magnetometer.
686      * @param hardIron                           known hard-iron.
687      * @param listener                           listener to handle events raised by this calibrator.
688      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
689      *                                  or if provided hard-iron array does not have length 3.
690      */
691     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
692             final Double groundTruthMagneticFluxDensityNorm,
693             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
694             final double[] hardIron,
695             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
696         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed, hardIron, listener);
697     }
698 
699     /**
700      * Constructor.
701      *
702      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
703      * @param measurements                       collection of body magnetic flux density
704      *                                           measurements with standard deviation of
705      *                                           magnetometer measurements taken at the same
706      *                                           position with zero velocity and unknown different
707      *                                           orientations.
708      * @param hardIron                           known hard-iron.
709      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
710      *                                  or if provided hard-iron matrix is not 3x1.
711      */
712     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
713             final Double groundTruthMagneticFluxDensityNorm,
714             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron) {
715         super(groundTruthMagneticFluxDensityNorm, measurements, hardIron);
716     }
717 
718     /**
719      * Constructor.
720      *
721      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
722      * @param measurements                       collection of body magnetic flux density
723      *                                           measurements with standard deviation of
724      *                                           magnetometer measurements taken at the same
725      *                                           position with zero velocity and unknown different
726      *                                           orientations.
727      * @param hardIron                           known hard-iron.
728      * @param listener                           listener to handle events raised by this calibrator.
729      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
730      *                                  or if provided hard-iron matrix is not 3x1.
731      */
732     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
733             final Double groundTruthMagneticFluxDensityNorm,
734             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron,
735             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
736         super(groundTruthMagneticFluxDensityNorm, measurements, hardIron, listener);
737     }
738 
739     /**
740      * Constructor.
741      *
742      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
743      * @param measurements                       collection of body magnetic flux density
744      *                                           measurements with standard deviation of
745      *                                           magnetometer measurements taken at the same
746      *                                           position with zero velocity and unknown different
747      *                                           orientations.
748      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
749      *                                           for the accelerometer, gyroscope and magnetometer.
750      * @param hardIron                           known hard-iron.
751      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
752      *                                  or if provided hard-iron matrix is not 3x1.
753      */
754     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
755             final Double groundTruthMagneticFluxDensityNorm,
756             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
757             final Matrix hardIron) {
758         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed, hardIron);
759     }
760 
761     /**
762      * Constructor.
763      *
764      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
765      * @param measurements                       collection of body magnetic flux density
766      *                                           measurements with standard deviation of
767      *                                           magnetometer measurements taken at the same
768      *                                           position with zero velocity and unknown different
769      *                                           orientations.
770      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
771      *                                           for the accelerometer, gyroscope and magnetometer.
772      * @param hardIron                           known hard-iron.
773      * @param listener                           listener to handle events raised by this calibrator.
774      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
775      *                                  or if provided hard-iron matrix is not 3x1.
776      */
777     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
778             final Double groundTruthMagneticFluxDensityNorm,
779             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
780             final Matrix hardIron,
781             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
782         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed, hardIron, listener);
783     }
784 
785     /**
786      * Constructor.
787      *
788      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
789      * @param measurements                       collection of body magnetic flux density
790      *                                           measurements with standard deviation of
791      *                                           magnetometer measurements taken at the same
792      *                                           position with zero velocity and unknown different
793      *                                           orientations.
794      * @param hardIron                           known hard-iron.
795      * @param initialMm                          initial soft-iron matrix containing scale factors
796      *                                           and cross coupling errors.
797      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
798      *                                  or if provided hard-iron matrix is not 3x1 or if
799      *                                  soft-iron matrix is not 3x3.
800      */
801     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
802             final Double groundTruthMagneticFluxDensityNorm,
803             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron,
804             final Matrix initialMm) {
805         super(groundTruthMagneticFluxDensityNorm, measurements, hardIron, initialMm);
806     }
807 
808     /**
809      * Constructor.
810      *
811      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
812      * @param measurements                       collection of body magnetic flux density
813      *                                           measurements with standard deviation of
814      *                                           magnetometer measurements taken at the same
815      *                                           position with zero velocity and unknown different
816      *                                           orientations.
817      * @param hardIron                           known hard-iron.
818      * @param initialMm                          initial soft-iron matrix containing scale factors
819      *                                           and cross coupling errors.
820      * @param listener                           listener to handle events raised by this calibrator.
821      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
822      *                                  or if provided hard-iron matrix is not 3x1 or if
823      *                                  soft-iron matrix is not 3x3.
824      */
825     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
826             final Double groundTruthMagneticFluxDensityNorm,
827             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final Matrix hardIron,
828             final Matrix initialMm,
829             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
830         super(groundTruthMagneticFluxDensityNorm, measurements, hardIron, initialMm, listener);
831     }
832 
833     /**
834      * Constructor.
835      *
836      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
837      * @param measurements                       collection of body magnetic flux density
838      *                                           measurements with standard deviation of
839      *                                           magnetometer measurements taken at the same
840      *                                           position with zero velocity and unknown different
841      *                                           orientations.
842      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
843      *                                           for the accelerometer, gyroscope and magnetometer.
844      * @param hardIron                           known hard-iron.
845      * @param initialMm                          initial soft-iron matrix containing scale factors
846      *                                           and cross coupling errors.
847      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
848      *                                  or if provided hard-iron matrix is not 3x1
849      *                                  or if soft-iron matrix is not 3x3.
850      */
851     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
852             final Double groundTruthMagneticFluxDensityNorm,
853             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
854             final Matrix hardIron, final Matrix initialMm) {
855         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed, hardIron, initialMm);
856     }
857 
858     /**
859      * Constructor.
860      *
861      * @param groundTruthMagneticFluxDensityNorm ground truth magnetic flux density norm expressed in Teslas (T).
862      * @param measurements                       collection of body magnetic flux density
863      *                                           measurements with standard deviation of
864      *                                           magnetometer measurements taken at the same
865      *                                           position with zero velocity and unknown different
866      *                                           orientations.
867      * @param commonAxisUsed                     indicates whether z-axis is assumed to be common
868      *                                           for the accelerometer, gyroscope and magnetometer.
869      * @param hardIron                           known hard-iron.
870      * @param initialMm                          initial soft-iron matrix containing scale factors
871      *                                           and cross coupling errors.
872      * @param listener                           listener to handle events raised by this calibrator.
873      * @throws IllegalArgumentException if provided magnetic flux norm value is negative,
874      *                                  or if provided hard-iron matrix is not 3x1
875      *                                  or if soft-iron matrix is not 3x3.
876      */
877     public MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator(
878             final Double groundTruthMagneticFluxDensityNorm,
879             final List<StandardDeviationBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
880             final Matrix hardIron, final Matrix initialMm,
881             final RobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibratorListener listener) {
882         super(groundTruthMagneticFluxDensityNorm, measurements, commonAxisUsed, hardIron, initialMm, listener);
883     }
884 
885     /**
886      * Gets threshold to determine whether samples are inliers or not when testing possible solutions.
887      * The threshold refers to the amount of error on norm between measured specific forces and the
888      * ones generated with estimated calibration parameters provided for each sample.
889      *
890      * @return threshold to determine whether samples are inliers or not.
891      */
892     public double getThreshold() {
893         return threshold;
894     }
895 
896     /**
897      * Sets threshold to determine whether samples are inliers or not when testing possible solutions.
898      * The threshold refers to the amount of error on norm between measured specific forces and the
899      * ones generated with estimated calibration parameters provided for each sample.
900      *
901      * @param threshold threshold to determine whether samples are inliers or not.
902      * @throws IllegalArgumentException if provided value is equal or less than zero.
903      * @throws LockedException          if calibrator is currently running.
904      */
905     public void setThreshold(final double threshold) throws LockedException {
906         if (running) {
907             throw new LockedException();
908         }
909         if (threshold <= MIN_THRESHOLD) {
910             throw new IllegalArgumentException();
911         }
912         this.threshold = threshold;
913     }
914 
915     /**
916      * Estimates magnetometer calibration parameters containing hard-iron
917      * bias and soft-iron scale factors and cross-coupling errors.
918      *
919      * @throws LockedException      if calibrator is currently running.
920      * @throws NotReadyException    if calibrator is not ready.
921      * @throws CalibrationException if estimation fails for numerical reasons.
922      */
923     @SuppressWarnings("DuplicatedCode")
924     @Override
925     public void calibrate() throws LockedException, NotReadyException, CalibrationException {
926         if (running) {
927             throw new LockedException();
928         }
929         if (!isReady()) {
930             throw new NotReadyException();
931         }
932 
933         final var innerEstimator = new MSACRobustEstimator<>(new MSACRobustEstimatorListener<PreliminaryResult>() {
934             @Override
935             public double getThreshold() {
936                 return threshold;
937             }
938 
939             @Override
940             public int getTotalSamples() {
941                 return measurements.size();
942             }
943 
944             @Override
945             public int getSubsetSize() {
946                 return preliminarySubsetSize;
947             }
948 
949             @Override
950             public void estimatePreliminarSolutions(
951                     final int[] samplesIndices, final List<PreliminaryResult> solutions) {
952                 computePreliminarySolutions(samplesIndices, solutions);
953             }
954 
955             @Override
956             public double computeResidual(final PreliminaryResult currentEstimation, final int i) {
957                 return computeError(measurements.get(i), currentEstimation);
958             }
959 
960             @Override
961             public boolean isReady() {
962                 return MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator.super.isReady();
963             }
964 
965             @Override
966             public void onEstimateStart(final RobustEstimator<PreliminaryResult> estimator) {
967                 // no action needed
968             }
969 
970             @Override
971             public void onEstimateEnd(final RobustEstimator<PreliminaryResult> estimator) {
972                 // no action needed
973             }
974 
975             @Override
976             public void onEstimateNextIteration(
977                     final RobustEstimator<PreliminaryResult> estimator, final int iteration) {
978                 if (listener != null) {
979                     listener.onCalibrateNextIteration(
980                             MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator.this,
981                             iteration);
982                 }
983             }
984 
985             @Override
986             public void onEstimateProgressChange(
987                     final RobustEstimator<PreliminaryResult> estimator, final float progress) {
988                 if (listener != null) {
989                     listener.onCalibrateProgressChange(
990                             MSACRobustKnownHardIronMagneticFluxDensityNormMagnetometerCalibrator.this,
991                             progress);
992                 }
993             }
994         });
995 
996         try {
997             running = true;
998 
999             if (listener != null) {
1000                 listener.onCalibrateStart(this);
1001             }
1002 
1003             inliersData = null;
1004 
1005             innerEstimator.setConfidence(confidence);
1006             innerEstimator.setMaxIterations(maxIterations);
1007             innerEstimator.setProgressDelta(progressDelta);
1008             final var preliminaryResult = innerEstimator.estimate();
1009             inliersData = innerEstimator.getInliersData();
1010 
1011             attemptRefine(preliminaryResult);
1012 
1013             if (listener != null) {
1014                 listener.onCalibrateEnd(this);
1015             }
1016 
1017         } catch (final com.irurueta.numerical.LockedException e) {
1018             throw new LockedException(e);
1019         } catch (final com.irurueta.numerical.NotReadyException e) {
1020             throw new NotReadyException(e);
1021         } catch (final RobustEstimatorException e) {
1022             throw new CalibrationException(e);
1023         } finally {
1024             running = false;
1025         }
1026     }
1027 
1028     /**
1029      * Returns method being used for robust estimation.
1030      *
1031      * @return method being used for robust estimation.
1032      */
1033     @Override
1034     public RobustEstimatorMethod getMethod() {
1035         return RobustEstimatorMethod.MSAC;
1036     }
1037 
1038     /**
1039      * Indicates whether this calibrator requires quality scores for each
1040      * measurement or not.
1041      *
1042      * @return true if quality scores are required, false otherwise.
1043      */
1044     @Override
1045     public boolean isQualityScoresRequired() {
1046         return false;
1047     }
1048 }