心電信号的噪聲
EGG信号具有微弱、低幅值、低頻、随杋性的特點,很容易被噪聲幹擾,而噪聲可能來自生物體内,如呼吸、肌肉顫抖,也可能因為接觸不良而引起體外幹擾。是ECG信号主要的三種噪聲為工頻幹擾、肌電幹擾和基線漂移3,也是在濾波過程中急需被抑制去除的噪聲幹擾。
- 工頻幹擾:是由采集心電信号的裝置周身的供電環境引起的電磁幹擾,幅值低,噪聲頻率為50Hz左右,其波形很像一個正弦信号,該噪聲常常會淹沒有用的心電信号,也會影響P波和T波的檢測。

- 肌電幹擾:在心電圖采集過程中,因為人體運動肌肉不自主顫抖造成,這種幹擾無規律可言,波形形态會急速變化,頻率很高,并且分布很廣,範圍在0-2000Hz内,能量集中在30-300Hz内,持續時間一般為50ms,肌電幹擾與心電信号會重合在一起,這會導緻有用的心電信号細微的變化很可能被忽視。
- 基線漂移:屬于低頻幹擾,頻率分布在0.15-0.3Hz内,由于電極位置的滑動變化或者人體的呼吸運動造成心電信号随時間緩慢變化而偏離正常基線位置産生基線漂移,幅度和頻率都會時刻變化着。心電信号中的PR波段和ST波段非常容易受到影響産生失真。
心電信号的預處理
小波變換(Wavelet Transform, WT)可以進行時頻變換,是對信号進行時域以及頻域分析的最為理想工具。本文對含噪心電信号采用基于小波變換的去噪處理方法,分為以下3個步驟:
- 由于噪聲和信号混雜在一起,首先選擇一個小波基函數,由于噪聲和信号混雜在一起,是以要用小波變換對含噪心電信号進行某尺度分解得到各尺度上的小波系數。
- 心電信号經過小波變換尺度分解後,幅值比較大的小波系數就是有用的信号,幅值比較小的小波系數就是噪聲,根據心電信号和夾雜噪聲的頻率分布,對各尺度上的小波系數進行門檻值處理,把小于門檻值的小波系數置零或用門檻值函數處理。
- 分别處理完小波尺度分解後的低頻系數和高頻系數,再重構信号。
4尺度小波分解所得各尺度系數示意圖如下,9尺度小波分解可以類比之:
小波系數處理的門檻值函數有硬門檻值和軟門檻值之分。
- 硬門檻值函數:若分解後的系數絕對值大于門檻值,保證其值不變;當其小于給定的門檻值時,令其為零。
- 軟門檻值函數:若分解後的系數絕對值大于門檻值,令其值減去λ;當其小于給定的門檻值時,令其為零。
其中w為原始小波系數,W為處理後的小波系數,λ為給定的門檻值,N為信号長度。λ的計算公式為
$$
\lambda=\frac{median|w|\sqrt{2lnN}}{0.6745}
$$
median為中位數
由上文分析可知,軟門檻值去噪法的小波系數在連續性上優于硬門檻值法,故本文采取了軟門檻值法結合小波基對信号進行仿真實驗。
關于小波變換的介紹可以參考這篇文章:https://blog.csdn.net/tbl1234567/article/details/52662985
代碼實戰
去噪理論大緻如此,下面來實戰編寫代碼。以編号為100的心電資料記錄為例,上一篇文章已經通過wfdb将心電資料讀取到了record變量中,record為一個大小為(65000,1)的numpy數組。要對其進行小波分解,首先要通過np.flatten()将其轉換為shape=(65000,)的數組。
record = wfdb.rdrecord(\'ecg_data/\' + 100, channel_names=[\'MLII\'])
data = record.p_signal.flatten()
Python中使用pywt包進行信号的時頻分析,其中包括傅裡葉變換、小波變換等工具。使用pywt.wavedec()将時域信号進行9尺度變換到頻域,小波基選用db5,傳回值即為各尺度系數。
# 用db5作為小波基,對心電資料進行9尺度小波變換
coeffs = pywt.wavedec(data=data, wavelet=\'db5\', level=9)
cA9, cD9, cD8, cD7, cD6, cD5, cD4, cD3, cD2, cD1 = coeffs
在對原始信号進行分解之後,我們可以知道,1-2層的細節分量的能量與原始信号的高頻幹擾保持一緻。表明1-2層是高頻噪聲(工頻幹擾以及肌電噪聲)集中的主要地方。是以我們需要濾除D1層和D2層的細節分量,通過将其置0來達到去除的目的。然後将信号分解得到的3~9層小波系數通過軟門檻值公式對信号的門檻值進行處理。pywt.threshold()函數提供了門檻值濾波功能,并且預設是mode=\'soft\'的軟門檻值濾波。
threshold = (np.median(np.abs(cD1)) / 0.6745) * (np.sqrt(2 * np.log(len(cD1))))
# 将高頻信号cD1、cD2置零
cD1.fill(0)
cD2.fill(0)
# 将其他中低頻信号按軟門檻值公式濾波
for i in range(1, len(coeffs) - 2):
coeffs[i] = pywt.threshold(coeffs[i], threshold)
最後對小波系數進行反變換,獲得去噪後的信号。
rdata = pywt.waverec(coeffs=coeffs, wavelet=\'db5\')
對預處理前後的100号信号截取前1500個信号點進行對比如下,可以看出降噪效果還是不錯的:
plt.figure(figsize=(20, 4))
plt.plot(data)
plt.show()
plt.plot(rdata)
plt.show()