본문 바로가기
Python Library/HeartPy

[HeartPy] Noisy ECG 신호 분석 (2)

by goatlab 2022. 8. 25.
728x90
반응형
SMALL

Noisy ECG 신호 분석

 

작동은 정상이지만, 일부 거부에는 하면 안 되는 부분이 있다 (올바른 피크가 잘못된 것으로 표시됨).

심전도에는 일반적으로 매우 좁은 피크가 있다. 필터링은 일반적으로 최대값을 같은 위치에 유지하지만 파형을 더 좁혀 문제를 일으킬 수 있다.

HeartPy는 훨씬 더 넓은 PPG 파형을 위해 설계되었기 때문에 업샘플링은 일반적으로 피크당 더 많은 데이터 포인트를 제공하기 때문에 트릭을 수행한다. 상대 피크 위치를 이동하거나 변경하지 않는다.

 

from scipy.signal import resample

resampled_signal = resample(filtered, len(filtered) * 4)

wd, m = hp.process(hp.scale_data(resampled_signal), sample_rate * 4)

plt.figure(figsize=(12,4))
hp.plotter(wd, m)

for measure in m.keys():
    print('%s: %f' %(measure, m[measure]))
        
# plot poincare
hp.plot_poincare(wd, m)

poincare_measures = ['sd1', 'sd2', 's', 'sd1/sd2']
for measure in poincare_measures:
    print('%s: %f' %(measure, m[measure]))

bpm: 81.378971
ibi: 737.291213
sdnn: 60.335413
sdsd: 72.855687
rmssd: 82.042853
pnn20: 0.302013
pnn50: 0.147651
hr_mad: 25.694444
sd1: 58.012517
sd2: 57.607573
s: 10499.077896
sd1/sd2: 1.007029
breathingrate: 0.150000

sd1: 58.012517
sd2: 57.607573
s: 10499.077896
sd1/sd2: 1.007029

 

이것은 탐지를 크게 향상시켰다. ECG를 사용하여 작업 중이고 필터링이 필요한 경우 짝수 계수로 업샘플링하는 것이 좋다. 일반적으로 4-10 사이의 인자로 충분하다.

이제, SNR이 6dB인 좀 더 까다로운 신호로 넘어간다.

 

ecg, annotations = load_visualise('118e06.csv', '118e06_ann.csv')

 

여기서 도전적인 영역으로 들어간다. 노이즈의 진폭은 비교적 크고 포인트에서 noise 스파이크가 QRS 콤플렉스와 일치하여 마스킹하더라도 대부분의 QRS 복합체는 여전히 볼 수 있다.

HeartPy 1.2.4 이후 enhance_ecg_peaks(data, sample_rate)라는 기능이 있다.

이 함수는 샘플링 속도를 기반으로 다양한 폭과 모양의 합성 QRS 복합체 세트를 생성하고 각 합성 QRS 복합체와 신호를 합성 QRS 복합체로 합성한다. 컨볼루션 (convolution)은 다른 모양 (또는 크기)에는 반응하지 않고, 모양과 비슷하게 생긴 모든 것에 강하게 반응한다. 이는 피크 위치에 영향을 주지 않고 신호 대 잡음비를 개선하는 효과가 있다.

이 기능은 신호 대 잡음비를 개선하기 위해 여러 번의 컨볼루션 과정을 반복하도록 설정할 수 있다. 그러나 너무 많은 반복 (일반적으로 14~16개 이상)을 사용하면 신호에서 overtone이 나타나 피크 위치가 왜곡되기 시작한다. 일반적으로 4-5회 반복하면 충분하다. 기본적으로 함수는 4회 반복한다.

 

filtered = hp.enhance_ecg_peaks(hp.scale_data(ecg), sample_rate, 
                                aggregation='median', iterations=5)

# show filtered signal
plt.figure(figsize=(12,4))
plt.plot(filtered)
plt.show()

# zoom in on signal section and overlay filtered segment 
plt.figure(figsize=(12,4))
plt.title('original signal zoom in')
plt.plot(hp.scale_data(ecg[15000:17000]), label='original data')
plt.title('processed signal zoom in')
plt.plot(hp.scale_data(filtered[15000:17000]), alpha=0.5, label='processed data')
plt.legend()
plt.show()

 

동일한 위치에 있는 동안 QRS 복합체가 많이 개선되었다.

전체 신호가 오른쪽 n-1 데이터 포인트로 이동하며, 여기서 n은 컨볼루션 반복 횟수이다. HeartPy가 이것을 수정한다.

 

resampled_signal = resample(filtered, len(filtered) * 10)

wd, m = hp.process(hp.scale_data(resampled_signal), sample_rate * 10)

plt.figure(figsize=(12,4))
hp.plotter(wd, m)

for measure in m.keys():
    print('%s: %f' %(measure, m[measure]))
        
# plot poincare
hp.plot_poincare(wd, m)

poincare_measures = ['sd1', 'sd2', 's', 'sd1/sd2']
for measure in poincare_measures:
    print('%s: %f' %(measure, m[measure]))

