- 数据采集工具csi_tool采集数据并保存为后缀.dat的数据文件,在csi_tool中提供一个c语言函数解析此文件。用MATLAB进行处理涉及MATLAB和C语言联合编程的问题。该部分C语言的解析代码的数据文件组织方法其实就是计网中数据帧格式的组织方式,但稍有不同。
数据格式
数据文件中包含有n个采样信息,而整个文件仅由n个bfee组成,因此这个bfee的意义不言而喻,就是和采样一一对应,具体而言,在WiFi中的bfee是指Beamforming Feedback
,即波束成形反馈
。
Tips:
波束成形是一种通过调整无线发射和接收天线的方向性以改善信号质量的技术。
-
bfee
由三部分构成:field_len , code, field。
bfee的数据结构如上所示。前两字节是field_len,之后一字节是code,再之后便是可变长度的field。field_len等于code+field的字长。
当code为187时,表示field中是信道信息;不是187时,表示field中是其他信息。
我们关心的是信道信息,其他信息不解析,跳过该bfee即可。 -
field:
若code等于187,field有如上图数据格式。
到这里你一定感觉很熟悉了。 field分为头部和有效载荷(payload)两部分。头部有20字节的固定长度,有效载荷是个可变长度,字长为len。 -
header:
头部各字段的数据类型和意义如下表:
可以见得,头部中包含了主要的信道信息。而其中最重要的csi矩阵,分为30个子载波(subcarrier),保存在有效载荷payload中,分别对应30个子载波。 -
subc:
结构如下表所示:
-
复数
的结构:每个subc的开始会有3位的非数据部分,因此subc的长度不是字节(8位)的整数倍,这将导致subc这部分的解析需要按比特操作,如果用python进行解析将增加解析工作的复杂度。
到这里,整个文件的数据结构都清楚了,如果有人对python解析感兴趣,可以参考这个github。
数据读取
- 我们用MATLAB进行数据处理:
- 读取头部信息和csi矩阵,即read_bfee_file()
%% 读取原始数据
str = 'test1.dat';% 输入文件名字,这个dat文件是有3*3的天线对得到的
csi_trace = read_bf_file(str);
csi_trace(all(cellfun(@isempty,csi_trace),2),:) = [];%去掉空部分,以防设备传输出现丢数据问题
row = size(csi_trace,1);
result_matrix = zeros(row,541); % 第1~3*3*30=270列存储振幅,第271~540列存储相位,第541列存储时间戳
Fs = 1000; % 采样频率
可以看到,变量csi_trace
对应的就是bfee
,每一个bfee中有数据包的头部信息和CSI矩阵信息。
-
header
各字段详解:timestamp_low:
时间戳,相连两包此值差单位为微秒,此参数可以确定出波形的横轴时间,指代NIC网卡1MHz时钟的低32位,它大约4300s(72min)重复一回。当发包频率过大会出现接收端停止收数的情况:20Hz正常,200Hz和1000Hz的采样频率,收端最多接收一分多钟的的数据(原因是recv函数接收数据阻塞导致)。
1、将包长变小后还是有同样的问题。
2、由数据速率引起的,它太高,程序无法处理(可以尝试设置非阻塞)。bfee_count:
驱动记录并发送到用户控件的波束测量值的总数。内核和用户空间之间的netlink通道是有损的,因此可以使用这些通道检测掉入该管道的测量值,可以用该变星来检测被丢弃的测量值。Nrx:
接收端使用的天线数量。Ntx:
发送端使用的天线数量。rssi_a,rssi_b,rssi_c:
由接收端NIC网卡测量出的RSSI值,对应于每个天线端口输入端接收NIC测量的RSSI。noise:
噪声值。agc:
记录有关信号强度的信息,以便分析和优化通信系统的性能。antenna_sel:
天线_选择,用来计算perm。perm:
展示NIC如何将3个接收天线的信号置换到处理测量数据的3个RF链中,eg.数据(perm=[1 2 3])表示天线A被发送到RF链A,天线B被发送到RF链B,天线C被发送到RF链C。rate:
发包频率。csi:
是csi本身,规范化为一个内部引用。它是一个nTx * nRx * 30的三维矩阵,其中第三维是OFDM信道的30个子载波。
-
读取每一条数据
%% 计算,将该dat原始文件的振幅和相位都存储在result_matrix矩阵中
% 这一节得到是result_matrix,维度为result_matrix,该数据是3*3*30维的csi
for i = 1:row
%读取第i条数据
csi_entry = csi_trace{
i};%结构体形式
%读取并存储第i条数据的时间戳
result_matrix(i,541) = csi_trace{
i}.timestamp_low;
%读取第i条数据的CSI值
csi = get_scaled_csi(csi_entry);%复数矩阵,3*3*30
csi1 = squeeze(csi);% 去掉全为1的数组,复数矩阵,3*3*30
% 提取当前时刻的信号数据包
current_packet = csi1;
% 计算振幅信息
amplitude = abs(current_packet);
% 计算相位信息
phase = angle(current_packet);
% 将振幅和相位信息存储到result_matrix中
result_matrix(i, 1:270) = reshape(amplitude, 1, []);
result_matrix(i, 271:540) = reshape(phase, 1,