Skip to content

Commit 5caa60b

Browse files
author
Benjamin Moody
committed
TestSignal: Test physical-to-digital conversion.
When converting physical to digital values, the input values are floating-point and therefore may have rounding errors. We want to ensure that the package rounds each value to the nearest integer, in order to avoid adding a bias towards zero. This test case tests all four code paths in Record.adc, and also checks that the high-level wfdb.wrsamp function works correctly for a round trip from physical to digital to physical. Note that wrsamp currently doesn't support expanded/multi-frequency data, so that is not tested.
1 parent 6db09b6 commit 5caa60b

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

tests/test_record.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,90 @@ def test_infer_sig_len(self):
971971

972972
assert record_2.__eq__(record)
973973

974+
def test_physical_conversion(self):
975+
n_sig = 3
976+
adc_gain = [1.0, 1234.567, 765.4321]
977+
baseline = [10, 20, -30]
978+
d_signal = np.repeat(np.arange(-100, 100), 3).reshape(-1, 3)
979+
e_d_signal = list(d_signal.transpose())
980+
fmt = ["16", "16", "16"]
981+
982+
# Test adding or subtracting a small offset (0.01 ADU) to check
983+
# that we correctly round to the nearest integer
984+
for offset in (0, -0.01, 0.01):
985+
p_signal = (d_signal + offset - baseline) / adc_gain
986+
e_p_signal = list(p_signal.transpose())
987+
988+
# Test converting p_signal to d_signal
989+
990+
record = wfdb.Record(
991+
n_sig=n_sig,
992+
p_signal=p_signal.copy(),
993+
adc_gain=adc_gain,
994+
baseline=baseline,
995+
fmt=fmt,
996+
)
997+
998+
d_signal_converted = record.adc(expanded=False, inplace=False)
999+
np.testing.assert_array_equal(d_signal_converted, d_signal)
1000+
1001+
record.adc(expanded=False, inplace=True)
1002+
np.testing.assert_array_equal(record.d_signal, d_signal)
1003+
1004+
# Test converting e_p_signal to e_d_signal
1005+
1006+
record = wfdb.Record(
1007+
n_sig=n_sig,
1008+
e_p_signal=[s.copy() for s in e_p_signal],
1009+
adc_gain=adc_gain,
1010+
baseline=baseline,
1011+
fmt=fmt,
1012+
)
1013+
1014+
e_d_signal_converted = record.adc(expanded=True, inplace=False)
1015+
self.assertEqual(len(e_d_signal_converted), n_sig)
1016+
for x, y in zip(e_d_signal_converted, e_d_signal):
1017+
np.testing.assert_array_equal(x, y)
1018+
1019+
record.adc(expanded=True, inplace=True)
1020+
self.assertEqual(len(record.e_d_signal), n_sig)
1021+
for x, y in zip(record.e_d_signal, e_d_signal):
1022+
np.testing.assert_array_equal(x, y)
1023+
1024+
# Test automatic conversion using wfdb.wrsamp()
1025+
1026+
wfdb.wrsamp(
1027+
"test_physical_conversion",
1028+
fs=1000,
1029+
sig_name=["X", "Y", "Z"],
1030+
units=["mV", "mV", "mV"],
1031+
p_signal=p_signal,
1032+
adc_gain=adc_gain,
1033+
baseline=baseline,
1034+
fmt=["16", "16", "16"],
1035+
)
1036+
record = wfdb.rdrecord("test_physical_conversion", physical=False)
1037+
np.testing.assert_array_equal(record.d_signal, d_signal)
1038+
1039+
record = wfdb.rdrecord("test_physical_conversion", physical=True)
1040+
for ch, gain in enumerate(adc_gain):
1041+
np.testing.assert_allclose(
1042+
record.p_signal[:, ch],
1043+
p_signal[:, ch],
1044+
rtol=0.0000001,
1045+
atol=(0.05 / gain),
1046+
)
1047+
1048+
@classmethod
1049+
def tearDownClass(cls):
1050+
writefiles = [
1051+
"test_physical_conversion.dat",
1052+
"test_physical_conversion.hea",
1053+
]
1054+
for file in writefiles:
1055+
if os.path.isfile(file):
1056+
os.remove(file)
1057+
9741058

9751059
class TestDownload(unittest.TestCase):
9761060
# Test that we can download records with no "dat" file

0 commit comments

Comments
 (0)