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.Point;
19  import com.irurueta.navigation.LockedException;
20  import com.irurueta.navigation.indoor.RadioSource;
21  import com.irurueta.navigation.indoor.RangingAndRssiReadingLocated;
22  import com.irurueta.navigation.indoor.Utils;
23  import com.irurueta.numerical.robust.RobustEstimatorMethod;
24  
25  import java.util.List;
26  
27  /**
28   * This is an abstract class to robustly estimate position, transmitted power and path-loss
29   * exponent of a radio source (e.g. Wi-Fi access point or bluetooth beacon), by discarding
30   * outliers and assuming that the ranging data is available to obtain position with
31   * greater accuracy and that the radio source emits isotropically following the
32   * expression below:
33   * Pr = Pt*Gt*Gr*lambda^2 / (4*pi*d)^2,
34   * where Pr is the received power (expressed in mW),
35   * Gt is the Gain of the transmission antenna
36   * Gr is the Gain of the receiver antenna
37   * d is the distance between emitter and receiver
38   * and lambda is the wavelength and is equal to: lambda = c / f,
39   * where c is the speed of light
40   * and f is the carrier frequency of the radio signal.
41   * Because usually information about the antenna of the radio source cannot be
42   * retrieved (because many measurements are made on unknown devices where
43   * physical access is not possible), this implementation will estimate the
44   * equivalent transmitted power as: Pte = Pt * Gt * Gr.
45   * If Readings contain RSSI standard deviations, those values will be used,
46   * otherwise it will be assumed an RSSI standard deviation of 1 dB.
47   * <p>
48   * Although RobustRssiRadioSourceEstimator can estimate the same parameters of a radio
49   * source, when ranging measures are available along with RSSI measurements,
50   * implementations of this class should be preferred instead as they can provide
51   * greater accuracy.
52   *
53   * @param <S> a {@link RadioSource} type.
54   * @param <P> a {@link Point} type.
55   */
56  @SuppressWarnings("Duplicates")
57  public abstract class RobustRangingAndRssiRadioSourceEstimator<S extends RadioSource, P extends Point<P>>
58          extends RobustRadioSourceEstimator<P, RangingAndRssiReadingLocated<S, P>,
59          RobustRangingAndRssiRadioSourceEstimatorListener<S, P>> {
60  
61      /**
62       * Indicates that by default position covariances of readings must be taken into account to increase
63       * the amount of standard deviation of each ranging measure by the amount of position standard deviation
64       * assuming that both measures are statistically independent.
65       */
66      public static final boolean DEFAULT_USE_READING_POSITION_COVARIANCES = true;
67  
68      /**
69       * Initially transmitted power to start the estimation of radio source
70       * transmitted power.
71       * If not defined, average value of received power readings will be used.
72       */
73      protected Double initialTransmittedPowerdBm;
74  
75      /**
76       * Initial position to start the estimation of radio source position.
77       * If not defined, centroid of provided located readings will be used.
78       */
79      protected P initialPosition;
80  
81      /**
82       * Initial exponent typically used on free space for path loss propagation in
83       * terms of distance.
84       * On different environments path loss exponent might have different values:
85       * - Free space: 2.0
86       * - Urban Area: 2.7 to 3.5
87       * - Suburban Area: 3 to 5
88       * - Indoor (line-of-sight): 1.6 to 1.8
89       * <p>
90       * If path loss exponent estimation is enabled, estimation will start at this
91       * value and will converge to the most appropriate value.
92       * If path loss exponent estimation is disabled, this value will be assumed
93       * to be exact and the estimated path loss exponent will be equal to this
94       * value.
95       */
96      protected double initialPathLossExponent = RangingAndRssiRadioSourceEstimator.DEFAULT_PATH_LOSS_EXPONENT;
97  
98      /**
99       * Indicates whether transmitted power estimation is enabled or not.
100      */
101     protected boolean transmittedPowerEstimationEnabled =
102             RangingAndRssiRadioSourceEstimator.DEFAULT_TRANSMITTED_POWER_ESTIMATION_ENABLED;
103 
104     /**
105      * Indicates whether path loss estimation is enabled or not.
106      */
107     protected boolean pathLossEstimationEnabled;
108 
109     /**
110      * Estimated transmitted power expressed in dBm's.
111      */
112     protected double estimatedTransmittedPowerdBm;
113 
114     /**
115      * Estimated exponent typically used on free space for path loss propagation in
116      * terms of distance.
117      * On different environments path loss exponent might have different values:
118      * - Free space: 2.0
119      * - Urban Area: 2.7 to 3.5
120      * - Suburban Area: 3 to 5
121      * - Indoor (line-of-sight): 1.6 to 1.8
122      * If path loss exponent estimation is not enabled, this value will always be equal to
123      * {@link RssiRadioSourceEstimator#DEFAULT_PATH_LOSS_EXPONENT}
124      */
125     protected double estimatedPathLossExponent = RangingAndRssiRadioSourceEstimator.DEFAULT_PATH_LOSS_EXPONENT;
126 
127     /**
128      * Variance of estimated transmitted power.
129      * This value will only be available when transmitted power
130      * estimation is enabled.
131      */
132     protected Double estimatedTransmittedPowerVariance;
133 
134     /**
135      * Variance of estimated path loss exponent.
136      * This value will only be available when path-loss
137      * exponent estimation is enabled.
138      */
139     protected Double estimatedPathLossExponentVariance;
140 
141     /**
142      * Indicates whether position covariances of readings must be taken into account to increase
143      * the amount of standard deviation of each ranging measure by the amount of position standard deviation
144      * assuming that both measures are statistically independent.
145      */
146     protected boolean useReadingPositionCovariances = DEFAULT_USE_READING_POSITION_COVARIANCES;
147 
148     /**
149      * Constructor.
150      */
151     protected RobustRangingAndRssiRadioSourceEstimator() {
152         super();
153     }
154 
155     /**
156      * Constructor.
157      * Sets signal readings belonging to the same radio source.
158      *
159      * @param readings signal readings belonging to the same radio source.
160      * @throws IllegalArgumentException if readings are not valid.
161      */
162     protected RobustRangingAndRssiRadioSourceEstimator(
163             final List<? extends RangingAndRssiReadingLocated<S, P>> readings) {
164         super(readings);
165     }
166 
167     /**
168      * Constructor.
169      *
170      * @param listener listener in charge of attending events raised by this instance.
171      */
172     protected RobustRangingAndRssiRadioSourceEstimator(
173             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
174         super(listener);
175     }
176 
177     /**
178      * Constructor.
179      * Sets signal readings belonging to the same radio source.
180      *
181      * @param readings signal readings belonging to the same radio source.
182      * @param listener listener in charge of attending events raised by this instance.
183      * @throws IllegalArgumentException if readings are not valid.
184      */
185     protected RobustRangingAndRssiRadioSourceEstimator(
186             final List<? extends RangingAndRssiReadingLocated<S, P>> readings,
187             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
188         super(readings, listener);
189     }
190 
191     /**
192      * Constructor.
193      * Sets signal readings belonging to the same radio source.
194      *
195      * @param readings        signal readings belonging to the same radio source.
196      * @param initialPosition initial position to start the estimation of radio
197      *                        source position.
198      * @throws IllegalArgumentException if readings are not valid.
199      */
200     protected RobustRangingAndRssiRadioSourceEstimator(
201             final List<? extends RangingAndRssiReadingLocated<S, P>> readings, final P initialPosition) {
202         super(readings);
203         this.initialPosition = initialPosition;
204     }
205 
206     /**
207      * Constructor.
208      *
209      * @param initialPosition initial position to start the estimation of radio
210      *                        source position.
211      */
212     protected RobustRangingAndRssiRadioSourceEstimator(final P initialPosition) {
213         this.initialPosition = initialPosition;
214     }
215 
216     /**
217      * Constructor.
218      *
219      * @param initialPosition initial position to start the estimation of radio
220      *                        source position.
221      * @param listener        listener in charge of attending events raised by this instance.
222      */
223     protected RobustRangingAndRssiRadioSourceEstimator(
224             final P initialPosition, final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
225         super(listener);
226         this.initialPosition = initialPosition;
227     }
228 
229     /**
230      * Constructor.
231      * Sets signal readings belonging to the same radio source.
232      *
233      * @param readings        signal readings belonging to the same radio source.
234      * @param initialPosition initial position to start the estimation of radio
235      *                        source position.
236      * @param listener        listener in charge of attending events raised by this instance.
237      * @throws IllegalArgumentException if readings are not valid.
238      */
239     protected RobustRangingAndRssiRadioSourceEstimator(
240             final List<? extends RangingAndRssiReadingLocated<S, P>> readings, final P initialPosition,
241             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
242         super(readings, listener);
243         this.initialPosition = initialPosition;
244     }
245 
246     /**
247      * Constructor.
248      *
249      * @param initialTransmittedPowerdBm initial transmitted power to start the
250      *                                   estimation of radio source transmitted power
251      *                                   (expressed in dBm's)
252      */
253     protected RobustRangingAndRssiRadioSourceEstimator(final Double initialTransmittedPowerdBm) {
254         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
255     }
256 
257     /**
258      * Constructor.
259      * Sets signal readings belonging to the same radio source.
260      *
261      * @param readings                   signal readings belonging to the same radio source.
262      * @param initialTransmittedPowerdBm initial transmitted power to start the
263      *                                   estimation of radio source transmitted power
264      *                                   (expressed in dBm's)
265      * @throws IllegalArgumentException if readings are not valid.
266      */
267     protected RobustRangingAndRssiRadioSourceEstimator(
268             final List<? extends RangingAndRssiReadingLocated<S, P>> readings,
269             final Double initialTransmittedPowerdBm) {
270         super(readings);
271         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
272     }
273 
274     /**
275      * Constructor.
276      *
277      * @param initialTransmittedPowerdBm initial transmitted power to start the
278      *                                   estimation of radio source transmitted power
279      *                                   (expressed in dBm's)
280      * @param listener                   listener in charge of attending events raised by this instance.
281      */
282     protected RobustRangingAndRssiRadioSourceEstimator(
283             final Double initialTransmittedPowerdBm,
284             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
285         super(listener);
286         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
287     }
288 
289     /**
290      * Constructor.
291      * Sets signal readings belonging to the same radio source.
292      *
293      * @param readings                   signal readings belonging to the same radio source.
294      * @param initialTransmittedPowerdBm initial transmitted power to start the
295      *                                   estimation of radio source transmitted power
296      *                                   (expressed in dBm's)
297      * @param listener                   listener in charge of attending events raised by this instance.
298      * @throws IllegalArgumentException if readings are not valid.
299      */
300     protected RobustRangingAndRssiRadioSourceEstimator(
301             final List<? extends RangingAndRssiReadingLocated<S, P>> readings, final Double initialTransmittedPowerdBm,
302             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
303         super(readings, listener);
304         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
305     }
306 
307     /**
308      * Constructor.
309      * Sets signal readings belonging to the same radio source.
310      *
311      * @param readings                   signal readings belonging to the same radio source.
312      * @param initialPosition            initial position to start the estimation of radio
313      *                                   source position.
314      * @param initialTransmittedPowerdBm initial transmitted power to start the
315      *                                   estimation of radio source transmitted power
316      *                                   (expressed in dBm's).
317      * @throws IllegalArgumentException if readings are not valid.
318      */
319     protected RobustRangingAndRssiRadioSourceEstimator(
320             final List<? extends RangingAndRssiReadingLocated<S, P>> readings, final P initialPosition,
321             final Double initialTransmittedPowerdBm) {
322         super(readings);
323         this.initialPosition = initialPosition;
324         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
325     }
326 
327     /**
328      * Constructor.
329      *
330      * @param initialPosition            initial position to start the estimation of radio
331      *                                   source position.
332      * @param initialTransmittedPowerdBm initial transmitted power to start the
333      *                                   estimation of radio source transmitted power
334      *                                   (expressed in dBm's).
335      */
336     protected RobustRangingAndRssiRadioSourceEstimator(
337             final P initialPosition, final Double initialTransmittedPowerdBm) {
338         this.initialPosition = initialPosition;
339         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
340     }
341 
342     /**
343      * Constructor.
344      *
345      * @param initialPosition            initial position to start the estimation of radio
346      *                                   source position.
347      * @param initialTransmittedPowerdBm initial transmitted power to start the
348      *                                   estimation of radio source transmitted power
349      *                                   (expressed in dBm's).
350      * @param listener                   in charge of attending events raised by this instance.
351      */
352     protected RobustRangingAndRssiRadioSourceEstimator(
353             final P initialPosition, final Double initialTransmittedPowerdBm,
354             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
355         super(listener);
356         this.initialPosition = initialPosition;
357         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
358     }
359 
360     /**
361      * Constructor.
362      * Sets signal readings belonging to the same radio source.
363      *
364      * @param readings                   signal readings belonging to the same radio source.
365      * @param initialPosition            initial position to start the estimation of radio
366      *                                   source position.
367      * @param initialTransmittedPowerdBm initial transmitted power to start the
368      *                                   estimation of radio source transmitted power
369      *                                   (expressed in dBm's).
370      * @param listener                   listener in charge of attending events raised by this instance.
371      * @throws IllegalArgumentException if readings are not valid.
372      */
373     protected RobustRangingAndRssiRadioSourceEstimator(
374             final List<? extends RangingAndRssiReadingLocated<S, P>> readings, final P initialPosition,
375             final Double initialTransmittedPowerdBm,
376             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
377         super(readings, listener);
378         this.initialPosition = initialPosition;
379         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
380     }
381 
382     /**
383      * Constructor.
384      * Sets signal readings belonging to the same radio source.
385      *
386      * @param readings                   signal readings belonging to the same radio source.
387      * @param initialPosition            initial position to start the estimation of radio
388      *                                   source position.
389      * @param initialTransmittedPowerdBm initial transmitted power to start the
390      *                                   estimation of radio source transmitted power
391      *                                   (expressed in dBm's).
392      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
393      * @throws IllegalArgumentException if readings are not valid.
394      */
395     protected RobustRangingAndRssiRadioSourceEstimator(
396             final List<? extends RangingAndRssiReadingLocated<S, P>> readings, final P initialPosition,
397             final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
398         this(readings, initialPosition, initialTransmittedPowerdBm);
399         this.initialPathLossExponent = initialPathLossExponent;
400     }
401 
402     /**
403      * Constructor.
404      *
405      * @param initialPosition            initial position to start the estimation of radio
406      *                                   source position.
407      * @param initialTransmittedPowerdBm initial transmitted power to start the
408      *                                   estimation of radio source transmitted power
409      *                                   (expressed in dBm's).
410      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
411      */
412     protected RobustRangingAndRssiRadioSourceEstimator(
413             final P initialPosition, final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
414         this(initialPosition, initialTransmittedPowerdBm);
415         this.initialPathLossExponent = initialPathLossExponent;
416     }
417 
418     /**
419      * Constructor.
420      *
421      * @param initialPosition            initial position to start the estimation of radio
422      *                                   source position.
423      * @param initialTransmittedPowerdBm initial transmitted power to start the
424      *                                   estimation of radio source transmitted power
425      *                                   (expressed in dBm's).
426      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
427      * @param listener                   listener in charge of attending events raised by this instance.
428      */
429     protected RobustRangingAndRssiRadioSourceEstimator(
430             final P initialPosition, final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
431             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
432         this(initialPosition, initialTransmittedPowerdBm, listener);
433         this.initialPathLossExponent = initialPathLossExponent;
434     }
435 
436     /**
437      * Constructor.
438      * Sets signal readings belonging to the same radio source.
439      *
440      * @param readings                   signal readings belonging to the same radio source.
441      * @param initialPosition            initial position to start the estimation of radio
442      *                                   source position.
443      * @param initialTransmittedPowerdBm initial transmitted power to start the
444      *                                   estimation of radio source transmitted power
445      *                                   (expressed in dBm's).
446      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
447      * @param listener                   listener in charge of attending events raised by this instance.
448      * @throws IllegalArgumentException if readings are not valid.
449      */
450     protected RobustRangingAndRssiRadioSourceEstimator(
451             final List<? extends RangingAndRssiReadingLocated<S, P>> readings, final P initialPosition,
452             final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
453             final RobustRangingAndRssiRadioSourceEstimatorListener<S, P> listener) {
454         this(readings, initialPosition, initialTransmittedPowerdBm, listener);
455         this.initialPathLossExponent = initialPathLossExponent;
456     }
457 
458     /**
459      * Gets initial transmitted power to start the estimation of radio source
460      * transmitted power (expressed in dBm's).
461      * If not defined, average value of received power readings will be used.
462      *
463      * @return initial transmitted power to start the estimation of radio source
464      * transmitted power.
465      */
466     public Double getInitialTransmittedPowerdBm() {
467         return initialTransmittedPowerdBm;
468     }
469 
470     /**
471      * Sets initial transmitted power to start the estimation of radio source
472      * transmitted power (expressed in dBm's).
473      * If not defined, average value of received power readings will be used.
474      *
475      * @param initialTransmittedPowerdBm initial transmitted power to start the
476      *                                   estimation of radio source transmitted
477      *                                   power.
478      * @throws LockedException if estimator is locked.
479      */
480     public void setInitialTransmittedPowerdBm(final Double initialTransmittedPowerdBm) throws LockedException {
481         if (isLocked()) {
482             throw new LockedException();
483         }
484         this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
485     }
486 
487     /**
488      * Gets initial transmitted power to start the estimation of radio source
489      * transmitted power (expressed in mW).
490      * If not defined, average value of received power readings will be used.
491      *
492      * @return initial transmitted power to start the estimation of radio source
493      * transmitted power.
494      */
495     public Double getInitialTransmittedPower() {
496         return initialTransmittedPowerdBm != null ? Utils.dBmToPower(initialTransmittedPowerdBm) : null;
497     }
498 
499     /**
500      * Sets initial transmitted power to start the estimation of radio source
501      * transmitted power (expressed in mW).
502      * If not defined, average value of received power readings will be used.
503      *
504      * @param initialTransmittedPower initial transmitted power to start the
505      *                                estimation of radio source transmitted power.
506      * @throws LockedException          if estimator is locked.
507      * @throws IllegalArgumentException if provided value is negative.
508      */
509     public void setInitialTransmittedPower(final Double initialTransmittedPower) throws LockedException {
510         if (isLocked()) {
511             throw new LockedException();
512         }
513         if (initialTransmittedPower != null) {
514             if (initialTransmittedPower < 0.0) {
515                 throw new IllegalArgumentException();
516             }
517             initialTransmittedPowerdBm = Utils.powerTodBm(initialTransmittedPower);
518         } else {
519             initialTransmittedPowerdBm = null;
520         }
521     }
522 
523     /**
524      * Gets initial position to start the estimation of radio source position.
525      * If not defined, centroid of provided fingerprints will be used.
526      *
527      * @return initial position to start the estimation of radio source position.
528      */
529     public P getInitialPosition() {
530         return initialPosition;
531     }
532 
533     /**
534      * Sets initial position to start the estimation of radio source position.
535      * If not defined, centroid of provided fingerprints will be used.
536      *
537      * @param initialPosition initial position to start the estimation of radio
538      *                        source position.
539      * @throws LockedException if estimator is locked.
540      */
541     public void setInitialPosition(final P initialPosition) throws LockedException {
542         if (isLocked()) {
543             throw new LockedException();
544         }
545         this.initialPosition = initialPosition;
546     }
547 
548     /**
549      * Gets initial exponent typically used on free space for path loss propagation
550      * in terms of distance.
551      * On different environments path loss exponent might have different value:
552      * - Free space: 2.0
553      * - Urban Area: 2.7 to 3.5
554      * - Suburban Area: 3 to 5
555      * - Indoor (line-of-sight): 1.6 to 1.8
556      * <p>
557      * If path loss exponent estimation is enabled, estimation will start at this
558      * value and will converge to the most appropriate value.
559      * If path loss exponent estimation is disabled, this value will be assumed
560      * to be exact and the estimated path loss exponent will be equal to this
561      * value.
562      *
563      * @return initial path loss exponent.
564      */
565     public double getInitialPathLossExponent() {
566         return initialPathLossExponent;
567     }
568 
569     /**
570      * Sets initial exponent typically used on free space for path loss propagation
571      * in terms of distance.
572      * On different environments path loss exponent might have different value:
573      * - Free space: 2.0
574      * - Urban Area: 2.7 to 3.5
575      * - Suburban Area: 3 to 5
576      * - Indoor (line-of-sight): 1.6 to 1.8
577      * <p>
578      * If path loss exponent estimation is enabled, estimation will start at this
579      * value and will converge to the most appropriate value.
580      * If path loss exponent estimation is disabled, this value will be assumed
581      * to be exact and the estimated path loss exponent will be equal to this
582      * value.
583      *
584      * @param initialPathLossExponent initial path loss exponent.
585      * @throws LockedException if estimator is locked.
586      */
587     public void setInitialPathLossExponent(final double initialPathLossExponent) throws LockedException {
588         if (isLocked()) {
589             throw new LockedException();
590         }
591         this.initialPathLossExponent = initialPathLossExponent;
592     }
593 
594     /**
595      * Indicates whether transmitted power estimation is enabled or not.
596      *
597      * @return true if transmitted power estimation is enabled, false otherwise.
598      */
599     public boolean isTransmittedPowerEstimationEnabled() {
600         return transmittedPowerEstimationEnabled;
601     }
602 
603     /**
604      * Specifies whether transmitted power estimation is enabled or not.
605      *
606      * @param transmittedPowerEstimationEnabled true if transmitted power estimation is enabled,
607      *                                          false otherwise.
608      * @throws LockedException if estimator is locked.
609      */
610     public void setTransmittedPowerEstimationEnabled(final boolean transmittedPowerEstimationEnabled)
611             throws LockedException {
612         if (isLocked()) {
613             throw new LockedException();
614         }
615         this.transmittedPowerEstimationEnabled = transmittedPowerEstimationEnabled;
616     }
617 
618     /**
619      * Indicates whether path loss estimation is enabled or not.
620      *
621      * @return true if path loss estimation is enabled, false otherwise.
622      */
623     public boolean isPathLossEstimationEnabled() {
624         return pathLossEstimationEnabled;
625     }
626 
627     /**
628      * Specifies whether path loss estimation is enabled or not.
629      *
630      * @param pathLossEstimationEnabled true if path loss estimation is enabled,
631      *                                  false otherwise.
632      * @throws LockedException if estimator is locked.
633      */
634     public void setPathLossEstimationEnabled(final boolean pathLossEstimationEnabled) throws LockedException {
635         if (isLocked()) {
636             throw new LockedException();
637         }
638         this.pathLossEstimationEnabled = pathLossEstimationEnabled;
639     }
640 
641     /**
642      * Indicates whether position covariances of readings must be taken into account to increase
643      * the amount of standard deviation of each ranging measure by the amount of position standard
644      * deviation assuming that both measures are statistically independent.
645      *
646      * @return true to take into account reading position covariances, false otherwise.
647      */
648     public boolean getUseReadingPositionCovariance() {
649         return useReadingPositionCovariances;
650     }
651 
652     /**
653      * Specifies whether position covariances of readings must be taken into account to increase
654      * the amount of standard deviation of each ranging measure by the amount of position standard
655      * deviation assuming that both measures are statistically independent.
656      *
657      * @param useReadingPositionCovariances true to take into account reading position covariances, false
658      *                                      otherwise.
659      * @throws LockedException if estimator is locked.
660      */
661     public void setUseReadingPositionCovariances(final boolean useReadingPositionCovariances) throws LockedException {
662         if (isLocked()) {
663             throw new LockedException();
664         }
665         this.useReadingPositionCovariances = useReadingPositionCovariances;
666     }
667 
668     /**
669      * Indicates whether an homogeneous linear solver is used to estimate an initial
670      * position for the internal ranging radio source estimator.
671      *
672      * @return true if homogeneous linear solver is used, false if an inhomogeneous linear
673      * one is used instead.
674      */
675     public abstract boolean isHomogeneousRangingLinearSolverUsed();
676 
677     /**
678      * Specifies whether an homogeneous linear solver is used to estimate an initial
679      * position for the internal ranging radio source estimator.
680      *
681      * @param useHomogeneousLinearSolver true if homogeneous linear solver is used, false
682      *                                   if an inhomogeneous linear one is used instead.
683      * @throws LockedException if estimator is locked.
684      */
685     public abstract void setHomogeneousRangingLinearSolverUsed(final boolean useHomogeneousLinearSolver)
686             throws LockedException;
687 
688     /**
689      * Indicates whether this instance is ready to start the estimation.
690      *
691      * @return true if this instance is ready, false otherwise.
692      */
693     @Override
694     public boolean isReady() {
695         // if transmitted power estimation is disabled, an initial transmitted power must be provided
696         return !(!transmittedPowerEstimationEnabled && initialTransmittedPowerdBm == null)
697                 // readings must also be valid
698                 && areValidReadings(readings);
699     }
700 
701     /**
702      * Gets estimated transmitted power variance.
703      * This is only available when result has been refined and covariance is kept.
704      *
705      * @return estimated transmitted power variance.
706      */
707     public Double getEstimatedTransmittedPowerVariance() {
708         return estimatedTransmittedPowerVariance;
709     }
710 
711     /**
712      * Gets estimated path loss exponent variance.
713      * This is only available when result has been refined and covariance is kept.
714      *
715      * @return estimated path loss exponent variance.
716      */
717     public Double getEstimatedPathLossExponentVariance() {
718         return estimatedPathLossExponentVariance;
719     }
720 
721     /**
722      * Gets estimated transmitted power expressed in milli watts (mW).
723      *
724      * @return estimated transmitted power expressed in milli watts.
725      */
726     public double getEstimatedTransmittedPower() {
727         return Utils.dBmToPower(estimatedTransmittedPowerdBm);
728     }
729 
730     /**
731      * Gets estimated transmitted power expressed in dBm's.
732      *
733      * @return estimated transmitted power expressed in dBm's.
734      */
735     public double getEstimatedTransmittedPowerdBm() {
736         return estimatedTransmittedPowerdBm;
737     }
738 
739     /**
740      * Gets estimated exponent typically used on free space for path loss propagation in
741      * terms of distance.
742      * On different environments path loss exponent might have different values:
743      * - Free space: 2.0
744      * - Urban Area: 2.7 to 3.5
745      * - Suburban Area: 3 to 5
746      * - Indoor (line-of-sight): 1.6 to 1.8
747      * If path loss exponent estimation is not enabled, this value will always be equal to
748      * {@link RssiRadioSourceEstimator#DEFAULT_PATH_LOSS_EXPONENT}
749      *
750      * @return estimated path loss exponent.
751      */
752     public double getEstimatedPathLossExponent() {
753         return estimatedPathLossExponent;
754     }
755 
756     /**
757      * Returns method being used for robust estimation.
758      *
759      * @return method being used for robust estimation.
760      */
761     public abstract RobustEstimatorMethod getMethod();
762 
763     /**
764      * Solves preliminary solution for a subset of samples.
765      *
766      * @param samplesIndices indices of subset samples.
767      * @param solutions      instance where solution will be stored.
768      */
769     protected abstract void solvePreliminarySolutions(final int[] samplesIndices, final List<Solution<P>> solutions);
770 
771     /**
772      * Estimates residual for a solution obtained for a subset of samples.
773      *
774      * @param currentEstimation solution obtained for a subset of samples.
775      * @param i                 i-th fingerprint to obtain residual for.
776      * @return difference between measured and expected RSSI value.
777      */
778     protected double residual(final Solution<P> currentEstimation, final int i) {
779         // Model fitted internally is equal to:
780         // Pr (dBm) = 10 * log(Pte * k^n / d^n) = 10*n*log(k) + 10*log(Pte) - 5*n*log(d^2)
781         // where:
782         // Pr is received, expressed in dBm
783         // Pte is equivalent transmitted power, expressed in dBm
784         // k is a constant equal to k = c^2 / (pi * f)^2, where c is speed of light
785         // and d is equal to distance between fingerprint and estimated position
786         final var reading = readings.get(i);
787         final var frequency = reading.getSource().getFrequency();
788 
789         final var pathLossExponent = currentEstimation.getEstimatedPathLossExponent();
790 
791         // compute k as the constant part of the isotropic received power formula
792         // so that: Pr = Pte*k^n/d^n
793         final var k = RssiRadioSourceEstimator.SPEED_OF_LIGHT / (4.0 * Math.PI * frequency);
794         final var kdB = 10.0 * pathLossExponent * Math.log10(k);
795 
796         // get distance from estimated radio source position and reading position
797         final var readingPosition = reading.getPosition();
798         final var radioSourcePosition = currentEstimation.getEstimatedPosition();
799 
800         final var sqrDistance = radioSourcePosition.sqrDistanceTo(readingPosition);
801 
802         final var transmittedPowerdBm = currentEstimation.getEstimatedTransmittedPowerdBm();
803 
804         // compute expected received power assuming isotropic transmission
805         // and compare against measured RSSI at fingerprint location
806         final var expectedRSSI = kdB + transmittedPowerdBm - 5.0 * pathLossExponent * Math.log10(sqrDistance);
807         final var rssi = reading.getRssi();
808 
809         return Math.abs(expectedRSSI - rssi);
810     }
811 
812     /**
813      * Contains a solution obtained during robust estimation for a subset of
814      * samples.
815      *
816      * @param <P> a {@link Point} type.
817      */
818     protected static class Solution<P extends Point<?>> {
819         /**
820          * Estimated position for a subset of samples.
821          */
822         private final P estimatedPosition;
823 
824         /**
825          * Estimated transmitted power expressed in dBm's for a subset of samples.
826          */
827         private final double estimatedTransmittedPowerdBm;
828 
829         /**
830          * Estimated path loss exponent for a subset of samples.
831          */
832         private final double estimatedPathLossExponent;
833 
834         /**
835          * Constructor.
836          *
837          * @param estimatedPosition            estimated position for a subset of samples.
838          * @param estimatedTransmittedPowerdBm estimated transmitted power expressed
839          *                                     in dBm's for a subset of samples.
840          * @param estimatedPathLossExponent    estimated path loss exponent.
841          */
842         public Solution(final P estimatedPosition, final double estimatedTransmittedPowerdBm,
843                         final double estimatedPathLossExponent) {
844             this.estimatedPosition = estimatedPosition;
845             this.estimatedTransmittedPowerdBm = estimatedTransmittedPowerdBm;
846             this.estimatedPathLossExponent = estimatedPathLossExponent;
847         }
848 
849         /**
850          * Gets estimated position for a subset of samples.
851          *
852          * @return estimated position for a subset of samples.
853          */
854         public P getEstimatedPosition() {
855             return estimatedPosition;
856         }
857 
858         /**
859          * Gets estimated transmitted power expressed in dBm's for a subset of
860          * samples.
861          *
862          * @return estimated transmitted power expressed in dBm's for a subset
863          * of samples.
864          */
865         public double getEstimatedTransmittedPowerdBm() {
866             return estimatedTransmittedPowerdBm;
867         }
868 
869         /**
870          * Gets estimated path loss exponent.
871          *
872          * @return estimated path loss exponent.
873          */
874         public double getEstimatedPathLossExponent() {
875             return estimatedPathLossExponent;
876         }
877     }
878 }