Skip to content

Commit 5cb3632

Browse files
committed
add docstring
1 parent c786318 commit 5cb3632

File tree

7 files changed

+179
-542
lines changed

7 files changed

+179
-542
lines changed

README.rst

Lines changed: 0 additions & 466 deletions
Large diffs are not rendered by default.

wfdb/processing/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from .basic import resample_ann, resample_sig, resample_singlechan, resample_multichan, normalize
1+
from .basic import (resample_ann, resample_sig, resample_singlechan,
2+
resample_multichan, normalize)
23
from .gqrs import gqrs_detect
34
from .hr import compute_hr
45
from .peaks import find_peaks, correct_peaks

wfdb/processing/basic.py

Lines changed: 129 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,38 @@
44
from wfdb import Annotation
55

66

7-
def resample_ann(tt, sample):
8-
# tt: numpy.array as returned by signal.resample
9-
# sample: numpy.array containing indices of annotations (Annotation.sample)
10-
11-
# Compute the new annotation indices
12-
13-
tmp = numpy.zeros(len(tt), dtype='int16')
7+
def resample_ann(resampled_t, ann_sample):
8+
"""
9+
Compute the new annotation indices
10+
11+
Parameters
12+
----------
13+
resampled_t : numpy array
14+
Array of signal locations as returned by scipy.signal.resample
15+
ann_sample : numpy array
16+
Array of annotation locations
17+
18+
Returns
19+
-------
20+
resampled_ann_sample : numpy array
21+
Array of resampled annotation locations
22+
23+
"""
24+
tmp = numpy.zeros(len(resampled_t), dtype='int16')
1425
j = 0
15-
tprec = tt[j]
16-
for i, v in enumerate(sample):
26+
tprec = resampled_t[j]
27+
for i, v in enumerate(ann_sample):
1728
while True:
1829
d = False
1930
if v < tprec:
2031
j -= 1
21-
tprec = tt[j]
32+
tprec = resampled_t[j]
2233

23-
if j+1 == len(tt):
34+
if j+1 == len(resampled_t):
2435
tmp[j] += 1
2536
break
2637

27-
tnow = tt[j+1]
38+
tnow = resampled_t[j+1]
2839
if tprec <= v and v <= tnow:
2940
if v-tprec < tnow-v:
3041
tmp[j] += 1
@@ -41,77 +52,144 @@ def resample_ann(tt, sample):
4152
for i in idx:
4253
for j in range(tmp[i]):
4354
res.append(i)
44-
assert len(res) == len(sample)
55+
assert len(res) == len(ann_sample)
56+
4557
return numpy.asarray(res, dtype='int64')
4658

4759

4860
def resample_sig(x, fs, fs_target):
49-
# x: a numpy.array containing the signal
50-
# fs: the current frequency
51-
# fs_target: the target frequency
52-
53-
# Resample a signal
61+
"""
62+
Resample a signal to a different frequency.
63+
64+
Parameters
65+
----------
66+
x : numpy array
67+
Array containing the signal
68+
fs : int, or float
69+
The original sampling frequency
70+
fs_target : int, or float
71+
The target frequency
72+
73+
Returns
74+
-------
75+
resampled_x : numpy array
76+
Array of the resampled signal values
77+
resampled_t : numpy array
78+
Array of the resampled signal locations
79+
80+
"""
5481

5582
t = numpy.arange(x.shape[0]).astype('float64')
5683

5784
if fs == fs_target:
5885
return x, t
5986

6087
new_length = int(x.shape[0]*fs_target/fs)
61-
xx, tt = signal.resample(x, num=new_length, t=t)
62-
assert xx.shape == tt.shape and xx.shape[0] == new_length
63-
assert numpy.all(numpy.diff(tt) > 0)
64-
return xx, tt
88+
resampled_x, resampled_t = signal.resample(x, num=new_length, t=t)
89+
assert resampled_x.shape == resampled_t.shape and resampled_x.shape[0] == new_length
90+
assert numpy.all(numpy.diff(resampled_t) > 0)
91+
92+
return resampled_x, resampled_t
6593

6694

