View Javadoc
1   /*
2    * Copyright (C) 2021 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.intervals.thresholdfactor;
17  
18  import com.irurueta.navigation.LockedException;
19  import com.irurueta.navigation.NotReadyException;
20  import com.irurueta.navigation.inertial.calibration.BodyKinematicsSequence;
21  import com.irurueta.navigation.inertial.calibration.StandardDeviationBodyKinematics;
22  import com.irurueta.navigation.inertial.calibration.StandardDeviationBodyMagneticFluxDensity;
23  import com.irurueta.navigation.inertial.calibration.StandardDeviationTimedBodyKinematics;
24  import com.irurueta.navigation.inertial.calibration.accelerometer.AccelerometerCalibratorMeasurementType;
25  import com.irurueta.navigation.inertial.calibration.accelerometer.AccelerometerNonLinearCalibrator;
26  import com.irurueta.navigation.inertial.calibration.gyroscope.GyroscopeCalibratorMeasurementOrSequenceType;
27  import com.irurueta.navigation.inertial.calibration.gyroscope.GyroscopeNonLinearCalibrator;
28  import com.irurueta.navigation.inertial.calibration.magnetometer.MagnetometerCalibratorMeasurementType;
29  import com.irurueta.navigation.inertial.calibration.magnetometer.MagnetometerNonLinearCalibrator;
30  
31  /**
32   * Optimizes the threshold factor for interval detection of accelerometer and gyroscope
33   * data based on results of calibration.
34   * Only accelerometer calibrators based on unknown orientation are supported (in other terms,
35   * calibrators must be {@link AccelerometerNonLinearCalibrator} and must support
36   * {@link AccelerometerCalibratorMeasurementType#STANDARD_DEVIATION_BODY_KINEMATICS}).
37   * Only gyroscope calibrators based on unknown orientation are supported (in other terms,
38   * calibrators must be {@link GyroscopeNonLinearCalibrator} and must support
39   * {@link GyroscopeCalibratorMeasurementOrSequenceType#BODY_KINEMATICS_SEQUENCE}).
40   * Only magnetometer calibrators based on unknown orientation are supported, in other terms,
41   * calibrators must be {@link MagnetometerNonLinearCalibrator} and must support
42   * {@link MagnetometerCalibratorMeasurementType#STANDARD_DEVIATION_BODY_MAGNETIC_FLUX_DENSITY}.
43   * This implementation makes an exhaustive search between minimum and maximum
44   * threshold factor values to find the threshold value that produces the
45   * minimum Mean Square Error (MSE) for calibration parameters.
46   */
47  public class ExhaustiveAccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizer extends
48          AccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizer {
49  
50      /**
51       * Default step value to make exhaustive search of threshold factor values.
52       */
53      public static final double DEFAULT_STEP = 1.0;
54  
55      /**
56       * Step to make exhaustive search of threshold factor values between
57       * {@link #getMaxThresholdFactor()} and {@link #getMaxThresholdFactor()}.
58       */
59      private double thresholdFactorStep = DEFAULT_STEP;
60  
61      /**
62       * Constructor.
63       */
64      public ExhaustiveAccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizer() {
65          super();
66      }
67  
68      /**
69       * Constructor.
70       *
71       * @param dataSource instance in charge of retrieving data for this optimizer.
72       */
73      public ExhaustiveAccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizer(
74              final AccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizerDataSource dataSource) {
75          super(dataSource);
76      }
77  
78      /**
79       * Constructor.
80       *
81       * @param accelerometerCalibrator an accelerometer calibrator to be used to
82       *                                optimize its Mean Square Error (MSE).
83       * @param gyroscopeCalibrator     a gyroscope calibrator to be used to optimize
84       *                                its Mean Square Error (MSE).
85       * @param magnetometerCalibrator  a magnetometer calibrator to be used to
86       *                                optimize its Mean Square Error (MSE).
87       * @throws IllegalArgumentException if accelerometer calibrator does not use
88       *                                  {@link StandardDeviationBodyKinematics} measurements,
89       *                                  if gyroscope calibrator does not use
90       *                                  {@link BodyKinematicsSequence} sequences of
91       *                                  {@link StandardDeviationTimedBodyKinematics} or
92       *                                  if magnetometer calibrator does not use
93       *                                  {@link StandardDeviationBodyMagneticFluxDensity} measurements.
94       */
95      public ExhaustiveAccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizer(
96              final AccelerometerNonLinearCalibrator accelerometerCalibrator,
97              final GyroscopeNonLinearCalibrator gyroscopeCalibrator,
98              final MagnetometerNonLinearCalibrator magnetometerCalibrator) {
99          super(accelerometerCalibrator, gyroscopeCalibrator, magnetometerCalibrator);
100     }
101 
102     /**
103      * Constructor.
104      *
105      * @param dataSource              instance in charge of retrieving data for this optimizer.
106      * @param accelerometerCalibrator an accelerometer calibrator to be used to
107      *                                optimize its Mean Square Error (MSE).
108      * @param gyroscopeCalibrator     a gyroscope calibrator to be used to optimize
109      *                                its Mean Square Error (MSE).
110      * @param magnetometerCalibrator  a magnetometer calibrator to be used to
111      *                                optimize its Mean Square Error (MSE).
112      * @throws IllegalArgumentException if accelerometer calibrator does not use
113      *                                  {@link StandardDeviationBodyKinematics} measurements,
114      *                                  if gyroscope calibrator does not use
115      *                                  {@link BodyKinematicsSequence} sequences of
116      *                                  {@link StandardDeviationTimedBodyKinematics} or
117      *                                  if magnetometer calibrator does not use
118      *                                  {@link StandardDeviationBodyMagneticFluxDensity} measurements.
119      */
120     public ExhaustiveAccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizer(
121             final AccelerometerGyroscopeAndMagnetometerIntervalDetectorThresholdFactorOptimizerDataSource dataSource,
122             final AccelerometerNonLinearCalibrator accelerometerCalibrator,
123             final GyroscopeNonLinearCalibrator gyroscopeCalibrator,
124             final MagnetometerNonLinearCalibrator magnetometerCalibrator) {
125         super(dataSource, accelerometerCalibrator, gyroscopeCalibrator, magnetometerCalibrator);
126     }
127 
128     /**
129      * Gets the step to make exhaustive search of threshold values between
130      * {@link #getMaxThresholdFactor()} and {@link #getMaxThresholdFactor()}.
131      *
132      * @return step to make exhaustive search of threshold values.
133      */
134     public double getThresholdFactorStep() {
135         return thresholdFactorStep;
136     }
137 
138     /**
139      * Sets step to make exhaustive search of threshold values between
140      * {@link #getMaxThresholdFactor()} and {@link #getMaxThresholdFactor()}.
141      *
142      * @param thresholdStep step to make exhaustive search of threshold values.
143      * @throws LockedException          if optimizer is already running.
144      * @throws IllegalArgumentException if provided value is zero or negative.
145      */
146     public void setThresholdFactorStep(final double thresholdStep) throws LockedException {
147         if (running) {
148             throw new LockedException();
149         }
150         if (thresholdStep <= 0.0) {
151             throw new IllegalArgumentException();
152         }
153 
154         thresholdFactorStep = thresholdStep;
155     }
156 
157     /**
158      * Optimizes the threshold factor for a static interval detector or measurement
159      * generator to minimize MSE (Minimum Squared Error) of estimated
160      * calibration parameters.
161      *
162      * @return optimized threshold factor.
163      * @throws NotReadyException                                 if this optimizer is not ready to start optimization.
164      * @throws LockedException                                   if optimizer is already running.
165      * @throws IntervalDetectorThresholdFactorOptimizerException if optimization fails for
166      *                                                           some reason.
167      */
168     @Override
169     public double optimize() throws NotReadyException, LockedException,
170             IntervalDetectorThresholdFactorOptimizerException {
171         if (running) {
172             throw new LockedException();
173         }
174 
175         if (!isReady()) {
176             throw new NotReadyException();
177         }
178 
179         var hasResult = false;
180         minMse = Double.MAX_VALUE;
181         try {
182             running = true;
183 
184             initProgress();
185             final var progressStep = (float) (thresholdFactorStep
186                     / (thresholdFactorStep + maxThresholdFactor - minThresholdFactor));
187 
188             if (listener != null) {
189                 listener.onOptimizeStart(this);
190             }
191 
192             for (var thresholdFactor = minThresholdFactor;
193                  thresholdFactor <= maxThresholdFactor;
194                  thresholdFactor += thresholdFactorStep) {
195                 try {
196                     evaluateForThresholdFactor(thresholdFactor);
197                     hasResult = true;
198                 } catch (final Exception ignore) {
199                     // when an error occurs, skip to the next iteration
200                 }
201 
202                 progress += progressStep;
203                 checkAndNotifyProgress();
204             }
205 
206             if (!hasResult) {
207                 throw new IntervalDetectorThresholdFactorOptimizerException();
208             }
209 
210             if (listener != null) {
211                 listener.onOptimizeEnd(this);
212             }
213 
214         } finally {
215             running = false;
216         }
217 
218         return optimalThresholdFactor;
219     }
220 }