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  
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 }