news 2026/10/4 15:55:54

openwifi 的 CSI 采集指南:从 FPGA 信道状态信息到 Chip State Information 的实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
openwifi 的 CSI 采集指南:从 FPGA 信道状态信息到 Chip State Information 的实战解析
  • 通信
  • 网络
  • 硬件开发
  • 嵌入式

【免费下载链接】openwifi

open-source IEEE 802.11 WiFi baseband FPGA (chip) design: driver, software

项目地址:https://gitcode.com/gh_mirrors/op/openwifi
点击查看免费下载

openwifi 在传统 CSI(Channel State Information,信道状态信息)概念之上做了巧妙的语义扩展,将其延伸为Chip State Information(芯片状态信息),通过 FPGA 内置的side channel(侧信道)基础设施,把 WiFi OFDM 接收机在解码每个数据包时产生的频率偏移、信道响应(Channel State/Response)与均衡器输出实时导流到上位机。本文基于 doc/app_notes/csi.md 应用笔记,结合 driver/side_ch/ 内核驱动与 user_space/side_ch_ctl_src/ 用户态工具源码,完整讲解 CSI 的快速上手、数据格式、条件捕获配置、均衡器输出数量(num_eq)配置、编译部署,以及如何借助 TSF 时间戳把 CSI 精确定位到每一个 WiFi 数据包。读完本文,你可以独立完成一次从 SDR 板到上位机的端到端 CSI 采集,并掌握离线分析 CSI 数据的完整工作流。

本文聚焦“通用 CSI 采集”。若希望利用 openwifi 全双工能力采集**自身发送(self-Tx)**信号的 CSI 实现类似雷达的感知功能,请参考姊妹篇 WiFi CSI radar via self CSI capturing。

快速开始:5 步拿到第一份 CSI

CSI 采集的全流程分成“板上采集”和“电脑显示”两段,二者通过以太网连接。前提条件如下:

  • SDR 板已上电,并通过网线直连一台电脑;
  • 电脑配置静态 IP192.168.10.1(该地址同时是 side_ch_ctl.c 中默认的远端服务器地址,见其server_ip = "192.168.10.1"定义);
  • 板上已按 openwifi 常规流程加载 FPGA 镜像、内核模块与无线驱动。

第 1 步:登录 SDR 板并启动通信栈。

ssh root@192.168.10.122 (password: openwifi) cd openwifi ./wgd.sh (Wait for the script completed)

wgd.sh完成 WiFi 驱动(sdr.ko 等)与 FPGA 镜像的加载初始化,是后续一切操作的前提。

第 2 步:进入监控模式并监听一个繁忙信道。

./monitor_ch.sh sdr0 11 (Monitor on channel 11. You can change 11 to other channel that is busy)

monitor_ch.sh 把网卡sdr0设为 monitor 模式并切换到指定信道(如 11 号信道),同时调用./agc_settings.sh 1打开自动增益控制,保证接收机以合适的增益捕获环境中的 WiFi 信号。

第 3 步:加载侧信道内核模块并开始采集。

insmod side_ch.ko ./side_ch_ctl g

side_ch.ko是 CSI 数据从 FPGA 到 Linux 用户态的桥梁(源码见 driver/side_ch/side_ch.c),side_ch_ctl g则以默认100ms周期反复向内核请求“侧信息”(side info)。板上终端会出现类似输出:

loop 64 side info count 61 loop 128 side info count 99 ...

其中每行第一个数字是请求循环次数(每 64 次打印一次),第二个数字是累计收到的有效侧信息条数。只要第二个数字非零且持续增长,就说明 CSI 数据正在顺畅地从板卡流向电脑——因为side_ch_ctl每收到一批有效数据,就会通过 UDP 4000 端口把它们推送到电脑端(对应sendto()逻辑见 side_ch_ctl.c)。

第 4 步:在电脑端(注意不是在 ssh 会话里!)启动实时显示。

cd openwifi/user_space/side_ch_ctl_src python3 side_info_display.py

首次运行前可能需要安装依赖:sudo apt install python3-numpy python3-matplotlib python3-tk。脚本启动后监听本机192.168.10.1:4000(见 side_info_display.py),实时绘制3 张图:

  • 频率偏移(freq offset):随数据包索引变化的频偏(单位 Hz);
  • 信道状态/响应(channel state/response):CSI 的幅值与相位随子载波索引的变化曲线;
  • 均衡器输出星座图(constellation from equalizer):均衡后 I/Q 符号的星座分布。

同时脚本在终端持续打印每条侧信息携带的timestamp(TSF 时间戳),并把所有原始数据追加写入side_info.txt文件。

