ESP32 CSI 人体检测:采集、鲁棒特征、session 标定与误报评估

作者 Wu Jun · 更新于 2026-10-29 · 约 6 分钟

ESP32 能把 Wi-Fi CSI 做成便宜的运动传感器,但“串口有数据”离“可用于自动化”还有几步: 固定发送端、确认 CSI 字段、建立空房基线、按 session 标定,以及报告误报/漏报。

本文把“人体检测”严格定义为运动代理:能发现活动,不能证明静止的人一定存在,也不能识别身份或人数。 方法级背景可参考 CSI 感知综述 [1]。

0. 先看结论

问题 正确回答
一块 ESP32 自己就能发射并接收测量吗? 不能;必须有路由器、第二块板或其他持续发包端
包率达到 100Hz,CSI 就是 100Hz 时间序列吗? 不一定;按实际匹配包、时间戳和丢失统计
ESP32 一定是 30–64 个子载波吗? 不固定;取决于 LTF、20/40MHz、STBC 和固件字段
motion score 能证明房间无人吗? 不能;静止、遮挡和多径都可能漏检
一段 30 秒数据能证明准确率吗? 不能;至少要独立 session,并报告误报/小时和延迟

1. 选采集拓扑

路线 硬件 优点 主要风险
单 ESP32 + 路由器 1 板 + AP 最便宜 发包率受 AP/省电/信道影响
双 ESP32 发送板 + 接收板 发送节奏更可控 两板 target、固件与时间轴需匹配
ESPectre / ESPHome 受支持 ESP32 直接生成 HA 实体 单区域覆盖,仍需现场标定

官方 esp-csi 提供 csi_recv_router、csi_recv 和 csi_send 等示例 [2]。ESPectre 则在设备端做运动检测并输出实体 [3]。

1.1 采集前必须确认的字段

ESP32 CSI 的每个复数样本通常是 int8 imaginary + int8 real,不能沿用路由器 int16 I/Q 的解析器。

2. 第一步不是算法,而是数据质量

先采 10 秒,输出以下统计:

frames_total
valid_csi_frames
duration = last_ts - first_ts
effective_rate = (valid_csi_frames - 1) / duration
gap_p50 / gap_p95 / gap_max
len histogram
RSSI min / mean / max
first_word_invalid count

如果有效帧率不足、包间隔不可解释或数据长度频繁变化,就不要进入阈值阶段。看起来“有波形”的 错误时间轴会让后续结论全部失效。

3. 先做逐子载波归一化

假设 H 是经过对齐的 frames × subcarriers 幅度矩阵。不要直接对原始幅度设置一个全局阈值: 不同子载波的噪声、衰减和缺失状态不同。

下面的代码只用“训练/空房 session”计算基线和尺度,再用它处理验证 session:

import numpy as np

def baseline_fit(H_quiet):
    baseline = np.median(H_quiet, axis=0)
    mad = np.median(np.abs(H_quiet - baseline), axis=0)
    scale = np.maximum(1.4826 * mad, 1e-6)
    return baseline, scale

def motion_series(H, baseline, scale, fs):
    # z 越大,表示当前子载波偏离空房基线的程度越高
    z = np.abs((H - baseline) / scale)
    frame_score = np.median(z, axis=1)      # 中位数抑制单个坏子载波
    width = max(1, int(round(fs)))          # 约 1 秒窗口
    kernel = np.ones(width) / width
    return np.convolve(frame_score, kernel, mode="same")

这只是透明、可复现的基线方法,不代表最优模型。任何深度学习或 ESPectre 模型也必须在独立 session 上验证; 不能在用于调参的空房数据上报告准确率。

4. 数据采集协议

类别 每段时长 建议 session 数 记录内容
空房 10 分钟 ≥ 3,不同时间 空调、窗帘、宠物、邻居干扰
正常走动 10 分钟 ≥ 3 不同速度、路径、距离
坐下/起立 5 分钟 ≥ 5 事件前后各 30 秒
静止坐着 10 分钟 ≥ 3 测试静止漏检
无人/有人交替 10 轮 ≥ 2 天 进入/离开时刻作为真值

记录:

采集协议至少覆盖两个位置、两个受试者;否则阈值很容易只拟合一个人和一个房间。训练/验证按 session 或日期切分,不能把相邻重叠窗口随机分到两边。

5. 阈值、滞回和保持时间

先分别得到:

q_quiet  = 训练空房 motion_series 的 P99
q_active = 训练活动 motion_series 的 P10

只有 q_quiet < q_active 且分离明显时,阈值才有意义。取中间区域并加滞回;如果两个分布重叠, 说明当前位置或特征无法区分,应先改硬件布局,而不是硬调阈值。

ENTER = q_quiet
EXIT = max(q_quiet * 0.8, q_active * 0.5)
MIN_ON_S = 0.5
MIN_OFF_S = 3.0

state = False
on_time = off_time = 0.0
dt = 1.0 / fs