bpm: 81.500454
ibi: 736.192214
sdnn: 62.569284
sdsd: 74.268486
rmssd: 83.828045
pnn20: 0.296875
pnn50: 0.156250
hr_mad: 23.333333
sd1: 59.268926
sd2: 60.129353
s: 11196.014605
sd1/sd2: 0.985690
breathingrate: nan

sd1: 59.268926
sd2: 60.129353
s: 11196.014605
sd1/sd2: 0.985690

 

원래의 신호를 고려하면 꽤 괜찮은 성능이다. 몇 개의 피크가 사라지면서 각각의 후속 피크가 거부되었는데, 이는 그 사이의 피크가 누락되었기 때문에 너무 큰 피크 간격이 생성되었기 때문이다. HeartPy는 이 후속 피크와 해당 피크 피크 간격을 거부하여 HRV 측정값이 이에 의해 왜곡되지 않도록 한다 (이상치에 매우 민감함).

이제, SNR이 0dB인 불가능한 신호를 사용한다.

 

ecg, annotations = load_visualise('118e00.csv', '118e00_ann.csv')

 

보시다시피 많은 QRS 복합체의 진폭은 소음에 비해 매우 낮다.

같은 컨볼루션 필터를 사용해보고 그것이 그것에 대해 뭔가를 할 수 있는지 본다.

 

filtered = hp.enhance_ecg_peaks(hp.scale_data(ecg), sample_rate, 
                                aggregation='median', iterations=4)

plt.figure(figsize=(12,4))
plt.plot(filtered)
plt.show()

plt.figure(figsize=(12,4))

# plt.subplot(211)
plt.title('original signal zoom in')
plt.plot(hp.scale_data(ecg[15000:17000]), label='original data')

# plt.subplot(212)
plt.title('processed signal zoom in')
plt.plot(hp.scale_data(filtered[15000:17000]), alpha=0.5, label='processed data')
plt.legend()
plt.show()

# filtered = hp.filter_signal(filtered, 0.05, sample_rate, filtertype='notch')
resampled_signal = resample(filtered, len(filtered) * 10)

wd, m = hp.process(hp.scale_data(resampled_signal), sample_rate * 10)

plt.figure(figsize=(12,4))
hp.plotter(wd, m)

for measure in m.keys():
    print('%s: %f' %(measure, m[measure]))
        
# plot poincare
hp.plot_poincare(wd, m)

poincare_measures = ['sd1', 'sd2', 's', 'sd1/sd2']
for measure in poincare_measures:
    print('%s: %f' %(measure, m[measure]))

bpm: 128.673550
ibi: 466.296296
sdnn: 193.293256
sdsd: 162.020374
rmssd: 219.765641
pnn20: 0.603774
pnn50: 0.584906
hr_mad: 191.111111
sd1: 151.015265
sd2: 226.179378
s: 107305.930822
sd1/sd2: 0.667679
breathingrate: nan

sd1: 151.015265
sd2: 226.179378
s: 107305.930822
sd1/sd2: 0.667679

 

이것은 분명히 올바른 해결책이 아니다. (현재로서는) HeartPy의 기능은 이제 끝났다.

이와 같은 신호로 인해 꼼짝 못하는 경우 합리적으로 수행할 수 있는 유일한 방법은 잡음이 있는 부분을 제거하고 신호가 양호한 나머지 부분을 분석하는 것이다. 즉, 이 예에서는 [0:14500]을 참조하면 된다.

 

filtered = hp.filter_signal(ecg[0:14500], 0.05, sample_rate, filtertype='notch')

wd, m = hp.process(hp.scale_data(filtered), sample_rate)

plt.figure(figsize=(12,4))
hp.plotter(wd, m)

for measure in m.keys():
    print('%s: %f' %(measure, m[measure]))
        
# plot poincare
hp.plot_poincare(wd, m)

poincare_measures = ['sd1', 'sd2', 's', 'sd1/sd2']
for measure in poincare_measures:
    print('%s: %f' %(measure, m[measure]))

bpm: 85.851754
ibi: 698.879142
sdnn: 69.744691
sdsd: 90.204488
rmssd: 108.183148
pnn20: 0.428571
pnn50: 0.285714
hr_mad: 16.666667
sd1: 76.494979
sd2: 53.160118
s: 12775.230350
sd1/sd2: 1.438954
breathingrate: 0.347586

sd1: 76.494979
sd2: 53.160118
s: 12775.230350
sd1/sd2: 1.438954

 

https://github.com/paulvangentcom/heartrate_analysis_python/blob/master/examples/5_noisy_ECG/Analysing_Noisy_ECG.ipynb

 

GitHub - paulvangentcom/heartrate_analysis_python: Python Heart Rate Analysis Package, for both PPG and ECG signals

Python Heart Rate Analysis Package, for both PPG and ECG signals - GitHub - paulvangentcom/heartrate_analysis_python: Python Heart Rate Analysis Package, for both PPG and ECG signals

github.com

 

728x90
반응형
LIST