首页
/ RuView 物理锚定背景减除(PABS)实战:用 R6.1 多散射体前向模型把 R12 负结果翻转为 1161× 闯入检测

RuView 物理锚定背景减除(PABS)实战:用 R6.1 多散射体前向模型把 R12 负结果翻转为 1161× 闯入检测

2026-09-09 09:11:15作者:卓炯娓

本篇技术指南围绕 RuView 研究循环中的 R12 PABS(Physics-Anchored Background Subtraction,物理锚定背景减除) 实现展开:它讲述一个此前被判定为"信号/漂移比 0.69×、不可检测"的 NEGATIVE 负结果,如何在多散射体 Fresnel 前向算子(R6.1)解锁后,被改写成基于"物理预测残差"的结构检测原语,并在 5 m / 2.4 GHz 合成链路上把意外人体的检测信噪比从 SVD 基线的 11× 提升到 1,161×(约 100 倍增益)。读完本文,你将掌握 PABS 的数学定义、六个基准场景的完整数据、它与朴素 SVD 的本质差异、其在 RuView 仓库中的可复现 NumPy 实现,以及如何通过 pose–PABS 闭环(R12.1)把误报问题解决到 9.36× 动态检测水平。

背景:R12 为什么是负结果

PABS 不是凭空出现的——它是 R12 负结果(tick 5)明确指出的修复路径。原始 R12-rf-weather-mapping.md 实验尝试了最简单的算法:对每帧 CSI 矩阵做 SVD,取 top-K 奇异值,比较两个时间段之间的谱余弦距离。结论是 WEAK

指标
AFTER(无扰动,对照组)与 BEFORE 的余弦距离 0.00035
AFTER(3 个子载波衰减 ~1.4 dB 扰动)与 BEFORE 的余弦距离 0.00024
信号 / 自然漂移比 0.69×

合成结构扰动产生的谱距离反而小于同一段录音中操作员移动造成的自然漂移,即信号-漂移比 < 1 = 不可检测。原因很直接:top-K 奇异值谱捕获的是信道状态中的主导能量,3/56 个子载波上 15% 的衰减只移动了总能量的约 0.8%,远低于移动人体造成的时变方差。

R12 文档因此给出了三条修复路线,其中第一条被后续实现采纳:

实现子空间主夹角作为比较度量,而不是奇异值上的余弦距离……PABS 能捕获奇异值余弦所遗漏的子空间旋转。

并明确写下:"需要 multi-day 数据 至少……目前仓库中不存在这样的数据集"。也就是说,R12 的结论不是"物理不可行",而是"算法选型错误 + 单日数据噪声结构不利"。这正是 PABS 诞生的直接动因。

从 R12 到 PABS:R6.1 前向算子如何解锁修复路径

R12 负结果之所以被卡住,核心原因是没有前向模型:它只能从数据里自己发明子空间基底,结果与自然漂移无法区分。而 R6-fresnel-forward-model.md 先给出了单散射体模型——第一 Fresnel 区半径

r_1(p) = sqrt(λ · L · p · (1 − p))      [米]

以及点散射体引入的路径差与子载波相移:

Δℓ(x) = sqrt(d_1² + x²) + sqrt(d_2² + x²) − (d_1 + d_2)
φ_k = 2π · f_k · Δℓ / c

随后 R6_1-multiscatterer-forward-model.md 把它推广为 6 散射体分布式人体模型(头、胸、两臂、两腿复相干求和):

csi[k] = Σ_b  (refl_b / (d_tx,b · d_rx,b)) · exp(2π·j·f_k·Δℓ_b / c)

R6.1 的结论有两层:一是多散射体相干求和导致呼吸带 SNR 比单散射体理想情况低 4.7 dB(这恰好解释了 R13 接触式血压 5 dB 缺口的物理来源);二是它直接宣告 "R12 的修复路径现在有了基础"——PABS 公式所需的显式 A(voxel) 算子可由 R6.1 计算:

y_predicted = Σ_voxels  A(voxel) · reflectivity(voxel)
residual = y_observed − y_predicted
PABS = norm(residual)

