返回系列

模拟信号与质量事件:为什么工程工具不能只依赖真实设备调试

复盘 RespiraScope 的内置模拟传感器、预设呼吸场景和 signal_quality 事件,解释它们如何服务算法调参和异常复盘。

背景问题

真实传感器调试有一个天然问题:你很难稳定复现同一段呼吸。正常呼吸、浅呼吸、屏气、咳嗽、体动伪影、低幅噪声都可能出现,但它们不一定在你调算法时刚好出现。

如果项目只能依赖真实设备,滤波参数和峰谷识别就很难做系统验证。RespiraScope 因此内置了模拟 TCP 传感器和多种呼吸预设,让后端像连接真实设备一样连接 mock server。

RespiraScope 模拟信号设置界面

设计方案对比

方案优点问题项目判断
只接真实设备最接近现场不可重复,异常场景难制造不利于算法调参
离线 CSV 回放可重复,容易测试和 TCP 实时链路有差异可作为补充
内置模拟 TCP server复用真实采集链路,实时可控模拟不等于真实生理信号当前采用
复杂生理模型更真实实现和参数解释成本高当前不需要

内置 mock 的关键不是“假装真实”,而是“让算法和前端可以被重复刺激”。它服务的是工程验证,不是生理建模。

当前方案

MockBreathConfig 定义了模拟信号参数:

参数含义
scenario预设名称
bpm基础呼吸频率
amplitude呼吸幅度
baseline基线值
noise随机噪声强度
drift慢速基线漂移
irregularity呼吸节律波动
apnea_interval_sec / apnea_duration_sec屏气或周期性减弱
artifact_chance / artifact_amplitude突发伪影概率和幅度
sample_interval_ms采样间隔

BreathWaveform.value_at() 根据这些参数生成当前时刻的值。AsyncSimulateSensor 再把值编码成和真实传感器一样的 4 字节包,持续写给 TCP client。

预设参数 normal / apnea / cough BreathWaveform 正弦 + 噪声 + 伪影 4 字节编码 high / low bytes TCP server 后端像真设备一样读取

信号质量事件

滤波和峰谷识别关注“呼吸周期”,但前端还需要知道信号是否可靠。SignalQualityAnalyzer 负责检测:

quality触发含义
good当前窗口没有明显异常
low_amplitude波形跨度过低,可能是弱信号或屏气
artifact单点突变或相对基线突变过大
noisy相邻差分中位数过大
gapsequence 出现明显断流

这类事件不会替代滤波,而是给前端和外部系统一个解释层。比如 BPM 变乱时,用户可以看到是否同时出现 artifact 或 noisy。

为什么这样选

模拟信号复用真实 TCP 链路,这是设计重点。如果 mock 只在前端生成一条曲线,它只能测试图表,不能测试 AsyncSocketClient、DataReceiver、SignalProcessor、DataSender 这条完整链路。现在 mock server 输出同样的 4 字节数据包,后端无需知道数据来自真实设备还是模拟器。

质量事件和模拟场景互相配合。cough_artifact、motion_artifact、weak_noisy 这类场景可以专门触发异常逻辑,用来检查滤波、峰谷识别和 UI 提示。

代价和边界

模拟信号不是医学真实数据。它使用正弦组合、漂移、噪声和伪影来构造“有用的测试刺激”,不能代表真实患者的全部呼吸形态。任何基于模拟数据调出的参数,都还需要在真实设备上验证。

质量事件也只是启发式检测。它根据幅度、突变、噪声和 gap 判断状态,不会自动区分咳嗽、体动、传感器脱落或患者真实异常。它的价值是提示“这段信号不适合无脑相信指标”。

关键函数表

函数或类作用设计点
MockBreathConfig模拟参数 dataclass让每个场景可配置、可序列化
SCENARIO_PRESETS预设场景表覆盖正常、浅呼吸、屏气、伪影等调试场景
BreathWaveform.value_at()按时间生成模拟值组合周期、漂移、噪声和伪影
encode_sensor_value()编码成 4 字节传感器包复用真实 TCP 读取链路
AsyncSimulateSensor.start()启动 mock TCP server后端无需区分真实或模拟源
SignalQualityAnalyzer.handle_data()分析 raw 点质量输出低幅、伪影、噪声和断流事件
analyze_signal_quality_batch()批量分析测试样本单元测试可直接验证异常检测

读源码建议

先读 mock_sensor/breath_simulator.py,理解每个场景如何由参数组成。再读 mock_sensor/async_sensor.py,看模拟值如何变成 4 字节 TCP 包。最后读 signal_quality.py,重点看 artifact、low amplitude、noisy 和 gap 的触发条件。