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