我知道与我的问题有关的堆叠溢出有很多问题,但我想知道是否有任何方法可以得到与RSSI的确切距离。
我跟踪了此链接和其他一些距离计算的git库方法以及教程。但我找不到正确的解决办法。
这就是我用来测量距离的东西:
protected double calculateDistance(float txPower, double rssi) {
if (rssi == 0) {
return -1.0; // if we cannot determine distance, return -1.
}
double ratio = rssi * 1.0 / txPower;
if (ratio < 1.0) {
return Math.pow(ratio, 10);
} else {
double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
return accuracy;
}
}当我调用这个方法时,我传递标准和rssi,这是我从mLeScanCallBack()获得的
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
BluetoothDeviceModel bluetoothDeviceModel = new BluetoothDeviceModel(device, rssi);
mLeDeviceListAdapter.addDevice(bluetoothDeviceModel, rssi, bluetoothDeviceModel.device.getAddress());
mLeDeviceListAdapter.notifyDataSetChanged();
if (mapBluetooth != null) {
mapBluetooth.put(bluetoothDeviceModel.getDevice().getAddress(), bluetoothDeviceModel);
mLeDeviceListAdapter.refresh(mapBluetooth);
}
}
});
}
};我面临什么问题?
上面的代码没有什么问题。它给我的距离,但我不满意,因为这不是正确的距离。那么,有人能告诉我,是否有可能通过上述方法获得精确的距离,或者是否有其他方法?
发布于 2020-05-07 08:42:00
你不能得到“精确距离”,因为你得到的RSSI是非常糟糕的,如果BLE标签是>1米的距离,RSSI振荡会变得非常高,越多,你就会增加距离,计算出的距离越多,计算的距离就越错。
您所测量的RSSI取决于许多因素,例如环境(内部或外部)、您正在使用的标记类型、所使用的接收器类型、您的标记与接收器之间是否存在某种东西、如果您的标记ecc ecc附近有标记。
使用蓝牙无法精确测量距离
但是,您可以通过执行一些操作来平滑所得到的高斯(测量值的振荡),从而更好地测量距离。
例如,如果您知道标记总是在相同的距离上,则可以对您获得的Rssi值进行平均处理。例如,您在最后1分钟完成了Rssi的平均值。
这样,您将得到一个更好的距离值,但标记必须保持相同的位置。
记住,在计算距离rssi和txPower的方式上:(0.89976) *Math.pow(比率,7.7095) + 0.111;
在这个公式中有3个常量,这些常数是标记&蓝牙接收器特定的。因此,为了提高精确度,您应该为您正在使用的每一种标签以及您正在使用的智能手机的每一种蓝牙模块计算这3个常量。
如果标记移动,您可以实现其他函数来平滑您的值,例如卡尔曼滤波器.。
wouterbulten - kalmanjs - GitHub) (信用:)
Java中的Kalman滤波器(用于Android):
private class KalmanFilter implements Serializable {
private double R; // Process Noise
private double Q; // Measurement Noise
private double A; // State Vector
private double B; // Control Vector
private double C; // Measurement Vector
private Double x; // Filtered Measurement Value (No Noise)
private double cov; // Covariance
public KalmanFilter(double r, double q, double a, double b, double c) {
R = r;
Q = q;
A = a;
B = b;
C = c;
}
public KalmanFilter(double r, double q){
R = r;
Q = q;
A = 1;
B = 0;
C = 1;
}
/** Public Methods **/
public double applyFilter(double rssi){
return applyFilter(rssi, 0.0d);
}
/**
* Filters a measurement
*
* @param measurement The measurement value to be filtered
* @param u The controlled input value
* @return The filtered value
*/
public double applyFilter(double measurement, double u) {
double predX; // Predicted Measurement Value
double K; // Kalman Gain
double predCov; // Predicted Covariance
if (x == null) {
x = (1 / C) * measurement;
cov = (1 / C) * Q * (1 / C);
} else {
predX = predictValue(u);
predCov = getUncertainty();
K = predCov * C * (1 / ((C * predCov * C) + Q));
x = predX + K * (measurement - (C * predX));
cov = predCov - (K * C * predCov);
}
return x;
}
/** Private Methods **/
private double predictValue(double control){
return (A * x) + (B * control);
}
private double getUncertainty(){
return ((A * cov) * A) + R;
}
@Override
public String toString() {
return "KalmanFilter{" +
"R=" + R +
", Q=" + Q +
", A=" + A +
", B=" + B +
", C=" + C +
", x=" + x +
", cov=" + cov +
'}';
}
}使用:
private KalmanFilter mKalmanFilter; // Property of your class to store kalman filter values
mKalmanFilter = new KalmanFilter(KALMAN_R, KALMAN_Q); // init Kalman Filter
// Method Apply Filter
private void applyKalmanFilterToRssi(){
mFilteredRSSI = mKalmanFilter.applyFilter(mRSSI);
}常量值:
// Kalman R & Q
private static final double KALMAN_R = 0.125d;
private static final double KALMAN_Q = 0.5d;+ KALMAN_R是进程噪声
+ KALMAN_Q是测量噪声
,您应该根据您的度量和使用情况来更改这两个值,。更改这两个值,您将更改过滤后的度量值从一个值到另一个值的速度。因此,如果您有带有大量噪声的值,并且希望减慢测量值变化的速度(为了平滑高斯),您应该尝试增加KALMAN_R & KALMAN_Q值。如果我没记错的话,KALMAN_R和KALMAN_Q的值是我为BLE设备编程时使用的值,所以KALMAN_R和KALMAN_Q的这两个值已经“大”了,因为BLE设备的RSSI变化很大。
我建议你用卡尔曼滤波器来平滑你的价值观。
希望这是有帮助的,有一个美好的一天和美好的编码!
上传,这些是我的TagBLE类:
标签蓝牙的基类低能:
public class TagBLE extends RealmObject implements Parcelable {
// Field Names
public static final String FIELD_ID = "id";
public static final String FIELD_MAC = FIELD_ID;
@Expose
@PrimaryKey
@SerializedName("tag_mac")
private String id;
@Expose
@SerializedName("tag_nome")
private String mName;
@Expose
@SerializedName("tx_power")
private int mTxPower;
public TagBLE(){}
public TagBLE(String mac, String name, int txPower){
id = mac;
mName = name;
mTxPower = txPower;
}
public TagBLE(TagBLE tag){
id = tag.getMAC();
mName = tag.getName();
mTxPower = tag.getTxPower();
}
/** Private Constructors **/
private TagBLE(Parcel in){
id = in.readString();
mName = in.readString();
mTxPower = in.readInt();
}
/** Public Static Factory Methods **/
public static TagBLE initInstanceFromScanResult(ScanResult result, int txPower){
BluetoothDevice bDevice = result.getDevice();
return new TagBLE(bDevice.getAddress(), bDevice.getName(), txPower);
}
/** Parcelling Methods **/
public static Parcelable.Creator<TagBLE> CREATOR = new TagBLECreator();
/** Override Parcelable Methods **/
@Override
public int describeContents(){
return 0x0;
}
@Override
public void writeToParcel(Parcel out, int flags){
out.writeString(id);
out.writeString(mName);
out.writeInt(mTxPower);
}
/** Getter Methods **/
public String getId(){
return id;
}
public String getMAC() {
return id;
}
public String getName() {
return mName;
}
public int getTxPower() {
return mTxPower;
}
/** Setter Methods **/
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
mName = name;
}
public void setTxPower(int txPower) {
mTxPower = txPower;
}
/** Public Methods **/
public double getDistance(int rssi){
return getDistance((double) rssi);
}
public double getDistance(double rssi){
return Math.pow(10, ((mTxPower - rssi) * 1.0) / 20);
}
@Override
public String toString() {
return "TagBLE{" +
"id='" + id + '\'' +
", mName='" + mName + '\'' +
", mTxPower=" + mTxPower +
'}';
}
/** Private Static Class - Parcelable Creator **/
private static class TagBLECreator implements Parcelable.Creator<TagBLE> {
@Override
public TagBLE createFromParcel(Parcel in) {
return new TagBLE(in);
}
@Override
public TagBLE[] newArray(int size) {
return new TagBLE[size];
}
}
}特定的类来管理数据(在我的例子中,我需要管理距离,如果它离设备很近,或者它很远,但是我从类代码中删除了这些部分)(使用KalmanFilter):
public class DataTagBLE extends RealmObject {
// Field Names
public static final String FIELD_ID = "id";
// Kalman R & Q
private static final double KALMAN_R = 0.125d;
private static final double KALMAN_Q = 0.5d;
@PrimaryKey
private String id;
@Expose
@SerializedName("tag")
private TagBLE mTag;
@Expose
@SerializedName("acquired")
private Date mAcquired;
@Expose
@SerializedName("rssi")
private int mRSSI;
@Expose
@SerializedName("filtered_rssi")
private double mFilteredRSSI;
@Ignore
private KalmanFilter mKalmanFilter;
private double mDistance;
public DataTagBLE(){}
public DataTagBLE(TagBLE tag){
id = UUID.randomUUID().toString();
mTag = tag;
mAcquired = new Date();
mRSSI = 0x0;
mFilteredRSSI = 0x0;
mKalmanFilter = new KalmanFilter(KALMAN_R, KALMAN_Q);
}
/** Private Constructors **/
private DataTagBLE(TagBLE tag, int rssi){
id = UUID.randomUUID().toString();
mTag = tag;
mAcquired = new Date();
mRSSI = rssi;
}
/** Public Static Factory Methods **/
public static DataTagBLE initInstanceDataTagFound(@NonNull ScanResult scanResult, int txPower){
return new DataTagBLE(TagBLE.initInstanceFromScanResult(scanResult, txPower));
}
/** Getter Methods **/
public TagBLE getTag(){
return mTag;
}
public Date getAcquired() {
return mAcquired;
}
public int getRSSI(){
return mRSSI;
}
public double getFilteredRSSI(){
return this.mFilteredRSSI;
}
public KalmanFilter getKalmanFilter() {
return mKalmanFilter;
}
/** Setter Methods **/
public void setTag(TagBLE tag){
mTag = tag;
}
public void setAcquired(Date acquired) {
this.mAcquired = acquired;
}
public void setRSSI(int rssi){
mRSSI = rssi;
}
public void setFilteredRSSI(int rssi){
this.mFilteredRSSI = rssi;
}
public void setKalmanFilter(KalmanFilter kalmanFilter) {
this.mKalmanFilter = kalmanFilter;
}
/** TagBLE Getter Methods **/
public String getTagMac() {
if (mTag != null) {
return mTag.getMAC();
} else {
return null;
}
}
/** TagBLE Setter Methods **/
public void setTagNameAndTxPower(String tagName, int txPower){
if(mTag != null){
mTag.setName(tagName);
mTag.setTxPower(txPower);
}
}
/** Public Methods **/
public void generateNewID(){
id = UUID.randomUUID().toString();
}
public void onNewDataTagAcquired(DataTagBLE dataTagFound){
setRSSI(dataTagFound.getRSSI());
applyKalmanFilterToRssi();
TagBLE tagFound = dataTagFound.getTag();
if(tagFound != null) {
setTagNameAndTxPower(tagFound.getName(), tagFound.getTxPower());
}
setAcquired(new Date());
}
public void store(){
generateNewID();
RealmHelper rHelper = new RealmHelper();
rHelper.saveUpdateRealmObject(this);
rHelper.close();
}
/** Distance & RSSI Filtering Methods **/
public double getDistanceFiltered(){
return mTag.getDistance(mFilteredRSSI);
}
public double getDistance(){
return mTag.getDistance(mRSSI);
}
/** Private Methods **/
private void applyKalmanFilterToRssi(){
mFilteredRSSI = mKalmanFilter.applyFilter(mRSSI);
}
@Override
public String toString() {
return "DataTagBLE{" +
"id='" + id + '\'' +
", mTag=" + mTag +
", mAcquired=" + mAcquired +
", mRSSI=" + mRSSI +
", mFilteredRSSI=" + mFilteredRSSI +
", mKalmanFilter=" + mKalmanFilter +
", mDistance=" + mDistance +
'}';
}
/** Private Classes **/
/*
SOURCE: https://github.com/wouterbulten/kalmanjs/blob/master/dist/kalman.js
*/
private class KalmanFilter implements Serializable {
private double R; // Process Noise
private double Q; // Measurement Noise
private double A; // State Vector
private double B; // Control Vector
private double C; // Measurement Vector
private Double x; // Filtered Measurement Value (No Noise)
private double cov; // Covariance
public KalmanFilter(double r, double q, double a, double b, double c) {
R = r;
Q = q;
A = a;
B = b;
C = c;
}
public KalmanFilter(double r, double q){
R = r;
Q = q;
A = 1;
B = 0;
C = 1;
}
/** Public Methods **/
public double applyFilter(double rssi){
return applyFilter(rssi, 0.0d);
}
/**
* Filters a measurement
*
* @param measurement The measurement value to be filtered
* @param u The controlled input value
* @return The filtered value
*/
public double applyFilter(double measurement, double u) {
double predX; // Predicted Measurement Value
double K; // Kalman Gain
double predCov; // Predicted Covariance
if (x == null) {
x = (0x1 / C) * measurement;
cov = (0x1 / C) * Q * (0x1 / C);
} else {
predX = predictValue(u);
predCov = getUncertainty();
K = predCov * C * (0x1 / (C * predCov * C + Q));
x = predX + K * (measurement - (C * predX));
cov = predCov - (K * C * predCov);
}
return x;
}
/** Private Methods **/
private double predictValue(double control){
return (A * x) + (B * control);
}
private double getUncertainty(){
return (A * cov * A) + R;
}
@Override
public String toString() {
return "KalmanFilter{" +
"R=" + R +
", Q=" + Q +
", A=" + A +
", B=" + B +
", C=" + C +
", x=" + x +
", cov=" + cov +
'}';
}
}
}在我的例子中,当我为标签BLE找到一个唯一的MAC时,我实例化了一个"DataTagBLE“(类还没有完成,我删除了我使用的所有距离检查)。我第一次引用这个实例:
DataTagBLE initInstanceDataTagFound(@NonNull ScanResult scanResult, int txPower)然后,每次我找到相同的标记(它将有不同的RSSI),我将通过查看MAC地址(在我的服务上使用一个DataTagBLE,DataTagBLE> )来获取这个标记的HashMap
myDataTagBLEInstance.onNewDataTagAcquired(DataTagBLE newDataTagBLEInstance)
(我的基本服务总是返回给我一个已生成的DataTagBLE实例,所以我将使用上面的方法使用新的实例数据更新旧实例),这只是为了回答下面的问题,KalmanFilter必须是同一个标记的同一个实例!
从信标获取txPower:
它使用:'com.neovisionaries:nv-bluetooth:1.8'
public static int getBeaconTxPower(ScanResult result){
if(result != null) {
// This part uses the library above
if(result.getScanRecord() != null) {
List<ADStructure> structures = ADPayloadParser.getInstance().parse(result.getScanRecord().getBytes());
if (structures != null && structures.size() > 0x0) {
for (ADStructure st : structures) {
if (st instanceof IBeacon) {
IBeacon beacon = (IBeacon) st;
if(beacon.getPower() != 0x0) {
return beacon.getPower();
}
}
}
}
}
// Add case here if the Tag doesn't have the txPower setted. For example: if(MAC ADDRESS contains "XX:XX:XX..." then txPower = Y"
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
return result.getTxPower();
}
}
return 0x0;
}
使用KalmanFilter的伪代码HashMap:
// Store here KalmanFilters associated to every MAC Address
HashMap<String, KalmanFilter> mKalmanFilters;
// When you find a tag:
if mKalmanFilters.keySet().contains(tagFound.mac){
KalmanFilter mKalman = mKalmanFilters.get(tagFound.mac());
// This will give you a smoothed RSSI value because 'x == lastRssi'
double smoothed = mKalman.applyFilter(tagFound.rssi);
// Do what you want with this rssi
} else {
KalmanFilter mKalman = new KalmanFilter(valR, valQ);
/* This will set the first measurement, so the 'x', of the KalmanFilter. Next time you find the tag and you use the 'if part' you will get a smoothed rssi value.
This rssi value will be smoothed depending on the 'C' value (so Measurement Vector) setted in your KalmanFilter instance. If C == 1 => smoothed == rssi. */
double smoothed = mKalman.applyFilter(tagFound.rssi);
mKalmanFilters.put(tagFound.mac, mKalmanFilter);
}发布于 2016-06-09 06:24:55
我也在做同样的事情。使用这种方法,您可以计算出距离,但该距离正在频繁变化。这是因为RSSI值也经常更改。
您需要做的是平滑您的结果,为此,您必须应用卡尔曼滤波或(线性二次估计)。如果你想坚持卡尔曼滤波,那么从这里开始。信标跟踪
我仍然在寻找更好的执行卡尔曼滤波为我的项目。或者,您可以平滑您的RSSI值。
H=∗+ (1−)∗−1)
是最近的值,−1是以前的平均值。
变化范围从0到1考虑=0.75
资料来源:- RSSI平滑
https://stackoverflow.com/questions/36399927
复制相似问题