微信小程序iBeacon测距及稳定程序的实现解析


Posted in Javascript onJuly 31, 2019

前言

iBeacon是苹果公司推出的一项低耗能蓝牙技术,由蓝牙设备发射包含指定信息的信号,再由移动设备接收信号,从而实现近场通信。微信小程序2017年开始支持iBeacon,摇一摇附近就是基于iBeacon实现的,此外iBeacon还可以实现距离测量,本文将介绍如何基于微信小程序实现iBeacon测距。

iBeacon测距原理

蓝牙信标发射的信号强度(rssi)与收发设备之间的距离,某种程度上呈正相关,因此通过合理的运算转化,可以通过rssi的值反推出与接收设备间的距离。

蓝牙信标的rssi值是一个参考值,没有固定标准。想要计算出蓝牙信标的距离,还必须知道这个信标设备的txPower值。txPower是指当距离蓝牙信标1m时的rssi值,不同的蓝牙设备或相同设备不同的工况甚至不同的场地环境,都会影响txPower值,因此这个值虽然可以测量,但一定程度上是个经验值,无法测准。

rssi测距公式

知道rssi和txPower后就可以计算距离了,有两种计算公式:

一、

微信小程序iBeacon测距及稳定程序的实现解析

这个公式里的三个变量A、B、C都是经验值,需要根据手机系统或硬件型号精确调校,通常会将所有设备的校准结果保存成一个设备信息表,移动终端先检测本机型号,然后匹配设备信息调取相应的计算配置,再进行计算。很明显这个公式是比较依赖硬件调校的,没有数据储备的前提下这个公式会很难用。

转换成js代码:

const calculateAccuracy = function (txPower, rssi) {
 return (0.89976) * Math.pow(rssi / txPower, 7.7095) + 0.111
}

未精校情况下的测距表现:

微信小程序iBeacon测距及稳定程序的实现解析

先说这个图怎么看。

  • 纵轴代表测量距离,横轴代表时间,每隔一秒取样一次,图中是近10次取样的数值曲线。
  • 绿线是设备接收到的rssi值,反应硬件真实接收到的数据情况;
  • 红线是套用公式计算得出的瞬时距离;
  • 黄线是微信小程序自带的瞬时测距结果。

蓝牙信标与手机的实际距离1m,测试设备为红米Note7。

从上图可见,rssi值相对稳定,说明硬件没有太大问题。红线和黄线的波动都很大,说明准确度不咋地。二者的波动趋势几乎一致,所以有理由怀疑微信小程序内部也是用的这个测距公式。从结果来看,这个公式的准确度比较差,可能是因为没有精校的原因。

二、

微信小程序iBeacon测距及稳定程序的实现解析

这个公式里的A就是rssi,tx是txPower,n是经验值,n的取值跟物理环境有关。

const calculateAccuracy = function (txPower, rssi) {
 return Math.pow(10, Math.abs(rssi - txPower) / (10 * 4))
}

公式二的测距表现:

微信小程序iBeacon测距及稳定程序的实现解析

人比人得死,货比货得扔啊。

图中黄线还是波动的那么疯狂,但红线却异常稳定,而且呈现出跟绿线一致的波动幅度,说明测距精度靠谱。这个公式只有一个参数,生产环境中的调校相对简单,这里我们选择公式二作为测距公式。

iBeacon测距稳定程序

蓝牙信号本身就有波动性,加上现实环境中的很多因素也会影响到信号强度,比如物体遮挡、设备方向变化、硬件自身的稳定性等,所以接收设备检测到的rssi值通常是“跳动”的,直接使用测距公式算出的结果,往往不可用。必须实现一个稳定程序,让计算结果呈现出连续性和稳定性。

数据滤波

稳定程序主要做的事就是对波段数据“削峰填谷”,也可以称作数据滤波。最简单的滤波处理,就是收集一段时间的值求平均,只要硬件不出问题,固定距离的蓝牙信标rssi值总是会在一个相对稳定的区间内变化,采样时间越长,采样的平均值就会越接近真实值,因此在静态测距场景中,求平均是最佳方式。

//求数组平均值
const arrayAverage = arr => arr.reduce((acc, val) => acc + val, 0) / arr.length;
return arrayAverage([...])

具体实现是,当程序源源不断的接收到信标的rssi时,先用公式计算出瞬时测距结果,然后将结果存进一个数组,然后计算这个数组的平均值。静态测距时,测量结果还是非常准的,2m以内的距离误差可以低至0.1m。

