-
Notifications
You must be signed in to change notification settings - Fork 838
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
make distance calculations specific to Android model
- Loading branch information
1 parent
c05082b
commit 35328c4
Showing
7 changed files
with
299 additions
and
0 deletions.
There are no files selected for viewing
68 changes: 68 additions & 0 deletions
68
src/main/java/org/altbeacon/beacon/distance/AndroidModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package org.altbeacon.beacon.distance; | ||
|
||
import android.os.Build; | ||
|
||
/** | ||
* Created by dyoung on 8/28/14. | ||
*/ | ||
public class AndroidModel { | ||
String mVersion; | ||
String mBuildNumber; | ||
String mModel; | ||
String mManufacturer; | ||
|
||
public AndroidModel(String version, String buildNumber, | ||
String model, | ||
String manufacturer) { | ||
mVersion = version; | ||
mBuildNumber = buildNumber; | ||
mModel = model; | ||
mManufacturer = manufacturer; | ||
|
||
} | ||
public static AndroidModel forThisDevice() { | ||
return new AndroidModel( | ||
Build.VERSION.RELEASE, | ||
Build.ID, | ||
Build.MODEL, | ||
Build.MANUFACTURER); | ||
} | ||
|
||
public String getVersion() { | ||
return mVersion; | ||
} | ||
|
||
public void setVersion(String mVersion) { | ||
this.mVersion = mVersion; | ||
} | ||
|
||
public String getBuildNumber() { | ||
return mBuildNumber; | ||
} | ||
|
||
public String getModel() { | ||
return mModel; | ||
} | ||
|
||
|
||
public String getManufacturer() { | ||
return mManufacturer; | ||
} | ||
|
||
public int matchScore(AndroidModel otherModel) { | ||
int score = 0; | ||
if (this.mManufacturer.equals(otherModel.mManufacturer)) { | ||
score = 1; | ||
} | ||
if (this.mModel.equals(otherModel.mModel)) { | ||
score = 2; | ||
} | ||
if (this.mBuildNumber.equals(otherModel.mBuildNumber)) { | ||
score = 3; | ||
} | ||
if (this.mVersion.equals(otherModel.mVersion)) { | ||
score = 4; | ||
} | ||
return score; | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
src/main/java/org/altbeacon/beacon/distance/CurveFittedDistanceCalculator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.altbeacon.beacon.distance; | ||
|
||
import org.altbeacon.beacon.BeaconManager; | ||
|
||
/** | ||
* Created by dyoung on 8/28/14. | ||
*/ | ||
public class CurveFittedDistanceCalculator implements DistanceCalculator { | ||
|
||
public static final String TAG = "CurveFittedDistanceCalculator"; | ||
private double mCoefficient1; | ||
private double mCoefficient2; | ||
private double mCoefficient3; | ||
|
||
public CurveFittedDistanceCalculator(double coefficient1, double coefficient2, double coefficient3) { | ||
mCoefficient1 = coefficient1; | ||
mCoefficient2 = coefficient2; | ||
mCoefficient3 = coefficient3; | ||
} | ||
|
||
/** | ||
* 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. | ||
} | ||
|
||
BeaconManager.logDebug(TAG, "calculating distance based on mRssi of " + rssi + " and txPower of " + txPower); | ||
|
||
|
||
double ratio = rssi*1.0/txPower; | ||
double distance; | ||
if (ratio < 1.0) { | ||
distance = Math.pow(ratio,10); | ||
} | ||
else { | ||
distance = (0.42093)*Math.pow(ratio,6.9476) + 0.54992; | ||
} | ||
BeaconManager.logDebug(TAG, " avg mRssi: "+rssi+" distance: "+distance); | ||
return distance; | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/main/java/org/altbeacon/beacon/distance/DistanceCalculator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package org.altbeacon.beacon.distance; | ||
|
||
/** | ||
* Created by dyoung on 8/28/14. | ||
*/ | ||
public interface DistanceCalculator { | ||
public double calculateDistance(int txPower, double rssi); | ||
} |
111 changes: 111 additions & 0 deletions
111
src/main/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package org.altbeacon.beacon.distance; | ||
|
||
import android.os.Build; | ||
import android.util.Log; | ||
|
||
import org.json.JSONArray; | ||
import org.json.JSONObject; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Properties; | ||
|
||
/** | ||
* Created by dyoung on 8/28/14. | ||
*/ | ||
public class ModelSpecificDistanceCalculator implements DistanceCalculator { | ||
Map<AndroidModel,DistanceCalculator> mModelMap; | ||
//private static final String CONFIG_FILE = "/model-distance-calculations.json"; | ||
private static final String CONFIG_FILE = "test.properties"; | ||
private static final String TAG = "ModelSpecificDistanceCalculator"; | ||
private DistanceCalculator mDefaultDistanceCalculator; | ||
private DistanceCalculator mDistanceCalculator; | ||
|
||
public ModelSpecificDistanceCalculator() { | ||
this(AndroidModel.forThisDevice()); | ||
} | ||
public ModelSpecificDistanceCalculator(AndroidModel model) { | ||
loadModelMap(); | ||
mDistanceCalculator = findCalculatorForModel(model); | ||
} | ||
|
||
private DistanceCalculator findCalculatorForModel(AndroidModel model) { | ||
Log.d(TAG, "Finding best distance calculator for "+model.getVersion()+","+ | ||
model.getBuildNumber()+","+model.getModel()+"," + | ||
""+model.getManufacturer()); | ||
|
||
int highestScore = 0; | ||
AndroidModel bestMatchingModel = null; | ||
for (AndroidModel candidateModel : mModelMap.keySet()) { | ||
if (candidateModel.matchScore(model) > highestScore) { | ||
highestScore = candidateModel.matchScore(model); | ||
bestMatchingModel = candidateModel; | ||
} | ||
} | ||
if (bestMatchingModel != null) { | ||
Log.d(TAG, "found a match with score "+highestScore); | ||
Log.d(TAG, "Finding best distance calculator for "+bestMatchingModel.getVersion()+","+ | ||
bestMatchingModel.getBuildNumber()+","+bestMatchingModel.getModel()+"," + | ||
""+bestMatchingModel.getManufacturer()); | ||
return mModelMap.get(bestMatchingModel); | ||
} | ||
|
||
Log.d(TAG, "Cannot find match for this device. Using default"); | ||
return mDefaultDistanceCalculator; | ||
} | ||
|
||
private void loadModelMap() { | ||
mModelMap = new HashMap<AndroidModel, DistanceCalculator>(); | ||
try { | ||
JSONObject jsonObject = new JSONObject(stringFromFilePath(CONFIG_FILE)); | ||
JSONArray array = jsonObject.getJSONArray("models"); | ||
for (int i = 0; i < array.length(); i++) { | ||
JSONObject modelObject = array.getJSONObject(i); | ||
boolean 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"); | ||
|
||
CurveFittedDistanceCalculator distanceCalculator = | ||
new CurveFittedDistanceCalculator(coefficient1,coefficient2,coefficient3); | ||
|
||
AndroidModel androidModel = new AndroidModel(version, buildNumber, model, manufacturer); | ||
mModelMap.put(androidModel, distanceCalculator); | ||
if (defaultFlag) { | ||
mDefaultDistanceCalculator = distanceCalculator; | ||
} | ||
} | ||
} | ||
catch (Exception e) { | ||
throw new RuntimeException("Cannot build model distance calculations", e); | ||
} | ||
} | ||
|
||
private String stringFromFilePath(String path) throws IOException { | ||
InputStream stream = ModelSpecificDistanceCalculator.class.getResourceAsStream(path); | ||
if (stream == null) { | ||
throw new RuntimeException("Cannot load resource at "+path); | ||
} | ||
StringBuilder inputStringBuilder = new StringBuilder(); | ||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); | ||
String line = bufferedReader.readLine(); | ||
while(line != null){ | ||
inputStringBuilder.append(line);inputStringBuilder.append('\n'); | ||
line = bufferedReader.readLine(); | ||
} | ||
return inputStringBuilder.toString(); | ||
} | ||
|
||
@Override | ||
public double calculateDistance(int txPower, double rssi) { | ||
return mDistanceCalculator.calculateDistance(txPower, rssi); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"models": | ||
[ | ||
{ | ||
"coefficient1": 0.42093, | ||
"coefficient2": 6.9476, | ||
"coefficient3": 0.54992, | ||
"version":"4.4.2", | ||
"build_number":"KOT49H", | ||
"model":"Nexus 4", | ||
"manufacturer":"LGE", | ||
"default": true | ||
}, | ||
{ | ||
"coefficient1": 0.42093, | ||
"coefficient2": 6.9476, | ||
"coefficient3": 0.54992, | ||
"version":"4.4.2", | ||
"build_number":"LPV79", | ||
"model":"Nexus 5", | ||
"manufacturer":"LGE", | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
] | ||
} |
Empty file.
40 changes: 40 additions & 0 deletions
40
src/test/java/org/altbeacon/beacon/distance/ModelSpecificDistanceCalculatorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.altbeacon.beacon.distance; | ||
|
||
import android.os.Parcel; | ||
|
||
import static android.test.MoreAsserts.assertNotEqual; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertNotNull; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
import org.altbeacon.beacon.AltBeacon; | ||
import org.altbeacon.beacon.AltBeaconParser; | ||
import org.altbeacon.beacon.Beacon; | ||
import org.robolectric.RobolectricTestRunner; | ||
|
||
import org.junit.runner.RunWith; | ||
import org.junit.Test; | ||
import org.robolectric.annotation.Config; | ||
|
||
@Config(emulateSdk = 18) | ||
@RunWith(RobolectricTestRunner.class) | ||
/* | ||
HOW TO SEE DEBUG LINES FROM YOUR UNIT TESTS: | ||
1. set a line like this at the start of your test: | ||
org.robolectric.shadows.ShadowLog.stream = System.err; | ||
2. run the tests from the command line | ||
3. Look at the test report file in your web browser, e.g. | ||
file:///Users/dyoung/workspace/AndroidProximityLibrary/build/reports/tests/index.html | ||
4. Expand the System.err section | ||
/** | ||
* Created by dyoung on 8/28/14. | ||
*/ | ||
public class ModelSpecificDistanceCalculatorTest { | ||
@Test | ||
public void testRecognizeBeacon() { | ||
ModelSpecificDistanceCalculator distanceCalculator = new ModelSpecificDistanceCalculator(); | ||
Double distance = distanceCalculator.calculateDistance(-59, -59); | ||
assertEquals("Distance should be 1.0 for same power and rssi", 1.0, (double) distance, 0.001); | ||
} | ||
} |
1 comment
on commit 35328c4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is not intentional. While close, the coefficients should be different for the Nexus 4 and 5.
The planned fix is to shift to a path loss formula, which is easier to implement for multiple devices. It is a work in progress here:
#251
is it intentional that the coefficients are duplicated