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