Skip to content

Commit d2a95d7

Browse files
committed
first finish refactor
1 parent 2842a25 commit d2a95d7

File tree

2 files changed

+14
-294
lines changed

2 files changed

+14
-294
lines changed

wfdb/_signals.py

Lines changed: 8 additions & 294 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
import math
44
from . import downloads
5-
import pdb
5+
66
# All defined WFDB dat formats
77
datformats = ["80","212","16","24","32"]
88

@@ -486,16 +486,11 @@ def rdsegment(filename, dirname, pbdir, nsig, fmt, siglen, byteoffset,
486486

487487
# Copy over the wanted signals
488488
for cn in range(len(out_datchannel[fn])):
489-
490489
signals[out_datchannel[fn][cn]] = datsignals[r_w_channel[fn][cn]]
491490

492-
493-
494491
return signals
495492

496493

497-
498-
499494
def rddat(filename, dirname, pbdir, fmt, nsig,
500495
siglen, byteoffset, sampsperframe,
501496
skew, sampfrom, sampto, smoothframes):
@@ -543,7 +538,7 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
543538
# Get the intermediate bytes or samples to process. Bit of a discrepancy. Recall special formats
544539
# load uint8 bytes, other formats already load samples.
545540

546-
#Get values from dat file, and append bytes/samples if needed.
541+
# Read values from dat file, and append bytes/samples if needed.
547542
if extraflatsamples:
548543
if fmt in ['212', '310', '311']:
549544
# Extra number of bytes to append onto the bytes read from the dat file.
@@ -557,8 +552,7 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
557552
else:
558553
sigbytes = getdatbytes(filename, dirname, pbdir, fmt, startbyte, nreadsamples)
559554

560-
# Read the required bytes from the dat file.
561-
# Then continue to process the read values into proper samples
555+
# Continue to process the read values into proper samples
562556

563557
# Special formats
564558
if fmt in ['212', '310', '311']:
@@ -599,7 +593,9 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
599593
else:
600594
for frame in range(sampsperframe[ch]):
601595
sig[:, ch] += sigbytes[sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
602-
sig = (sig / sampsperframe)
596+
597+
# Have to change the dtype for averaging frames
598+
sig = (sig.astype('float64') / sampsperframe)
603599

604600
# Skew the signal
605601
sig = skewsig(sig, skew, nsig, readlen, fmt, nanreplace)
@@ -657,7 +653,8 @@ def rddat(filename, dirname, pbdir, fmt, nsig,
657653
else:
658654
for frame in range(sampsperframe[ch]):
659655
sig[:, ch] += sigbytes[sum(([0] + sampsperframe)[:ch + 1]) + frame::tsampsperframe]
660-
sig = (sig / sampsperframe)
656+
# Have to change the dtype for averaging frames
657+
sig = (sig.astype('float64') / sampsperframe)
661658

662659
# Skew the signal
663660
sig = skewsig(sig, skew, nsig, readlen, fmt, nanreplace)
@@ -834,7 +831,6 @@ def getdatbytes(filename, dirname, pbdir, fmt, startbyte, nsamp):
834831
return sigbytes
835832

836833

837-
838834
def bytes2samples(sigbytes, nsamp, fmt):
839835
"""
840836
Converts loaded uint8 blocks into samples for special formats
@@ -977,288 +973,6 @@ def checksigdims(sig, readlen, nsig, sampsperframe):
977973
raise ValueError('Samples were not loaded correctly')
978974

979975

980-
981-
982-
983-
984-
985-
986-
987-
988-
989-
990-
991-
992-
993-
994-
995-
# OLD! DO NOT USE
996-
997-
# Read digital samples from a wfdb signal file
998-
# Returns the signal and the number of bytes read.
999-
def processwfdbbytes(filename, dirname, pbdir, fmt, startbyte, readlen, nsig, sampsperframe, floorsamp=0):
1000-
"""
1001-
Read digital samples from a wfdb dat file
1002-
1003-
Input variables:
1004-
- filename: the name of the dat file.
1005-
- dirname: the full directory where the dat file is located, if the dat file is local.
1006-
- pbdir: the physiobank directory where the dat file is located, if the dat file is remote.
1007-
- fmt: the format of the dat file
1008-
- startbyte: the starting byte to skip to
1009-
- readlen: the length of the signal to be read, in samples.
1010-
- nsig:
1011-
- floorsamp: the extra sample index used to read special formats (212, 310, 311).
1012-
1013-
"""
1014-
1015-
# Total number of samples per frame
1016-
tsampsperframe = sum(sampsperframe)
1017-
1018-
# Total number of signal samples to be collected (including discarded ones)
1019-
nsamp = readlen * tsampsperframe + floorsamp
1020-
1021-
# Reading the dat file into np array and reshaping. Formats 212, 310, and 311 need special processing.
1022-
# Note that for these formats with multi samples/frame, have to convert
1023-
# bytes to samples before returning average frame values.
1024-
if fmt == '212':
1025-
# Read the bytes from the file as unsigned integer blocks
1026-
sigbytes, bytesloaded = getdatbytes(filename, dirname, pbdir, fmt, nsamp, startbyte)
1027-
1028-
# use this for byte processing
1029-
processnsamp = nsamp
1030-
1031-
# For odd sampled records, imagine an extra sample and add an extra byte
1032-
# to simplify the processing step and remove the extra sample at the end.
1033-
if processnsamp % 2:
1034-
sigbytes = np.append(sigbytes, 0).astype('uint64')
1035-
processnsamp+=1
1036-
1037-
# No extra samples/frame
1038-
if tsampsperframe == nsig:
1039-
# Turn the bytes into actual samples.
1040-
sig = np.zeros(processnsamp) # 1d array of actual samples
1041-
# One sample pair is stored in one byte triplet.
1042-
sig[0::2] = sigbytes[0::3] + 256 * \
1043-
np.bitwise_and(sigbytes[1::3], 0x0f) # Even numbered samples
1044-
if len(sig > 1):
1045-
# Odd numbered samples
1046-
sig[1::2] = sigbytes[2::3] + 256*np.bitwise_and(sigbytes[1::3] >> 4, 0x0f)
1047-
if floorsamp: # Remove extra sample read
1048-
sig = sig[floorsamp:]
1049-
1050-
# Remove extra sample read if originally odd sampled
1051-
if nsamp % 2:
1052-
sig = sig[:-1]
1053-
1054-
# Reshape into final array of samples
1055-
sig = sig.reshape(readlen, nsig)
1056-
sig = sig.astype(int)
1057-
# Loaded values as unsigned. Convert to 2's complement form: values
1058-
# > 2^11-1 are negative.
1059-
sig[sig > 2047] -= 4096
1060-
# At least one channel has multiple samples per frame. All extra samples are averaged
1061-
else:
1062-
# Turn the bytes into actual samples.
1063-
sigall = np.zeros(processnsamp) # 1d array of actual samples
1064-
sigall[0::2] = sigbytes[0::3] + 256 * \
1065-
np.bitwise_and(sigbytes[1::3], 0x0f) # Even numbered samples
1066-
1067-
if len(sigall) > 1:
1068-
# Odd numbered samples
1069-
sigall[1::2] = sigbytes[2::3] + 256 * \
1070-
np.bitwise_and(sigbytes[1::3] >> 4, 0x0f)
1071-
if floorsamp: # Remove extra sample read
1072-
sigall = sigall[floorsamp:]
1073-
1074-
# Remove extra sample read if originally odd sampled
1075-
if nsamp % 2:
1076-
sigall = sigall[:-1]
1077-
1078-
# Convert to int64 to be able to hold -ve values
1079-
sigall = sigall.astype('int')
1080-
# Loaded values as unsigned. Convert to 2's complement form: values
1081-
# > 2^11-1 are negative.
1082-
sigall[sigall > 2047] -= 4096
1083-
# Give the average sample in each frame for each channel
1084-
sig = np.zeros([readlen, nsig])
1085-
for ch in range(0, nsig):
1086-
if sampsperframe[ch] == 1:
1087-
sig[:, ch] = sigall[
1088-
sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
1089-
else:
1090-
for frame in range(0, sampsperframe[ch]):
1091-
sig[:, ch] += sigall[sum(([0] + sampsperframe)
1092-
[:ch + 1]) + frame::tsampsperframe]
1093-
sig = (sig / sampsperframe).astype('int')
1094-
# Three 10 bit samples packed into 4 bytes with 2 bits discarded
1095-
elif fmt == '310':
1096-
1097-
# Read the bytes from the file as unsigned integer blocks
1098-
sigbytes, bytesloaded = getdatbytes(filename, dirname, pbdir, fmt, nsamp, startbyte)
1099-
1100-
if tsampsperframe == nsig: # No extra samples/frame
1101-
# Turn the bytes into actual samples.
1102-
# 1d array of actual samples. Fill the individual triplets.
1103-
1104-
sig = np.zeros(nsamp)
1105-
1106-
sig[0::3] = (sigbytes[0::4] >> 1)[0:len(sig[0::3])] + 128 * \
1107-
np.bitwise_and(sigbytes[1::4], 0x07)[0:len(sig[0::3])]
1108-
if len(sig > 1):
1109-
sig[1::3] = (sigbytes[2::4] >> 1)[0:len(sig[1::3])] + 128 * \
1110-
np.bitwise_and(sigbytes[3::4], 0x07)[0:len(sig[1::3])]
1111-
if len(sig > 2):
1112-
sig[2::3] = np.bitwise_and((sigbytes[1::4] >> 3), 0x1f)[0:len(
1113-
sig[2::3])] + 32 * np.bitwise_and(sigbytes[3::4] >> 3, 0x1f)[0:len(sig[2::3])]
1114-
# First signal is 7 msb of first byte and 3 lsb of second byte.
1115-
# Second signal is 7 msb of third byte and 3 lsb of forth byte
1116-
# Third signal is 5 msb of second byte and 5 msb of forth byte
1117-
1118-
if floorsamp: # Remove extra sample read
1119-
sig = sig[floorsamp:]
1120-
# Reshape into final array of samples
1121-
sig = sig.reshape(readlen, nsig)
1122-
# Convert to int64 to be able to hold -ve values
1123-
sig = sig.astype('int')
1124-
# Loaded values as unsigned. Convert to 2's complement form: values
1125-
# > 2^9-1 are negative.
1126-
sig[sig > 511] -= 1024
1127-
1128-
else: # At least one channel has multiple samples per frame. All extra samples are averaged.
1129-
# Turn the bytes into actual samples.
1130-
# 1d array of actual samples. Fill the individual triplets.
1131-
sigall = np.zeros(nsamp)
1132-
sigall[0::3] = (sigbytes[0::4] >> 1)[0:len(
1133-
sigall[0::3])] + 128 * np.bitwise_and(sigbytes[1::4], 0x07)[0:len(sigall[0::3])]
1134-
if len(sigall > 1):
1135-
sigall[1::3] = (sigbytes[2::4] >> 1)[0:len(
1136-
sigall[1::3])] + 128 * np.bitwise_and(sigbytes[3::4], 0x07)[0:len(sigall[1::3])]
1137-
if len(sigall > 2):
1138-
sigall[2::3] = np.bitwise_and((sigbytes[1::4] >> 3), 0x1f)[0:len(
1139-
sigall[2::3])] + 32 * np.bitwise_and(sigbytes[3::4] >> 3, 0x1f)[0:len(sigall[2::3])]
1140-
if floorsamp: # Remove extra sample read
1141-
sigall = sigall[floorsamp:]
1142-
# Convert to int64 to be able to hold -ve values
1143-
sigall = sigall.astype('int')
1144-
# Loaded values as unsigned. Convert to 2's complement form: values
1145-
# > 2^9-1 are negative.
1146-
sigall[sigall > 511] -= 1024
1147-
1148-
# Give the average sample in each frame for each channel
1149-
sig = np.zeros([readlen, nsig])
1150-
for ch in range(0, nsig):
1151-
if sampsperframe[ch] == 1:
1152-
sig[:, ch] = sigall[
1153-
sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
1154-
else:
1155-
for frame in range(0, sampsperframe[ch]):
1156-
sig[:, ch] += sigall[sum(([0] + sampsperframe)
1157-
[:ch + 1]) + frame::tsampsperframe]
1158-
sig = (sig / sampsperframe).astype('int')
1159-
1160-
elif fmt == '311': # Three 10 bit samples packed into 4 bytes with 2 bits discarded
1161-
1162-
# Read the bytes from the file as unsigned integer blocks
1163-
sigbytes, bytesloaded = getdatbytes(filename, dirname, pbdir, fmt, nsamp, startbyte)
1164-
1165-
if tsampsperframe == nsig: # No extra samples/frame
1166-
# Turn the bytes into actual samples.
1167-
# 1d array of actual samples. Fill the individual triplets.
1168-
sig = np.zeros(nsamp)
1169-
1170-
sig[0::3] = sigbytes[0::4][
1171-
0:len(sig[0::3])] + 256 * np.bitwise_and(sigbytes[1::4], 0x03)[0:len(sig[0::3])]
1172-
if len(sig > 1):
1173-
sig[1::3] = (sigbytes[1::4] >> 2)[0:len(sig[1::3])] + 64 * \
1174-
np.bitwise_and(sigbytes[2::4], 0x0f)[0:len(sig[1::3])]
1175-
if len(sig > 2):
1176-
sig[2::3] = (sigbytes[2::4] >> 4)[0:len(sig[2::3])] + 16 * \
1177-
np.bitwise_and(sigbytes[3::4], 0x7f)[0:len(sig[2::3])]
1178-
# First signal is first byte and 2 lsb of second byte.
1179-
# Second signal is 6 msb of second byte and 4 lsb of third byte
1180-
# Third signal is 4 msb of third byte and 6 msb of forth byte
1181-
if floorsamp: # Remove extra sample read
1182-
sig = sig[floorsamp:]
1183-
# Reshape into final array of samples
1184-
sig = sig.reshape(readlen, nsig)
1185-
# Convert to int64 to be able to hold -ve values
1186-
sig = sig.astype('int')
1187-
# Loaded values as unsigned. Convert to 2's complement form: values
1188-
# > 2^9-1 are negative.
1189-
sig[sig > 511] -= 1024
1190-
1191-
else: # At least one channel has multiple samples per frame. All extra samples are averaged.
1192-
# Turn the bytes into actual samples.
1193-
# 1d array of actual samples. Fill the individual triplets.
1194-
sigall = np.zeros(nsamp)
1195-
sigall[
1196-
0::3] = sigbytes[
1197-
0::4][
1198-
0:len(
1199-
sigall[
1200-
0::3])] + 256 * np.bitwise_and(
1201-
sigbytes[
1202-
1::4], 0x03)[
1203-
0:len(
1204-
sigall[
1205-
0::3])]
1206-
if len(sigall > 1):
1207-
sigall[1::3] = (sigbytes[1::4] >> 2)[0:len(
1208-
sigall[1::3])] + 64 * np.bitwise_and(sigbytes[2::4], 0x0f)[0:len(sigall[1::3])]
1209-
if len(sigall > 2):
1210-
sigall[2::3] = (sigbytes[2::4] >> 4)[0:len(
1211-
sigall[2::3])] + 16 * np.bitwise_and(sigbytes[3::4], 0x7f)[0:len(sigall[2::3])]
1212-
if floorsamp: # Remove extra sample read
1213-
sigall = sigall[floorsamp:]
1214-
# Convert to int64 to be able to hold -ve values
1215-
sigall = sigall.astype('int')
1216-
# Loaded values as unsigned. Convert to 2's complement form: values
1217-
# > 2^9-1 are negative.
1218-
sigall[sigall > 511] -= 1024
1219-
# Give the average sample in each frame for each channel
1220-
sig = np.zeros([readlen, nsig])
1221-
for ch in range(0, nsig):
1222-
if sampsperframe[ch] == 1:
1223-
sig[:, ch] = sigall[
1224-
sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
1225-
else:
1226-
for frame in range(0, sampsperframe[ch]):
1227-
sig[:, ch] += sigall[sum(([0] + sampsperframe)
1228-
[:ch + 1]) + frame::tsampsperframe]
1229-
sig = (sig / sampsperframe).astype('int')
1230-
1231-
else: # Simple format signals that can be loaded as they are stored.
1232-
1233-
# Read the dat file in the specified format
1234-
sigbytes, bytesloaded = getdatbytes(filename, dirname, pbdir, fmt, nsamp, startbyte)
1235-
1236-
# No extra samples/frame. Just reshape results.
1237-
if tsampsperframe == nsig:
1238-
sig = sigbytes.reshape(readlen, nsig).astype('int')
1239-
# At least one channel has multiple samples per frame. Extra samples are averaged.
1240-
else:
1241-
# Keep the first sample in each frame for each channel
1242-
sig = np.zeros([readlen, nsig])
1243-
for ch in range(0, nsig):
1244-
if sampsperframe[ch] == 1:
1245-
sig[:, ch] = sigbytes[sum(([0] + sampsperframe)[:ch + 1])::tsampsperframe]
1246-
else:
1247-
for frame in range(0, sampsperframe[ch]):
1248-
sig[:, ch] += sigbytes[sum(([0] + sampsperframe)
1249-
[:ch + 1]) + frame::tsampsperframe]
1250-
sig = (sig / sampsperframe).astype('int')
1251-
1252-
# Adjust for byte offset formats
1253-
if fmt == '80':
1254-
sig = sig - 128
1255-
elif fmt == '160':
1256-
sig = sig - 32768
1257-
1258-
return sig, bytesloaded
1259-
1260-
1261-
1262976
# Bytes required to hold each sample (including wasted space) for
1263977
# different wfdb formats
1264978
bytespersample = {'8': 1, '16': 2, '24': 3, '32': 4, '61': 2,

wfdb/records.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,11 +816,16 @@ def rdsamp(recordname, sampfrom=0, sampto=None, channels = None, physical = True
816816

817817
# Arrange/edit the object fields to reflect user channel and/or signal range input
818818
record.arrangefields(channels, expanded=False)
819+
# Obtain physical values
819820
if physical == 1:
820821
# Perform dac to get physical signal
821822
record.p_signals = record.dac(expanded=False)
822823
# Clear memory
823824
record.d_signals = None
825+
# If the frames had to be smoothed, and d_signals is desired,
826+
# the dtype must be cast back into int
827+
elif max(record.sampsperframe)>1:
828+
record.d_signals = record.d_signals.astype('int64')
824829

825830
# Return each sample of the signals with multiple samples per frame
826831
else:
@@ -830,6 +835,7 @@ def rdsamp(recordname, sampfrom=0, sampto=None, channels = None, physical = True
830835

831836
# Arrange/edit the object fields to reflect user channel and/or signal range input
832837
record.arrangefields(channels, expanded=True)
838+
# Obtain physical values
833839
if physical == 1:
834840
# Perform dac to get physical signal
835841
record.e_p_signals = record.dac(expanded=True)

0 commit comments

Comments
 (0)