第 5 步:离线分析。

采集过程中产生的side_info.txt可用仓库自带的 MATLAB 脚本 test_side_info_file_display.m 做离线解析与绘图,便于对 Chip State Information 做深入分析(如逐包观察 CSI 相位、频率偏移的时序变化)。

理解 CSI 特性:side channel 的架构与数据格式

架构:从 FPGA 到电脑的完整数据链路

CSI 信息是通过 openwifi 的side channel 基础设施提取出来的。整条链路可以概括为:

  1. FPGA 侧:WiFi OFDM 接收机(openwifi 基带 IP)在解码每个数据包时,把解码副产品(频率偏移、信道响应、均衡器输出)连同 TSF 时间戳打包成“侧信息”,交给 FPGA 中的side_ch逻辑模块;
  2. DMA 传输:侧信息通过 DMA 从可编程逻辑(PL)搬运到处理系统(PS)的内存。在 side_ch.c 的get_side_info()中,驱动先读取 FPGA 的SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR得到待搬运数据量,再通过 DMA 通道tx_dma_s2mm一次性拉取(每次搬运最多MAX_NUM_DMA_SYMBOL(8192)个 64bit DMA symbol);
  3. 内核侧:side_ch.ko(driver/side_ch/side_ch.c)是平台驱动,负责 FPGA 寄存器读写、DMA 搬运,并通过Netlink(NETLINK_USERSOCK)与用户态程序交互——收到ACTION_SIDE_INFO_GET请求即执行一次采集并回传数据;
  4. 用户态 + 网络:板上side_ch_ctl把收到的侧信息通过 UDP(目标端口 4000)发送到电脑;
  5. 上位机:side_info_display.py接收 UDP 数据包并解析、绘图、落盘side_info.txt,MATLAB 脚本test_side_info_file_display.m负责离线分析。

驱动侧与 FPGA 侧的所有寄存器地址都在 driver/side_ch/side_ch.h 中定义,例如配置寄存器SIDE_CH_REG_CONFIG_ADDR(索引 1)、num_eq 寄存器SIDE_CH_REG_NUM_EQ_ADDR(索引 4)、FC 匹配目标SIDE_CH_REG_FC_TARGET_ADDR(索引 5)、addr1/addr2 匹配目标(索引 6/7)等——这些正是下文side_ch_ctl whXhY命令操作的硬件寄存器。

数据格式:每条侧信息的 64bit 元素结构

每条侧信息的布局与长度定义在源码中以宏的形式统一维护(side_ch.h 与 side_info_display.py 保持一致):

  • HEADER_LEN = 2:timestamp 与频率偏移;
  • CSI_LEN = 56:单条 CSI 的长度;
  • EQUALIZER_LEN = 56 - 4 = 52:单组均衡器输出长度,其中非 HT(802.11a/g)模式只有 48 个子载波有效,末尾 4 个用{32767, 32767}填充补齐到 52;
  • 每组“传输单元”(一次采集携带的一条侧信息)总长为HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN个 DMA symbol,每个 DMA symbol 实际大小为64bit。

具体到每个字段(每元素 64bit):

字段占用说明含义
timestamp64bit TSF 定时器值与 tcpdump、wireshark、dmesg 中 openwifi 打印的时间戳是同一个值,是 CSI 与 WiFi 数据包匹配的唯一身份标识
freq_offset仅使用低 16bit频率偏移估计值
csi(信道状态/响应)仅使用前两个 16bit(I/Q)56 个子载波上的信道响应,剩余两个 16bit 为未来多天线场景预留
equalizer仅使用前两个 16bit(I/Q)均衡器输出,剩余两个 16bit 预留

关于子载波有效性:802.11n 下 56 个子载波全部有效;802.11a/g 下仅 52 个子载波有效,均衡器输出仅 48 个子载波有效(其余以填充值补足 52)。

理解数据包格式最精确的方式是阅读并运行附带的 Python 与 MATLAB 脚本:side_info_display.py 中的parse_side_info()逐条解析出 timestamp(由 4 个 16bit 拼成 64bit TSF)、freq_offset、csi 与 equalizer 数组;MATLAB 侧test_side_info_file_display.m的b = reshape(a, [4, length(a)/4])'同理完成解析。

配置捕获条件:只采集你关心的数据包

快速开始默认采集 OFDM 接收机解码的所有数据包的 CSI。如果只想采集满足特定条件的数据包,需要在执行./side_ch_ctl g之前下发配置命令。配置通过向side_ch_ctl传入不同参数实现,参数格式为:

