View Javadoc
1   /*
2    * Copyright (C) 2020 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.navigation.inertial.calibration.accelerometer;
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.StandardDeviationFrameBodyKinematics;
23  import com.irurueta.numerical.robust.LMedSRobustEstimator;
24  import com.irurueta.numerical.robust.LMedSRobustEstimatorListener;
25  import com.irurueta.numerical.robust.RobustEstimator;
26  import com.irurueta.numerical.robust.RobustEstimatorException;
27  import com.irurueta.numerical.robust.RobustEstimatorMethod;
28  import com.irurueta.units.Acceleration;
29  
30  import java.util.List;
31  
32  /**
33   * Robustly estimates accelerometer cross couplings and scaling factors using
34   * a LMedS algorithm to discard outliers.
35   * This estimator assumes that biases are known.
36   * <p>
37   * To use this calibrator at least 4 measurements at different known frames must
38   * be provided. In other words, accelerometer samples must be obtained at 4
39   * different positions, orientations and velocities (although typically velocities are
40   * always zero).
41   * <p>
42   * Measured specific force is assumed to follow the model shown below:
43   * <pre>
44   *     fmeas = ba + (I + Ma) * ftrue + w
45   * </pre>
46   * Where:
47   * - fmeas is the measured specific force. This is a 3x1 vector.
48   * - ba is accelerometer bias. Ideally, on a perfect accelerometer, this should be a
49   * 3x1 zero vector.
50   * - I is the 3x3 identity matrix.
51   * - Ma is the 3x3 matrix containing cross-couplings and scaling factors. Ideally, on
52   * a perfect accelerometer, this should be a 3x3 zero matrix.
53   * - ftrue is ground-truth specific force.
54   * - w is measurement noise.
55   */
56  public class LMedSRobustKnownBiasAndFrameAccelerometerCalibrator extends
57          RobustKnownBiasAndFrameAccelerometerCalibrator {
58  
59      /**
60       * Default value to be used for stop threshold. Stop threshold can be used to
61       * avoid keeping the algorithm unnecessarily iterating in case that best
62       * estimated threshold using median of residuals is not small enough. Once a
63       * solution is found that generates a threshold below this value, the
64       * algorithm will stop.
65       * The stop threshold can be used to prevent the LMedS algorithm iterating
66       * too many times in cases where samples have a very similar accuracy.
67       * For instance, in cases where proportion of outliers is very small (close
68       * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
69       * iterate for a long time trying to find the best solution when indeed
70       * there is no need to do that if a reasonable threshold has already been
71       * reached.
72       * Because of this behaviour the stop threshold can be set to a value much
73       * lower than the one typically used in RANSAC, and yet the algorithm could
74       * still produce even smaller thresholds in estimated results.
75       */
76      public static final double DEFAULT_STOP_THRESHOLD = 1e-5;
77  
78      /**
79       * Minimum allowed stop threshold value.
80       */
81      public static final double MIN_STOP_THRESHOLD = 0.0;
82  
83      /**
84       * Threshold to be used to keep the algorithm iterating in case that best
85       * estimated threshold using median of residuals is not small enough. Once
86       * a solution is found that generates a threshold below this value, the
87       * algorithm will stop.
88       * The stop threshold can be used to prevent the LMedS algorithm iterating
89       * too many times in cases where samples have a very similar accuracy.
90       * For instance, in cases where proportion of outliers is very small (close
91       * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
92       * iterate for a long time trying to find the best solution when indeed
93       * there is no need to do that if a reasonable threshold has already been
94       * reached.
95       * Because of this behaviour the stop threshold can be set to a value much
96       * lower than the one typically used in RANSAC, and yet the algorithm could
97       * still produce even smaller thresholds in estimated results.
98       */
99      private double stopThreshold = DEFAULT_STOP_THRESHOLD;
100 
101     /**
102      * Constructor.
103      */
104     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator() {
105         super();
106     }
107 
108     /**
109      * Constructor.
110      *
111      * @param listener listener to be notified of events such as when estimation
112      *                 starts, ends or its progress significantly changes.
113      */
114     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
115             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
116         super(listener);
117     }
118 
119     /**
120      * Constructor.
121      *
122      * @param measurements list of body kinematics measurements with standard
123      *                     deviations taken at different frames (positions, orientations
124      *                     and velocities).
125      */
126     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
127             final List<StandardDeviationFrameBodyKinematics> measurements) {
128         super(measurements);
129     }
130 
131     /**
132      * Constructor.
133      *
134      * @param measurements list of body kinematics measurements with standard
135      *                     deviations taken at different frames (positions, orientations
136      *                     and velocities).
137      * @param listener     listener to handle events raised by this calibrator.
138      */
139     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
140             final List<StandardDeviationFrameBodyKinematics> measurements,
141             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
142         super(measurements, listener);
143     }
144 
145     /**
146      * Constructor.
147      *
148      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
149      *                       accelerometer and gyroscope.
150      */
151     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(final boolean commonAxisUsed) {
152         super(commonAxisUsed);
153     }
154 
155     /**
156      * Constructor.
157      *
158      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
159      *                       accelerometer and gyroscope.
160      * @param listener       listener to handle events raised by this calibrator.
161      */
162     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
163             final boolean commonAxisUsed, final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
164         super(commonAxisUsed, listener);
165     }
166 
167     /**
168      * Constructor.
169      *
170      * @param measurements   list of body kinematics measurements with standard
171      *                       deviations taken at different frames (positions, orientations
172      *                       and velocities).
173      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
174      *                       accelerometer and gyroscope.
175      */
176     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
177             final List<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed) {
178         super(measurements, commonAxisUsed);
179     }
180 
181     /**
182      * Constructor.
183      *
184      * @param measurements   list of body kinematics measurements with standard
185      *                       deviations taken at different frames (positions, orientations
186      *                       and velocities).
187      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
188      *                       accelerometer and gyroscope.
189      * @param listener       listener to handle events raised by this calibrator.
190      */
191     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
192             final List<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
193             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
194         super(measurements, commonAxisUsed, listener);
195     }
196 
197     /**
198      * Constructor.
199      *
200      * @param biasX known x coordinate of accelerometer bias expressed in meters per
201      *              squared second (m/s^2).
202      * @param biasY known y coordinate of accelerometer bias expressed in meters per
203      *              squared second (m/s^2).
204      * @param biasZ known z coordinate of accelerometer bias expressed in meters per
205      *              squared second (m/s^2).
206      */
207     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
208             final double biasX, final double biasY, final double biasZ) {
209         super(biasX, biasY, biasZ);
210     }
211 
212     /**
213      * Constructor.
214      *
215      * @param biasX    known x coordinate of accelerometer bias expressed in meters per
216      *                 squared second (m/s^2).
217      * @param biasY    known y coordinate of accelerometer bias expressed in meters per
218      *                 squared second (m/s^2).
219      * @param biasZ    known z coordinate of accelerometer bias expressed in meters per
220      *                 squared second (m/s^2).
221      * @param listener listener to be notified of events such as when estimation
222      *                 starts, ends or its progress significantly changes.
223      */
224     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
225             final double biasX, final double biasY, final double biasZ,
226             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
227         super(biasX, biasY, biasZ, listener);
228     }
229 
230     /**
231      * Constructor.
232      *
233      * @param measurements list of body kinematics measurements with standard
234      *                     deviations taken at different frames (positions, orientations
235      *                     and velocities).
236      * @param biasX        known x coordinate of accelerometer bias expressed in meters per
237      *                     squared second (m/s^2).
238      * @param biasY        known y coordinate of accelerometer bias expressed in meters per
239      *                     squared second (m/s^2).
240      * @param biasZ        known z coordinate of accelerometer bias expressed in meters per
241      *                     squared second (m/s^2).
242      */
243     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
244             final List<StandardDeviationFrameBodyKinematics> measurements,
245             final double biasX, final double biasY, final double biasZ) {
246         super(measurements, biasX, biasY, biasZ);
247     }
248 
249     /**
250      * Constructor.
251      *
252      * @param measurements list of body kinematics measurements with standard
253      *                     deviations taken at different frames (positions, orientations
254      *                     and velocities).
255      * @param biasX        known x coordinate of accelerometer bias expressed in meters per
256      *                     squared second (m/s^2).
257      * @param biasY        known y coordinate of accelerometer bias expressed in meters per
258      *                     squared second (m/s^2).
259      * @param biasZ        known z coordinate of accelerometer bias expressed in meters per
260      *                     squared second (m/s^2).
261      * @param listener     listener to handle events raised by this calibrator.
262      */
263     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
264             final List<StandardDeviationFrameBodyKinematics> measurements,
265             final double biasX, final double biasY, final double biasZ,
266             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
267         super(measurements, biasX, biasY, biasZ, listener);
268     }
269 
270     /**
271      * Constructor.
272      *
273      * @param biasX          known x coordinate of accelerometer bias expressed in meters per
274      *                       squared second (m/s^2).
275      * @param biasY          known y coordinate of accelerometer bias expressed in meters per
276      *                       squared second (m/s^2).
277      * @param biasZ          known z coordinate of accelerometer bias expressed in meters per
278      *                       squared second (m/s^2).
279      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
280      *                       accelerometer and gyroscope.
281      */
282     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
283             final double biasX, final double biasY, final double biasZ, final boolean commonAxisUsed) {
284         super(biasX, biasY, biasZ, commonAxisUsed);
285     }
286 
287     /**
288      * Constructor.
289      *
290      * @param biasX          known x coordinate of accelerometer bias expressed in meters per
291      *                       squared second (m/s^2).
292      * @param biasY          known y coordinate of accelerometer bias expressed in meters per
293      *                       squared second (m/s^2).
294      * @param biasZ          known z coordinate of accelerometer bias expressed in meters per
295      *                       squared second (m/s^2).
296      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
297      *                       accelerometer and gyroscope.
298      * @param listener       listener to handle events raised by this calibrator.
299      */
300     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
301             final double biasX, final double biasY, final double biasZ, final boolean commonAxisUsed,
302             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
303         super(biasX, biasY, biasZ, commonAxisUsed, listener);
304     }
305 
306     /**
307      * Constructor.
308      *
309      * @param measurements   list of body kinematics measurements with standard
310      *                       deviations taken at different frames (positions, orientations
311      *                       and velocities).
312      * @param biasX          known x coordinate of accelerometer bias expressed in meters per
313      *                       squared second (m/s^2).
314      * @param biasY          known y coordinate of accelerometer bias expressed in meters per
315      *                       squared second (m/s^2).
316      * @param biasZ          known z coordinate of accelerometer bias expressed in meters per
317      *                       squared second (m/s^2).
318      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
319      *                       accelerometer and gyroscope.
320      */
321     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
322             final List<StandardDeviationFrameBodyKinematics> measurements,
323             final double biasX, final double biasY, final double biasZ, final boolean commonAxisUsed) {
324         super(measurements, biasX, biasY, biasZ, commonAxisUsed);
325     }
326 
327     /**
328      * Constructor.
329      *
330      * @param measurements   list of body kinematics measurements with standard
331      *                       deviations taken at different frames (positions, orientations
332      *                       and velocities).
333      * @param biasX          known x coordinate of accelerometer bias expressed in meters per
334      *                       squared second (m/s^2).
335      * @param biasY          known y coordinate of accelerometer bias expressed in meters per
336      *                       squared second (m/s^2).
337      * @param biasZ          known z coordinate of accelerometer bias expressed in meters per
338      *                       squared second (m/s^2).
339      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
340      *                       accelerometer and gyroscope.
341      * @param listener       listener to handle events raised by this calibrator.
342      */
343     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
344             final List<StandardDeviationFrameBodyKinematics> measurements,
345             final double biasX, final double biasY, final double biasZ, final boolean commonAxisUsed,
346             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
347         super(measurements, biasX, biasY, biasZ, commonAxisUsed, listener);
348     }
349 
350     /**
351      * Constructor.
352      *
353      * @param biasX known x coordinate of accelerometer bias.
354      * @param biasY known y coordinate of accelerometer bias.
355      * @param biasZ known z coordinate of accelerometer bias.
356      */
357     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
358             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ) {
359         super(biasX, biasY, biasZ);
360     }
361 
362     /**
363      * Constructor.
364      *
365      * @param biasX    known x coordinate of accelerometer bias.
366      * @param biasY    known y coordinate of accelerometer bias.
367      * @param biasZ    known z coordinate of accelerometer bias.
368      * @param listener listener to be notified of events such as when estimation
369      *                 starts, ends or its progress significantly changes.
370      */
371     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
372             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ,
373             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
374         super(biasX, biasY, biasZ, listener);
375     }
376 
377     /**
378      * Constructor.
379      *
380      * @param measurements list of body kinematics measurements with standard
381      *                     deviations taken at different frames (positions, orientations
382      *                     and velocities).
383      * @param biasX        known x coordinate of accelerometer bias.
384      * @param biasY        known y coordinate of accelerometer bias.
385      * @param biasZ        known z coordinate of accelerometer bias.
386      */
387     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
388             final List<StandardDeviationFrameBodyKinematics> measurements,
389             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ) {
390         super(measurements, biasX, biasY, biasZ);
391     }
392 
393     /**
394      * Constructor.
395      *
396      * @param measurements list of body kinematics measurements with standard
397      *                     deviations taken at different frames (positions, orientations
398      *                     and velocities).
399      * @param biasX        known x coordinate of accelerometer bias.
400      * @param biasY        known y coordinate of accelerometer bias.
401      * @param biasZ        known z coordinate of accelerometer bias.
402      * @param listener     listener to handle events raised by this calibrator.
403      */
404     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
405             final List<StandardDeviationFrameBodyKinematics> measurements,
406             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ,
407             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
408         super(measurements, biasX, biasY, biasZ, listener);
409     }
410 
411     /**
412      * Constructor.
413      *
414      * @param biasX          known x coordinate of accelerometer bias.
415      * @param biasY          known y coordinate of accelerometer bias.
416      * @param biasZ          known z coordinate of accelerometer bias.
417      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
418      *                       accelerometer and gyroscope.
419      */
420     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
421             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ,
422             final boolean commonAxisUsed) {
423         super(biasX, biasY, biasZ, commonAxisUsed);
424     }
425 
426     /**
427      * Constructor.
428      *
429      * @param biasX          known x coordinate of accelerometer bias.
430      * @param biasY          known y coordinate of accelerometer bias.
431      * @param biasZ          known z coordinate of accelerometer bias.
432      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
433      *                       accelerometer and gyroscope.
434      * @param listener       listener to handle events raised by this calibrator.
435      */
436     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
437             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ, final boolean commonAxisUsed,
438             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
439         super(biasX, biasY, biasZ, commonAxisUsed, listener);
440     }
441 
442     /**
443      * Constructor.
444      *
445      * @param measurements   list of body kinematics measurements with standard
446      *                       deviations taken at different frames (positions, orientations
447      *                       and velocities).
448      * @param biasX          known x coordinate of accelerometer bias.
449      * @param biasY          known y coordinate of accelerometer bias.
450      * @param biasZ          known z coordinate of accelerometer bias.
451      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
452      *                       accelerometer and gyroscope.
453      */
454     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
455             final List<StandardDeviationFrameBodyKinematics> measurements,
456             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ,
457             final boolean commonAxisUsed) {
458         super(measurements, biasX, biasY, biasZ, commonAxisUsed);
459     }
460 
461     /**
462      * Constructor.
463      *
464      * @param measurements   list of body kinematics measurements with standard
465      *                       deviations taken at different frames (positions, orientations
466      *                       and velocities).
467      * @param biasX          known x coordinate of accelerometer bias.
468      * @param biasY          known y coordinate of accelerometer bias.
469      * @param biasZ          known z coordinate of accelerometer bias.
470      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
471      *                       accelerometer and gyroscope.
472      * @param listener       listener to handle events raised by this calibrator.
473      */
474     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
475             final List<StandardDeviationFrameBodyKinematics> measurements,
476             final Acceleration biasX, final Acceleration biasY, final Acceleration biasZ, final boolean commonAxisUsed,
477             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
478         super(measurements, biasX, biasY, biasZ, commonAxisUsed, listener);
479     }
480 
481     /**
482      * Constructor.
483      *
484      * @param bias known accelerometer bias.
485      * @throws IllegalArgumentException if provided array does not have length 3.
486      */
487     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(final double[] bias) {
488         super(bias);
489     }
490 
491     /**
492      * Constructor.
493      *
494      * @param bias     known accelerometer bias.
495      * @param listener listener to be notified of events such as when estimation
496      *                 starts, ends or its progress significantly changes.
497      * @throws IllegalArgumentException if provided array does not have length 3.
498      */
499     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
500             final double[] bias, final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
501         super(bias, listener);
502     }
503 
504     /**
505      * Constructor.
506      *
507      * @param measurements list of body kinematics measurements with standard
508      *                     deviations taken at different frames (positions, orientations
509      *                     and velocities).
510      * @param bias         known accelerometer bias.
511      * @throws IllegalArgumentException if provided array does not have length 3.
512      */
513     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
514             final List<StandardDeviationFrameBodyKinematics> measurements, final double[] bias) {
515         super(measurements, bias);
516     }
517 
518     /**
519      * Constructor.
520      *
521      * @param measurements list of body kinematics measurements with standard
522      *                     deviations taken at different frames (positions, orientations
523      *                     and velocities).
524      * @param bias         known accelerometer bias.
525      * @param listener     listener to handle events raised by this calibrator.
526      * @throws IllegalArgumentException if provided array does not have length 3.
527      */
528     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
529             final List<StandardDeviationFrameBodyKinematics> measurements, final double[] bias,
530             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
531         super(measurements, bias, listener);
532     }
533 
534     /**
535      * Constructor.
536      *
537      * @param bias           known accelerometer bias.
538      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
539      *                       accelerometer and gyroscope.
540      * @throws IllegalArgumentException if provided array does not have length 3.
541      */
542     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(final double[] bias, final boolean commonAxisUsed) {
543         super(bias, commonAxisUsed);
544     }
545 
546     /**
547      * Constructor.
548      *
549      * @param bias           known accelerometer bias.
550      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
551      *                       accelerometer and gyroscope.
552      * @param listener       listener to handle events raised by this calibrator.
553      * @throws IllegalArgumentException if provided array does not have length 3.
554      */
555     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
556             final double[] bias, final boolean commonAxisUsed,
557             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
558         super(bias, commonAxisUsed, listener);
559     }
560 
561     /**
562      * Constructor.
563      *
564      * @param measurements   list of body kinematics measurements with standard
565      *                       deviations taken at different frames (positions, orientations
566      *                       and velocities).
567      * @param bias           known accelerometer bias.
568      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
569      *                       accelerometer and gyroscope.
570      * @throws IllegalArgumentException if provided array does not have length 3.
571      */
572     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
573             final List<StandardDeviationFrameBodyKinematics> measurements, final double[] bias,
574             final boolean commonAxisUsed) {
575         super(measurements, bias, commonAxisUsed);
576     }
577 
578     /**
579      * Constructor.
580      *
581      * @param measurements   list of body kinematics measurements with standard
582      *                       deviations taken at different frames (positions, orientations
583      *                       and velocities).
584      * @param bias           known accelerometer bias.
585      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
586      *                       accelerometer and gyroscope.
587      * @param listener       listener to handle events raised by this calibrator.
588      * @throws IllegalArgumentException if provided array does not have length 3.
589      */
590     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
591             final List<StandardDeviationFrameBodyKinematics> measurements, final double[] bias,
592             final boolean commonAxisUsed, final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
593         super(measurements, bias, commonAxisUsed, listener);
594     }
595 
596     /**
597      * Constructor.
598      *
599      * @param bias known accelerometer bias.
600      * @throws IllegalArgumentException if provided matrix is not 3x1.
601      */
602     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(final Matrix bias) {
603         super(bias);
604     }
605 
606     /**
607      * Constructor.
608      *
609      * @param bias     known accelerometer bias.
610      * @param listener listener to be notified of events such as when estimation
611      *                 starts, ends or its progress significantly changes.
612      * @throws IllegalArgumentException if provided matrix is not 3x1.
613      */
614     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
615             final Matrix bias, final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
616         super(bias, listener);
617     }
618 
619     /**
620      * Constructor.
621      *
622      * @param measurements list of body kinematics measurements with standard
623      *                     deviations taken at different frames (positions, orientations
624      *                     and velocities).
625      * @param bias         known accelerometer bias.
626      * @throws IllegalArgumentException if provided matrix is not 3x1.
627      */
628     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
629             final List<StandardDeviationFrameBodyKinematics> measurements, final Matrix bias) {
630         super(measurements, bias);
631     }
632 
633     /**
634      * Constructor.
635      *
636      * @param measurements list of body kinematics measurements with standard
637      *                     deviations taken at different frames (positions, orientations
638      *                     and velocities).
639      * @param bias         known accelerometer bias.
640      * @param listener     listener to handle events raised by this calibrator.
641      * @throws IllegalArgumentException if provided matrix is not 3x1.
642      */
643     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
644             final List<StandardDeviationFrameBodyKinematics> measurements, final Matrix bias,
645             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
646         super(measurements, bias, listener);
647     }
648 
649     /**
650      * Constructor.
651      *
652      * @param bias           known accelerometer bias.
653      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
654      *                       accelerometer and gyroscope.
655      * @throws IllegalArgumentException if provided matrix is not 3x1.
656      */
657     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(final Matrix bias, final boolean commonAxisUsed) {
658         super(bias, commonAxisUsed);
659     }
660 
661     /**
662      * Constructor.
663      *
664      * @param bias           known accelerometer bias.
665      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
666      *                       accelerometer and gyroscope.
667      * @param listener       listener to handle events raised by this calibrator.
668      * @throws IllegalArgumentException if provided matrix is not 3x1.
669      */
670     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
671             final Matrix bias, final boolean commonAxisUsed,
672             final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
673         super(bias, commonAxisUsed, listener);
674     }
675 
676     /**
677      * Constructor.
678      *
679      * @param measurements   list of body kinematics measurements with standard
680      *                       deviations taken at different frames (positions, orientations
681      *                       and velocities).
682      * @param bias           known accelerometer bias.
683      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
684      *                       accelerometer and gyroscope.
685      * @throws IllegalArgumentException if provided matrix is not 3x1.
686      */
687     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
688             final List<StandardDeviationFrameBodyKinematics> measurements, final Matrix bias,
689             final boolean commonAxisUsed) {
690         super(measurements, bias, commonAxisUsed);
691     }
692 
693     /**
694      * Constructor.
695      *
696      * @param measurements   list of body kinematics measurements with standard
697      *                       deviations taken at different frames (positions, orientations
698      *                       and velocities).
699      * @param bias           known accelerometer bias.
700      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
701      *                       accelerometer and gyroscope.
702      * @param listener       listener to handle events raised by this calibrator.
703      * @throws IllegalArgumentException if provided matrix is not 3x1.
704      */
705     public LMedSRobustKnownBiasAndFrameAccelerometerCalibrator(
706             final List<StandardDeviationFrameBodyKinematics> measurements, final Matrix bias,
707             final boolean commonAxisUsed, final RobustKnownBiasAndFrameAccelerometerCalibratorListener listener) {
708         super(measurements, bias, commonAxisUsed, listener);
709     }
710 
711     /**
712      * Returns threshold to be used to keep the algorithm iterating in case that
713      * best estimated threshold using median of residuals is not small enough.
714      * Once a solution is found that generates a threshold below this value, the
715      * algorithm will stop.
716      * The stop threshold can be used to prevent the LMedS algorithm to iterate
717      * too many times in cases where samples have a very similar accuracy.
718      * For instance, in cases where proportion of outliers is very small (close
719      * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
720      * iterate for a long time trying to find the best solution when indeed
721      * there is no need to do that if a reasonable threshold has already been
722      * reached.
723      * Because of this behaviour the stop threshold can be set to a value much
724      * lower than the one typically used in RANSAC, and yet the algorithm could
725      * still produce even smaller thresholds in estimated results.
726      *
727      * @return stop threshold to stop the algorithm prematurely when a certain
728      * accuracy has been reached.
729      */
730     public double getStopThreshold() {
731         return stopThreshold;
732     }
733 
734     /**
735      * Sets threshold to be used to keep the algorithm iterating in case that
736      * best estimated threshold using median of residuals is not small enough.
737      * Once a solution is found that generates a threshold below this value,
738      * the algorithm will stop.
739      * The stop threshold can be used to prevent the LMedS algorithm to iterate
740      * too many times in cases where samples have a very similar accuracy.
741      * For instance, in cases where proportion of outliers is very small (close
742      * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
743      * iterate for a long time trying to find the best solution when indeed
744      * there is no need to do that if a reasonable threshold has already been
745      * reached.
746      * Because of this behaviour the stop threshold can be set to a value much
747      * lower than the one typically used in RANSAC, and yet the algorithm could
748      * still produce even smaller thresholds in estimated results.
749      *
750      * @param stopThreshold stop threshold to stop the algorithm prematurely
751      *                      when a certain accuracy has been reached.
752      * @throws IllegalArgumentException if provided value is zero or negative.
753      * @throws LockedException          if calibrator is currently running.
754      */
755     public void setStopThreshold(final double stopThreshold) throws LockedException {
756         if (running) {
757             throw new LockedException();
758         }
759         if (stopThreshold <= MIN_STOP_THRESHOLD) {
760             throw new IllegalArgumentException();
761         }
762 
763         this.stopThreshold = stopThreshold;
764     }
765 
766     /**
767      * Estimates accelerometer calibration parameters containing scale factors
768      * and cross-coupling errors.
769      *
770      * @throws LockedException      if calibrator is currently running.
771      * @throws NotReadyException    if calibrator is not ready.
772      * @throws CalibrationException if estimation fails for numerical reasons.
773      */
774     @SuppressWarnings("DuplicatedCode")
775     @Override
776     public void calibrate() throws LockedException, NotReadyException, CalibrationException {
777         if (running) {
778             throw new LockedException();
779         }
780         if (!isReady()) {
781             throw new NotReadyException();
782         }
783 
784         final var innerEstimator = new LMedSRobustEstimator<>(new LMedSRobustEstimatorListener<Matrix>() {
785             @Override
786             public int getTotalSamples() {
787                 return measurements.size();
788             }
789 
790             @Override
791             public int getSubsetSize() {
792                 return preliminarySubsetSize;
793             }
794 
795             @Override
796             public void estimatePreliminarSolutions(final int[] samplesIndices, final List<Matrix> solutions) {
797                 computePreliminarySolutions(samplesIndices, solutions);
798             }
799 
800             @Override
801             public double computeResidual(final Matrix currentEstimation, final int i) {
802                 return computeError(measurements.get(i), currentEstimation);
803             }
804 
805             @Override
806             public boolean isReady() {
807                 return LMedSRobustKnownBiasAndFrameAccelerometerCalibrator.this.isReady();
808             }
809 
810             @Override
811             public void onEstimateStart(final RobustEstimator<Matrix> estimator) {
812                 // no action needed
813             }
814 
815             @Override
816             public void onEstimateEnd(final RobustEstimator<Matrix> estimator) {
817                 // no action needed
818             }
819 
820             @Override
821             public void onEstimateNextIteration(final RobustEstimator<Matrix> estimator, final int iteration) {
822                 if (listener != null) {
823                     listener.onCalibrateNextIteration(
824                             LMedSRobustKnownBiasAndFrameAccelerometerCalibrator.this, iteration);
825                 }
826             }
827 
828             @Override
829             public void onEstimateProgressChange(final RobustEstimator<Matrix> estimator, final float progress) {
830                 if (listener != null) {
831                     listener.onCalibrateProgressChange(
832                             LMedSRobustKnownBiasAndFrameAccelerometerCalibrator.this, progress);
833                 }
834             }
835         });
836 
837         try {
838             running = true;
839 
840             if (listener != null) {
841                 listener.onCalibrateStart(this);
842             }
843 
844             inliersData = null;
845             innerEstimator.setConfidence(confidence);
846             innerEstimator.setMaxIterations(maxIterations);
847             innerEstimator.setProgressDelta(progressDelta);
848             innerEstimator.setStopThreshold(stopThreshold);
849             final var preliminaryResult = innerEstimator.estimate();
850             inliersData = innerEstimator.getInliersData();
851 
852             attemptRefine(preliminaryResult);
853 
854             if (listener != null) {
855                 listener.onCalibrateEnd(this);
856             }
857 
858         } catch (final com.irurueta.numerical.LockedException e) {
859             throw new LockedException(e);
860         } catch (final com.irurueta.numerical.NotReadyException e) {
861             throw new NotReadyException(e);
862         } catch (final RobustEstimatorException e) {
863             throw new CalibrationException(e);
864         } finally {
865             running = false;
866         }
867     }
868 
869     /**
870      * Returns method being used for robust estimation.
871      *
872      * @return method being used for robust estimation.
873      */
874     @Override
875     public RobustEstimatorMethod getMethod() {
876         return RobustEstimatorMethod.LMEDS;
877     }
878 
879     /**
880      * Indicates whether this calibrator requires quality scores for each
881      * measurement or not.
882      *
883      * @return true if quality scores are required, false otherwise.
884      */
885     @Override
886     public boolean isQualityScoresRequired() {
887         return false;
888     }
889 }