WIFI信号状态信息 CSI 数据处理篇之读取数据与数据解析(二)

本篇主要讲做完实验后怎么处理收集到的数据。处理数据的第一步是正确的读取和存储这些数据。本教程参考了发表在Ebaina上的
基于Wi-Fi CSI的摔倒检测(一):CSI数据的导入_专栏_易百纳技术社区 (ebaina.com)

在此基础上做出了一些修改。

目录

1 实验数据基本介绍和解包

2 数据读取

3 数据可视化

 4 完整代码及公开数据集地址

1 实验数据基本介绍和解包

关于实验的硬件和软件操作见
2022/07 CSI TOOL 安装及使用_Silver_777的博客-CSDN博客
在实验中,CSI TOOL接收端采集到的信号数据会自动存在linux-80211n-csitool-supplementary/injection/ 中,以dat文件形式存在。这种文件格式是不能被直接查看的,CSI TOOL的发布者同步写了一个Matlab函数“read_bf_file”帮助读取这些数据。相关的函数都在linux-80211n-csitool-supplementary\matlab中。在运行后续程序的时候,要把这个路径添加到matlab的运行路径中,不然会报错。 

以一个公开数据集的数据为例。我会一行一行代码的解释。(此公开数据集饰演的采样频率约为30Hz,属于较粗糙的水平)

close all
clear
clc

%% 读取原始数据
str = 'csi_a1_1.dat';% 输入文件名字
csi_trace = read_bf_file(str);
row = size(csi_trace,1);
result_matrix = zeros(row,181); % 第1~90列存储振幅,第91~180列存储相位,第181列存储时间戳

如上述代码所示,read_bf_file(文件名称)就可以调用函数读取,读取出的数据全部被存放在csi_trace这个单元胞数组中。每一个时间戳的数据包的所有相关信息都被封装在一个struct结构中。如下图所示,timestamp_low是时间戳,相邻数据包的时间戳间隔是10^6/采样频率,例如你的采样频率是100Hz,那么相邻数据包的时间戳基本相差10000(为什么说基本呢,因为我做实验的时候发现这个数值并不是严格一致,而是在 10^6/采样频率 上下微微浮动),Nrx是接受天线数量,Ntx是发射天线数量,我们所要使用的信号状态信息就是csi。

这个1×3×30的复数矩阵中。“1”表示发射天线数量,“3”表示接收天线数量,“30”表示每一路天线对包含的子载波数量(这个csi tool使用的intel 5300网卡就决定了每条天线对子载波数量是30)。因此可以看到,3条天线链路形成了90个子载波,也就是每一个时间戳的数据,都是由90个子载波构成的。这个矩阵全由复数构成,这与无线信号的特性相关。在无线通信中,信号一般被表示为复数,其中实部表示幅度(或强度),虚部表示相位(或角度)。在这种表示方式下,复数的模代表信号的幅度,复数的辐角代表信号的相位。

然后声明了一个result_matrix数组,将把这个每个csi的振幅和相位数据都存放进去。result_matrix的维度是(X,181),其中X表示时间戳个数;第二维度有181列,是由于每个数据包都包含90个子载波,第1~90列分别表示1~90号子载波的振幅数据,第91~180分别表示1~90号子载的相位数据,第181是时间戳。这样存储便于后面读取,三个关键的信息,振幅、相位、时间戳都有了,能够随时调用。(read_bf_file函数读取需要时间,如果你的采样频率又大采样时间又长,整体数据文件很大的话,会花费较长的时间)。

2 数据读取

在上一部分中,完成了dat原始数据文件的初步解包,并声明了数组result_matrix。接下来需要对csi中的复数矩阵进行计算,这里用Matlab自带的abs和angle函数就可以把振幅和相位信息提取出来。这一步也很简单,就是遍历一遍信号段,挨个算,代码如下。

%% 计算,将该dat原始文件的振幅和相位都存储在result_matrix矩阵中

for i = 1:row
    %读取第i条数据
    csi_entry = csi_trace{i};%结构体形式

    %读取并存储第i条数据的时间戳
    result_matrix(i,181) = csi_trace{i}.timestamp_low;

    %读取第i条数据的CSI值
    csi = get_scaled_csi(csi_entry);%复数矩阵,1*3*30
    csi1 = squeeze(csi);% 去掉全为1的数组以降维,复数矩阵,3*30

    % 提取当前时刻的信号数据包
    current_packet = csi1;%复数矩阵,3*30

    % 计算振幅信息
    amplitude = abs(current_packet);

    % 计算相位信息
    phase = angle(current_packet);

    % 将振幅和相位信息存储到result_matrix中
    result_matrix(i, 1:90) = reshape(amplitude, 1, []);
    result_matrix(i, 91:180) = reshape(phase, 1, []);
