在生物医学信号处理领域,光电容积图(PPG)是一种通过光学手段测量血液容积变化的常见技术。它广泛应用于心率监测、血氧饱和度检测等场景。然而,原始PPG信号往往包含大量噪声和干扰,如何从中准确提取心率信息一直是工程实践中的关键挑战。
本项目通过Python实现了完整的PPG信号处理流程:从模拟信号生成、短时傅里叶变换(STFT)滤波到心率提取。相比传统方法,STFT能同时保留时域和频域信息,特别适合处理非平稳的生物信号。下面我将详细解析每个环节的技术实现与设计考量。
优质的心率提取首先需要理解PPG信号的组成。典型的PPG信号包含以下成分:
python复制# 基础心率信号 (1Hz)
f_ppg = 1.0
ppg = (0.5 * np.sin(2 * np.pi * f_ppg * t) +
0.2 * np.sin(2 * np.pi * 2 * f_ppg * t) +
0.3 * np.sin(2 * np.pi * 3 * f_ppg * t))
# 低频基线漂移 (0.1Hz)
baseline = 0.3 * np.sin(2 * np.pi * 0.1 * t)
# 高频噪声
noise = 0.2 * np.random.randn(len(t))
# 50Hz工频干扰
power_line = 0.15 * np.sin(2 * np.pi * 50 * t)
signal_raw = ppg + baseline + noise + power_line
设计要点:
- 基波频率设为1Hz(60bpm)模拟正常心率
- 添加二次和三次谐波反映真实PPG波形特征
- 基线漂移模拟呼吸运动等低频干扰
- 高斯白噪声模拟传感器噪声
- 50Hz正弦波模拟电源干扰
python复制window = 'hann' # 汉宁窗
nperseg = 256 # 窗口长度
noverlap = 128 # 重叠点数
nfft = 256 # FFT点数
f, t_stft, Zxx = signal.stft(signal_raw, fs=fs,
window=window,
nperseg=nperseg,
noverlap=noverlap,
nfft=nfft)
关键参数选择逻辑:
- 汉宁窗:减少频谱泄漏,主瓣宽度与旁瓣衰减平衡
- 256点窗口:时间分辨率≈0.256s,频率分辨率≈3.9Hz
- 50%重叠:保证时频连续性同时避免过度计算
心率信号通常位于0.5-5Hz(30-300bpm)范围:
python复制mask = np.ones_like(Zxx, dtype=float)
freq_indices = np.where((f < 0.5) | (f > 5.0))[0]
mask[freq_indices, :] = 0.0
Zxx_filtered = Zxx * mask
注意事项:
- 下限0.5Hz避免包含呼吸等超低频干扰
- 上限5Hz可滤除肌电噪声等高频成分
- 掩码后需验证保留频带的能量占比
python复制t_reconstructed, signal_filtered = signal.istft(Zxx_filtered, fs=fs,
window=window,
nperseg=nperseg,
noverlap=noverlap)
# 长度对齐处理
min_len = min(len(signal_raw), len(signal_filtered))
signal_filtered = signal_filtered[:min_len]
python复制min_distance_peaks = int(0.3 * fs) # 对应200bpm
peaks, _ = find_peaks(signal_filtered,
distance=min_distance_peaks,
height=0.2)
valleys, _ = find_peaks(-signal_filtered,
distance=min_distance_peaks,
height=0.2)
参数优化建议:
distance参数应根据预期心率范围动态调整height阈值建议设为信号幅值的20-40%- 可结合斜率阈值提升检测鲁棒性
python复制if len(peaks) >= 2:
peak_intervals = np.diff(t[peaks])
instant_hr = 60.0 / peak_intervals
hr_std = np.std(instant_hr) # 心率变异性指标
print(f"心率变异性:{hr_std:.2f} bpm")

python复制# 脉搏波传导时间(PTT)
ptt = valley_times - peak_times[:-1]
avg_ptt = np.mean(ptt) * 1000 # 转换为毫秒
# 灌注指数(PI)
pi = (np.mean(signal_filtered[peaks]) -
np.mean(signal_filtered[valleys])) / 2
python复制# 实信号FFT的共轭对称性应用
Y = np.zeros(N, dtype=complex)
Y[0] = X[0] # 直流分量
Y[1] = X[1] # 低频成分
Y[-1] = X[-1] # 对称分量
| 特征 | 偶数点序列 | 奇数点序列 |
|---|---|---|
| 奈奎斯特点 | 存在(实数) | 不存在 |
| 独立频点数 | N/2+1 | (N+1)/2 |
| 对称性 | k和N-k共轭 | k和N-k共轭 |
工程经验:
- 医疗设备通常采用2^n点数(如256/512)简化计算
- 实时系统可优先选用偶数点FFT
- 分析超低频信号时可选择更长序列
python复制# 滑动窗口STFT实现
frame_size = 256
hop_size = 64
for i in range(0, len(signal)-frame_size, hop_size):
frame = signal[i:i+frame_size]
# 实时处理逻辑...
在医疗级设备开发中,还需要通过ISO 80601-2-61等标准认证。建议在实际部署前进行以下验证: