Estimating beacon proximity/distance based on RSSI - Bluetooth LE
Asked Answered
U

4

25

I've got a simple iOS app which displays the proximity of the Bluetooth LE beacons it detects using such expressions as "immediate", "near" etc. and I need to write something similar on Android.

I've followed the tutorial at Android developer and I'm able to list detected devices and now want to estimate the distance/proximity - this is where it's become a problem. According to this SO thread it's just a handful of mathematical calculations. However, they require me to provide a txPower value.

According to this tutorial by Dave Smith (and cross-referencing with this Bluetooth SIG statement), it should be broadcast by the beacon devices as an "AD structure" of type 0x0A. So what I do is parse the AD structures and look for the payload of the one that matches the type.

Problem: I've got 4 beacons - 2 estimotes and 2 appflares. The estimotes don't broadcast the txPower at all and the appflares broadcast theirs as 0.

Is there anything I'm missing here? The iOS app seems to be handling it all without any problem, but using the iOS SDK it does it behind the scenes so I'm not sure how to produce the exact same or similar behaviour. Is there any other way I could solve my problem?

In case you'd like to take a look at the code I'm using to parse the AD structures, it's taken from the aforementioned Dave Smith's github and can be found here. The only change I did to that class was add the following method:

public byte[] getData() {

    return mData;
}

And this is how I handle the callback from the scans:

// Prepare the callback for BLE device scan
this.leScanCallback = new BluetoothAdapter.LeScanCallback() {

    @Override
    public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {

        if (!deviceList.contains(device)) {

            MyService.this.deviceList.add(device);
            Log.e("Test", "Device: " + device.getName());

            List<AdRecord> adRecords = AdRecord.parseScanRecord(scanRecord);

            for (AdRecord adRecord : adRecords) {

                if (adRecord.getType() == AdRecord.TYPE_TRANSMITPOWER) {

                    Log.e("Test", "size of payload: " + adRecord.getData().length);
                    Log.e("Test", "payload: " + Byte.toString(adRecord.getData()[0]));
                }
            }
        }
    }
};

And what I see in the console is:

04-01 11:33:35.864: E/Test(15061): Device: estimote
04-01 11:33:36.304: E/Test(15061): Device: estimote
04-01 11:33:36.475: E/Test(15061): Device: n86
04-01 11:33:36.475: E/Test(15061): size of payload: 1
04-01 11:33:36.475: E/Test(15061): payload: 0
04-01 11:33:36.525: E/Test(15061): Device: f79
04-01 11:33:36.525: E/Test(15061): size of payload: 1
04-01 11:33:36.525: E/Test(15061): payload: 0
Ullyot answered 1/4, 2014 at 11:28 Comment(0)
C
25

It is unclear whether your inability to read the "txPower" or "measuredPower" calibration constant is due to the AdRecord class or due to the information being missing from the advertisements you are trying to parse. It doesn't look to me like that class will parse a standard iBeacon advertisement. Either way, there is a solution:

SOLUTION 1: If your beacons send a standard iBeacon advertisement that includes the calibration constant, you can parse it out using code in the open source Android iBeacon Library's IBeacon class here.

SOLUTION 2: If your beacons DO NOT send a standard iBeacon advertisement or do not include a calibration constant:

You must hard-code a calibration constant in your app for each device type you might use. All you really need from the advertisement to estimate distance is the the RSSI measurement. The whole point of embedding a calibration constant in the transmission is to allow a wide variety of beacons with quite different transmitter output power to work with the same distance estimating algorithm.

The calibration constant, as defined by Apple, basically says what the RSSI should be if your device is exactly one meter away from the beacon. If the signal is stronger (less negative RSSI), then the device is less than one meter away. If the signal is weaker (more negative RSSI), then the device is over one meter away. You can use a formula to make a numerical estimate of distance. See here.