于是 tick 19(R12 PABS)成为"负结果 + 新工具解锁"的标准范例:R12 需要模型但没模型,R6.1 把模型造出来了

PABS 方法:期望场景前向预测 vs 观测

PABS 的数学定义极其简洁(R12-pabs-implementation.md):

PABS = ||y_observed − y_predicted||² / ||y_observed||²

其中 y_predicted 由 R6.1 多散射体模型计算,输入是"场景应该长什么样"的先验——已知位置的人体 + 已知位置的墙面反射体

实验链路配置:

  • 链路:5 m 链路,2.4 GHz
  • 期望场景
    • 1 名受试者位于 (2.5, 2.75)——离 LOS 线 25 cm(R6.1 指出 LOS 线上是退化配置)
    • 4 个墙面反射体位于房间四角,反射率递减
  • 前向算子:为期望场景计算 y_predicted

随后在六个观测场景上测试(场景定义完整继承自原文档):

场景 描述
A 空房间——无占用者(受试者缺失)
B 受试者恰好位于期望位置(健全性检查——PABS 应为 0)
C 受试者 + 新增 1 件家具
D 受试者 + 1 名意外进入的第二个人
E 墙体反射率漂移 5%(自然漂移下限)
F 受试者相对期望位置移动 10 cm

这些场景在仓库中都有完整可复现的实现:examples/research-sota/06-structure-detection/r12_pabs_implementation.py,运行后输出 r12_pabs_results.json 与终端判定。

结果:PABS 对 SVD 的全场景碾压

原文档的结果表(六个场景的 PABS、SVD 基线、以及各自相对自然漂移倍数的完整数据):

场景 PABS SVD(R12 基线) PABS / 漂移 SVD / 漂移
A:无占用者 4.17 0.60 7,362× 65×
B:受试者符合期望 0.00 0.00
C:+1 新增结构元素 0.047 0.10 84× 11×
D:+1 意外人类 0.658 0.099 1,161× 11×
E:墙体漂移 5%(自然漂移下限) 0.0006 0.009
F:受试者移动 10 cm 12.44 0.84 21,966× 90×

头条对比(原文档原话):

PABS 在自然漂移下限的 1,161 倍处检测到意外人类。R12 的朴素 SVD 在同一场景只有 11 倍。

这约 100× 的提升纯粹来自"用物理接地预测代替统计本征移位"。R12 的原始负结果(信号/漂移 0.69× = 不可检测)如今变成 1,161× = 微不足道地可检测。

脚本中的判定逻辑(r12_pabs_implementation.py)会自动给出结论:

if pabs_signal_to_drift > 3 and svd_signal_to_drift < 2:
    print("VERDICT: PABS works where R12 naive SVD failed. R12 NEGATIVE -> revisited and POSITIVE.")

为什么 PABS 有效而 SVD 无效

原文档给出了两点核心论证,这也是理解整个方法的分水岭:

  • SVD 在 |y| 上把 CSI 当作通用 1-D 向量,寻找相对学习基线的统计偏差。它无法区分"墙体漂移"和"多出一个人"——两者看起来都是泛泛的谱平移。
  • PABS 则与"应该是什么"的前向建模预测比较。新散射体会在前向模型预测缺失的精确逐子载波签名处产生残差;自然漂移产生的残差则是弥散的、低幅度的模式。几何结构把二者分开——而这个分离正是 100× 比值的来源。

从源码层面看,这种"逐子载波签名"的精确性来自 r12_pabs_implementation.py 中的相位编码:每个散射体贡献 amp = reflectivity / max(d_tx·d_rx, 1e-3) 的幅度与 2π·f_k·Δℓ/c 的相位。人体 6 个散射体(胸部反射率 0.50、其余各 0.10,human_body 定义)+ 4 个角落墙面反射体(幅度 0.3/0.2/0.15/0.1,static_wall_reflectors 定义)叠加后,任何"场景多了一块东西"都会在该物体对应的路径差上留下相位签名——这是幅度谱统计方法天然看不到的信息维度。

场景 F 的深读:为什么"受试者移动 10 cm"不该被当成 bug

