def test_decode_data(bedmaster_reader: BedmasterReader): # float signal codified_data = np.repeat([[48, 46, 50], [49, 46, 50]], 5, axis=0) decoded_data = np.repeat([0.2, 1.2], 5) assert np.array_equal(bedmaster_reader.format_data(codified_data), decoded_data) # int signal codified_data = np.repeat([[51, 50], [50, 57]], 5, axis=0) decoded_data = np.repeat([32, 29], 5) assert np.array_equal(bedmaster_reader.format_data(codified_data), decoded_data) # string nan 1 and 2 codified_data = np.repeat([[48, 46, 50, 51], [49, 46, 50, 49]], 5, axis=0) codified_data[3] = [78, 111, 110, 101] decoded_data = np.repeat([0.23, 1.21], 5) decoded_data[3] = np.nan obtained = bedmaster_reader.format_data(codified_data) assert np.array_equal( obtained[~np.isnan(obtained)], decoded_data[~np.isnan(decoded_data)], ) assert np.isnan(obtained[3]) codified_data[3] = [88, 32, 32, 32] obtained = bedmaster_reader.format_data(codified_data) assert np.array_equal( obtained[~np.isnan(obtained)], decoded_data[~np.isnan(decoded_data)], ) assert np.isnan(obtained[3])
def test_list_vs(bedmaster_reader: BedmasterReader, empty_matfile: h5py.File): expected_vs = ["CO", "CUFF", "HR", "SPO2%", "SPO2R"] assert bedmaster_reader.list_vs() == expected_vs # No vs on file: empty_reader = BedmasterReader(empty_matfile.name) assert empty_reader.list_vs() == []
def test_contiguous_nparrays(bedmaster_reader: BedmasterReader): heart_rate = bedmaster_reader.get_vs("HR") if heart_rate is None: assert False ecgv = bedmaster_reader.get_wv("ch10", "V") if ecgv is None: assert False signals = [heart_rate, ecgv] for signal in signals: assert not signal.value.dtype == object assert not signal.time.dtype == object
def test_get_interbundle_correction(bedmaster_reader: BedmasterReader): art1d = bedmaster_reader.get_vs("CO") if art1d is None: assert False ch10 = bedmaster_reader.get_wv("ch10", "v") if ch10 is None: assert False no_correction = {"vs": None, "wv": None} prev_max_vs = { "segmentNo": 2, "maxTime": art1d.time[4], "signalName": "CO", } prev_max_wv = { "segmentNo": 1, "maxTime": ch10.time[14], "signalName": "ch10", } prev_max_info = {"vs": prev_max_vs, "wv": prev_max_wv} expected_vs = {"maxTime": art1d.time[3], "timeCorr": 2} expected_wv = {"maxTime": ch10.time[15], "timeCorr": -0.25} def _change_ibcor_dict(source_type, **kwargs): new_dict = prev_max_info.copy() for source in source_type: for key in kwargs: new_dict[source][key] = kwargs[key] return new_dict assert bedmaster_reader.interbundle_corr == no_correction # Normal case: bedmaster_reader.get_interbundle_correction(prev_max_info) assert bedmaster_reader.interbundle_corr["vs"] == expected_vs assert bedmaster_reader.interbundle_corr["wv"] == expected_wv # Case: signal does not exist on current bundle previous = _change_ibcor_dict(["vs", "wv"], signalName="Random") bedmaster_reader.get_interbundle_correction(previous) assert bedmaster_reader.interbundle_corr == no_correction # Case: no overlap between previous and current bundle previous = _change_ibcor_dict(["vs", "wv"], segmentNo=-1) bedmaster_reader.get_interbundle_correction(previous) assert bedmaster_reader.interbundle_corr == no_correction # Case: complete overlap between previous and current previous = _change_ibcor_dict(["vs", "wv"], segmentNo=100) bedmaster_reader.get_interbundle_correction(previous) assert bedmaster_reader.interbundle_corr == no_correction
def test_list_wv(bedmaster_reader: BedmasterReader, empty_matfile: h5py.File): expected_dict = { "I": "ch7", "II": "ch8", "III": "ch9", "V": "ch10", "SPO2": "ch39", "RESP": "ch40", } assert bedmaster_reader.list_wv() == expected_dict # No wv on file: empty_reader = BedmasterReader(empty_matfile.name) assert empty_reader.list_vs() == []
def test_get_vs(bedmaster_reader: BedmasterReader, matfile: h5py.File): def _linearize(arr): return np.transpose(arr)[0] # Standard case heart_rate = bedmaster_reader.get_vs("HR") if heart_rate is None: assert False assert heart_rate.name == "HR" assert np.array_equal(heart_rate.value, _linearize(matfile["vs/HR"][()])) assert np.array_equal( heart_rate.time, _linearize(matfile["vs_time_corrected/HR/res_vs"][()]), ) assert heart_rate.scale_factor == 0.5 assert heart_rate.units == "Bpm" assert heart_rate.sample_freq == np.array([(0.5, 0)], dtype="float,int") # Check that dataevents are collected time_corr_arr = np.unpackbits(heart_rate.time_corr_arr, axis=None) irregularities = np.where(time_corr_arr)[0] expected_irr_idx = np.array([2, 3, 11]) assert np.array_equal(irregularities, expected_irr_idx) # Check that interbundle correction is applied bedmaster_reader.interbundle_corr["vs"] = { "maxTime": heart_rate.time[10], "timeCorr": 3, } heart_rate_corr = bedmaster_reader.get_vs("HR") if heart_rate_corr is None: assert False assert len(heart_rate_corr.time) == len(heart_rate.time) - 11 assert len(heart_rate_corr.value) == len(heart_rate.value) - 11 # Case with unknown scale factor and unit spo2r = bedmaster_reader.get_vs("SPO2R") if spo2r is None: assert False assert spo2r.scale_factor == 1 assert spo2r.units == "UNKNOWN" assert spo2r.sample_freq == np.array([(0.5, 0)], dtype="float,int")
def test_format_data(bedmaster_reader: BedmasterReader): expected_data = np.arange(10) # Case column vector [[0], [1]] -> [0,1] unformatted_data = np.transpose([expected_data]) assert np.array_equal(bedmaster_reader.format_data(unformatted_data), expected_data) # Case single-row 2D vector [[0,1]] -> [0,1] unformatted_data = np.array([expected_data]) assert np.array_equal(bedmaster_reader.format_data(unformatted_data), expected_data) # Case column matrix input_2d_data = np.repeat([[48, 46, 50], [49, 46, 50]], 5, axis=0) formatted_data = np.repeat([0.2, 1.2], 5) assert np.array_equal(bedmaster_reader.format_data(input_2d_data), formatted_data) # Case row matrix input_2d_data = np.transpose(input_2d_data) formatted_data = np.repeat([0.2, 1.2], 5) assert np.array_equal(bedmaster_reader.format_data(input_2d_data), formatted_data)
def test_apply_interbundle_correction(bedmaster_reader: BedmasterReader): def _create_ib_corr_dict(signal: BedmasterSignal, cut_idx: int, time_corr: int): source_corr = { "maxTime": signal.time[cut_idx], "timeCorr": time_corr, } return source_corr def _apply_and_assert_ib(signal: Optional[BedmasterSignal], sig_type: str): if signal is None: assert False signal.time_corr_arr = np.unpackbits(signal.time_corr_arr) signal_original = copy.deepcopy(signal) bedmaster_reader.interbundle_corr[sig_type] = _create_ib_corr_dict( signal, cut_idx[sig_type], time_corr[sig_type], ) bedmaster_reader.apply_ibcorr(signal) _assert_ib_correction( signal_original, signal, cut_idx[sig_type], time_corr[sig_type], ) bedmaster_reader.interbundle_corr[sig_type] = None cut_idx = {"wv": 10, "vs": 4} time_corr = {"wv": 5, "vs": 3} # Standard case ecgi = bedmaster_reader.get_wv("ch7", "I") _apply_and_assert_ib(ecgi, "wv") cuff = bedmaster_reader.get_vs("CUFF") _apply_and_assert_ib(cuff, "vs") # With DE ecgv = bedmaster_reader.get_wv("ch10", "V") _apply_and_assert_ib(ecgv, "wv") hr = bedmaster_reader.get_vs("HR") _apply_and_assert_ib(hr, "vs") # With missing values ecgiii = bedmaster_reader.get_wv("ch9", "prova") _apply_and_assert_ib(ecgiii, "wv") # Multiple sf ecgii = bedmaster_reader.get_wv("ch8", "II") _apply_and_assert_ib(ecgii, "wv")
def _write_bedmaster_data( bedmaster_files: List[str], writer: Writer, scaling_and_units: Dict, ): all_files = True previous_max = None untensorized_files: Dict[str, List[str]] = {"file": [], "error": []} for bedmaster_file in bedmaster_files: try: with BedmasterReader(bedmaster_file, scaling_and_units) as reader: if previous_max: reader.get_interbundle_correction(previous_max) # These blocks can be easily parallelized with MPI: # >>> rank = MPI.COMM_WORLD.rank # >>> if rank == 1: vs_signals = reader.list_vs() for vs_signal_name in vs_signals: vs_signal = reader.get_vs(vs_signal_name) if vs_signal: writer.write_signal(vs_signal) # >>> if rank == 2 wv_signals = reader.list_wv() for wv_signal_name, channel in wv_signals.items(): wv_signal = reader.get_wv(channel, wv_signal_name) if wv_signal: writer.write_signal(wv_signal) previous_max = reader.max_segment except Exception as error: untensorized_files["file"].append(bedmaster_file) untensorized_files["error"].append(repr(error)) if len(untensorized_files["file"]) > 0: all_files = False return all_files, untensorized_files
def test_max_segment(bedmaster_reader: BedmasterReader): def _create_max_seg_dict(seg_no, max_time, signal_name): return { "segmentNo": seg_no, "maxTime": max_time, "signalName": signal_name, } empty_vs_dict = _create_max_seg_dict(0, -1, "") empty_wv_dict = _create_max_seg_dict(0, -1, "") expected_wv_max = _create_max_seg_dict( seg_no=6, max_time=1452438403.75, signal_name="ch10", ) expected_vs_max = _create_max_seg_dict( seg_no=6, max_time=1452438402.0, signal_name="CO", ) assert bedmaster_reader.max_segment["vs"] == empty_vs_dict assert bedmaster_reader.max_segment["wv"] == empty_wv_dict wv_signals = bedmaster_reader.list_wv() for wv_signal_name, channel in wv_signals.items(): bedmaster_reader.get_wv(channel, wv_signal_name) assert bedmaster_reader.max_segment["vs"] == empty_vs_dict assert bedmaster_reader.max_segment["wv"] == expected_wv_max vs_signals = bedmaster_reader.list_vs() for vs_signal_name in vs_signals: bedmaster_reader.get_vs(vs_signal_name) assert bedmaster_reader.max_segment["vs"] == expected_vs_max assert bedmaster_reader.max_segment["wv"] == expected_wv_max
def test_get_wv(bedmaster_reader: BedmasterReader, matfile: h5py.File): def linearize(arr): return np.transpose(arr)[0] # Check standard case ecgv = bedmaster_reader.get_wv("ch10", "V") if ecgv is None: assert False assert ecgv.name == "V" assert np.array_equal(ecgv.value, linearize(matfile["wv/ch10"][()])) assert np.array_equal( ecgv.time, linearize(matfile["wv_time_corrected/ch10/res_wv"][()]), ) assert ecgv.units == "mV" assert ecgv.scale_factor == 0.0243 assert np.array_equal(ecgv.sample_freq, np.array([(240, 0)], dtype="float,int")) # Check that it works without specifying signal name ecgv_copy = bedmaster_reader.get_wv("ch10") if ecgv_copy is None: assert False assert ecgv_copy.name == ecgv.name assert np.array_equal(ecgv_copy.value, ecgv.value) # Check dataevents are collected time_corr_arr = np.unpackbits(ecgv.time_corr_arr, axis=None) irregularities = np.where(time_corr_arr)[0] expected_irr_idx = np.array([3, 4, 20, 32, 40, 50, 54]) assert np.array_equal(irregularities, expected_irr_idx) # Case with multiple sample frequency ecg2 = bedmaster_reader.get_wv("ch8", "II") if ecg2 is None: assert False assert np.array_equal( ecg2.sample_freq, np.array([(240, 0), (120, 80)], dtype="float,int"), ) # Check that interbundle correction is applied overlap = 5 bedmaster_reader.interbundle_corr["wv"] = { "maxTime": ecgv.time[overlap - 1], "timeCorr": 8, } ecg2_corr = bedmaster_reader.get_wv("ch8", "II") if ecg2_corr is None: assert False values_cut = overlap * ecg2_corr.sample_freq[0][0] / 4 assert len(ecg2_corr.time) == len(ecgv.time) - overlap assert len(ecg2_corr.value) == len(ecgv.value) - values_cut assert np.array_equal( ecg2_corr.sample_freq, np.array([(240, 0), (120, 75)], dtype="float,int"), ) # Case with unknown scale factor and unit ecg3 = bedmaster_reader.get_wv("ch9", "III") if ecg3 is None: assert False assert ecg3.units == "??V" assert ecg3.scale_factor == 2.44 assert np.array_equal(ecg3.sample_freq, np.array([(240, 0)], dtype="float,int"))
def bedmaster_reader( test_scale_units: Dict[str, Dict[str, Union[int, float, str]]], ) -> Iterator[BedmasterReader]: with h5py.File(pytest.mat_file, "r") as mat_file: reader = BedmasterReader(mat_file.filename, test_scale_units) yield reader