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 }