View Javadoc
1   /*
2    * Copyright (C) 2020 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.navigation.inertial.calibration.magnetometer;
17  
18  import com.irurueta.algebra.AlgebraException;
19  import com.irurueta.algebra.Matrix;
20  import com.irurueta.algebra.WrongSizeException;
21  import com.irurueta.navigation.LockedException;
22  import com.irurueta.navigation.NotReadyException;
23  import com.irurueta.navigation.frames.CoordinateTransformation;
24  import com.irurueta.navigation.frames.FrameType;
25  import com.irurueta.navigation.frames.NEDFrame;
26  import com.irurueta.navigation.frames.converters.ECEFtoNEDFrameConverter;
27  import com.irurueta.navigation.inertial.BodyKinematics;
28  import com.irurueta.navigation.inertial.BodyMagneticFluxDensity;
29  import com.irurueta.navigation.inertial.calibration.CalibrationException;
30  import com.irurueta.navigation.inertial.calibration.MagneticFluxDensityTriad;
31  import com.irurueta.navigation.inertial.calibration.StandardDeviationFrameBodyMagneticFluxDensity;
32  import com.irurueta.navigation.inertial.estimators.BodyMagneticFluxDensityEstimator;
33  import com.irurueta.navigation.inertial.wmm.NEDMagneticFluxDensity;
34  import com.irurueta.navigation.inertial.wmm.WMMEarthMagneticFluxDensityEstimator;
35  import com.irurueta.navigation.inertial.wmm.WorldMagneticModel;
36  import com.irurueta.numerical.fitting.FittingException;
37  import com.irurueta.numerical.fitting.LevenbergMarquardtMultiVariateFitter;
38  import com.irurueta.numerical.fitting.LevenbergMarquardtMultiVariateFunctionEvaluator;
39  import com.irurueta.statistics.MaxIterationsExceededException;
40  import com.irurueta.units.MagneticFluxDensity;
41  import com.irurueta.units.MagneticFluxDensityConverter;
42  import com.irurueta.units.MagneticFluxDensityUnit;
43  
44  import java.io.IOException;
45  import java.util.Collection;
46  
47  /**
48   * Estimates magnetometer hard-iron biases, cross couplings and scaling
49   * factors.
50   * <p>
51   * This calibrator uses an iterative approach to find a minimum least squared error
52   * solution.
53   * <p>
54   * To use this calibrator at least 4 measurements at different known frames must
55   * be provided. In other words, magnetometer samples must be obtained at 4
56   * different positions or orientations.
57   * Notice that frame velocities are ignored by this calibrator.
58   * <p>
59   * Measured magnetic flux density is assumed to follow the model shown below:
60   * <pre>
61   *     mBmeas = bm + (I + Mm) * mBtrue + w
62   * </pre>
63   * Where:
64   * - mBmeas is the measured magnetic flux density. This is a 3x1 vector.
65   * - bm is magnetometer hard-iron bias. Ideally, on a perfect magnetometer,
66   * this should be a 3x1 zero vector.
67   * - I is the 3x3 identity matrix.
68   * - Mm is the 3x3 soft-iron matrix containing cross-couplings and scaling
69   * factors. Ideally, on a perfect magnetometer, this should be a 3x3 zero
70   * matrix.
71   * - mBtrue is ground-truth magnetic flux density. This is a 3x1 vector.
72   * - w is measurement noise. This is a 3x1 vector.
73   */
74  public class KnownFrameMagnetometerNonLinearLeastSquaresCalibrator implements
75          KnownFrameMagnetometerCalibrator<StandardDeviationFrameBodyMagneticFluxDensity,
76                  KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener>, MagnetometerNonLinearCalibrator,
77          UnknownHardIronNonLinearMagnetometerCalibrator,
78          UnorderedStandardDeviationFrameBodyMagneticFluxDensityMagnetometerCalibrator {
79  
80      /**
81       * Indicates whether by default a common z-axis is assumed for the accelerometer,
82       * gyroscope and magnetometer.
83       */
84      public static final boolean DEFAULT_USE_COMMON_Z_AXIS = false;
85  
86      /**
87       * Required minimum number of measurements.
88       */
89      public static final int MINIMUM_MEASUREMENTS = 4;
90  
91      /**
92       * Number of unknowns when common z-axis is assumed for the accelerometer,
93       * gyroscope and magnetometer.
94       */
95      private static final int COMMON_Z_AXIS_UNKNOWNS = 9;
96  
97      /**
98       * Number of unknowns for the general case.
99       */
100     private static final int GENERAL_UNKNOWNS = 12;
101 
102     /**
103      * Levenberg-Marquardt fitter to find a non-linear solution.
104      */
105     private final LevenbergMarquardtMultiVariateFitter fitter = new LevenbergMarquardtMultiVariateFitter();
106 
107     /**
108      * Initial x-coordinate of hard-iron bias to be used to find a solution.
109      * This is expressed in Teslas (T).
110      */
111     private double initialHardIronX;
112 
113     /**
114      * Initial y-coordinate of hard-iron bias to be used to find a solution.
115      * This is expressed in Teslas (T).
116      */
117     private double initialHardIronY;
118 
119     /**
120      * Initial z-coordinate of hard-iron bias to be used to find a solution.
121      * This is expressed in Teslas (T).
122      */
123     private double initialHardIronZ;
124 
125     /**
126      * Initial x scaling factor.
127      */
128     private double initialSx;
129 
130     /**
131      * Initial y scaling factor.
132      */
133     private double initialSy;
134 
135     /**
136      * Initial z scaling factor.
137      */
138     private double initialSz;
139 
140     /**
141      * Initial x-y cross coupling error.
142      */
143     private double initialMxy;
144 
145     /**
146      * Initial x-z cross coupling error.
147      */
148     private double initialMxz;
149 
150     /**
151      * Initial y-x cross coupling error.
152      */
153     private double initialMyx;
154 
155     /**
156      * Initial y-z cross coupling error.
157      */
158     private double initialMyz;
159 
160     /**
161      * Initial z-x cross coupling error.
162      */
163     private double initialMzx;
164 
165     /**
166      * Initial z-y cross coupling error.
167      */
168     private double initialMzy;
169 
170     /**
171      * Contains a collection of body magnetic flux density measurements taken
172      * at different frames (positions and orientations) and containing the
173      * standard deviation of magnetometer measurements.
174      * If a single device magnetometer needs to be calibrated, typically all
175      * measurements are taken at the same position, with zero velocity and
176      * multiple orientations.
177      * However, if we just want to calibrate a given magnetometer model (e.g.
178      * obtain an average and less precise calibration for the magnetometer of
179      * a given phone model), we could take measurements collected throughout
180      * the planet at multiple positions while the phone remains static (e.g.
181      * while charging), hence each measurement position will change, velocity
182      * will remain zero and orientation will be typically constant at
183      * horizontal orientation while the phone remains on a
184      * flat surface.
185      */
186     private Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements;
187 
188     /**
189      * This flag indicates whether z-axis is assumed to be common for accelerometer,
190      * gyroscope and magnetometer.
191      * When enabled, this eliminates 3 variables from Mm matrix.
192      */
193     private boolean commonAxisUsed = DEFAULT_USE_COMMON_Z_AXIS;
194 
195     /**
196      * Listener to handle events raised by this calibrator.
197      */
198     private KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener;
199 
200     /**
201      * Estimated magnetometer hard-iron biases for each magnetometer axis
202      * expressed in Teslas (T).
203      */
204     private double[] estimatedHardIron;
205 
206     /**
207      * Estimated magnetometer soft-iron matrix containing scale factors
208      * and cross coupling errors.
209      * This is the product of matrix Tm containing cross coupling errors and Km
210      * containing scaling factors.
211      * So tat:
212      * <pre>
213      *     Mm = [sx    mxy  mxz] = Tm*Km
214      *          [myx   sy   myz]
215      *          [mzx   mzy  sz ]
216      * </pre>
217      * Where:
218      * <pre>
219      *     Km = [sx 0   0 ]
220      *          [0  sy  0 ]
221      *          [0  0   sz]
222      * </pre>
223      * and
224      * <pre>
225      *     Tm = [1          -alphaXy    alphaXz ]
226      *          [alphaYx    1           -alphaYz]
227      *          [-alphaZx   alphaZy     1       ]
228      * </pre>
229      * Hence:
230      * <pre>
231      *     Mm = [sx    mxy  mxz] = Tm*Km =  [sx             -sy * alphaXy   sz * alphaXz ]
232      *          [myx   sy   myz]            [sx * alphaYx   sy              -sz * alphaYz]
233      *          [mzx   mzy  sz ]            [-sx * alphaZx  sy * alphaZy    sz           ]
234      * </pre>
235      * This instance allows any 3x3 matrix however, typically alphaYx, alphaZx and alphaZy
236      * are considered to be zero if the accelerometer z-axis is assumed to be the same
237      * as the body z-axis. When this is assumed, myx = mzx = mzy = 0 and the Mm matrix
238      * becomes upper diagonal:
239      * <pre>
240      *     Mm = [sx    mxy  mxz]
241      *          [0     sy   myz]
242      *          [0     0    sz ]
243      * </pre>
244      * Values of this matrix are unit-less.
245      */
246     private Matrix estimatedMm;
247 
248     /**
249      * Estimated covariance matrix for estimated parameters.
250      */
251     private Matrix estimatedCovariance;
252 
253     /**
254      * Estimated chi square value.
255      */
256     private double estimatedChiSq;
257 
258     /**
259      * Estimated degrees of freedom of chi square value. Degrees of freedom is equal to the number of sampled data
260      * minus the number of estimated parameters.
261      */
262     private int estimatedChiSqDegreesOfFreedom;
263 
264     /**
265      * Estimated reduced chi square value. This is equal to estimated chi square value divided by its degrees of
266      * freedom. Ideally this value should be close to 1.0.
267      */
268     private double estimatedReducedChiSq;
269 
270     /**
271      * Estimated mean square error respect to provided measurements.
272      */
273     private double estimatedMse;
274 
275     /**
276      * Estimated probability of finding a smaller chi square value expressed as a value between 0.0 and 1.0. The smaller
277      * the found chi square value is, the better the fit of the estimated parameters to the actual parameter. Thus, the
278      * smaller the chance of finding a smaller chi square value, then the better the estimated fit is.
279      */
280     private double estimatedP;
281 
282     /**
283      * Estimated measure of quality of estimated fit as a value between 0.0 and 1.0. The larger the quality value is,
284      * the better the fit that has been estimated.
285      */
286     private double estimatedQ;
287 
288     /**
289      * Indicates whether calibrator is running.
290      */
291     private boolean running;
292 
293     /**
294      * Contains Earth's magnetic model.
295      */
296     private WorldMagneticModel magneticModel;
297 
298     /**
299      * Constructor.
300      */
301     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator() {
302     }
303 
304     /**
305      * Constructor
306      *
307      * @param listener listener to handle events raised by this calibrator.
308      */
309     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
310             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
311         this.listener = listener;
312     }
313 
314     /**
315      * Constructor.
316      *
317      * @param measurements collection of body magnetic flux density measurements with
318      *                     standard deviations taken at different frames (positions
319      *                     and orientations).
320      */
321     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
322             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements) {
323         this.measurements = measurements;
324     }
325 
326     /**
327      * Constructor.
328      *
329      * @param measurements collection of body magnetic flux density measurements with
330      *                     standard deviations taken at different frames (positions
331      *                     and orientations).
332      * @param listener     listener to handle events raised by this calibrator.
333      */
334     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
335             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
336             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
337         this(measurements);
338         this.listener = listener;
339     }
340 
341     /**
342      * Constructor.
343      *
344      * @param commonAxisUsed indicates whether z-axis is assumed to be common
345      *                       for the accelerometer, gyroscope and magnetometer.
346      */
347     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(final boolean commonAxisUsed) {
348         this.commonAxisUsed = commonAxisUsed;
349     }
350 
351     /**
352      * Constructor.
353      *
354      * @param commonAxisUsed indicates whether z-axis is assumed to be common
355      *                       for the accelerometer, gyroscope and magnetometer.
356      * @param listener       listener to handle events raised by this calibrator.
357      */
358     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
359             final boolean commonAxisUsed,
360             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
361         this(commonAxisUsed);
362         this.listener = listener;
363     }
364 
365     /**
366      * Constructor.
367      *
368      * @param measurements   collection of body magnetic flux density measurements with
369      *                       standard deviations taken at different frames (positions
370      *                       and orientations).
371      * @param commonAxisUsed indicates whether z-axis is assumed to be common
372      *                       for the accelerometer, gyroscope and magnetometer.
373      */
374     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
375             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
376             final boolean commonAxisUsed) {
377         this(measurements);
378         this.commonAxisUsed = commonAxisUsed;
379     }
380 
381     /**
382      * Constructor.
383      *
384      * @param measurements   collection of body magnetic flux density measurements with
385      *                       standard deviations taken at different frames (positions
386      *                       and orientations).
387      * @param commonAxisUsed indicates whether z-axis is assumed to be common
388      *                       for the accelerometer, gyroscope and magnetometer.
389      * @param listener       listener to handle events raised by this calibrator.
390      */
391     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
392             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
393             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
394         this(measurements, commonAxisUsed);
395         this.listener = listener;
396     }
397 
398     /**
399      * Constructor.
400      *
401      * @param magneticModel Earth's magnetic model. If null, a default model
402      *                      will be used instead.
403      */
404     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(final WorldMagneticModel magneticModel) {
405         this.magneticModel = magneticModel;
406     }
407 
408     /**
409      * Constructor.
410      *
411      * @param magneticModel Earth's magnetic model. If null, a default model
412      *                      will be used instead.
413      * @param listener      listener to handle events raised by this calibrator.
414      */
415     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
416             final WorldMagneticModel magneticModel,
417             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
418         this(listener);
419         this.magneticModel = magneticModel;
420     }
421 
422     /**
423      * Constructor.
424      *
425      * @param measurements  collection of body magnetic flux density measurements with
426      *                      standard deviations taken at different frames (positions
427      *                      and orientations).
428      * @param magneticModel Earth's magnetic model. If null, a default model
429      *                      will be used instead.
430      */
431     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
432             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
433             final WorldMagneticModel magneticModel) {
434         this(measurements);
435         this.magneticModel = magneticModel;
436     }
437 
438     /**
439      * Constructor.
440      *
441      * @param measurements  collection of body magnetic flux density measurements with
442      *                      standard deviations taken at different frames (positions
443      *                      and orientations).
444      * @param magneticModel Earth's magnetic model. If null, a default model
445      *                      will be used instead.
446      * @param listener      listener to handle events raised by this calibrator.
447      */
448     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
449             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
450             final WorldMagneticModel magneticModel,
451             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
452         this(measurements, listener);
453         this.magneticModel = magneticModel;
454     }
455 
456     /**
457      * Constructor.
458      *
459      * @param commonAxisUsed indicates whether z-axis is assumed to be common
460      *                       for the accelerometer, gyroscope and magnetometer.
461      * @param magneticModel  Earth's magnetic model. If null, a default model
462      *                       will be used instead.
463      */
464     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
465             final boolean commonAxisUsed, final WorldMagneticModel magneticModel) {
466         this(commonAxisUsed);
467         this.magneticModel = magneticModel;
468     }
469 
470     /**
471      * Constructor.
472      *
473      * @param commonAxisUsed indicates whether z-axis is assumed to be common
474      *                       for the accelerometer, gyroscope and magnetometer.
475      * @param magneticModel  Earth's magnetic model. If null, a default model
476      *                       will be used instead.
477      * @param listener       listener to handle events raised by this calibrator.
478      */
479     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
480             final boolean commonAxisUsed, final WorldMagneticModel magneticModel,
481             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
482         this(commonAxisUsed, listener);
483         this.magneticModel = magneticModel;
484     }
485 
486     /**
487      * Constructor.
488      *
489      * @param measurements   collection of body magnetic flux density measurements with
490      *                       standard deviations taken at different frames (positions
491      *                       and orientations).
492      * @param commonAxisUsed indicates whether z-axis is assumed to be common
493      *                       for the accelerometer, gyroscope and magnetometer.
494      * @param magneticModel  Earth's magnetic model. If null, a default model
495      *                       will be used instead.
496      */
497     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
498             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
499             final WorldMagneticModel magneticModel) {
500         this(measurements, commonAxisUsed);
501         this.magneticModel = magneticModel;
502     }
503 
504     /**
505      * Constructor.
506      *
507      * @param measurements   collection of body magnetic flux density measurements with
508      *                       standard deviations taken at different frames (positions
509      *                       and orientations).
510      * @param commonAxisUsed indicates whether z-axis is assumed to be common
511      *                       for the accelerometer, gyroscope and magnetometer.
512      * @param magneticModel  Earth's magnetic model. If null, a default model
513      *                       will be used instead.
514      * @param listener       listener to handle events raised by this calibrator.
515      */
516     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
517             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
518             final WorldMagneticModel magneticModel,
519             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
520         this(measurements, commonAxisUsed, listener);
521         this.magneticModel = magneticModel;
522     }
523 
524     /**
525      * Constructor.
526      *
527      * @param initialHardIronX initial x-coordinate of magnetometer
528      *                         hard-iron bias expressed in Teslas (T).
529      * @param initialHardIronY initial y-coordinate of magnetometer
530      *                         hard-iron bias expressed in Teslas (T).
531      * @param initialHardIronZ initial z-coordinate of magnetometer
532      *                         hard-iron bias expressed in Teslas (T).
533      */
534     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
535             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ) {
536         try {
537             setInitialHardIron(initialHardIronX, initialHardIronY, initialHardIronZ);
538         } catch (final LockedException ignore) {
539             // never happens
540         }
541     }
542 
543     /**
544      * Constructor.
545      *
546      * @param initialHardIronX initial x-coordinate of magnetometer
547      *                         hard-iron bias expressed in Teslas (T).
548      * @param initialHardIronY initial y-coordinate of magnetometer
549      *                         hard-iron bias expressed in Teslas (T).
550      * @param initialHardIronZ initial z-coordinate of magnetometer
551      *                         hard-iron bias expressed in Teslas (T).
552      * @param listener         listener to handle events raised by this calibrator.
553      */
554     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
555             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
556             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
557         this(initialHardIronX, initialHardIronY, initialHardIronZ);
558         this.listener = listener;
559     }
560 
561     /**
562      * Constructor.
563      *
564      * @param measurements     collection of body magnetic flux density measurements with
565      *                         standard deviations taken at different frames (positions
566      *                         and orientations).
567      * @param initialHardIronX initial x-coordinate of magnetometer
568      *                         hard-iron bias expressed in Teslas (T).
569      * @param initialHardIronY initial y-coordinate of magnetometer
570      *                         hard-iron bias expressed in Teslas (T).
571      * @param initialHardIronZ initial z-coordinate of magnetometer
572      *                         hard-iron bias expressed in Teslas (T).
573      */
574     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
575             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
576             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ) {
577         this(initialHardIronX, initialHardIronY, initialHardIronZ);
578         this.measurements = measurements;
579     }
580 
581     /**
582      * Constructor.
583      *
584      * @param measurements     collection of body magnetic flux density measurements with
585      *                         standard deviations taken at different frames (positions
586      *                         and orientations).
587      * @param initialHardIronX initial x-coordinate of magnetometer
588      *                         hard-iron bias expressed in Teslas (T).
589      * @param initialHardIronY initial y-coordinate of magnetometer
590      *                         hard-iron bias expressed in Teslas (T).
591      * @param initialHardIronZ initial z-coordinate of magnetometer
592      *                         hard-iron bias expressed in Teslas (T).
593      * @param listener         listener to handle events raised by this calibrator.
594      */
595     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
596             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
597             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
598             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
599         this(measurements, initialHardIronX, initialHardIronY, initialHardIronZ);
600         this.listener = listener;
601     }
602 
603     /**
604      * Constructor.
605      *
606      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
607      *                         for the accelerometer, gyroscope and magnetometer.
608      * @param initialHardIronX initial x-coordinate of magnetometer
609      *                         hard-iron bias expressed in Teslas (T).
610      * @param initialHardIronY initial y-coordinate of magnetometer
611      *                         hard-iron bias expressed in Teslas (T).
612      * @param initialHardIronZ initial z-coordinate of magnetometer
613      *                         hard-iron bias expressed in Teslas (T).
614      */
615     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
616             final boolean commonAxisUsed, final double initialHardIronX, final double initialHardIronY,
617             final double initialHardIronZ) {
618         this(initialHardIronX, initialHardIronY, initialHardIronZ);
619         this.commonAxisUsed = commonAxisUsed;
620     }
621 
622     /**
623      * Constructor.
624      *
625      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
626      *                         for the accelerometer, gyroscope and magnetometer.
627      * @param initialHardIronX initial x-coordinate of magnetometer
628      *                         hard-iron bias expressed in Teslas (T).
629      * @param initialHardIronY initial y-coordinate of magnetometer
630      *                         hard-iron bias expressed in Teslas (T).
631      * @param initialHardIronZ initial z-coordinate of magnetometer
632      *                         hard-iron bias expressed in Teslas (T).
633      * @param listener         listener to handle events raised by this calibrator.
634      */
635     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
636             final boolean commonAxisUsed, final double initialHardIronX, final double initialHardIronY,
637             final double initialHardIronZ,
638             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
639         this(commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ);
640         this.listener = listener;
641     }
642 
643     /**
644      * Constructor.
645      *
646      * @param measurements     collection of body magnetic flux density measurements with
647      *                         standard deviations taken at different frames (positions
648      *                         and orientations).
649      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
650      *                         for the accelerometer, gyroscope and magnetometer.
651      * @param initialHardIronX initial x-coordinate of magnetometer
652      *                         hard-iron bias expressed in Teslas (T).
653      * @param initialHardIronY initial y-coordinate of magnetometer
654      *                         hard-iron bias expressed in Teslas (T).
655      * @param initialHardIronZ initial z-coordinate of magnetometer
656      *                         hard-iron bias expressed in Teslas (T).
657      */
658     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
659             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
660             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ) {
661         this(commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ);
662         this.measurements = measurements;
663     }
664 
665     /**
666      * Constructor.
667      *
668      * @param measurements     collection of body magnetic flux density measurements with
669      *                         standard deviations taken at different frames (positions
670      *                         and orientations).
671      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
672      *                         for the accelerometer, gyroscope and magnetometer.
673      * @param initialHardIronX initial x-coordinate of magnetometer
674      *                         hard-iron bias expressed in Teslas (T).
675      * @param initialHardIronY initial y-coordinate of magnetometer
676      *                         hard-iron bias expressed in Teslas (T).
677      * @param initialHardIronZ initial z-coordinate of magnetometer
678      *                         hard-iron bias expressed in Teslas (T).
679      * @param listener         listener to handle events raised by this calibrator.
680      */
681     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
682             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
683             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
684             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
685         this(measurements, commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ);
686         this.listener = listener;
687     }
688 
689     /**
690      * Constructor.
691      *
692      * @param magneticModel    Earth's magnetic model. If null, a default model
693      *                         will be used instead.
694      * @param initialHardIronX initial x-coordinate of magnetometer
695      *                         hard-iron bias expressed in Teslas (T).
696      * @param initialHardIronY initial y-coordinate of magnetometer
697      *                         hard-iron bias expressed in Teslas (T).
698      * @param initialHardIronZ initial z-coordinate of magnetometer
699      *                         hard-iron bias expressed in Teslas (T).
700      */
701     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
702             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
703             final double initialHardIronZ) {
704         this(initialHardIronX, initialHardIronY, initialHardIronZ);
705         this.magneticModel = magneticModel;
706     }
707 
708     /**
709      * Constructor.
710      *
711      * @param magneticModel    Earth's magnetic model. If null, a default model
712      *                         will be used instead.
713      * @param initialHardIronX initial x-coordinate of magnetometer
714      *                         hard-iron bias expressed in Teslas (T).
715      * @param initialHardIronY initial y-coordinate of magnetometer
716      *                         hard-iron bias expressed in Teslas (T).
717      * @param initialHardIronZ initial z-coordinate of magnetometer
718      *                         hard-iron bias expressed in Teslas (T).
719      * @param listener         listener to handle events raised by this calibrator.
720      */
721     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
722             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
723             final double initialHardIronZ,
724             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
725         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ);
726         this.listener = listener;
727     }
728 
729     /**
730      * Constructor.
731      *
732      * @param measurements     collection of body magnetic flux density measurements with
733      *                         standard deviations taken at different frames (positions
734      *                         and orientations).
735      * @param magneticModel    Earth's magnetic model. If null, a default model
736      *                         will be used instead.
737      * @param initialHardIronX initial x-coordinate of magnetometer
738      *                         hard-iron bias expressed in Teslas (T).
739      * @param initialHardIronY initial y-coordinate of magnetometer
740      *                         hard-iron bias expressed in Teslas (T).
741      * @param initialHardIronZ initial z-coordinate of magnetometer
742      *                         hard-iron bias expressed in Teslas (T).
743      */
744     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
745             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
746             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
747             final double initialHardIronZ) {
748         this(initialHardIronX, initialHardIronY, initialHardIronZ);
749         this.measurements = measurements;
750         this.magneticModel = magneticModel;
751     }
752 
753     /**
754      * Constructor.
755      *
756      * @param measurements     collection of body magnetic flux density measurements with
757      *                         standard deviations taken at different frames (positions
758      *                         and orientations).
759      * @param magneticModel    Earth's magnetic model. If null, a default model
760      *                         will be used instead.
761      * @param initialHardIronX initial x-coordinate of magnetometer
762      *                         hard-iron bias expressed in Teslas (T).
763      * @param initialHardIronY initial y-coordinate of magnetometer
764      *                         hard-iron bias expressed in Teslas (T).
765      * @param initialHardIronZ initial z-coordinate of magnetometer
766      *                         hard-iron bias expressed in Teslas (T).
767      * @param listener         listener to handle events raised by this calibrator.
768      */
769     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
770             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
771             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
772             final double initialHardIronZ,
773             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
774         this(measurements, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ);
775         this.listener = listener;
776     }
777 
778     /**
779      * Constructor.
780      *
781      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
782      *                         for the accelerometer, gyroscope and magnetometer.
783      * @param magneticModel    Earth's magnetic model. If null, a default model
784      *                         will be used instead.
785      * @param initialHardIronX initial x-coordinate of magnetometer
786      *                         hard-iron bias expressed in Teslas (T).
787      * @param initialHardIronY initial y-coordinate of magnetometer
788      *                         hard-iron bias expressed in Teslas (T).
789      * @param initialHardIronZ initial z-coordinate of magnetometer
790      *                         hard-iron bias expressed in Teslas (T).
791      */
792     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
793             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final double initialHardIronX,
794             final double initialHardIronY, final double initialHardIronZ) {
795         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ);
796         this.commonAxisUsed = commonAxisUsed;
797     }
798 
799     /**
800      * Constructor.
801      *
802      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
803      *                         for the accelerometer, gyroscope and magnetometer.
804      * @param magneticModel    Earth's magnetic model. If null, a default model
805      *                         will be used instead.
806      * @param initialHardIronX initial x-coordinate of magnetometer
807      *                         hard-iron bias expressed in Teslas (T).
808      * @param initialHardIronY initial y-coordinate of magnetometer
809      *                         hard-iron bias expressed in Teslas (T).
810      * @param initialHardIronZ initial z-coordinate of magnetometer
811      *                         hard-iron bias expressed in Teslas (T).
812      * @param listener         listener to handle events raised by this calibrator.
813      */
814     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
815             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final double initialHardIronX,
816             final double initialHardIronY, final double initialHardIronZ,
817             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
818         this(commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ);
819         this.listener = listener;
820     }
821 
822     /**
823      * Constructor.
824      *
825      * @param measurements     collection of body magnetic flux density measurements with
826      *                         standard deviations taken at different frames (positions
827      *                         and orientations).
828      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
829      *                         for the accelerometer, gyroscope and magnetometer.
830      * @param magneticModel    Earth's magnetic model. If null, a default model
831      *                         will be used instead.
832      * @param initialHardIronX initial x-coordinate of magnetometer
833      *                         hard-iron bias expressed in Teslas (T).
834      * @param initialHardIronY initial y-coordinate of magnetometer
835      *                         hard-iron bias expressed in Teslas (T).
836      * @param initialHardIronZ initial z-coordinate of magnetometer
837      *                         hard-iron bias expressed in Teslas (T).
838      */
839     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
840             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
841             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
842             final double initialHardIronZ) {
843         this(commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ);
844         this.measurements = measurements;
845     }
846 
847     /**
848      * Constructor.
849      *
850      * @param measurements     collection of body magnetic flux density measurements with
851      *                         standard deviations taken at different frames (positions
852      *                         and orientations).
853      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
854      *                         for the accelerometer, gyroscope and magnetometer.
855      * @param magneticModel    Earth's magnetic model. If null, a default model
856      *                         will be used instead.
857      * @param initialHardIronX initial x-coordinate of magnetometer
858      *                         hard-iron bias expressed in Teslas (T).
859      * @param initialHardIronY initial y-coordinate of magnetometer
860      *                         hard-iron bias expressed in Teslas (T).
861      * @param initialHardIronZ initial z-coordinate of magnetometer
862      *                         hard-iron bias expressed in Teslas (T).
863      * @param listener         listener to handle events raised by this calibrator.
864      */
865     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
866             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
867             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
868             final double initialHardIronZ,
869             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
870         this(measurements, commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ);
871         this.listener = listener;
872     }
873 
874     /**
875      * Constructor.
876      *
877      * @param initialHardIronX initial x-coordinate of magnetometer
878      *                         hard-iron bias expressed in Teslas (T).
879      * @param initialHardIronY initial y-coordinate of magnetometer
880      *                         hard-iron bias expressed in Teslas (T).
881      * @param initialHardIronZ initial z-coordinate of magnetometer
882      *                         hard-iron bias expressed in Teslas (T).
883      * @param initialSx        initial x scaling factor.
884      * @param initialSy        initial y scaling factor.
885      * @param initialSz        initial z scaling factor.
886      */
887     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
888             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
889             final double initialSx, final double initialSy, final double initialSz) {
890         this(initialHardIronX, initialHardIronY, initialHardIronZ);
891         try {
892             setInitialScalingFactors(initialSx, initialSy, initialSz);
893         } catch (final LockedException ignore) {
894             // never happens
895         }
896     }
897 
898     /**
899      * Constructor.
900      *
901      * @param initialHardIronX initial x-coordinate of magnetometer
902      *                         hard-iron bias expressed in Teslas (T).
903      * @param initialHardIronY initial y-coordinate of magnetometer
904      *                         hard-iron bias expressed in Teslas (T).
905      * @param initialHardIronZ initial z-coordinate of magnetometer
906      *                         hard-iron bias expressed in Teslas (T).
907      * @param initialSx        initial x scaling factor.
908      * @param initialSy        initial y scaling factor.
909      * @param initialSz        initial z scaling factor.
910      * @param listener         listener to handle events raised by this calibrator.
911      */
912     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
913             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
914             final double initialSx, final double initialSy, final double initialSz,
915             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
916         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
917         this.listener = listener;
918     }
919 
920     /**
921      * Constructor.
922      *
923      * @param measurements     collection of body magnetic flux density measurements with
924      *                         standard deviations taken at different frames (positions
925      *                         and orientations).
926      * @param initialHardIronX initial x-coordinate of magnetometer
927      *                         hard-iron bias expressed in Teslas (T).
928      * @param initialHardIronY initial y-coordinate of magnetometer
929      *                         hard-iron bias expressed in Teslas (T).
930      * @param initialHardIronZ initial z-coordinate of magnetometer
931      *                         hard-iron bias expressed in Teslas (T).
932      * @param initialSx        initial x scaling factor.
933      * @param initialSy        initial y scaling factor.
934      * @param initialSz        initial z scaling factor.
935      */
936     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
937             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
938             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
939             final double initialSx, final double initialSy, final double initialSz) {
940         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
941         this.measurements = measurements;
942     }
943 
944     /**
945      * Constructor.
946      *
947      * @param measurements     collection of body magnetic flux density measurements with
948      *                         standard deviations taken at different frames (positions
949      *                         and orientations).
950      * @param initialHardIronX initial x-coordinate of magnetometer
951      *                         hard-iron bias expressed in Teslas (T).
952      * @param initialHardIronY initial y-coordinate of magnetometer
953      *                         hard-iron bias expressed in Teslas (T).
954      * @param initialHardIronZ initial z-coordinate of magnetometer
955      *                         hard-iron bias expressed in Teslas (T).
956      * @param initialSx        initial x scaling factor.
957      * @param initialSy        initial y scaling factor.
958      * @param initialSz        initial z scaling factor.
959      * @param listener         listener to handle events raised by this calibrator.
960      */
961     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
962             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
963             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
964             final double initialSx, final double initialSy, final double initialSz,
965             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
966         this(measurements, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
967         this.listener = listener;
968     }
969 
970     /**
971      * Constructor.
972      *
973      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
974      *                         for the accelerometer, gyroscope and magnetometer.
975      * @param initialHardIronX initial x-coordinate of magnetometer
976      *                         hard-iron bias expressed in Teslas (T).
977      * @param initialHardIronY initial y-coordinate of magnetometer
978      *                         hard-iron bias expressed in Teslas (T).
979      * @param initialHardIronZ initial z-coordinate of magnetometer
980      *                         hard-iron bias expressed in Teslas (T).
981      * @param initialSx        initial x scaling factor.
982      * @param initialSy        initial y scaling factor.
983      * @param initialSz        initial z scaling factor.
984      */
985     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
986             final boolean commonAxisUsed, final double initialHardIronX, final double initialHardIronY,
987             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz) {
988         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
989         this.commonAxisUsed = commonAxisUsed;
990     }
991 
992     /**
993      * Constructor.
994      *
995      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
996      *                         for the accelerometer, gyroscope and magnetometer.
997      * @param initialHardIronX initial x-coordinate of magnetometer
998      *                         hard-iron bias expressed in Teslas (T).
999      * @param initialHardIronY initial y-coordinate of magnetometer
1000      *                         hard-iron bias expressed in Teslas (T).
1001      * @param initialHardIronZ initial z-coordinate of magnetometer
1002      *                         hard-iron bias expressed in Teslas (T).
1003      * @param initialSx        initial x scaling factor.
1004      * @param initialSy        initial y scaling factor.
1005      * @param initialSz        initial z scaling factor.
1006      * @param listener         listener to handle events raised by this calibrator.
1007      */
1008     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1009             final boolean commonAxisUsed, final double initialHardIronX, final double initialHardIronY,
1010             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1011             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1012         this(commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
1013         this.listener = listener;
1014     }
1015 
1016     /**
1017      * Constructor.
1018      *
1019      * @param measurements     collection of body magnetic flux density measurements with
1020      *                         standard deviations taken at different frames (positions
1021      *                         and orientations).
1022      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1023      *                         for the accelerometer, gyroscope and magnetometer.
1024      * @param initialHardIronX initial x-coordinate of magnetometer
1025      *                         hard-iron bias expressed in Teslas (T).
1026      * @param initialHardIronY initial y-coordinate of magnetometer
1027      *                         hard-iron bias expressed in Teslas (T).
1028      * @param initialHardIronZ initial z-coordinate of magnetometer
1029      *                         hard-iron bias expressed in Teslas (T).
1030      * @param initialSx        initial x scaling factor.
1031      * @param initialSy        initial y scaling factor.
1032      * @param initialSz        initial z scaling factor.
1033      */
1034     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1035             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1036             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1037             final double initialSx, final double initialSy, final double initialSz) {
1038         this(commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
1039         this.measurements = measurements;
1040     }
1041 
1042     /**
1043      * Constructor.
1044      *
1045      * @param measurements     collection of body magnetic flux density measurements with
1046      *                         standard deviations taken at different frames (positions
1047      *                         and orientations).
1048      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1049      *                         for the accelerometer, gyroscope and magnetometer.
1050      * @param initialHardIronX initial x-coordinate of magnetometer
1051      *                         hard-iron bias expressed in Teslas (T).
1052      * @param initialHardIronY initial y-coordinate of magnetometer
1053      *                         hard-iron bias expressed in Teslas (T).
1054      * @param initialHardIronZ initial z-coordinate of magnetometer
1055      *                         hard-iron bias expressed in Teslas (T).
1056      * @param initialSx        initial x scaling factor.
1057      * @param initialSy        initial y scaling factor.
1058      * @param initialSz        initial z scaling factor.
1059      * @param listener         listener to handle events raised by this calibrator.
1060      */
1061     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1062             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1063             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1064             final double initialSx, final double initialSy, final double initialSz,
1065             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1066         this(measurements, commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ,
1067                 initialSx, initialSy, initialSz);
1068         this.listener = listener;
1069     }
1070 
1071     /**
1072      * Constructor.
1073      *
1074      * @param magneticModel    Earth's magnetic model. If null, a default model
1075      *                         will be used instead.
1076      * @param initialHardIronX initial x-coordinate of magnetometer
1077      *                         hard-iron bias expressed in Teslas (T).
1078      * @param initialHardIronY initial y-coordinate of magnetometer
1079      *                         hard-iron bias expressed in Teslas (T).
1080      * @param initialHardIronZ initial z-coordinate of magnetometer
1081      *                         hard-iron bias expressed in Teslas (T).
1082      * @param initialSx        initial x scaling factor.
1083      * @param initialSy        initial y scaling factor.
1084      * @param initialSz        initial z scaling factor.
1085      */
1086     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1087             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1088             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz) {
1089         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
1090         this.magneticModel = magneticModel;
1091     }
1092 
1093     /**
1094      * Constructor.
1095      *
1096      * @param magneticModel    Earth's magnetic model. If null, a default model
1097      *                         will be used instead.
1098      * @param initialHardIronX initial x-coordinate of magnetometer
1099      *                         hard-iron bias expressed in Teslas (T).
1100      * @param initialHardIronY initial y-coordinate of magnetometer
1101      *                         hard-iron bias expressed in Teslas (T).
1102      * @param initialHardIronZ initial z-coordinate of magnetometer
1103      *                         hard-iron bias expressed in Teslas (T).
1104      * @param initialSx        initial x scaling factor.
1105      * @param initialSy        initial y scaling factor.
1106      * @param initialSz        initial z scaling factor.
1107      * @param listener         listener to handle events raised by this calibrator.
1108      */
1109     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1110             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1111             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1112             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1113         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
1114         this.listener = listener;
1115     }
1116 
1117     /**
1118      * Constructor.
1119      *
1120      * @param measurements     collection of body magnetic flux density measurements with
1121      *                         standard deviations taken at different frames (positions
1122      *                         and orientations).
1123      * @param magneticModel    Earth's magnetic model. If null, a default model
1124      *                         will be used instead.
1125      * @param initialHardIronX initial x-coordinate of magnetometer
1126      *                         hard-iron bias expressed in Teslas (T).
1127      * @param initialHardIronY initial y-coordinate of magnetometer
1128      *                         hard-iron bias expressed in Teslas (T).
1129      * @param initialHardIronZ initial z-coordinate of magnetometer
1130      *                         hard-iron bias expressed in Teslas (T).
1131      * @param initialSx        initial x scaling factor.
1132      * @param initialSy        initial y scaling factor.
1133      * @param initialSz        initial z scaling factor.
1134      */
1135     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1136             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1137             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1138             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz) {
1139         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
1140         this.measurements = measurements;
1141     }
1142 
1143     /**
1144      * Constructor.
1145      *
1146      * @param measurements     collection of body magnetic flux density measurements with
1147      *                         standard deviations taken at different frames (positions
1148      *                         and orientations).
1149      * @param magneticModel    Earth's magnetic model. If null, a default model
1150      *                         will be used instead.
1151      * @param initialHardIronX initial x-coordinate of magnetometer
1152      *                         hard-iron bias expressed in Teslas (T).
1153      * @param initialHardIronY initial y-coordinate of magnetometer
1154      *                         hard-iron bias expressed in Teslas (T).
1155      * @param initialHardIronZ initial z-coordinate of magnetometer
1156      *                         hard-iron bias expressed in Teslas (T).
1157      * @param initialSx        initial x scaling factor.
1158      * @param initialSy        initial y scaling factor.
1159      * @param initialSz        initial z scaling factor.
1160      * @param listener         listener to handle events raised by this calibrator.
1161      */
1162     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1163             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1164             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1165             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1166             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1167         this(measurements, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1168                 initialSx, initialSy, initialSz);
1169         this.listener = listener;
1170     }
1171 
1172     /**
1173      * Constructor.
1174      *
1175      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1176      *                         for the accelerometer, gyroscope and magnetometer.
1177      * @param magneticModel    Earth's magnetic model. If null, a default model
1178      *                         will be used instead.
1179      * @param initialHardIronX initial x-coordinate of magnetometer
1180      *                         hard-iron bias expressed in Teslas (T).
1181      * @param initialHardIronY initial y-coordinate of magnetometer
1182      *                         hard-iron bias expressed in Teslas (T).
1183      * @param initialHardIronZ initial z-coordinate of magnetometer
1184      *                         hard-iron bias expressed in Teslas (T).
1185      * @param initialSx        initial x scaling factor.
1186      * @param initialSy        initial y scaling factor.
1187      * @param initialSz        initial z scaling factor.
1188      */
1189     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1190             final boolean commonAxisUsed, final WorldMagneticModel magneticModel,
1191             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1192             final double initialSx, final double initialSy, final double initialSz) {
1193         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz);
1194         this.commonAxisUsed = commonAxisUsed;
1195     }
1196 
1197     /**
1198      * Constructor.
1199      *
1200      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1201      *                         for the accelerometer, gyroscope and magnetometer.
1202      * @param magneticModel    Earth's magnetic model. If null, a default model
1203      *                         will be used instead.
1204      * @param initialHardIronX initial x-coordinate of magnetometer
1205      *                         hard-iron bias expressed in Teslas (T).
1206      * @param initialHardIronY initial y-coordinate of magnetometer
1207      *                         hard-iron bias expressed in Teslas (T).
1208      * @param initialHardIronZ initial z-coordinate of magnetometer
1209      *                         hard-iron bias expressed in Teslas (T).
1210      * @param initialSx        initial x scaling factor.
1211      * @param initialSy        initial y scaling factor.
1212      * @param initialSz        initial z scaling factor.
1213      * @param listener         listener to handle events raised by this calibrator.
1214      */
1215     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1216             final boolean commonAxisUsed, final WorldMagneticModel magneticModel,
1217             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1218             final double initialSx, final double initialSy, final double initialSz,
1219             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1220         this(commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1221                 initialSx, initialSy, initialSz);
1222         this.listener = listener;
1223     }
1224 
1225     /**
1226      * Constructor.
1227      *
1228      * @param measurements     collection of body magnetic flux density measurements with
1229      *                         standard deviations taken at different frames (positions
1230      *                         and orientations).
1231      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1232      *                         for the accelerometer, gyroscope and magnetometer.
1233      * @param magneticModel    Earth's magnetic model. If null, a default model
1234      *                         will be used instead.
1235      * @param initialHardIronX initial x-coordinate of magnetometer
1236      *                         hard-iron bias expressed in Teslas (T).
1237      * @param initialHardIronY initial y-coordinate of magnetometer
1238      *                         hard-iron bias expressed in Teslas (T).
1239      * @param initialHardIronZ initial z-coordinate of magnetometer
1240      *                         hard-iron bias expressed in Teslas (T).
1241      * @param initialSx        initial x scaling factor.
1242      * @param initialSy        initial y scaling factor.
1243      * @param initialSz        initial z scaling factor.
1244      */
1245     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1246             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1247             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1248             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz) {
1249         this(commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1250                 initialSx, initialSy, initialSz);
1251         this.measurements = measurements;
1252     }
1253 
1254     /**
1255      * Constructor.
1256      *
1257      * @param measurements     collection of body magnetic flux density measurements with
1258      *                         standard deviations taken at different frames (positions
1259      *                         and orientations).
1260      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1261      *                         for the accelerometer, gyroscope and magnetometer.
1262      * @param magneticModel    Earth's magnetic model. If null, a default model
1263      *                         will be used instead.
1264      * @param initialHardIronX initial x-coordinate of magnetometer
1265      *                         hard-iron bias expressed in Teslas (T).
1266      * @param initialHardIronY initial y-coordinate of magnetometer
1267      *                         hard-iron bias expressed in Teslas (T).
1268      * @param initialHardIronZ initial z-coordinate of magnetometer
1269      *                         hard-iron bias expressed in Teslas (T).
1270      * @param initialSx        initial x scaling factor.
1271      * @param initialSy        initial y scaling factor.
1272      * @param initialSz        initial z scaling factor.
1273      * @param listener         listener to handle events raised by this calibrator.
1274      */
1275     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1276             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1277             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1278             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1279             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1280         this(measurements, commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1281                 initialSx, initialSy, initialSz);
1282         this.listener = listener;
1283     }
1284 
1285     /**
1286      * Constructor.
1287      *
1288      * @param initialHardIronX initial x-coordinate of magnetometer
1289      *                         hard-iron bias expressed in Teslas (T).
1290      * @param initialHardIronY initial y-coordinate of magnetometer
1291      *                         hard-iron bias expressed in Teslas (T).
1292      * @param initialHardIronZ initial z-coordinate of magnetometer
1293      *                         hard-iron bias expressed in Teslas (T).
1294      * @param initialSx        initial x scaling factor.
1295      * @param initialSy        initial y scaling factor.
1296      * @param initialSz        initial z scaling factor.
1297      * @param initialMxy       initial x-y cross coupling error.
1298      * @param initialMxz       initial x-z cross coupling error.
1299      * @param initialMyx       initial y-x cross coupling error.
1300      * @param initialMyz       initial y-z cross coupling error.
1301      * @param initialMzx       initial z-x cross coupling error.
1302      * @param initialMzy       initial z-y cross coupling error.
1303      */
1304     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1305             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1306             final double initialSx, final double initialSy, final double initialSz,
1307             final double initialMxy, final double initialMxz, final double initialMyx,
1308             final double initialMyz, final double initialMzx, final double initialMzy) {
1309         this(initialHardIronX, initialHardIronY, initialHardIronZ);
1310         try {
1311             setInitialScalingFactorsAndCrossCouplingErrors(initialSx, initialSy, initialSz,
1312                     initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1313         } catch (final LockedException ignore) {
1314             // never happens
1315         }
1316     }
1317 
1318     /**
1319      * Constructor.
1320      *
1321      * @param initialHardIronX initial x-coordinate of magnetometer
1322      *                         hard-iron bias expressed in Teslas (T).
1323      * @param initialHardIronY initial y-coordinate of magnetometer
1324      *                         hard-iron bias expressed in Teslas (T).
1325      * @param initialHardIronZ initial z-coordinate of magnetometer
1326      *                         hard-iron bias expressed in Teslas (T).
1327      * @param initialSx        initial x scaling factor.
1328      * @param initialSy        initial y scaling factor.
1329      * @param initialSz        initial z scaling factor.
1330      * @param initialMxy       initial x-y cross coupling error.
1331      * @param initialMxz       initial x-z cross coupling error.
1332      * @param initialMyx       initial y-x cross coupling error.
1333      * @param initialMyz       initial y-z cross coupling error.
1334      * @param initialMzx       initial z-x cross coupling error.
1335      * @param initialMzy       initial z-y cross coupling error.
1336      * @param listener         listener to handle events raised by this calibrator.
1337      */
1338     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1339             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1340             final double initialSx, final double initialSy, final double initialSz,
1341             final double initialMxy, final double initialMxz, final double initialMyx,
1342             final double initialMyz, final double initialMzx, final double initialMzy,
1343             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1344         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1345                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1346         this.listener = listener;
1347     }
1348 
1349     /**
1350      * Constructor.
1351      *
1352      * @param measurements     collection of body magnetic flux density measurements with
1353      *                         standard deviations taken at different frames (positions
1354      *                         and orientations).
1355      * @param initialHardIronX initial x-coordinate of magnetometer
1356      *                         hard-iron bias expressed in Teslas (T).
1357      * @param initialHardIronY initial y-coordinate of magnetometer
1358      *                         hard-iron bias expressed in Teslas (T).
1359      * @param initialHardIronZ initial z-coordinate of magnetometer
1360      *                         hard-iron bias expressed in Teslas (T).
1361      * @param initialSx        initial x scaling factor.
1362      * @param initialSy        initial y scaling factor.
1363      * @param initialSz        initial z scaling factor.
1364      * @param initialMxy       initial x-y cross coupling error.
1365      * @param initialMxz       initial x-z cross coupling error.
1366      * @param initialMyx       initial y-x cross coupling error.
1367      * @param initialMyz       initial y-z cross coupling error.
1368      * @param initialMzx       initial z-x cross coupling error.
1369      * @param initialMzy       initial z-y cross coupling error.
1370      */
1371     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1372             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1373             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1374             final double initialSx, final double initialSy, final double initialSz,
1375             final double initialMxy, final double initialMxz, final double initialMyx,
1376             final double initialMyz, final double initialMzx, final double initialMzy) {
1377         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1378                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1379         this.measurements = measurements;
1380     }
1381 
1382     /**
1383      * Constructor.
1384      *
1385      * @param measurements     collection of body magnetic flux density measurements with
1386      *                         standard deviations taken at different frames (positions
1387      *                         and orientations).
1388      * @param initialHardIronX initial x-coordinate of magnetometer
1389      *                         hard-iron bias expressed in Teslas (T).
1390      * @param initialHardIronY initial y-coordinate of magnetometer
1391      *                         hard-iron bias expressed in Teslas (T).
1392      * @param initialHardIronZ initial z-coordinate of magnetometer
1393      *                         hard-iron bias expressed in Teslas (T).
1394      * @param initialSx        initial x scaling factor.
1395      * @param initialSy        initial y scaling factor.
1396      * @param initialSz        initial z scaling factor.
1397      * @param initialMxy       initial x-y cross coupling error.
1398      * @param initialMxz       initial x-z cross coupling error.
1399      * @param initialMyx       initial y-x cross coupling error.
1400      * @param initialMyz       initial y-z cross coupling error.
1401      * @param initialMzx       initial z-x cross coupling error.
1402      * @param initialMzy       initial z-y cross coupling error.
1403      * @param listener         listener to handle events raised by this calibrator.
1404      */
1405     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1406             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1407             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1408             final double initialSx, final double initialSy, final double initialSz,
1409             final double initialMxy, final double initialMxz, final double initialMyx,
1410             final double initialMyz, final double initialMzx, final double initialMzy,
1411             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1412         this(measurements, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1413                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1414         this.listener = listener;
1415     }
1416 
1417     /**
1418      * Constructor.
1419      *
1420      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1421      *                         for the accelerometer, gyroscope and magnetometer.
1422      * @param initialHardIronX initial x-coordinate of magnetometer
1423      *                         hard-iron bias expressed in Teslas (T).
1424      * @param initialHardIronY initial y-coordinate of magnetometer
1425      *                         hard-iron bias expressed in Teslas (T).
1426      * @param initialHardIronZ initial z-coordinate of magnetometer
1427      *                         hard-iron bias expressed in Teslas (T).
1428      * @param initialSx        initial x scaling factor.
1429      * @param initialSy        initial y scaling factor.
1430      * @param initialSz        initial z scaling factor.
1431      * @param initialMxy       initial x-y cross coupling error.
1432      * @param initialMxz       initial x-z cross coupling error.
1433      * @param initialMyx       initial y-x cross coupling error.
1434      * @param initialMyz       initial y-z cross coupling error.
1435      * @param initialMzx       initial z-x cross coupling error.
1436      * @param initialMzy       initial z-y cross coupling error.
1437      */
1438     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1439             final boolean commonAxisUsed, final double initialHardIronX, final double initialHardIronY,
1440             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1441             final double initialMxy, final double initialMxz, final double initialMyx,
1442             final double initialMyz, final double initialMzx, final double initialMzy) {
1443         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1444                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1445         this.commonAxisUsed = commonAxisUsed;
1446     }
1447 
1448     /**
1449      * Constructor.
1450      *
1451      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1452      *                         for the accelerometer, gyroscope and magnetometer.
1453      * @param initialHardIronX initial x-coordinate of magnetometer
1454      *                         hard-iron bias expressed in Teslas (T).
1455      * @param initialHardIronY initial y-coordinate of magnetometer
1456      *                         hard-iron bias expressed in Teslas (T).
1457      * @param initialHardIronZ initial z-coordinate of magnetometer
1458      *                         hard-iron bias expressed in Teslas (T).
1459      * @param initialSx        initial x scaling factor.
1460      * @param initialSy        initial y scaling factor.
1461      * @param initialSz        initial z scaling factor.
1462      * @param initialMxy       initial x-y cross coupling error.
1463      * @param initialMxz       initial x-z cross coupling error.
1464      * @param initialMyx       initial y-x cross coupling error.
1465      * @param initialMyz       initial y-z cross coupling error.
1466      * @param initialMzx       initial z-x cross coupling error.
1467      * @param initialMzy       initial z-y cross coupling error.
1468      * @param listener         listener to handle events raised by this calibrator.
1469      */
1470     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1471             final boolean commonAxisUsed, final double initialHardIronX, final double initialHardIronY,
1472             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1473             final double initialMxy, final double initialMxz, final double initialMyx,
1474             final double initialMyz, final double initialMzx, final double initialMzy,
1475             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1476         this(commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1477                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1478         this.listener = listener;
1479     }
1480 
1481     /**
1482      * Constructor.
1483      *
1484      * @param measurements     collection of body magnetic flux density measurements with
1485      *                         standard deviations taken at different frames (positions
1486      *                         and orientations).
1487      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1488      *                         for the accelerometer, gyroscope and magnetometer.
1489      * @param initialHardIronX initial x-coordinate of magnetometer
1490      *                         hard-iron bias expressed in Teslas (T).
1491      * @param initialHardIronY initial y-coordinate of magnetometer
1492      *                         hard-iron bias expressed in Teslas (T).
1493      * @param initialHardIronZ initial z-coordinate of magnetometer
1494      *                         hard-iron bias expressed in Teslas (T).
1495      * @param initialSx        initial x scaling factor.
1496      * @param initialSy        initial y scaling factor.
1497      * @param initialSz        initial z scaling factor.
1498      * @param initialMxy       initial x-y cross coupling error.
1499      * @param initialMxz       initial x-z cross coupling error.
1500      * @param initialMyx       initial y-x cross coupling error.
1501      * @param initialMyz       initial y-z cross coupling error.
1502      * @param initialMzx       initial z-x cross coupling error.
1503      * @param initialMzy       initial z-y cross coupling error.
1504      */
1505     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1506             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1507             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1508             final double initialSx, final double initialSy, final double initialSz,
1509             final double initialMxy, final double initialMxz, final double initialMyx,
1510             final double initialMyz, final double initialMzx, final double initialMzy) {
1511         this(commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1512                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1513         this.measurements = measurements;
1514     }
1515 
1516     /**
1517      * Constructor.
1518      *
1519      * @param measurements     collection of body magnetic flux density measurements with
1520      *                         standard deviations taken at different frames (positions
1521      *                         and orientations).
1522      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1523      *                         for the accelerometer, gyroscope and magnetometer.
1524      * @param initialHardIronX initial x-coordinate of magnetometer
1525      *                         hard-iron bias expressed in Teslas (T).
1526      * @param initialHardIronY initial y-coordinate of magnetometer
1527      *                         hard-iron bias expressed in Teslas (T).
1528      * @param initialHardIronZ initial z-coordinate of magnetometer
1529      *                         hard-iron bias expressed in Teslas (T).
1530      * @param initialSx        initial x scaling factor.
1531      * @param initialSy        initial y scaling factor.
1532      * @param initialSz        initial z scaling factor.
1533      * @param initialMxy       initial x-y cross coupling error.
1534      * @param initialMxz       initial x-z cross coupling error.
1535      * @param initialMyx       initial y-x cross coupling error.
1536      * @param initialMyz       initial y-z cross coupling error.
1537      * @param initialMzx       initial z-x cross coupling error.
1538      * @param initialMzy       initial z-y cross coupling error.
1539      * @param listener         listener to handle events raised by this calibrator.
1540      */
1541     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1542             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1543             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1544             final double initialSx, final double initialSy, final double initialSz,
1545             final double initialMxy, final double initialMxz, final double initialMyx,
1546             final double initialMyz, final double initialMzx, final double initialMzy,
1547             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1548         this(measurements, commonAxisUsed, initialHardIronX, initialHardIronY, initialHardIronZ,
1549                 initialSx, initialSy, initialSz, initialMxy, initialMxz, initialMyx,
1550                 initialMyz, initialMzx, initialMzy);
1551         this.listener = listener;
1552     }
1553 
1554     /**
1555      * Constructor.
1556      *
1557      * @param magneticModel    Earth's magnetic model. If null, a default model
1558      *                         will be used instead.
1559      * @param initialHardIronX initial x-coordinate of magnetometer
1560      *                         hard-iron bias expressed in Teslas (T).
1561      * @param initialHardIronY initial y-coordinate of magnetometer
1562      *                         hard-iron bias expressed in Teslas (T).
1563      * @param initialHardIronZ initial z-coordinate of magnetometer
1564      *                         hard-iron bias expressed in Teslas (T).
1565      * @param initialSx        initial x scaling factor.
1566      * @param initialSy        initial y scaling factor.
1567      * @param initialSz        initial z scaling factor.
1568      * @param initialMxy       initial x-y cross coupling error.
1569      * @param initialMxz       initial x-z cross coupling error.
1570      * @param initialMyx       initial y-x cross coupling error.
1571      * @param initialMyz       initial y-z cross coupling error.
1572      * @param initialMzx       initial z-x cross coupling error.
1573      * @param initialMzy       initial z-y cross coupling error.
1574      */
1575     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1576             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1577             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1578             final double initialMxy, final double initialMxz, final double initialMyx,
1579             final double initialMyz, final double initialMzx, final double initialMzy) {
1580         this(initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1581                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1582         this.magneticModel = magneticModel;
1583     }
1584 
1585     /**
1586      * Constructor.
1587      *
1588      * @param magneticModel    Earth's magnetic model. If null, a default model
1589      *                         will be used instead.
1590      * @param initialHardIronX initial x-coordinate of magnetometer
1591      *                         hard-iron bias expressed in Teslas (T).
1592      * @param initialHardIronY initial y-coordinate of magnetometer
1593      *                         hard-iron bias expressed in Teslas (T).
1594      * @param initialHardIronZ initial z-coordinate of magnetometer
1595      *                         hard-iron bias expressed in Teslas (T).
1596      * @param initialSx        initial x scaling factor.
1597      * @param initialSy        initial y scaling factor.
1598      * @param initialSz        initial z scaling factor.
1599      * @param initialMxy       initial x-y cross coupling error.
1600      * @param initialMxz       initial x-z cross coupling error.
1601      * @param initialMyx       initial y-x cross coupling error.
1602      * @param initialMyz       initial y-z cross coupling error.
1603      * @param initialMzx       initial z-x cross coupling error.
1604      * @param initialMzy       initial z-y cross coupling error.
1605      * @param listener         listener to handle events raised by this calibrator.
1606      */
1607     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1608             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1609             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1610             final double initialMxy, final double initialMxz, final double initialMyx,
1611             final double initialMyz, final double initialMzx, final double initialMzy,
1612             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1613         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1614                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1615         this.listener = listener;
1616     }
1617 
1618     /**
1619      * Constructor.
1620      *
1621      * @param measurements     collection of body magnetic flux density measurements with
1622      *                         standard deviations taken at different frames (positions
1623      *                         and orientations).
1624      * @param magneticModel    Earth's magnetic model. If null, a default model
1625      *                         will be used instead.
1626      * @param initialHardIronX initial x-coordinate of magnetometer
1627      *                         hard-iron bias expressed in Teslas (T).
1628      * @param initialHardIronY initial y-coordinate of magnetometer
1629      *                         hard-iron bias expressed in Teslas (T).
1630      * @param initialHardIronZ initial z-coordinate of magnetometer
1631      *                         hard-iron bias expressed in Teslas (T).
1632      * @param initialSx        initial x scaling factor.
1633      * @param initialSy        initial y scaling factor.
1634      * @param initialSz        initial z scaling factor.
1635      * @param initialMxy       initial x-y cross coupling error.
1636      * @param initialMxz       initial x-z cross coupling error.
1637      * @param initialMyx       initial y-x cross coupling error.
1638      * @param initialMyz       initial y-z cross coupling error.
1639      * @param initialMzx       initial z-x cross coupling error.
1640      * @param initialMzy       initial z-y cross coupling error.
1641      */
1642     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1643             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1644             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1645             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1646             final double initialMxy, final double initialMxz, final double initialMyx,
1647             final double initialMyz, final double initialMzx, final double initialMzy) {
1648         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1649                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1650         this.measurements = measurements;
1651     }
1652 
1653     /**
1654      * Constructor.
1655      *
1656      * @param measurements     collection of body magnetic flux density measurements with
1657      *                         standard deviations taken at different frames (positions
1658      *                         and orientations).
1659      * @param magneticModel    Earth's magnetic model. If null, a default model
1660      *                         will be used instead.
1661      * @param initialHardIronX initial x-coordinate of magnetometer
1662      *                         hard-iron bias expressed in Teslas (T).
1663      * @param initialHardIronY initial y-coordinate of magnetometer
1664      *                         hard-iron bias expressed in Teslas (T).
1665      * @param initialHardIronZ initial z-coordinate of magnetometer
1666      *                         hard-iron bias expressed in Teslas (T).
1667      * @param initialSx        initial x scaling factor.
1668      * @param initialSy        initial y scaling factor.
1669      * @param initialSz        initial z scaling factor.
1670      * @param initialMxy       initial x-y cross coupling error.
1671      * @param initialMxz       initial x-z cross coupling error.
1672      * @param initialMyx       initial y-x cross coupling error.
1673      * @param initialMyz       initial y-z cross coupling error.
1674      * @param initialMzx       initial z-x cross coupling error.
1675      * @param initialMzy       initial z-y cross coupling error.
1676      * @param listener         listener to handle events raised by this calibrator.
1677      */
1678     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1679             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1680             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1681             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1682             final double initialMxy, final double initialMxz, final double initialMyx,
1683             final double initialMyz, final double initialMzx, final double initialMzy,
1684             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1685         this(measurements, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1686                 initialSx, initialSy, initialSz, initialMxy, initialMxz, initialMyx,
1687                 initialMyz, initialMzx, initialMzy);
1688         this.listener = listener;
1689     }
1690 
1691     /**
1692      * Constructor.
1693      *
1694      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1695      *                         for the accelerometer, gyroscope and magnetometer.
1696      * @param magneticModel    Earth's magnetic model. If null, a default model
1697      *                         will be used instead.
1698      * @param initialHardIronX initial x-coordinate of magnetometer
1699      *                         hard-iron bias expressed in Teslas (T).
1700      * @param initialHardIronY initial y-coordinate of magnetometer
1701      *                         hard-iron bias expressed in Teslas (T).
1702      * @param initialHardIronZ initial z-coordinate of magnetometer
1703      *                         hard-iron bias expressed in Teslas (T).
1704      * @param initialSx        initial x scaling factor.
1705      * @param initialSy        initial y scaling factor.
1706      * @param initialSz        initial z scaling factor.
1707      * @param initialMxy       initial x-y cross coupling error.
1708      * @param initialMxz       initial x-z cross coupling error.
1709      * @param initialMyx       initial y-x cross coupling error.
1710      * @param initialMyz       initial y-z cross coupling error.
1711      * @param initialMzx       initial z-x cross coupling error.
1712      * @param initialMzy       initial z-y cross coupling error.
1713      */
1714     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1715             final boolean commonAxisUsed, final WorldMagneticModel magneticModel,
1716             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1717             final double initialSx, final double initialSy, final double initialSz,
1718             final double initialMxy, final double initialMxz, final double initialMyx,
1719             final double initialMyz, final double initialMzx, final double initialMzy) {
1720         this(magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ, initialSx, initialSy, initialSz,
1721                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1722         this.commonAxisUsed = commonAxisUsed;
1723     }
1724 
1725     /**
1726      * Constructor.
1727      *
1728      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1729      *                         for the accelerometer, gyroscope and magnetometer.
1730      * @param magneticModel    Earth's magnetic model. If null, a default model
1731      *                         will be used instead.
1732      * @param initialHardIronX initial x-coordinate of magnetometer
1733      *                         hard-iron bias expressed in Teslas (T).
1734      * @param initialHardIronY initial y-coordinate of magnetometer
1735      *                         hard-iron bias expressed in Teslas (T).
1736      * @param initialHardIronZ initial z-coordinate of magnetometer
1737      *                         hard-iron bias expressed in Teslas (T).
1738      * @param initialSx        initial x scaling factor.
1739      * @param initialSy        initial y scaling factor.
1740      * @param initialSz        initial z scaling factor.
1741      * @param initialMxy       initial x-y cross coupling error.
1742      * @param initialMxz       initial x-z cross coupling error.
1743      * @param initialMyx       initial y-x cross coupling error.
1744      * @param initialMyz       initial y-z cross coupling error.
1745      * @param initialMzx       initial z-x cross coupling error.
1746      * @param initialMzy       initial z-y cross coupling error.
1747      * @param listener         listener to handle events raised by this calibrator.
1748      */
1749     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1750             final boolean commonAxisUsed, final WorldMagneticModel magneticModel,
1751             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ,
1752             final double initialSx, final double initialSy, final double initialSz,
1753             final double initialMxy, final double initialMxz, final double initialMyx,
1754             final double initialMyz, final double initialMzx, final double initialMzy,
1755             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1756         this(commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1757                 initialSx, initialSy, initialSz, initialMxy, initialMxz, initialMyx,
1758                 initialMyz, initialMzx, initialMzy);
1759         this.listener = listener;
1760     }
1761 
1762     /**
1763      * Constructor.
1764      *
1765      * @param measurements     collection of body magnetic flux density measurements with
1766      *                         standard deviations taken at different frames (positions
1767      *                         and orientations).
1768      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1769      *                         for the accelerometer, gyroscope and magnetometer.
1770      * @param magneticModel    Earth's magnetic model. If null, a default model
1771      *                         will be used instead.
1772      * @param initialHardIronX initial x-coordinate of magnetometer
1773      *                         hard-iron bias expressed in Teslas (T).
1774      * @param initialHardIronY initial y-coordinate of magnetometer
1775      *                         hard-iron bias expressed in Teslas (T).
1776      * @param initialHardIronZ initial z-coordinate of magnetometer
1777      *                         hard-iron bias expressed in Teslas (T).
1778      * @param initialSx        initial x scaling factor.
1779      * @param initialSy        initial y scaling factor.
1780      * @param initialSz        initial z scaling factor.
1781      * @param initialMxy       initial x-y cross coupling error.
1782      * @param initialMxz       initial x-z cross coupling error.
1783      * @param initialMyx       initial y-x cross coupling error.
1784      * @param initialMyz       initial y-z cross coupling error.
1785      * @param initialMzx       initial z-x cross coupling error.
1786      * @param initialMzy       initial z-y cross coupling error.
1787      */
1788     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1789             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1790             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1791             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1792             final double initialMxy, final double initialMxz, final double initialMyx,
1793             final double initialMyz, final double initialMzx, final double initialMzy) {
1794         this(commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1795                 initialSx, initialSy, initialSz, initialMxy, initialMxz, initialMyx,
1796                 initialMyz, initialMzx, initialMzy);
1797         this.measurements = measurements;
1798     }
1799 
1800     /**
1801      * Constructor.
1802      *
1803      * @param measurements     collection of body magnetic flux density measurements with
1804      *                         standard deviations taken at different frames (positions
1805      *                         and orientations).
1806      * @param commonAxisUsed   indicates whether z-axis is assumed to be common
1807      *                         for the accelerometer, gyroscope and magnetometer.
1808      * @param magneticModel    Earth's magnetic model. If null, a default model
1809      *                         will be used instead.
1810      * @param initialHardIronX initial x-coordinate of magnetometer
1811      *                         hard-iron bias expressed in Teslas (T).
1812      * @param initialHardIronY initial y-coordinate of magnetometer
1813      *                         hard-iron bias expressed in Teslas (T).
1814      * @param initialHardIronZ initial z-coordinate of magnetometer
1815      *                         hard-iron bias expressed in Teslas (T).
1816      * @param initialSx        initial x scaling factor.
1817      * @param initialSy        initial y scaling factor.
1818      * @param initialSz        initial z scaling factor.
1819      * @param initialMxy       initial x-y cross coupling error.
1820      * @param initialMxz       initial x-z cross coupling error.
1821      * @param initialMyx       initial y-x cross coupling error.
1822      * @param initialMyz       initial y-z cross coupling error.
1823      * @param initialMzx       initial z-x cross coupling error.
1824      * @param initialMzy       initial z-y cross coupling error.
1825      * @param listener         listener to handle events raised by this calibrator.
1826      */
1827     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1828             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
1829             final WorldMagneticModel magneticModel, final double initialHardIronX, final double initialHardIronY,
1830             final double initialHardIronZ, final double initialSx, final double initialSy, final double initialSz,
1831             final double initialMxy, final double initialMxz, final double initialMyx,
1832             final double initialMyz, final double initialMzx, final double initialMzy,
1833             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1834         this(measurements, commonAxisUsed, magneticModel, initialHardIronX, initialHardIronY, initialHardIronZ,
1835                 initialSx, initialSy, initialSz, initialMxy, initialMxz, initialMyx,
1836                 initialMyz, initialMzx, initialMzy);
1837         this.listener = listener;
1838     }
1839 
1840     /**
1841      * Constructor.
1842      *
1843      * @param initialHardIron initial hard-iron to find a solution.
1844      * @throws IllegalArgumentException if provided hard-iron array does
1845      *                                  not have length 3.
1846      */
1847     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(final double[] initialHardIron) {
1848         try {
1849             setInitialHardIron(initialHardIron);
1850         } catch (final LockedException ignore) {
1851             // never happens
1852         }
1853     }
1854 
1855     /**
1856      * Constructor.
1857      *
1858      * @param initialHardIron initial hard-iron to find a solution.
1859      * @param listener        listener to handle events raised by this
1860      *                        calibrator.
1861      * @throws IllegalArgumentException if provided hard-iron array does
1862      *                                  not have length 3.
1863      */
1864     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1865             final double[] initialHardIron,
1866             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1867         this(initialHardIron);
1868         this.listener = listener;
1869     }
1870 
1871     /**
1872      * Constructor.
1873      *
1874      * @param measurements    collection of body magnetic flux density measurements with
1875      *                        standard deviations taken at different frames (positions
1876      *                        and orientations).
1877      * @param initialHardIron initial hard-iron to find a solution.
1878      * @throws IllegalArgumentException if provided hard-iron array does
1879      *                                  not have length 3.
1880      */
1881     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1882             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1883             final double[] initialHardIron) {
1884         this(initialHardIron);
1885         this.measurements = measurements;
1886     }
1887 
1888     /**
1889      * Constructor.
1890      *
1891      * @param measurements    collection of body magnetic flux density measurements with
1892      *                        standard deviations taken at different frames (positions
1893      *                        and orientations).
1894      * @param initialHardIron initial hard-iron to find a solution.
1895      * @param listener        listener to handle events raised by this calibrator.
1896      * @throws IllegalArgumentException if provided hard-iron array does
1897      *                                  not have length 3.
1898      */
1899     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1900             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1901             final double[] initialHardIron,
1902             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1903         this(measurements, initialHardIron);
1904         this.listener = listener;
1905     }
1906 
1907     /**
1908      * Constructor.
1909      *
1910      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
1911      *                        for the accelerometer, gyroscope and magnetometer.
1912      * @param initialHardIron initial hard-iron to find a solution.
1913      * @throws IllegalArgumentException if provided hard-iron array does
1914      *                                  not have length 3.
1915      */
1916     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1917             final boolean commonAxisUsed, final double[] initialHardIron) {
1918         this(initialHardIron);
1919         this.commonAxisUsed = commonAxisUsed;
1920     }
1921 
1922     /**
1923      * Constructor.
1924      *
1925      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
1926      *                        for the accelerometer, gyroscope and magnetometer.
1927      * @param initialHardIron initial hard-iron to find a solution.
1928      * @param listener        listener to handle events raised by this calibrator.
1929      * @throws IllegalArgumentException if provided hard-iron array does
1930      *                                  not have length 3.
1931      */
1932     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1933             final boolean commonAxisUsed, final double[] initialHardIron,
1934             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1935         this(commonAxisUsed, initialHardIron);
1936         this.listener = listener;
1937     }
1938 
1939     /**
1940      * Constructor.
1941      *
1942      * @param measurements    collection of body magnetic flux density measurements with
1943      *                        standard deviations taken at different frames (positions
1944      *                        and orientations).
1945      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
1946      *                        for the accelerometer, gyroscope and magnetometer.
1947      * @param initialHardIron initial hard-iron to find a solution.
1948      * @throws IllegalArgumentException if provided hard-iron array does
1949      *                                  not have length 3.
1950      */
1951     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1952             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1953             final boolean commonAxisUsed, final double[] initialHardIron) {
1954         this(commonAxisUsed, initialHardIron);
1955         this.measurements = measurements;
1956     }
1957 
1958     /**
1959      * Constructor.
1960      *
1961      * @param measurements    collection of body magnetic flux density measurements with
1962      *                        standard deviations taken at different frames (positions
1963      *                        and orientations).
1964      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
1965      *                        for the accelerometer, gyroscope and magnetometer.
1966      * @param initialHardIron initial hard-iron to find a solution.
1967      * @param listener        listener to handle events raised by this calibrator.
1968      * @throws IllegalArgumentException if provided hard-iron array does
1969      *                                  not have length 3.
1970      */
1971     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1972             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
1973             final boolean commonAxisUsed, final double[] initialHardIron,
1974             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
1975         this(measurements, commonAxisUsed, initialHardIron);
1976         this.listener = listener;
1977     }
1978 
1979     /**
1980      * Constructor.
1981      *
1982      * @param magneticModel   Earth's magnetic model. If null, a default model
1983      *                        will be used instead.
1984      * @param initialHardIron initial hard-iron to find a solution.
1985      * @throws IllegalArgumentException if provided hard-iron array does
1986      *                                  not have length 3.
1987      */
1988     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
1989             final WorldMagneticModel magneticModel, final double[] initialHardIron) {
1990         this(initialHardIron);
1991         this.magneticModel = magneticModel;
1992     }
1993 
1994     /**
1995      * Constructor.
1996      *
1997      * @param magneticModel   Earth's magnetic model. If null, a default model
1998      *                        will be used instead.
1999      * @param initialHardIron initial hard-iron to find a solution.
2000      * @param listener        listener to handle events raised by this calibrator.
2001      * @throws IllegalArgumentException if provided hard-iron array does
2002      *                                  not have length 3.
2003      */
2004     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2005             final WorldMagneticModel magneticModel, final double[] initialHardIron,
2006             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2007         this(magneticModel, initialHardIron);
2008         this.listener = listener;
2009     }
2010 
2011     /**
2012      * Constructor.
2013      *
2014      * @param measurements    collection of body magnetic flux density measurements with
2015      *                        standard deviations taken at different frames (positions
2016      *                        and orientations).
2017      * @param magneticModel   Earth's magnetic model. If null, a default model
2018      *                        will be used instead.
2019      * @param initialHardIron initial hard-iron to find a solution.
2020      * @throws IllegalArgumentException if provided hard-iron array does
2021      *                                  not have length 3.
2022      */
2023     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2024             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2025             final WorldMagneticModel magneticModel, final double[] initialHardIron) {
2026         this(magneticModel, initialHardIron);
2027         this.measurements = measurements;
2028     }
2029 
2030     /**
2031      * Constructor.
2032      *
2033      * @param measurements    collection of body magnetic flux density measurements with
2034      *                        standard deviations taken at different frames (positions
2035      *                        and orientations).
2036      * @param magneticModel   Earth's magnetic model. If null, a default model
2037      *                        will be used instead.
2038      * @param initialHardIron initial hard-iron to find a solution.
2039      * @param listener        listener to handle events raised by this calibrator.
2040      * @throws IllegalArgumentException if provided hard-iron array does
2041      *                                  not have length 3.
2042      */
2043     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2044             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2045             final WorldMagneticModel magneticModel, final double[] initialHardIron,
2046             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2047         this(measurements, magneticModel, initialHardIron);
2048         this.listener = listener;
2049     }
2050 
2051     /**
2052      * Constructor.
2053      *
2054      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2055      *                        for the accelerometer, gyroscope and magnetometer.
2056      * @param magneticModel   Earth's magnetic model. If null, a default model
2057      *                        will be used instead.
2058      * @param initialHardIron initial hard-iron to find a solution.
2059      * @throws IllegalArgumentException if provided hard-iron array does
2060      *                                  not have length 3.
2061      */
2062     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2063             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final double[] initialHardIron) {
2064         this(magneticModel, initialHardIron);
2065         this.commonAxisUsed = commonAxisUsed;
2066     }
2067 
2068     /**
2069      * Constructor.
2070      *
2071      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2072      *                        for the accelerometer, gyroscope and magnetometer.
2073      * @param magneticModel   Earth's magnetic model. If null, a default model
2074      *                        will be used instead.
2075      * @param initialHardIron initial hard-iron to find a solution.
2076      * @param listener        listener to handle events raised by this calibrator.
2077      * @throws IllegalArgumentException if provided hard-iron array does
2078      *                                  not have length 3.
2079      */
2080     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2081             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final double[] initialHardIron,
2082             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2083         this(commonAxisUsed, magneticModel, initialHardIron);
2084         this.listener = listener;
2085     }
2086 
2087     /**
2088      * Constructor.
2089      *
2090      * @param measurements    collection of body magnetic flux density measurements with
2091      *                        standard deviations taken at different frames (positions
2092      *                        and orientations).
2093      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2094      *                        for the accelerometer, gyroscope and magnetometer.
2095      * @param magneticModel   Earth's magnetic model. If null, a default model
2096      *                        will be used instead.
2097      * @param initialHardIron initial hard-iron to find a solution.
2098      * @throws IllegalArgumentException if provided hard-iron array does
2099      *                                  not have length 3.
2100      */
2101     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2102             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2103             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final double[] initialHardIron) {
2104         this(commonAxisUsed, magneticModel, initialHardIron);
2105         this.measurements = measurements;
2106     }
2107 
2108     /**
2109      * Constructor.
2110      *
2111      * @param measurements    collection of body magnetic flux density measurements with
2112      *                        standard deviations taken at different frames (positions
2113      *                        and orientations).
2114      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2115      *                        for the accelerometer, gyroscope and magnetometer.
2116      * @param magneticModel   Earth's magnetic model. If null, a default model
2117      *                        will be used instead.
2118      * @param initialHardIron initial hard-iron to find a solution.
2119      * @param listener        listener to handle events raised by this calibrator.
2120      */
2121     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2122             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2123             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final double[] initialHardIron,
2124             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2125         this(measurements, commonAxisUsed, magneticModel, initialHardIron);
2126         this.listener = listener;
2127     }
2128 
2129     /**
2130      * Constructor.
2131      *
2132      * @param initialHardIron initial hard-iron to find a solution.
2133      * @throws IllegalArgumentException if provided hard-iron matrix is not
2134      *                                  3x1.
2135      */
2136     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(final Matrix initialHardIron) {
2137         try {
2138             setInitialHardIron(initialHardIron);
2139         } catch (final LockedException ignore) {
2140             // never happens
2141         }
2142     }
2143 
2144     /**
2145      * Constructor.
2146      *
2147      * @param initialHardIron initial hard-iron to find a solution.
2148      * @param listener        listener to handle events raised by this
2149      *                        calibrator.
2150      * @throws IllegalArgumentException if provided hard-iron matrix is not
2151      *                                  3x1.
2152      */
2153     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2154             final Matrix initialHardIron,
2155             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2156         this(initialHardIron);
2157         this.listener = listener;
2158     }
2159 
2160     /**
2161      * Constructor.
2162      *
2163      * @param measurements    collection of body magnetic flux density measurements with
2164      *                        standard deviations taken at different frames (positions
2165      *                        and orientations).
2166      * @param initialHardIron initial hard-iron to find a solution.
2167      * @throws IllegalArgumentException if provided hard-iron matrix is not
2168      *                                  3x1.
2169      */
2170     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2171             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2172             final Matrix initialHardIron) {
2173         this(initialHardIron);
2174         this.measurements = measurements;
2175     }
2176 
2177     /**
2178      * Constructor.
2179      *
2180      * @param measurements    collection of body magnetic flux density measurements with
2181      *                        standard deviations taken at different frames (positions
2182      *                        and orientations).
2183      * @param initialHardIron initial hard-iron to find a solution.
2184      * @param listener        listener to handle events raised by this calibrator.
2185      * @throws IllegalArgumentException if provided hard-iron matrix is not
2186      *                                  3x1.
2187      */
2188     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2189             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final Matrix initialHardIron,
2190             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2191         this(measurements, initialHardIron);
2192         this.listener = listener;
2193     }
2194 
2195     /**
2196      * Constructor.
2197      *
2198      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2199      *                        for the accelerometer, gyroscope and magnetometer.
2200      * @param initialHardIron initial hard-iron to find a solution.
2201      * @throws IllegalArgumentException if provided hard-iron matrix is not
2202      *                                  3x1.
2203      */
2204     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2205             final boolean commonAxisUsed, final Matrix initialHardIron) {
2206         this(initialHardIron);
2207         this.commonAxisUsed = commonAxisUsed;
2208     }
2209 
2210     /**
2211      * Constructor.
2212      *
2213      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2214      *                        for the accelerometer, gyroscope and magnetometer.
2215      * @param initialHardIron initial hard-iron to find a solution.
2216      * @param listener        listener to handle events raised by this calibrator.
2217      * @throws IllegalArgumentException if provided hard-iron matrix is not
2218      *                                  3x1.
2219      */
2220     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2221             final boolean commonAxisUsed, final Matrix initialHardIron,
2222             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2223         this(commonAxisUsed, initialHardIron);
2224         this.listener = listener;
2225     }
2226 
2227     /**
2228      * Constructor.
2229      *
2230      * @param measurements    collection of body magnetic flux density measurements with
2231      *                        standard deviations taken at different frames (positions
2232      *                        and orientations).
2233      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2234      *                        for the accelerometer, gyroscope and magnetometer.
2235      * @param initialHardIron initial hard-iron to find a solution.
2236      * @throws IllegalArgumentException if provided hard-iron matrix is not
2237      *                                  3x1.
2238      */
2239     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2240             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2241             final boolean commonAxisUsed, final Matrix initialHardIron) {
2242         this(commonAxisUsed, initialHardIron);
2243         this.measurements = measurements;
2244     }
2245 
2246     /**
2247      * Constructor.
2248      *
2249      * @param measurements    collection of body magnetic flux density measurements with
2250      *                        standard deviations taken at different frames (positions
2251      *                        and orientations).
2252      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2253      *                        for the accelerometer, gyroscope and magnetometer.
2254      * @param initialHardIron initial hard-iron to find a solution.
2255      * @param listener        listener to handle events raised by this calibrator.
2256      * @throws IllegalArgumentException if provided hard-iron matrix is not
2257      *                                  3x1.
2258      */
2259     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2260             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2261             final boolean commonAxisUsed, final Matrix initialHardIron,
2262             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2263         this(measurements, commonAxisUsed, initialHardIron);
2264         this.listener = listener;
2265     }
2266 
2267     /**
2268      * Constructor.
2269      *
2270      * @param magneticModel   Earth's magnetic model. If null, a default model
2271      *                        will be used instead.
2272      * @param initialHardIron initial hard-iron to find a solution.
2273      * @throws IllegalArgumentException if provided hard-iron matrix is not
2274      *                                  3x1.
2275      */
2276     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2277             final WorldMagneticModel magneticModel, final Matrix initialHardIron) {
2278         this(initialHardIron);
2279         this.magneticModel = magneticModel;
2280     }
2281 
2282     /**
2283      * Constructor.
2284      *
2285      * @param magneticModel   Earth's magnetic model. If null, a default model
2286      *                        will be used instead.
2287      * @param initialHardIron initial hard-iron to find a solution.
2288      * @param listener        listener to handle events raised by this calibrator.
2289      * @throws IllegalArgumentException if provided hard-iron matrix is not
2290      *                                  3x1.
2291      */
2292     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2293             final WorldMagneticModel magneticModel, final Matrix initialHardIron,
2294             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2295         this(magneticModel, initialHardIron);
2296         this.listener = listener;
2297     }
2298 
2299     /**
2300      * Constructor.
2301      *
2302      * @param measurements    collection of body magnetic flux density measurements with
2303      *                        standard deviations taken at different frames (positions
2304      *                        and orientations).
2305      * @param magneticModel   Earth's magnetic model. If null, a default model
2306      *                        will be used instead.
2307      * @param initialHardIron initial hard-iron to find a solution.
2308      * @throws IllegalArgumentException if provided hard-iron matrix is not
2309      *                                  3x1.
2310      */
2311     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2312             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2313             final WorldMagneticModel magneticModel, final Matrix initialHardIron) {
2314         this(magneticModel, initialHardIron);
2315         this.measurements = measurements;
2316     }
2317 
2318     /**
2319      * Constructor.
2320      *
2321      * @param measurements    collection of body magnetic flux density measurements with
2322      *                        standard deviations taken at different frames (positions
2323      *                        and orientations).
2324      * @param magneticModel   Earth's magnetic model. If null, a default model
2325      *                        will be used instead.
2326      * @param initialHardIron initial hard-iron to find a solution.
2327      * @param listener        listener to handle events raised by this calibrator.
2328      * @throws IllegalArgumentException if provided hard-iron matrix is not
2329      *                                  3x1.
2330      */
2331     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2332             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2333             final WorldMagneticModel magneticModel, final Matrix initialHardIron,
2334             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2335         this(measurements, magneticModel, initialHardIron);
2336         this.listener = listener;
2337     }
2338 
2339     /**
2340      * Constructor.
2341      *
2342      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2343      *                        for the accelerometer, gyroscope and magnetometer.
2344      * @param magneticModel   Earth's magnetic model. If null, a default model
2345      *                        will be used instead.
2346      * @param initialHardIron initial hard-iron to find a solution.
2347      * @throws IllegalArgumentException if provided hard-iron matrix is not
2348      *                                  3x1.
2349      */
2350     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2351             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final Matrix initialHardIron) {
2352         this(magneticModel, initialHardIron);
2353         this.commonAxisUsed = commonAxisUsed;
2354     }
2355 
2356     /**
2357      * Constructor.
2358      *
2359      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2360      *                        for the accelerometer, gyroscope and magnetometer.
2361      * @param magneticModel   Earth's magnetic model. If null, a default model
2362      *                        will be used instead.
2363      * @param initialHardIron initial hard-iron to find a solution.
2364      * @param listener        listener to handle events raised by this calibrator.
2365      * @throws IllegalArgumentException if provided hard-iron matrix is not
2366      *                                  3x1.
2367      */
2368     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2369             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final Matrix initialHardIron,
2370             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2371         this(commonAxisUsed, magneticModel, initialHardIron);
2372         this.listener = listener;
2373     }
2374 
2375     /**
2376      * Constructor.
2377      *
2378      * @param measurements    collection of body magnetic flux density measurements with
2379      *                        standard deviations taken at different frames (positions
2380      *                        and orientations).
2381      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2382      *                        for the accelerometer, gyroscope and magnetometer.
2383      * @param magneticModel   Earth's magnetic model. If null, a default model
2384      *                        will be used instead.
2385      * @param initialHardIron initial hard-iron to find a solution.
2386      * @throws IllegalArgumentException if provided hard-iron matrix is not
2387      *                                  3x1.
2388      */
2389     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2390             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2391             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final Matrix initialHardIron) {
2392         this(commonAxisUsed, magneticModel, initialHardIron);
2393         this.measurements = measurements;
2394     }
2395 
2396     /**
2397      * Constructor.
2398      *
2399      * @param measurements    collection of body magnetic flux density measurements with
2400      *                        standard deviations taken at different frames (positions
2401      *                        and orientations).
2402      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2403      *                        for the accelerometer, gyroscope and magnetometer.
2404      * @param magneticModel   Earth's magnetic model. If null, a default model
2405      *                        will be used instead.
2406      * @param initialHardIron initial hard-iron to find a solution.
2407      * @param listener        listener to handle events raised by this calibrator.
2408      * @throws IllegalArgumentException if provided hard-iron matrix is not
2409      *                                  3x1.
2410      */
2411     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2412             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
2413             final WorldMagneticModel magneticModel, final Matrix initialHardIron,
2414             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2415         this(measurements, commonAxisUsed, magneticModel, initialHardIron);
2416         this.listener = listener;
2417     }
2418 
2419     /**
2420      * Constructor.
2421      *
2422      * @param initialHardIron initial hard-iron to find a solution.
2423      * @param initialMm       initial soft-iron matrix containing scale factors
2424      *                        and cross coupling errors.
2425      * @throws IllegalArgumentException if provided hard-iron matrix is not
2426      *                                  3x1 or if soft-iron matrix is not
2427      *                                  3x3.
2428      */
2429     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(final Matrix initialHardIron, final Matrix initialMm) {
2430         this(initialHardIron);
2431         try {
2432             setInitialMm(initialMm);
2433         } catch (final LockedException ignore) {
2434             // never happens
2435         }
2436     }
2437 
2438     /**
2439      * Constructor.
2440      *
2441      * @param initialHardIron initial hard-iron to find a solution.
2442      * @param initialMm       initial soft-iron matrix containing scale factors
2443      *                        and cross coupling errors.
2444      * @param listener        listener to handle events raised by this
2445      *                        calibrator.
2446      * @throws IllegalArgumentException if provided hard-iron matrix is not
2447      *                                  3x1 or if soft-iron matrix is not
2448      *                                  3x3.
2449      */
2450     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2451             final Matrix initialHardIron, final Matrix initialMm,
2452             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2453         this(initialHardIron, initialMm);
2454         this.listener = listener;
2455     }
2456 
2457     /**
2458      * Constructor.
2459      *
2460      * @param measurements    collection of body magnetic flux density measurements with
2461      *                        standard deviations taken at different frames (positions
2462      *                        and orientations).
2463      * @param initialHardIron initial hard-iron to find a solution.
2464      * @param initialMm       initial soft-iron matrix containing scale factors
2465      *                        and cross coupling errors.
2466      * @throws IllegalArgumentException if provided hard-iron matrix is not
2467      *                                  3x1 or if soft-iron matrix is not
2468      *                                  3x3.
2469      */
2470     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2471             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2472             final Matrix initialHardIron, final Matrix initialMm) {
2473         this(initialHardIron, initialMm);
2474         this.measurements = measurements;
2475     }
2476 
2477     /**
2478      * Constructor.
2479      *
2480      * @param measurements    collection of body magnetic flux density measurements with
2481      *                        standard deviations taken at different frames (positions
2482      *                        and orientations).
2483      * @param initialHardIron initial hard-iron to find a solution.
2484      * @param initialMm       initial soft-iron matrix containing scale factors
2485      *                        and cross coupling errors.
2486      * @param listener        listener to handle events raised by this calibrator.
2487      * @throws IllegalArgumentException if provided hard-iron matrix is not
2488      *                                  3x1 or if soft-iron matrix is not
2489      *                                  3x3.
2490      */
2491     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2492             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2493             final Matrix initialHardIron, final Matrix initialMm,
2494             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2495         this(measurements, initialHardIron, initialMm);
2496         this.listener = listener;
2497     }
2498 
2499     /**
2500      * Constructor.
2501      *
2502      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2503      *                        for the accelerometer, gyroscope and magnetometer.
2504      * @param initialHardIron initial hard-iron to find a solution.
2505      * @param initialMm       initial soft-iron matrix containing scale factors
2506      *                        and cross coupling errors.
2507      * @throws IllegalArgumentException if provided hard-iron matrix is not
2508      *                                  3x1 or if soft-iron matrix is not
2509      *                                  3x3.
2510      */
2511     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2512             final boolean commonAxisUsed, final Matrix initialHardIron, final Matrix initialMm) {
2513         this(initialHardIron, initialMm);
2514         this.commonAxisUsed = commonAxisUsed;
2515     }
2516 
2517     /**
2518      * Constructor.
2519      *
2520      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2521      *                        for the accelerometer, gyroscope and magnetometer.
2522      * @param initialHardIron initial hard-iron to find a solution.
2523      * @param initialMm       initial soft-iron matrix containing scale factors
2524      *                        and cross coupling errors.
2525      * @param listener        listener to handle events raised by this calibrator.
2526      * @throws IllegalArgumentException if provided hard-iron matrix is not
2527      *                                  3x1 or if soft-iron matrix is not
2528      *                                  3x3.
2529      */
2530     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2531             final boolean commonAxisUsed, final Matrix initialHardIron, final Matrix initialMm,
2532             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2533         this(commonAxisUsed, initialHardIron, initialMm);
2534         this.listener = listener;
2535     }
2536 
2537     /**
2538      * Constructor.
2539      *
2540      * @param measurements    collection of body magnetic flux density measurements with
2541      *                        standard deviations taken at different frames (positions
2542      *                        and orientations).
2543      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2544      *                        for the accelerometer, gyroscope and magnetometer.
2545      * @param initialHardIron initial hard-iron to find a solution.
2546      * @param initialMm       initial soft-iron matrix containing scale factors
2547      *                        and cross coupling errors.
2548      * @throws IllegalArgumentException if provided hard-iron matrix is not
2549      *                                  3x1 or if soft-iron matrix is not
2550      *                                  3x3.
2551      */
2552     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2553             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
2554             final Matrix initialHardIron, final Matrix initialMm) {
2555         this(commonAxisUsed, initialHardIron, initialMm);
2556         this.measurements = measurements;
2557     }
2558 
2559     /**
2560      * Constructor.
2561      *
2562      * @param measurements    collection of body magnetic flux density measurements with
2563      *                        standard deviations taken at different frames (positions
2564      *                        and orientations).
2565      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2566      *                        for the accelerometer, gyroscope and magnetometer.
2567      * @param initialHardIron initial hard-iron to find a solution.
2568      * @param initialMm       initial soft-iron matrix containing scale factors
2569      *                        and cross coupling errors.
2570      * @param listener        listener to handle events raised by this calibrator.
2571      * @throws IllegalArgumentException if provided hard-iron matrix is not
2572      *                                  3x1 or if soft-iron matrix is not
2573      *                                  3x3.
2574      */
2575     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2576             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
2577             final Matrix initialHardIron, final Matrix initialMm,
2578             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2579         this(measurements, commonAxisUsed, initialHardIron, initialMm);
2580         this.listener = listener;
2581     }
2582 
2583     /**
2584      * Constructor.
2585      *
2586      * @param magneticModel   Earth's magnetic model. If null, a default model
2587      *                        will be used instead.
2588      * @param initialHardIron initial hard-iron to find a solution.
2589      * @param initialMm       initial soft-iron matrix containing scale factors
2590      *                        and cross coupling errors.
2591      * @throws IllegalArgumentException if provided hard-iron matrix is not
2592      *                                  3x1 or if soft-iron matrix is not
2593      *                                  3x3.
2594      */
2595     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2596             final WorldMagneticModel magneticModel, final Matrix initialHardIron, final Matrix initialMm) {
2597         this(initialHardIron, initialMm);
2598         this.magneticModel = magneticModel;
2599     }
2600 
2601     /**
2602      * Constructor.
2603      *
2604      * @param magneticModel   Earth's magnetic model. If null, a default model
2605      *                        will be used instead.
2606      * @param initialHardIron initial hard-iron to find a solution.
2607      * @param initialMm       initial soft-iron matrix containing scale factors
2608      *                        and cross coupling errors.
2609      * @param listener        listener to handle events raised by this calibrator.
2610      * @throws IllegalArgumentException if provided hard-iron matrix is not
2611      *                                  3x1 or if soft-iron matrix is not
2612      *                                  3x3.
2613      */
2614     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2615             final WorldMagneticModel magneticModel, final Matrix initialHardIron, final Matrix initialMm,
2616             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2617         this(magneticModel, initialHardIron, initialMm);
2618         this.listener = listener;
2619     }
2620 
2621     /**
2622      * Constructor.
2623      *
2624      * @param measurements    collection of body magnetic flux density measurements with
2625      *                        standard deviations taken at different frames (positions
2626      *                        and orientations).
2627      * @param magneticModel   Earth's magnetic model. If null, a default model
2628      *                        will be used instead.
2629      * @param initialHardIron initial hard-iron to find a solution.
2630      * @param initialMm       initial soft-iron matrix containing scale factors
2631      *                        and cross coupling errors.
2632      * @throws IllegalArgumentException if provided hard-iron matrix is not
2633      *                                  3x1 or if soft-iron matrix is not
2634      *                                  3x3.
2635      */
2636     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2637             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2638             final WorldMagneticModel magneticModel, final Matrix initialHardIron, final Matrix initialMm) {
2639         this(magneticModel, initialHardIron, initialMm);
2640         this.measurements = measurements;
2641     }
2642 
2643     /**
2644      * Constructor.
2645      *
2646      * @param measurements    collection of body magnetic flux density measurements with
2647      *                        standard deviations taken at different frames (positions
2648      *                        and orientations).
2649      * @param magneticModel   Earth's magnetic model. If null, a default model
2650      *                        will be used instead.
2651      * @param initialHardIron initial hard-iron to find a solution.
2652      * @param initialMm       initial soft-iron matrix containing scale factors
2653      *                        and cross coupling errors.
2654      * @param listener        listener to handle events raised by this calibrator.
2655      * @throws IllegalArgumentException if provided hard-iron matrix is not
2656      *                                  3x1 or if soft-iron matrix is not
2657      *                                  3x3.
2658      */
2659     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2660             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements,
2661             final WorldMagneticModel magneticModel, final Matrix initialHardIron, final Matrix initialMm,
2662             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2663         this(measurements, magneticModel, initialHardIron, initialMm);
2664         this.listener = listener;
2665     }
2666 
2667     /**
2668      * Constructor.
2669      *
2670      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2671      *                        for the accelerometer, gyroscope and magnetometer.
2672      * @param magneticModel   Earth's magnetic model. If null, a default model
2673      *                        will be used instead.
2674      * @param initialHardIron initial hard-iron to find a solution.
2675      * @param initialMm       initial soft-iron matrix containing scale factors
2676      *                        and cross coupling errors.
2677      * @throws IllegalArgumentException if provided hard-iron matrix is not
2678      *                                  3x1 or if soft-iron matrix is not
2679      *                                  3x3.
2680      */
2681     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2682             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final Matrix initialHardIron,
2683             final Matrix initialMm) {
2684         this(magneticModel, initialHardIron, initialMm);
2685         this.commonAxisUsed = commonAxisUsed;
2686     }
2687 
2688     /**
2689      * Constructor.
2690      *
2691      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2692      *                        for the accelerometer, gyroscope and magnetometer.
2693      * @param magneticModel   Earth's magnetic model. If null, a default model
2694      *                        will be used instead.
2695      * @param initialHardIron initial hard-iron to find a solution.
2696      * @param initialMm       initial soft-iron matrix containing scale factors
2697      *                        and cross coupling errors.
2698      * @param listener        listener to handle events raised by this calibrator.
2699      * @throws IllegalArgumentException if provided hard-iron matrix is not
2700      *                                  3x1 or if soft-iron matrix is not
2701      *                                  3x3.
2702      */
2703     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2704             final boolean commonAxisUsed, final WorldMagneticModel magneticModel, final Matrix initialHardIron,
2705             final Matrix initialMm, final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2706         this(commonAxisUsed, magneticModel, initialHardIron, initialMm);
2707         this.listener = listener;
2708     }
2709 
2710     /**
2711      * Constructor.
2712      *
2713      * @param measurements    collection of body magnetic flux density measurements with
2714      *                        standard deviations taken at different frames (positions
2715      *                        and orientations).
2716      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2717      *                        for the accelerometer, gyroscope and magnetometer.
2718      * @param magneticModel   Earth's magnetic model. If null, a default model
2719      *                        will be used instead.
2720      * @param initialHardIron initial hard-iron to find a solution.
2721      * @param initialMm       initial soft-iron matrix containing scale factors
2722      *                        and cross coupling errors.
2723      * @throws IllegalArgumentException if provided hard-iron matrix is not
2724      *                                  3x1 or if soft-iron matrix is not
2725      *                                  3x3.
2726      */
2727     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2728             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
2729             final WorldMagneticModel magneticModel, final Matrix initialHardIron, final Matrix initialMm) {
2730         this(commonAxisUsed, magneticModel, initialHardIron, initialMm);
2731         this.measurements = measurements;
2732     }
2733 
2734     /**
2735      * Constructor.
2736      *
2737      * @param measurements    collection of body magnetic flux density measurements with
2738      *                        standard deviations taken at different frames (positions
2739      *                        and orientations).
2740      * @param commonAxisUsed  indicates whether z-axis is assumed to be common
2741      *                        for the accelerometer, gyroscope and magnetometer.
2742      * @param magneticModel   Earth's magnetic model. If null, a default model
2743      *                        will be used instead.
2744      * @param initialHardIron initial hard-iron to find a solution.
2745      * @param initialMm       initial soft-iron matrix containing scale factors
2746      *                        and cross coupling errors.
2747      * @param listener        listener to handle events raised by this calibrator.
2748      * @throws IllegalArgumentException if provided hard-iron matrix is not
2749      *                                  3x1 or if soft-iron matrix is not
2750      *                                  3x3.
2751      */
2752     public KnownFrameMagnetometerNonLinearLeastSquaresCalibrator(
2753             final Collection<StandardDeviationFrameBodyMagneticFluxDensity> measurements, final boolean commonAxisUsed,
2754             final WorldMagneticModel magneticModel, final Matrix initialHardIron, final Matrix initialMm,
2755             final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener) {
2756         this(measurements, commonAxisUsed, magneticModel, initialHardIron, initialMm);
2757         this.listener = listener;
2758     }
2759 
2760     /**
2761      * Gets initial x-coordinate of magnetometer hard-iron bias to be used
2762      * to find a solution.
2763      * This is expressed in Teslas (T).
2764      *
2765      * @return initial x-coordinate of magnetometer hard-iron bias.
2766      */
2767     @Override
2768     public double getInitialHardIronX() {
2769         return initialHardIronX;
2770     }
2771 
2772     /**
2773      * Sets initial x-coordinate of magnetometer hard-iron bias to be used
2774      * to find a solution.
2775      * This is expressed in Teslas (T).
2776      *
2777      * @param initialHardIronX initial x-coordinate of magnetometer
2778      *                         hard-iron bias.
2779      * @throws LockedException if calibrator is currently running.
2780      */
2781     @Override
2782     public void setInitialHardIronX(final double initialHardIronX) throws LockedException {
2783         if (running) {
2784             throw new LockedException();
2785         }
2786         this.initialHardIronX = initialHardIronX;
2787     }
2788 
2789     /**
2790      * Gets initial y-coordinate of magnetometer hard-iron bias to be used
2791      * to find a solution.
2792      * This is expressed in Teslas (T).
2793      *
2794      * @return initial y-coordinate of magnetometer hard-iron bias.
2795      */
2796     @Override
2797     public double getInitialHardIronY() {
2798         return initialHardIronY;
2799     }
2800 
2801     /**
2802      * Sets initial y-coordinate of magnetometer hard-iron bias to be used
2803      * to find a solution.
2804      * This is expressed in Teslas (T).
2805      *
2806      * @param initialHardIronY initial y-coordinate of magnetometer
2807      *                         hard-iron bias.
2808      * @throws LockedException if calibrator is currently running.
2809      */
2810     @Override
2811     public void setInitialHardIronY(final double initialHardIronY) throws LockedException {
2812         if (running) {
2813             throw new LockedException();
2814         }
2815         this.initialHardIronY = initialHardIronY;
2816     }
2817 
2818     /**
2819      * Gets initial z-coordinate of magnetometer hard-iron bias to be used
2820      * to find a solution.
2821      * This is expressed in Teslas (T).
2822      *
2823      * @return initial z-coordinate of magnetometer hard-iron bias.
2824      */
2825     @Override
2826     public double getInitialHardIronZ() {
2827         return initialHardIronZ;
2828     }
2829 
2830     /**
2831      * Sets initial z-coordinate of magnetometer hard-iron bias to be used
2832      * to find a solution.
2833      * This is expressed in meters Teslas (T).
2834      *
2835      * @param initialHardIronZ initial z-coordinate of magnetometer
2836      *                         hard-iron bias.
2837      * @throws LockedException if calibrator is currently running.
2838      */
2839     @Override
2840     public void setInitialHardIronZ(final double initialHardIronZ) throws LockedException {
2841         if (running) {
2842             throw new LockedException();
2843         }
2844         this.initialHardIronZ = initialHardIronZ;
2845     }
2846 
2847     /**
2848      * Gets initial x-coordinate of magnetometer hard iron bias to be used
2849      * to find a solution.
2850      *
2851      * @return initial x-coordinate of magnetometer hard-iron bias.
2852      */
2853     @Override
2854     public MagneticFluxDensity getInitialHardIronXAsMagneticFluxDensity() {
2855         return new MagneticFluxDensity(initialHardIronX, MagneticFluxDensityUnit.TESLA);
2856     }
2857 
2858     /**
2859      * Gets initial x-coordinate of magnetometer hard iron bias to be used
2860      * to find a solution.
2861      *
2862      * @param result instance where result will be stored.
2863      */
2864     @Override
2865     public void getInitialHardIronXAsMagneticFluxDensity(final MagneticFluxDensity result) {
2866         result.setValue(initialHardIronX);
2867         result.setUnit(MagneticFluxDensityUnit.TESLA);
2868     }
2869 
2870     /**
2871      * Sets initial x-coordinate of magnetometer hard iron bias to be used
2872      * to find a solution.
2873      *
2874      * @param initialHardIronX initial x-coordinate of magnetometer bias.
2875      * @throws LockedException if calibrator is currently running.
2876      */
2877     @Override
2878     public void setInitialHardIronX(final MagneticFluxDensity initialHardIronX) throws LockedException {
2879         if (running) {
2880             throw new LockedException();
2881         }
2882         this.initialHardIronX = convertMagneticFluxDensity(initialHardIronX);
2883     }
2884 
2885     /**
2886      * Gets initial y-coordinate of magnetometer hard iron bias to be used
2887      * to find a solution.
2888      *
2889      * @return initial y-coordinate of magnetometer hard-iron bias.
2890      */
2891     @Override
2892     public MagneticFluxDensity getInitialHardIronYAsMagneticFluxDensity() {
2893         return new MagneticFluxDensity(initialHardIronY, MagneticFluxDensityUnit.TESLA);
2894     }
2895 
2896     /**
2897      * Gets initial y-coordinate of magnetometer hard iron bias to be used
2898      * to find a solution.
2899      *
2900      * @param result instance where result will be stored.
2901      */
2902     @Override
2903     public void getInitialHardIronYAsMagneticFluxDensity(final MagneticFluxDensity result) {
2904         result.setValue(initialHardIronY);
2905         result.setUnit(MagneticFluxDensityUnit.TESLA);
2906     }
2907 
2908     /**
2909      * Sets initial y-coordinate of magnetometer hard iron bias to be used
2910      * to find a solution.
2911      *
2912      * @param initialHardIronY initial y-coordinate of magnetometer bias.
2913      * @throws LockedException if calibrator is currently running.
2914      */
2915     @Override
2916     public void setInitialHardIronY(final MagneticFluxDensity initialHardIronY) throws LockedException {
2917         if (running) {
2918             throw new LockedException();
2919         }
2920         this.initialHardIronY = convertMagneticFluxDensity(initialHardIronY);
2921     }
2922 
2923     /**
2924      * Gets initial z-coordinate of magnetometer hard iron bias to be used
2925      * to find a solution.
2926      *
2927      * @return initial z-coordinate of magnetometer hard-iron bias.
2928      */
2929     @Override
2930     public MagneticFluxDensity getInitialHardIronZAsMagneticFluxDensity() {
2931         return new MagneticFluxDensity(initialHardIronZ, MagneticFluxDensityUnit.TESLA);
2932     }
2933 
2934     /**
2935      * Gets initial z-coordinate of magnetometer hard iron bias to be used
2936      * to find a solution.
2937      *
2938      * @param result instance where result will be stored.
2939      */
2940     @Override
2941     public void getInitialHardIronZAsMagneticFluxDensity(final MagneticFluxDensity result) {
2942         result.setValue(initialHardIronZ);
2943         result.setUnit(MagneticFluxDensityUnit.TESLA);
2944     }
2945 
2946     /**
2947      * Sets initial z-coordinate of magnetometer hard iron bias to be used
2948      * to find a solution.
2949      *
2950      * @param initialHardIronZ initial z-coordinate of magnetometer bias.
2951      * @throws LockedException if calibrator is currently running.
2952      */
2953     @Override
2954     public void setInitialHardIronZ(final MagneticFluxDensity initialHardIronZ) throws LockedException {
2955         if (running) {
2956             throw new LockedException();
2957         }
2958         this.initialHardIronZ = convertMagneticFluxDensity(initialHardIronZ);
2959     }
2960 
2961     /**
2962      * Sets initial hard-iron bias coordinates of magnetometer used to find
2963      * a solution expressed in Teslas (T).
2964      *
2965      * @param initialHardIronX initial x-coordinate of magnetometer
2966      *                         hard-iron bias.
2967      * @param initialHardIronY initial y-coordinate of magnetometer
2968      *                         hard-iron bias.
2969      * @param initialHardIronZ initial z-coordinate of magnetometer
2970      *                         hard-iron bias.
2971      * @throws LockedException if calibrator is currently running.
2972      */
2973     @Override
2974     public void setInitialHardIron(
2975             final double initialHardIronX, final double initialHardIronY, final double initialHardIronZ)
2976             throws LockedException {
2977         if (running) {
2978             throw new LockedException();
2979         }
2980         this.initialHardIronX = initialHardIronX;
2981         this.initialHardIronY = initialHardIronY;
2982         this.initialHardIronZ = initialHardIronZ;
2983     }
2984 
2985     /**
2986      * Sets initial hard iron coordinates of magnetometer used to find a solution.
2987      *
2988      * @param initialHardIronX initial x-coordinate of magnetometer bias.
2989      * @param initialHardIronY initial y-coordinate of magnetometer bias.
2990      * @param initialHardIronZ initial z-coordinate of magnetometer bias.
2991      * @throws LockedException if calibrator is currently running.
2992      */
2993     @Override
2994     public void setInitialHardIron(
2995             final MagneticFluxDensity initialHardIronX, final MagneticFluxDensity initialHardIronY,
2996             final MagneticFluxDensity initialHardIronZ) throws LockedException {
2997         if (running) {
2998             throw new LockedException();
2999         }
3000 
3001         this.initialHardIronX = convertMagneticFluxDensity(initialHardIronX);
3002         this.initialHardIronY = convertMagneticFluxDensity(initialHardIronY);
3003         this.initialHardIronZ = convertMagneticFluxDensity(initialHardIronZ);
3004     }
3005 
3006     /**
3007      * Gets initial hard-iron used to find a solution.
3008      *
3009      * @return initial hard-iron.
3010      */
3011     @Override
3012     public MagneticFluxDensityTriad getInitialHardIronAsTriad() {
3013         return new MagneticFluxDensityTriad(MagneticFluxDensityUnit.TESLA,
3014                 initialHardIronX, initialHardIronY, initialHardIronZ);
3015     }
3016 
3017     /**
3018      * Gets initial hard-iron used to find a solution.
3019      *
3020      * @param result instance where result will be stored.
3021      */
3022     @Override
3023     public void getInitialHardIronAsTriad(final MagneticFluxDensityTriad result) {
3024         result.setValueCoordinatesAndUnit(initialHardIronX, initialHardIronY, initialHardIronZ,
3025                 MagneticFluxDensityUnit.TESLA);
3026     }
3027 
3028     /**
3029      * Sets initial hard-iron used to find a solution.
3030      *
3031      * @param initialHardIron initial hard-iron to be set.
3032      * @throws LockedException if calibrator is currently running.
3033      */
3034     @Override
3035     public void setInitialHardIron(final MagneticFluxDensityTriad initialHardIron) throws LockedException {
3036         if (running) {
3037             throw new LockedException();
3038         }
3039 
3040         initialHardIronX = convertMagneticFluxDensity(initialHardIron.getValueX(), initialHardIron.getUnit());
3041         initialHardIronY = convertMagneticFluxDensity(initialHardIron.getValueY(), initialHardIron.getUnit());
3042         initialHardIronZ = convertMagneticFluxDensity(initialHardIron.getValueZ(), initialHardIron.getUnit());
3043     }
3044 
3045     /**
3046      * Gets initial x scaling factor.
3047      *
3048      * @return initial x scaling factor.
3049      */
3050     @Override
3051     public double getInitialSx() {
3052         return initialSx;
3053     }
3054 
3055     /**
3056      * Sets initial x scaling factor.
3057      *
3058      * @param initialSx initial x scaling factor.
3059      * @throws LockedException if calibrator is currently running.
3060      */
3061     @Override
3062     public void setInitialSx(final double initialSx) throws LockedException {
3063         if (running) {
3064             throw new LockedException();
3065         }
3066         this.initialSx = initialSx;
3067     }
3068 
3069     /**
3070      * Gets initial y scaling factor.
3071      *
3072      * @return initial y scaling factor.
3073      */
3074     @Override
3075     public double getInitialSy() {
3076         return initialSy;
3077     }
3078 
3079     /**
3080      * Sets initial y scaling factor.
3081      *
3082      * @param initialSy initial y scaling factor.
3083      * @throws LockedException if calibrator is currently running.
3084      */
3085     @Override
3086     public void setInitialSy(final double initialSy) throws LockedException {
3087         if (running) {
3088             throw new LockedException();
3089         }
3090         this.initialSy = initialSy;
3091     }
3092 
3093     /**
3094      * Gets initial z scaling factor.
3095      *
3096      * @return initial z scaling factor.
3097      */
3098     @Override
3099     public double getInitialSz() {
3100         return initialSz;
3101     }
3102 
3103     /**
3104      * Sets initial z scaling factor.
3105      *
3106      * @param initialSz initial z scaling factor.
3107      * @throws LockedException if calibrator is currently running.
3108      */
3109     @Override
3110     public void setInitialSz(final double initialSz) throws LockedException {
3111         if (running) {
3112             throw new LockedException();
3113         }
3114         this.initialSz = initialSz;
3115     }
3116 
3117     /**
3118      * Gets initial x-y cross coupling error.
3119      *
3120      * @return initial x-y cross coupling error.
3121      */
3122     @Override
3123     public double getInitialMxy() {
3124         return initialMxy;
3125     }
3126 
3127     /**
3128      * Sets initial x-y cross coupling error.
3129      *
3130      * @param initialMxy initial x-y cross coupling error.
3131      * @throws LockedException if calibrator is currently running.
3132      */
3133     @Override
3134     public void setInitialMxy(final double initialMxy) throws LockedException {
3135         if (running) {
3136             throw new LockedException();
3137         }
3138         this.initialMxy = initialMxy;
3139     }
3140 
3141     /**
3142      * Gets initial x-z cross coupling error.
3143      *
3144      * @return initial x-z cross coupling error.
3145      */
3146     @Override
3147     public double getInitialMxz() {
3148         return initialMxz;
3149     }
3150 
3151     /**
3152      * Sets initial x-z cross coupling error.
3153      *
3154      * @param initialMxz initial x-z cross coupling error.
3155      * @throws LockedException if calibrator is currently running.
3156      */
3157     @Override
3158     public void setInitialMxz(final double initialMxz) throws LockedException {
3159         if (running) {
3160             throw new LockedException();
3161         }
3162         this.initialMxz = initialMxz;
3163     }
3164 
3165     /**
3166      * Gets initial y-x cross coupling error.
3167      *
3168      * @return initial y-x cross coupling error.
3169      */
3170     @Override
3171     public double getInitialMyx() {
3172         return initialMyx;
3173     }
3174 
3175     /**
3176      * Sets initial y-x cross coupling error.
3177      *
3178      * @param initialMyx initial y-x cross coupling error.
3179      * @throws LockedException if calibrator is currently running.
3180      */
3181     @Override
3182     public void setInitialMyx(final double initialMyx) throws LockedException {
3183         if (running) {
3184             throw new LockedException();
3185         }
3186         this.initialMyx = initialMyx;
3187     }
3188 
3189     /**
3190      * Gets initial y-z cross coupling error.
3191      *
3192      * @return initial y-z cross coupling error.
3193      */
3194     @Override
3195     public double getInitialMyz() {
3196         return initialMyz;
3197     }
3198 
3199     /**
3200      * Sets initial y-z cross coupling error.
3201      *
3202      * @param initialMyz initial y-z cross coupling error.
3203      * @throws LockedException if calibrator is currently running.
3204      */
3205     @Override
3206     public void setInitialMyz(final double initialMyz) throws LockedException {
3207         if (running) {
3208             throw new LockedException();
3209         }
3210         this.initialMyz = initialMyz;
3211     }
3212 
3213     /**
3214      * Gets initial z-x cross coupling error.
3215      *
3216      * @return initial z-x cross coupling error.
3217      */
3218     @Override
3219     public double getInitialMzx() {
3220         return initialMzx;
3221     }
3222 
3223     /**
3224      * Sets initial z-x cross coupling error.
3225      *
3226      * @param initialMzx initial z-x cross coupling error.
3227      * @throws LockedException if calibrator is currently running.
3228      */
3229     @Override
3230     public void setInitialMzx(final double initialMzx) throws LockedException {
3231         if (running) {
3232             throw new LockedException();
3233         }
3234         this.initialMzx = initialMzx;
3235     }
3236 
3237     /**
3238      * Gets initial z-y cross coupling error.
3239      *
3240      * @return initial z-y cross coupling error.
3241      */
3242     @Override
3243     public double getInitialMzy() {
3244         return initialMzy;
3245     }
3246 
3247     /**
3248      * Sets initial z-y cross coupling error.
3249      *
3250      * @param initialMzy initial z-y cross coupling error.
3251      * @throws LockedException if calibrator is currently running.
3252      */
3253     @Override
3254     public void setInitialMzy(final double initialMzy) throws LockedException {
3255         if (running) {
3256             throw new LockedException();
3257         }
3258         this.initialMzy = initialMzy;
3259     }
3260 
3261     /**
3262      * Sets initial scaling factors.
3263      *
3264      * @param initialSx initial x scaling factor.
3265      * @param initialSy initial y scaling factor.
3266      * @param initialSz initial z scaling factor.
3267      * @throws LockedException if calibrator is currently running.
3268      */
3269     @Override
3270     public void setInitialScalingFactors(
3271             final double initialSx, final double initialSy, final double initialSz) throws LockedException {
3272         if (running) {
3273             throw new LockedException();
3274         }
3275         this.initialSx = initialSx;
3276         this.initialSy = initialSy;
3277         this.initialSz = initialSz;
3278     }
3279 
3280     /**
3281      * Sets initial cross coupling errors.
3282      *
3283      * @param initialMxy initial x-y cross coupling error.
3284      * @param initialMxz initial x-z cross coupling error.
3285      * @param initialMyx initial y-x cross coupling error.
3286      * @param initialMyz initial y-z cross coupling error.
3287      * @param initialMzx initial z-x cross coupling error.
3288      * @param initialMzy initial z-y cross coupling error.
3289      * @throws LockedException if calibrator is currently running.
3290      */
3291     @Override
3292     public void setInitialCrossCouplingErrors(
3293             final double initialMxy, final double initialMxz, final double initialMyx,
3294             final double initialMyz, final double initialMzx, final double initialMzy) throws LockedException {
3295         if (running) {
3296             throw new LockedException();
3297         }
3298         this.initialMxy = initialMxy;
3299         this.initialMxz = initialMxz;
3300         this.initialMyx = initialMyx;
3301         this.initialMyz = initialMyz;
3302         this.initialMzx = initialMzx;
3303         this.initialMzy = initialMzy;
3304     }
3305 
3306     /**
3307      * Sets initial scaling factors and cross coupling errors.
3308      *
3309      * @param initialSx  initial x scaling factor.
3310      * @param initialSy  initial y scaling factor.
3311      * @param initialSz  initial z scaling factor.
3312      * @param initialMxy initial x-y cross coupling error.
3313      * @param initialMxz initial x-z cross coupling error.
3314      * @param initialMyx initial y-x cross coupling error.
3315      * @param initialMyz initial y-z cross coupling error.
3316      * @param initialMzx initial z-x cross coupling error.
3317      * @param initialMzy initial z-y cross coupling error.
3318      * @throws LockedException if calibrator is currently running.
3319      */
3320     @Override
3321     public void setInitialScalingFactorsAndCrossCouplingErrors(
3322             final double initialSx, final double initialSy, final double initialSz,
3323             final double initialMxy, final double initialMxz, final double initialMyx,
3324             final double initialMyz, final double initialMzx, final double initialMzy) throws LockedException {
3325         if (running) {
3326             throw new LockedException();
3327         }
3328         setInitialScalingFactors(initialSx, initialSy, initialSz);
3329         setInitialCrossCouplingErrors(initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
3330     }
3331 
3332     /**
3333      * Gets initial hard-iron bias to be used to find a solution as an array.
3334      * Array values are expressed in Teslas (T).
3335      *
3336      * @return array containing coordinates of initial bias.
3337      */
3338     @Override
3339     public double[] getInitialHardIron() {
3340         final var result = new double[BodyMagneticFluxDensity.COMPONENTS];
3341         getInitialHardIron(result);
3342         return result;
3343     }
3344 
3345     /**
3346      * Gets initial hard-iron bias to be used to find a solution as an array.
3347      * Array values are expressed in Teslas (T).
3348      *
3349      * @param result instance where result data will be copied to.
3350      * @throws IllegalArgumentException if provided array does not have
3351      *                                  length 3.
3352      */
3353     @Override
3354     public void getInitialHardIron(final double[] result) {
3355         if (result.length != BodyMagneticFluxDensity.COMPONENTS) {
3356             throw new IllegalArgumentException();
3357         }
3358         result[0] = initialHardIronX;
3359         result[1] = initialHardIronY;
3360         result[2] = initialHardIronZ;
3361     }
3362 
3363     /**
3364      * Sets initial hard-iron bias to be used to find a solution as an array.
3365      * Array values are expressed in Teslas (T).
3366      *
3367      * @param initialHardIron initial hard-iron to find a solution.
3368      * @throws LockedException          if calibrator is currently running.
3369      * @throws IllegalArgumentException if provided array does not have length 3.
3370      */
3371     @Override
3372     public void setInitialHardIron(final double[] initialHardIron) throws LockedException {
3373         if (running) {
3374             throw new LockedException();
3375         }
3376 
3377         if (initialHardIron.length != BodyMagneticFluxDensity.COMPONENTS) {
3378             throw new IllegalArgumentException();
3379         }
3380         initialHardIronX = initialHardIron[0];
3381         initialHardIronY = initialHardIron[1];
3382         initialHardIronZ = initialHardIron[2];
3383     }
3384 
3385     /**
3386      * Gets initial hard-iron bias to be used to find a solution as a
3387      * column matrix.
3388      * Values are expressed in Teslas (T).
3389      *
3390      * @return initial hard-iron bias to be used to find a solution as a
3391      * column matrix.
3392      */
3393     @Override
3394     public Matrix getInitialHardIronAsMatrix() {
3395         Matrix result;
3396         try {
3397             result = new Matrix(BodyMagneticFluxDensity.COMPONENTS, 1);
3398             getInitialHardIronAsMatrix(result);
3399         } catch (final WrongSizeException ignore) {
3400             // never happens
3401             result = null;
3402         }
3403         return result;
3404     }
3405 
3406     /**
3407      * Gets initial hard-iron bias to be used to find a solution as a
3408      * column matrix.
3409      * Values are expressed in Teslas (T).
3410      *
3411      * @param result instance where result data will be copied to.
3412      * @throws IllegalArgumentException if provided matrix is not 3x1.
3413      */
3414     @Override
3415     public void getInitialHardIronAsMatrix(final Matrix result) {
3416         if (result.getRows() != BodyMagneticFluxDensity.COMPONENTS || result.getColumns() != 1) {
3417             throw new IllegalArgumentException();
3418         }
3419         result.setElementAtIndex(0, initialHardIronX);
3420         result.setElementAtIndex(1, initialHardIronY);
3421         result.setElementAtIndex(2, initialHardIronZ);
3422     }
3423 
3424     /**
3425      * Sets initial hard-iron bias to be used to find a solution as a column
3426      * matrix with values expressed in Teslas (T).
3427      *
3428      * @param initialHardIron initial hard-iron bias to find a solution.
3429      * @throws LockedException          if calibrator is currently running.
3430      * @throws IllegalArgumentException if provided matrix is not 3x1.
3431      */
3432     @Override
3433     public void setInitialHardIron(final Matrix initialHardIron) throws LockedException {
3434         if (running) {
3435             throw new LockedException();
3436         }
3437         if (initialHardIron.getRows() != BodyMagneticFluxDensity.COMPONENTS || initialHardIron.getColumns() != 1) {
3438             throw new IllegalArgumentException();
3439         }
3440 
3441         initialHardIronX = initialHardIron.getElementAtIndex(0);
3442         initialHardIronY = initialHardIron.getElementAtIndex(1);
3443         initialHardIronZ = initialHardIron.getElementAtIndex(2);
3444     }
3445 
3446     /**
3447      * Gets initial scale factors and cross coupling errors matrix.
3448      *
3449      * @return initial scale factors and cross coupling errors matrix.
3450      */
3451     @Override
3452     public Matrix getInitialMm() {
3453         Matrix result;
3454         try {
3455             result = new Matrix(BodyMagneticFluxDensity.COMPONENTS, BodyMagneticFluxDensity.COMPONENTS);
3456             getInitialMm(result);
3457         } catch (final WrongSizeException ignore) {
3458             // never happens
3459             result = null;
3460         }
3461         return result;
3462     }
3463 
3464     /**
3465      * Gets initial scale factors and cross coupling errors matrix.
3466      *
3467      * @param result instance where data will be stored.
3468      * @throws IllegalArgumentException if provided matrix is not 3x3.
3469      */
3470     @Override
3471     public void getInitialMm(final Matrix result) {
3472         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != BodyKinematics.COMPONENTS) {
3473             throw new IllegalArgumentException();
3474         }
3475         result.setElementAtIndex(0, initialSx);
3476         result.setElementAtIndex(1, initialMyx);
3477         result.setElementAtIndex(2, initialMzx);
3478 
3479         result.setElementAtIndex(3, initialMxy);
3480         result.setElementAtIndex(4, initialSy);
3481         result.setElementAtIndex(5, initialMzy);
3482 
3483         result.setElementAtIndex(6, initialMxz);
3484         result.setElementAtIndex(7, initialMyz);
3485         result.setElementAtIndex(8, initialSz);
3486     }
3487 
3488     /**
3489      * Sets initial scale factors and cross coupling errors matrix.
3490      *
3491      * @param initialMm initial scale factors and cross coupling errors matrix.
3492      * @throws IllegalArgumentException if provided matrix is not 3x3.
3493      * @throws LockedException          if calibrator is currently running.
3494      */
3495     @Override
3496     public void setInitialMm(final Matrix initialMm) throws LockedException {
3497         if (running) {
3498             throw new LockedException();
3499         }
3500         if (initialMm.getRows() != BodyKinematics.COMPONENTS || initialMm.getColumns() != BodyKinematics.COMPONENTS) {
3501             throw new IllegalArgumentException();
3502         }
3503 
3504         initialSx = initialMm.getElementAtIndex(0);
3505         initialMyx = initialMm.getElementAtIndex(1);
3506         initialMzx = initialMm.getElementAtIndex(2);
3507 
3508         initialMxy = initialMm.getElementAtIndex(3);
3509         initialSy = initialMm.getElementAtIndex(4);
3510         initialMzy = initialMm.getElementAtIndex(5);
3511 
3512         initialMxz = initialMm.getElementAtIndex(6);
3513         initialMyz = initialMm.getElementAtIndex(7);
3514         initialSz = initialMm.getElementAtIndex(8);
3515     }
3516 
3517     /**
3518      * Gets a collection of body magnetic flux density measurements taken at different
3519      * frames (positions, orientations and velocities).
3520      * If a single device IMU needs to be calibrated, typically all measurements are
3521      * taken at the same position, with zero velocity and multiple orientations.
3522      * However, if we just want to calibrate a given IMU model (e.g. obtain
3523      * an average and less precise calibration for the IMU of a given phone model),
3524      * we could take measurements collected throughout the planet at multiple positions
3525      * while the phone remains static (e.g. while charging), hence each measurement
3526      * position will change, velocity will remain zero and orientation will be
3527      * typically constant at horizontal orientation while the phone remains on a
3528      * flat surface.
3529      *
3530      * @return a collection of body magnetic flux density measurements taken at different
3531      * frames (positions, orientations and velocities).
3532      */
3533     @Override
3534     public Collection<StandardDeviationFrameBodyMagneticFluxDensity> getMeasurements() {
3535         return measurements;
3536     }
3537 
3538     /**
3539      * Sets a collection of body magnetic flux density measurements taken at different
3540      * frames (positions, orientations and velocities).
3541      * If a single device IMU needs to be calibrated, typically all measurements are
3542      * taken at the same position, with zero velocity and multiple orientations.
3543      * However, if we just want to calibrate the a given IMU model (e.g. obtain
3544      * an average and less precise calibration for the IMU of a given phone model),
3545      * we could take measurements collected throughout the planet at multiple positions
3546      * while the phone remains static (e.g. while charging), hence each measurement
3547      * position will change, velocity will remain zero and orientation will be
3548      * typically constant at horizontal orientation while the phone remains on a
3549      * flat surface.
3550      *
3551      * @param measurements collection of body magnetic flux density measurements
3552      *                     taken at different frames (positions, orientations
3553      *                     and velocities).
3554      * @throws LockedException if estimator is currently running.
3555      */
3556     @Override
3557     public void setMeasurements(final Collection<? extends StandardDeviationFrameBodyMagneticFluxDensity> measurements)
3558             throws LockedException {
3559         if (running) {
3560             throw new LockedException();
3561         }
3562         //noinspection unchecked
3563         this.measurements = (Collection<StandardDeviationFrameBodyMagneticFluxDensity>) measurements;
3564     }
3565 
3566     /**
3567      * Indicates the type of measurement used by this calibrator.
3568      *
3569      * @return type of measurement used by this calibrator.
3570      */
3571     @Override
3572     public MagnetometerCalibratorMeasurementType getMeasurementType() {
3573         return MagnetometerCalibratorMeasurementType.STANDARD_DEVIATION_FRAME_BODY_MAGNETIC_FLUX_DENSITY;
3574     }
3575 
3576     /**
3577      * Indicates whether this calibrator requires ordered measurements in a
3578      * list or not.
3579      *
3580      * @return true if measurements must be ordered, false otherwise.
3581      */
3582     @Override
3583     public boolean isOrderedMeasurementsRequired() {
3584         return false;
3585     }
3586 
3587     /**
3588      * Indicates whether this calibrator requires quality scores for each
3589      * measurement or not.
3590      *
3591      * @return true if quality scores are required, false otherwise.
3592      */
3593     @Override
3594     public boolean isQualityScoresRequired() {
3595         return false;
3596     }
3597 
3598     /**
3599      * Indicates whether z-axis is assumed to be common for accelerometer,
3600      * gyroscope and magnetometer.
3601      * When enabled, this eliminates 3 variables from Mm (soft-iron) matrix.
3602      *
3603      * @return true if z-axis is assumed to be common for accelerometer,
3604      * gyroscope and magnetometer, false otherwise.
3605      */
3606     @Override
3607     public boolean isCommonAxisUsed() {
3608         return commonAxisUsed;
3609     }
3610 
3611     /**
3612      * Specifies whether z-axis is assumed to be common for accelerometer and
3613      * gyroscope.
3614      * When enabled, this eliminates 3 variables from Mm matrix.
3615      *
3616      * @param commonAxisUsed true if z-axis is assumed to be common for
3617      *                       accelerometer, gyroscope and magnetometer, false
3618      *                       otherwise.
3619      * @throws LockedException if estimator is currently running.
3620      */
3621     @Override
3622     public void setCommonAxisUsed(final boolean commonAxisUsed) throws LockedException {
3623         if (running) {
3624             throw new LockedException();
3625         }
3626 
3627         this.commonAxisUsed = commonAxisUsed;
3628     }
3629 
3630     /**
3631      * Gets listener to handle events raised by this calibrator.
3632      *
3633      * @return listener to handle events raised by this calibrator.
3634      */
3635     @Override
3636     public KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener getListener() {
3637         return listener;
3638     }
3639 
3640     /**
3641      * Sets listener to handle events raised by this calibrator.
3642      *
3643      * @param listener listener to handle events raised by this calibrator.
3644      * @throws LockedException if calibrator is currently running.
3645      */
3646     @Override
3647     public void setListener(final KnownFrameMagnetometerNonLinearLeastSquaresCalibratorListener listener)
3648             throws LockedException {
3649         if (running) {
3650             throw new LockedException();
3651         }
3652 
3653         this.listener = listener;
3654     }
3655 
3656     /**
3657      * Gets minimum number of required measurements.
3658      *
3659      * @return minimum number of required measurements.
3660      */
3661     @Override
3662     public int getMinimumRequiredMeasurements() {
3663         return MINIMUM_MEASUREMENTS;
3664     }
3665 
3666     /**
3667      * Indicates whether calibrator is ready to start the estimator.
3668      *
3669      * @return true if calibrator is ready, false otherwise.
3670      */
3671     @Override
3672     public boolean isReady() {
3673         return measurements != null && measurements.size() >= MINIMUM_MEASUREMENTS;
3674     }
3675 
3676     /**
3677      * Indicates whether calibrator is currently running or no.
3678      *
3679      * @return true if calibrator is running, false otherwise.
3680      */
3681     @Override
3682     public boolean isRunning() {
3683         return running;
3684     }
3685 
3686     /**
3687      * Gets Earth's magnetic model.
3688      *
3689      * @return Earth's magnetic model or null if not provided.
3690      */
3691     public WorldMagneticModel getMagneticModel() {
3692         return magneticModel;
3693     }
3694 
3695     /**
3696      * Sets Earth's magnetic model.
3697      *
3698      * @param magneticModel Earth's magnetic model to be set.
3699      * @throws LockedException if calibrator is currently running.
3700      */
3701     public void setMagneticModel(final WorldMagneticModel magneticModel) throws LockedException {
3702         if (running) {
3703             throw new LockedException();
3704         }
3705         this.magneticModel = magneticModel;
3706     }
3707 
3708     /**
3709      * Estimates magnetometer calibration parameters containing scale factors
3710      * and cross-coupling errors.
3711      *
3712      * @throws LockedException      if calibrator is currently running.
3713      * @throws NotReadyException    if calibrator is not ready.
3714      * @throws CalibrationException if calibration fails for numerical reasons.
3715      */
3716     @Override
3717     public void calibrate() throws LockedException, NotReadyException, CalibrationException {
3718         if (running) {
3719             throw new LockedException();
3720         }
3721 
3722         if (!isReady()) {
3723             throw new NotReadyException();
3724         }
3725 
3726         try {
3727             running = true;
3728 
3729             if (listener != null) {
3730                 listener.onCalibrateStart(this);
3731             }
3732 
3733             if (commonAxisUsed) {
3734                 calibrateCommonAxis();
3735             } else {
3736                 calibrateGeneral();
3737             }
3738 
3739             if (listener != null) {
3740                 listener.onCalibrateEnd(this);
3741             }
3742 
3743         } catch (final AlgebraException | FittingException | com.irurueta.numerical.NotReadyException | IOException e) {
3744             throw new CalibrationException(e);
3745         } finally {
3746             running = false;
3747         }
3748     }
3749 
3750     /**
3751      * Gets array containing x,y,z components of estimated magnetometer
3752      * hard-iron biases expressed in Teslas (T).
3753      *
3754      * @return array containing x,y,z components of estimated magnetometer
3755      * hard-iron biases.
3756      */
3757     @Override
3758     public double[] getEstimatedHardIron() {
3759         return estimatedHardIron;
3760     }
3761 
3762     /**
3763      * Gets array containing x,y,z components of estimated magnetometer
3764      * hard-iron biases expressed in Teslas (T).
3765      *
3766      * @param result instance where estimated magnetometer biases will be
3767      *               stored.
3768      * @return true if result instance was updated, false otherwise (when
3769      * estimation is not yet available).
3770      */
3771     @Override
3772     public boolean getEstimatedHardIron(final double[] result) {
3773         if (estimatedHardIron != null) {
3774             System.arraycopy(estimatedHardIron, 0, result, 0, estimatedHardIron.length);
3775             return true;
3776         } else {
3777             return false;
3778         }
3779     }
3780 
3781     /**
3782      * Gets column matrix containing x,y,z components of estimated
3783      * magnetometer hard-iron biases expressed in Teslas (T).
3784      *
3785      * @return column matrix containing x,y,z components of estimated
3786      * magnetometer hard-iron biases.
3787      */
3788     @Override
3789     public Matrix getEstimatedHardIronAsMatrix() {
3790         return estimatedHardIron != null ? Matrix.newFromArray(estimatedHardIron) : null;
3791     }
3792 
3793     /**
3794      * Gets column matrix containing x,y,z components of estimated
3795      * magnetometer hard-iron biases expressed in Teslas (T).
3796      *
3797      * @param result instance where result data will be stored.
3798      * @return true if result was updated, false otherwise.
3799      * @throws WrongSizeException if provided result instance has invalid size.
3800      */
3801     @Override
3802     public boolean getEstimatedHardIronAsMatrix(final Matrix result) throws WrongSizeException {
3803         if (estimatedHardIron != null) {
3804             result.fromArray(estimatedHardIron);
3805             return true;
3806         } else {
3807             return false;
3808         }
3809     }
3810 
3811     /**
3812      * Gets x coordinate of estimated magnetometer bias expressed in
3813      * Teslas (T).
3814      *
3815      * @return x coordinate of estimated magnetometer bias or null if not
3816      * available.
3817      */
3818     @Override
3819     public Double getEstimatedHardIronX() {
3820         return estimatedHardIron != null ? estimatedHardIron[0] : null;
3821     }
3822 
3823     /**
3824      * Gets y coordinate of estimated magnetometer bias expressed in
3825      * Teslas (T).
3826      *
3827      * @return y coordinate of estimated magnetometer bias or null if not
3828      * available.
3829      */
3830     @Override
3831     public Double getEstimatedHardIronY() {
3832         return estimatedHardIron != null ? estimatedHardIron[1] : null;
3833     }
3834 
3835     /**
3836      * Gets z coordinate of estimated magnetometer bias expressed in
3837      * Teslas (T).
3838      *
3839      * @return z coordinate of estimated magnetometer bias or null if not
3840      * available.
3841      */
3842     @Override
3843     public Double getEstimatedHardIronZ() {
3844         return estimatedHardIron != null ? estimatedHardIron[2] : null;
3845     }
3846 
3847     /**
3848      * Gets x coordinate of estimated magnetometer bias.
3849      *
3850      * @return x coordinate of estimated magnetometer bias.
3851      */
3852     @Override
3853     public MagneticFluxDensity getEstimatedHardIronXAsMagneticFluxDensity() {
3854         return estimatedHardIron != null
3855                 ? new MagneticFluxDensity(estimatedHardIron[0], MagneticFluxDensityUnit.TESLA) : null;
3856     }
3857 
3858     /**
3859      * Gets x coordinate of estimated magnetometer bias.
3860      *
3861      * @param result instance where result will be stored.
3862      * @return true if estimated magnetometer bias is available, false otherwise.
3863      */
3864     @Override
3865     public boolean getEstimatedHardIronXAsMagneticFluxDensity(final MagneticFluxDensity result) {
3866         if (estimatedHardIron != null) {
3867             result.setValue(estimatedHardIron[0]);
3868             result.setUnit(MagneticFluxDensityUnit.TESLA);
3869             return true;
3870         } else {
3871             return false;
3872         }
3873     }
3874 
3875     /**
3876      * Gets y coordinate of estimated magnetometer bias.
3877      *
3878      * @return y coordinate of estimated magnetometer bias.
3879      */
3880     @Override
3881     public MagneticFluxDensity getEstimatedHardIronYAsMagneticFluxDensity() {
3882         return estimatedHardIron != null
3883                 ? new MagneticFluxDensity(estimatedHardIron[1], MagneticFluxDensityUnit.TESLA) : null;
3884     }
3885 
3886     /**
3887      * Gets y coordinate of estimated magnetometer bias.
3888      *
3889      * @param result instance where result will be stored.
3890      * @return true if estimated magnetometer bias is available, false otherwise.
3891      */
3892     @Override
3893     public boolean getEstimatedHardIronYAsMagneticFluxDensity(final MagneticFluxDensity result) {
3894         if (estimatedHardIron != null) {
3895             result.setValue(estimatedHardIron[1]);
3896             result.setUnit(MagneticFluxDensityUnit.TESLA);
3897             return true;
3898         } else {
3899             return false;
3900         }
3901     }
3902 
3903     /**
3904      * Gets z coordinate of estimated magnetometer bias.
3905      *
3906      * @return z coordinate of estimated magnetometer bias.
3907      */
3908     @Override
3909     public MagneticFluxDensity getEstimatedHardIronZAsMagneticFluxDensity() {
3910         return estimatedHardIron != null
3911                 ? new MagneticFluxDensity(estimatedHardIron[2], MagneticFluxDensityUnit.TESLA) : null;
3912     }
3913 
3914     /**
3915      * Gets z coordinate of estimated magnetometer bias.
3916      *
3917      * @param result instance where result will be stored.
3918      * @return true if estimated magnetometer bias is available, false otherwise.
3919      */
3920     @Override
3921     public boolean getEstimatedHardIronZAsMagneticFluxDensity(final MagneticFluxDensity result) {
3922         if (estimatedHardIron != null) {
3923             result.setValue(estimatedHardIron[2]);
3924             result.setUnit(MagneticFluxDensityUnit.TESLA);
3925             return true;
3926         } else {
3927             return false;
3928         }
3929     }
3930 
3931     /**
3932      * Gets estimated magnetometer bias.
3933      *
3934      * @return estimated magnetometer bias or null if not available.
3935      */
3936     @Override
3937     public MagneticFluxDensityTriad getEstimatedHardIronAsTriad() {
3938         return estimatedHardIron != null
3939                 ? new MagneticFluxDensityTriad(MagneticFluxDensityUnit.TESLA,
3940                 estimatedHardIron[0], estimatedHardIron[1], estimatedHardIron[2])
3941                 : null;
3942     }
3943 
3944     /**
3945      * Gets estimated magnetometer bias.
3946      *
3947      * @param result instance where result will be stored.
3948      * @return true if estimated magnetometer bias is available and result was
3949      * modified, false otherwise.
3950      */
3951     @Override
3952     public boolean getEstimatedHardIronAsTriad(final MagneticFluxDensityTriad result) {
3953         if (estimatedHardIron != null) {
3954             result.setValueCoordinatesAndUnit(
3955                     estimatedHardIron[0], estimatedHardIron[1], estimatedHardIron[2], MagneticFluxDensityUnit.TESLA);
3956             return true;
3957         } else {
3958             return false;
3959         }
3960     }
3961 
3962     /**
3963      * Gets estimated magnetometer soft-iron matrix containing scale factors
3964      * and cross coupling errors.
3965      * This is the product of matrix Tm containing cross coupling errors and Km
3966      * containing scaling factors.
3967      * So tat:
3968      * <pre>
3969      *     Mm = [sx    mxy  mxz] = Tm*Km
3970      *          [myx   sy   myz]
3971      *          [mzx   mzy  sz ]
3972      * </pre>
3973      * Where:
3974      * <pre>
3975      *     Km = [sx 0   0 ]
3976      *          [0  sy  0 ]
3977      *          [0  0   sz]
3978      * </pre>
3979      * and
3980      * <pre>
3981      *     Tm = [1          -alphaXy    alphaXz ]
3982      *          [alphaYx    1           -alphaYz]
3983      *          [-alphaZx   alphaZy     1       ]
3984      * </pre>
3985      * Hence:
3986      * <pre>
3987      *     Mm = [sx    mxy  mxz] = Tm*Km =  [sx             -sy * alphaXy   sz * alphaXz ]
3988      *          [myx   sy   myz]            [sx * alphaYx   sy              -sz * alphaYz]
3989      *          [mzx   mzy  sz ]            [-sx * alphaZx  sy * alphaZy    sz           ]
3990      * </pre>
3991      * This instance allows any 3x3 matrix however, typically alphaYx, alphaZx and alphaZy
3992      * are considered to be zero if the accelerometer z-axis is assumed to be the same
3993      * as the body z-axis. When this is assumed, myx = mzx = mzy = 0 and the Mm matrix
3994      * becomes upper diagonal:
3995      * <pre>
3996      *     Mm = [sx    mxy  mxz]
3997      *          [0     sy   myz]
3998      *          [0     0    sz ]
3999      * </pre>
4000      * Values of this matrix are unit-less.
4001      *
4002      * @return estimated magnetometer soft-iron scale factors and cross coupling errors,
4003      * or null if not available.
4004      */
4005     @Override
4006     public Matrix getEstimatedMm() {
4007         return estimatedMm;
4008     }
4009 
4010     /**
4011      * Gets estimated x-axis scale factor.
4012      *
4013      * @return estimated x-axis scale factor or null if not available.
4014      */
4015     @Override
4016     public Double getEstimatedSx() {
4017         return estimatedMm != null ? estimatedMm.getElementAt(0, 0) : null;
4018     }
4019 
4020     /**
4021      * Gets estimated y-axis scale factor.
4022      *
4023      * @return estimated y-axis scale factor or null if not available.
4024      */
4025     @Override
4026     public Double getEstimatedSy() {
4027         return estimatedMm != null ? estimatedMm.getElementAt(1, 1) : null;
4028     }
4029 
4030     /**
4031      * Gets estimated z-axis scale factor.
4032      *
4033      * @return estimated z-axis scale factor or null if not available.
4034      */
4035     @Override
4036     public Double getEstimatedSz() {
4037         return estimatedMm != null ? estimatedMm.getElementAt(2, 2) : null;
4038     }
4039 
4040     /**
4041      * Gets estimated x-y cross-coupling error.
4042      *
4043      * @return estimated x-y cross-coupling error or null if not available.
4044      */
4045     @Override
4046     public Double getEstimatedMxy() {
4047         return estimatedMm != null ? estimatedMm.getElementAt(0, 1) : null;
4048     }
4049 
4050     /**
4051      * Gets estimated x-z cross-coupling error.
4052      *
4053      * @return estimated x-z cross-coupling error or null if not available.
4054      */
4055     @Override
4056     public Double getEstimatedMxz() {
4057         return estimatedMm != null ? estimatedMm.getElementAt(0, 2) : null;
4058     }
4059 
4060     /**
4061      * Gets estimated y-x cross-coupling error.
4062      *
4063      * @return estimated y-x cross-coupling error or null if not available.
4064      */
4065     @Override
4066     public Double getEstimatedMyx() {
4067         return estimatedMm != null ? estimatedMm.getElementAt(1, 0) : null;
4068     }
4069 
4070     /**
4071      * Gets estimated y-z cross-coupling error.
4072      *
4073      * @return estimated y-z cross-coupling error or null if not available.
4074      */
4075     @Override
4076     public Double getEstimatedMyz() {
4077         return estimatedMm != null ? estimatedMm.getElementAt(1, 2) : null;
4078     }
4079 
4080     /**
4081      * Gets estimated z-x cross-coupling error.
4082      *
4083      * @return estimated z-x cross-coupling error or null if not available.
4084      */
4085     @Override
4086     public Double getEstimatedMzx() {
4087         return estimatedMm != null ? estimatedMm.getElementAt(2, 0) : null;
4088     }
4089 
4090     /**
4091      * Gets estimated z-y cross-coupling error.
4092      *
4093      * @return estimated z-y cross-coupling error or null if not available.
4094      */
4095     @Override
4096     public Double getEstimatedMzy() {
4097         return estimatedMm != null ? estimatedMm.getElementAt(2, 1) : null;
4098     }
4099 
4100     /**
4101      * Gets estimated covariance matrix for estimated calibration parameters.
4102      * Diagonal elements of the matrix contains variance for the following
4103      * parameters (following indicated order): bx, by, bz, sx, sy, sz,
4104      * mxy, mxz, myx, myz, mzx, mzy.
4105      *
4106      * @return estimated covariance matrix for estimated calibration parameters.
4107      */
4108     @Override
4109     public Matrix getEstimatedCovariance() {
4110         return estimatedCovariance;
4111     }
4112 
4113     /**
4114      * Gets estimated chi square value.
4115      *
4116      * @return estimated chi square value.
4117      */
4118     @Override
4119     public double getEstimatedChiSq() {
4120         return estimatedChiSq;
4121     }
4122 
4123     /**
4124      * Gets estimated chi square degrees of freedom. Degrees of freedom is equal to the number of sampled data minus the
4125      * number of estimated parameters.
4126      *
4127      * @return estimated degrees of freedom of chi square value
4128      */
4129     @Override
4130     public int getEstimatedChiSqDegreesOfFreedom() {
4131         return estimatedChiSqDegreesOfFreedom;
4132     }
4133 
4134     /**
4135      * Gets estimated reduced chi square value. This is equal to estimated chi square value divided by its degrees of
4136      * freedom. Ideally this value should be close to 1.0, indicating that fit is optimal.
4137      * A value larger than 1.0 indicates that fit is not good or noise has been underestimated, and a value smaller than
4138      * 1.0 indicates that there is overfitting or noise has been overestimated.
4139      *
4140      * @return estimated reduced chi square value
4141      */
4142     @Override
4143     public double getEstimatedReducedChiSq() {
4144         return estimatedReducedChiSq;
4145     }
4146 
4147     /**
4148      * Gets estimated mean square error respect to provided measurements.
4149      *
4150      * @return estimated mean square error respect to provided measurements.
4151      */
4152     @Override
4153     public double getEstimatedMse() {
4154         return estimatedMse;
4155     }
4156 
4157     /**
4158      * Gets estimated probability of finding a smaller chi square value expressed as a value between 0.0 and 1.0. The
4159      * smaller the found chi square value is, the better the fit of the estimated parameters to the actual parameter.
4160      * Thus, the smaller the chance of finding a smaller chi square value, then the better the estimated fit is.
4161      *
4162      * @return estimated probability of finding a smaller chi square value.
4163      */
4164     @Override
4165     public double getEstimatedP() {
4166         return estimatedP;
4167     }
4168 
4169     /**
4170      * Gets estimated measure of quality of estimated fit as a value between 0.0 and 1.0. The larger the quality value
4171      * is, the better the fit that has been estimated.
4172      *
4173      * @return estimated measure of quality of estimated fit.
4174      */
4175     @Override
4176     public double getEstimatedQ() {
4177         return estimatedQ;
4178     }
4179 
4180     /**
4181      * Gets variance of estimated x coordinate of magnetometer bias expressed in
4182      * squared Teslas (T^2).
4183      *
4184      * @return variance of estimated x coordinate of magnetometer bias or null if
4185      * not available.
4186      */
4187     public Double getEstimatedHardIronXVariance() {
4188         return estimatedCovariance != null ? estimatedCovariance.getElementAt(0, 0) : null;
4189     }
4190 
4191     /**
4192      * Gets standard deviation of estimated x coordinate of magnetometer bias
4193      * expressed in Teslas (T).
4194      *
4195      * @return standard deviation of estimated x coordinate of magnetometer bias
4196      * or null if not available.
4197      */
4198     public Double getEstimatedHardIronXStandardDeviation() {
4199         final var variance = getEstimatedHardIronXVariance();
4200         return variance != null ? Math.sqrt(variance) : null;
4201     }
4202 
4203     /**
4204      * Gets standard deviation of estimated x coordinate of magnetometer bias.
4205      *
4206      * @return standard deviation of estimated x coordinate of magnetometer bias
4207      * or null if not available.
4208      */
4209     public MagneticFluxDensity getEstimatedHardIronXStandardDeviationAsMagneticFluxDensity() {
4210         return estimatedCovariance != null
4211                 ? new MagneticFluxDensity(getEstimatedHardIronXStandardDeviation(), MagneticFluxDensityUnit.TESLA)
4212                 : null;
4213     }
4214 
4215     /**
4216      * Gets standard deviation of estimated x coordinate of magnetometer bias.
4217      *
4218      * @param result instance where result will be stored.
4219      * @return true if standard deviation of estimated x coordinate of
4220      * magnetometer bias is available, false otherwise.
4221      */
4222     public boolean getEstimatedHardIronXStandardDeviationAsMagneticFluxDensity(final MagneticFluxDensity result) {
4223         if (estimatedCovariance != null) {
4224             result.setValue(getEstimatedHardIronXStandardDeviation());
4225             result.setUnit(MagneticFluxDensityUnit.TESLA);
4226             return true;
4227         } else {
4228             return false;
4229         }
4230     }
4231 
4232     /**
4233      * Gets variance of estimated y coordinate of magnetometer bias expressed in
4234      * squared Teslas (T^2).
4235      *
4236      * @return variance of estimated y coordinate of magnetometer bias or null if
4237      * not available.
4238      */
4239     public Double getEstimatedHardIronYVariance() {
4240         return estimatedCovariance != null ? estimatedCovariance.getElementAt(1, 1) : null;
4241     }
4242 
4243     /**
4244      * Gets standard deviation of estimated y coordinate of magnetometer bias
4245      * expressed in Teslas (T).
4246      *
4247      * @return standard deviation of estimated y coordinate of magnetometer bias
4248      * or null if not available.
4249      */
4250     public Double getEstimatedHardIronYStandardDeviation() {
4251         final var variance = getEstimatedHardIronYVariance();
4252         return variance != null ? Math.sqrt(variance) : null;
4253     }
4254 
4255     /**
4256      * Gets standard deviation of estimated y coordinate of magnetometer bias.
4257      *
4258      * @return standard deviation of estimated y coordinate of magnetometer bias
4259      * or null if not available.
4260      */
4261     public MagneticFluxDensity getEstimatedHardIronYStandardDeviationAsMagneticFluxDensity() {
4262         return estimatedCovariance != null
4263                 ? new MagneticFluxDensity(getEstimatedHardIronYStandardDeviation(), MagneticFluxDensityUnit.TESLA)
4264                 : null;
4265     }
4266 
4267     /**
4268      * Gets standard deviation of estimated y coordinate of magnetometer bias.
4269      *
4270      * @param result instance where result will be stored.
4271      * @return true if standard deviation of estimated y coordinate of
4272      * magnetometer bias is available, false otherwise.
4273      */
4274     public boolean getEstimatedHardIronYStandardDeviationAsMagneticFluxDensity(final MagneticFluxDensity result) {
4275         if (estimatedCovariance != null) {
4276             result.setValue(getEstimatedHardIronYStandardDeviation());
4277             result.setUnit(MagneticFluxDensityUnit.TESLA);
4278             return true;
4279         } else {
4280             return false;
4281         }
4282     }
4283 
4284     /**
4285      * Gets variance of estimated z coordinate of magnetometer bias expressed in
4286      * squared Teslas (T^2).
4287      *
4288      * @return variance of estimated z coordinate of magnetometer bias or null if
4289      * not available.
4290      */
4291     public Double getEstimatedHardIronZVariance() {
4292         return estimatedCovariance != null ? estimatedCovariance.getElementAt(2, 2) : null;
4293     }
4294 
4295     /**
4296      * Gets standard deviation of estimated z coordinate of magnetometer bias
4297      * expressed in Teslas (T).
4298      *
4299      * @return standard deviation of estimated z coordinate of magnetometer bias
4300      * or null if not available.
4301      */
4302     public Double getEstimatedHardIronZStandardDeviation() {
4303         final var variance = getEstimatedHardIronZVariance();
4304         return variance != null ? Math.sqrt(variance) : null;
4305     }
4306 
4307     /**
4308      * Gets standard deviation of estimated z coordinate of magnetometer bias.
4309      *
4310      * @return standard deviation of estimated z coordinate of magnetometer bias
4311      * or null if not available.
4312      */
4313     public MagneticFluxDensity getEstimatedHardIronZStandardDeviationAsMagneticFluxDensity() {
4314         return estimatedCovariance != null
4315                 ? new MagneticFluxDensity(getEstimatedHardIronZStandardDeviation(), MagneticFluxDensityUnit.TESLA)
4316                 : null;
4317     }
4318 
4319     /**
4320      * Gets standard deviation of estimated z coordinate of magnetometer bias.
4321      *
4322      * @param result instance where result will be stored.
4323      * @return true if standard deviation of estimated z coordinate of
4324      * magnetometer bias is available, false otherwise.
4325      */
4326     public boolean getEstimatedHardIronZStandardDeviationAsMagneticFluxDensity(final MagneticFluxDensity result) {
4327         if (estimatedCovariance != null) {
4328             result.setValue(getEstimatedHardIronZStandardDeviation());
4329             result.setUnit(MagneticFluxDensityUnit.TESLA);
4330             return true;
4331         } else {
4332             return false;
4333         }
4334     }
4335 
4336     /**
4337      * Gets standard deviation of estimated magnetometer bias coordinates.
4338      *
4339      * @return standard deviation of estimated magnetometer bias coordinates.
4340      */
4341     public MagneticFluxDensityTriad getEstimatedHardIronStandardDeviation() {
4342         return estimatedCovariance != null
4343                 ? new MagneticFluxDensityTriad(MagneticFluxDensityUnit.TESLA,
4344                 getEstimatedHardIronXStandardDeviation(),
4345                 getEstimatedHardIronYStandardDeviation(),
4346                 getEstimatedHardIronZStandardDeviation())
4347                 : null;
4348     }
4349 
4350     /**
4351      * Gets standard deviation of estimated magnetometer bias coordinates.
4352      *
4353      * @param result instance where result will be stored.
4354      * @return true if standard deviation of magnetometer bias was available,
4355      * false otherwise.
4356      */
4357     public boolean getEstimatedHardIronStandardDeviation(final MagneticFluxDensityTriad result) {
4358         if (estimatedCovariance != null) {
4359             result.setValueCoordinatesAndUnit(
4360                     getEstimatedHardIronXStandardDeviation(),
4361                     getEstimatedHardIronYStandardDeviation(),
4362                     getEstimatedHardIronZStandardDeviation(),
4363                     MagneticFluxDensityUnit.TESLA);
4364             return true;
4365         } else {
4366             return false;
4367         }
4368     }
4369 
4370     /**
4371      * Gets average of estimated standard deviation of magnetometer bias coordinates
4372      * expressed in Teslas (T).
4373      *
4374      * @return average of estimated standard deviation of magnetometer bias coordinates,
4375      * or null if not available.
4376      */
4377     public Double getEstimatedHardIronStandardDeviationAverage() {
4378         return estimatedCovariance != null
4379                 ? (getEstimatedHardIronXStandardDeviation() + getEstimatedHardIronYStandardDeviation()
4380                 + getEstimatedHardIronZStandardDeviation()) / 3.0 : null;
4381     }
4382 
4383     /**
4384      * Gets average of estimated standard deviation of magnetometer bias coordinates.
4385      *
4386      * @return average of estimated standard deviation of magnetometer bias coordinates,
4387      * or null if not available.
4388      */
4389     public MagneticFluxDensity getEstimatedHardIronStandardDeviationAverageAsMagneticFluxDensity() {
4390         return estimatedCovariance != null
4391                 ? new MagneticFluxDensity(getEstimatedHardIronStandardDeviationAverage(), MagneticFluxDensityUnit.TESLA)
4392                 : null;
4393     }
4394 
4395     /**
4396      * Gets average of estimated standard deviation of magnetometer bias coordinates.
4397      *
4398      * @param result instance where result will be stored.
4399      * @return true if average of estimated standard deviation of magnetometer bias is available,
4400      * false otherwise.
4401      */
4402     public boolean getEstimatedHardIronStandardDeviationAverageAsMagneticFluxDensity(final MagneticFluxDensity result) {
4403         if (estimatedCovariance != null) {
4404             result.setValue(getEstimatedHardIronStandardDeviationAverage());
4405             result.setUnit(MagneticFluxDensityUnit.TESLA);
4406             return true;
4407         } else {
4408             return false;
4409         }
4410     }
4411 
4412     /**
4413      * Gets norm of estimated standard deviation of magnetometer bias expressed in
4414      * Teslas (T).
4415      *
4416      * @return norm of estimated standard deviation of magnetometer bias or null
4417      * if not available.
4418      */
4419     public Double getEstimatedHardIronStandardDeviationNorm() {
4420         return estimatedCovariance != null
4421                 ? Math.sqrt(getEstimatedHardIronXVariance() + getEstimatedHardIronYVariance()
4422                 + getEstimatedHardIronZVariance())
4423                 : null;
4424     }
4425 
4426     /**
4427      * Gets norm of estimated standard deviation of magnetometer bias.
4428      *
4429      * @return norm of estimated standard deviation of magnetometer bias or null
4430      * if not available.
4431      */
4432     public MagneticFluxDensity getEstimatedHardIronStandardDeviationNormAsMagneticFluxDensity() {
4433         return estimatedCovariance != null
4434                 ? new MagneticFluxDensity(getEstimatedHardIronStandardDeviationNorm(), MagneticFluxDensityUnit.TESLA)
4435                 : null;
4436     }
4437 
4438     /**
4439      * Gets norm of estimated standard deviation of magnetometer bias.
4440      *
4441      * @param result instance where result will be stored.
4442      * @return true if norm of estimated standard deviation of magnetometer bias
4443      * is available, false otherwise.
4444      */
4445     public boolean getEstimatedHardIronStandardDeviationNormAsMagneticFluxDensity(final MagneticFluxDensity result) {
4446         if (estimatedCovariance != null) {
4447             result.setValue(getEstimatedHardIronStandardDeviationNorm());
4448             result.setUnit(MagneticFluxDensityUnit.TESLA);
4449             return true;
4450         } else {
4451             return false;
4452         }
4453     }
4454 
4455     /**
4456      * Internal method to perform calibration when common z-axis is assumed for both
4457      * the accelerometer and gyroscope.
4458      *
4459      * @throws AlgebraException                         if there are numerical errors.
4460      * @throws FittingException                         if no convergence to solution is found.
4461      * @throws com.irurueta.numerical.NotReadyException if fitter is not ready.
4462      * @throws IOException                              if world magnetic model cannot be loaded.
4463      */
4464     private void calibrateCommonAxis() throws AlgebraException, FittingException,
4465             com.irurueta.numerical.NotReadyException, IOException {
4466         // The accelerometer model is:
4467         // mBmeas = ba + (I + Ma) * mBtrue + w
4468 
4469         // Ideally a least squares solution tries to minimize noise component, so:
4470         // mBmeas = ba + (I + Ma) * mBtrue
4471 
4472         // Hence:
4473         // [mBmeasx] = [bx] + ( [1  0   0] + [sx    mxy mxz])   [mBtruex]
4474         // [mBmeasy] = [by]     [0  1   0]   [myx   sy  myz]    [mBtruey]
4475         // [mBmeasz] = [bz]     [0  0   1]   [mzx   mzy sz ]    [mBtruez]
4476 
4477         // where myx = mzx = mzy = 0
4478 
4479         // Hence:
4480         // [mBmeasx] = [bx] + ( [1  0   0] + [sx    mxy mxz])   [mBtruex]
4481         // [mBmeasy] = [by]     [0  1   0]   [0     sy  myz]    [mBtruey]
4482         // [mBmeasz] = [bz]     [0  0   1]   [0     0   sz ]    [mBtruez]
4483 
4484         // [mBmeasx] = [bx] +   [1+sx   mxy     mxz ][mBtruex]
4485         // [mBmeasy]   [by]     [0      1+sy    myz ][mBtruey]
4486         // [mBmeasz]   [bz]     [0      0       1+sz][mBtruez]
4487 
4488         // mBmeasx = bx + (1+sx) * mBtruex + mxy * mBtruey + mxz * mBtruez
4489         // mBmeasy = by + (1+sy) * mBtruey + myz * mBtruez
4490         // mBmeasz = bz + (1+sz) * mBtruez
4491 
4492         // Where the unknowns are: bx, by, bz, sx, sy, sz, mxy mxz, myz
4493         // Reordering:
4494         // mBmeasx = bx + mBtruex + sx * mBtruex + mxy * mBtruey + mxz * mBtruez
4495         // mBmeasy = by + mBtruey + sy * mBtruey + myz * mBtruez
4496         // mBmeasz = bz + mBtruez + sz * mBtruez
4497 
4498         // mBmeasx - mBtruex = bx + sx * mBtruex + mxy * mBtruey + mxz * mBtruez
4499         // mBmeasy - mBtruey = by + sy * mBtruey + myz * mBtruez
4500         // mBmeasz - mBtruez = bz + sz * mBtruez
4501 
4502         // [1   0   0   mBtruex  0        0        mBtruey  mBtruez  0      ][bx ] = [mBmeasx - mBtruex]
4503         // [0   1   0   0        mBtruey  0        0        0        mBtruez][by ]   [mBmeasy - mBtruey]
4504         // [0   0   1   0        0        mBtruez  0        0        0      ][bz ]   [mBmeasz - mBtruez]
4505         //                                                                   [sx ]
4506         //                                                                   [sy ]
4507         //                                                                   [sz ]
4508         //                                                                   [mxy]
4509         //                                                                   [mxz]
4510         //                                                                   [myz]
4511 
4512         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiVariateFunctionEvaluator() {
4513             @Override
4514             public int getNumberOfDimensions() {
4515                 // Input points are true magnetic flux density coordinates
4516                 return BodyMagneticFluxDensity.COMPONENTS;
4517             }
4518 
4519             @Override
4520             public int getNumberOfVariables() {
4521                 // The multivariate function returns the components of measured magnetic flux density
4522                 return BodyMagneticFluxDensity.COMPONENTS;
4523             }
4524 
4525             @Override
4526             public double[] createInitialParametersArray() {
4527                 final var initial = new double[COMMON_Z_AXIS_UNKNOWNS];
4528 
4529                 initial[0] = initialHardIronX;
4530                 initial[1] = initialHardIronY;
4531                 initial[2] = initialHardIronZ;
4532 
4533                 initial[3] = initialSx;
4534                 initial[4] = initialSy;
4535                 initial[5] = initialSz;
4536 
4537                 initial[6] = initialMxy;
4538                 initial[7] = initialMxz;
4539                 initial[8] = initialMyz;
4540 
4541                 return initial;
4542             }
4543 
4544             @Override
4545             public void evaluate(
4546                     final int i, final double[] point, final double[] result, final double[] params,
4547                     final Matrix jacobian) {
4548                 // We know that:
4549                 // mBmeasx = bx + mBtruex + sx * mBtruex + mxy * mBtruey + mxz * mBtruez
4550                 // mBmeasy = by + mBtruey + sy * mBtruey + myz * mBtruez
4551                 // mBmeasz = bz + mBtruez + sz * mBtruez
4552 
4553                 // Hence, the derivatives respect the parameters bx, by, bz, sx, sy,
4554                 // sz, mxy, mxz, myz
4555 
4556                 // d(fmeasx)/d(bx) = 1.0
4557                 // d(fmeasx)/d(by) = 0.0
4558                 // d(fmeasx)/d(bz) = 0.0
4559                 // d(fmeasx)/d(sx) = mBtruex
4560                 // d(fmeasx)/d(sy) = 0.0
4561                 // d(fmeasx)/d(sz) = 0.0
4562                 // d(fmeasx)/d(mxy) = mBtruey
4563                 // d(fmeasx)/d(mxz) = mBtruez
4564                 // d(fmeasx)/d(myz) = 0.0
4565 
4566                 // d(fmeasy)/d(bx) = 0.0
4567                 // d(fmeasy)/d(by) = 1.0
4568                 // d(fmeasy)/d(bz) = 0.0
4569                 // d(fmeasy)/d(sx) = 0.0
4570                 // d(fmeasy)/d(sy) = mBtruey
4571                 // d(fmeasy)/d(sz) = 0.0
4572                 // d(fmeasy)/d(mxy) = 0.0
4573                 // d(fmeasy)/d(mxz) = 0.0
4574                 // d(fmeasy)/d(myz) = mBtruez
4575 
4576                 // d(fmeasz)/d(bx) = 0.0
4577                 // d(fmeasz)/d(by) = 0.0
4578                 // d(fmeasz)/d(bz) = 1.0
4579                 // d(fmeasz)/d(sx) = 0.0
4580                 // d(fmeasz)/d(sy) = 0.0
4581                 // d(fmeasz)/d(sz) = mBtruez
4582                 // d(fmeasz)/d(mxy) = 0.0
4583                 // d(fmeasz)/d(mxz) = 0.0
4584                 // d(fmeasz)/d(myz) = 0.0
4585 
4586                 final var bx = params[0];
4587                 final var by = params[1];
4588                 final var bz = params[2];
4589 
4590                 final var sx = params[3];
4591                 final var sy = params[4];
4592                 final var sz = params[5];
4593 
4594                 final var mxy = params[6];
4595                 final var mxz = params[7];
4596                 final var myz = params[8];
4597 
4598                 final var btruex = point[0];
4599                 final var btruey = point[1];
4600                 final var btruez = point[2];
4601 
4602                 result[0] = bx + btruex + sx * btruex + mxy * btruey + mxz * btruez;
4603                 result[1] = by + btruey + sy * btruey + myz * btruez;
4604                 result[2] = bz + btruez + sz * btruez;
4605 
4606                 jacobian.setElementAt(0, 0, 1.0);
4607                 jacobian.setElementAt(0, 1, 0.0);
4608                 jacobian.setElementAt(0, 2, 0.0);
4609                 jacobian.setElementAt(0, 3, btruex);
4610                 jacobian.setElementAt(0, 4, 0.0);
4611                 jacobian.setElementAt(0, 5, 0.0);
4612                 jacobian.setElementAt(0, 6, btruey);
4613                 jacobian.setElementAt(0, 7, btruez);
4614                 jacobian.setElementAt(0, 8, 0.0);
4615 
4616                 jacobian.setElementAt(1, 0, 0.0);
4617                 jacobian.setElementAt(1, 1, 1.0);
4618                 jacobian.setElementAt(1, 2, 0.0);
4619                 jacobian.setElementAt(1, 3, 0.0);
4620                 jacobian.setElementAt(1, 4, btruey);
4621                 jacobian.setElementAt(1, 5, 0.0);
4622                 jacobian.setElementAt(1, 6, 0.0);
4623                 jacobian.setElementAt(1, 7, 0.0);
4624                 jacobian.setElementAt(1, 8, btruez);
4625 
4626                 jacobian.setElementAt(2, 0, 0.0);
4627                 jacobian.setElementAt(2, 1, 0.0);
4628                 jacobian.setElementAt(2, 2, 1.0);
4629                 jacobian.setElementAt(2, 3, 0.0);
4630                 jacobian.setElementAt(2, 4, 0.0);
4631                 jacobian.setElementAt(2, 5, btruez);
4632                 jacobian.setElementAt(2, 6, 0.0);
4633                 jacobian.setElementAt(2, 7, 0.0);
4634                 jacobian.setElementAt(2, 8, 0.0);
4635             }
4636         });
4637 
4638         setInputData();
4639 
4640         fitter.fit();
4641 
4642         final var result = fitter.getA();
4643 
4644         final var bx = result[0];
4645         final var by = result[1];
4646         final var bz = result[2];
4647 
4648         final var sx = result[3];
4649         final var sy = result[4];
4650         final var sz = result[5];
4651 
4652         final var mxy = result[6];
4653         final var mxz = result[7];
4654         final var myz = result[8];
4655 
4656         if (estimatedHardIron == null) {
4657             estimatedHardIron = new double[BodyMagneticFluxDensity.COMPONENTS];
4658         }
4659 
4660         estimatedHardIron[0] = bx;
4661         estimatedHardIron[1] = by;
4662         estimatedHardIron[2] = bz;
4663 
4664         if (estimatedMm == null) {
4665             estimatedMm = new Matrix(BodyMagneticFluxDensity.COMPONENTS, BodyMagneticFluxDensity.COMPONENTS);
4666         } else {
4667             estimatedMm.initialize(0.0);
4668         }
4669 
4670         estimatedMm.setElementAt(0, 0, sx);
4671 
4672         estimatedMm.setElementAt(0, 1, mxy);
4673         estimatedMm.setElementAt(1, 1, sy);
4674 
4675         estimatedMm.setElementAt(0, 2, mxz);
4676         estimatedMm.setElementAt(1, 2, myz);
4677         estimatedMm.setElementAt(2, 2, sz);
4678 
4679         estimatedCovariance = fitter.getCovar();
4680 
4681         // propagate covariance matrix so that all parameters are taken into
4682         // account in the order: bx, by, bz, sx, sy, sz, mxy, mxz, myx,
4683         // myz, mzx, mzy.
4684 
4685         // We define a lineal function mapping original parameters for the common
4686         // axis case to the general case
4687         // [bx'] = [1  0  0  0  0  0  0  0  0][bx]
4688         // [by']   [0  1  0  0  0  0  0  0  0][by]
4689         // [bz']   [0  0  1  0  0  0  0  0  0][bz]
4690         // [sx']   [0  0  0  1  0  0  0  0  0][sx]
4691         // [sy']   [0  0  0  0  1  0  0  0  0][sy]
4692         // [sz']   [0  0  0  0  0  1  0  0  0][sz]
4693         // [mxy']  [0  0  0  0  0  0  1  0  0][mxy]
4694         // [mxz']  [0  0  0  0  0  0  0  1  0][mxz]
4695         // [myx']  [0  0  0  0  0  0  0  0  0][myz]
4696         // [myz']  [0  0  0  0  0  0  0  0  1]
4697         // [mzx']  [0  0  0  0  0  0  0  0  0]
4698         // [mzy']  [0  0  0  0  0  0  0  0  0]
4699 
4700         // As defined in com.irurueta.statistics.MultivariateNormalDist,
4701         // if we consider the jacobian of the lineal application the matrix shown
4702         // above, then covariance can be propagated as follows
4703         final var jacobian = Matrix.identity(GENERAL_UNKNOWNS, COMMON_Z_AXIS_UNKNOWNS);
4704         jacobian.setElementAt(8, 8, 0.0);
4705         jacobian.setElementAt(9, 8, 1.0);
4706         // propagated covariance is J * Cov * J'
4707         final var jacobianTrans = jacobian.transposeAndReturnNew();
4708         jacobian.multiply(estimatedCovariance);
4709         jacobian.multiply(jacobianTrans);
4710         estimatedCovariance = jacobian;
4711         estimatedChiSq = fitter.getChisq();
4712         estimatedChiSqDegreesOfFreedom = fitter.getChisqDegreesOfFreedom();
4713         estimatedReducedChiSq = fitter.getReducedChisq();
4714         estimatedMse = fitter.getMse();
4715         try {
4716             estimatedP = fitter.getP();
4717             estimatedQ = fitter.getQ();
4718         } catch (final MaxIterationsExceededException ignore) {
4719             // if numerical instabilities arise, we assume worst case (no fit at all)
4720             // probability of finding a smaller chi square value is 1.0
4721             // quality of fit is 0.0
4722             estimatedP = 1.0;
4723             estimatedQ = 0.0;
4724         }
4725     }
4726 
4727     /**
4728      * Internal method to perform general calibration.
4729      *
4730      * @throws AlgebraException                         if there are numerical errors.
4731      * @throws FittingException                         if no convergence to solution is found.
4732      * @throws com.irurueta.numerical.NotReadyException if fitter is not ready.
4733      * @throws IOException                              if world magnetic model cannot be loaded.
4734      */
4735     private void calibrateGeneral() throws AlgebraException, FittingException, com.irurueta.numerical.NotReadyException,
4736             IOException {
4737         // The magnetometer model is:
4738         // mBmeas = ba + (I + Mm) * mBtrue + w
4739 
4740         // Ideally a least squares solution tries to minimize noise component, so:
4741         // mBmeas = ba + (I + Mm) * mBtrue
4742 
4743         // Hence:
4744         // [mBmeasx] = [bx] + ( [1  0   0] + [sx    mxy mxz])   [mBtruex]
4745         // [mBmeasy] = [by]     [0  1   0]   [myx   sy  myz]    [mBtruey]
4746         // [mBmeasz] = [bz]     [0  0   1]   [mzx   mzy sz ]    [mBtruez]
4747 
4748         // [mBmeasx] = [bx] +   [1+sx   mxy     mxz ][mBtruex]
4749         // [mBmeasy]   [by]     [myx    1+sy    myz ][mBtruey]
4750         // [mBmeasz]   [bz]     [mzx    mzy     1+sz][mBtruez]
4751 
4752         // mBmeasx = bx + (1+sx) * mBtruex + mxy * mBtruey + mxz * mBtruez
4753         // mBmeasy = by + myx * mBtruex + (1+sy) * mBtruey + myz * mBtruez
4754         // mBmeasz = bz + mzx * mBtruex + mzy * mBtruey + (1+sz) * mBtruez
4755 
4756         // Where the unknowns are: bx, by, bz, sx, sy, sz, mxy mxz, myx, myz, mzx, mzy
4757         // Reordering:
4758         // mBmeasx = bx + mBtruex + sx * mBtruex + mxy * mBtruey + mxz * mBtruez
4759         // mBmeasy = by + myx * mBtruex + mBtruey + sy * mBtruey + myz * mBtruez
4760         // mBmeasz = bz + mzx * mBtruex + mzy * mBtruey + mBtruez + sz * mBtruez
4761 
4762         // mBmeasx - mBtruex = bx + sx * mBtruex + mxy * mBtruey + mxz * mBtruez
4763         // mBmeasy - mBtruey = by + myx * mBtruex + sy * mBtruey + myz * mBtruez
4764         // mBmeasz - mBtruez = bz + mzx * mBtruex + mzy * mBtruey + sz * mBtruez
4765 
4766         // [1   0   0   mBtruex  0        0        mBtruey  mBtruez  0        0        0        0      ][bx ] = [mBmeasx - mBtruex]
4767         // [0   1   0   0        mBtruey  0        0        0        mBtruex  mBtruez  0        0      ][by ]   [mBmeasy - mBtruey]
4768         // [0   0   1   0        0        mBtruez  0        0        0        0        mBtruex  mBtruey][bz ]   [mBmeasz - mBtruez]
4769         //                                                                                              [sx ]
4770         //                                                                                              [sy ]
4771         //                                                                                              [sz ]
4772         //                                                                                              [mxy]
4773         //                                                                                              [mxz]
4774         //                                                                                              [myx]
4775         //                                                                                              [myz]
4776         //                                                                                              [mzx]
4777         //                                                                                              [mzy]
4778 
4779         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiVariateFunctionEvaluator() {
4780             @Override
4781             public int getNumberOfDimensions() {
4782                 // Input points are true magnetic flux density coordinates
4783                 return BodyMagneticFluxDensity.COMPONENTS;
4784             }
4785 
4786             @Override
4787             public int getNumberOfVariables() {
4788                 // The multivariate function returns the components of measured magnetic flux density
4789                 return BodyMagneticFluxDensity.COMPONENTS;
4790             }
4791 
4792             @Override
4793             public double[] createInitialParametersArray() {
4794                 final var initial = new double[GENERAL_UNKNOWNS];
4795 
4796                 initial[0] = initialHardIronX;
4797                 initial[1] = initialHardIronY;
4798                 initial[2] = initialHardIronZ;
4799 
4800                 initial[3] = initialSx;
4801                 initial[4] = initialSy;
4802                 initial[5] = initialSz;
4803 
4804                 initial[6] = initialMxy;
4805                 initial[7] = initialMxz;
4806                 initial[8] = initialMyx;
4807                 initial[9] = initialMyz;
4808                 initial[10] = initialMzx;
4809                 initial[11] = initialMzy;
4810 
4811                 return initial;
4812             }
4813 
4814             @Override
4815             public void evaluate(
4816                     final int i, final double[] point, final double[] result, final double[] params,
4817                     final Matrix jacobian) {
4818                 // We know that:
4819                 // mBmeasx = bx + mBtruex + sx * mBtruex + mxy * mBtruey + mxz * mBtruez
4820                 // mBmeasy = by + myx * mBtruex + mBtruey + sy * mBtruey + myz * mBtruez
4821                 // mBmeasz = bz + mzx * mBtruex + mzy * mBtruey + mBtruez + sz * mBtruez
4822 
4823                 // Hence, the derivatives respect the parameters bx, by, bz, sx, sy,
4824                 // sz, mxy, mxz, myx, myz, mzx and mzy is:
4825 
4826                 // d(fmeasx)/d(bx) = 1.0
4827                 // d(fmeasx)/d(by) = 0.0
4828                 // d(fmeasx)/d(bz) = 0.0
4829                 // d(fmeasx)/d(sx) = mBtruex
4830                 // d(fmeasx)/d(sy) = 0.0
4831                 // d(fmeasx)/d(sz) = 0.0
4832                 // d(fmeasx)/d(mxy) = mBtruey
4833                 // d(fmeasx)/d(mxz) = mBtruez
4834                 // d(fmeasx)/d(myx) = 0.0
4835                 // d(fmeasx)/d(myz) = 0.0
4836                 // d(fmeasx)/d(mzx) = 0.0
4837                 // d(fmeasx)/d(mzy) = 0.0
4838 
4839                 // d(fmeasy)/d(bx) = 0.0
4840                 // d(fmeasy)/d(by) = 1.0
4841                 // d(fmeasy)/d(bz) = 0.0
4842                 // d(fmeasy)/d(sx) = 0.0
4843                 // d(fmeasy)/d(sy) = mBtruey
4844                 // d(fmeasy)/d(sz) = 0.0
4845                 // d(fmeasy)/d(mxy) = 0.0
4846                 // d(fmeasy)/d(mxz) = 0.0
4847                 // d(fmeasy)/d(myx) = mBtruex
4848                 // d(fmeasy)/d(myz) = mBtruez
4849                 // d(fmeasy)/d(mzx) = 0.0
4850                 // d(fmeasy)/d(mzy) = 0.0
4851 
4852                 // d(fmeasz)/d(bx) = 0.0
4853                 // d(fmeasz)/d(by) = 0.0
4854                 // d(fmeasz)/d(bz) = 1.0
4855                 // d(fmeasz)/d(sx) = 0.0
4856                 // d(fmeasz)/d(sy) = 0.0
4857                 // d(fmeasz)/d(sz) = mBtruez
4858                 // d(fmeasz)/d(mxy) = 0.0
4859                 // d(fmeasz)/d(mxz) = 0.0
4860                 // d(fmeasz)/d(myx) = 0.0
4861                 // d(fmeasz)/d(myz) = 0.0
4862                 // d(fmeasz)/d(mzx) = mBtruex
4863                 // d(fmeasz)/d(mzy) = mBtruey
4864 
4865                 final var bx = params[0];
4866                 final var by = params[1];
4867                 final var bz = params[2];
4868 
4869                 final var sx = params[3];
4870                 final var sy = params[4];
4871                 final var sz = params[5];
4872 
4873                 final var mxy = params[6];
4874                 final var mxz = params[7];
4875                 final var myx = params[8];
4876                 final var myz = params[9];
4877                 final var mzx = params[10];
4878                 final var mzy = params[11];
4879 
4880                 final var btruex = point[0];
4881                 final var btruey = point[1];
4882                 final var btruez = point[2];
4883 
4884                 result[0] = bx + btruex + sx * btruex + mxy * btruey + mxz * btruez;
4885                 result[1] = by + myx * btruex + btruey + sy * btruey + myz * btruez;
4886                 result[2] = bz + mzx * btruex + mzy * btruey + btruez + sz * btruez;
4887 
4888                 jacobian.setElementAt(0, 0, 1.0);
4889                 jacobian.setElementAt(0, 1, 0.0);
4890                 jacobian.setElementAt(0, 2, 0.0);
4891                 jacobian.setElementAt(0, 3, btruex);
4892                 jacobian.setElementAt(0, 4, 0.0);
4893                 jacobian.setElementAt(0, 5, 0.0);
4894                 jacobian.setElementAt(0, 6, btruey);
4895                 jacobian.setElementAt(0, 7, btruez);
4896                 jacobian.setElementAt(0, 8, 0.0);
4897                 jacobian.setElementAt(0, 9, 0.0);
4898                 jacobian.setElementAt(0, 10, 0.0);
4899                 jacobian.setElementAt(0, 11, 0.0);
4900 
4901                 jacobian.setElementAt(1, 0, 0.0);
4902                 jacobian.setElementAt(1, 1, 1.0);
4903                 jacobian.setElementAt(1, 2, 0.0);
4904                 jacobian.setElementAt(1, 3, 0.0);
4905                 jacobian.setElementAt(1, 4, btruey);
4906                 jacobian.setElementAt(1, 5, 0.0);
4907                 jacobian.setElementAt(1, 6, 0.0);
4908                 jacobian.setElementAt(1, 7, 0.0);
4909                 jacobian.setElementAt(1, 8, btruex);
4910                 jacobian.setElementAt(1, 9, btruez);
4911                 jacobian.setElementAt(1, 10, 0.0);
4912                 jacobian.setElementAt(1, 11, 0.0);
4913 
4914                 jacobian.setElementAt(2, 0, 0.0);
4915                 jacobian.setElementAt(2, 1, 0.0);
4916                 jacobian.setElementAt(2, 2, 1.0);
4917                 jacobian.setElementAt(2, 3, 0.0);
4918                 jacobian.setElementAt(2, 4, 0.0);
4919                 jacobian.setElementAt(2, 5, btruez);
4920                 jacobian.setElementAt(2, 6, 0.0);
4921                 jacobian.setElementAt(2, 7, 0.0);
4922                 jacobian.setElementAt(2, 8, 0.0);
4923                 jacobian.setElementAt(2, 9, 0.0);
4924                 jacobian.setElementAt(2, 10, btruex);
4925                 jacobian.setElementAt(2, 11, btruey);
4926             }
4927         });
4928 
4929         setInputData();
4930 
4931         fitter.fit();
4932 
4933         final var result = fitter.getA();
4934 
4935         final var bx = result[0];
4936         final var by = result[1];
4937         final var bz = result[2];
4938 
4939         final var sx = result[3];
4940         final var sy = result[4];
4941         final var sz = result[5];
4942 
4943         final var mxy = result[6];
4944         final var mxz = result[7];
4945         final var myx = result[8];
4946         final var myz = result[9];
4947         final var mzx = result[10];
4948         final var mzy = result[11];
4949 
4950         if (estimatedHardIron == null) {
4951             estimatedHardIron = new double[BodyMagneticFluxDensity.COMPONENTS];
4952         }
4953 
4954         estimatedHardIron[0] = bx;
4955         estimatedHardIron[1] = by;
4956         estimatedHardIron[2] = bz;
4957 
4958         if (estimatedMm == null) {
4959             estimatedMm = new Matrix(BodyMagneticFluxDensity.COMPONENTS, BodyMagneticFluxDensity.COMPONENTS);
4960         } else {
4961             estimatedMm.initialize(0.0);
4962         }
4963 
4964         estimatedMm.setElementAt(0, 0, sx);
4965         estimatedMm.setElementAt(1, 0, myx);
4966         estimatedMm.setElementAt(2, 0, mzx);
4967 
4968         estimatedMm.setElementAt(0, 1, mxy);
4969         estimatedMm.setElementAt(1, 1, sy);
4970         estimatedMm.setElementAt(2, 1, mzy);
4971 
4972         estimatedMm.setElementAt(0, 2, mxz);
4973         estimatedMm.setElementAt(1, 2, myz);
4974         estimatedMm.setElementAt(2, 2, sz);
4975 
4976         estimatedCovariance = fitter.getCovar();
4977         estimatedChiSq = fitter.getChisq();
4978         estimatedChiSqDegreesOfFreedom = fitter.getChisqDegreesOfFreedom();
4979         estimatedReducedChiSq = fitter.getReducedChisq();
4980         estimatedMse = fitter.getMse();
4981         try {
4982             estimatedP = fitter.getP();
4983             estimatedQ = fitter.getQ();
4984         } catch (final MaxIterationsExceededException ignore) {
4985             // if numerical instabilities arise, we assume worst case (no fit at all)
4986             // probability of finding a smaller chi square value is 1.0
4987             // quality of fit is 0.0
4988             estimatedP = 1.0;
4989             estimatedQ = 0.0;
4990         }
4991     }
4992 
4993     /**
4994      * Sets input data into Levenberg-Marquardt fitter.
4995      *
4996      * @throws WrongSizeException never happens.
4997      * @throws IOException        if world magnetic model cannot be loaded.
4998      */
4999     private void setInputData() throws WrongSizeException, IOException {
5000         // set input data using:
5001         // mBmeasx = bx + mBtruex + sx * mBtruex + mxy * mBtruey + mxz * mBtruez
5002         // mBmeasy = by + myx * mBtruex + mBtruey + sy * mBtruey + myz * mBtruez
5003         // mBmeasz = bz + mzx * mBtruex + mzy * mBtruey + mBtruez + sz * mBtruez
5004 
5005         final WMMEarthMagneticFluxDensityEstimator wmmEstimator;
5006         if (magneticModel != null) {
5007             wmmEstimator = new WMMEarthMagneticFluxDensityEstimator(magneticModel);
5008         } else {
5009             wmmEstimator = new WMMEarthMagneticFluxDensityEstimator();
5010         }
5011 
5012         final var expectedMagneticFluxDensity = new BodyMagneticFluxDensity();
5013         final var nedFrame = new NEDFrame();
5014         final var earthB = new NEDMagneticFluxDensity();
5015         final var cbn = new CoordinateTransformation(FrameType.BODY_FRAME, FrameType.LOCAL_NAVIGATION_FRAME);
5016         final var cnb = new CoordinateTransformation(FrameType.LOCAL_NAVIGATION_FRAME, FrameType.BODY_FRAME);
5017 
5018         final var numMeasurements = measurements.size();
5019         final var x = new Matrix(numMeasurements, BodyMagneticFluxDensity.COMPONENTS);
5020         final var y = new Matrix(numMeasurements, BodyMagneticFluxDensity.COMPONENTS);
5021         final var specificForceStandardDeviations = new double[numMeasurements];
5022         var i = 0;
5023         for (final var measurement : measurements) {
5024             final var measuredMagneticFluxDensity = measurement.getMagneticFluxDensity();
5025 
5026             // estimate Earth magnetic flux density at frame position and
5027             // timestamp using WMM
5028             final var ecefFrame = measurement.getFrame();
5029             ECEFtoNEDFrameConverter.convertECEFtoNED(ecefFrame, nedFrame);
5030 
5031             final var year = measurement.getYear();
5032 
5033             final var latitude = nedFrame.getLatitude();
5034             final var longitude = nedFrame.getLongitude();
5035             final var height = nedFrame.getHeight();
5036 
5037             nedFrame.getCoordinateTransformation(cbn);
5038             cbn.inverse(cnb);
5039 
5040             wmmEstimator.estimate(latitude, longitude, height, year, earthB);
5041 
5042             // estimate expected body magnetic flux density taking into
5043             // account body attitude (inverse of frame orientation) and
5044             // estimated Earth magnetic flux density
5045             BodyMagneticFluxDensityEstimator.estimate(earthB, cnb, expectedMagneticFluxDensity);
5046 
5047             final var bMeasX = measuredMagneticFluxDensity.getBx();
5048             final var bMeasY = measuredMagneticFluxDensity.getBy();
5049             final var bMeasZ = measuredMagneticFluxDensity.getBz();
5050 
5051             final var bTrueX = expectedMagneticFluxDensity.getBx();
5052             final var bTrueY = expectedMagneticFluxDensity.getBy();
5053             final var bTrueZ = expectedMagneticFluxDensity.getBz();
5054 
5055             x.setElementAt(i, 0, bTrueX);
5056             x.setElementAt(i, 1, bTrueY);
5057             x.setElementAt(i, 2, bTrueZ);
5058 
5059             y.setElementAt(i, 0, bMeasX);
5060             y.setElementAt(i, 1, bMeasY);
5061             y.setElementAt(i, 2, bMeasZ);
5062 
5063             specificForceStandardDeviations[i] = measurement.getMagneticFluxDensityStandardDeviation();
5064             i++;
5065         }
5066 
5067         fitter.setInputData(x, y, specificForceStandardDeviations);
5068     }
5069 
5070     /**
5071      * Converts magnetic flux density value and unit to Teslas.
5072      *
5073      * @param value magnetic flux density value.
5074      * @param unit  unit of magnetic flux density value.
5075      * @return converted value.
5076      */
5077     private static double convertMagneticFluxDensity(final double value, final MagneticFluxDensityUnit unit) {
5078         return MagneticFluxDensityConverter.convert(value, unit, MagneticFluxDensityUnit.TESLA);
5079     }
5080 
5081     /**
5082      * Converts magnetic flux density instance to Teslas.
5083      *
5084      * @param magneticFluxDensity magnetic flux density instance to be converted.
5085      * @return converted value.
5086      */
5087     private static double convertMagneticFluxDensity(final MagneticFluxDensity magneticFluxDensity) {
5088         return convertMagneticFluxDensity(magneticFluxDensity.getValue().doubleValue(), magneticFluxDensity.getUnit());
5089     }
5090 }