PPG对体温的量化准备工作
目前俩个理论比较肯定一、单PPG下的PWTT替代定义核心算法放弃绝对传导时间改用同一脉搏波周期内的相对时间特征它们与体温-血管张力的映射关系与PWTT等价。推荐特征1标准化收缩期上升时间nRT定义nRT (T_peak - T_foot) / T_cycleT_foot单个PPG周期起始点一阶导数由负转正的点T_peak该周期峰值点一阶导数为零T_cycle该周期总时长相邻两个T_foot的间隔生理解释血管扩张时上升支斜率变缓nRT增大血管收缩时nRT减小。归一化后消除了心率快慢的影响可比性极强。推荐特征2重搏波切迹时间比DTIDicrotic Notch Time Index定义DTI (T_notch - T_foot) / (T_peak - T_foot)T_notch重搏波切迹点N二阶导数过零点生理解释反映动脉血管弹性和外周阻力。体温升高时外周阻力下降切迹位置后移DTI增大。从一个图上来看懂什么是nRT和DTIFP之间的时间T_riseFF1之间的时间T_cycleFN之间的时间T_notch1、上升支从F到P“推”的过程。心脏猛地一收缩把血“推”进主动脉动脉瞬间被撑开波形像爬山一样急速上升。这就是你摸脉搏时感觉到的“咚”的那一下。2、下降支从P到下一个F“放”的过程。心脏开始舒张主动脉瓣“啪”地关上产生切迹N被撑开的动脉靠自身弹性慢慢回缩把血液继续挤向外周波形像下台阶一样缓慢下降。3、现在标记特征公式1、nRT T_rise / T_cycle。如果体温升高血管扩张上升变慢T_rise变长nRT变大。2、DTI T_notch / T_rise。其中 T_notch 是从足部(F)到切迹(N)的时间。它反映了切迹在下降支中的相对位置。看懂了上面这两个指标就一目了然了指标计算公式图上怎么看物理意义nRT标准化上升时间T_rise / T_cycle上升支爬坡的时长除以整个周期的总时长。体温升高血管变软爬坡变慢这个比值就会变大。DTI重搏波切迹时间比T_notch / T_rise从起点(F)走到切迹(N)的时长除以爬坡(T_rise)的时长。这个比值反映了切迹在下降支中出现的早晚。还有一个与体温有关那就是AC和DC的分量抗运动干扰的“比较”技巧必修课运动时肌肉挤压血管会导致DC瞬间剧烈抖动。此时直接比较 AC/DC 会引入巨大误差。商业级解决方案在滑动窗口中引入“信噪比SNR”作为比较的置信度。计算窗口内原始信号的总能量E_total。计算经过0.5Hz~5Hz带通滤波后的AC能量E_AC。运动判别如果E_AC / E_total 0.6即噪声能量超过40%则判定为严重运动。策略运动中停止DC/AC的静态比较只保留卡尔曼滤波的预测值靠惯性推算运动停止后采用指数加权移动平均EWMA快速拉回真实基线。如何利用PPG原始数据求的DC和AC值这里有标准流程二、详细分步实现 具体数值示例假设我们截取到一段3秒的原始PPG信号为了方便演示我用简化的8个点代替375个点但逻辑完全一致原始PPG数组Raw[100, 120, 105, 135, 110, 125, 95, 115]单位ADC量化值第一步DC分量的“双保险”提取① 稳健中位法抗突发运动对窗口内所有点排序取中位数。本例计算排序[95,100,105,110,115,120,125,135]中位数 (110115)/2 112.5。物理意义这个值代表该窗口内组织骨骼、肌肉、静脉血的平均光吸收基线完全剔除了运动尖峰如突然的125跳变。② 硬核低通滤波提取慢变趋势设计滤波器0.01Hz ~ 0.5Hz 低通实际是截止频率0.5Hz的低通带0.01Hz高通用于去直流漂移。将上述原始数组送入滤波器此处略去卷积计算输出平滑后的趋势值假设得到113.0。工程决策在你的XGBoost模型中优先使用滤波后的DC_trend它比单点中位数更平滑与体温变化的相关性更高。仅当滤波运算耗时如MCU资源紧张时退化为中位法。第二步AC分量的提取峰谷差值法附动态阈值③ 带通滤波0.5Hz ~ 5Hz这一步把DC基线113和极高频噪声全部滤掉只留下搏动波形。滤波后数组滤除直流后近似为[-13, 7, -8, 22, -3, 12, -18, 2]可以看到负值对应波谷正值对应波峰。④ 使用“动态阈值法”寻找波峰和波谷核心难点不能用固定高度比如10算波峰因为PPG幅值会随体温变化。必须用相对突出度Prominence。算法步骤计算该窗口内滤波后信号的标准差σ。本例方差约 140σ ≈11.8。设定波峰检测阈值Peak_Threshold 0.5 × σ 5.9。意思是只要某个点比左右两个邻近的谷底高出5.9就算一个有效波峰。逐点扫描逻辑寻找波峰索引0-13→ 不是。索引17比前一点(-13)高20比后一点(-8)高15且高于阈值5.9 →判定为波峰1Peak1。索引322比前一点(-8)高30比后一点(-3)高25且高于阈值5.9 →判定为波峰2Peak2。寻找波谷找极小值同理寻找低于左右邻居且低于-0.5×σ即-5.9的点。索引0-13→判定为波谷1Valley1索引2-8→ 低于-5.9但它在波峰1和波峰2之间作为波谷2。索引6-18→判定为波谷3Valley3⑤ 计算每一拍的AC幅值配对逻辑采用“前谷后峰”配对法确保是同一个心跳周期Beat1Valley1(-13) → Peak1(7) → Valley2(-8)。幅值1 Peak1 - Valley1 7 - (-13) 20。比用Valley2更准因为Valley1是真正的舒张末期。Beat2Valley2(-8) → Peak2(22) → Valley3(-18)。幅值2 22 - (-8) 30。⑥ 窗口内AC聚合中位数剔除异常得到的AC数组[20, 30]。取中位数AC_beat_median (2030)/2 25。第三步进阶抗运动方案标准差替代法当信号质量极差时比如剧烈抖动导致上述峰值检测频繁失败算法自动降级执行条件如果检测到的有效波峰数量 2个即无法配对。计算逻辑直接利用滤波后信号带通0.5~5Hz的结果的标准差σ来反推幅值。推导依据对于近似正弦波的PPG信号峰峰值AC ≈ σ × 2√2。本例代入σ 11.8则AC_estimated 11.8 × 2 × 1.414 ≈ 33.3。工程对比中位法算出的AC是25标准差法估算是33。在剧烈运动时33更接近真实搏动血流量的统计学期望虽然不精确但比算不出数值NaN导致模型崩溃要强得多。经过上述3秒窗口你最终得到以下稳健特征特征名本例计算值说明DC113.0滤波后的组织基线血容量AC25.0或运动降级时用33.3有效搏动幅值PI灌注指数25 / 113 ≈22.1%归一化特征消除个体肤色/佩戴松紧差异商业级工程约束必加项防踩坑边界效应处理极其重要使用scipy.signal.filtfilt零相位滤波时信号开头和结尾会有振铃失真。硬性规定丢弃每个窗口前0.5秒约62个点和后0.5秒约62个点的数据只用中间2秒计算AC和DC。这会损失一点实时性但换来的是±0.05℃的精度提升。滑动窗口重叠实时性优化不要每3秒完全刷新算一次采用1秒步长重叠2/3。这样每秒输出一组体温特征平滑度极高用户体感无顿挫。信号质量标签QoS计算滤波后信号的信噪比SNRSNR 10*log10(AC_std² / (Raw_std² - AC_std²))。如果SNR 2dB将该窗口标记为validFalse模型直接复用上一秒的特征不更新体温。注意仅绿光是无法计算出血氧饱和度请确认你的传感器类型这会决定你如何操作传感器配置与血氧的关系体温算法操作建议仅绿光手表心率常用无任何关系算不出SpO2。完全忽略血氧概念。只需关注PI的趋势变化率无需做缺氧补偿。红光红外指夹/部分手表紧密相关可算SpO2。必须将SpO2绝对值或R值作为环境上下文特征输入模型用于剔除缺氧导致的PI假性升高。