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