计算公式:
d = 10^((abs(RSSI) - A) / (10 * n))
其中:
d - 计算所得距离
RSSI - 接收信号强度(负值)
A - 发射端和接收端相隔1米时的信号强度
n - 环境衰减因子
计算公式的代码实现
(float)calcDistByRSSI:(int)rssi
{
int iRssi = abs(rssi);
float power = (iRssi-59)/(10*2.0);
return pow(10, power);
}
传入RSSI值,返回距离(单位:米)。其中,A参数赋了59,n赋了2.0。
由于所处环境不同,每台发射源(蓝牙设备)对应参数值都不一样。按道理,公式里的每项参数都应该做实验(校准)获得。
当你不知道周围蓝牙设备准确位置时,只能给A和n赋经验值(如本例)。
实验获取公式
问:如何开展读取RSSI值的实验?
答:读取RSSI值的实验可以这样搭建,主设备固定位置,向从设备发送信号,从设备LED光和Buzzer报警为通信成功,逐次移动从设备,而获取RSSI值随物理距离之间的关系。下图是笔者做实验的数据:
|Distance(m)|1|2|3|4|5|6|7|8|9|10|
|-------------|---------------|
|RSSI(dBm) |-47|-59|-73|-80|-80|-79|-85|-88|-86|-87|
|Loss(p) |0|0|9|11|27|2|50|32|22|49|
实验器材为2块CC2540芯片,主芯片发射功率为4dBm(2.51mW),Loss是通信节点中失败次数。
问:如何将接收RSSI实验数据得到距离计算公式呢?
答:最好的工具是EXCEL软件,以上表中的实验数据和EXCEL 2007为例。首先选中Distance和RSSI两行,点击“插入->散列图”,软件会自动生成如下图:
选取其中任意点,点右键,“添加趋势线->对数”,将会出现下图:
可见RSSI与距离的关系是比较符合指数函数,再点击“显示公式”
此时得到指数函数公式为:y = -49.53 – 17.7 ln (x),再把自然对数换成10常用对数,则有:y = -49.53 – 40.71 lg (x)。通过以上几步就轻松得到RSSI与距离之间的计算公式。
滤波算法
- 卡尔曼滤波不行? 知乎回答
目前rssi测距需要兼顾设备反应的灵敏度以及rssi采样的准确性。一般的中值滤波已经无法满足这个需求,有无更合理的滤波方式?我猜想卡尔曼滤波器对这类数据会有较好的表现,但rssi信号受到环境干扰的因素太多,尝试了之后并不理想。
- 滑动防脉冲干扰平均滤波法
问:针对RSSI采样值选用什么样的滤波算法
答:RSSI采样值遵循以下特点:有个别的脉冲干扰引起极大值和极小值的出现,其他采样数据值沿平均值分布,比较适合的算法是:滑动防脉冲干扰平均滤波法。它的原理是,设有N个单位的队列,用新的采样值覆盖旧的采样值,去除队列中最大值和最小值后,再计算队列中采样数据的平均值。用C语言描述如下:
static INT8S Filter(INT8S chVal)
{
#define FIFO_NUM 10
INT8S chMinVal, chMaxVal, chTemp;
INT16S nCnt, nSum;
static INT8S s_chIx = 0, s_chIsFull = FALSE;
static INT8S s_achBuf[FIFO_NUM];
/* Save the NEW value, kick out the OLDest one */
s_achBuf[s_chIx] = chVal;
if (++s_chIx >= FIFO_NUM)
{
s_chIx = 0; /* Wrap to 1th unit */
s_chIsFull = TRUE;
}
/* Number of sampled data less than N */
if (!s_chIsFull)
{
nSum = 0;
for (nCnt = 0; nCnt < s_chIx; ++nCnt)
{
nSum += s_achBuf[nCnt];
}
return (INT8S)(nSum / s_chIx);
}
/* Get the SUM and Max. and Min. */
chMaxVal = chMinVal = nSum = 0;
for (nCnt = 0; nCnt < FIFO_NUM; ++nCnt)
{
chTemp = s_achBuf[nCnt];
nSum += chTemp;
if (chTemp > chMaxVal)
{
chMaxVal = chTemp;
}
else if (chTemp < chMinVal)
{
chMinVal = chTemp;
}
}
/* Calculate the average */
nSum -= (chMaxVal + chMinVal); /* SUB Max. and Min. */
nSum /= (FIFO_NUM - 2); /* Get average */
return (INT8S)nSum;
}
其他相关资源
- github
- 本科毕业设计:蓝牙防丢器Bluetooth anti-lost App ——可自行设定报警dBm&报警距离
- Bluetooth_rssi_MPU_postion
- BLE-Distance-Estimation: Distance estimation scheme with Bluetooth Low Energy beacons based on RSSI measurements using ** Kalman filter **
- Kalman-and-Bayesian-Filters-in-Python
相关知识
- 卡尔曼滤波(Kalman filter)
- 深海的小鱼的例子方便理解
假设我们要研究的对象是一个房间的温度。根据你的经验判断,这个房间的温度是恒定的,也就是下一分钟的温度等于现在这一分钟的温度(假设我们用一分钟来做时间单位)。假设你对你的经验不是100%的相信,可能会有上下偏差几度。我们把这些偏差看成是高斯白噪声(White Gaussian Noise),也就是这些偏差跟前后时间是没有关系的而且符合高斯分配(Gaussian Distribution)。另外,我们在房间里放一个温度计,但是这个温度计也不准确的,测量值会比实际值偏差。我们也把这些偏差看成是高斯白噪声。
好了,现在对于某一分钟我们有两个有关于该房间的温度值:你根据经验的预测值(系统的预测值)和温度计的值(测量值)。下面我们要用这两个值结合他们各自的噪声来估算出房间的实际温度值。
假如我们要估算k时刻的是实际温度值。首先你要根据k-1时刻的温度值,来预测k时刻的温度。因为你相信温度是恒定的,所以你会得到k时刻的温度预测值是跟k-1时刻一样的,假设是23度,同时该值的高斯噪声的偏差是5度(5是这样得到的:如果k-1时刻估算出的最优温度值的偏差是3,你对自己预测的不确定度是4度,他们平方相加再开方,就是5)。然后,你从温度计那里得到了k时刻的温度值,假设是25度,同时该值的偏差是4度。
由于我们用于估算k时刻的实际温度有两个温度值,分别是23度和25度。究竟实际温度是多少呢?相信自己还是相信温度计呢?究竟相信谁多一点,我们可以用他们的covariance来判断。因为Kg2=52/(52+42),所以Kg=0.78,我们可以估算出k时刻的实际温度值是:23+0.78(25-23)=24.56度。可以看出,因为温度计的covariance比较小(比较相信温度计),所以估算出的最优温度值偏向温度计的值。
现在我们已经得到k时刻的最优温度值了,下一步就是要进入k+1时刻,进行新的最优估算。到现在为止,好像还没看到什么自回归的东西出现。对了,在进入k+1时刻之前,我们还要算出k时刻那个最优值(24.56度)的偏差。算法如下:((1-Kg)52)0.5=2.35。这里的5就是上面的k时刻你预测的那个23度温度值的偏差,得出的2.35就是进入k+1时刻以后k时刻估算出的最优温度值的偏差(对应于上面的3)。
就是这样,卡尔曼滤波器就不断的把covariance递归,从而估算出最优的温度值。他运行的很快,而且它只保留了上一时刻的covariance。上面的Kg,就是卡尔曼增益(Kalman Gain)。他可以随不同的时刻而改变他自己的值,是不是很神奇!