场景 F(PABS = 21,966× 漂移)在原文档中被特意单列说明——这不是缺陷,而是完全正确的行为

  • 前向模型预测的是"受试者在 (2.5, 2.75)"
  • 观测到的是"受试者在 (2.5, 2.85)"
  • 残差是一个移动了 10 cm 的散射体的逐子载波签名——它本来就很大

代码层面(r12_pabs_implementation.py):

# ===== Scenario F: small subject position shift (subject moved 10 cm) =====
subject_shifted = human_body(2.5, 2.85)  # 10 cm closer to LOS
y_F = simulate(subject_shifted + walls, tx, rx, freq_ghz)
pabs_F = pabs(y_F, y_expected)

因此,对于真实的结构检测管线,PABS 必须与姿态跟踪器耦合,实时更新期望场景模型。真正的结构检测信号是 pose 更新之后的 PABS——即扣除了受试者被跟踪位置之后剩余的残差。新家具/闯入者会产生姿态跟踪器无法解释的残差;受试者自身的移动则不会。

仓库已经内置姿态跟踪能力:v2/crates/wifi-densepose-signal/src/ruvsense/pose_tracker.rs 实现了 17 关键点 Kalman 姿态跟踪(每关键点 6D 状态 [x, y, z, vx, vy, vz]、常速模型、过程噪声 0.3 m/s²、量测噪声 0.08 m ≈ 躯干 RMS < 8 cm、跟踪生命周期 Tentative → Active → Lost → Terminated,检测-跟踪关联由 Mahalanobis 距离 60% + AETHER re-ID 余弦相似度 40% 组成)。缺失的只是姿态更新与 PABS 前向模型之间的闭环耦合——原文档估算约 50–100 行 Rust 胶水代码

R12 NEGATIVE → POSITIVE:前后对照

原文档用一张表完整总结了这次"负转正"的转变:

维度 R12(NEGATIVE) R12 PABS(POSITIVE)
方法 SVD 谱余弦距离 前向建模残差范数
所需输入 y_observed + y_baseline(无模型) y_observed + R6.1 前向模型
意外人体上的信号/漂移 0.69× 1,161×
新家具上的信号/漂移 未测量 84×
对时间平均的依赖 需要数周基线 单帧即可
卡点 没有前向模型 R6.1 解锁

本循环中出现了两个负结果(R12 + R13)。R12 已被重新审视并转正——这正是让研究循环的 NEGATIVE 条目变得有生产力而非死寂的那类后续动作。R13 则无法同样翻案:它的 5 dB 缺口是硬物理下限,不是缺模型。

源码级实现拆解:一个可复现的纯 NumPy 实验

