WiFi 感知人体行为监测
摄像头监控有天然的隐私阻力(卧室、卫生间、养老院老人的尊严问题),穿戴设备有「忘戴/抗拒」问题。这个项目走第三条路:利用环境中已有的 WiFi 信号做感知——人在房间里活动时,身体会反射和散射 WiFi 电磁波,改变信道的多径结构。接收端把这些变化(CSI)采集下来,用信号处理 + 机器学习解码出「有没有人、在做什么、有没有跌倒」。没有镜头、无需穿戴、全屋覆盖、成本几乎为零。
一、为什么 WiFi 能感知人体
WiFi 信号从发射端到接收端不止一条路径(直射 + 墙面反射 + 家具散射 + 人体反射)。人在环境中移动时:
- 多普勒效应:移动速度在电磁波上的投影引起载波频偏——跑步、走路、静止的频偏特征完全不同
- 多径扰动:身体占据/腾出某条路径,接收端 CSI 幅值和相位产生对应波动
- 呼吸微动:即使是静卧的人,胸腔起伏也会对路径长度产生毫米级调制——静息呼吸都能被捕获
信道状态信息(CSI,Channel State Information)比传统 RSSI 细粒度高两个数量级:RSSI 是整条信道的单一强度值,CSI 把 OFDM 每个子载波(常见 56/114 个)的幅相都给了出来——相当于从「一个数」变成「一张随时间变化的谱」。
二、系统架构
┌────────────────────────────────────────────────────────┐
│ 应用层 存在检测 · 跌倒报警 · 行为统计 · 呼吸监测 │
├────────────────────────────────────────────────────────┤
│ 模型层 时序分类模型(CNN+LSTM / Transformer) │
│ 跌倒检测 · 行为识别 · 多目标分离 │
├────────────────────────────────────────────────────────┤
│ 特征层 去噪 · 子载波筛选 · 多普勒时频图 · 统计特征 │
├────────────────────────────────────────────────────────┤
│ 采集层 CSI 采集(ESP32 / 网卡 CSI Tool)· 时间同步 │
├────────────────────────────────────────────────────────┤
│ 物理层 普通 WiFi 路由器 + 接收节点(无专用传感器) │
└────────────────────────────────────────────────────────┘三、采集层:CSI 从哪来
| 方案 | 载频 | CSI 质量 | 成本 | 适用 |
|---|---|---|---|---|
| ESP32(本项目主力) | 2.4G | 每包一组 CSI(幅值为主) | ~20 元/节点 | 大规模部署、产品化 |
| Intel 5300 CSI Tool | 2.4/5G | 30 子载波,科研经典 | 二手网卡 | 算法验证 |
| Atheros CSI Tool | 2.4/5G | 114 子载波,含相位 | 网卡 | 相位敏感算法 |
ESP32 的采集要点:
// ESP32 CSI 采集核心配置:只在信道空闲时拿到完整 CSI
wifi_set_csi(true);
wifi_csi_config_t cfg = {
.lltf_en = true, // 长训练字段——CSI 的来源
.htlf_en = true, // HT-LTF:802.11n 40MHz 频宽
.dump_ack_en = false, // 不要 ACK 包的 CSI(噪声大)
.val_of_dcm = 1,
};
wifi_set_csi_config(&cfg);
wifi_csi_register_cb(on_csi_received); // 每个 WiFi 包回调一次实战坑:采样率取决于环境中的 WiFi 流量——没人传数据就没有包、就没有 CSI。解法是接收端主动发 ICMP/UDP 探测包「喂」信道,把采样率稳在 100Hz 以上(跌倒检测的最低要求:事件持续 0.5~0.8s,需要足够的时间分辨率)。
四、特征层:把信号洗干净
原始 CSI 直接喂模型效果很差,信号处理的功夫决定了上限:
1. 去噪与去趋势
def preprocess(csi: np.ndarray) -> np.ndarray:
# ① 异常子载波剔除(恒为0或全满幅的坏点)
csi = csi[:, valid_subcarriers]
# ② Hampel 滤波去脉冲噪声(WiFi 包冲突造成的尖刺)
csi = hampel_filter(csi, window=5, sigma=3)
# ③ 去直流 + 归一化:消除收发链路增益差异(分环境自校准的关键)
csi = csi - csi.mean(axis=0)
csi = csi / (np.abs(csi).std(axis=0) + 1e-8)
return csi2. 子载波筛选
不是所有子载波都对人体敏感(有的子载波落在深衰落区,全程只有噪声)。用方差贡献法动态选 Top-K 灵敏子载波——顺带解决了「换环境后部分子载波失效」的域偏移问题。
3. 多普勒时频图:行为识别的核心特征
对 CSI 幅值做滑动窗口 STFT,得到的时频图里:
- 走路:多普勒谱上规律的「手臂-腿」双频带摆动(1~3Hz 步频谐波)
- 跌倒:短时(<0.5s)大速度冲击 → 高多普勒分量突现后迅速归零,且之后持续静止——和「快速坐下」的唯一区别就在跌倒后无恢复活动
- 起立/坐下:中等冲击但随后有伴随小幅调整动作
频率
↑ 跌倒特征:瞬时宽带冲击 + 后续静默
██████ │ ▓▓
│ ▓▓▓▓
│ ▓▓▓▓▓▓
│ ▁▁▁▁▁▁▁▁▁ ← 落地后静止
└──────────────────→ 时间
冲击 静默五、模型层:时序分类
| 任务 | 输入 | 模型 | 说明 |
|---|---|---|---|
| 存在检测 | CSI 幅值序列 | 一维 CNN + 统计特征 | 二分类,最难的是「无人的基线漂移」抑制 |
| 跌倒检测 | 多普勒时频图 | CNN(轻量) | 高召回优先——漏报是事故,误报只是打扰 |
| 行为识别 | 多子载波时序 | CNN + LSTM / Transformer | 走/坐/起/卧/跌倒等多分类 |
两个关键工程决策:
- 跌倒检测用「事件级联」而不是「逐帧分类」:先能量检测找候选事件 → 分类器判型 → 落地后静默 10s 确认 → 报警。三段式把误报率压下来(宠物跳沙发、重物落地都会被「落地后有恢复活动」这一条排掉)
- 模型必须轻到能跑在 ESP32 或网关上:量化后的 CNN 只有几十 KB——感知数据不该上云,行为事件才上云,这也是隐私承诺的一部分
六、最难的三件事(真实痛点)
1. 环境敏感性——换房间等于换模型
家具挪动、门窗开关都会改变多径基线。缓解手段(彻底解决至今是学界难题):
- 在线基线自适应:慢速滑动平均跟踪环境漂移(学习率 << 人体运动频率,环境变化慢、人动快,频域上分得开)
- 多收发对冗余:两对收发链路视角不同,环境扰动很少同时废掉两条
- 部署时的一次性「环境校准」流程(空屋采集 30s 基线)
2. 多人分离
两个人在房间里,CSI 是混叠的。工程上可用的手段:
- 多收发对(链路 = 准「视线」约束,两人对两条链路的扰动模式不同,配合聚类可分离)
- 行为级统计(不追求逐人识别时:占用人数估计用奇异值变化数近似)
3. 和 WiFi 业务的共存
探测包功率、频率要克制(不能为了感知把人家的网络刷出延迟);信道跳变(路由器 DFS/自动选信道)会让 CSI 流中断,接收端要监听信道事件并触发重新校准。
七、性能指标
| 指标 | 数值 |
|---|---|
| 存在检测准确率 | 【待补充】 |
| 跌倒检测召回/精确率 | 【待补充】 |
| 呼吸频率估计误差 | 【待补充】 |
| 事件报警延迟 | 【待补充】 |
| 端侧推理耗时 | 【待补充】 |
八、收获
这个项目最大的启发是换个视角看基础设施:WiFi 本来是通信管道,但它的物理层信号里藏着环境语义——「感知」不必新增传感器,解读已有信号就够了。另外对「隐私优先的设计」有了具体经验:信号不出户、模型在端侧、只上报事件语义——技术方案里每一个「多此一举」的本地化设计,在养老、医疗场景里都是产品能不能被接受的生死线。