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