如何用Python修复SciPy内置EKG数据集的基线漂移问题
修复EKG信号中的基线漂移问题(基于SciPy)
针对EKG信号的基线漂移(由人体运动等导致的低频基线波动),以下是几种实用的修复方法,基于SciPy或自定义实现:
1. 巴特沃斯高通滤波(医疗设备主流方案)
基线漂移属于低频干扰(通常<0.5Hz),高通滤波可直接剔除这类信号。使用SciPy的signal.butter设计巴特沃斯滤波器,配合filtfilt做零相位滤波,避免信号相位失真。
import numpy as np import scipy.signal as signal from scipy.datasets import electrocardiogram import matplotlib.pyplot as plt # 加载内置EKG数据,采样频率360Hz ekg = electrocardiogram() fs = 360 # 设计4阶巴特沃斯高通滤波器,截止频率0.5Hz order = 4 cutoff = 0.5 nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = signal.butter(order, normal_cutoff, btype='high', analog=False) # 零相位滤波(避免信号偏移) ekg_filtered = signal.filtfilt(b, a, ekg) # 对比可视化 time = np.arange(ekg.size) / fs plt.figure(figsize=(12, 6)) plt.subplot(2,1,1) plt.plot(time, ekg, label='原始信号') plt.title('原始EKG信号(含基线漂移)') plt.subplot(2,1,2) plt.plot(time, ekg_filtered, label='滤波后信号', color='red') plt.title('去除基线漂移后的EKG信号') plt.tight_layout() plt.show()
2. 形态学开运算去除基线漂移
形态学开运算(先腐蚀后膨胀)能保留QRS波的尖锐峰值,同时提取缓慢变化的基线。用中值滤波近似实现,适合处理非平稳的基线突变。
import numpy as np import scipy.signal as signal from scipy.datasets import electrocardiogram import matplotlib.pyplot as plt ekg = electrocardiogram() fs = 360 # 定义结构元素长度:覆盖QRS波宽度(取0.2s,对应72个采样点) struct_len = int(0.2 * fs) # 用中值滤波估计基线(忽略QRS波尖峰) baseline = signal.medfilt(ekg, kernel_size=struct_len) # 原始信号减去基线得到校正后信号 ekg_corrected = ekg - baseline # 对比可视化 time = np.arange(ekg.size) / fs plt.figure(figsize=(12,6)) plt.subplot(2,1,1) plt.plot(time, ekg, label='原始信号') plt.plot(time, baseline, label='估计基线', color='orange') plt.legend() plt.subplot(2,1,2) plt.plot(time, ekg_corrected, label='校正后信号', color='red') plt.legend() plt.tight_layout() plt.show()
3. 改进的滑动中位数基线估计
替换粗糙的移动平均为滑动窗口中位数(不受QRS波尖峰干扰),再用三次样条插值平滑基线,适合处理分段平稳的漂移。
import numpy as np import scipy.signal as signal from scipy.interpolate import CubicSpline from scipy.datasets import electrocardiogram import matplotlib.pyplot as plt ekg = electrocardiogram() fs = 360 # 取1秒窗口(覆盖多个心跳) window_size = int(1.0 * fs) # 计算滑动窗口中位数 baseline_est = [] for i in range(0, len(ekg), window_size): window = ekg[i:i+window_size] baseline_est.append(np.median(window)) # 三次样条插值得到平滑基线 x = np.arange(0, len(ekg), window_size) x_full = np.arange(len(ekg)) cs = CubicSpline(x, baseline_est) baseline_smooth = cs(x_full) ekg_corrected = ekg - baseline_smooth # 对比可视化 time = np.arange(ekg.size) / fs plt.figure(figsize=(12,6)) plt.subplot(2,1,1) plt.plot(time, ekg, label='原始信号') plt.plot(time, baseline_smooth, label='平滑基线', color='orange') plt.legend() plt.subplot(2,1,2) plt.plot(time, ekg_corrected, label='校正后信号', color='red') plt.legend() plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者aero-man
相关产品推荐
相关产品推荐

