AltBeacon / spec

AltBeacon Technical Specification
http://altbeacon.org
208 stars 34 forks source link

Distance equation wrong? #30

Closed WallyHale closed 9 years ago

WallyHale commented 9 years ago

Testing Android and iOS devices side by side, using 7 beacons on their "loudest" setting (-63 Tx), we find that -

Distance, iOS (RSSI) 0m (-35), 1m (-63 = Tx), 2m (-70), 4.5m (-75), 10m (-80), 25 (-90)

Distance, Android (RSSI) 0m (-35), 1m (-63 = Tx), 1.2m (-70), 1.6m (-75), 2.7m (-80), 4 (-90)

Is it possible to either find a way to adjust parameter in the formula to mach iOS calculations closer or use liner approximation based on the experimental data above

davidgyoung commented 9 years ago

@WallyHale, you are correct in your observations. The current formula used by the library is imperfect and has real problems on underestimating distance for weaker transmitters.

We have been experimenting with a different formula in this branch here: https://github.com/AltBeacon/android-beacon-library/tree/path-loss-distance-calculations. We are trying to use this formula under the theory that we can simply calculate a single dB difference between the receiver sensitivity of various device models and apply that device-specific correction constant before calculating distance. If this works, it should give better distance estimates for different beacon transmitter power levels.

However, we are still having trouble because we are finding that the RSSI returned by some Android devices at larger distances is inconsistent with what would be expected. Doing tests with the Samsung Galaxy S6 vs. the iPhone, we found that the delta in the RSSI between the devices seeing the same beacon at various distances did not stay consistent:

The RSSI offset between the iPhone and the Galaxy S6 Edge + does not stay consistent with changes in distance. For this technique to work, we need the delta RSSI in dB to be consistent for a device even as the distance increases. Unfortunately, we saw RSSI numbers like this:

Rad Beacon Dot Beacon @ 1m
iPhone     Galaxy S6      Delta
-48.1        -50.8        -2.7

Rad Beacon Dot Beacon @ 5m
iPhone     Galaxy S6     Delta
-70.0       -81.1         -11.1

I'd appreciate help from folks with any expertise in this area to figure out a solution.

The RSSI offset between the iPhone and the Galaxy S6 Edge + does not stay consistent with changes in distance.

WallyHale commented 9 years ago

While I understand that it is VERY difficult to have a one solution fits all (especially with the variety of Android devices), that doesn't explain the distance calculations with similar, and consistent RSSI values.

If similar RSSI readings to that of an iOS device, the formula should be able to be tweaked so the distance calculation in relation to the RSSI should be somewhat accurate, or at least a lot more accurate than what we are currently seeing? ie. a -90 RSSI with a Tx of -63, should never equal 4 metres?

I too am seeing massive differences with the RSSI reading, when comparing a Nexus 5X to a Nexus 5, but difference in receivers and devices aside, the formula should be accurate for whatever RSSI / Tx values it's being fed.

If, in the end, the device has a stronger receiver, so the beacon appears closer than it actually is, this shouldn't matter, the important thing is a sound calculation when the RSSI's DO match

WallyHale commented 9 years ago

I just realised that the figures and explanation may be misleading.

The distance and RSSI quoted above is the calculated distance (beacon.getDistance()) value, NOT the actual physical distance of the device from the beacon.

So, the Android and iOS devices are side by side, moving away from beacon and taking readings, and the RSSI values are similar on both devices, but the calculated distance is wildly incorrect on Android compared to 1) the iOS distance reading 2) the actual physical distance the device is from the beacon

So this is not to do with the Bluetooth receiver picking up weaker signals, it's the calculation of the RSSI.

The beacons were physically ~25m from the devices, the RSSI are similar (-90), the Android device says the beacon is 4m away, while iOS more on the money.

I hope this clears any confusion!

davidgyoung commented 9 years ago

Understood. As I mentioned before, the current formula in the library has a significant flaw. It works well with higher powered transmitters but exhibits the results you see on lower power transmitters. This is why we proposed switching to a different formula that works better in the referenced pull request: https://github.com/AltBeacon/android-beacon-library/tree/path-loss-distance-calculations It will help the problem you see.

The trouble is that we have not gotten far enough with this formula to merge it into the release. I'd welcome any help you could give in testing with the branch associated with that pull request to see how well it predicts the distances on the devices you have.

WallyHale commented 9 years ago

Thanks @davidgyoung - I've built the path-loss-distance-calculation branch and included it in my project (removing the 2.6 build references to be certain), but I'm still seeing much shorter calculated distances when RSSI is -90 to -100 .. beacon.getDistance returns 5 metres or so away, when it's physically ~17 metres.

We'll keep investigating!

