蓝牙定位算法——处理多径效应问题
最近在做蓝牙定位项目的时候,标签总会在很短的时间窗口内上传多个数据基本相同的报文。
这里的Beacon-Tag-Base之间的数据传递逻辑是:
Tag在固定时间窗口内收集齐3个以上Beacon的广播信息后,进行一次广播,系统根据Tag的广播数据进行Tag定位。
当短时间内出现多条来自Tag且数据相同的报文时,基本可以判定为多径效应造成的数据重复接收。BLE基站没有对多径效应进行处理,这就需要服务器端的我来解决了。
想要解决这个问题其实也很简单,利用一个字典来保存当前收到报文的tag_code、时间戳以及rssi,收到新数据时,检查字典是否包含该tag_code,包含就对比时间戳,如果两者比较接近(比如相差不到0.2秒),则直接舍弃掉。舍弃掉的原因很简单:
- 就报文而言,除了时间和Tag自身的RSSI外是没有区别的,计算出来的定位点也是同一个点,所以没必要
- 实际的业务场景中对于定位频率的要求很低,可能10秒一定位,在满足基本业务需求的情况下还得照顾电池续航能力,所以其实1秒时间窗口内的报文都可以丢弃,只有在给客户展示的时候需要适当加快定位频率
python代码的实现 be like
......
TIME_WINDOW = 0.25 # 秒
<= RSSI_DIFF_TOLERANCE = 6
recent_beacons = {}
class BeaconData:
def __init__(self, major, minor, rssi):
self.major = major
self.minor = minor
self.rssi = rssi
def __str__(self):
return f"{self.minor[-1:]}:{self.rssi}"
def extractTagAndBeacon(data):
......
tag_id = ''.join(f'{byte:02X}' for byte in data[19:21])
base_code = ''.join(f'{byte:02X}' for byte in data[4:6])
current_time = datetime.now().strftime('%H:%M:%S.%f')[:-3]
current_timestamp = time.time()
rssi = data[6] - 256
if tag_id in recent_beacons:
last_timestamp, last_rssi = recent_beacons[tag_id]
if current_timestamp - last_timestamp < TIME_WINDOW and abs(last_rssi - rssi) <= RSSI_DIFF_TOLERANCE:
#print(f"Discarding multipath effect data for tag: {tag_id}")
recent_beacons[tag_id] = (current_timestamp, rssi)
return None, None, None
recent_beacons[tag_id] = (current_timestamp, rssi)
......
# survive from 多径效应检测,开始处理报文数据
return tag_id, iBeacon_count, beacon_data_list
def receiveData():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 8081))
print("Listening on port 8081...")
while True:
data, _ = sock.recvfrom(1024)
while len(data) >= 45:
tag_code, iBeacon_count, beacon_data_list = extractTagAndBeacon(data)
if not tag_code or not iBeacon_count or not beacon_data_list or iBeacon_count < 3:
break
# 处理业务
......
rec_thread = threading.Thread(target=receiveData, daemon=True)
rec_thread.start()