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 }