davidgyoung commented 9 years ago

Two things you can experiment with, @WallyHale:

  1. Try adjusting the 0.35 constant in the formula: distance = Math.pow(10.0, ((-adjustedRssi+txPower)/10*0.35)); This constant needs to be the same across all devices, but may be changed to give the best results.
  2. Try changing the receiver_rssi_offset for each of your mobile devices in model-distance-calculations-r2.json. This is designed to adjust the RSSI values you get to make them more similar to what an iOS device sees at the same distance. The theory is that a static offset can correct for differences in antenna gain.

I have been working at tuning this off and on for months, and would love to get this to the point where it gives consistently better results than the current built-in formula.

WallyHale commented 9 years ago

We have come up with a linear approximation algorithm that meets our needs, and importantly, giving similar and consistent readings to iOS on various devices tested.

davidhelms commented 9 years ago

Wally, that sounds very promising. Do you plan to submit a pull request to incorporate this into the library?

David Helms Chief Product Officer Radius Networks dhelms@radiusnetworks.com 703.582.1576

On Nov 20, 2015, at 7:34 AM, WallyHale notifications@github.com wrote:

We have come up with a linear approximation algorithm that meets our needs, and importantly, giving similar and consistent readings to iOS on various devices tested.

— Reply to this email directly or view it on GitHub https://github.com/AltBeacon/spec/issues/30#issuecomment-158386127.

davidgyoung commented 9 years ago

I'd love to see what you have come up with if you can share.

WallyHale commented 9 years ago

It probably won't suit all uses, but maybe you can work with / refine it further. The calculations were done from our testing at loudest beacon setting (-63), but it also works when changing beacon loudness to lower (weaker) values too without modifying the code.

public double calculateDistance(int tx, double rssi) {
    //define reference points based on iOS test
    //point 1
    double x_1 = (double) -35 / -63;
    double y_1 = 0;

    //point 2
    double x_2 = (double) -63 / -63;
    double y_2 = 1;

    //point 3
    double x_3 = (double) -70 / -63;
    double y_3 = 2;

    //point 4
    double x_4 = (double) -75 / -63;
    double y_4 = 4.5;

    //point 5
    double x_5 = (double) -80 / -63;
    double y_5 = 10;

    //point 6
    double x_6 = (double) -90 / -63;
    double y_6 = 25;

    //calculate relative signal strength the distance depends on
    double x = rssi / tx;

    //calculate distance
    double distance = 0.0;
    double x_startpoint = 0;
    double y_startpoint = 0;
    double x_endpoint = 0;
    double y_endpoint = 0;

    //check if x less than x_1 first, set distance to 0 in this case
    if (x < x_1)
        distance = 0.0;
    else // check if x is larger then x_6  set distance to unknown in this case
        if (x > x_6) distance = 0.0;
        else
            // find 2 points to use for approximation
            if (x >= x_5) {
                // x is between 5 and 6
                x_startpoint = x_5;
                y_startpoint = y_5;
                x_endpoint = x_6;
                y_endpoint = y_6;
            } else if (x >= x_4) {
                // x is between 4 and 5
                x_startpoint = x_4;
                y_startpoint = y_4;
                x_endpoint = x_5;
                y_endpoint = y_5;
            } else if (x >= x_3) {
                // x is between 3 and 4
                x_startpoint = x_3;
                y_startpoint = y_3;
                x_endpoint = x_4;
                y_endpoint = y_4;
            } else if (x >= x_2) {
                // x is between 2 and 3
                x_startpoint = x_2;
                y_startpoint = y_2;
                x_endpoint = x_3;
                y_endpoint = y_3;
            } else if (x >= x_1) {
                // x is between 1 and 2
                x_startpoint = x_1;
                y_startpoint = y_1;
                x_endpoint = x_2;
                y_endpoint = y_2;
            }

    Log.i("CalculateDistance", "x_startpoint= " + x_startpoint);
    Log.i("CalculateDistance", "y_startpoint= " + y_startpoint);
    Log.i("CalculateDistance", "x_endpoint= " + x_endpoint);
    Log.i("CalculateDistance", "y_endpoint= " + y_endpoint);

    // if we found 2 points use linear approximation formula below
    if (x_startpoint > 0 && x_endpoint > 0)
        distance = ((y_endpoint - y_startpoint) / (x_endpoint - x_startpoint)) * (x - x_startpoint) + y_startpoint;

    // display distance
    Log.i("CalculateDistance", "distance= " + distance);
    return distance;
}
davidgyoung commented 9 years ago

I have created an issue to track this here: https://github.com/AltBeacon/android-beacon-library/issues/318 as it is more appropriate to be in the repo for the Android Beacon Library.