开发背景
1. CSI数据的定义
关于WIFI Sensing的资料参考此文档:什么是WIFI Sensing 技术? - 知乎 (zhihu.com)
CSI(channel state information)是无线通信中用于描述无线信道状态的信息,包括信噪比、干扰、多径效应等。
2. CSI数据的来源
在802.11协议中,CSI数据由接收端的物理层测量得到,并传递给数据链路层。测量方式包括显式反馈和隐式反馈两种。显式反馈是通过特定的管理帧或控制帧发送CSI数据,而隐式反馈则是通过ACK/NACK帧、重传次数等方式传递信道状态信息
3. CSI数据的应用
基于CSI的动作识别算法通过对WiFi数据包中的CSI信息进行预处理、特征提取和分类识别,识别出人的行为动作。系统包括前台客户端模块、后台管理模块和动作识别模块,能够准确快速地识别人的基本行为动作。目前国内很多大厂都有在研究。还有一种UWB的技术与其类似,在此不赘述了,有兴趣自己百度。
实现过程
本篇文章主要介绍MTK平台中抓取的CSI原始数据(.bin)文件如何解析出特定算法所需要的数据。由于保密需要,所以本篇本文章只简单做个分享,旨在记录下自己的工作流程。
1. 数据介绍
首先由于各芯片平台不同,其原始的CSI数据格式也不同,以MTK为例,其CSI数据的原始格式为.bin档,由于是.bin文件,所以无法直接查看,若虚查看,目前可通过BeyondCompare以16进制的形式打开,如图所示:选择Hex Compare,再把.bin文件拖入即可
CSI原始数据打开后如下图所示:
打开后以16进制的格式显示,单纯这样是看不出数据含义的。此时就需要针对IC厂商提供的解释文档去研究了
2. 数据分析
数据分析阶段的重点在于研究IC厂商提供的文档,以下简单截图示例
根据文档可知,数据的开头AC为magic number,然后后面length 为2byte的数据是数据长度(一个CSI的数据长度);也就是说后面04 50代表一个CSI段的长度。0450转换成十进制是1104个byte。
为了方便自己对数据的理解,我借用Excel将前1104个byte数据都copy下来,用来进一步分析用,如下图:
以上思路仅供参考哈!
3. 数据解析
数据分析理解完成以后,就要开始coding了,如何将十六进制数据根据文档解析出实际意义的数据来:
首先,你需要一个最基本的读取.bin文件的函数,将其中数据转为10进制:
def read_int(fd, byte_num, sign):
"""
:param fd: file stream
:param byte_num: byte number
:param sign: True/False True是有符号,False无符号的意思
:return:
"""
val = 0
try:
code = fd.read(byte_num)
if byte_num == 1 and sign == False: # 1byte 无符号
val = unpack('B', code)[0]
elif byte_num == 1 and sign == True: # 1byte 有符号
val = unpack('b', code)[0]
elif byte_num == 2 and sign == False: # 2byte 无符号
val = unpack('<H', code)[0]
elif byte_num == 2 and sign == True: # 2byte 有符号
val = unpack('<h', code)[0]
elif byte_num == 4 and sign == False: # 4byte 无符号
val = unpack('<I', code)[0]
elif byte_num == 4 and sign == True: # 4byte 有符号
val = unpack('<i', code)[0]
elif byte_num == 8 and sign == False: # 8byte 无符号
val = unpack('<Q', code)[0]
elif byte_num == 8 and sign == True: # 8byte 有符号
val = unpack('<q', code)[0]
return val
except Exception:
raise
然后需要写一个生成器函数(因为.bin文件太大,一次读取耗内存,所以需要每调用一次即返回一段CSI的数据(1104个byte))
根据IC厂商Manua即可将CSI数据解析出来,以下为部分内容截取:
最后,可根据需要将数据写入txt或者其他类型数据格式:
界面构建
以上只是简单介绍问题解决思路,重点在于如何构建一个简单GUI供客户使用
1. 界面需求
界面需求其实比较简单,只需要给用户提供一个窗口可加载原始CSI数据文件,然后再加几个Button将数据转为所需格式即可。这次使用的仍然是PysimpleGUI库
2. 界面实现
首先需要简单构建一个窗口,code如下,很简单
def make_window():
layout = [
[sg.Text('Select MTK CSI raw data to open:')],
[sg.Input(default_text='', size=(50, 2), key='-FILE-', tooltip='Click Browse to select csi raw data'), sg.Button('Browse', size=(12, 1), key='-BROWSE-', enable_events=True)],
[sg.Text()],
[sg.Push(), sg.Button('Convert to .npy', size=(12, 1), key='-NPY-', enable_events=True), sg.Push(), sg.Button('Convert to .txt', size=(12, 1), key='-TXT-', enable_events=True), sg.Push()],
[sg.Text()],
[sg.Text('Log output:')],
[sg.Output(size=(64, 6), key='-OUTPUT-')]
]
window = sg.Window('xxxx', layout, auto_size_text=True, size=(500, 320), finalize=True, enable_close_attempted_event=True)
return window
呈现的结果如下:
然后再将每个Button需要实现的功能写一下就OK了
def run_gui():
window = make_window()
while True:
event, values = window.read()
if event == '-BROWSE-':
filePath = sg.PopupGetFile('Select MTK raw data file', multiple_files=False, file_types=(("ALL Files", ".bin"),), no_window=True)
continue
if event == '-TXT-':
window['-OUTPUT-'].update('')
csi_file = window['-FILE-'].get()
if not csi_file:
sg.PopupError('Please select csi file !')
continue
ConvertCsi.dump_csi_to_txt(csi_file)
window.close()
总结
对于该数据类型转换的工作重点在于对原始数据的理解,其中对数据理解的部分占总体工作的80%,当你彻底理解数据后,那么开发起来就易如反掌了。
对数据的理解又离不开对文档的研究,所以切记要沉下心,这对于一名RD来说至关重要!
其实这边文章应该属于Python技术专栏,但是想着该工作最后的呈现是以GUI的形式,所以还是放到GUI专栏吧!就相当于对自己工作的记录了!