View Javadoc
1   /*
2    * Copyright (C) 2018 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.indoor.radiosource;
17  
18  import com.irurueta.geometry.Point3D;
19  import com.irurueta.navigation.LockedException;
20  import com.irurueta.navigation.NotReadyException;
21  import com.irurueta.navigation.indoor.RadioSource;
22  import com.irurueta.navigation.indoor.RangingAndRssiReadingLocated;
23  import com.irurueta.numerical.robust.MSACRobustEstimator;
24  import com.irurueta.numerical.robust.MSACRobustEstimatorListener;
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 estimate 3D position, transmitted power and path-loss
33   * exponent of a radio source (e.g. Wi-Fi access point or bluetooth beacon), by discarding
34   * outliers using MSAC algorithm and assuming that the ranging data is available to
35   * obtain position with greater accuracy and that the radio source emits isotropically
36   * following the expression below:
37   * Pr = Pt*Gt*Gr*lambda^2 / (4*pi*d)^2,
38   * where Pr is the received power (expressed in mW),
39   * Gt is the Gain of the transmission antenna
40   * Gr is the Gain of the receiver antenna
41   * d is the distance between emitter and receiver
42   * and lambda is the wavelength and is equal to: lambda = c / f,
43   * where c is the speed of light
44   * and f is the carrier frequency of the radio signal.
45   * Because usually information about the antenna of the radio source cannot be
46   * retrieved (because many measurements are made on unknown devices where
47   * physical access is not possible), this implementation will estimate the
48   * equivalent transmitted power as: Pte = Pt * Gt * Gr.
49   * If Readings contain RSSI standard deviations, those values will be used,
50   * otherwise it will be assumed an RSSI standard deviation of 1 dB.
51   *
52   * @param <S> a {@link RadioSource} type.
53   */
54  @SuppressWarnings("Duplicates")
55  public class MSACRobustRangingAndRssiRadioSourceEstimator3D<S extends RadioSource> extends
56          RobustRangingAndRssiRadioSourceEstimator3D<S> {
57  
58      /**
59       * Constant defining default threshold to determine whether samples are
60       * inliers or not.
61       */
62      public static final double DEFAULT_THRESHOLD = 0.1;
63  
64      /**
65       * Minimum value that can be set as threshold.
66       * Threshold must be strictly greater than 0.0.
67       */
68      public static final double MIN_THRESHOLD = 0.0;
69  
70      /**
71       * Threshold to determine whether samples are inliers or not when
72       * testing possible estimation solutions.
73       */
74      private double threshold = DEFAULT_THRESHOLD;
75  
76      /**
77       * Constructor.
78       */
79      public MSACRobustRangingAndRssiRadioSourceEstimator3D() {
80          super();
81      }
82  
83      /**
84       * Constructor.
85       * Sets signal readings belonging to the same radio source.
86       *
87       * @param readings signal readings belonging to the same radio source.
88       * @throws IllegalArgumentException if readings are not valid.
89       */
90      public MSACRobustRangingAndRssiRadioSourceEstimator3D(
91              final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings) {
92          super(readings);
93      }
94  
95      /**
96       * Constructor.
97       *
98       * @param listener listener in charge of attending events raised by this instance.
99       */
100     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
101             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
102         super(listener);
103     }
104 
105     /**
106      * Constructor.
107      * Sets signal readings belonging to the same radio source.
108      *
109      * @param readings signal readings belonging to the same radio source.
110      * @param listener listener in charge of attending events raised by this instance.
111      * @throws IllegalArgumentException if readings are not valid.
112      */
113     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
114             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings,
115             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
116         super(readings, listener);
117     }
118 
119     /**
120      * Constructor.
121      * Sets signal readings belonging to the same radio source.
122      *
123      * @param readings        signal readings belonging to the same radio source.
124      * @param initialPosition initial position to start the estimation of radio
125      *                        source position.
126      * @throws IllegalArgumentException if readings are not valid.
127      */
128     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
129             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition) {
130         super(readings, initialPosition);
131     }
132 
133     /**
134      * Constructor.
135      *
136      * @param initialPosition initial position to start the estimation of radio
137      *                        source position.
138      */
139     public MSACRobustRangingAndRssiRadioSourceEstimator3D(final Point3D initialPosition) {
140         super(initialPosition);
141     }
142 
143     /**
144      * Constructor.
145      *
146      * @param initialPosition initial position to start the estimation of radio
147      *                        source position.
148      * @param listener        listener in charge of attending events raised by this instance.
149      */
150     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
151             final Point3D initialPosition,
152             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
153         super(initialPosition, listener);
154     }
155 
156     /**
157      * Constructor.
158      * Sets signal readings belonging to the same radio source.
159      *
160      * @param readings        signal readings belonging to the same radio source.
161      * @param initialPosition initial position to start the estimation of radio
162      *                        source position.
163      * @param listener        listener in charge of attending events raised by this instance.
164      * @throws IllegalArgumentException if readings are not valid.
165      */
166     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
167             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
168             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
169         super(readings, initialPosition, listener);
170     }
171 
172     /**
173      * Constructor.
174      *
175      * @param initialTransmittedPowerdBm initial transmitted power to start the
176      *                                   estimation of radio source transmitted power
177      *                                   (expressed in dBm's)
178      */
179     public MSACRobustRangingAndRssiRadioSourceEstimator3D(final Double initialTransmittedPowerdBm) {
180         super(initialTransmittedPowerdBm);
181     }
182 
183     /**
184      * Constructor.
185      * Sets signal readings belonging to the same radio source.
186      *
187      * @param readings                   signal readings belonging to the same radio source.
188      * @param initialTransmittedPowerdBm initial transmitted power to start the
189      *                                   estimation of radio source transmitted power
190      *                                   (expressed in dBm's)
191      * @throws IllegalArgumentException if readings are not valid.
192      */
193     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
194             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings,
195             final Double initialTransmittedPowerdBm) {
196         super(readings, initialTransmittedPowerdBm);
197     }
198 
199     /**
200      * Constructor.
201      *
202      * @param initialTransmittedPowerdBm initial transmitted power to start the
203      *                                   estimation of radio source transmitted power
204      *                                   (expressed in dBm's)
205      * @param listener                   listener in charge of attending events raised by this instance.
206      */
207     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
208             final Double initialTransmittedPowerdBm,
209             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
210         super(initialTransmittedPowerdBm, listener);
211     }
212 
213     /**
214      * Constructor.
215      * Sets signal readings belonging to the same radio source.
216      *
217      * @param readings                   signal readings belonging to the same radio source.
218      * @param initialTransmittedPowerdBm initial transmitted power to start the
219      *                                   estimation of radio source transmitted power
220      *                                   (expressed in dBm's)
221      * @param listener                   listener in charge of attending events raised by this instance.
222      * @throws IllegalArgumentException if readings are not valid.
223      */
224     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
225             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings,
226             final Double initialTransmittedPowerdBm,
227             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
228         super(readings, initialTransmittedPowerdBm, listener);
229     }
230 
231     /**
232      * Constructor.
233      * Sets signal readings belonging to the same radio source.
234      *
235      * @param readings                   signal readings belonging to the same radio source.
236      * @param initialPosition            initial position to start the estimation of radio
237      *                                   source position.
238      * @param initialTransmittedPowerdBm initial transmitted power to start the
239      *                                   estimation of radio source transmitted power
240      *                                   (expressed in dBm's).
241      * @throws IllegalArgumentException if readings are not valid.
242      */
243     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
244             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
245             final Double initialTransmittedPowerdBm) {
246         super(readings, initialPosition, initialTransmittedPowerdBm);
247     }
248 
249     /**
250      * Constructor.
251      *
252      * @param initialPosition            initial position to start the estimation of access
253      *                                   point position.
254      * @param initialTransmittedPowerdBm initial transmitted power to start the
255      *                                   estimation of radio source transmitted power
256      *                                   (expressed in dBm's).
257      */
258     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
259             final Point3D initialPosition, final Double initialTransmittedPowerdBm) {
260         super(initialPosition, initialTransmittedPowerdBm);
261     }
262 
263     /**
264      * Constructor.
265      *
266      * @param initialPosition            initial position to start the estimation of radio
267      *                                   source position.
268      * @param initialTransmittedPowerdBm initial transmitted power to start the
269      *                                   estimation of radio source transmitted power
270      *                                   (expressed in dBm's).
271      * @param listener                   in charge of attending events raised by this instance.
272      */
273     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
274             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
275             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
276         super(initialPosition, initialTransmittedPowerdBm, listener);
277     }
278 
279     /**
280      * Constructor.
281      * Sets signal readings belonging to the same radio source.
282      *
283      * @param readings                   signal readings belonging to the same radio source.
284      * @param initialPosition            initial position to start the estimation of radio
285      *                                   source position.
286      * @param initialTransmittedPowerdBm initial transmitted power to start the
287      *                                   estimation of radio source transmitted power
288      *                                   (expressed in dBm's).
289      * @param listener                   listener in charge of attending events raised by this instance.
290      * @throws IllegalArgumentException if readings are not valid.
291      */
292     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
293             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
294             final Double initialTransmittedPowerdBm,
295             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
296         super(readings, initialPosition, initialTransmittedPowerdBm, listener);
297     }
298 
299     /**
300      * Constructor.
301      * Sets signal readings belonging to the same radio source.
302      *
303      * @param readings                   signal readings belonging to the same radio source.
304      * @param initialPosition            initial position to start the estimation of radio
305      *                                   source position.
306      * @param initialTransmittedPowerdBm initial transmitted power to start the
307      *                                   estimation of radio source transmitted power
308      *                                   (expressed in dBm's).
309      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
310      * @throws IllegalArgumentException if readings are not valid.
311      */
312     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
313             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
314             final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
315         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
316     }
317 
318     /**
319      * Constructor.
320      *
321      * @param initialPosition            initial position to start the estimation of radio
322      *                                   source position.
323      * @param initialTransmittedPowerdBm initial transmitted power to start the
324      *                                   estimation of radio source transmitted power
325      *                                   (expressed in dBm's).
326      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
327      */
328     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
329             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
330             final double initialPathLossExponent) {
331         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
332     }
333 
334     /**
335      * Constructor.
336      *
337      * @param initialPosition            initial position to start the estimation of radio
338      *                                   source position.
339      * @param initialTransmittedPowerdBm initial transmitted power to start the
340      *                                   estimation of radio source transmitted power
341      *                                   (expressed in dBm's).
342      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
343      * @param listener                   listener in charge of attending events raised by this instance.
344      */
345     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
346             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
347             final double initialPathLossExponent,
348             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
349         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
350     }
351 
352     /**
353      * Constructor.
354      * Sets signal readings belonging to the same radio source.
355      *
356      * @param readings                   signal readings belonging to the same radio source.
357      * @param initialPosition            initial position to start the estimation of radio
358      *                                   source position.
359      * @param initialTransmittedPowerdBm initial transmitted power to start the
360      *                                   estimation of radio source transmitted power
361      *                                   (expressed in dBm's).
362      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
363      * @param listener                   listener in charge of attending events raised by this instance.
364      * @throws IllegalArgumentException if readings are not valid.
365      */
366     public MSACRobustRangingAndRssiRadioSourceEstimator3D(
367             final List<? extends RangingAndRssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
368             final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
369             final RobustRangingAndRssiRadioSourceEstimatorListener<S, Point3D> listener) {
370         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
371     }
372 
373     /**
374      * Returns threshold to determine whether samples are inliers or not.
375      *
376      * @return threshold to determine whether samples are inliers or not.
377      */
378     public double getThreshold() {
379         return threshold;
380     }
381 
382     /**
383      * Sets threshold to determine whether samples are inliers or not.
384      *
385      * @param threshold threshold to be set.
386      * @throws IllegalArgumentException if provided value is equal or less than
387      *                                  zero.
388      * @throws LockedException          if robust estimator is locked because an
389      *                                  estimation is already in progress.
390      */
391     public void setThreshold(final double threshold) throws LockedException {
392         if (isLocked()) {
393             throw new LockedException();
394         }
395         if (threshold <= MIN_THRESHOLD) {
396             throw new IllegalArgumentException();
397         }
398         this.threshold = threshold;
399     }
400 
401     /**
402      * Robustly estimates position, transmitted power and path-loss exponent for a
403      * radio source.
404      *
405      * @throws LockedException          if instance is busy during estimation.
406      * @throws NotReadyException        if estimator is not ready.
407      * @throws RobustEstimatorException if estimation fails for any reason
408      *                                  (i.e. numerical instability, no solution available, etc).
409      */
410     @Override
411     public void estimate() throws LockedException, NotReadyException, RobustEstimatorException {
412         if (isLocked()) {
413             throw new LockedException();
414         }
415         if (!isReady()) {
416             throw new NotReadyException();
417         }
418 
419         final var innerEstimator = new MSACRobustEstimator<>(new MSACRobustEstimatorListener<Solution<Point3D>>() {
420             @Override
421             public double getThreshold() {
422                 return threshold;
423             }
424 
425             @Override
426             public int getTotalSamples() {
427                 return readings.size();
428             }
429 
430             @Override
431             public int getSubsetSize() {
432                 return Math.max(preliminarySubsetSize, getMinReadings());
433             }
434 
435             @Override
436             public void estimatePreliminarSolutions(
437                     final int[] samplesIndices, final List<Solution<Point3D>> solutions) {
438                 solvePreliminarySolutions(samplesIndices, solutions);
439             }
440 
441             @Override
442             public double computeResidual(final Solution<Point3D> currentEstimation, final int i) {
443                 return residual(currentEstimation, i);
444             }
445 
446             @Override
447             public boolean isReady() {
448                 return MSACRobustRangingAndRssiRadioSourceEstimator3D.this.isReady();
449             }
450 
451             @Override
452             public void onEstimateStart(final RobustEstimator<Solution<Point3D>> estimator) {
453                 // no action needed
454             }
455 
456             @Override
457             public void onEstimateEnd(final RobustEstimator<Solution<Point3D>> estimator) {
458                 // no action needed
459             }
460 
461             @Override
462             public void onEstimateNextIteration(
463                     final RobustEstimator<Solution<Point3D>> estimator, final int iteration) {
464                 if (listener != null) {
465                     listener.onEstimateNextIteration(
466                             MSACRobustRangingAndRssiRadioSourceEstimator3D.this, iteration);
467                 }
468             }
469 
470             @Override
471             public void onEstimateProgressChange(
472                     final RobustEstimator<Solution<Point3D>> estimator, final float progress) {
473                 if (listener != null) {
474                     listener.onEstimateProgressChange(
475                             MSACRobustRangingAndRssiRadioSourceEstimator3D.this, progress);
476                 }
477             }
478         });
479 
480         try {
481             locked = true;
482 
483             if (listener != null) {
484                 listener.onEstimateStart(this);
485             }
486 
487             inliersData = null;
488             innerEstimator.setConfidence(confidence);
489             innerEstimator.setMaxIterations(maxIterations);
490             innerEstimator.setProgressDelta(progressDelta);
491             final var result = innerEstimator.estimate();
492             inliersData = innerEstimator.getInliersData();
493             attemptRefine(result);
494 
495             if (listener != null) {
496                 listener.onEstimateEnd(this);
497             }
498 
499         } catch (final com.irurueta.numerical.LockedException e) {
500             throw new LockedException(e);
501         } catch (final com.irurueta.numerical.NotReadyException e) {
502             throw new NotReadyException(e);
503         } finally {
504             locked = false;
505         }
506     }
507 
508     /**
509      * Returns method being used for robust estimation.
510      *
511      * @return method being used for robust estimation.
512      */
513     @Override
514     public RobustEstimatorMethod getMethod() {
515         return RobustEstimatorMethod.MSAC;
516     }
517 }