这几年做智能家居和室内感知方案,我接触过摄像头、毫米波雷达、红外阵列,各有各的麻烦。摄像头怕隐私争议,红外只能感知运动,毫米波效果最好但一套下来价格不低。
去年在开源社区翻到RuView这个项目,才意识到手边最普通的WiFi路由器,其实也可以改造成一套“隔墙识别人体动作”的感知系统。这篇文章就围绕RuView,把它的原理、硬件选型、数据采集、模型训练到实战踩坑完整拆一遍,给想入无线感知方向的朋友一条可复现的路径。RuView做的核心事情可以概括成一句话:用普通商用WiFi网卡采集信道状态信息(CSI),再通过机器学习模型把环境里的人体动作“读”出来。它不依赖摄像头,不需要用户佩戴任何传感器,甚至能做到隔墙检测。这套技术落在智能家居、老人照护、安防巡检等领域都很有价值,尤其适合嵌入式开发者、无线感知研究者以及做智能硬件方案的人参考。
1. RuView在做什么:用WiFi信号感知人体的思路拆解
1.1 它要解决的真实问题
室内人体感知这个需求,长期存在“三难”。
摄像头方案难在隐私和光线。卧室、卫生间、养老床位这些场景,摄像头一装争议就来了,而且夜间红外画质差,墙体遮挡更是直接失效。红外传感器难在分辨率和静态检测。PIR只能告诉你“有没有动”,人坐着不动十几秒,输出就归零了,更别提区分走路、摔倒这些细粒度动作。毫米波雷达难在成本与穿墙。60GHz毫米波对微动检测很灵敏,但环境稍复杂、隔一道墙,信号衰减就非常明显,且整机成本下不来。
RuView代表的WiFi感知路线,正好打在这三个痛点的空档上。WiFi基础设施家家都有,不用额外铺设备;信号具备一定的穿透能力,能感知到墙另一侧的大幅动作;采集的是信道特征而不是图像,天然没有隐私画面问题。它的定位不是替代毫米波,而是在“够用就行”的场景里提供一个成本极低、易部署的感知选项。做智能家居的人应该能直观感受到,这东西如果成熟了,等于给全屋加了一层无感的环境雷达。
1.2 从RSSI到CSI,看穿墙壁的原理
要理解RuView,得先弄清楚一个概念:为什么同样的WiFi信号,系统能知道你怎么动?
射频信号在室内传播时,会经历直射、墙体反射、家具散射、人体反射等一系列路径。接收端的信号,是所有路径叠加的结果,这就是多径效应。人体移动时,作为反射体的位置、姿态都在变化,各路信号的相对相位和幅度也随之变化,等价于信道响应持续在变。
早期的WiFi设备只上报一个叫RSSI的指标,它把整条链路上的接收功率压成一个单一数值。问题是这个数值太粗糙,人动一下和窗帘动一下,RSSI可能都是同一个波动量级,信息量不够用。
CSI则完全不同。在OFDM系统里,发送端把信号调制到多个子载波上,每个子载波都对应一个信道频率响应值,包含幅度和相位两个分量。接收端网卡测出来的,是一个“天线数×子载波数×时间帧”的高维矩阵。人体动作会引发特定子载波上的幅度起伏和相位跳变,这相当于在多条路径上同时留下了指纹。
穿墙的原理也在这里。2.4GHz和5GHz的电磁波能透过普通砖墙、木门、石膏板传播,墙体让信号衰减,但不至于中断。只要接收端还能解出信号,人的运动导致的路径变化就会反映在CSI上。说白了,墙是蒙住了“眼睛”,但没有蒙住“耳朵”,RuView做的就是把耳朵里听到的细微变化翻译成动作。
这里可以打一个生活化的比方:RSSI就像你在隔壁房间只听到有人大喊,而CSI就像你贴墙能听出屋里的人是走路还是搬椅子。信息维度完全不同,后面的处理方式自然也不同。
2. 方案选型解析:硬件、软件与工具链怎么配
2.1 硬件选型:哪些网卡能做CSI感知
先泼一盆冷水:不是所有WiFi网卡都能做CSI感知。普通网卡的驱动固件只把最终功率值上报给系统,CSI这种底层信道信息需要专门的固件和驱动配合才能掏出来。
我实测过几类方案,按照资料成熟度和上手难度排个序:
| 网卡/芯片 | 接口 | 可用的CSI工具链 | 上手难度 | 说明 |
|---|---|---|---|---|
| Intel 5300 | mini-PCIe | halperin/linux-80211n-csitool | 中等 | 经典方案,资料全,子载波30个,需老内核 |
| Intel 8260/8265 | M.2 | Linux 802.11ac CSI Tool | 较复杂 | 需要特殊固件,子载波50+ |
| Intel AX200/AX210 | M.2 | axCSI / Linux 802.11ax CSI Tool | 较复杂 | 支持802.11ax,采样率和稳定性更好 |
| Broadcom/Realtek | 板载 | Nexmon CSI | 较难 | 需刷固件,部分芯片已停产 |
| ESP32 | 板载 | ESP32-CSI | 简单 | 适合原型验证,子载波有限 |
如果你只想快速跑通RuView的体验流程,我建议先搞一块二手Intel 5300网卡,配一台带mini-PCIe接口的旧笔记本,跑经典的Linux CSI Tool。这个路线在网上能找到大量先例,资料和坑都被人踩过无数遍,遇到问题随便一搜就有答案。
如果要做新项目、追求更好的采样质量和带宽,直接考虑Intel AX200加axCSI。这块网卡便宜、好买,M.2接口在主流主板上都是标配,802.11ax下的信道探测能力更强,子载波数量能到200多个,感知细节更丰富。后面的实操部分按AX200+axCSI路线来讲,兼顾当前可用性和可扩展性。
2.2 软件工具链与数据处理路线
拿到CSI原始数据之后,RuView的整体链路其实很清晰:采集、预处理、特征提取、模型推理。
采集端使用CSI工具将网卡收到的信道信息包解析为带时间戳的幅度/相位数据。以axCSI为例,它基于Linux的mac80211框架,在monitor模式下可以持续导出CSI。预处理端数据会混入环境噪声、硬件增益波动和直流偏置,需要用带通滤波去掉与人体运动频率无关的分量。特征端的常见做法是把一段时间窗口内的CSI幅度矩阵按子载波排列成“时间×子载波”的二维热力图,直接喂给神经网络;也可以先做PCA降维,把几十上百路子载波的信息浓缩成几个主成分。推理端存在检测用阈值或轻量分类器就够了,动作识别用CNN或LSTM,部署时直接跑在采集端同一台PC,或者把数据转发到树莓派、NVIDIA Jetson上。
这套链路里最容易被忽视的是采集端的“稳定性”。WiFi信道本身是共享的,旁边有人看视频、下文件,CSI数值就会掺入别人的业务流量干扰。实操时建议先把网卡锁定在一个不那么拥挤的信道,再开始采集,否则后期预处理会花掉大量时间。
3. 实操全流程:从数据采集到模型部署
3.1 环境准备与系统配置
以Intel AX200+axCSI路线为例。硬件上准备一块AX200网卡、一台带M.2接口的Linux主机,我用的是Ubuntu 22.04,内核5.15以上基本都支持。软件上需要三块:axCSI的内核补丁、csitool的解析脚本、Python数据处理环境。
一个值得注意的点是,axCSI这类工具通常要求网卡工作在monitor模式。你需要先把系统的NetworkManager停掉,把无线网卡从managed模式切换到monitor模式,否则采集程序拿不到原始信道探测帧。具体做法是:
sudo systemctl stop NetworkManager sudo ip link set wlan0 down sudo iw phy phy0 interface add mon0 type monitor sudo ip link set mon0 up切换到monitor模式之后,用sudo iw dev确认模式生效。如果卡在这一步,多半是固件版本不对或者内核模块没有加载完整,后面我会单独列排查项。
接着安装axCSI。项目仓库里带了一个补丁脚本,针对内核源码打补丁后重新编译mac80211模块。这一步比较耗时,建议在终端挂着编译的同时,先把Python环境搭好:
pip install numpy scipy scikit-learn torch顺带一提,内核编译时建议先确认当前内核版本和补丁脚本要求的版本一致。版本错位是最常见的编译失败原因,而且错误日志不一定直观,看起来像是缺少依赖,实际是打补丁时上下文不匹配。
3.2 采集数据:关键参数与实际操作
实验拓扑不必复杂:把采集端电脑放在房间一侧,普通路由器作为发射端放在另一侧,两者之间留出一片人能走动的空间。人在中间来回走动、做指定动作,采集端记录CSI数据。如果想要穿墙效果,就把路由器放到隔壁房间,中间隔一面墙,人也在隔壁活动。
采集时需要配置的核心参数有三个。
第一个是信道带宽与中心频率。家用路由器建议用5GHz、80MHz带宽,子载波多,感知细节好;如果墙很厚,2.4GHz穿透性更好但子载波数少。这个取舍,按照实际墙体和距离来定。第二个是CSI采样率。也就是每秒导出多少帧CSI。人体运动的频率集中在0.2Hz到5Hz之间,采样率设在100Hz左右足够,太高会造成数据冗余,太低会漏掉快速动作。第三个是数据打标签。采集每个动作时,把开始时间和动作名称记下来。比如“actions/walk_01.bin”对应“01号走路样本”,模型训练阶段就靠这个对齐标签。
文件导出之后,csitool附带了一套MATLAB解析脚本,但不建议在MATLAB里做完整流程。推荐直接把它们转成Python可读的格式,核心代码逻辑很简单:
import numpy as np def parse_csi_file(file_path, num_antennas=2, num_subcarriers=234): # 简化版本:按记录块读取幅度 with open(file_path, 'rb') as f: raw = np.frombuffer(f.read(), dtype=np.uint8) # 实际数据需要按axCSI的帧头结构拆包 # 这里示意为:N个时间帧 × 天线数 × 子载波数 frames = raw[: len(raw) - len(raw) % (num_antennas * num_subcarriers)] csi = frames.reshape(-1, num_antennas, num_subcarriers) return csi.astype(np.float32)实际解析时,axCSI仓库里有一个log_to_csv工具,可以直接把原始日志导成CSV,包含每个天线每个子载波的幅度和相位。我的建议是:先拿官方工具导出CSV,用Pandas做初步检查,再换成numpy矩阵做后续处理,能少踩不少格式坑。
3.3 数据预处理:把CSI变成可学习的特征
拿到原始CSI之后,别急着往模型里塞。我踩过最深的坑,就是忽略了CSI里的低频漂移和硬件增益跳变。
人体运动导致的CSI变化,主要集中在0.2Hz到5Hz频段。环境温度变化、网卡自动增益控制引起的缓慢漂移,通常在0.1Hz以下;交流谐波等干扰又集中在更高的频率。所以第一步处理是带通滤波:
from scipy.signal import butter, filtfilt def bandpass_filter(data, lowcut=0.2, highcut=5.0, fs=100.0): nyquist = 0.5 * fs low = lowcut / nyquist high = highcut / nyquist b, a = butter(2, [low, high], btype='band') return filtfilt(b, a, data, axis=0)滤波之后,把数据按时间窗口切分。对于动作识别,2秒窗口、1秒步长比较通用;对于存在检测,1秒窗口就够了。切好的样本把“子载波”和“时间”两个维度保留成二维矩阵,直接变成热力图,是后续CNN最自然的输入。
如果觉得两百多个子载波直接进模型太冗余,可以做PCA降维,保留前10到20个主成分。我实测下来,PCA后的特征不仅训练速度更快,抗噪能力反而更好,因为主成分会自动把相关性高的子载波信息合并,噪声通道被压缩掉了。
3.4 模型训练与简单部署
模型部分分两级。
第一级是存在检测,最简单。把窗口内CSI幅度方差作为特征,设定一个阈值,超过阈值认为环境中有明显的人体活动。实测中这个方案在单人安静环境下的准确率能到90%以上。优点是零训练成本,适合先跑通全链路。
第二级是动作识别,需要一个分类模型。典型做法是把“2秒窗口×234个子载波”的幅度热力图当作单通道图像,用一个小型CNN分类。网络结构不用太复杂,两三个卷积层加上全局池化就够:
import torch.nn as nn class SimpleCSINet(nn.Module): def __init__(self, num_classes): super().__init__() self.features = nn.Sequential( nn.Conv2d(1, 32, kernel_size=3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, kernel_size=3, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d(1) ) self.classifier = nn.Linear(64, num_classes) def forward(self, x): x = self.features(x) x = x.flatten(1) return self.classifier(x)训练时数据划分为走路、坐下、举手、无活动四类,每类采集两三百个窗口样本,在CPU上训练几分钟就能收敛。部署时把模型导出成TorchScript,直接在采集端跑推理,延迟在几十毫秒量级。
这里想特别提醒一点:训练集和测试集最好分房间采集。你在A房间训练的模型,直接拿到B房间用,准确率会掉一截。原因是不同环境下多径分布差异很大,模型容易过拟合到当前房间的反射特征。
4. 实战中的常见问题与排查实录
4.1 问题排查速查表
整理一份我实际遇到过的、以及社区高频出现的问题速查表:
| 症状 | 可能原因 | 排查与解决 |
|---|---|---|
| 网卡驱动加载失败 | 内核版本过新/过旧,补丁未打全 | 检查内核版本,重新应用补丁,确认modinfo看到新模块 |
| monitor模式无法启用 | NetworkManager抢占网卡 | 停掉NetworkManager,使用iw命令手工切换 |
| 采集到数据全为0 | 发射端与接收端信道不匹配 | 确认两边都锁定到同一信道,关闭自动信道选择 |
| 数据噪声大、波形毛刺多 | 信道太拥挤,业务流量干扰 | 换到人少信道;采集时断掉大流量业务 |
| 静止人体检测不到 | 滤波把低频分量切掉了 | 存在检测里保留0.05Hz以上低频;或者增加天线数 |
| 穿墙后效果明显变差 | 发射功率太低或信道衰减过大 | 提高AP发射功率;换2.4GHz;缩短收发端距离 |
| 模型换房间精度暴跌 | 环境过拟合 | 多房间混合训练;用PCA提取环境无关特征 |
4.2 影响穿墙效果的关键因素
很多人把“穿墙”想成零成本,实际上隔墙感知的效果,由几个物理因素共同决定。
第一是墙体材质。砖墙、混凝土墙对2.4GHz的衰减差异很大,钢筋结构墙基本不要抱太大希望。第二是人离接收端的距离,人体反射的信号强度随距离衰减得很快,隔两堵墙还要求识别具体动作,现阶段并不现实。第三是天线布局。两条接收天线能提供空间分集,比单天线稳定得多,摆放时尽量让天线平面垂直于人体运动方向。
实测里还有一个容易被忽略的点:发射端和接收端之间如果存在直达路径,即便隔着墙,感知信噪比会好很多。也就是说,路由器和采集端不要刻意避开对方,让信号“直达”经过人体所在区域,多径变化量才足够大。反过来,如果把收发两端放得太偏,信号绕射路径太长,人体反射贡献就会被淹没在环境底噪里。
5. 从原型到落地:扩展场景与边界
5.1 几个值得做的落地方向
跑通RuView之后,能做的事比想象中多。
老人跌倒检测是当前比较刚需的方向。卫生间、卧室这种不便于装摄像头的场景,用存在检测加“快速大幅运动特征”识别跌倒,误报率比单用PIR低得多。睡眠状态监测也可以做,把采集端放在床侧,通过CSI的微弱呼吸起伏特征做存在检测,能实现无感监测,不打扰用户。
办公与仓库人员存在感知同样是落地价值很高的方向。判断房间内是否有人活动,联动空调、灯光做节能管理,这在无人值守场景里能直接省电费。多模态融合也是一个趋势,把WiFi感知和摄像头、毫米波雷达的结果合并,摄像头负责确认身份,WiFi负责隐私区域的运动信号,两个信号源互为补充,整体可靠性比单一传感器高不少。
这些方向都避开了WiFi感知“识别精度不如摄像头”的短板,把它的核心优势——穿墙、无隐私画面、低成本——放大出来了。做产品选型时,关键是想清楚你要的是精确识别还是趋势判断,WiFi感知更适合后者。
5.2 合规边界与隐私提醒
这一点必须单独讲。WiFi感知能“看”穿墙壁,天然带有隐私敏感性。技术本身是中性的,但使用必须限制在合理范围内:自有房屋、授权管理的办公空间、获得用户明确同意的照护场景,这些都没有问题。
不要把这项技术用于窥探他人、非法侦察或获取他人活动信息。做产品落地时,也应该在设计上就加入数据最小化原则:只提取识别所需的运动特征,不保存原始CSI数据,不采集可关联身份的信息。这也是我在这篇解析里反复强调“用自有设备、自有环境验证”的原因。无线感知和安防摄像头的边界,靠的不是技术能力,而是使用者的边界意识和产品设计的默认取舍。
6. 我个人实操中的几点体会
最后分享几个只有亲手做一遍才会注意到的细节。
第一,信道选择比模型调参更重要。同一个房间,2.4GHz拥挤信道和5GHz空闲信道下采集的数据质量,差别是肉眼可见的。我在实验时会把发射端固定信道,然后挨个扫一遍各信道的CSI底噪,选底噪最低的那一个再开始采集。
第二,天线方向性影响很大。我曾把采集端的天线平放,信号反射路径全部落在水平面,结果动作特征很弱;改成垂直摆放后,人体上下移动带来的相位变化也更明显,识别率明显提升。
第三,先跑通存在检测再上动作识别。用阈值检测把整个采集、滤波、特征提取链路跑顺,半小时就能完成。直接一上来就训练动作分类模型,很容易在数据格式、标签对齐这类基础问题上面浪费一整天。
RuView的价值在于它把一个原本停留在学术论文里的技术,压缩成了一个普通人也能搭建验证的开源方案。如果你正好手头有闲置的无线网卡和一台旧电脑,至少可以先用存在检测跑一遍完整链路,再决定要不要往动作识别深挖。无线感知这条赛道还在快速演进,RuView给了很好的起点,剩下的就是动手试错。