for score in motion:
    if not state:
        on_time = on_time + dt if score > ENTER else 0.0
        if on_time >= MIN_ON_S:
            state, on_time, off_time = True, 0.0, 0.0
    else:
        off_time = off_time + dt if score < EXIT else 0.0
        if off_time >= MIN_OFF_S:
            state, on_time, off_time = False, 0.0, 0.0

这些是示例参数,不是各房间通用常数。真正的保持时间应由误报成本决定:开灯可以短, 安防报警必须长,并且需要人工复核。

6. 事件级评估

逐帧 accuracy 会对“没有运动”的多数样本过于乐观。家庭场景更应报告:

指标 定义
False alarms per hour 无人时每小时误触发次数
Event recall 真实事件在容差窗口内被发现的次数 / 总事件数
Miss rate while still 静止受试者被误判为无人的比例
Detection latency 事件真实开始到状态变 true 的时间
Release latency 人离开到状态变 false 的时间
Unavailable time MQTT/串口/HA 中断占比

若没有同步视频或人工事件表,只能报告“未标定运动代理”,不能报告准确率。建议在报告里给出 原始数据路径、代码 commit、阈值、包率、位置和失败 session。

7. 真实房间中的失败模式

现象 可能原因 正确修法
串口有日志但没有 CSI 未连上 AP或没有持续流量 先 ping/发送端,查 CSI enable
包率抖动 信道竞争、省电、串口带宽 固定发送端、关闭省电、降速绘图
子载波长度变化 不同 LTF/带宽/STBC 包 保留 len、mode 与 first_word_invalid
空房一直报警 空调/窗帘/宠物/邻居 重新采空房、延长窗口、剔除异常子载波
有人静止时显示无人 没有足够微动 加独立传感器,不能伪造 presence
办公室可用家里不可用 多径与 AP 位置变化 每个房间独立标定

8. 什么时候换路由器或增加传感器

如果目标覆盖多个房间,一台 MT6000 可共享采集和网络,减少每屋一块 ESP32 的维护;代价是要处理 mt76 固件、独立 AP、CSI 采样率与路由器性能。参考MT6000 复现教程。

如果目标是可靠安防或跌倒报警,单一 CSI 传感器不够。应增加独立传感器、人工复核、故障告警和 隐私合规评估,而不是用不存在的准确率承诺替代工程设计。

9. 从零开始的验收顺序

  1. 用官方示例得到 CSI_DATA;
  2. 验证 len、data 数量、时间戳和包率;
  3. 采空房/行走两个 session,画 motion score;
  4. 用独立 session 检查分布是否重叠;
  5. 设置滞回和保持时间;
  6. 连续跑 24 小时,统计误报和不可用时间;
  7. 最后才接 Home Assistant、灯或空调。

相关:ESP32 CSI 入门 · 接入 Home Assistant · 对比 mmWave 雷达 · Wi-Fi CSI 雷达

参考与数据来源

本文的每条外部结论都标注来源与证据等级(分级标准);标注 E 级的是本项目可复现的实测数据。

  1. A 级 · 标准/综述 WiFi Sensing with Channel State Information: A Survey
    W. Ma, W. Zhou, X. Wang · ACM Computing Surveys · 2019
    doi:10.1145/3310194 · 被引 857 · 核实: CrossRef API, 2026-10-11 · 领域内最常被引用的 CSI 感知综述(被引 857 次,核实于 CrossRef)。
  2. C 级 · 官方资料 espressif/esp-csi — Applications based on Wi-Fi CSI
    Espressif Systems
    github.com/espressif/esp-csi · 核实: GitHub API 2026-10-29 (stars 1,723; README confirms the complete ESP32 series list and three sender/receiver routes) · 官方 README 原文:“All ESP32 series support CSI, including ESP32 / ESP32-S2 / ESP32-C3 / ESP32-S3 / ESP32-C5 / ESP32-C6 / ESP32-C61.”
  3. C 级 · 官方资料 francescopace/espectre — Wi-Fi CSI motion sensing for ESP32 (ESPHome)
    F. Pace
    github.com/francescopace/espectre · 核实: GitHub API and official README fetched 2026-10-29 (stars 9,700; GPLv3; ESPHome source path, Direct API port 62587 and supported chips documented) · 官方项目提供 ESPHome、Native MQTT、Matter 与浏览器烧录路线;同一块 ESP32 覆盖一个区域,不识别身份或人数。
  4. C 级 · 官方资料 ESP-IDF — Wi-Fi Channel State Information (ESP32-S3)
    Espressif Systems
    docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-guides/wifi-driver/wifi-vendor-features.html#wi-fi-channel-state-information · 核实: official docs fetched 2026-10-29 (ESP32-S3 CSI section: LTF/byte-count table and the first_word_invalid note)
  5. C 级 · 官方资料 StevenMHernandez/ESP32-CSI-Tool — active/passive CSI extraction for ESP32
    S. M. Hernandez
    github.com/StevenMHernandez/ESP32-CSI-Tool · 核实: GitHub API 2026-10-11 (stars 571, MIT, last push 2024-07-16)