Esempio n. 1
0
def calc_metrics(rrs):
    buf_duration_scnds = 300
    tacho_buf_dur = 300
    min_rr = 0.3
    max_rr = 1.7
    sp_skip = 10
    buf_size = int(max(buf_duration_scnds, tacho_buf_dur) / min_rr) + 1

    buf = Buffer(buf_size)
    print "[+] Calculating all usefull metrics: "
    si = SI(buf, buf_duration_scnds, min_rr, max_rr)
    sis = np.zeros(len(rrs))  # stress indices
    shs = np.zeros(
        (len(si.get_histogram()), len(rrs) / sp_skip + 1))  # stress histograms
    si_ready = 0

    sp = RRTachogrammEnergySpectrum(buf, tacho_buf_dur, min_rr, max_rr)
    sp_ready = 0
    sps = np.zeros((len(sp.get_spectrum()), len(rrs) / sp_skip + 1))
    ics = np.zeros(len(rrs))
    iscas = np.zeros(len(rrs))
    vbs = np.zeros(len(rrs))

    hrvs = np.zeros(len(rrs))
    cnt = -1
    ls = len(rrs)
    md = ls / 10
    for r in rrs:
        if cnt % md == 0:
            print "[+] Done {0:.2f}%".format(float(100 * cnt) / ls)
        cnt += 1
        si.update(r)
        sp.update(r)
        buf.add_sample(r)
        # ## Calculating stress indices
        si.calc_si()
        if si.is_ready():
            si_ready += 1
            sis[cnt] = si.get_stress()
            if cnt % sp_skip == 0:
                shs[:, cnt / sp_skip] = si.get_histogram()
        # ## Calculating RR-Tachogram spectrums
        if sp.is_ready():
            sp.calc_energy_spectrum()
            if cnt % sp_skip == 0:
                sps[:, cnt / sp_skip] = sp.get_spectrum()
            ics[cnt] = sp.get_IC()
            iscas[cnt] = sp.get_ISCA()
            vbs[cnt] = sp.get_vegetative_balance()
            sp_ready += 1
        # ## Fulfil heart rate buffer
    print "[+] Calculation finnished: SI ready " + "{0:.2f}%".format(
        float(si_ready * 100) / cnt) + " SP ready: {0:.2f}%".format(
            float(sp_ready * 100) / cnt)
    return sis, shs, sps, ics, iscas, vbs
