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