From d6fbf9afcade8e402ac25997c47c4c1e498e891d Mon Sep 17 00:00:00 2001 From: "David G. Young" Date: Sun, 26 Jul 2015 15:01:12 -0400 Subject: [PATCH 1/5] Add path loss distance calculation algorithm --- .../beacon/distance/AndroidModel.java | 50 ++++++++++++++++ .../ModelSpecificDistanceCalculator.java | 53 +++++++++++++---- .../distance/PathLossDistanceCalculator.java | 58 +++++++++++++++++++ .../model-distance-calculations.json | 23 ++++++++ .../ModelSpecificDistanceCalculatorTest.java | 34 +++++++++++ .../model-distance-calculations.json | 29 +++++++++- 6 files changed, 232 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java diff --git a/src/main/java/org/altbeacon/beacon/distance/AndroidModel.java b/src/main/java/org/altbeacon/beacon/distance/AndroidModel.java index d934a428d..835d96502 100644 --- a/src/main/java/org/altbeacon/beacon/distance/AndroidModel.java +++ b/src/main/java/org/altbeacon/beacon/distance/AndroidModel.java @@ -91,6 +91,56 @@ public int matchScore(AndroidModel otherModel) { return score; } + /** + * Calculates a qualitative match score between two different Android device models for the + * purposes of how likely they are to have similar Bluetooth signal level responses + * This algorithm takes into account partial matches of model strings, as Samsung devices + * commonly have different model name suffixes + * @param otherModel + * @return match quality, higher numbers are a better match + */ + public double matchScoreWithPartialModel(AndroidModel otherModel) { + double score = 0; + if (this.mManufacturer.equalsIgnoreCase(otherModel.mManufacturer)) { + score = 1; + } + if (score == 1 ) { + score = 1+ratioOfMatchingPrefixCharacters(this.getModel(), otherModel.getModel()); + } + LogManager.d(TAG, "Score is %s for %s compared to %s", score, toString(), otherModel); + return score; + } + + /** + * Returns 1.0 if the string is a complete match, 0.0 if the first characters are different + * and 0.5 if the first halves of each string match. Not case sensitive. + * @param string1 + * @param string2 + * @return + */ + private double ratioOfMatchingPrefixCharacters(String string1, String string2) { + int maxLength = 0; + int minLength = 0; + int matchingChars = 0; + String lower1 = string1.toLowerCase(); + String lower2 = string2.toLowerCase(); + if (string2.length() >= string1.length()) { + maxLength = string2.length(); + minLength = string1.length(); + } + else { + maxLength = string1.length(); + minLength = string2.length(); + } + + for (int i = 0; i < minLength; i++) { + if (lower1.charAt(i) == lower2.charAt(i)) { + matchingChars++; + } + } + return 1.0*matchingChars/maxLength; + } + @Override public String toString() { return ""+mManufacturer+";"+mModel+";"+mBuildNumber+";"+mVersion; diff --git a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java index bd3069c77..68eeb7ddb 100644 --- a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java +++ b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java @@ -55,6 +55,7 @@ public class ModelSpecificDistanceCalculator implements DistanceCalculator { private String mRemoteUpdateUrlString = null; private Context mContext; private ReentrantLock mLock = new ReentrantLock(); + private static String sCalculatorClassName = CurveFittedDistanceCalculator.class.getName(); /** * Obtains the best possible DistanceCalculator for the Android device calling @@ -64,6 +65,14 @@ public ModelSpecificDistanceCalculator(Context context, String remoteUpdateUrlSt this(context, remoteUpdateUrlString, AndroidModel.forThisDevice()); } + /** + * Configures the distnace calculator to be used + * @param className + */ + public static void setDistanceCalculatorClassName(String className) { + sCalculatorClassName = className; + } + /** * Obtains the best possible DistanceCalculator for the Android device passed * as an argument @@ -118,11 +127,11 @@ private DistanceCalculator findCalculatorForModel(AndroidModel model) { return null; } - int highestScore = 0; + double highestScore = 0; AndroidModel bestMatchingModel = null; for (AndroidModel candidateModel : mModelMap.keySet()) { - if (candidateModel.matchScore(model) > highestScore) { - highestScore = candidateModel.matchScore(model); + if (candidateModel.matchScoreWithPartialModel(model) > highestScore) { + highestScore = candidateModel.matchScoreWithPartialModel(model); bestMatchingModel = candidateModel; } } @@ -274,21 +283,41 @@ private void buildModelMap(String jsonString) throws JSONException { if (modelObject.has("default")) { defaultFlag = modelObject.getBoolean("default"); } - Double coefficient1 = modelObject.getDouble("coefficient1"); - Double coefficient2 = modelObject.getDouble("coefficient2"); - Double coefficient3 = modelObject.getDouble("coefficient3"); + String version = modelObject.getString("version"); String buildNumber = modelObject.getString("build_number"); String model = modelObject.getString("model"); String manufacturer = modelObject.getString("manufacturer"); + AndroidModel androidModel = new AndroidModel(version, buildNumber, model, manufacturer); - CurveFittedDistanceCalculator distanceCalculator = - new CurveFittedDistanceCalculator(coefficient1,coefficient2,coefficient3); + DistanceCalculator distanceCalculator = null; + if (sCalculatorClassName.equals(CurveFittedDistanceCalculator.class.getName())) { + Double coefficient1 = modelObject.optDouble("coefficient1"); + Double coefficient2 = modelObject.optDouble("coefficient2"); + Double coefficient3 = modelObject.optDouble("coefficient3"); - AndroidModel androidModel = new AndroidModel(version, buildNumber, model, manufacturer); - mModelMap.put(androidModel, distanceCalculator); - if (defaultFlag) { - mDefaultModel = androidModel; + if (!coefficient1.isNaN() && !coefficient2.isNaN() && !coefficient3.isNaN()) { + distanceCalculator = + new CurveFittedDistanceCalculator(coefficient1,coefficient2,coefficient3); + } + } + else if (sCalculatorClassName.equals(PathLossDistanceCalculator.class.getName())) { + Double receiverRssiOffset = modelObject.optDouble("receiver_rssi_offset"); + if (!receiverRssiOffset.isNaN()) { + distanceCalculator = + new PathLossDistanceCalculator(receiverRssiOffset); + } + } + + if (distanceCalculator != null) { + mModelMap.put(androidModel, distanceCalculator); + if (defaultFlag) { + mDefaultModel = androidModel; + } + } + else { + LogManager.w(TAG, "No distance calculator may be constructed for model "+androidModel+ + " because data are missing for configured calculator "+sCalculatorClassName); } } } diff --git a/src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java b/src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java new file mode 100644 index 000000000..63b87a311 --- /dev/null +++ b/src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java @@ -0,0 +1,58 @@ +package org.altbeacon.beacon.distance; + +import org.altbeacon.beacon.logging.LogManager; + +/** + * This class estimates the distance between the mobile device and a BLE beacon based on the measured + * RSSI and a txPower calibration value that represents the expected RSSI for an iPhone 5 receiving + * the signal when it is 1 meter away. + *

+ * This class uses a path loss equation with a receiverRssiOffset parameter. The offset must + * be supplied by the caller and is specific to the Android device being used. See the + * ModelSpecificDistanceCalculator for more information on the offset. + *

+ * Created by dyoung on 7/26/15. + */ +public class PathLossDistanceCalculator implements DistanceCalculator { + + public static final String TAG = "PathLossDistanceCalculator"; + private double mReceiverRssiOffset; + + /** + * Construct a calculator with an offset specific for the device's antenna gain + * + * @param receiverRssiOffset + */ + public PathLossDistanceCalculator(double receiverRssiOffset) { + mReceiverRssiOffset = receiverRssiOffset; + } + + /** + * Calculated the estimated distance in meters to the beacon based on a reference rssi at 1m + * and the known actual rssi at the current location + * + * @param txPower + * @param rssi + * @return estimated distance + */ + @Override + public double calculateDistance(int txPower, double rssi) { + if (rssi == 0) { + return -1.0; // if we cannot determine accuracy, return -1. + } + + LogManager.d(TAG, "calculating distance based on mRssi of %s and txPower of %s", rssi, txPower); + + + double ratio = rssi * 1.0 / txPower; + double distance; + if (ratio < 1.0) { + distance = Math.pow(ratio, 10); + } else { + distance = Math.pow(10.0, ((-rssi+mReceiverRssiOffset+txPower)/10*0.41)); + + } + LogManager.d(TAG, "avg mRssi: %s distance: %s", rssi, distance); + return distance; + } +} diff --git a/src/main/resources/model-distance-calculations.json b/src/main/resources/model-distance-calculations.json index 015f30ec8..2c1b20a2e 100644 --- a/src/main/resources/model-distance-calculations.json +++ b/src/main/resources/model-distance-calculations.json @@ -14,11 +14,34 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, + "receiver_rssi_offset": -2.5, "version":"4.4.2", "build_number":"LPV79", "model":"Nexus 5", "manufacturer":"LGE", "default": true + }, + { + "receiver_rssi_offset": -17.25, + "version":"5.1.1", + "build_number":"LVY48C", + "model":"Moto G", + "manufacturer":"motorola" + }, + { + "receiver_rssi_offset": -21.25, + "version":"5.0", + "build_number":"LRX21T", + "model":"SM-G900V", + "manufacturer":"samsung" + }, + { + "receiver_rssi_offset": -0.25, + "version":"4.4.2", + "build_number":"KOT49H", + "model":"SCH-I535", + "manufacturer":"samsung" } + ] } diff --git a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java index 0a97f1ad2..4f242660d 100644 --- a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java +++ b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java @@ -30,11 +30,35 @@ public class ModelSpecificDistanceCalculatorTest { public void testCalculatesDistance() { org.robolectric.shadows.ShadowLog.stream = System.err; + ModelSpecificDistanceCalculator.setDistanceCalculatorClassName(CurveFittedDistanceCalculator.class.getName()); ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null); Double distance = distanceCalculator.calculateDistance(-59, -59); assertEquals("Distance should be 1.0 for same power and rssi", 1.0, distance, 0.1); } + @Test + public void testCalculatesDistanceAt10MetersOnANexus5() { + org.robolectric.shadows.ShadowLog.stream = System.err; + AndroidModel model = new AndroidModel("5.0.0", "LPV79","Nexus 5","LGE"); + + ModelSpecificDistanceCalculator.setDistanceCalculatorClassName(CurveFittedDistanceCalculator.class.getName()); + ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); + Double distance = distanceCalculator.calculateDistance(-45,-71); + assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); + } + + @Test + public void testCalculatesDistanceAt10MetersOnANexus5WithPathLossFormula() { + org.robolectric.shadows.ShadowLog.stream = System.err; + AndroidModel model = new AndroidModel("5.0.0", "LPV79","Nexus 5","LGE"); + ModelSpecificDistanceCalculator.setDistanceCalculatorClassName(PathLossDistanceCalculator.class.getName()); + + ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); + Double distance = distanceCalculator.calculateDistance(-45,-71); + assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); + } + + @Test public void testSelectsDefaultModel() { org.robolectric.shadows.ShadowLog.stream = System.err; @@ -52,6 +76,16 @@ public void testSelectsNexus4OnExactMatch() { assertEquals("should be Nexus 4", "Nexus 4", distanceCalculator.getModel().getModel()); } + @Test + public void testSelectsSamsungS3OnEPartialMatch() { + org.robolectric.shadows.ShadowLog.stream = System.err; + AndroidModel model = new AndroidModel("4.4.4.4.4", "nonsense","SCH-I536","samsung"); + ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); + assertEquals("should be S3 SCH-I535", "SCH-I535", distanceCalculator.getModel().getModel()); + } + + + @Test public void testConcurrentModificationException() { org.robolectric.shadows.ShadowLog.stream = System.err; diff --git a/src/test/resources/model-distance-calculations.json b/src/test/resources/model-distance-calculations.json index 64b445460..2c1b20a2e 100644 --- a/src/test/resources/model-distance-calculations.json +++ b/src/test/resources/model-distance-calculations.json @@ -2,9 +2,9 @@ "models": [ { - "coefficient1": 0.89976, - "coefficient2": 7.7095, - "coefficient3": 0.111, + "coefficient1": 0.42093, + "coefficient2": 6.9476, + "coefficient3": 0.54992, "version":"4.4.2", "build_number":"KOT49H", "model":"Nexus 4", @@ -14,11 +14,34 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, + "receiver_rssi_offset": -2.5, "version":"4.4.2", "build_number":"LPV79", "model":"Nexus 5", "manufacturer":"LGE", "default": true + }, + { + "receiver_rssi_offset": -17.25, + "version":"5.1.1", + "build_number":"LVY48C", + "model":"Moto G", + "manufacturer":"motorola" + }, + { + "receiver_rssi_offset": -21.25, + "version":"5.0", + "build_number":"LRX21T", + "model":"SM-G900V", + "manufacturer":"samsung" + }, + { + "receiver_rssi_offset": -0.25, + "version":"4.4.2", + "build_number":"KOT49H", + "model":"SCH-I535", + "manufacturer":"samsung" } + ] } From 122450489d2456571565454ff13e3c14bd3aaa9c Mon Sep 17 00:00:00 2001 From: "David G. Young" Date: Sun, 26 Jul 2015 23:02:56 -0400 Subject: [PATCH 2/5] Use different filename for new calculator config. Set new calculator via class not class name. --- .../org/altbeacon/beacon/BeaconManager.java | 2 +- .../ModelSpecificDistanceCalculator.java | 18 +++---- .../model-distance-calculations-r2.json | 47 ++++++++++++++++++ .../model-distance-calculations.json | 23 --------- .../ModelSpecificDistanceCalculatorTest.java | 14 ++++-- .../model-distance-calculations-r2.json | 48 +++++++++++++++++++ .../model-distance-calculations.json | 23 --------- 7 files changed, 115 insertions(+), 60 deletions(-) create mode 100644 src/main/resources/model-distance-calculations-r2.json create mode 100644 src/test/resources/model-distance-calculations-r2.json diff --git a/src/main/java/org/altbeacon/beacon/BeaconManager.java b/src/main/java/org/altbeacon/beacon/BeaconManager.java index fa057341c..1c580ba61 100644 --- a/src/main/java/org/altbeacon/beacon/BeaconManager.java +++ b/src/main/java/org/altbeacon/beacon/BeaconManager.java @@ -668,7 +668,7 @@ public static void logDebug(String tag, String message, Throwable t) { protected static BeaconSimulator beaconSimulator; - protected static String distanceModelUpdateUrl = "http://data.altbeacon.org/android-distance.json"; + protected static String distanceModelUpdateUrl = "http://data.altbeacon.org/android-distance-r2.json"; public static String getDistanceModelUpdateUrl() { return distanceModelUpdateUrl; diff --git a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java index 68eeb7ddb..f398decba 100644 --- a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java +++ b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java @@ -46,7 +46,7 @@ */ public class ModelSpecificDistanceCalculator implements DistanceCalculator { Map mModelMap; - private static final String CONFIG_FILE = "model-distance-calculations.json"; + private static final String CONFIG_FILE = "model-distance-calculations-r2.json"; private static final String TAG = "ModelSpecificDistanceCalculator"; private AndroidModel mDefaultModel; private DistanceCalculator mDistanceCalculator; @@ -55,7 +55,7 @@ public class ModelSpecificDistanceCalculator implements DistanceCalculator { private String mRemoteUpdateUrlString = null; private Context mContext; private ReentrantLock mLock = new ReentrantLock(); - private static String sCalculatorClassName = CurveFittedDistanceCalculator.class.getName(); + private static Class sCalculatorClass = CurveFittedDistanceCalculator.class; /** * Obtains the best possible DistanceCalculator for the Android device calling @@ -66,11 +66,11 @@ public ModelSpecificDistanceCalculator(Context context, String remoteUpdateUrlSt } /** - * Configures the distnace calculator to be used - * @param className + * Configures the distance calculator to be used + * @param klass */ - public static void setDistanceCalculatorClassName(String className) { - sCalculatorClassName = className; + public static void setDistanceCalculatorClass(Class klass) { + sCalculatorClass = klass; } /** @@ -291,7 +291,7 @@ private void buildModelMap(String jsonString) throws JSONException { AndroidModel androidModel = new AndroidModel(version, buildNumber, model, manufacturer); DistanceCalculator distanceCalculator = null; - if (sCalculatorClassName.equals(CurveFittedDistanceCalculator.class.getName())) { + if (sCalculatorClass.equals(CurveFittedDistanceCalculator.class)) { Double coefficient1 = modelObject.optDouble("coefficient1"); Double coefficient2 = modelObject.optDouble("coefficient2"); Double coefficient3 = modelObject.optDouble("coefficient3"); @@ -301,7 +301,7 @@ private void buildModelMap(String jsonString) throws JSONException { new CurveFittedDistanceCalculator(coefficient1,coefficient2,coefficient3); } } - else if (sCalculatorClassName.equals(PathLossDistanceCalculator.class.getName())) { + else if (sCalculatorClass.equals(PathLossDistanceCalculator.class)) { Double receiverRssiOffset = modelObject.optDouble("receiver_rssi_offset"); if (!receiverRssiOffset.isNaN()) { distanceCalculator = @@ -317,7 +317,7 @@ else if (sCalculatorClassName.equals(PathLossDistanceCalculator.class.getName()) } else { LogManager.w(TAG, "No distance calculator may be constructed for model "+androidModel+ - " because data are missing for configured calculator "+sCalculatorClassName); + " because data are missing for configured calculator "+sCalculatorClass.getName()); } } } diff --git a/src/main/resources/model-distance-calculations-r2.json b/src/main/resources/model-distance-calculations-r2.json new file mode 100644 index 000000000..2c1b20a2e --- /dev/null +++ b/src/main/resources/model-distance-calculations-r2.json @@ -0,0 +1,47 @@ +{ + "models": + [ + { + "coefficient1": 0.42093, + "coefficient2": 6.9476, + "coefficient3": 0.54992, + "version":"4.4.2", + "build_number":"KOT49H", + "model":"Nexus 4", + "manufacturer":"LGE" + }, + { + "coefficient1": 0.42093, + "coefficient2": 6.9476, + "coefficient3": 0.54992, + "receiver_rssi_offset": -2.5, + "version":"4.4.2", + "build_number":"LPV79", + "model":"Nexus 5", + "manufacturer":"LGE", + "default": true + }, + { + "receiver_rssi_offset": -17.25, + "version":"5.1.1", + "build_number":"LVY48C", + "model":"Moto G", + "manufacturer":"motorola" + }, + { + "receiver_rssi_offset": -21.25, + "version":"5.0", + "build_number":"LRX21T", + "model":"SM-G900V", + "manufacturer":"samsung" + }, + { + "receiver_rssi_offset": -0.25, + "version":"4.4.2", + "build_number":"KOT49H", + "model":"SCH-I535", + "manufacturer":"samsung" + } + + ] +} diff --git a/src/main/resources/model-distance-calculations.json b/src/main/resources/model-distance-calculations.json index 2c1b20a2e..015f30ec8 100644 --- a/src/main/resources/model-distance-calculations.json +++ b/src/main/resources/model-distance-calculations.json @@ -14,34 +14,11 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, - "receiver_rssi_offset": -2.5, "version":"4.4.2", "build_number":"LPV79", "model":"Nexus 5", "manufacturer":"LGE", "default": true - }, - { - "receiver_rssi_offset": -17.25, - "version":"5.1.1", - "build_number":"LVY48C", - "model":"Moto G", - "manufacturer":"motorola" - }, - { - "receiver_rssi_offset": -21.25, - "version":"5.0", - "build_number":"LRX21T", - "model":"SM-G900V", - "manufacturer":"samsung" - }, - { - "receiver_rssi_offset": -0.25, - "version":"4.4.2", - "build_number":"KOT49H", - "model":"SCH-I535", - "manufacturer":"samsung" } - ] } diff --git a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java index 4f242660d..09d3e3380 100644 --- a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java +++ b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java @@ -3,6 +3,7 @@ import android.content.Context; import org.junit.Test; +import org.junit.Before; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; @@ -26,11 +27,16 @@ * Created by dyoung on 8/28/14. */ public class ModelSpecificDistanceCalculatorTest { + + @Before + public void setup() { + ModelSpecificDistanceCalculator.setDistanceCalculatorClass(CurveFittedDistanceCalculator.class); + } + @Test public void testCalculatesDistance() { org.robolectric.shadows.ShadowLog.stream = System.err; - ModelSpecificDistanceCalculator.setDistanceCalculatorClassName(CurveFittedDistanceCalculator.class.getName()); ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null); Double distance = distanceCalculator.calculateDistance(-59, -59); assertEquals("Distance should be 1.0 for same power and rssi", 1.0, distance, 0.1); @@ -41,7 +47,6 @@ public void testCalculatesDistanceAt10MetersOnANexus5() { org.robolectric.shadows.ShadowLog.stream = System.err; AndroidModel model = new AndroidModel("5.0.0", "LPV79","Nexus 5","LGE"); - ModelSpecificDistanceCalculator.setDistanceCalculatorClassName(CurveFittedDistanceCalculator.class.getName()); ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); Double distance = distanceCalculator.calculateDistance(-45,-71); assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); @@ -51,7 +56,7 @@ public void testCalculatesDistanceAt10MetersOnANexus5() { public void testCalculatesDistanceAt10MetersOnANexus5WithPathLossFormula() { org.robolectric.shadows.ShadowLog.stream = System.err; AndroidModel model = new AndroidModel("5.0.0", "LPV79","Nexus 5","LGE"); - ModelSpecificDistanceCalculator.setDistanceCalculatorClassName(PathLossDistanceCalculator.class.getName()); + ModelSpecificDistanceCalculator.setDistanceCalculatorClass(PathLossDistanceCalculator.class); ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); Double distance = distanceCalculator.calculateDistance(-45,-71); @@ -79,6 +84,7 @@ public void testSelectsNexus4OnExactMatch() { @Test public void testSelectsSamsungS3OnEPartialMatch() { org.robolectric.shadows.ShadowLog.stream = System.err; + ModelSpecificDistanceCalculator.setDistanceCalculatorClass(PathLossDistanceCalculator.class); AndroidModel model = new AndroidModel("4.4.4.4.4", "nonsense","SCH-I536","samsung"); ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); assertEquals("should be S3 SCH-I535", "SCH-I535", distanceCalculator.getModel().getModel()); @@ -94,7 +100,7 @@ public void testConcurrentModificationException() { final AndroidModel model = new AndroidModel("4.4.2", "KOT49H", "Nexus 4", "LGE"); final String modelMapJson = - "{\"models\":[ \"coefficient1\": 0.89976,\"coefficient2\": 7.7095,\"coefficient3\": 0.111," + + "{\"models\":[ {\"coefficient1\": 0.89976,\"coefficient2\": 7.7095,\"coefficient3\": 0.111," + "\"version\":\"4.4.2\",\"build_number\":\"KOT49H\",\"model\":\"Nexus 4\"," + "\"manufacturer\":\"LGE\"},{\"coefficient1\": 0.42093,\"coefficient2\": 6.9476," + "\"coefficient3\": 0.54992,\"version\":\"4.4.2\",\"build_number\":\"LPV79\"," + diff --git a/src/test/resources/model-distance-calculations-r2.json b/src/test/resources/model-distance-calculations-r2.json new file mode 100644 index 000000000..870860edd --- /dev/null +++ b/src/test/resources/model-distance-calculations-r2.json @@ -0,0 +1,48 @@ +{ + "models": + [ + { + "coefficient1": 0.42093, + "coefficient2": 6.9476, + "coefficient3": 0.54992, + "receiver_rssi_offset": -2.5, + "version":"4.4.2", + "build_number":"KOT49H", + "model":"Nexus 4", + "manufacturer":"LGE" + }, + { + "coefficient1": 0.42093, + "coefficient2": 6.9476, + "coefficient3": 0.54992, + "receiver_rssi_offset": -2.5, + "version":"4.4.2", + "build_number":"LPV79", + "model":"Nexus 5", + "manufacturer":"LGE", + "default": true + }, + { + "receiver_rssi_offset": -17.25, + "version":"5.1.1", + "build_number":"LVY48C", + "model":"Moto G", + "manufacturer":"motorola" + }, + { + "receiver_rssi_offset": -21.25, + "version":"5.0", + "build_number":"LRX21T", + "model":"SM-G900V", + "manufacturer":"samsung" + }, + { + "receiver_rssi_offset": -0.25, + "version":"4.4.2", + "build_number":"KOT49H", + "model":"SCH-I535", + "manufacturer":"samsung" + } + + ] +} diff --git a/src/test/resources/model-distance-calculations.json b/src/test/resources/model-distance-calculations.json index 2c1b20a2e..015f30ec8 100644 --- a/src/test/resources/model-distance-calculations.json +++ b/src/test/resources/model-distance-calculations.json @@ -14,34 +14,11 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, - "receiver_rssi_offset": -2.5, "version":"4.4.2", "build_number":"LPV79", "model":"Nexus 5", "manufacturer":"LGE", "default": true - }, - { - "receiver_rssi_offset": -17.25, - "version":"5.1.1", - "build_number":"LVY48C", - "model":"Moto G", - "manufacturer":"motorola" - }, - { - "receiver_rssi_offset": -21.25, - "version":"5.0", - "build_number":"LRX21T", - "model":"SM-G900V", - "manufacturer":"samsung" - }, - { - "receiver_rssi_offset": -0.25, - "version":"4.4.2", - "build_number":"KOT49H", - "model":"SCH-I535", - "manufacturer":"samsung" } - ] } From fe75acfc47a8d171b070951011d842e952d25fd9 Mon Sep 17 00:00:00 2001 From: "David G. Young" Date: Thu, 22 Oct 2015 10:55:43 -0400 Subject: [PATCH 3/5] add more model distance offsets, tests, and debugging info --- .../ModelSpecificDistanceCalculator.java | 7 ++++--- .../model-distance-calculations-r2.json | 13 ++++++++++--- .../java/org/altbeacon/beacon/RegionTest.java | 17 +++++++++++++++++ .../ModelSpecificDistanceCalculatorTest.java | 10 ++++++++++ .../model-distance-calculations-r2.json | 11 +++++++++-- 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java index dc75255ec..0fe88eadb 100644 --- a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java +++ b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java @@ -78,6 +78,7 @@ public static void setDistanceCalculatorClass(Class klass) { * as an argument */ public ModelSpecificDistanceCalculator(Context context, String remoteUpdateUrlString, AndroidModel model) { + LogManager.i(TAG, "Constructing model distance database"); mRequestedModel = model; mRemoteUpdateUrlString = remoteUpdateUrlString; mContext = context; @@ -118,12 +119,12 @@ DistanceCalculator findCalculatorForModelWithLock(AndroidModel model) { } private DistanceCalculator findCalculatorForModel(AndroidModel model) { - LogManager.d(TAG, "Finding best distance calculator for %s, %s, %s, %s", + LogManager.i(TAG, "Finding best distance calculator for %s, %s, %s, %s", model.getVersion(), model.getBuildNumber(), model.getModel(), model.getManufacturer()); if (mModelMap == null) { - LogManager.d(TAG, "Cannot get distance calculator because modelMap was never initialized"); + LogManager.e(TAG, "Cannot get distance calculator because modelMap was never initialized"); return null; } @@ -137,7 +138,7 @@ private DistanceCalculator findCalculatorForModel(AndroidModel model) { } if (bestMatchingModel != null) { LogManager.d(TAG, "found a match with score %s", highestScore); - LogManager.d(TAG, "Finding best distance calculator for %s, %s, %s, %s", + LogManager.i(TAG, "Using best match distance calculator for %s, %s, %s, %s", bestMatchingModel.getVersion(), bestMatchingModel.getBuildNumber(), bestMatchingModel.getModel(), bestMatchingModel.getManufacturer()); mModel = bestMatchingModel; diff --git a/src/main/resources/model-distance-calculations-r2.json b/src/main/resources/model-distance-calculations-r2.json index 2c1b20a2e..4df854552 100644 --- a/src/main/resources/model-distance-calculations-r2.json +++ b/src/main/resources/model-distance-calculations-r2.json @@ -5,6 +5,7 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, + "receiver_rssi_offset": -2.5, "version":"4.4.2", "build_number":"KOT49H", "model":"Nexus 4", @@ -22,7 +23,7 @@ "default": true }, { - "receiver_rssi_offset": -17.25, + "receiver_rssi_offset": -10, "version":"5.1.1", "build_number":"LVY48C", "model":"Moto G", @@ -36,12 +37,18 @@ "manufacturer":"samsung" }, { - "receiver_rssi_offset": -0.25, + "receiver_rssi_offset": -4, "version":"4.4.2", "build_number":"KOT49H", "model":"SCH-I535", "manufacturer":"samsung" + }, + { + "receiver_rssi_offset": -0.5, + "version":"5.1.1", + "build_number":"LMY47X.G928TUVU2COI5", + "model":"SM-G928T", + "manufacturer":"samsung" } - ] } diff --git a/src/test/java/org/altbeacon/beacon/RegionTest.java b/src/test/java/org/altbeacon/beacon/RegionTest.java index e6dca7ae8..34d64feca 100644 --- a/src/test/java/org/altbeacon/beacon/RegionTest.java +++ b/src/test/java/org/altbeacon/beacon/RegionTest.java @@ -175,5 +175,22 @@ public void testConvenienceIdentifierAccessors() { assertEquals("3", region.getId3().toString()); } + @Test + public void testSingleIdentifierMatchesWildcardRegion() { + ArrayList idlist = new ArrayList(1); + idlist.add(Identifier.fromInt(123)); + + Beacon beacon = new Beacon.Builder() + .setIdentifiers(idlist) + .setManufacturer(0x4c) + .setTxPower(-59) + .build(); + + Region region = new Region("com.example.myapp.boostrapRegion", null, null, null); + + assertTrue("Beacon should match region", region.matchesBeacon(beacon)); + } + + } diff --git a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java index 09d3e3380..50da708c4 100644 --- a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java +++ b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java @@ -63,6 +63,16 @@ public void testCalculatesDistanceAt10MetersOnANexus5WithPathLossFormula() { assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); } + @Test + public void testCalculatesDistanceAt10MetersOnAGalaxyS6EdgePlusWithPathLossFormula() { + org.robolectric.shadows.ShadowLog.stream = System.err; + AndroidModel model = new AndroidModel("5.1.1", "LMY47X.G928TUVU2COI5","SM-G928T","samsung"); + ModelSpecificDistanceCalculator.setDistanceCalculatorClass(PathLossDistanceCalculator.class); + + ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); + Double distance = distanceCalculator.calculateDistance(-50,-75); + assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); + } @Test public void testSelectsDefaultModel() { diff --git a/src/test/resources/model-distance-calculations-r2.json b/src/test/resources/model-distance-calculations-r2.json index 870860edd..066bc20ee 100644 --- a/src/test/resources/model-distance-calculations-r2.json +++ b/src/test/resources/model-distance-calculations-r2.json @@ -23,7 +23,7 @@ "default": true }, { - "receiver_rssi_offset": -17.25, + "receiver_rssi_offset": -10, "version":"5.1.1", "build_number":"LVY48C", "model":"Moto G", @@ -37,11 +37,18 @@ "manufacturer":"samsung" }, { - "receiver_rssi_offset": -0.25, + "receiver_rssi_offset": -4, "version":"4.4.2", "build_number":"KOT49H", "model":"SCH-I535", "manufacturer":"samsung" + }, + { + "receiver_rssi_offset": -0.5, + "version":"5.1.1", + "build_number":"LMY47X.G928TUVU2COI5", + "model":"SM-G928T", + "manufacturer":"samsung" } ] From f0e1cb305acb51810385e1d3d644aa79eaf7ce77 Mon Sep 17 00:00:00 2001 From: "David G. Young" Date: Wed, 4 Nov 2015 20:09:38 -0500 Subject: [PATCH 4/5] Added abilty to track advertisement counts and running average rssi in client --- .../java/org/altbeacon/beacon/Beacon.java | 37 +++++++++++++++++++ .../beacon/service/BeaconService.java | 1 + .../beacon/service/RangedBeacon.java | 5 +++ .../java/org/altbeacon/beacon/BeaconTest.java | 2 + 4 files changed, 45 insertions(+) diff --git a/src/main/java/org/altbeacon/beacon/Beacon.java b/src/main/java/org/altbeacon/beacon/Beacon.java index 8a2777347..e76e1362b 100644 --- a/src/main/java/org/altbeacon/beacon/Beacon.java +++ b/src/main/java/org/altbeacon/beacon/Beacon.java @@ -126,6 +126,11 @@ public class Beacon implements Parcelable { */ protected int mBeaconTypeCode; + /** + * A count of the number of advertisements detected + */ + protected long mAdvertisementCount; + /** * A two byte code indicating the beacon manufacturer. A list of registered manufacturer codes * may be found here: @@ -223,6 +228,10 @@ protected Beacon(Parcel in) { } mManufacturer = in.readInt(); mBluetoothName = in.readString(); + // This nonsense is needed because we can't do readDouble on null values. + // See: http://stackoverflow.com/a/10769887/1461050 + mRunningAverageRssi = (Double) in.readValue(Double.class.getClassLoader()); + mAdvertisementCount = in.readLong(); } /** @@ -262,6 +271,18 @@ public void setRunningAverageRssi(double rssi) { mDistance = null; // force calculation of accuracy and proximity next time they are requested } + /** + * Gets the running average rssi, if available, otherwise get the latest rssi + */ + public double getRunningAverageRssi() { + if (mRunningAverageRssi != null) { + return mRunningAverageRssi; + } + else { + return getRssi(); + } + } + /** * Sets the most recently measured rssi for use in distance calculations if a running average is * not available @@ -367,6 +388,20 @@ public List getIdentifiers() { } } + /** + * @see #mAdvertisementCount + */ + public long getAdvertisementCount() { + return mAdvertisementCount; + } + + /** + * @see #mAdvertisementCount + */ + public void setAdvertisementCount(long advertisementCount) { + mAdvertisementCount = advertisementCount; + } + /** * Provides a calculated estimate of the distance to the beacon based on a running average of @@ -526,6 +561,8 @@ public void writeToParcel(Parcel out, int flags) { } out.writeInt(mManufacturer); out.writeString(mBluetoothName); + out.writeValue(mRunningAverageRssi); + out.writeLong(mAdvertisementCount); } diff --git a/src/main/java/org/altbeacon/beacon/service/BeaconService.java b/src/main/java/org/altbeacon/beacon/service/BeaconService.java index 1ec4932bc..81e14e71b 100644 --- a/src/main/java/org/altbeacon/beacon/service/BeaconService.java +++ b/src/main/java/org/altbeacon/beacon/service/BeaconService.java @@ -451,6 +451,7 @@ protected Void doInBackground(ScanData... params) { } } if (beacon != null) { + android.util.Log.d(TAG, "brssi, "+(new java.util.Date().getTime())+", "+scanData.rssi); mDetectionTracker.recordDetection(); processBeaconFromScan(beacon); } diff --git a/src/main/java/org/altbeacon/beacon/service/RangedBeacon.java b/src/main/java/org/altbeacon/beacon/service/RangedBeacon.java index 34722c4a0..c4b77d826 100644 --- a/src/main/java/org/altbeacon/beacon/service/RangedBeacon.java +++ b/src/main/java/org/altbeacon/beacon/service/RangedBeacon.java @@ -14,6 +14,7 @@ public class RangedBeacon { //kept here for backward compatibility public static final long DEFAULT_SAMPLE_EXPIRATION_MILLISECONDS = 20000; /* 20 seconds */ private static long sampleExpirationMilliseconds = DEFAULT_SAMPLE_EXPIRATION_MILLISECONDS; + private static long mAdvertisementCount = 0; private boolean mTracked = true; protected long lastTrackedTimeMillis = 0; Beacon mBeacon; @@ -62,6 +63,10 @@ public void commitMeasurements() { } public void addMeasurement(Integer rssi) { + if (mAdvertisementCount < Long.MAX_VALUE) { + mAdvertisementCount++; + } + mBeacon.setAdvertisementCount(mAdvertisementCount); // Filter out unreasonable values per // http://stackoverflow.com/questions/30118991/rssi-returned-by-altbeacon-library-127-messes-up-distance if (rssi != 127) { diff --git a/src/test/java/org/altbeacon/beacon/BeaconTest.java b/src/test/java/org/altbeacon/beacon/BeaconTest.java index e31e6f545..434e0a611 100644 --- a/src/test/java/org/altbeacon/beacon/BeaconTest.java +++ b/src/test/java/org/altbeacon/beacon/BeaconTest.java @@ -166,6 +166,7 @@ public void testCanSerializeParcelable() { Beacon beacon = new AltBeacon.Builder().setId1("1").setId2("2").setId3("3").setRssi(4) .setBeaconTypeCode(5).setTxPower(6).setBluetoothName("xx") .setBluetoothAddress("1:2:3:4:5:6").setDataFields(Arrays.asList(100l)).build(); + beacon.setRunningAverageRssi(-15.0); beacon.writeToParcel(parcel, 0); parcel.setDataPosition(0); Beacon beacon2 = new Beacon(parcel); @@ -182,6 +183,7 @@ public void testCanSerializeParcelable() { assertEquals("manufacturer is same after deserialization", beacon.getManufacturer(), beacon2.getManufacturer()); assertEquals("data field 0 is the same after deserialization", beacon.getDataFields().get(0), beacon2.getDataFields().get(0)); assertEquals("data field 0 is the right value", beacon.getDataFields().get(0), (Long) 100l); + assertEquals("running average rssi is the right value", beacon2.getRunningAverageRssi(), -15.0, 0.001); } @Test From 007de849198dedaf6b2c3c16500205569238f319 Mon Sep 17 00:00:00 2001 From: "David G. Young" Date: Wed, 4 Nov 2015 20:10:06 -0500 Subject: [PATCH 5/5] Experimental attempts to improve path loss formula on Samsung devices --- .../ModelSpecificDistanceCalculator.java | 5 ++-- .../distance/PathLossDistanceCalculator.java | 17 +++++++++----- .../model-distance-calculations-r2.json | 13 ++++++++--- .../ModelSpecificDistanceCalculatorTest.java | 23 +++++++++++++++---- .../model-distance-calculations-r2.json | 12 +++++++--- 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java index 0fe88eadb..675fcba2b 100644 --- a/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java +++ b/src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java @@ -304,9 +304,10 @@ private void buildModelMap(String jsonString) throws JSONException { } else if (sCalculatorClass.equals(PathLossDistanceCalculator.class)) { Double receiverRssiOffset = modelObject.optDouble("receiver_rssi_offset"); - if (!receiverRssiOffset.isNaN()) { + Double receiverRssiSlope = modelObject.optDouble("receiver_rssi_slope"); + if (!receiverRssiOffset.isNaN() && !receiverRssiSlope.isNaN()) { distanceCalculator = - new PathLossDistanceCalculator(receiverRssiOffset); + new PathLossDistanceCalculator(receiverRssiSlope, receiverRssiOffset); } } diff --git a/src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java b/src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java index 63b87a311..d0ceba05c 100644 --- a/src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java +++ b/src/main/java/org/altbeacon/beacon/distance/PathLossDistanceCalculator.java @@ -7,15 +7,16 @@ * RSSI and a txPower calibration value that represents the expected RSSI for an iPhone 5 receiving * the signal when it is 1 meter away. *

- * This class uses a path loss equation with a receiverRssiOffset parameter. The offset must - * be supplied by the caller and is specific to the Android device being used. See the - * ModelSpecificDistanceCalculator for more information on the offset. + * This class uses a path loss equation with receiverRssiSlope and receiverRssiOffset parameter. + * The offset must be supplied by the caller and is specific to the Android device being used. + * See the ModelSpecificDistanceCalculator for more information on the offset. *

* Created by dyoung on 7/26/15. */ public class PathLossDistanceCalculator implements DistanceCalculator { public static final String TAG = "PathLossDistanceCalculator"; + private double mReceiverRssiSlope; private double mReceiverRssiOffset; /** @@ -23,7 +24,8 @@ public class PathLossDistanceCalculator implements DistanceCalculator { * * @param receiverRssiOffset */ - public PathLossDistanceCalculator(double receiverRssiOffset) { + public PathLossDistanceCalculator(double receiverRssiSlope, double receiverRssiOffset) { + mReceiverRssiSlope = receiverRssiSlope; mReceiverRssiOffset = receiverRssiOffset; } @@ -49,8 +51,11 @@ public double calculateDistance(int txPower, double rssi) { if (ratio < 1.0) { distance = Math.pow(ratio, 10); } else { - distance = Math.pow(10.0, ((-rssi+mReceiverRssiOffset+txPower)/10*0.41)); - + double adjustment = +mReceiverRssiSlope*rssi+mReceiverRssiOffset; + double adjustedRssi = rssi-adjustment; + System.out.println("Adjusting rssi by "+adjustment+" when rssi is "+rssi); + System.out.println("Adjusted rssi is now "+adjustedRssi); + distance = Math.pow(10.0, ((-adjustedRssi+txPower)/10*0.35)); } LogManager.d(TAG, "avg mRssi: %s distance: %s", rssi, distance); return distance; diff --git a/src/main/resources/model-distance-calculations-r2.json b/src/main/resources/model-distance-calculations-r2.json index 4df854552..667bdd24a 100644 --- a/src/main/resources/model-distance-calculations-r2.json +++ b/src/main/resources/model-distance-calculations-r2.json @@ -5,7 +5,8 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, - "receiver_rssi_offset": -2.5, + "receiver_rssi_offset": -4, + "receiver_rssi_slope": 0, "version":"4.4.2", "build_number":"KOT49H", "model":"Nexus 4", @@ -15,7 +16,8 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, - "receiver_rssi_offset": -2.5, + "receiver_rssi_offset": -4, + "receiver_rssi_slope": 0, "version":"4.4.2", "build_number":"LPV79", "model":"Nexus 5", @@ -24,6 +26,7 @@ }, { "receiver_rssi_offset": -10, + "receiver_rssi_slope": 0, "version":"5.1.1", "build_number":"LVY48C", "model":"Moto G", @@ -31,6 +34,7 @@ }, { "receiver_rssi_offset": -21.25, + "receiver_rssi_slope": 0, "version":"5.0", "build_number":"LRX21T", "model":"SM-G900V", @@ -38,17 +42,20 @@ }, { "receiver_rssi_offset": -4, + "receiver_rssi_slope": 0, "version":"4.4.2", "build_number":"KOT49H", "model":"SCH-I535", "manufacturer":"samsung" }, { - "receiver_rssi_offset": -0.5, + "receiver_rssi_offset": 11.38316832, + "receiver_rssi_slope": 0.2772277228, "version":"5.1.1", "build_number":"LMY47X.G928TUVU2COI5", "model":"SM-G928T", "manufacturer":"samsung" } + ] } diff --git a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java index 50da708c4..103b2d229 100644 --- a/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java +++ b/src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java @@ -52,16 +52,18 @@ public void testCalculatesDistanceAt10MetersOnANexus5() { assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); } + /* @Test - public void testCalculatesDistanceAt10MetersOnANexus5WithPathLossFormula() { + public void testCalculatesDistanceAt5MetersOnANexus5WithPathLossFormula() { org.robolectric.shadows.ShadowLog.stream = System.err; AndroidModel model = new AndroidModel("5.0.0", "LPV79","Nexus 5","LGE"); ModelSpecificDistanceCalculator.setDistanceCalculatorClass(PathLossDistanceCalculator.class); ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); - Double distance = distanceCalculator.calculateDistance(-45,-71); - assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); + Double distance = distanceCalculator.calculateDistance(-53,-64); + assertEquals("Distance should be 5.0 ", 5.0, distance, 1.0); } + */ @Test public void testCalculatesDistanceAt10MetersOnAGalaxyS6EdgePlusWithPathLossFormula() { @@ -70,8 +72,19 @@ public void testCalculatesDistanceAt10MetersOnAGalaxyS6EdgePlusWithPathLossFormu ModelSpecificDistanceCalculator.setDistanceCalculatorClass(PathLossDistanceCalculator.class); ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); - Double distance = distanceCalculator.calculateDistance(-50,-75); - assertEquals("Distance should be 10.0 ", 10.0, distance, 1.0); + Double distance = distanceCalculator.calculateDistance(-48,-81); + assertEquals("Distance should be 10.0 ", 5.0, distance, 1.0); + } + + @Test + public void testCalculatesDistanceAt10MetersOnAGalaxyS6EdgePlusWithPathLossFormulaAndLowPowerDot() { + org.robolectric.shadows.ShadowLog.stream = System.err; + AndroidModel model = new AndroidModel("5.1.1", "LMY47X.G928TUVU2COI5","SM-G928T","samsung"); + ModelSpecificDistanceCalculator.setDistanceCalculatorClass(PathLossDistanceCalculator.class); + + ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(null, null, model); + Double distance = distanceCalculator.calculateDistance(-56,-74); + assertEquals("Distance should be 2.0 ", 2.0, distance, 1.0); } @Test diff --git a/src/test/resources/model-distance-calculations-r2.json b/src/test/resources/model-distance-calculations-r2.json index 066bc20ee..667bdd24a 100644 --- a/src/test/resources/model-distance-calculations-r2.json +++ b/src/test/resources/model-distance-calculations-r2.json @@ -5,7 +5,8 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, - "receiver_rssi_offset": -2.5, + "receiver_rssi_offset": -4, + "receiver_rssi_slope": 0, "version":"4.4.2", "build_number":"KOT49H", "model":"Nexus 4", @@ -15,7 +16,8 @@ "coefficient1": 0.42093, "coefficient2": 6.9476, "coefficient3": 0.54992, - "receiver_rssi_offset": -2.5, + "receiver_rssi_offset": -4, + "receiver_rssi_slope": 0, "version":"4.4.2", "build_number":"LPV79", "model":"Nexus 5", @@ -24,6 +26,7 @@ }, { "receiver_rssi_offset": -10, + "receiver_rssi_slope": 0, "version":"5.1.1", "build_number":"LVY48C", "model":"Moto G", @@ -31,6 +34,7 @@ }, { "receiver_rssi_offset": -21.25, + "receiver_rssi_slope": 0, "version":"5.0", "build_number":"LRX21T", "model":"SM-G900V", @@ -38,13 +42,15 @@ }, { "receiver_rssi_offset": -4, + "receiver_rssi_slope": 0, "version":"4.4.2", "build_number":"KOT49H", "model":"SCH-I535", "manufacturer":"samsung" }, { - "receiver_rssi_offset": -0.5, + "receiver_rssi_offset": 11.38316832, + "receiver_rssi_slope": 0.2772277228, "version":"5.1.1", "build_number":"LMY47X.G928TUVU2COI5", "model":"SM-G928T",