Esempio n. 1
0
 def sqi2(self):
     """linear resampling (between two fiducials up to length L, correlation)"""
     slicez, islicez = self.slices(method='variable')
     L = len(self.template)
     corrs = np.array([(cross_corr(sig_resample(sl, L), self.template)
                        if len(sl) else 0.0) for sl in slicez])
     corrs = np.clip(corrs, a_min=0.0, a_max=1.0)
     return corrs
Esempio n. 2
0
 def sqi3(self):
     """DTW resampling (resampling to length L and correlation)"""
     slicez, islicez = self.slices(method='variable')
     corrs = np.array([
         cross_corr(*self.dtw_resample(sl)) if len(sl) else 0.0
         for sl in slicez
     ])
     corrs = np.clip(corrs, a_min=0.0, a_max=1.0)
     return corrs
Esempio n. 3
0
 def sqi1(self):
     """direct matching (fiducial + length L template correlation)"""
     # nb. slight difference: we are centering the window on the beat, while Li et al
     slicez, islicez = self.slices(method='fixed')
     corrs = np.array([
         cross_corr(sl, self.template) if len(sl) else 0.0 for sl in slicez
     ])
     corrs = np.clip(corrs, a_min=0.0, a_max=1.0)
     return corrs
Esempio n. 4
0
def ecg_kept(raw):
    sig0 = raw

    fps = sig0.fps

    # print 'slice.x shape=', sig0.slice(slice(int(0*fps), int(ECG_DURATION*fps))).x.shape
    ###

    ecg = beatdet_ecg(sig0.slice(slice(int(0 * fps), int(ECG_DURATION * fps))))
    ecg.lead = LEADS[ECG_LEAD]

    # scaling for plot
    pcs = np.array([np.percentile(ecg.x, 10), np.percentile(ecg.x, 90)])
    pcs = (pcs - np.mean(pcs)) * 5.0 + np.mean(pcs)

    ###

    slicez = sqi_slices(ecg, method='fixed', slice_front=0.5, slice_back=-0.5)
    L = max([len(sl) for sl in slicez])
    padded_slicez = np.array(
        [sig_pad(sl, L, side='center', mode='constant') for sl in slicez])

    ###

    perc = envelopes_perc_threshold(padded_slicez)
    le, ue = envelopes_at_perc(padded_slicez, perc)
    mb = np.median(padded_slicez, axis=0)

    bpt = beat_penalty_threshold(le, ue, mb)

    bps = np.array([beat_penalty(sl, le, ue, mb) for sl in padded_slicez])

    bp_ok = bps < bpt

    ###

    template = np.median(padded_slicez, axis=0)
    corrs = np.array([cross_corr(sl, template) for sl in padded_slicez])

    CORR_THRESHOLD = 0.8
    corr_ok = corrs > CORR_THRESHOLD

    ###

    # next beat is OK as well?
    bp_ibi_ok = bp_ok & np.roll(bp_ok, -1)
    corr_ibi_ok = corr_ok & np.roll(corr_ok, -1)

    igood = np.where(bp_ibi_ok & corr_ibi_ok)[0]
Esempio n. 5
0
    def beat_template_1(self):
        self.L = np.median(np.diff(self.tbeats))
        slicez_1, islicez_1 = self.slices(
            method="fixed")  #, hwin=int(self.L*self.fps/2.)))
        self.ibis_good = islicez_1
        template_1 = np.mean(slicez_1, axis=0)
        #print 'template_1', template_1
        slicez, islicez = self.slices(method="fixed", scrub=False)
        corrs = np.array([cross_corr(sl, template_1) for sl in slicez])
        self.slicez_1, self.islicez_1, self.template_1 = slicez_1, islicez_1, template_1
        self.slicez, self.islicez, self.corrs = slicez, islicez, corrs
        # TODO: penalize the correlation of overlong IBIs (since correlation only goes until the beat template ends)

        # debug: put shape envelopes
        self.env_min = sqi_copy_to_idxs(self.s_min, len(self.x),
                                        self.ibeats.astype(int),
                                        [sqi_slice_norm(sl) for sl in slicez])
        self.env_max = sqi_copy_to_idxs(self.s_max, len(self.x),
                                        self.ibeats.astype(int),
                                        [sqi_slice_norm(sl) for sl in slicez])