实际应用中往往都是动态测距,所以采样数据的长度要加以限制,比如按后进先出的顺序,取最近10组数据。具体采样队列设为多长,要根据项目实际需求而定。采样队列的长度越长,测距结果越平滑,但对移动端的动态捕捉越迟钝;反之采样队列越短,结果越锐利,对移动端的动态捕捉越灵敏。

有时因为一些偶然因素,采样队列中会出现个别大幅偏离真实值的“燥音”数据,即使求平均也难以有效抹除影响,为消除这种影响,可以在求平均前先用高斯模糊算法对“偏大值”和“偏小值”做平滑处理,最大限度的降低数据噪音的干扰。

高斯模糊算法的关键是根据平均差求权重,一维高斯模糊的权重计算公式:

微信小程序iBeacon测距及稳定程序的实现解析

转换成js代码:

//求一维队列某点的高斯模糊权重 @param(队列长度,目标位置, 平均差)
const getOneGuassionArray = function (size, kerR, sigma) {
 if (size % 2 > 0) {
  size -= 1
 }
 if (!size) {
  return []
 }
 if (kerR > size-1){
  return []
 }
 let sum = 0;
 let arr = new Array(size);

 for (let i = 0; i < size; i++) {
  arr[i] = Math.exp(-((i - kerR) * (i - kerR)) / (2 * sigma * sigma));
  sum += arr[i];
 }

 return arr.map(e => e / sum);
}

关于“偏大值”和“偏小值”的概念将在下文介绍,这里只要知道我们的模糊目标是那些“极端数据”就行了。

时间加权

基于采样队列求平均的处理方式,不可避免的会让结果产生滞后性,这时可以引入时间加权的补偿算法。

所谓时间加权,是指在求平均值的时候,给距离当前时间较近的值更高的计算权重,反之给距离当前时间较远的值较低的计算权重,实现起来也非常简单。

以最简单的权重分配为例,将采样队列一分为二,按时间远近定位为“当前组”和“过去组”,比如说我想让当前组的权重是过去组的2倍,那么只要将当前组数据全部复制一份加入队列,然后再计算新队列的平均值。

//时间加权处理
queue = queue.slice(0, parseInt(queue.length / 2)).concat(queue)
//求平均
return arrayAverage(queue)

动态跟进

经过时间加权处理后,数据的滞后性会得到一定的抑制,但如果遇到比较“陡峭”的距离变化,这种处理仍然会给出一个相对“平滑”的反馈,为了让稳定程序能更好的感知动态变化,并且做出跟进反应,还需要人为的设置一些特殊条件。

首先,如何判断移动设备正在远离或靠近?

这里有一个简单的思路,可以先找出采样队列中的最大值和最小值,然后以一定的阈值找出偏大值和偏小值。比如队列中的最大值是3,最小值是1,阈值设置为0.1m,那么大于2.9m的数据都算偏大值,小于1.1m的数据都算偏小值。偏大值和偏小值的队列长度最长不超过总队列的二分之一。

然后,如果偏大值集中在队列的前三分之一部分,那么我们可以认为移动设备正在果断远离;反之偏小值集中在队列的前三分之一部分,则可以认为移动设备正在靠近。

//maxCount为偏大值的序号数组
//minCount为偏小值的序号数组
//queueLength为队列长度

if (arrayAverage(maxCount) < parseInt(queueLength / 3)) {
  console.log(`正在远离`)
} else if (arrayAverage(minCount) < parseInt(queueLength / 3)) {
  console.log(`正在靠近`)
}

基于这种远离和靠近的趋势判断,我们可以人为的让数据向运动方向做更激进的倾斜。怎么做呢?跳过时间加权逻辑,如果判断为正在远离,那么就将队列中的偏小值过滤掉,反之则将偏大值过滤掉,只计算剩下的数据;这种处理会得到一个明显过激的结果,但考虑到现实世界中的运动往往具有惯性,这种激进处理,可能会更贴合真实的运动情况,而且让数据的响应更“灵敏”。

效果检验

做到目前为止效果怎么样呢,直接看图吧。

下图中,绿线依然是rssi值,红线是根据rssi直接算出来的瞬时测距结果,黄线是加入稳定程序后的测距结果。

第一张图是相对静止的条件,可以看到黄线相对红线明显更加平稳,说明稳定程序还是起作用的。

微信小程序iBeacon测距及稳定程序的实现解析

第二张图是模拟快速远离的场景,可以看到黄线在保证平稳的前提下紧跟红线,没有被甩掉,主要体现的是稳定程序的动态跟进效果。

微信小程序iBeacon测距及稳定程序的实现解析

第三张图是抡胳膊甩手机+遮挡信号模拟出的场景,貌似稳定程序也架不住了,有点飘忽。

