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
21 /**
22 * Optimizes the threshold factor for interval detection of accelerometer data based
23 * on results of accelerometers, gyroscopes or magnetometers calibration.
24 *
25 * @param <T> type of data to be used as input for this optimizer.
26 * @param <S> type of data source for this optimizer.
27 */
28 public abstract class IntervalDetectorThresholdFactorOptimizer<T,
29 S extends IntervalDetectorThresholdFactorOptimizerDataSource<T>> {
30
31 /**
32 * Default amount of progress variation before notifying a change in optimization progress.
33 * By default, this is set to 5%.
34 */
35 public static final float DEFAULT_PROGRESS_DELTA = 0.05f;
36
37 /**
38 * Minimum allowed value for progress delta.
39 */
40 public static final float MIN_PROGRESS_DELTA = 0.0f;
41
42 /**
43 * Maximum allowed value for progress delta.
44 */
45 public static final float MAX_PROGRESS_DELTA = 1.0f;
46
47 /**
48 * Retrieves data for this optimizer.
49 */
50 protected S dataSource;
51
52 /**
53 * Indicates whether this optimizer is running or not.
54 */
55 protected boolean running;
56
57 /**
58 * Minimum Mean Square Error that has been found.
59 */
60 protected double minMse;
61
62 /**
63 * Optimal threshold factor that has been found.
64 */
65 protected double optimalThresholdFactor;
66
67 /**
68 * Listener that notifies events generated by this optimizer.
69 */
70 protected IntervalDetectorThresholdFactorOptimizerListener<T, S> listener;
71
72 /**
73 * Amount of progress variation before notifying a progress change during optimization.
74 */
75 protected float progressDelta = DEFAULT_PROGRESS_DELTA;
76
77 /**
78 * Current progress of optimization.
79 */
80 protected float progress;
81
82 /**
83 * Previously notified progress of optimization.
84 */
85 protected float previousProgress;
86
87 /**
88 * Constructor.
89 */
90 protected IntervalDetectorThresholdFactorOptimizer() {
91 }
92
93 /**
94 * Constructor.
95 *
96 * @param dataSource instance in charge of retrieving data for this optimizer.
97 */
98 protected IntervalDetectorThresholdFactorOptimizer(final S dataSource) {
99 this.dataSource = dataSource;
100 }
101
102 /**
103 * Gets instance in charge of retrieving data for this optimizer.
104 *
105 * @return instance in charge of retrieving data for this optimizer.
106 */
107 public S getDataSource() {
108 return dataSource;
109 }
110
111 /**
112 * Sets an instance in charge of retrieving data for this optimizer.
113 *
114 * @param dataSource instance in charge of retrieving data for this optimizer.
115 * @throws LockedException if optimizer is already running.
116 */
117 public void setDataSource(final S dataSource) throws LockedException {
118 if (running) {
119 throw new LockedException();
120 }
121
122 this.dataSource = dataSource;
123 }
124
125 /**
126 * Gets a listener that notifies events generated by this optimizer.
127 *
128 * @return listener that notifies events generated by this optimizer.
129 */
130 public IntervalDetectorThresholdFactorOptimizerListener<T, S> getListener() {
131 return listener;
132 }
133
134 /**
135 * Sets a listener that notifies events generated by this optimizer.
136 *
137 * @param listener listener that notifies events generated by this optimizer.
138 * @throws LockedException if optimizer is already running.
139 */
140 public void setListener(final IntervalDetectorThresholdFactorOptimizerListener<T, S> listener)
141 throws LockedException {
142 if (running) {
143 throw new LockedException();
144 }
145
146 this.listener = listener;
147 }
148
149 /**
150 * Returns the amount of progress variation before notifying a progress change during
151 * optimization.
152 *
153 * @return amount of progress variation before notifying a progress change during
154 * optimization.
155 */
156 public float getProgressDelta() {
157 return progressDelta;
158 }
159
160 /**
161 * Sets the amount of progress variation before notifying a progress change during
162 * optimization.
163 *
164 * @param progressDelta amount of progress variation before notifying a progress
165 * change during optimization.
166 * @throws IllegalArgumentException if the progress delta is less than zero or greater than 1.
167 * @throws LockedException if optimizer is currently running.
168 */
169 public void setProgressDelta(final float progressDelta) throws LockedException {
170 if (running) {
171 throw new LockedException();
172 }
173 if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) {
174 throw new IllegalArgumentException();
175 }
176 this.progressDelta = progressDelta;
177 }
178
179 /**
180 * Indicates whether this optimizer is busy optimizing a threshold factor.
181 *
182 * @return true if optimizer is busy, false otherwise.
183 */
184 public boolean isRunning() {
185 return running;
186 }
187
188 /**
189 * Indicates whether this optimizer is ready to start optimization.
190 *
191 * @return true if this optimizer is ready, false otherwise.
192 */
193 public boolean isReady() {
194 return dataSource != null;
195 }
196
197 /**
198 * Gets minimum Mean Square Error that has been found for calibration.
199 *
200 * @return minimum Mean Square Error that has been found.
201 */
202 public double getMinMse() {
203 return minMse;
204 }
205
206 /**
207 * Gets the optimal threshold factor that has been found.
208 *
209 * @return optimal threshold factor that has been found.
210 */
211 public double getOptimalThresholdFactor() {
212 return optimalThresholdFactor;
213 }
214
215 /**
216 * Optimizes the threshold factor for a static interval detector or measurement
217 * generator to minimize MSE (Minimum Squared Error) of estimated
218 * calibration parameters.
219 *
220 * @return optimized threshold factor.
221 * @throws NotReadyException if this optimizer is not
222 * ready to start optimization.
223 * @throws LockedException if optimizer is already
224 * running.
225 * @throws IntervalDetectorThresholdFactorOptimizerException if optimization fails for
226 * some reason.
227 */
228 public abstract double optimize() throws NotReadyException, LockedException,
229 IntervalDetectorThresholdFactorOptimizerException;
230
231 /**
232 * Checks current progress and notifies if progress has changed significantly.
233 */
234 protected void checkAndNotifyProgress() {
235 if (listener != null && (progress - previousProgress > progressDelta)) {
236 previousProgress = progress;
237 listener.onOptimizeProgressChange(this, Math.min(progress, 1.0f));
238 }
239 }
240
241 /**
242 * Initializes progress values.
243 */
244 protected void initProgress() {
245 previousProgress = 0.0f;
246 progress = 0.0f;
247 }
248 }