iBeacon Receiver (MQTT, JAVA, 227L), problem with distance calculation

Hello,

I bought several receivers and various beacons to test their potential of application in BLE Real Time Location System. I just used iPhone 5s and AprilBeacon App from iStore to check the distance accuracy first and the 227L beacon provides best results. The problem that I encountered is very low accuracy of distance measured using iBeacon Receiver, JAVA and MQTT server. What may be the reason, lower quality of the bluetooth module inside, or maybe you have used better algorithms in IOS SDK?

For example using iPhone I have distance Approx. 4-5meters, but using beacon receiver located in the same place where iPhone I have output results Aprprox. 0,8m - 1.2 m.

My settings are:
Tx power: 0dBm (in fact it’s working as +10dBm, right?)
measuredPower: 57 (checked using calibration function from your IOS APP).
Advertising Freq: 8

Please find my code below, I will be grateful if you could take a look at this, maybe I mixed up something.

package testm;

import java.net.URISyntaxException;
import org.fusesource.mqtt.client.BlockingConnection;
import org.fusesource.mqtt.client.MQTT;
import org.fusesource.mqtt.client.Message;
import org.fusesource.mqtt.client.QoS;
import org.fusesource.mqtt.client.Topic;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

public class MClient {

public static Topic[] topics = {new Topic("/beacons", QoS.AT_MOST_ONCE)};

public static double getDistance(int measuredPower, double rssi) {
    if (rssi >= 0) {
        return -1.0;
    }
    if (measuredPower == 0) {
        return -1.0;
    }
    double ratio = rssi * 1.0 / measuredPower;
    if (ratio < 1.0) {
        System.out.println("measuredPower (ratio <1.0)" + measuredPower);
        System.out.println("rssi (ratio <1.0)" + rssi);
        return Math.pow(ratio, 10);
    } else {
        double distance = (0.42093) * Math.pow(ratio, 6.9476) + 0.54992;
        System.out.println("measuredPower" + measuredPower);
        System.out.println("rssi" + rssi);
        //double distance = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
        return distance;
    }
}

public static long parseUnsignedHex(String text) {
    if (text.length() == 16) {
        return (parseUnsignedHex(text.substring(0, 1)) << 60)
                | parseUnsignedHex(text.substring(1));
    }
    return Long.parseLong(text, 16);
}

public static void main(String[] args) {
    MQTT mqtt = new MQTT();
    try {
        // MQTT parameters
        mqtt.setHost("tcp://192.168.0.206:1883");
        mqtt.setClientId("beacons");
        mqtt.setCleanSession(true);
        mqtt.setReconnectAttemptsMax(6);
        mqtt.setReconnectDelay(2000);
        mqtt.setKeepAlive((short) 30);
        mqtt.setSendBufferSize(2 * 1024 * 1024);

        // MQTT BlockingConnection 
        BlockingConnection connection = mqtt.blockingConnection();
        connection.connect();
        if (connection.isConnected()) {
            System.out.println("connection success");
        } else {
            System.out.println("connection failed");
        }
        while (true) {
            Thread.sleep(1000);
            byte[] qoses = connection.subscribe(topics);
            Message message = connection.receive();
            byte[] payload = message.getPayload();
            message.ack();

            JSONParser parser = new JSONParser();
            Object obj = parser.parse(message.getPayloadBuffer().ascii().toString());
            JSONObject jsonObject = (JSONObject) obj;

            String[] splited = jsonObject.get("raw_beacons_data").toString().split(";");
            for (int i = 0; i < splited.length; i++) {

                // SHOW 227L BEACON (150m range) DATA ONLY
                if ("2091482669C7".equals(splited[i].substring(0, 12))) {
                    System.out.println("BEACON= " + splited[i].substring(0, 12));

                    // Get rssi value from raw data
                    String rssiHex = splited[i].substring(56, 58);
                    long rssiLong = parseUnsignedHex(rssiHex);
                    double rssi = Double.valueOf(rssiLong) - 256; // We need to subtract 255 for real rssi

                    // Get measured power from raw data
                    String measuredPowerHex = splited[i].substring(52, 54);
                    int measuredPower = Integer.parseInt(measuredPowerHex, 16) - 256; // We need to subtract 255 for real measuredPower

                    // Print out distance in meters
                    System.out.println(getDistance(measuredPower, rssi) + "m");
                }
            }
        }
    } catch (URISyntaxException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {

    }
}

}

Try to use: double distance =(0.89976)*Math.pow(ratio,7.7095)+0.111 in get Distance

I’ve tried it too without success, you can find this formula commented in the example code above.

Result is the same, distance is Aprox. 1.3m (and changes +/- 50cm) while my iPhone located in the same place says 3,70m (and changes +/- 10cm), iPhone value is correct.

Interesting is RSSI for both devices:

On the iPhone RSSI varies between -57 and -64
On the iBeaaconReceiver RSSI varies between -62 to -66

So I’ve changed RSSI (minus 5 each time before calling the function getDistance), and now RSSI and MeasuredPower seems to be the same as for iPhone App, but still there is a big difference in measured distance. I think there must be a difference in algorithms of obtaining a distance value.

Could you help me somehow? Maybe could you share with me the distance methods from iOS SDK?

Best Regards,
Kamil Radzik

https://developer.apple.com/library/ios/samplecode/AirLocate/Introduction/Intro.html

Did you find any solution for this?

I am afraid that there is no better (more accurate) solution for these iBeacon Receivers.

Finally I’m just using following formula to calc. dist.: return (0.89976) * Math.pow(ratio, 7.7095) + 0.111;

In my project it’s enought to achieve about 1m precision in 5x5m square rooms, but I had to implement partical filter algorithm to locate objects. Maybe soon Bluetooth 5.0 will be able to do it better.