微信小程序iBeacon测距及稳定程序的实现解析

以上是关于稳定程序的简要实现思路,生产环境中肯定会面临更加复杂的情况,免不了还要做大量调试,这里只是抛砖引玉。

总结

蓝牙测距简单来说就是一个公式的应用,本身比较简单,基于测距可以实现很多近场应用,比如近场签到、近场推送等等,更进一步甚至可以实现对移动设备的定位,有了定位信息,很多室内定位、室内导航相关的应用就都可以实现了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
让GoogleCode的SVN下的HTML文件在FireFox下正常显示.
May 25 Javascript
jQuery学习笔记 更改jQuery对象
Sep 19 Javascript
JQuery给元素添加/删除节点比如select
Apr 02 Javascript
一个简单的弹性返回顶部JS代码实现介绍
Jun 09 Javascript
JQGrid的用法解析(列编辑,添加行,删除行)
Nov 08 Javascript
JavaScript的类型、值和变量小结
Jul 09 Javascript
jQuery网页版打砖块小游戏源码分享
Aug 20 Javascript
javascript入门教程基础篇
Nov 16 Javascript
Javascript blur与click冲突解决办法
Jan 09 Javascript
JavaScript实现三级联动菜单实例代码
Jun 26 Javascript
Three.js实现浏览器变动时进行自适应的方法
Sep 26 Javascript
ES10的13个新特性示例(小结)
Sep 23 Javascript
JS获取动态添加元素的方法详解
Jul 31 #Javascript
JS/jQuery实现超简单的Table表格添加,删除行功能示例
Jul 31 #jQuery
详解Vuex下Store的模块化拆分实践
Jul 31 #Javascript
ES6 Iterator接口和for...of循环用法分析
Jul 31 #Javascript
Vuex 模块化使用详解
Jul 31 #Javascript
判断“命令按钮”是否被鼠标单击详解
Jul 31 #Javascript
express框架下使用session的方法
Jul 31 #Javascript
You might like
一个PHP验证码类代码分享(已封装成类)
2011/07/17 PHP
浅析memcache启动以及telnet命令详解
2013/06/28 PHP
php中文字符串截取方法实例总结
2014/09/30 PHP
typecho插件编写教程(六):调用接口
2015/05/28 PHP
php实现通过cookie换肤的方法
2015/07/13 PHP
Laravel中间件实现原理详解
2016/10/09 PHP
Mac系统下安装PHP Xdebug
2018/03/30 PHP
MooTools 页面滚动浮动层智能定位实现代码
2011/08/23 Javascript
Jqgrid表格随窗口大小改变而改变的简单实例
2013/12/28 Javascript
JavaScript中逗号运算符介绍及使用示例
2015/03/13 Javascript
JavaScript动态改变表格单元格内容的方法
2015/03/30 Javascript
javascript作用域、作用域链(菜鸟必看)
2016/06/16 Javascript
基于Javascript倒计时效果
2016/12/22 Javascript
react-native使用leanclound消息推送的方法
2018/08/06 Javascript
详解Vue开发微信H5微信分享签名失败问题解决方案
2018/08/09 Javascript
Layui数据表格之获取表格中所有的数据方法
2018/08/20 Javascript
回调函数的意义以及python实现实例
2017/06/20 Python
利用Python yagmail三行代码实现发送邮件
2018/05/11 Python
Python获取Redis所有Key以及内容的方法
2019/02/19 Python
Python Sympy计算梯度、散度和旋度的实例
2019/12/06 Python
python多项式拟合之np.polyfit 和 np.polyld详解
2020/02/18 Python
python求numpy中array按列非零元素的平均值案例
2020/06/08 Python
Python pexpect模块及shell脚本except原理解析
2020/08/03 Python
如何用python开发Zeroc Ice应用
2021/01/29 Python
CSS3 透明色 RGBA使用介绍
2013/08/06 HTML / CSS
JBL加拿大官方商店:扬声器、耳机等
2020/10/23 全球购物
城建学院毕业生自荐信
2014/01/31 职场文书
科级干部考察材料
2014/02/15 职场文书
大学迎新生标语
2014/10/06 职场文书
2014年优秀班主任工作总结
2014/12/16 职场文书
护理专业自我评价
2015/03/11 职场文书
幼儿园教师节活动总结
2015/03/23 职场文书
送给教师们,到底该如何写好教学反思?
2019/07/02 职场文书
聘任书的格式及模板
2019/10/28 职场文书
Go语言中的UTF-8实现
2021/04/26 Golang
如何用六步教会你使用python爬虫爬取数据
2022/04/06 Python