whXhY

其中:

  • w:写入(write);
  • h:硬件寄存器(hardware register);
  • X:寄存器索引;
  • h:十六进制(hex);
  • Y:十六进制格式的寄存器值。

其余字符保持原样。这套语法由 side_ch_ctl.c 中的parse_para_string()解析,命令最终经 Netlink 到达内核驱动,由side_ch_nl_recv_msg()执行reg_write(reg_idx*4, reg_val)写入 FPGA 寄存器(见 side_ch.c)。对应关系(寄存器索引在 side_ch.h 中定义):

寄存器索引 X含义用途
1CONFIG 配置寄存器开关条件匹配:bit12=FC 匹配开关、bit13=addr1 匹配开关、bit14=addr2 匹配开关;bit11~bit0 应保持001
5FC 匹配目标寄存器指定 FC(Frame Control)匹配值
6addr1 匹配目标寄存器指定目标 MAC(addr1)匹配值
7addr2 匹配目标寄存器指定源 MAC(addr2)匹配值

打开/关闭条件捕获(寄存器 1)

Y的 bit 含义:

  • bit11~bit0:应为001(十六进制);
  • bit12:FC 匹配开关(1=开);
  • bit13:addr1 匹配开关(1=开);
  • bit14:addr2 匹配开关(1=开)。
# 仅匹配 FC ./side_ch_ctl wh1h1001 # (1001 为十六进制值) # 仅匹配 addr2(源地址) ./side_ch_ctl wh1h4001 # 同时匹配 FC 和 addr1(目标地址) ./side_ch_ctl wh1h3001 # 关闭条件捕获(采集所有数据包) ./side_ch_ctl wh1h0001

指定匹配目标(寄存器 5/6/7)

当某种匹配被上面的命令打开后,用下列命令指定匹配目标:

# 指定 FC 匹配目标 ./side_ch_ctl wh5hY # (Y 为十六进制 FC 值) # 指定 addr1(目标地址)匹配目标 ./side_ch_ctl wh6hY # 指定 addr2(源地址)匹配目标 ./side_ch_ctl wh7hY # (Y 为十六进制 MAC 地址,只需 MAC 的后 32 位。 # 例:对 56:5b:01:ec:e2:8f,应输入 01ece28f)

完整示例:只采集 MAC 地址为56:5b:01:ec:e2:8f的设备发出的数据包的 CSI:

./side_ch_ctl wh1h4001 ./side_ch_ctl wh7h01ece28f (01ece28f are the last 32 bits of MAC address 56:5b:01:ec:e2:8f) ./side_ch_ctl g

说明:驱动dev_probe()初始化时会把 CONFIG 寄存器写为0x7001(同时打开 FC/addr1/addr2 匹配这一“最严格条件”以在启动阶段抑制侧信道动作),随后再写回0x0001允许所有数据包(见 side_ch.c),因此用户在下发g之前的配置命令会按顺序覆盖该寄存器。

自定义采集周期

side_ch_ctl g默认每100ms采集一次,直到按Ctrl+C退出。如需其他周期:

side_ch_ctl gN

周期即为N*1ms(例如g400表示每 400ms 采集一次;g0表示尽可能连续采集,雷达自 CSI 场景即使用此参数)。解析逻辑见 side_ch_ctl.c:未带参数时默认 100ms,非法输入也会回退到 100ms。

配置 num_eq:按需裁剪均衡器输出

num_eq(均衡器输出组数)决定每条侧信息携带多少组均衡器输出(每组 52 个)。如果不需要这么多均衡器信息,可以调小以降低单条数据量与网络/存储开销。合法取值范围是0~8。

关键约束:num_eq必须在三处保持一致——内核模块side_ch.ko、Python 脚本side_info_display.py、MATLAB 脚本test_side_info_file_display.m,否则解析会错位。

  • 加载内核模块时:
insmod side_ch.ko num_eq_init=3

可把 3 换成 0~8 中的任意数。8 是默认值(快速开始一节无需显式指定)。该参数对应驱动中的模块参数num_eq_init(默认 8,声明见 side_ch.c),dev_probe()会把它写入 FPGA 的SIDE_CH_REG_NUM_EQ_ADDR寄存器,并在每次get_side_info()中用它计算单次传输所需 DMA symbol 数:HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN(见 side_ch.c)。

  • 启动 Python 脚本时:
side_info_display.py 3

脚本第一个位置参数即 num_eq(默认 8),见 side_info_display.py 的参数解析。

  • 使用 MATLAB 脚本时:修改 test_side_info_file_display.m 中的num_eq变量(默认 8)为对应值(3 仅为例)。

