
ESPectre 统一 Raw CSI 采集HTTP 单传输协议、固定环缓冲与可观测丢帧设计解析【免费下载链接】espectreWi-Fi CSI motion sensing for ESP32. C SDK, ESPHome, Native, and Matter frontends, browser tools, and a CLI for the full device lifecycle. GPLv3 and commercial licensing.项目地址: https://gitcode.com/GitHub_Trending/es/espectre本篇文章深入解析 ESPectre 项目的一则关键架构决策记录ADR将原始 Wi-Fi CSI 数据采集从专用 C Streamer 前端统一迁移到 raw HTTP 单一传输路径。你将了解 ESPectre 如何保证采集数据在顺序、溯源provenance与可观测性上的严格约束掌握GET /csi会话所有权模型、60 字节传输前缀与 CSI V8 记录格式、设备端 16 槽 SPSC 环形缓冲与丢帧计数不变量以及./espectre collect与外部 UDP 流量生成器的完整实操用法。背景为何统一 Raw CSI 采集传输ESPectre 的高速率 CSI 采集最初沿用了 Python 原型路径进入 C 架构后由一个独立的 Streamer 前端承担它以采集端collector节拍发送 UDP并在固件侧实现显式发送背压TX backpressure。这一方案让采集行为与 C 架构对齐但带来了沉重的架构负担——独立前端意味着要重复维护 Wi-Fi 生命周期、mDNS 发现、构建、发布与校验逻辑。与此同时其余被维护的传感前端Native、ESPHome、Matter已经具备 raw HTTP 路径。当同一能力存在两套传输实现时采集结果会依赖具体传输介质数据集的可复现性也随之受损。因此本 ADR 的核心决定是移除 Streamer 前端raw HTTP 成为所有受支持 ESPectre 前端唯一的在线采集传输并对外发布协议版本号1CSI 记录版本保持8。需要说明的是该 ADR 状态标记为 Superseded in part部分被取代二进制帧格式、记录顺序、溯源字段与固定环缓冲行为仍然有效并被采纳而显式命令创建会话与 bearer 绑定机制已由 2026-09-03 采用面向资源的设备 API 取代——即现在的GET /csi自动拥有整个采集会话的生命周期。决策原始采集保持原样转发的数据面raw 采集是研究数据的入口它的数据面在设计上刻意保持被动不改变已配置的流量来源、不对输出做节拍控制、不挑选最新鲜的样本、也不应用时间接纳temporal admission逻辑。任何设备侧的选择性行为都可能隐藏丢帧或引入数据集偏差因此每个被分类classified的原始帧按顺序进入一个预分配的 16 记录原子 SPSC 环形缓冲一个由任务通知task-notified驱动的专用 worker 每次最多按序发送 4 条记录环形缓冲满时丢弃最新帧并累加显式计数器每个被投递的帧在入队前获得 64 位流序号stream sequence因此任何丢弃都会在流中形成可观测的序列空洞而不是被静默替换。设备端数据面从 CSI 回调到 HTTP 分块发送源码级实现印证了上述设计。采集数据面的核心位于 direct_http_service_esp_idf.cpp 的offer_raw_packet()回调上下文先检查会话激活状态然后通过raw_offer_sequence_.fetch_add(...)为每个投递帧分配单调递增的 64 位流序号对载荷做边界校验非空、偶数长度、不超过kRawSlotPayloadBytes即 HT20 的 64 复数子载波归一化长度非法样本计入raw_drop_total_通过头尾原子索引判断tail - head kRawQueueDepth队列深度固定 16来决定是否丢弃入队成功后以 release 语义推进 tail 并通知 raw worker见 direct_http_service_esp_idf.h 中kRawQueueDepth 16U、kRawBatchRecords 4U。发送侧service_raw_stream_()每次从环形缓冲弹出至多 4 条记录kRawBatchRecords每条记录前追加 60 字节 HTTP 帧前缀然后一次性httpd_resp_send_chunk发送。若发送失败固件累加raw_send_backpressure_total将该批次全部计入丢弃并以SLOW_CLIENT停止会话——这就是网络发送前隐藏损失可被量化的机制来源。关键的丢失可观测性不变量如下在数据排空drain后恒成立fresh_record_total raw_drop_total classified_frames_offered_to_raw其中classified_frames_offered_to_raw就是流序号。该不变量在 C 测试 test_direct_http_service.cpp 中被显式验证投递 17 个样本、环形缓冲满 16 后测试断言fresh_record_total 17、raw_drop_total 1、stream_sequence fresh_record_total raw_drop_total 18从而证明任何丢失都会同时反映在计数与序号空洞上。线缆协议60 字节 HTTP 前缀 CSI V8 记录raw HTTP 为每条 CSI V8 记录前置一个 60 字节的传输记录。传输层协议常量与结构体定义在 raw_csi.h端点/espectre/v1/csiESPECTRE_RAW_CSI_ENDPOINT协议版本1ESPECTRE_RAW_CSI_PROTOCOL_VERSION记录版本8ESPECTRE_RAW_CSI_RECORD_VERSION会话 ID16 字节ESPECTRE_RAW_CSI_SESSION_ID_BYTES由固件以随机数填充响应魔数0x52505345ASCIIESPR。60 字节前缀RawCsiHttpFramePrefixpacked 布局并有static_assert(sizeof 60U)固化携带的关键字段字段大小含义magic4 字节固定ESPR魔数version/record_version各 1 字节传输协议版本1/ CSI 记录版本8header_len2 字节前缀长度60session_id16 字节本次采集会话标识stream_sequence8 字节64 位流序号用于暴露传输丢失record_len2 字节后续记录长度flags2 字节预留标志位fresh_record_total8 字节已成功发送的记录累计数raw_drop_total8 字节已丢弃记录累计数raw_send_backpressure_total8 字节发送失败背压累计数CSI V8 记录头定义于 csi_raw_record.hRawCsiRecordHeaderV8同样为 64 字节 packed 结构完整保留无线电上下文与溯源信息chip、seq_num、num_subcarriers、csi_len_bytes、device_id、设备单调时钟device_ticks_us、wifi_rx_ts_us、wifi_rx_start_ts_ns、channel、rssi_dbm、noise_floor_dbm、背压计数以及三条关键 PHY 溯源字段——phy_mode、ltf_type、channel_width。PHY 溯源枚举定义了更宽的取值空间phy_mode涵盖LEGACY / HT / VHT / HE_SU / HE_MU / HE_ERSU / HE_TBltf_type涵盖LLTF / HT_LTF / VHT_LTF / HE_LTFchannel_width涵盖 20/40/80/160/8080 MHz。需要强调的是携带更宽的枚举值并不意味着支持更宽的传感模式。项目生产传感契约仍是分类器优先的 HT20见 2026-07-23 采用分类器优先的 HT20 传感契约这些枚举只是为了不丢失记录本身的无线电身份。主机工具链保留了历史 V7 记录的读取支持但没有任何维护中的工作流再发射 Streamer UDP 记录。会话所有权GET /csi 独占整个采集生命周期原始 ADR 决策中显式命令创建会话 bearer 绑定的部分已被取代。按 2026-09-03 面向资源设备 API 的新模型GET /espectre/v1/csi打开唯一的独占二进制采集会话TCP 响应的建立即开始采集连接关闭即停止采集客户端采用第一个二进制帧中的 16 字节会话 ID同一连接内若发现会话 ID 变化则拒绝采集期间所有传输通道上的派生传感事件motion 等暂停控制类与资源类事件保持可用第二个/csi请求或 sensing/Wi-Fi/OTA 变更返回409连接关闭后固件恢复先前状态、必要时重新校准并只在 readiness 恢复后才恢复派生事件。从源码结构看会话生命周期的编排由 raw_csi_session_controller.cpp 的RawCsiSessionController承担begin()校验运行时能力capabilities().supports_raw_csi与操作状态生成会话配置后先启动 raw 会话再启动运行时采集handle_command()对所有命令一律返回 CSI collection is opened with GET /csi印证了命令式入口已被资源式入口取代。会话停止原因枚举RawCsiStopReason覆盖REQUESTED / OWNER_DISCONNECTED / RAW_DISCONNECTED / WIFI_LOST / CHANNEL_CHANGED / BIND_TIMEOUT / SLOW_CLIENT / SHUTDOWN / INTERNAL_ERROR便于事后审计。主机侧采集./espectre collect 实操./espectre collect是 HTTP-only 的主机侧采集入口同一运行时路径支持三种模式在线检查live inspection不传--label在线录制live recording传--label保存数据集只读数据集盘点使用--info以data/dataset_info.json为数据源按环境打印每个芯片一张标签行表格。常用参数参数作用--target设备 IP、主机名、完整 Direct 端点或设备 ID省略时自动发现 raw-capable 设备--frontend可选native、esphome、matter发现过滤器--source-ip多网卡主机上的本地 IPv4 源地址--durationN 秒后停止--label保存的数据集标签1-64 个 ASCII 字母/数字/下划线/连字符以字母或数字开头省略则只检查不保存--start-delay延迟 N 秒再开始采集要求同时指定--duration--pps外部 UDP 生成器的目标速率同时作为标称数据集速率--detector就绪门使用的检测器lightweight或high_accuracy逗号分隔列表仅用于在线并行对比--ready-stable-seconds保存采集前检测器需持续低于阈值的时间设0关闭就绪门发现与目标解析省略--target时collect在启动时执行一次_espectre._tcp.local.的 mDNS 浏览并保留 raw-capable 记录在其通告的 Direct 端口0 台设备时显式失败并提示--target1 台时自动选中多台时交互选择。发现完成沿用事件驱动规则完整记录到达后 350ms 无变化即完成若始终无记录则消耗完整 2.5 秒默认超时。--target是确定性旁路可解析 IP、主机名、完整 Direct 端点或完整设备 IDNative/Matter/ESPHome 默认使用端口62587ESPECTRE_DIRECT_PORT手工输入的完整端点可指定其他端口但解析器不探测遗留端口。相关解析逻辑见 host.py。采集流程与顺序保证在线采集的固定顺序是协商 CSI 支持能力持久化设置csi_traffic_mode为external并校验结果资源从 tools/espectre_traffic_generator.py 导入ExternalTrafficGenerator并启动最后才打开GET /csi。关闭响应即结束采集并停止生成器。采集器刻意不恢复之前的流量模式——external是持久的设备设置采集后流量所有权保持显式。该顺序在 test_espectre_cli_collect.py 的test_prepare_raw_collection_persists_external_before_constructing_data_plane等用例中被固定为[session, generator, bind]并断言在构造数据面之前就已执行PATCH sensing {csi_traffic_mode: external}。针对由发现选中的目标采集器还会校验每条 CSI 记录携带的device_id与 mDNS 通告一致——若地址被其他设备复用则中止采集而非保存身份混淆的数据。采集术语与质量门Delivered rate采集端收到的 CSI 记录速率ppsAdmitted rate经时间接纳后占用检测器时隙的记录Excess同一时隙内不提升占用率的额外记录Backpressure固件上报无法按产生速度发送记录Queue drop固定 16 记录环形缓冲已满导致分类记录被拒。当设置--label保存时采集会等待检测器在--ready-stable-seconds内持续低于阈值才落盘设0显式绕过--detector lightweight需要正常启动校准high_accuracy无需启动校准但仍需填满特征窗口。保存后立即运行验证器的逐文件完整性、信号质量、时间占用率与流连续性检查时间占用率在完整生产检测器窗口上度量低于 85% 告警、低于 70% 接纳底线则失败失败的采集仍保留供诊断但collect以非零状态退出。时长从收到的第一个包在线检查或开始录制保存数据集起算。典型命令示例# 针对指定设备以 100 pps 外部流量在线检查 ./espectre collect --target 192.168.1.51 --pps 100 # 按前端过滤自动发现并采集 ./espectre collect --frontend esphome --pps 120 # 保存 45 秒 wave 数据集 ./espectre collect --label wave --duration 45 --target espectre-0123456789abcdef.local # 延迟 15 秒后再开始保存 ./espectre collect --label wave --duration 45 --start-delay 15 --target http://192.168.1.50 # 只读盘点已收集数据集 ./espectre collect --info外部流量生成器UDP 标记与速率所有权ExternalTrafficGenerator是独立的、仅依赖标准库的 UDP 流量生成器同时被./espectre collect以库方式导入也可作为独立脚本运行python3 tools/espectre_traffic_generator.py start # 后台启动 python3 tools/espectre_traffic_generator.py stop # 停止 python3 tools/espectre_traffic_generator.py status # 查看状态 python3 tools/espectre_traffic_generator.py run # 前台运行CtrlC 停止关键行为见 espectre_traffic_generator.py默认目标TARGETS [192.168.1.100]端口PORT 5555速率RATE 100pps每个 UDP 数据报携带恰好四字节的 UTF-8 标记.encode(utf-8)即十六进制F0 9F 91 BB这是设备侧识别外部传感流量的唯一规范载荷--pps只控制该 UDP 生成器的速率与数据集溯源provenanceHTTP 数据面不施加任何信用窗口、自适应速率或样本替换通过next_send_deadline()保持发送相位而不调度追赶流量避免突发补偿套接字配置中IP_TOS设为46 2EF 类优先并支持单播与本地链路组播默认组播组239.255.0.1不应对子网或受限广播地址发包——这类帧通常以 legacy PHY 到达不会产生 HT20 CSI。设备的 UDP 监听器仅在端口 5555 接受该四字节标记单播 ICMP Echo Request 也可成为 CSI 候选由正常 IP 栈回复。多播传感流量可能以组播 MAC 或 AP 转换为单播后的单播 MAC 到达两种形式都要求配置的组播目的 IP、UDP 端口与精确标记发往其他设备的帧会被拒绝。网页版 raw 工具复用设备已有的 internal/external 配置不暴露 PPS 控件。数据集契约NPZ 文件中的传输与 PHY 溯源保存的采集文件与目录条目记录transporthttp、Direct 端点、请求与观测 PPS、raw 协议版本、CSI 记录版本、前端、芯片、固件版本与设备 ID。每个文件按data/label/下的{label}_{chip}_{num_sc}sc_{device_token}_{timestamp}_{save_index}.npz命名每个device_id一个文件。ML_DATA_COLLECTION.md 定义了当前采集器写入 NPZ 的核心字段csi_dataint8[N, SC*2]Espressif 的[Q0, I0, Q1, I1, ...]排列、num_subcarriers当前为 64、stream_seq_num、raw_stream_sequence规范 raw HTTP 序号含可见空洞、device_ticks_us、phy_mode、ltf_type、channel_width、transport当前为http、raw_protocol_version当前为1、record_version当前为8、requested_pps/observed_pps/effective_pps、fresh_record_total/raw_drop_total/send_backpressure_total/raw_final_stream_sequence用于校验 raw 丢失不变量以及csi_target_pps、detector_admitted_packets等时间接纳复核字段。历史数据集若缺少这些字段只要其布局能证明早期 HT20 契约就保留文档化的 HT、HT-LTF、20 MHz 解释。训练与校验加载器如 tools/lib/csi_io.py 的load_npz_as_packets默认给出生产传感视图phy_modeht、ltf_typeht-ltf、channel_width20与 64 子载波 HT20 布局部分缺失PHY 元数据部分数组存在、部分缺失会被拒绝而非默认补全因为该采集引入 PHY 溯源后应携带全部字段。固定训练/校验视图是 HT20 HT-LTF 64 子载波原始 ESP32/ESP32-S2 上运行时可能选择lltf20VHT 5 GHz 关联可能选择vht20但这些行保留 PHY 元数据且不在默认数据集视图内。决策历史与演进日期方向决议2026-07-03使用专用 C Streamer 前端采集端节拍 UDP TX 背压反馈各维护中的传感前端具备 raw 采集后被替换2026-07-19在 Streamer V7 数据集中保留逐记录 PHY 溯源作为格式不变量保留至 CSI V8 与 raw HTTP v22026-08-25移除 Streamer跨受支持前端通过 raw HTTP 采集采纳2026-08-25在 HTTP 数据面内节拍或替换样本拒绝传输反馈会决定哪些记录进入数据集2026-08-29将当前 raw HTTP 帧格式发布为协议版本1而非2采纳CSI 记录版本保持8被拒绝的替代方案及其原因保留 Streamer 作为采集回退会维护两套固件、发现、协议与发布面并使采集依赖传输介质为 raw HTTP 增加信用额度或自适应节拍固定内存边界配合显式丢弃让丢失可度量传输反馈不应参与数据选择把所有归一化记录存为通用 HT20通用归一化网格不代表通用 PHY 或 LTF抹除元数据会破坏事后审计与分层分析仅为采集会话临时切换流量模式采集是有意为之的操作行为持久化external让会话结束后的实际流量所有权保持显式采集前应用时间接纳原始研究数据必须保留被分类的输入与时间信息后续检测器视图才能复现已部署的接纳契约。采纳后的结果与约束每个受维护的 ESP-IDF 前端共享一个raw 采集契约与 Direct 发现路径数据集捕获能观察到全部被分类帧显式固定环丢弃除外排空后满足fresh_record_total raw_drop_total classified_frames_offered_to_raw不变量逐记录 PHY 与时间溯源跨传输迁移保留流量所有权是持久化的设备设置合法模式只有internal与external历史 Streamer 评审、基准与数据集仍作为证据保留而 Streamer 代码、构建、CI、发布产物与当前文档均已移除。相关文档采用面向资源的设备 APIGET /csi 会话所有权采用分类器优先的 HT20 传感契约采用 Improv Serial 与 Direct HTTP 进行本地控制标准化受管理的 CSI 流量来源CLI 手册collect 命令API 手册CSI 采集与错误映射ML 数据采集手册NPZ 契约与采集注意事项CSI 手册外部流量来源与捕获质量【免费下载链接】espectreWi-Fi CSI motion sensing for ESP32. C SDK, ESPHome, Native, and Matter frontends, browser tools, and a CLI for the full device lifecycle. GPLv3 and commercial licensing.项目地址: https://gitcode.com/GitHub_Trending/es/espectre创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考