Skip to content

Commit 186ae72

Browse files
author
Benjamin Moody
committed
SignalMixin.smooth_frames: assorted optimizations.
The variable tspf is not used and can be removed. sig_len can be calculated using // rather than / and truncating to an integer (the latter could be incorrect for records longer than 2**53.) The output array can be allocated using np.empty instead of np.zeros since it will be fully initialized by the subsequent loop. Since each frame is independent of the others, the loop can be broken up into blocks (here, arbitrarily chosen as 2**16 frames) to reduce temporary memory usage while still spending most of our CPU time in numpy operations.
1 parent 6db9ebf commit 186ae72

File tree

1 file changed

+11
-7
lines changed

1 file changed

+11
-7
lines changed

wfdb/io/_signal.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -827,9 +827,6 @@ def smooth_frames(self, sigtype='physical'):
827827
if spf[ch] is None:
828828
spf[ch] = 1
829829

830-
# Total samples per frame
831-
tspf = sum(spf)
832-
833830
# The output data type should be the smallest type that can
834831
# represent any input sample value. The intermediate data type
835832
# must be able to represent the sum of spf[ch] sample values.
@@ -854,7 +851,7 @@ def smooth_frames(self, sigtype='physical'):
854851
raise ValueError("sigtype must be 'physical' or 'digital'")
855852

856853
n_sig = len(expanded_signal)
857-
sig_len = int(len(expanded_signal[0])/spf[0])
854+
sig_len = len(expanded_signal[0]) // spf[0]
858855
input_dtypes = set()
859856
for ch in range(n_sig):
860857
if len(expanded_signal[ch]) != sig_len * spf[ch]:
@@ -868,15 +865,22 @@ def smooth_frames(self, sigtype='physical'):
868865
if all(dt <= output_dtype for dt in input_dtypes):
869866
break
870867

871-
signal = np.zeros((sig_len, n_sig), dtype=output_dtype)
868+
signal = np.empty((sig_len, n_sig), dtype=output_dtype)
869+
870+
# Large input arrays will be processed in chunks to avoid the need
871+
# to allocate a single huge temporary array.
872+
CHUNK_SIZE = 65536
872873

873874
for ch in range(n_sig):
874875
if spf[ch] == 1:
875876
signal[:, ch] = expanded_signal[ch]
876877
else:
877878
frames = expanded_signal[ch].reshape(-1, spf[ch])
878-
signal_sum = np.sum(frames, axis=1, dtype=intermediate_dtype)
879-
signal[:, ch] = signal_sum / spf[ch]
879+
for chunk_start in range(0, sig_len, CHUNK_SIZE):
880+
chunk_end = chunk_start + CHUNK_SIZE
881+
signal_sum = np.sum(frames[chunk_start:chunk_end, :],
882+
axis=1, dtype=intermediate_dtype)
883+
signal[chunk_start:chunk_end, ch] = signal_sum / spf[ch]
880884

881885
return signal
882886

0 commit comments

Comments
 (0)