@@ -865,7 +865,7 @@ def smooth_frames(self, sigtype='physical'):
865
865
866
866
867
867
def _rd_segment (file_name , dir_name , pn_dir , fmt , n_sig , sig_len , byte_offset ,
868
- samps_per_frame , skew , sampfrom , sampto , channels ,
868
+ samps_per_frame , skew , init_value , sampfrom , sampto , channels ,
869
869
smooth_frames , ignore_skew , no_file = False , sig_data = None , return_res = 64 ):
870
870
"""
871
871
Read the digital samples from a single segment record's associated
@@ -893,6 +893,8 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
893
893
The samples/frame for each signal of the dat file.
894
894
skew : list
895
895
The skew for the signals of the dat file.
896
+ init_value : list
897
+ The initial value for each signal of the dat file.
896
898
sampfrom : int
897
899
The starting sample number to be read from the signals.
898
900
sampto : int
@@ -939,6 +941,7 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
939
941
byte_offset = byte_offset [:]
940
942
samps_per_frame = samps_per_frame [:]
941
943
skew = skew [:]
944
+ init_value = init_value [:]
942
945
943
946
# Set defaults for empty fields
944
947
for i in range (n_sig ):
@@ -948,6 +951,8 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
948
951
samps_per_frame [i ] = 1
949
952
if skew [i ] == None :
950
953
skew [i ] = 0
954
+ if init_value [i ] == None :
955
+ init_value [i ] = 0
951
956
952
957
# If skew is to be ignored, set all to 0
953
958
if ignore_skew :
@@ -964,6 +969,7 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
964
969
w_byte_offset = {} # one scalar per dat file
965
970
w_samps_per_frame = {} # one list per dat file
966
971
w_skew = {} # one list per dat file
972
+ w_init_value = {} # one list per dat file
967
973
w_channel = {} # one list per dat file
968
974
969
975
for fn in file_name :
@@ -977,6 +983,7 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
977
983
w_byte_offset [fn ] = byte_offset [datchannel [fn ][0 ]]
978
984
w_samps_per_frame [fn ] = [samps_per_frame [c ] for c in datchannel [fn ]]
979
985
w_skew [fn ] = [skew [c ] for c in datchannel [fn ]]
986
+ w_init_value [fn ] = [init_value [c ] for c in datchannel [fn ]]
980
987
w_channel [fn ] = idc
981
988
982
989
# Wanted dat channels, relative to the dat file itself
@@ -997,17 +1004,23 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
997
1004
998
1005
# Read each wanted dat file and store signals
999
1006
for fn in w_file_name :
1000
- if no_file :
1001
- signals [:, out_dat_channel [fn ]] = _rd_dat_signals (fn , dir_name ,
1002
- pn_dir , w_fmt [fn ], len (datchannel [fn ]), sig_len ,
1003
- w_byte_offset [fn ], w_samps_per_frame [fn ], w_skew [fn ],
1004
- sampfrom , sampto , smooth_frames , no_file = True ,
1005
- sig_data = sig_data )[:, r_w_channel [fn ]]
1006
- else :
1007
- signals [:, out_dat_channel [fn ]] = _rd_dat_signals (fn , dir_name ,
1008
- pn_dir , w_fmt [fn ], len (datchannel [fn ]), sig_len ,
1009
- w_byte_offset [fn ], w_samps_per_frame [fn ], w_skew [fn ],
1010
- sampfrom , sampto , smooth_frames )[:, r_w_channel [fn ]]
1007
+ datsignals = _rd_dat_signals (
1008
+ file_name = fn ,
1009
+ dir_name = dir_name ,
1010
+ pn_dir = pn_dir ,
1011
+ fmt = w_fmt [fn ],
1012
+ n_sig = len (datchannel [fn ]),
1013
+ sig_len = sig_len ,
1014
+ byte_offset = w_byte_offset [fn ],
1015
+ samps_per_frame = w_samps_per_frame [fn ],
1016
+ skew = w_skew [fn ],
1017
+ init_value = w_init_value [fn ],
1018
+ sampfrom = sampfrom ,
1019
+ sampto = sampto ,
1020
+ smooth_frames = smooth_frames ,
1021
+ no_file = no_file ,
1022
+ sig_data = sig_data )
1023
+ signals [:, out_dat_channel [fn ]] = datsignals [:, r_w_channel [fn ]]
1011
1024
1012
1025
# Return each sample in signals with multiple samples/frame, without smoothing.
1013
1026
# Return a list of numpy arrays for each signal.
@@ -1016,16 +1029,22 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
1016
1029
1017
1030
for fn in w_file_name :
1018
1031
# Get the list of all signals contained in the dat file
1019
- if no_file :
1020
- datsignals = _rd_dat_signals (fn , dir_name , pn_dir , w_fmt [fn ],
1021
- len (datchannel [fn ]), sig_len , w_byte_offset [fn ],
1022
- w_samps_per_frame [fn ], w_skew [fn ], sampfrom , sampto ,
1023
- smooth_frames , no_file = True , sig_data = sig_data )
1024
- else :
1025
- datsignals = _rd_dat_signals (fn , dir_name , pn_dir , w_fmt [fn ],
1026
- len (datchannel [fn ]), sig_len , w_byte_offset [fn ],
1027
- w_samps_per_frame [fn ], w_skew [fn ], sampfrom , sampto ,
1028
- smooth_frames )
1032
+ datsignals = _rd_dat_signals (
1033
+ file_name = fn ,
1034
+ dir_name = dir_name ,
1035
+ pn_dir = pn_dir ,
1036
+ fmt = w_fmt [fn ],
1037
+ n_sig = len (datchannel [fn ]),
1038
+ sig_len = sig_len ,
1039
+ byte_offset = w_byte_offset [fn ],
1040
+ samps_per_frame = w_samps_per_frame [fn ],
1041
+ skew = w_skew [fn ],
1042
+ init_value = w_init_value [fn ],
1043
+ sampfrom = sampfrom ,
1044
+ sampto = sampto ,
1045
+ smooth_frames = smooth_frames ,
1046
+ no_file = no_file ,
1047
+ sig_data = sig_data )
1029
1048
1030
1049
# Copy over the wanted signals
1031
1050
for cn in range (len (out_dat_channel [fn ])):
@@ -1035,8 +1054,9 @@ def _rd_segment(file_name, dir_name, pn_dir, fmt, n_sig, sig_len, byte_offset,
1035
1054
1036
1055
1037
1056
def _rd_dat_signals (file_name , dir_name , pn_dir , fmt , n_sig , sig_len ,
1038
- byte_offset , samps_per_frame , skew , sampfrom , sampto ,
1039
- smooth_frames , no_file = False , sig_data = None ):
1057
+ byte_offset , samps_per_frame , skew , init_value ,
1058
+ sampfrom , sampto , smooth_frames ,
1059
+ no_file = False , sig_data = None ):
1040
1060
"""
1041
1061
Read all signals from a WFDB dat file.
1042
1062
@@ -1062,6 +1082,8 @@ def _rd_dat_signals(file_name, dir_name, pn_dir, fmt, n_sig, sig_len,
1062
1082
The samples/frame for each signal of the dat file.
1063
1083
skew : list
1064
1084
The skew for the signals of the dat file.
1085
+ init_value : list
1086
+ The initial value for each signal of the dat file.
1065
1087
sampfrom : int
1066
1088
The starting sample number to be read from the signals.
1067
1089
sampto : int
@@ -1160,6 +1182,32 @@ def _rd_dat_signals(file_name, dir_name, pn_dir, fmt, n_sig, sig_len,
1160
1182
elif fmt == '160' :
1161
1183
sig_data = (sig_data .astype ('int32' ) - 32768 ).astype ('int16' )
1162
1184
1185
+ # For format 8, convert sample differences to absolute samples. Note
1186
+ # that if sampfrom is not 0, the results will be wrong, since we can't
1187
+ # know the starting value without reading the entire record from the
1188
+ # beginning - an inherent limitation of the format, and the use of
1189
+ # format 8 is discouraged for this reason! However, the following is
1190
+ # consistent with the behavior of the WFDB library: the initial value
1191
+ # specified by the header file is used as the starting sample value,
1192
+ # regardless of where in the record we begin reading. Therefore, the
1193
+ # following should give the same results as rdsamp.
1194
+ if fmt == '8' :
1195
+ dif_frames = sig_data .reshape (- 1 , tsamps_per_frame )
1196
+ abs_frames = np .empty (dif_frames .shape , dtype = 'int32' )
1197
+ ch_start = 0
1198
+ for ch in range (n_sig ):
1199
+ ch_end = ch_start + samps_per_frame [ch ]
1200
+ # Extract sample differences as a 2D array
1201
+ ch_dif_signal = dif_frames [:, ch_start :ch_end ]
1202
+ # Convert to a 1D array of absolute samples
1203
+ ch_abs_signal = ch_dif_signal .cumsum (dtype = abs_frames .dtype )
1204
+ ch_abs_signal += init_value [ch ]
1205
+ # Transfer to the output array
1206
+ ch_abs_signal = ch_abs_signal .reshape (ch_dif_signal .shape )
1207
+ abs_frames [:, ch_start :ch_end ] = ch_abs_signal
1208
+ ch_start = ch_end
1209
+ sig_data = abs_frames .reshape (- 1 )
1210
+
1163
1211
# At this point, dtype of sig_data is the minimum integer format
1164
1212
# required for storing the final digital samples.
1165
1213
@@ -1472,14 +1520,6 @@ def _blocks_to_samples(sig_data, n_samp, fmt):
1472
1520
sig [sig > 2047 ] -= 4096
1473
1521
1474
1522
elif fmt == '310' :
1475
- # Easier to process when dealing with whole blocks
1476
- if n_samp % 3 :
1477
- n_samp = upround (n_samp ,3 )
1478
- added_samps = n_samp % 3
1479
- sig_data = np .append (sig_data , np .zeros (added_samps , dtype = 'uint8' ))
1480
- else :
1481
- added_samps = 0
1482
-
1483
1523
sig_data = sig_data .astype ('int16' )
1484
1524
sig = np .zeros (n_samp , dtype = 'int16' )
1485
1525
@@ -1491,24 +1531,11 @@ def _blocks_to_samples(sig_data, n_samp, fmt):
1491
1531
# Third signal is 5 msb of second byte and 5 msb of forth byte
1492
1532
sig [2 ::3 ] = np .bitwise_and ((sig_data [1 ::4 ] >> 3 ), 0x1f )[0 :len (sig [2 ::3 ])] + 32 * np .bitwise_and (sig_data [3 ::4 ] >> 3 , 0x1f )[0 :len (sig [2 ::3 ])]
1493
1533
1494
- # Remove trailing samples read within the byte block if
1495
- # originally not 3n sampled
1496
- if added_samps :
1497
- sig = sig [:- added_samps ]
1498
-
1499
1534
# Loaded values as un_signed. Convert to 2's complement form:
1500
1535
# values > 2^9-1 are negative.
1501
1536
sig [sig > 511 ] -= 1024
1502
1537
1503
1538
elif fmt == '311' :
1504
- # Easier to process when dealing with whole blocks
1505
- if n_samp % 3 :
1506
- n_samp = upround (n_samp ,3 )
1507
- added_samps = n_samp % 3
1508
- sig_data = np .append (sig_data , np .zeros (added_samps , dtype = 'uint8' ))
1509
- else :
1510
- added_samps = 0
1511
-
1512
1539
sig_data = sig_data .astype ('int16' )
1513
1540
sig = np .zeros (n_samp , dtype = 'int16' )
1514
1541
@@ -1520,11 +1547,6 @@ def _blocks_to_samples(sig_data, n_samp, fmt):
1520
1547
# Third sample is 4 msb of third byte and 6 msb of forth byte
1521
1548
sig [2 ::3 ] = (sig_data [2 ::4 ] >> 4 )[0 :len (sig [2 ::3 ])] + 16 * np .bitwise_and (sig_data [3 ::4 ], 0x7f )[0 :len (sig [2 ::3 ])]
1522
1549
1523
- # Remove trailing samples read within the byte block if
1524
- # originally not 3n sampled
1525
- if added_samps :
1526
- sig = sig [:- added_samps ]
1527
-
1528
1550
# Loaded values as un_signed. Convert to 2's complement form.
1529
1551
# Values > 2^9-1 are negative.
1530
1552
sig [sig > 511 ] -= 1024
0 commit comments