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.InhomogeneousPoint2D;
19  import com.irurueta.geometry.Point2D;
20  import com.irurueta.navigation.indoor.Beacon;
21  import com.irurueta.navigation.indoor.BeaconWithPowerAndLocated2D;
22  import com.irurueta.navigation.indoor.RadioSource;
23  import com.irurueta.navigation.indoor.RadioSourceWithPowerAndLocated;
24  import com.irurueta.navigation.indoor.RssiReadingLocated;
25  import com.irurueta.navigation.indoor.WifiAccessPoint;
26  import com.irurueta.navigation.indoor.WifiAccessPointWithPowerAndLocated2D;
27  
28  import java.util.List;
29  
30  /**
31   * Estimates 2D position, transmitted power and path-loss exponent
32   * of a radio source assuming that the radio source emits
33   * isotropically following the expression below:
34   * Pr = Pt*Gt*Gr*lambda^2 / (4*pi*d)^2,
35   * where Pr is the received power (expressed in mW),
36   * Gt is the Gain of the transmission antenna
37   * Gr is the Gain of the receiver antenna
38   * d is the distance between emitter and receiver
39   * and lambda is the wavelength and is equal to: lambda = c / f,
40   * where c is the speed of light
41   * and f is the carrier frequency of the radio signal.
42   * Because usually information about the antenna of the radio source cannot be
43   * retrieved (because many measurements are made on unknown access points where
44   * physical access is not possible), this implementation will estimate the
45   * equivalent transmitted power as: Pte = Pt * Gt * Gr.
46   * If Readings contain RSSI standard deviations, those values will be used,
47   * otherwise it will be assumed an RSSI standard deviation of 1 dB.
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   */
61  @SuppressWarnings("Duplicates")
62  public class RssiRadioSourceEstimator2D<S extends RadioSource> extends RssiRadioSourceEstimator<S, Point2D> {
63  
64      /**
65       * Constructor.
66       */
67      public RssiRadioSourceEstimator2D() {
68      }
69  
70      /**
71       * Constructor.
72       * Sets radio signal readings belonging to the same radio source.
73       *
74       * @param readings radio signal readings belonging to the same
75       *                 radio source.
76       * @throws IllegalArgumentException if readings are not valid.
77       */
78      public RssiRadioSourceEstimator2D(final List<? extends RssiReadingLocated<S, Point2D>> readings) {
79          super(readings);
80      }
81  
82      /**
83       * Constructor.
84       *
85       * @param listener listener in charge of attending events raised by this instance.
86       */
87      public RssiRadioSourceEstimator2D(final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
88          super(listener);
89      }
90  
91      /**
92       * Constructor.
93       * Sets radio signal readings belonging to the same radio source.
94       *
95       * @param readings radio signal readings belonging to the same
96       *                 radio source.
97       * @param listener listener in charge of attending events raised by this instance.
98       * @throws IllegalArgumentException if readings are not valid.
99       */
100     public RssiRadioSourceEstimator2D(
101             final List<? extends RssiReadingLocated<S, Point2D>> readings,
102             final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
103         super(readings, listener);
104     }
105 
106     /**
107      * Constructor.
108      *
109      * @param initialPosition initial position to start the estimation of access
110      *                        point position.
111      */
112     public RssiRadioSourceEstimator2D(final Point2D initialPosition) {
113         super(initialPosition);
114     }
115 
116     /**
117      * Constructor.
118      * Sets radio signal readings belonging to the same radio source.
119      *
120      * @param readings        radio signal readings belonging to the same
121      *                        radio source.
122      * @param initialPosition initial position to start the estimation of radio
123      *                        source position.
124      * @throws IllegalArgumentException if readings are not valid.
125      */
126     public RssiRadioSourceEstimator2D(
127             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition) {
128         super(readings, initialPosition);
129     }
130 
131     /**
132      * Constructor.
133      *
134      * @param initialPosition initial position to start the estimation of radio
135      *                        source position.
136      * @param listener        listener in charge of attending events raised by this instance.
137      */
138     public RssiRadioSourceEstimator2D(
139             final Point2D initialPosition, final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
140         super(initialPosition, listener);
141     }
142 
143     /**
144      * Constructor.
145      * Sets radio signal readings belonging to the same radio source.
146      *
147      * @param readings        radio signal readings belonging to the same
148      *                        radio source.
149      * @param initialPosition initial position to start the estimation of radio
150      *                        source position.
151      * @param listener        listener in charge of attending events raised by this instance.
152      * @throws IllegalArgumentException if readings are not valid.
153      */
154     public RssiRadioSourceEstimator2D(
155             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
156             final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
157         super(readings, initialPosition, listener);
158     }
159 
160     /**
161      * Constructor.
162      *
163      * @param initialTransmittedPowerdBm initial transmitted power to start the
164      *                                   estimation of radio source transmitted power
165      *                                   (expressed in dBm's)
166      */
167     public RssiRadioSourceEstimator2D(final Double initialTransmittedPowerdBm) {
168         super(initialTransmittedPowerdBm);
169     }
170 
171     /**
172      * Constructor.
173      * Sets radio signal readings belonging to the same radio source.
174      *
175      * @param readings                   radio signal readings belonging to the same
176      *                                   radio source.
177      * @param initialTransmittedPowerdBm initial transmitted power to start the
178      *                                   estimation of radio source transmitted power
179      *                                   (expressed in dBm's)
180      * @throws IllegalArgumentException if readings are not valid.
181      */
182     public RssiRadioSourceEstimator2D(
183             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Double initialTransmittedPowerdBm) {
184         super(readings, initialTransmittedPowerdBm);
185     }
186 
187     /**
188      * Constructor.
189      *
190      * @param initialTransmittedPowerdBm initial transmitted power to start the
191      *                                   estimation of access point transmitted power
192      *                                   (expressed in dBm's)
193      * @param listener                   listener in charge of attending events raised by this instance.
194      */
195     public RssiRadioSourceEstimator2D(
196             final Double initialTransmittedPowerdBm, final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
197         super(initialTransmittedPowerdBm, listener);
198     }
199 
200     /**
201      * Constructor.
202      * Sets radio signal readings belonging to the same radio source.
203      *
204      * @param readings                   radio signal readings belonging to the same
205      *                                   radio source.
206      * @param initialTransmittedPowerdBm initial transmitted power to start the
207      *                                   estimation of radio source transmitted power
208      *                                   (expressed in dBm's)
209      * @param listener                   listener in charge of attending events raised by this instance.
210      * @throws IllegalArgumentException if readings are not valid.
211      */
212     public RssiRadioSourceEstimator2D(
213             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Double initialTransmittedPowerdBm,
214             final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
215         super(readings, initialTransmittedPowerdBm, listener);
216     }
217 
218     /**
219      * Constructor.
220      * Sets radio signal readings belonging to the same radio source.
221      *
222      * @param readings                   radio signal readings belonging to the same
223      *                                   radio source.
224      * @param initialPosition            initial position to start the estimation of radio
225      *                                   source position.
226      * @param initialTransmittedPowerdBm initial transmitted power to start the
227      *                                   estimation of radio source transmitted power
228      *                                   (expressed in dBm's)
229      * @throws IllegalArgumentException if readings are not valid.
230      */
231     public RssiRadioSourceEstimator2D(
232             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
233             final Double initialTransmittedPowerdBm) {
234         super(readings, initialPosition, initialTransmittedPowerdBm);
235     }
236 
237     /**
238      * Constructor.
239      *
240      * @param initialPosition            initial position to start the estimation of radio
241      *                                   source position.
242      * @param initialTransmittedPowerdBm initial transmitted power to start the
243      *                                   estimation of radio source transmitted power
244      *                                   (expressed in dBm's)
245      */
246     public RssiRadioSourceEstimator2D(final Point2D initialPosition, final Double initialTransmittedPowerdBm) {
247         super(initialPosition, initialTransmittedPowerdBm);
248     }
249 
250     /**
251      * Constructor.
252      *
253      * @param initialPosition            initial position to start the estimation of radio
254      *                                   source position.
255      * @param initialTransmittedPowerdBm initial transmitted power to start the
256      *                                   estimation of radio source transmitted power
257      *                                   (expressed in dBm's)
258      * @param listener                   listener in charge of attending events raised by this instance.
259      */
260     public RssiRadioSourceEstimator2D(
261             final Point2D initialPosition, final Double initialTransmittedPowerdBm,
262             final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
263         super(initialPosition, initialTransmittedPowerdBm, listener);
264     }
265 
266     /**
267      * Constructor.
268      * Sets radio signal readings belonging to the same radio source.
269      *
270      * @param readings                   radio signal readings belonging to the same
271      *                                   radio source.
272      * @param initialPosition            initial position to start the estimation of radio
273      *                                   source position.
274      * @param initialTransmittedPowerdBm initial transmitted power to start the
275      *                                   estimation of radio source transmitted power
276      *                                   (expressed in dBm's)
277      * @param listener                   listener in charge of attending events raised by this instance.
278      * @throws IllegalArgumentException if readings are not valid.
279      */
280     public RssiRadioSourceEstimator2D(
281             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
282             final Double initialTransmittedPowerdBm, final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
283         super(readings, initialPosition, initialTransmittedPowerdBm, listener);
284     }
285 
286     /**
287      * Constructor.
288      * Sets radio signal readings belonging to the same radio source.
289      *
290      * @param readings                   radio signal readings belonging to the same
291      *                                   radio source.
292      * @param initialPosition            initial position to start the estimation of radio
293      *                                   source position.
294      * @param initialTransmittedPowerdBm initial transmitted power to start the
295      *                                   estimation of radio source transmitted power
296      *                                   (expressed in dBm's).
297      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
298      * @throws IllegalArgumentException if readings are not valid.
299      */
300     public RssiRadioSourceEstimator2D(
301             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
302             final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
303         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
304     }
305 
306     /**
307      * Constructor.
308      *
309      * @param initialPosition            initial position to start the estimation of radio
310      *                                   source position.
311      * @param initialTransmittedPowerdBm initial transmitted power to start the
312      *                                   estimation of radio source transmitted power
313      *                                   (expressed in dBm's)
314      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
315      */
316     public RssiRadioSourceEstimator2D(
317             final Point2D initialPosition, final Double initialTransmittedPowerdBm,
318             final double initialPathLossExponent) {
319         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
320     }
321 
322     /**
323      * Constructor.
324      *
325      * @param initialPosition            initial position to start the estimation of radio
326      *                                   source position.
327      * @param initialTransmittedPowerdBm initial transmitted power to start the
328      *                                   estimation of radio source transmitted power
329      *                                   (expressed in dBm's)
330      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
331      * @param listener                   listener in charge of attending events raised by this instance.
332      */
333     public RssiRadioSourceEstimator2D(
334             final Point2D initialPosition, final Double initialTransmittedPowerdBm,
335             final double initialPathLossExponent, final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
336         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
337     }
338 
339     /**
340      * Constructor.
341      * Sets radio signal readings belonging to the same radio source.
342      *
343      * @param readings                   radio signal readings belonging to the same
344      *                                   radio source.
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 initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
351      * @param listener                   listener in charge of attending events raised by this instance.
352      * @throws IllegalArgumentException if readings are not valid.
353      */
354     public RssiRadioSourceEstimator2D(
355             final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
356             final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
357             final RssiRadioSourceEstimatorListener<S, Point2D> listener) {
358         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
359     }
360 
361     /**
362      * Gets minimum required number of readings to estimate
363      * power, position and path-loss exponent.
364      * This value depends on the number of parameters to
365      * be estimated, but for position only, this is 3
366      * readings.
367      *
368      * @return minimum required number of readings.
369      */
370     @Override
371     public int getMinReadings() {
372         var minReadings = 0;
373         if (isPositionEstimationEnabled()) {
374             minReadings += Point2D.POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH;
375         }
376         if (isTransmittedPowerEstimationEnabled()) {
377             minReadings++;
378         }
379         if (isPathLossEstimationEnabled()) {
380             minReadings++;
381         }
382         return ++minReadings;
383     }
384 
385     /**
386      * Gets number of dimensions of position points.
387      * This is always 2.
388      *
389      * @return number of dimensions of position points.
390      */
391     @Override
392     public int getNumberOfDimensions() {
393         return Point2D.POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH;
394     }
395 
396     /**
397      * Gets estimated radio source 2D position.
398      *
399      * @return estimated radio source 2D position.
400      */
401     @Override
402     public Point2D getEstimatedPosition() {
403         if (estimatedPositionCoordinates == null) {
404             return null;
405         }
406 
407         final var result = new InhomogeneousPoint2D();
408         getEstimatedPosition(result);
409         return result;
410 
411     }
412 
413     /**
414      * Gets estimated located radio source with estimated transmitted power.
415      *
416      * @return estimated located radio source with estimated transmitted power or null.
417      */
418     @Override
419     @SuppressWarnings("unchecked")
420     public RadioSourceWithPowerAndLocated<Point2D> getEstimatedRadioSource() {
421         final var readings = getReadings();
422         if (readings == null || readings.isEmpty()) {
423             return null;
424         }
425         final var source = readings.get(0).getSource();
426 
427         final var estimatedPosition = getEstimatedPosition();
428         if (estimatedPosition == null) {
429             return null;
430         }
431 
432         final var estimatedPositionCovariance = getEstimatedPositionCovariance();
433 
434         final var transmittedPowerVariance = getEstimatedTransmittedPowerVariance();
435         final var transmittedPowerStandardDeviation = transmittedPowerVariance != null
436                 ? Math.sqrt(transmittedPowerVariance) : null;
437 
438         final var pathlossExponentVariance = getEstimatedPathLossExponentVariance();
439         final var pathlossExponentStandardDeviation = pathlossExponentVariance != null
440                 ? Math.sqrt(pathlossExponentVariance) : null;
441 
442         if (source instanceof WifiAccessPoint accessPoint) {
443             return new WifiAccessPointWithPowerAndLocated2D(accessPoint.getBssid(), source.getFrequency(),
444                     accessPoint.getSsid(), getEstimatedTransmittedPowerdBm(), transmittedPowerStandardDeviation,
445                     getEstimatedPathLossExponent(), pathlossExponentStandardDeviation, estimatedPosition,
446                     estimatedPositionCovariance);
447         } else if (source instanceof Beacon beacon) {
448             return new BeaconWithPowerAndLocated2D(beacon.getIdentifiers(), getEstimatedTransmittedPowerdBm(),
449                     beacon.getFrequency(), beacon.getBluetoothAddress(), beacon.getBeaconTypeCode(),
450                     beacon.getManufacturer(), beacon.getServiceUuid(), beacon.getBluetoothName(),
451                     getEstimatedPathLossExponent(), transmittedPowerStandardDeviation,
452                     pathlossExponentStandardDeviation, estimatedPosition, estimatedPositionCovariance);
453         } else {
454             return null;
455         }
456     }
457 }