6795
def resample_singlechan(x, ann, fs, fs_target):
68-
# x: a numpy.array containing the signal
69-
# ann: an Annotation object
70-
# fs: the current frequency
71-
# fs_target: the target frequency
72-
73-
# Resample a single-channel signal with its annotations
74-
75-
xx, tt = resample_sig(x, fs, fs_target)
76-
77-
new_sample = resample_ann(tt, ann.sample)
96+
"""
97+
Resample a single-channel signal with its annotations
98+
99+
Parameters
100+
----------
101+
x: numpy array
102+
The signal array
103+
ann : wfdb Annotation
104+
The wfdb annotation object
105+
fs : int, or float
106+
The original frequency
107+
fs_target : int, or float
108+
The target frequency
109+
110+
Returns
111+
-------
112+
resampled_x : numpy array
113+
Array of the resampled signal values
114+
resampled_ann : wfdb Annotation
115+
Annotation containing resampled annotation locations
116+
117+
"""
118+
119+
resampled_x, resampled_t = resample_sig(x, fs, fs_target)
120+
121+
new_sample = resample_ann(resampled_t, ann.sample)
78122
assert ann.sample.shape == new_sample.shape
79123

80-
new_ann = Annotation(ann.record_name, ann.extension, new_sample, ann.symbol, ann.num, ann.subtype, ann.chan, ann.aux_note, ann.fs)
81-
return xx, new_ann
82-
124+
resampled_ann = Annotation(ann.record_name, ann.extension, new_sample,
125+
ann.symbol, ann.num, ann.subtype, ann.chan, ann.aux_note, ann.fs)
83126

84-
def resample_multichan(xs, ann, fs, fs_target, resamp_ann_chan=0):
85-
# xs: a numpy.ndarray containing the signals as returned by wfdb.srdsamp
86-
# ann: an Annotation object
87-
# fs: the current frequency
88-
# fs_target: the target frequency
89-
# resample_ann_channel: the signal channel that is used to compute new annotation indices
127+
return resampled_x, resampled_ann
90128

91-
# Resample multiple channels with their annotations
92129

130+
def resample_multichan(xs, ann, fs, fs_target, resamp_ann_chan=0):
131+
"""
132+
Resample multiple channels with their annotations
133+
134+
Parameters
135+
----------
136+
xs: numpy array
137+
The signal array
138+
ann : wfdb Annotation
139+
The wfdb annotation object
140+
fs : int, or float
141+
The original frequency
142+
fs_target : int, or float
143+
The target frequency
144+
resample_ann_channel : int, optional
145+
The signal channel used to compute new annotation indices
146+
147+
Returns
148+
-------
149+
resampled_xs : numpy array
150+
Array of the resampled signal values
151+
resampled_ann : wfdb Annotation
152+
Annotation containing resampled annotation locations
153+
154+
"""
93155
assert resamp_ann_chan < xs.shape[1]
94156

95157
lx = []
96158
lt = None
97159
for chan in range(xs.shape[1]):
98-
xx, tt = resample_sig(xs[:, chan], fs, fs_target)
99-
lx.append(xx)
160+
resampled_x, resampled_t = resample_sig(xs[:, chan], fs, fs_target)
161+
lx.append(resampled_x)
100162
if chan == resamp_ann_chan:
101-
lt = tt
163+
lt = resampled_t
102164

103165
new_sample = resample_ann(lt, ann.sample)
104166
assert ann.sample.shape == new_sample.shape
105167

106-
new_ann = Annotation(ann.record_name, ann.extension, new_sample, ann.symbol, ann.num, ann.subtype, ann.chan, ann.aux_note, ann.fs)
107-
return numpy.column_stack(lx), new_ann
168+
resampled_ann = Annotation(ann.record_name, ann.extension, new_sample, ann.symbol,
169+
ann.num, ann.subtype, ann.chan, ann.aux_note, ann.fs)
108170

171+
return numpy.column_stack(lx), resampled_ann
109172

110-
def normalize(x, lb=0, ub=1):
111-
# lb: Lower bound
112-
# ub: Upper bound
113173

114-
# Resizes a signal between the lower and upper bound
174+
def normalize(x, lb=0, ub=1):
175+
"""
176+
Normalize a signal between the lower and upper bound
177+
178+
Parameters
179+
----------
180+
x : numpy array
181+
Original signal to be normalized
182+
lb : int, or float
183+
Lower bound
184+
ub : int, or float
185+
Upper bound
186+
187+
Returns
188+
-------
189+
x_normalized : numpy array
190+
Normalized signal
191+
192+
"""
115193

116194
mid = ub - (ub - lb) / 2
117195
min_v = numpy.min(x)