编译 side channel 驱动与用户态程序

CSI 功能需要自行编译两个组件:

1. 内核模块side_ch.ko

$OPENWIFI_DIR/driver/side_ch/make_driver.sh $OPENWIFI_DIR $XILINX_DIR ARCH_BIT

其中$OPENWIFI_DIR是 openwifi 仓库根目录,$XILINX_DIR是 Xilinx 安装目录,ARCH_BIT取 32 或 64:Zynq 7000 平台填 32,Zynq MPSoC 平台填 64。脚本内部会设置内核源码目录(KDIR)并调用 driver/side_ch/Makefile 完成模块编译。

2. 用户态程序side_ch_ctl

side_ch_ctl需要在 SDR 板上编译,源码为 user_space/side_ch_ctl_src/side_ch_ctl.c:

gcc -o side_ch_ctl side_ch_ctl.c

在 monitor 之外的模式下运行 CSI

CSI 功能并不局限于 monitor 模式。openwifi 的 CSI 采集可以与AP-Client(AP/STA)模式、ad-hoc 模式等正常通信模式同时运行:先把通信功能在相应模式下完全建立起来,然后照常执行板上两步——insmod side_ch.ko与./side_ch_ctl g——即可在正常收发数据的同时把 CSI 提取到电脑端。这为“联合通信与感知”(joint radar and communication)类应用提供了便利,例如在 AP 模式下为某个关联站点持续采集其数据包的信道响应。

将 CSI 映射到具体的 WiFi 数据包

CSI 与 WiFi 数据包的对应关系,是分析(如信道探测、感知)时最常遇到的问题。

  • 如果要在采集 CSI 的同时关联到具体 WiFi 数据包,需要用tcpdump / wireshark 等工具同步抓包;
  • 然后以timestamp(TSF 定时器值)作为唯一关联键,把 WiFi 数据包与 CSI 信息匹配起来——因为 TSF 时间戳是同一个 WiFi 数据包与其对应 CSI 信息的唯一共同身份标识;
  • 具体逐包提取 CSI 的方法,请学习 Python 脚本 side_info_display.py 的parse_side_info()与 MATLAB 脚本 test_side_info_file_display.m(后者的idx_to_check参数即可用于查看指定索引单包的 CSI 曲线),按需定制自己的解析逻辑。

关于该映射机制的更详细讨论,可参考 openwifi 社区讨论串(docs/discussions 中亦有引用,详见 doc/app_notes/csi.md 原文)。

小结与延伸

通过本文你应该已经掌握:openwifi 如何以 side channel 为骨架把 FPGA 解码过程中的频率偏移、信道响应与均衡器输出实时搬运到上位机;64bit 元素的 CSI 数据格式与side_ch.h/脚本中的长度宏如何一一对应;如何用whXhY参数串完成 FC/addr1/addr2 条件捕获与gN周期配置;如何用num_eq_init裁剪数据量并在三处工具间保持一致性;以及如何借助 TSF 时间戳把 CSI 关联到具体 WiFi 包。仓库中的 doc/app_notes/csi.md、driver/side_ch/side_ch.c、user_space/side_ch_ctl_src/side_ch_ctl.c 与两个解析脚本是进一步深挖的第一手资料。若想利用本平台的全双工自收自发能力,把 self-Tx CSI 用于雷达感知,请继续阅读 WiFi CSI radar via self CSI capturing。

  • 通信
  • 网络
  • 硬件开发
  • 嵌入式

【免费下载链接】openwifi

open-source IEEE 802.11 WiFi baseband FPGA (chip) design: driver, software

项目地址:https://gitcode.com/gh_mirrors/op/openwifi
点击查看免费下载

相关推荐

上一篇:IoT-For-Beginners 硬件实战:Wio Terminal 开发板入门与 PlatformIO Hello World 完整指南
下一篇:StarRocks Shared-nothing 与 Shared-data 两种部署架构的功能差异全解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/4 15:55:46

降AIGC工具红黑榜:TaoToken统一API通道下的选型避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 15:55:20

Windows下ESP32-C3开发环境搭建:VS Code与AI辅助从零到点亮LED

1. 为什么要在 Windows 上折腾 ESP32-C3 这套环境先说结论:如果你手头有一块 ESP32-C3 开发板,想在 Windows 上把开发环境跑通,并且希望用 AI 辅助写代码来降低入门门槛,那这套组合是值得花一个下午搞定的。ESP32-C3 是乐鑫推出的…

作者头像 李华