Esempio n. 2
0
class RRTachogrammEnergySpectrum:
    def __init__(self, buf, buf_duration_scnds=300, min_rr=0.3, max_rr=1.71):

        self.time_span = TimeSpanBuffer(
            buf, buf_duration_scnds)  # remembers last 300 sec
        buf_size = int(buf_duration_scnds / min_rr) + 1
        # energy spectrum
        self.cum_times_buf = Buffer(buf_size)
        self.time_step = 1.0 / 67  #min_rr
        self.spectr_intervals_cnt = int(
            buf_duration_scnds /
            self.time_step)  # assume 1 heart beat per second
        self.freqs = np.fft.fftfreq(self.spectr_intervals_cnt, self.time_step)
        idx = np.argsort(self.freqs)
        self.idx = [i for i in idx if 0.0 <= self.freqs[i] < 0.5]
        self.last_spectrum = np.zeros(len(self.idx), dtype=float)
        self._wnd = np.hamming(self.spectr_intervals_cnt)
        self.may_calc = 1.0 - max_rr / buf_duration_scnds  # when 90% of RR times collected in buffer - may start calculations

    def _get_section_params(self, ps):
        return np.sum(ps), np.max(ps)

    def get_total_power(self):
        return self._get_section_params(self.last_spectrum)

    def get_hf_power(self):
        ids = [i for i in self.idx if 0.15 <= self.freqs[i] < 0.4]
        return self._get_section_params(self.last_spectrum[ids])

    def get_lf_power(self):
        ids = [i for i in self.idx if 0.04 <= self.freqs[i] < 0.15]
        return self._get_section_params(self.last_spectrum[ids])

    def get_vlf_power(self):
        ids = [i for i in self.idx if 0.015 <= self.freqs[i] < 0.04]
        return self._get_section_params(self.last_spectrum[ids])

    def get_ulf_power(self):
        ids = [i for i in self.idx if 0.0 <= self.freqs[i] < 0.015]
        return self._get_section_params(self.last_spectrum[ids])

    def get_IC(self):
        """
        Index of Centralization -IC (Index of centralization, IC = (VLF +LF / HF)
        IC reflects a degree of prevalence of non-respiratory sinus arrhythmia over the respiratory one.
        Actually - this is quantitative characteristic of ratio between central and independent contours
        of heart rhythm regulation.
        """
        vlf = self.get_vlf_power()[0]
        lf = self.get_lf_power()[0]
        hf = self.get_hf_power()[0]
        if hf > 0 and self.is_vlf_ready():
            return vlf + float(lf) / hf
        return 0

    def get_ISCA(self):
        """
        index of activation of sub cortical nervous centers ISCA (Index of Subcortical
        Centers Activity, ISCA = VLF / LF).

        ISCA characterizes activity of cardiovascular subcortical nervous center in relation
        to higher levels of management. The increased activity of sub cortical nervous centers
        is played by growth of ISCA.
        With help of this index processes the brain inhibiting effect can be supervised.
        """
        vlf = self.get_vlf_power()[0]
        lf = self.get_lf_power()[0]
        if lf > 0 and self.is_vlf_ready():
            return vlf / float(lf)
        return 0

    def get_vegetative_balance(self):
        """HF/LF is interpreted as a parameter of vegetative balance"""
        hf = self.get_hf_power()[0]
        lf = self.get_lf_power()[0]
        if lf > 0 and self.is_lf_ready():
            return hf / float(lf)
        return 0

    def get_freq(self):
        return self.freqs[self.idx]

    def get_spectrum(self):
        return self.last_spectrum

    def calc_energy_spectrum(self):

        #http://stackoverflow.com/questions/15382076/plotting-power-spectrum-in-python
        # get unidistant sampled times
        use_N_last_RRs = self.time_span.get_N()
        unitimes = np.linspace(self.cum_times_buf.samples[-use_N_last_RRs],
                               self.cum_times_buf.samples[-1],
                               self.spectr_intervals_cnt)

        # interpolate rr_ms_sqr
        uni_rr_ms_sqr = np.interp(
            unitimes,
            self.cum_times_buf.samples[-use_N_last_RRs:],
            #1.0/np.array(self.time_span.get_samples())) # energy levels over heart frequency
            np.array(self.time_span.get_samples()
                     ))  # 1.0/energy levels over 1.0/heart_frequency

        uni_rr_ms_sqr -= np.mean(uni_rr_ms_sqr)
        # calculate spectrum
        ps = np.abs(np.fft.fft(uni_rr_ms_sqr * self._wnd))**2
        #plt.plot(freqs[self.idx], ps[self.idx])
        #s = np.sum(ps[self.idx])
        #if s < self.zero_eps:
        #    s = 1.0
        self.last_spectrum = ps[self.idx]  #/ s
        #return self.last_spectrum

    def is_hf_ready(self):

        return self.time_span.buf_real_duration > 14.

    def is_lf_ready(self):

        return self.time_span.buf_real_duration > 50.

    def is_vlf_ready(self):

        return self.time_span.buf_real_duration > 132.0

    def is_ulf_ready(self):
        """
        Different buffer duration allows to perform different calculations
        ULF        Less than 0,015      More than 66 secs
        """
        return self.time_span.buf_real_duration > 300.  # standard time

    def is_ready(self):
        return self.is_vlf_ready()
        #return self.get_progress() >= self.may_calc

    def get_progress(self):
        return self.time_span.get_progress()

    def update(self, rr):
        self.time_span.update_buf_duration(rr)
        if len(self.cum_times_buf.samples) > 0:
            self.cum_times_buf.add_sample(self.cum_times_buf.samples[-1] + rr)
        else:
            self.cum_times_buf.add_sample(rr)