Skip to content

Commit 6cd18ba

Browse files
author
Benjamin Moody
committed
multi_to_single: add expanded argument.
When reading a multi-segment record, the multi_to_single function is used to stitch the segments together into a virtual single-segment record. To enable this to work in expanded (non-smooth-frames) mode, we want to combine the 'e_p_signal' or 'e_d_signal' arrays from the individual segments, rather than 'p_signal' or 'd_signal'.
1 parent 5ff3563 commit 6cd18ba

File tree

1 file changed

+46
-12
lines changed

1 file changed

+46
-12
lines changed

wfdb/io/record.py

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,7 +1269,7 @@ def _arrange_fields(
12691269
self.n_seg = len(self.segments)
12701270
self._adjust_datetime(sampfrom=sampfrom)
12711271

1272-
def multi_to_single(self, physical, return_res=64):
1272+
def multi_to_single(self, physical, return_res=64, expanded=False):
12731273
"""
12741274
Create a Record object from the MultiRecord object. All signal
12751275
segments will be combined into the new object's `p_signal` or
@@ -1283,6 +1283,11 @@ def multi_to_single(self, physical, return_res=64):
12831283
return_res : int, optional
12841284
The return resolution of the `p_signal` field. Options are:
12851285
64, 32, and 16.
1286+
expanded : bool, optional
1287+
If false, combine the sample data from `p_signal` or `d_signal`
1288+
into a single two-dimensional array. If true, combine the
1289+
sample data from `e_p_signal` or `e_d_signal` into a list of
1290+
one-dimensional arrays.
12861291
12871292
Returns
12881293
-------
@@ -1386,18 +1391,31 @@ def multi_to_single(self, physical, return_res=64):
13861391

13871392
# Figure out signal attribute to set, and its dtype.
13881393
if physical:
1389-
sig_attr = "p_signal"
1394+
if expanded:
1395+
sig_attr = "e_p_signal"
1396+
else:
1397+
sig_attr = "p_signal"
13901398
# Figure out the largest required dtype
13911399
dtype = _signal._np_dtype(return_res, discrete=False)
13921400
nan_vals = np.array([self.n_sig * [np.nan]], dtype=dtype)
13931401
else:
1394-
sig_attr = "d_signal"
1402+
if expanded:
1403+
sig_attr = "e_d_signal"
1404+
else:
1405+
sig_attr = "d_signal"
13951406
# Figure out the largest required dtype
13961407
dtype = _signal._np_dtype(return_res, discrete=True)
13971408
nan_vals = np.array([_signal._digi_nan(fields["fmt"])], dtype=dtype)
13981409

1410+
samps_per_frame = fields["samps_per_frame"]
1411+
13991412
# Initialize the full signal array
1400-
combined_signal = np.repeat(nan_vals, self.sig_len, axis=0)
1413+
if expanded:
1414+
combined_signal = []
1415+
for nan_val, spf in zip(nan_vals[0], samps_per_frame):
1416+
combined_signal.append(np.repeat(nan_val, spf * self.sig_len))
1417+
else:
1418+
combined_signal = np.repeat(nan_vals, self.sig_len, axis=0)
14011419

14021420
# Start and end samples in the overall array to place the
14031421
# segment samples into
@@ -1408,9 +1426,16 @@ def multi_to_single(self, physical, return_res=64):
14081426
# Copy over the signals directly. Recall there are no
14091427
# empty segments in fixed layout records.
14101428
for i in range(self.n_seg):
1411-
combined_signal[start_samps[i] : end_samps[i], :] = getattr(
1412-
self.segments[i], sig_attr
1413-
)
1429+
if expanded:
1430+
signals = getattr(self.segments[i], sig_attr)
1431+
for ch in range(self.n_sig):
1432+
start = start_samps[i] * samps_per_frame[ch]
1433+
end = end_samps[i] * samps_per_frame[ch]
1434+
combined_signal[ch][start:end] = signals[ch]
1435+
else:
1436+
combined_signal[start_samps[i] : end_samps[i], :] = getattr(
1437+
self.segments[i], sig_attr
1438+
)
14141439
else:
14151440
# Copy over the signals into the matching channels
14161441
for i in range(1, self.n_seg):
@@ -1424,9 +1449,18 @@ def multi_to_single(self, physical, return_res=64):
14241449
for ch in range(self.n_sig):
14251450
# Copy over relevant signal
14261451
if segment_channels[ch] is not None:
1427-
combined_signal[
1428-
start_samps[i] : end_samps[i], ch
1429-
] = getattr(seg, sig_attr)[:, segment_channels[ch]]
1452+
if expanded:
1453+
signals = getattr(seg, sig_attr)
1454+
signal = signals[segment_channels[ch]]
1455+
start = start_samps[i] * samps_per_frame[ch]
1456+
end = end_samps[i] * samps_per_frame[ch]
1457+
combined_signal[ch][start:end] = signal
1458+
else:
1459+
combined_signal[
1460+
start_samps[i] : end_samps[i], ch
1461+
] = getattr(seg, sig_attr)[
1462+
:, segment_channels[ch]
1463+
]
14301464

14311465
# Create the single segment Record object and set attributes
14321466
record = Record()
@@ -1436,9 +1470,9 @@ def multi_to_single(self, physical, return_res=64):
14361470

14371471
# Use the signal to set record features
14381472
if physical:
1439-
record.set_p_features()
1473+
record.set_p_features(expanded=expanded)
14401474
else:
1441-
record.set_d_features()
1475+
record.set_d_features(expanded=expanded)
14421476

14431477
return record
14441478

0 commit comments

Comments
 (0)