def calculate_hrv_features(rri, f=360): """ Calculate features for detecting sleep apnea The features contain statistical measures, morphology and periodogram of the ECG signal. Parameters ---------- RR_int: array_like Array containing RR intervals f: float, optional Number corresponding to the sampling frequency of the input signal, must be in Hertz Returns ------- X: array_like Features """ result_td = np.reshape(np.asarray(list(time_domain(rri).values())), (1, 6)) result_fd = np.reshape(np.asarray(list(frequency_domain(rri).values())), (1, 7)) result_nl = np.reshape(np.asarray(list(non_linear(rri).values())), (1, 2)) hrv_features = np.concatenate([result_td, result_fd, result_nl], axis=1) return hrv_features
def feature_extraction(recording, signal, labels): data = [] for i in tqdm(range(len(labels)), desc=recording, file=sys.stdout): segment = signal[i * fs * 60:(i + 1) * fs * 60] segment, _, _ = st.filter_signal(segment, ftype='FIR', band='bandpass', order=int(0.3 * fs), frequency=[3, 45], sampling_rate=fs) # Finding R peaks rpeaks, = hamilton_segmenter(segment, sampling_rate=fs) rpeaks, = correct_rpeaks(segment, rpeaks, sampling_rate=fs, tol=0.1) # Extracting feature label = 0 if labels[i] == "N" else 1 if 40 <= len(rpeaks) <= 200: # Remove abnormal R peaks rri_tm, rri = rpeaks[1:] / float(fs), np.diff(rpeaks, axis=-1) / float(fs) rri = medfilt(rri, kernel_size=3) edr_tm, edr = rpeaks / float(fs), segment[rpeaks] # Remove physiologically impossible HR signal if np.all(np.logical_and(60 / rri >= hr_min, 60 / rri <= hr_max)): rri_time_features, rri_frequency_features = time_domain( rri * 1000), frequency_domain(rri, rri_tm) edr_frequency_features = frequency_domain(edr, edr_tm) # 6 + 6 + 6 + 1 = 19 data.append([ rri_time_features["rmssd"], rri_time_features["sdnn"], rri_time_features["nn50"], rri_time_features["pnn50"], rri_time_features["mrri"], rri_time_features["mhr"], rri_frequency_features["vlf"] / rri_frequency_features["total_power"], rri_frequency_features["lf"] / rri_frequency_features["total_power"], rri_frequency_features["hf"] / rri_frequency_features["total_power"], rri_frequency_features["lf_hf"], rri_frequency_features["lfnu"], rri_frequency_features["hfnu"], edr_frequency_features["vlf"] / edr_frequency_features["total_power"], edr_frequency_features["lf"] / edr_frequency_features["total_power"], edr_frequency_features["hf"] / edr_frequency_features["total_power"], edr_frequency_features["lf_hf"], edr_frequency_features["lfnu"], edr_frequency_features["hfnu"], label ]) else: data.append([np.nan] * 18 + [label]) else: data.append([np.nan] * 18 + [label]) data = np.array(data, dtype="float") return data
def test_correct_response_with_rri_in_seconds(self): response = time_domain(np.array(FAKE_RRI) / 1000) expected = {'rmssd': 38.07, 'sdnn': 29.82, 'nn50': 1, 'pnn50': 25, 'mrri': 793.75, 'mhr': 75.67} np.testing.assert_almost_equal(sorted(response.values()), sorted(expected.values()), decimal=2)
def test_correct_response(self): response = time_domain(FAKE_RRI) expected = {'rmssd': 38.07, 'sdnn': 29.82, 'nn50': 1, 'pnn50': 25, 'mrri': 793.75, 'mhr': 75.67} np.testing.assert_almost_equal(sorted(response.values()), sorted(expected.values()), decimal=2) self.assertEqual(response.keys(), expected.keys())
def test_correct_response_with_rri_in_seconds(self): response = time_domain(np.array(FAKE_RRI) / 1000) expected = { "rmssd": 38.07, "sdnn": 29.82, "sdsd": 41.93, "nn50": 1, "pnn50": 25, "mrri": 793.75, "mhr": 75.67, } np.testing.assert_almost_equal(sorted(response.values()), sorted(expected.values()), decimal=2)
def test_correct_response(self): response = time_domain(FAKE_RRI) expected = { "rmssd": 38.07, "sdnn": 29.82, "sdsd": 41.93, "nn50": 1, "pnn50": 25, "mrri": 793.75, "mhr": 75.67, } np.testing.assert_almost_equal(sorted(response.values()), sorted(expected.values()), decimal=2) self.assertEqual(response.keys(), expected.keys())
def get_hrv(rr_interval): """Get three domain heart rate variability. Get time domain, frequency domain, and non-linear domain heart rate variability. Args: rr_interval: narray, RR-interval. Returns: A dictionary representation of the three domain HRV. Notes: *Authors* - the hrv dev team (https://github.com/rhenanbartels/hrv) *Dependencies* - hrv - numpy *See Also* - hrv: https://github.com/rhenanbartels/hrv """ if np.median(rr_interval) < 1: rr_interval *= 1000 time_domain_analysis = time_domain(rr_interval) frequency_domain_analysis = frequency_domain(rri=rr_interval, fs=4.0, method='welch', interp_method='cubic', detrend='linear') non_linear_domain_analysis = non_linear(rr_interval) hrv_info = { 'time': time_domain_analysis, 'frequency': frequency_domain_analysis, 'non-linear': non_linear_domain_analysis } return hrv_info
from hrv.filters import moving_median import numpy as np # def _moving_function(rri, order, func): # offset = int(order / 2) # filt_rri = np.array(rri.copy(), dtype=np.float64) # for i in range(offset, len(rri) - offset, 1): # filt_rri[i] = func(rri[i-offset:i+offset+1]) # return filt_rri # def moving_median(rri, order=3): # return _moving_function(rri, order, np.median) rri = open_rri('./data/test/extracted/Iris_kangxi_peyin_RRI.txt') filt_rri = moving_median(rri, order=3) results = time_domain(filt_rri) print(results) results = frequency_domain(rri=filt_rri, fs=4.0, method='welch', interp_method='cubic', detrend='linear') print(results) results = non_linear(filt_rri) print(results)
# change it depending on which one you want output specifier = 'td' # this script is GENERAL purpose. you need to change some of these to match the filenames for i in range(1, 55): # change range filename_header = 'nsr' + str(i).zfill(3) # change name possibly filename = filename_header + 'rri.txt' classifier = '' try: rri = open_rri(filename) except: continue if specifier == 'td': results = time_domain(rri) # output is dict elif specifier == 'nl': results = non_linear(rri) else: print("Invalid argument!") output_csv_name = filename_header + 'hrv_' + specifier + '.csv' with open(output_csv_name, 'wb') as f: # Just use 'w' mode in 3.x w = csv.DictWriter(f, results.keys()) w.writeheader() w.writerow(results) print(filename_header + ' rri file has been processed') """ print(results) print(type(results)) """