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