If you aren't dealing with advertisements that contain a "txPower" or "measuredPower" calibration constant, then you can hard-code a lookup table in your app that stores the known calibration constants for various transmitters. You will first need to measure the average RSSI of each transmitter at one meter away. You'll then need some kind of key to look up these calibration constants in the table. (Perhaps you can use the some part of the string from the AD structure, or the mac address?) So your table might look like this:

HashMap<String,Integer> txPowerLookupTable = new HashMap<String,Integer>();
txPowerLookupTable.put("a5:09:37:78:c3:22", new Integer(-65));
txPowerLookupTable.put("d2:32:33:5c:87:09", new Integer(-78));

Then after parsing an advertisement, you can look up the calibration constant in your onLeScan method like this:

String macAddress = device.getAddress();
Integer txPower = txPowerLookupTable.get(macAddress);
Cyanic answered 1/4, 2014 at 13:35 Comment(3)
Hey, my beacons do send the standard iBeacon advertisement. However, I'm using Ionic framework so can't use Android iBeacon Library directly at least, any way of doing it in JS ?Af
@Tushar, you should open a new question if you need help on this, but you can detect beacons with Ionic using the cordova-beacon-pulugin. See: thepolyglotdeveloper.com/2015/09/…Cyanic
We are trying to calibrate our beacons. The manufacturer has provided us with a table with the different values ​​of tx power (9 - 40 dBm. 8 -30 dBm...1 dBm 4). How should we interpret this value? Because we also have measured power. How should we calibrate the beacons correctly?Viviyan
O
34

The txPower mentioned by @davidgyoung is given by the formula:

RSSI = -10 n log d + A

where

  • d = distance
  • A = txPower
  • n = signal propagation constant
  • RSSI = dBm

In free space n = 2, but it will vary based on local geometry – for example, a wall will reduce RSSI by ~3dBm and will affect n accordingly.

If you want the highest possible accuracy, it may be worthwhile to experimentally determine these values for your particular system.

Reference: see the paper Evaluation of the Reliability of RSSI for Indoor Localization by Qian Dong and Waltenegus Dargie for a more detailed explanation of the derivation and calibration.

Omnidirectional answered 16/6, 2014 at 14:13 Comment(9)
Where do you have the value for n =2 i can not find it in the paper. How would this value change if I have obstacles in my way :)Convexity
Good question, I seem to recall gathering n = 2 from other references though I now notice in this paper n = 4.2119. These values likely reflect different experimental conditions for determining n.Omnidirectional
The reason n can vary so much is because signal propagation is affected by anything that causes interference in the transmitting waves e.g. walls. You can see how this works mathematically by looking at figure 1, imagining how the introduction of a wall would shift the data points, and seeing how n might change for the curve to better fit the data.Omnidirectional
Could you repair broken url to the mentioned paper?Mayhap
@Mayhap just updated the link and added the name of the paper in case it's moved again.Omnidirectional
@Omnidirectional thanks a lot! That reference might be really helpful.Mayhap
Choosing value for n is not exact science and it depends on the enviroment. Typical values are: 2 for free space, 2.7 to 3.5 for urban areas, 3.0 to 5.0 in suburban areas and 1.6 to 1.8 for indoors when there is line of sight to the router. You can have a look at this page: appelsiini.net/2017/trilateration-with-n-pointsPotful
Thank you! Thought, from the paper you mentioned, is it not - A in the end?Breechloader
Both sign conventions for txPower are common. The paper uses -A, so it's tx power value is negative, but the example in a previous comment as well as this answer https://mcmap.net/q/523547/-estimating-beacon-proximity-distance-based-on-rssi-bluetooth-le use positive tx powerOmnidirectional
C
29
double getDistance(int rssi, int txPower) {
    /*
     * RSSI = TxPower - 10 * n * lg(d)
     * n = 2 (in free space)
     * 
     * d = 10 ^ ((TxPower - RSSI) / (10 * n))
     */

    return Math.pow(10d, ((double) txPower - rssi) / (10 * 2));
}
Canvass answered 18/12, 2014 at 15:56 Comment(4)
According to above equation, when using kontakt beacon and kontakt SDK, just making one try I got the following: beacon.getAccuracy() = 1.87, getDistance() = 2.32.Lummox
how to get txPower from the Bluetooth Device?Cutanddried
hot to get this txPower ?Collimate
To answer on how to get txPower, "(...) and A [or txPower] is a reference received signal strength in dBm (the RSSI value measured when the separation distance between the receiver and the transmitter is one meter)." (ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=6402492) \\\/// "var txPower = -59 //hard coded power value. Usually ranges between -59 to -65" (developer.apple.com/forums/thread/656117) \\\/// ScanResult.getTxPower() (gist.github.com/jamesjmtaylor/77578aaed78ee02f475bbbbc85f88e65) - note for this last one, only from Oreo onwards, it seems...Breechloader
C
25

It is unclear whether your inability to read the "txPower" or "measuredPower" calibration constant is due to the AdRecord class or due to the information being missing from the advertisements you are trying to parse. It doesn't look to me like that class will parse a standard iBeacon advertisement. Either way, there is a solution:

SOLUTION 1: If your beacons send a standard iBeacon advertisement that includes the calibration constant, you can parse it out using code in the open source Android iBeacon Library's IBeacon class here.

SOLUTION 2: If your beacons DO NOT send a standard iBeacon advertisement or do not include a calibration constant:

You must hard-code a calibration constant in your app for each device type you might use. All you really need from the advertisement to estimate distance is the the RSSI measurement. The whole point of embedding a calibration constant in the transmission is to allow a wide variety of beacons with quite different transmitter output power to work with the same distance estimating algorithm.

The calibration constant, as defined by Apple, basically says what the RSSI should be if your device is exactly one meter away from the beacon. If the signal is stronger (less negative RSSI), then the device is less than one meter away. If the signal is weaker (more negative RSSI), then the device is over one meter away. You can use a formula to make a numerical estimate of distance. See here.

If you aren't dealing with advertisements that contain a "txPower" or "measuredPower" calibration constant, then you can hard-code a lookup table in your app that stores the known calibration constants for various transmitters. You will first need to measure the average RSSI of each transmitter at one meter away. You'll then need some kind of key to look up these calibration constants in the table. (Perhaps you can use the some part of the string from the AD structure, or the mac address?) So your table might look like this:

HashMap<String,Integer> txPowerLookupTable = new HashMap<String,Integer>();
txPowerLookupTable.put("a5:09:37:78:c3:22", new Integer(-65));
txPowerLookupTable.put("d2:32:33:5c:87:09", new Integer(-78));

Then after parsing an advertisement, you can look up the calibration constant in your onLeScan method like this:

String macAddress = device.getAddress();
Integer txPower = txPowerLookupTable.get(macAddress);
Cyanic answered 1/4, 2014 at 13:35 Comment(3)
Hey, my beacons do send the standard iBeacon advertisement. However, I'm using Ionic framework so can't use Android iBeacon Library directly at least, any way of doing it in JS ?Af
@Tushar, you should open a new question if you need help on this, but you can detect beacons with Ionic using the cordova-beacon-pulugin. See: thepolyglotdeveloper.com/2015/09/…Cyanic
We are trying to calibrate our beacons. The manufacturer has provided us with a table with the different values ​​of tx power (9 - 40 dBm. 8 -30 dBm...1 dBm 4). How should we interpret this value? Because we also have measured power. How should we calibrate the beacons correctly?Viviyan
H
-2

use the getAccuracy() method in the library, it gives you the distance of the beacon

Hessler answered 24/6, 2014 at 6:50 Comment(2)
The getAccuracy() method is not a dependable method to calculate the distance. Use it only to identify the difference between two beacons with the same RSSI value.Conventionalism
False. The "accuracy" value represents the width of one standard of deviation of the bell curve distribution of probable distance.Mogilev

© 2022 - 2024 — McMap. All rights reserved.