Skip to content

Commit 2842a25

Browse files
committed
refactor rddat for all formats
1 parent e7ef151 commit 2842a25

File tree

1 file changed

+81
-110
lines changed

1 file changed

+81
-110
lines changed

wfdb/_signals.py

Lines changed: 81 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ def rdsegment(filename, dirname, pbdir, nsig, fmt, siglen, byteoffset,
467467
if smoothframes or sum(sampsperframe)==nsig:
468468

469469
# Allocate signal array
470-
signals = np.empty([sampto-sampfrom, len(channels)], dtype = 'int64')
470+
signals = np.zeros([sampto-sampfrom, len(channels)], dtype = 'int64')
471471

472472
# Read each wanted dat file and store signals
473473
for fn in w_filename:
@@ -539,7 +539,6 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
539539

540540
# Total number of bytes to be processed in intermediate step.
541541
totalprocessbytes = requiredbytenum('read', fmt, totalprocesssamples)
542-
543542

544543
# Get the intermediate bytes or samples to process. Bit of a discrepancy. Recall special formats
545544
# load uint8 bytes, other formats already load samples.
@@ -560,9 +559,9 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
560559

561560
# Read the required bytes from the dat file.
562561
# Then continue to process the read values into proper samples
563-
if fmt == '212':
564-
565-
# Clear memory???
562+
563+
# Special formats
564+
if fmt in ['212', '310', '311']:
566565

567566
# No extra samples/frame. Obtain original uniform numpy array
568567
if tsampsperframe==nsig:
@@ -584,22 +583,22 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
584583
elif smoothframes:
585584

586585
# Turn the bytes into actual samples. Flat 1d array. All samples for all frames.
587-
sigflat = bytes2samples(sigbytes, totalprocesssamples, fmt)
586+
sigbytes = bytes2samples(sigbytes, totalprocesssamples, fmt)
588587

589588
# Remove extra leading sample read within the byte block if any
590589
if blockfloorsamples:
591-
sigflat = sigflat[blockfloorsamples:]
590+
sigbytes = sigbytes[blockfloorsamples:]
592591

593-
# Smoothed signal
594-
sig = np.zeros((int(len(sigflat)/tsampsperframe) , nsig))
592+
# Allocate memory for smoothed signal
593+
sig = np.zeros((int(len(sigbytes)/tsampsperframe) , nsig), dtype='int64')
595594

596595
# Transfer and average samples
597596
for ch in range(nsig):
598597
if sampsperframe[ch] == 1:
599-
sig[:, ch] = sigflat[sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
598+
sig[:, ch] = sigbytes[sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
600599
else:
601600
for frame in range(sampsperframe[ch]):
602-
sig[:, ch] += sigflat[sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
601+
sig[:, ch] += sigbytes[sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
603602
sig = (sig / sampsperframe)
604603

605604
# Skew the signal
@@ -608,28 +607,23 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
608607
# Extra frames present without wanting smoothing. Return all expanded samples.
609608
else:
610609
# Turn the bytes into actual samples. Flat 1d array. All samples for all frames.
611-
sigflat = bytes2samples(sigbytes, totalprocesssamples, fmt)
610+
sigbytes = bytes2samples(sigbytes, totalprocesssamples, fmt)
612611

613612
# Remove extra leading sample read within the byte block if any
614613
if blockfloorsamples:
615-
sigflat = sigflat[blockfloorsamples:]
614+
sigbytes = sigbytes[blockfloorsamples:]
616615

617616
# Arranged signals
618617
sig = []
619618

620619
# Transfer over samples
621620
for ch in range(nsig):
622621
# Indices of the flat signal that belong to the channel
623-
ch_indices = np.concatenate(([np.array(range(sampsperframe[ch])) + sum([0]+sampsperframe[:ch]) + tsampsperframe*framenum for framenum in range(int(len(sigflat)/tsampsperframe))]))
624-
sig.append(sigflat[ch_indices])
622+
ch_indices = np.concatenate(([np.array(range(sampsperframe[ch])) + sum([0]+sampsperframe[:ch]) + tsampsperframe*framenum for framenum in range(int(len(sigbytes)/tsampsperframe))]))
623+
sig.append(sigbytes[ch_indices])
625624

626625
# Skew the signal
627626
sig = skewsig(sig, skew, nsig, readlen, fmt, nanreplace, sampsperframe)
628-
629-
elif fmt == '310':
630-
pass
631-
elif fmt == '311':
632-
pass
633627
# Simple format signals that are loaded as they are stored.
634628
else:
635629
# Adjust for skew, reshape, and consider sampsperframe.
@@ -640,9 +634,6 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
640634
elif fmt == '160':
641635
sigbytes = sigbytes - 32768
642636

643-
#print('sigbytes:', sigbytes)
644-
645-
646637
# No extra samples/frame. Obtain original uniform numpy array
647638
if tsampsperframe==nsig:
648639

@@ -656,19 +647,20 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
656647
# Extra frames present to be smoothed. Obtain averaged uniform numpy array
657648
elif smoothframes:
658649

659-
# Allocate memory for signal
660-
sig = np.empty([readlen, nsig], dtype='int')
650+
# Allocate memory for smoothed signal
651+
sig = np.zeros((int(len(sigbytes)/tsampsperframe) , nsig), dtype='int64')
661652

662-
# Samples are averaged within frames
663-
# Obtain the correct samples, factoring in skew
653+
# Transfer and average samples
664654
for ch in range(nsig):
665655
if sampsperframe[ch] == 1:
666-
sig[:, ch] = sigbytes[skew[ch]*tsampsperframe+sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
656+
sig[:, ch] = sigbytes[sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
667657
else:
668658
for frame in range(sampsperframe[ch]):
669-
sig[:, ch] += sigbytes[skew[ch]*tsampsperframe+sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
659+
sig[:, ch] += sigbytes[sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
670660
sig = (sig / sampsperframe)
671661

662+
# Skew the signal
663+
sig = skewsig(sig, skew, nsig, readlen, fmt, nanreplace)
672664

673665
# Extra frames present without wanting smoothing. Return all expanded samples.
674666
else:
@@ -677,14 +669,8 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
677669

678670
# Transfer over samples
679671
for ch in range(nsig):
680-
# chansig = np.zeros(readlen*sampsperframe[ch], dtype='int')
681-
# for frame in range(sampsperframe[ch]):
682-
# chansig[frame::sampsperframe[ch]] = sigbytes[skew[ch]*tsampsperframe+sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
683-
# sig.append(chansig)
684-
685-
# Get the sample indices of the channel samples to transfer over
672+
# Indices of the flat signal that belong to the channel
686673
ch_indices = np.concatenate([np.array(range(sampsperframe[ch])) + sum([0]+sampsperframe[:ch]) + tsampsperframe*framenum for framenum in range(int(len(sigbytes)/tsampsperframe))])
687-
688674
sig.append(sigbytes[ch_indices])
689675

690676
# Skew the signal
@@ -848,11 +834,12 @@ def getdatbytes(filename, dirname, pbdir, fmt, startbyte, nsamp):
848834
return sigbytes
849835

850836

851-
# Converts loaded uint8 blocks into samples for special formats
852-
def bytes2samples(sigbytes, nsamp, fmt):
853837

838+
def bytes2samples(sigbytes, nsamp, fmt):
839+
"""
840+
Converts loaded uint8 blocks into samples for special formats
841+
"""
854842
if fmt == '212':
855-
856843
# Easier to process when dealing with whole blocks
857844
if nsamp % 2:
858845
nsamp = nsamp + 1
@@ -877,19 +864,69 @@ def bytes2samples(sigbytes, nsamp, fmt):
877864
# Loaded values as unsigned. Convert to 2's complement form:
878865
# values > 2^11-1 are negative.
879866
sig[sig > 2047] -= 4096
880-
sig[sig > 2047] -= 4096
881867

882868
elif fmt == '310':
883-
pass
869+
# Easier to process when dealing with whole blocks
870+
if nsamp % 3:
871+
nsamp = upround(nsamp,3)
872+
addedsamps = nsamp % 3
873+
sigbytes = np.append(sigbytes, np.zeros(addedsamps, dtype='uint8'))
874+
else:
875+
addedsamps = 0
876+
877+
# 1d array of actual samples. Fill the individual triplets.
878+
sig = np.zeros(nsamp, dtype='int64')
879+
880+
# One sample triplet is stored in one byte quartet
881+
# First sample is 7 msb of first byte and 3 lsb of second byte.
882+
sig[0::3] = (sigbytes[0::4] >> 1)[0:len(sig[0::3])] + 128 * np.bitwise_and(sigbytes[1::4], 0x07)[0:len(sig[0::3])]
883+
# Second signal is 7 msb of third byte and 3 lsb of forth byte
884+
sig[1::3] = (sigbytes[2::4] >> 1)[0:len(sig[1::3])] + 128 * np.bitwise_and(sigbytes[3::4], 0x07)[0:len(sig[1::3])]
885+
# Third signal is 5 msb of second byte and 5 msb of forth byte
886+
sig[2::3] = np.bitwise_and((sigbytes[1::4] >> 3), 0x1f)[0:len(sig[2::3])] + 32 * np.bitwise_and(sigbytes[3::4] >> 3, 0x1f)[0:len(sig[2::3])]
887+
888+
# Remove trailing samples read within the byte block if originally not 3n sampled
889+
if addedsamps:
890+
sig = sig[:-addedsamps]
891+
892+
# Loaded values as unsigned. Convert to 2's complement form:
893+
# values > 2^9-1 are negative.
894+
sig[sig > 511] -= 1024
884895

885896
elif fmt == '311':
886-
pass
897+
# Easier to process when dealing with whole blocks
898+
if nsamp % 3:
899+
nsamp = upround(nsamp,3)
900+
addedsamps = nsamp % 3
901+
sigbytes = np.append(sigbytes, np.zeros(addedsamps, dtype='uint8'))
902+
else:
903+
addedsamps = 0
904+
905+
# 1d array of actual samples. Fill the individual triplets.
906+
sig = np.zeros(nsamp, dtype='int64')
907+
908+
# One sample triplet is stored in one byte quartet
909+
# First sample is first byte and 2 lsb of second byte.
910+
sig[0::3] = sigbytes[0::4][0:len(sig[0::3])] + 256 * np.bitwise_and(sigbytes[1::4], 0x03)[0:len(sig[0::3])]
911+
# Second sample is 6 msb of second byte and 4 lsb of third byte
912+
sig[1::3] = (sigbytes[1::4] >> 2)[0:len(sig[1::3])] + 64 * np.bitwise_and(sigbytes[2::4], 0x0f)[0:len(sig[1::3])]
913+
# Third sample is 4 msb of third byte and 6 msb of forth byte
914+
sig[2::3] = (sigbytes[2::4] >> 4)[0:len(sig[2::3])] + 16 * np.bitwise_and(sigbytes[3::4], 0x7f)[0:len(sig[2::3])]
915+
916+
# Remove trailing samples read within the byte block if originally not 3n sampled
917+
if addedsamps:
918+
sig = sig[:-addedsamps]
919+
920+
# Loaded values as unsigned. Convert to 2's complement form:
921+
# values > 2^9-1 are negative.
922+
sig[sig > 511] -= 1024
887923
return sig
888924

889925

890-
# Skew the signal and shave off extra samples
891926
def skewsig(sig, skew, nsig, readlen, fmt, nanreplace, sampsperframe=None):
892927
"""
928+
Skew the signal, insert nans and shave off end of array if needed.
929+
893930
fmt is just for the correct nan value.
894931
sampsperframe is only used for skewing expanded signals.
895932
"""
@@ -1202,7 +1239,7 @@ def processwfdbbytes(filename, dirname, pbdir, fmt, startbyte, readlen, nsig, sa
12021239
# At least one channel has multiple samples per frame. Extra samples are averaged.
12031240
else:
12041241
# Keep the first sample in each frame for each channel
1205-
sig = np.empty([readlen, nsig])
1242+
sig = np.zeros([readlen, nsig])
12061243
for ch in range(0, nsig):
12071244
if sampsperframe[ch] == 1:
12081245
sig[:, ch] = sigbytes[sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
@@ -1222,68 +1259,6 @@ def processwfdbbytes(filename, dirname, pbdir, fmt, startbyte, readlen, nsig, sa
12221259

12231260

12241261

1225-
1226-
1227-
1228-
1229-
1230-
1231-
1232-
1233-
1234-
1235-
1236-
# OLD! DO NOT USE
1237-
def skewsignal(sig, skew, filename, dirname, pbdir, nsig, fmt, siglen, sampfrom, sampto, startbyte,
1238-
bytesloaded, byteoffset, sampsperframe):
1239-
1240-
# Total number of samples per frame.
1241-
tsampsperframe = sum(sampsperframe)
1242-
1243-
if max(skew) > 0:
1244-
# Array of samples to fill in the final samples of the skewed channels.
1245-
extrasig = np.empty([max(skew), nsig])
1246-
extrasig.fill(digi_nan(fmt))
1247-
1248-
# Load the extra samples if the end of the file hasn't been reached.
1249-
if siglen - (sampto - sampfrom):
1250-
startbyte = startbyte + bytesloaded
1251-
# Point the the file pointer to the start of a block of 3 or 4 and
1252-
# keep track of how many samples to discard after reading. For
1253-
# regular formats the file pointer is already at the correct
1254-
# location.
1255-
if fmt == '212':
1256-
# Extra samples to read
1257-
floorsamp = (startbyte - byteoffset) % 3
1258-
# Now the byte pointed to is the first of a byte triplet
1259-
# storing 2 samples. It happens that the extra samples match
1260-
# the extra bytes for fmt 212
1261-
startbyte = startbyte - floorsamp
1262-
elif (fmt == '310') | (fmt == '311'):
1263-
floorsamp = (startbyte - byteoffset) % 4
1264-
# Now the byte pointed to is the first of a byte quartet
1265-
# storing 3 samples.
1266-
startbyte = startbyte - floorsamp
1267-
1268-
# The length of extra signals to be loaded
1269-
extraloadlen = min(siglen - (sampto - sampfrom), max(skew))
1270-
1271-
# Array of extra loaded samples
1272-
extraloadedsig = processwfdbbytes(filename, dirname, pbdir,
1273-
fmt, startbyte, extraloadlen, nsig, sampsperframe, floorsamp)[0]
1274-
1275-
# Fill in the extra loaded samples
1276-
extrasig[:extraloadedsig.shape[0], :] = extraloadedsig
1277-
1278-
# Fill in the skewed channels with the appropriate values.
1279-
for ch in range(0, nsig):
1280-
if skew[ch] > 0:
1281-
sig[:-skew[ch], ch] = sig[skew[ch]:, ch]
1282-
sig[-skew[ch]:, ch] = extrasig[:skew[ch], ch]
1283-
return sig
1284-
1285-
1286-
12871262
# Bytes required to hold each sample (including wasted space) for
12881263
# different wfdb formats
12891264
bytespersample = {'8': 1, '16': 2, '24': 3, '32': 4, '61': 2,
@@ -1458,10 +1433,6 @@ def wrdatfile(filename, fmt, d_signals, byteoffset, expanded=False, e_d_signals=
14581433
for framenum in range(spf):
14591434
d_signals[:, expand_ch] = e_d_signals[ch][framenum::spf]
14601435
expand_ch = expand_ch + 1
1461-
1462-
# ch_indices = np.concatenate(([np.array(range(sampsperframe[ch])) + sum([0]+sampsperframe[:ch]) + tsampsperframe*framenum for framenum in range(int(len(sigflat)/tsampsperframe))]))
1463-
# sig.append(sigflat[ch_indices])
1464-
# d_signals[] = e_d_signals[ch]
14651436

14661437
# This nsig is used for making list items.
14671438
# Does not necessarily represent number of signals (ie. for expanded=True)

0 commit comments

Comments
 (0)