Esempio n. 6
0
    def beat_detect(self, debug=False, outlierthreshold=0.001):
        # Heuristics:
        # * found enough beats
        # * median ibi is in plausible range (or even: some percentile of ibis is in plausible range)
        # * histogram of beat correlations is plausible (lots of good correlation)
        #
        # Good beats have positive correlation, e.g. rho > 0.5 with the median beat.

        ecg = self.ecg

        #ecg.x[:int(ecg.fps*5)] *= 0.0  # avoid the terrible swing

        #
        # Kim ECG beat detection
        #
        smoothsignal = np.array(ecg.x)

        # kill outliers
        mn, mx = np.min(smoothsignal), np.max(smoothsignal)
        m = min(abs(mn), abs(mx))
        N = 100
        step = m / float(N)
        for i in range(N):
            n = len(np.where(smoothsignal < -m)[0]) + len(
                np.where(smoothsignal > m)[0])
            if n > outlierthreshold * len(smoothsignal):
                break
            m -= step
        mn, mx = -m, m

        smoothsignal[smoothsignal < mn] = mn
        smoothsignal[smoothsignal > mx] = mx
        smoothsignal[-10:] = 0  # extreme outlier in last few frames

        # adjust distribution to the one Kim has optimized for
        smoothsignal = (smoothsignal - np.mean(smoothsignal)
                        ) / np.std(smoothsignal) * 0.148213 - 0.191034
        loc, beattime = self.QRSdetection(smoothsignal,
                                          ecg.fps,
                                          ecg.t,
                                          ftype=0)
        loc = loc.flatten()

        #
        # check error Kim vs. localmax of R peaks
        #
        new_loc = localmax_climb(ecg.x, loc,
                                 hwin=int(0.02 * ecg.fps))  # hwin = 20 ms
        peak_errs = (new_loc - loc) / float(ecg.fps)
        #print 'np.mean(peak_errs), np.std(peak_errs)', np.mean(peak_errs), np.std(peak_errs)

        ibis = np.diff(loc / float(ecg.fps))
        median_ibi = np.median(ibis)

        #
        # filter beats by cross-correlation with median beat
        #
        ecg_slices = np.array(
            slices(ecg.x, loc, hwin=int(np.ceil(median_ibi * ecg.fps)) // 2))
        # median value from each timepoint (not a single one of any of the beats)
        median_beat = np.median(ecg_slices, axis=0)
        if debug:
            plt.plot(np.arange(len(median_beat)) / float(ecg.fps), median_beat)
            plt.title('median ECG beat')
        cross_corrs = [cross_corr(sl, median_beat) for sl in ecg_slices]

        spectrum_ok = np.array(
            [self.slice_good(sl, median_beat) for sl in ecg_slices])
        ccs_ok = np.array(cross_corrs) > NoisyECG.GOOD_BEAT_THRESHOLD

        good_loc_idxs = np.where(ccs_ok & spectrum_ok)[0]
        if debug:
            [
                plt.plot(
                    np.arange(len(ecg_slices[i])) / float(ecg.fps),
                    ecg_slices[i]) for i in range(1, len(ecg_slices))
                if i in good_loc_idxs
            ]
            plt.title('all good ECG beats with rho > {:.2f}'.format(
                NoisyECG.GOOD_BEAT_THRESHOLD))
            plt.show()

        beat_idxs = loc[good_loc_idxs]
        beat_times = beattime[good_loc_idxs]

        self._beattime, self._cross_corrs = beattime, cross_corrs

        if debug:
            self.debug_plot()

        #self.cross_corrs = np.array(cross_corrs)[good_loc_idxs]
        self.median_ibi = median_ibi
        self.good_beat_fraction = float(len(good_loc_idxs)) / len(cross_corrs)
        return beat_idxs, beat_times