wfdb/processing/gqrs.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,8 @@ def gqrs_detect(x, fs, adcgain, adczero, threshold=1.0,
463463
Functionally, a direct port of the gqrs algorithm from the original
464464
wfdb package. Therefore written to accept wfdb record fields.
465465
466-
Input arguments:
466+
Parameters
467+
----------
467468
- x (required): The digital signal as a numpy array
468469
- fs (required): The sampling frequency of the signal
469470
- adcgain: The gain of the signal (the number of adus (q.v.) per physical unit)
@@ -481,7 +482,10 @@ def gqrs_detect(x, fs, adcgain, adczero, threshold=1.0,
481482
- QRSa (default=750): Typical QRS peak-to-peak amplitude, in microvolts
482483
- QRSamin (default=130): Minimum QRS peak-to-peak amplitude, in microvolts
483484
484-
Note: This function should not be used for signals with fs <= 50Hz
485+
Notes
486+
-----
487+
This function should not be used for signals with fs <= 50Hz
488+
485489
"""
486490
conf = Conf(freq=fs, gain=adcgain, hr=hr,
487491
RRdelta=RRdelta, RRmin=RRmin, RRmax=RRmax,

wfdb/processing/hr.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
import numpy as np
22

33

4-
def compute_hr(siglen, peak_indices, fs):
4+
def compute_hr(sig_len, peak_indices, fs):
55
"""
66
Compute instantaneous heart rate from peak indices.
77
8-
Usage:
9-
heart_rate = compute_hr(siglen, peak_indices, fs)
8+
Parameters
9+
----------
10+
sig_len : int
11+
The length of the corresponding signal
12+
peak_indices : numpy array
13+
The peak index locations
14+
fs : int, or float
15+
The corresponding signal's sampling frequency.
16+
17+
Returns
18+
-------
19+
heart_rate : numpy array
20+
An array of the instantaneous heart rate, with the length of the
21+
corresponding signal. Contains numpy.nan where heart rate could not be
22+
computed.
1023
11-
Input argumnets:
12-
- siglen (required): The length of the corresponding signal
13-
- peak_indices (required): The peak indices.
14-
- fs (required): The corresponding signal's sampling frequency.
15-
16-
Output arguments:
17-
- heart_rate: A numpy array of the instantaneous heart rate, with the length
18-
of the corresponding signal. Contains numpy.nan where heart rate could not be computed.
1924
"""
20-
heart_rate = np.full(siglen, np.nan, dtype='float32')
25+
heart_rate = np.full(sig_len, np.nan, dtype='float32')
2126

2227
if len(peak_indices) < 2:
2328
return heart_rate

wfdb/processing/peaks.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
import copy
22
import numpy
3-
from .gqrs import time_to_sample_number, Conf, Peak, Annotation
4-
from .basic import smooth
53

6-
def find_peaks(x):
7-
# Definitions:
8-
# * Hard peak: a peak that is either /\ or \/
9-
# * Soft peak: a peak that is either /-*\ or \-*/ (In that cas we define the middle of it as the peak)
4+
from .basic import smooth
5+
from .gqrs import time_to_sample_number, Conf, Peak, Annotation
106

11-
# Returns two numpy arrays:
12-
# * hard_peaks contains the indices of the Hard peaks
13-
# * soft_peaks contains the indices of the Soft peaks
147

8+
def find_peaks(x):
9+
"""
10+
Find hard peaks and soft peaks in a signal, defined as follows:
11+
- Hard peak: a peak that is either /\ or \/
12+
- Soft peak: a peak that is either /-*\ or \-*/ (In that case we define the
13+
middle of it as the peak)
14+
15+
Parameters
16+
----------
17+
x : numpy array
18+
The signal array
19+
20+
Returns
21+
-------
22+
hard_peaks : numpy array
23+
Array containing the indices of the hard peaks:
24+
soft_peaks : numpy array
25+
Array containing the indices of the soft peaks
26+
27+
"""
1528
if len(x) == 0:
1629
return numpy.empty([0]), numpy.empty([0])
1730

@@ -41,6 +54,8 @@ def find_peaks(x):
4154

4255

4356
def correct_peaks(x, peak_indices, min_gap, max_gap, smooth_window):
57+
"""
58+
"""
4459
N = x.shape[0]
4560

4661
rpeaks = numpy.zeros(N)

wfdb/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.3.9'
1+
__version__ = '2.0.0'

0 commit comments

Comments
 (0)