PABS 实现是纯 NumPy、零框架依赖的(r12_pabs_implementation.py),全流程可一键复现:

  1. 链路几何:Tx 位于 (0, 2.5)、Rx 位于 (5, 2.5)、频率 2.4 GHz(L98-L100);
  2. 子载波网格:52 个使用子载波、312.5 kHz 间隔,围绕中心频率对称排布(sub_offsets = (np.arange(n_sub) − n_sub//2) * sub_spacing_khz * 1e3);
  3. 前向模拟simulate() 对每个散射体调用 csi_contribution() 并复相干求和(L55-L62),路径差由 path_delta_m() 计算 d_tx + d_rx − d_direct
  4. 期望场景subject_expected = human_body(2.5, 2.75) + 4 个静态墙面反射体,得到 y_expected
  5. 六个场景逐一构造
    • A:只模拟墙体 simulate(walls, ...)
    • B:simulate(subject_expected + walls, ...)
    • C:新增 {"pos": [3.5, 1.0], "refl": 0.25, "name": "new_chair"}
    • D:叠加 human_body(2.0, 2.0) 作为闯入者
    • E:墙体幅度变为 (0.315, 0.21, 0.158, 0.105)——即每个反射率 ×1.05 的 5% 漂移(对应湿度/温度循环)
    • F:human_body(2.5, 2.85)
  6. 对比基线svd_distance() 在 |y| 上做范数差,复现 R12 朴素 SVD 的失败路径;
  7. 判定输出:计算 pabs_signal_to_drift = pabs_D / pabs_E 等比值并写入 JSON。

值得注意的工程细节是场景 E 的构造方式:脚本把"自然漂移下限"实现为四个墙体反射率的整体 5% 缩放,而 PABS 恰好被归一化到这条基准线上(所有"PABS / 漂移"列都以 E 为分母)。这保证了六列数据之间的相对倍数可以直接对照,也解释了为什么 B 场景的 0.00 在除以漂移后是 0×(受试者与期望一致时残差为零)。

与既有研究线程的组合

PABS 不是孤立实验,原文档明确列出了它与其他线程的合成关系(本节完整继承):

  • R5(显著性)——PABS 的残差本身可以再做显著性分解,用来定位结构变化发生在哪里(哪个身体部位 / 哪个体素)。尚未实现,是自然的下一步。
  • R6——单散射体 Fresnel,提供积木块。
  • R6.1——多散射体前向算子,正是本次 tick 的解锁者
  • R6.2 / R6.2.2——最大化 Fresnel 覆盖的布放也最大化 PABS 灵敏度(覆盖区内的残差可靠检出)。
  • R7(mincut 对抗)——PABS 残差对比逐链路前向模型,给 R7-multilink-consistency.md 的多链路一致性检查一个精确定义:残差范数应在所有链路上同时很小;单条链路的尖峰 = 局部结构变化链路被攻破,由 R7 的 Stoer-Wagner mincut 消歧。
  • R10(植被 / 野生动物)——只要森林的静态散射体能建模或作为逐安装基线被学习,PABS 对森林冠层同样成立。
  • R11(海事)——舱内 PABS 通过"密封舱场景模型"的残差检测"货柜被打开/篡改"。
  • R12 NEGATIVE——现已 POSITIVE。
  • R14 / ADR-105 / ADR-106——PABS 是联邦协议可以分发的逐 cog 原语,适用同一套隐私框架(详见 R14-empathic-appliances.md:只暴露"残差存在性"而不暴露"是谁")。

诚实的边界

原文档用一整节列出 PABS 当前不可回避的限制,此处完整保留:

  • PABS 需要实时的姿态感知前向模型来避免受试者移动造成的误报(场景 F)。没有 pose–PABS 闭环,每一次受试者移动都会触发结构告警。
  • 自然漂移下限是几何相关的。5% 墙体反射率漂移是通用假设;湿度/温度循环下具体安装的漂移下限可能高达 10–15%。
  • 这里同样没有建模多径。墙面反射体是静态点散射体,模型不包含地面/天花板反射。
  • 没有带标注的真实世界测试。基准建立在合成数据上;在真实 CSI 采集上跑 PABS 是下一步。
  • 人群先验人体假设。PABS 使用通用人体模型;逐受试者的人体建模会进一步收紧残差(R3 + R15 提供嵌入句柄)。
  • 单时间帧。真实 PABS 管线应跨时间窗口积分以抑制噪声;当前结果是单帧的。

它能做什么 / 不能做什么

能够做到(原文档 1–3 条完整继承):

  1. R12 NEGATIVE → POSITIVE——死掉的线程现在有了带 100× 提升的工作实现。
  2. 为多站 ADR-029 实现给出具体下一步——ADR-029-ruvsense-multistatic-sensing-mode.md 中逐链路前向模型上的 PABS 就是结构检测原语。
  3. 一个完整的范例——展示"负结果 + 新工具解锁"如何把死研究转化为可交付功能。

不能做到(原文档完整保留):

  • 生产级结构检测(需要 pose–PABS 闭环 + 时间平均 + 真实世界标定)。
  • 结构变化定位(残差范数给出检测;残差方向才给出定位——自然下一步)。
  • 跨房间结构迁移(每次安装有自己的前向模型;跨安装迁移走 ADR-105 / ADR-106)。

后续 tick 与 pose–PABS 闭环(R12.1)

原文档列出四项后续工作:

  • R12.1 — Pose–PABS 闭环:把 pose_tracker.rs 的更新耦合进期望场景模型,约 50–100 行 Rust 胶水。
  • R12.2 — 局部化残差分解:把残差投影到逐体素基上,识别结构变化发生在哪里
  • R12.3 — 真实世界验证:在 bench ESP32 的真实 CSI 采集上跑 PABS,测量真实漂移下限与真实闯入者检测。
  • ADR 修订:ADR-029(多站感知)应引用 PABS 作为结构检测原语。

其中 R12.1 已经在同一循环内实现并合成验证(见 R12_1-pose-pabs-closed-loop.md)。实验配置:5 m 链路、2.4 GHz、50 帧,受试者从 (2.0, 2.0) 连续走到 (3.0, 3.5),闯入者第 T=25 帧进入并固定在 (1.5, 1.5)。对比两条管线:

阶段 Fixed-expected(朴素 R12 PABS) Pose-updated(R12.1 闭环)
闯入前(T<25),受试者移动中 6.02 0.30
闯入后(T≥25),闯入者进入 7.76 2.84
闯入检测提升 1.29× 9.36×

闭环的结果是:姿态更新把受试者运动的贡献压低了 20×(6.02 → 0.30),同时闯入者仍然以 9.36× 提升被检出(对比朴素管线的 1.29×)。这之所以可行,是因为 R6.1 多散射体人体模型是平滑的——姿态跟踪器 5 cm 位置噪声(对应 ADR-079 ~95% PCK@20 的精度水平)产生的逐子载波预测误差远低于静态漂移下限。

R12.1 给出的闭环伪代码(原文档完整保留,这也是生产路线图的核心):

// pseudocode for the closed loop in vital_signs / structure module

let pose = pose_tracker.estimate(csi_window)?;  // ADR-079 / ADR-101
let expected_scene = body_model.from_pose(pose) + room_walls;
let y_predicted = fresnel_forward.simulate(expected_scene);
let pabs = (csi_window - y_predicted).norm_sq() / csi_window.norm_sq();
if pabs > threshold {
    emit_structure_event();
}

三处新增代码:body_model.from_pose(pose)(姿态跟踪输出 → 散射体位置)、fresnel_forward.simulate(scene)(R6.1 多散射体模型)、pabs(observed, predicted)(纯 L2 范数),合计约 80 行 + 约 30 行管道代码,插槽位置是 vital_signs cog 的逐帧推理路径。对应实现已落地在 examples/research-sota/06-structure-detection/r12_1_pose_pabs_loop.py

R12 线程至此完整闭环(三 tick 三段状态):

Tick 线程状态 头条
R12(tick 5) NEGATIVE SVD 本征移位失败:0.69× 信号/漂移
R12 PABS(tick 19) POSITIVE 1,161× 闯入检测(静态)
R12.1(闭环) CLOSED LOOP 9.36× 闯入检测(动态)

00-summary.md 的研究循环总表中,这条 R12 弧线被列为"Missing-tool(可重访)"型负结果的范本,并被写进生产路线图 Tier 1:R12.1 pose–PABS 落入 vital_signs cog 约 80 LOC、约 3 天工作量,与 ADR-029 修订共同在 Q3 2026 交付 9.36× 闯入检测提升

总结:一个可复现的"负转正"方法学样板

PABS 的完整链条可以浓缩为四步:R12 用统计本征移位失败(0.69×)→ R6 提供 Fresnel 基底 → R6.1 提供多散射体前向算子 → PABS 用前向残差范数把闯入检测推到 1,161×(静态)/ 9.36×(动态)。整个实验以纯 NumPy 脚本的形式存放在 examples/research-sota/06-structure-detection/r12_pabs_implementation.pyr12_1_pose_pabs_loop.py 及对应 JSON 结果),任何读者都可以直接运行复现,也可以把 simulate() 换成自己的链路几何来验证不同房间的灵敏度。

它给 RuView 带来的不是单个算法,而是一个方法论模板:当统计方法撞上物理漂移噪声时,显式写出前向模型、用"应该是什么"去减"观测到了什么",往往比在特征空间里找更复杂的判别边界更有效。而"负结果 + 新工具解锁 → 重新审视 → 转正 → 闭环"这条研究路径,正是仓库研究循环最值得复用的资产。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
858
1.35 K
docsdocs
暂无描述
Markdown
899
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
923
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.83 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
532
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
524
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
393