end

3 数据可视化

跑完数据了总要看看数据正不正常,所以有时候需要可视化看下信号图像。这里我plot了所有子载波共90根,如果想看单根天线的图像,修改画图代码即可。再result_matrix的排列是一根一根天线来的,例如在前90列的振幅数据中,1~30是第一个天线对的子载波,31~60是第二个天线对...在91~180的相位数据中,91~120是第一个...

% 可视化
% 振幅图
figure(1);
plot(result_matrix(:, 1:90));
xlabel('时间');
ylabel('振幅');
title('振幅随时间的变化');
grid on;

% 相位图
figure(2);
plot(result_matrix(:, 91:180));
xlabel('时间');
ylabel('相位 (弧度)');
title('相位随时间的变化');
grid on;

振幅图比较直观,可以看到振幅随着时间的变化,在信号不受干扰的时候,振幅是平稳的,当活动发生时,信号开始波动。 

 相位图由于相位跳变而导致图像显得很混乱,具体相位跳变的概念可以搜寻有关解释。总之相位的原始图是很混乱的,需要进行相位解卷绕处理。

 用matlab自带的unwrap函数做一个简单的接卷绕,代码如下

% 相位接卷绕后的图
phase_wrapped = result_matrix(:, 91:180); % 原始相位数据
phase_unwrapped = unwrap(phase_wrapped);

figure;
subplot(2, 1, 1);
plot(phase_wrapped);
title('Wrapped Phase');
subplot(2, 1, 2);
plot(phase_unwrapped);
title('Unwrapped Phase');

解卷绕前后图像如下 

 4 完整代码及公开数据集地址

close all
clear
clc

%% 读取原始数据
str = 'csi_a1_1.dat';% 输入文件名字
csi_trace = read_bf_file(str);
csi_trace(all(cellfun(@isempty,csi_trace),2),:) = [];%去掉空部分,以防设备传输出现丢数据问题
row = size(csi_trace,1);
result_matrix = zeros(row,181); % 第1~90列存储振幅,第91~180列存储相位,第181列存储时间戳

Fs = 1000; % 采样频率

%% 计算,将该dat原始文件的振幅和相位都存储在result_matrix矩阵中
% 这一节得到是result_matrix,维度为result_matrix

for i = 1:row
    %读取第i条数据
    csi_entry = csi_trace{i};%结构体形式

    %读取并存储第i条数据的时间戳
    result_matrix(i,181) = csi_trace{i}.timestamp_low;

    %读取第i条数据的CSI值
    csi = get_scaled_csi(csi_entry);%复数矩阵,1*3*30
    csi1 = squeeze(csi);% 去掉全为1的数组,复数矩阵,3*30

    % 提取当前时刻的信号数据包
    current_packet = csi1;

    % 计算振幅信息
    amplitude = abs(current_packet);

    % 计算相位信息
    phase = angle(current_packet);

    % 将振幅和相位信息存储到result_matrix中
    result_matrix(i, 1:90) = reshape(amplitude, 1, []);
    result_matrix(i, 91:180) = reshape(phase, 1, []);

end

% 可视化
% 振幅图
figure(1);
plot(result_matrix(:, 1:90));
xlabel('时间');
ylabel('振幅');
title('振幅随时间的变化');
grid on;

% 相位图
figure(2);
plot(result_matrix(:, 91:180));
xlabel('时间');
ylabel('相位 (弧度)');
title('相位随时间的变化');
grid on;

% 相位接卷绕后的图
phase_wrapped = result_matrix(:, 91:180); % 原始相位数据
phase_unwrapped = unwrap(phase_wrapped);
figure(3);
subplot(2, 1, 1);
plot(phase_wrapped);
title('Wrapped Phase');
subplot(2, 1, 2);
plot(phase_unwrapped);
title('Unwrapped Phase');

总结,这一部分的内容很简单,主要理解一下数据流,从dat文件→cell单元胞→struct结构体→csi复数矩阵和时间戳→计算振幅和相位→存储数据。

本博客使用的样例dat文件来自公开数据集wiar:
GitHub - linteresa/WiAR: WiFi-based activity recognition dataset

论文:

Wiar: A Public Dataset for Wifi-Based Activity Recognition

Wiar: A Public Dataset for Wifi-Based Activity Recognition | IEEE Journals & Magazine | IEEE Xplore

  • 27
    点赞
  • 119
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值