Skip to content

Commit 4a646c3

Browse files
committed
working on solution for coincidence of peaks
1 parent ede827c commit 4a646c3

File tree

2 files changed

+63
-22
lines changed

2 files changed

+63
-22
lines changed

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
'matplotlib>=1.5.1',
5858
'requests>=2.10.0',
5959
'pandas>=0.19.1',
60+
'scipy>=0.19.0',
6061
],
6162

6263
# List additional groups of dependencies here (e.g. development

wfdb/processing/ecg/peakdetect.py

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import numpy as np
22
import scipy.signal as scisig
3-
3+
import pdb
4+
import matplotlib.pyplot as plt
45

56
class PanTompkins(object):
67
"""
@@ -14,7 +15,7 @@ def __init__(self, sig=None, fs=None, streamsig=None):
1415
self.sig = sig
1516
self.fs = fs
1617

17-
self.livesig = livesig
18+
self.streamsig = streamsig
1819

1920
if sig is not None:
2021
self.siglen = len(sig)
@@ -32,18 +33,57 @@ def detect_qrs_static(self):
3233
"""
3334

3435
# Resample the signal to 200Hz if necessary
35-
self.resample()
36+
self.resample()
3637

3738
# Bandpass filter the signal
38-
self.sig_F = self.bandpass()
39+
self.bandpass(plotsteps=False)
3940

4041
# Calculate the moving wave integration signal
41-
self.sig_I = self.mwi()
42+
self.mwi(plotsteps=False)
4243

4344
# Align the filtered and integrated signal with the original
4445
self.alignsignals()
45-
4646

47+
48+
49+
# Let's do some investigating!
50+
# Compare sig, sig_F, and sig_I
51+
52+
# 1. Compare sig_F and sig_I peaks
53+
54+
fpeaks = findpeaks_radius(self.sig_F, 20)
55+
56+
ipeaks = findpeaks_radius(self.sig_I, 20)
57+
58+
fpeaks = fpeaks[np.where(self.sig_F[fpeaks]>4)[0]]
59+
ipeaks = ipeaks[np.where(self.sig_I[ipeaks]>4)[0]]
60+
61+
62+
63+
#allpeaks = np.union1d(fpeaks, ipeaks)
64+
65+
66+
print('fpeaks:', fpeaks)
67+
print('ipeaks:', ipeaks)
68+
69+
plt.figure(1)
70+
plt.plot(self.sig_F, 'b')
71+
plt.plot(fpeaks, self.sig_F[fpeaks], 'b*')
72+
73+
plt.plot(self.sig_I,'r')
74+
plt.plot(ipeaks, self.sig_I[ipeaks], 'r*')
75+
76+
#plt.plot(allpeaks, self.sig_F[allpeaks], 'g*')
77+
78+
79+
80+
plt.show()
81+
82+
83+
84+
85+
86+
4787
# Initialize learning parameters via the two learning phases
4888
self.learnparams()
4989

@@ -133,16 +173,14 @@ def detect_qrs_static(self):
133173

134174

135175
# Convert the peak indices back to the original fs if necessary
136-
self.returnresample()
176+
self.reverseresampleqrs()
137177

138178
return
139179

140180

141-
142-
143181
def resample(self):
144182
if self.fs != 200:
145-
self.sig = scisig.resample(self.sig, int(self.siglen*200/fs))
183+
self.sig = scisig.resample(self.sig, int(self.siglen*200/self.fs))
146184
return
147185

148186
# Bandpass filter the signal from 5-15Hz
@@ -162,10 +200,10 @@ def bandpass(self, plotsteps):
162200
plt.plot(self.sig_F)
163201
plt.legend(['After LP', 'After LP+HP'])
164202
plt.show()
165-
return
203+
return
166204

167205
# Compute the moving wave integration waveform from the filtered signal
168-
def mwi(sig, plotsteps):
206+
def mwi(self, plotsteps):
169207
# Compute 5 point derivative
170208
a_deriv = [1]
171209
b_deriv = [1/4, 1/8, 0, -1/8, -1/4]
@@ -245,8 +283,8 @@ def learnparams(self):
245283
while (windownum+1)*learntime*200<self.siglen:
246284
wavelearn_F = self.sig_F[windownum*learntime*200:(windownum+1)*learntime*200]
247285
wavelearn_I = self.sig_I[windownum*learntime*200:(windownum+1)*learntime*200]
248-
249-
# Find peaks in the signals
286+
287+
# Find peaks in the signal sections
250288
peakinds_F = findpeaks_radius(wavelearn_F, radius)
251289
peakinds_I = findpeaks_radius(wavelearn_I, radius)
252290
peaks_F = wavelearn_F[peakinds_F]
@@ -258,22 +296,24 @@ def learnparams(self):
258296
# Align peaks to minimum value and set to unit variance
259297
peaks_F = (peaks_F - min(peaks_F)) / np.std(peaks_F)
260298
peaks_I = (peaks_I - min(peaks_I)) / np.std(peaks_I)
261-
sigpeakinds_F = np.where(peaks_F) >= 1.4
262-
sigpeakinds_I = np.where(peaks_I) >= 1.4
299+
sigpeakinds_F = np.where(peaks_F >= 1.4)
300+
sigpeakinds_I = np.where(peaks_I >= 1.4)
263301

264302
# Final signal peak when both signals agree
265-
sigpeakinds = np.intersect1d(sigpeaks_F, sigpeaks_I)
303+
sigpeakinds = np.intersect1d(sigpeakinds_F, sigpeakinds_I)
266304
# Noise peaks are the remainders
267305
noisepeakinds_F = np.setdiff1d(peakinds_F, sigpeakinds)
268306
noisepeakinds_I = np.setdiff1d(peakinds_I, sigpeakinds)
269307

270308
# Found at least 2 peaks. Also peak 1 and 2 must be >200ms apart
271309
if len(sigpeakinds)>1 and sigpeakinds[1]-sigpeakinds[0]>40:
310+
print('should be out')
272311
break
273312

274313
# Didn't find 2 satisfactory peaks. Check the next window.
275314
windownum = windownum + 1
276-
315+
316+
277317
# Found at least 2 satisfactory peaks. Use them to set parameters.
278318

279319
# Set running peak estimates to first values
@@ -428,14 +468,14 @@ def istwave(self, i):
428468
else:
429469
return False
430470

431-
def returnresample(self):
471+
def reverseresampleqrs(self):
432472
# Refactor the qrs indices to match the fs of the original signal
433473

434474
self.qrs_inds = np.array(self.qrs_inds)
435475

436476
if self.fs!=200:
437477
self.qrs_inds = self.qrs_inds*fs/200
438-
478+
439479
self.qrs_inds = self.qrs_inds.astype('int64')
440480

441481

@@ -447,7 +487,7 @@ def pantompkins(sig, fs):
447487

448488
detector = PanTompkins(sig=sig, fs=fs)
449489

450-
detect_qrs_static()
490+
detector.detect_qrs_static()
451491

452492
return detector.qrs_inds
453493

@@ -470,7 +510,7 @@ def findpeaks_radius(sig, radius):
470510
peaklocs = []
471511

472512
# Pad samples at start and end
473-
sig = np.concatenate((np.ones(radius)*sig[0],sig, np.ones(radius)*sig[-1]))
513+
sig = np.concatenate((np.ones(radius)*sig[0], sig, np.ones(radius)*sig[-1]))
474514

475515
i=radius
476516
while i<siglen+radius:

0 commit comments

Comments
 (0)