예제 #1
0
    def _get_qrs_power_signal(self):
        if self.apply_filter:
            filtered_ecg = normalize(
                bandpass(self.ecg_signal, self.bandpass_min, self.bandpass_max,
                         self.ecg_ts.sampling_rate))
        else:
            filtered_ecg = self.ecg_signal

        # Differentiate and square the signal?
        if self.apply_diff_sq:
            # Differentiate the signal and square it
            diff_sq = np.ediff1d(filtered_ecg, to_begin=0)**2
        else:
            diff_sq = filtered_ecg

        # If we're to apply a Moving Average smoothing
        if self.apply_smooth_ma:
            # MA smoothing
            smooth_ma = smooth(diff_sq,
                               window_len=self.smoothing_window_len,
                               window=self.smoothing_window)
        else:
            smooth_ma = diff_sq
        if not self.use_ECG2:
            # for visualization purposes
            return normalize(smooth_ma)
        logger.info("Using 2nd ECG signal")

        # Use secondary ECG signal and combine QRS power
        if self.apply_filter:
            filtered_ecg2 = normalize(
                bandpass(self.ecg2_signal, self.bandpass_min,
                         self.bandpass_max, self.ecg_ts.sampling_rate))
        else:
            filtered_ecg2 = self.ecg2_signal
        if self.apply_diff_sq:
            diff_sq2 = np.ediff1d(filtered_ecg2, to_begin=0)**2
        else:
            diff_sq2 = filtered_ecg2

        if self.apply_smooth_ma:
            smooth_ma2 = smooth(diff_sq2,
                                window_len=self.smoothing_window_len,
                                window=self.smoothing_window)
        else:
            smooth_ma2 = diff_sq2

        return normalize(((1 - self.ecg2_weight) * smooth_ma +
                          self.ecg2_weight * smooth_ma2)**2)
예제 #2
0
 def beat_to_time_feature_matrix(self, beatnum):
     """
     Turns a heartbeat into a matrix. There is one row for each millisecond between
     the r point and the c point. Each row represents the time corresponding to
     its center.  That timepoint is padded by self.pre_point_msec and
     self.post_point_msec. If self.include_derivative, the derivative is appended to
     the end of each row
     """
     include_derivative = self.include_derivative
     pre_msec = self.pre_point_msec
     post_msec = self.post_point_msec
     r_ind = self.physiodata.r_indices[beatnum]
     c_ind = self.physiodata.c_indices[beatnum]
     if r_ind == c_ind:
         raise ValueError("Invalid r and c point for beat %d" % beatnum)
     _sig = self.physiodata.mea_dzdt_matrix[beatnum][:]
     # The targets are msec from the b-point
     if include_derivative:
         signal = [np.concatenate([_sig[(ind-pre_msec):(ind+post_msec+1)],
             10*np.diff(
                smooth(_sig[(ind-pre_msec):(ind+post_msec+1)], 7))]) \
                             for ind in xrange(r_ind,c_ind)]
     else:
         signal = [_sig[(ind-pre_msec):(ind+post_msec+1)] for ind \
                                                 in xrange(r_ind,c_ind)]
     return np.row_stack(signal)
예제 #3
0
 def _get_aux_signal(self):
     if not self.use_secondary_heartbeat: return np.array([])
     sig = getattr(self.physiodata, self.secondary_heartbeat + "_data")
     if self.secondary_heartbeat_abs:
         sig = np.abs(sig)
     if self.secondary_heartbeat_window_len > 0:
         sig = smooth(sig,
                      window_len=self.secondary_heartbeat_window_len,
                      window=self.secondary_heartbeat_window)
     return normalize(sig)
예제 #4
0
    def mark_similar(self,
                     unmarked_beat,
                     smoothing_window_len=21,
                     search_window=SEARCH_WINDOW):
        """
        Extracts a time point specific to ``unmarked_beat`` that
        has similar signal property (min/max/inflection) within
        a specific time window
        """
        # Get the necessary info from the unmarked beat
        unmarked_point = getattr(unmarked_beat, self.name)
        ts = getattr(unmarked_beat, self.applies_to + "_signal")
        # Define the search area
        window_min_idx = self.index - search_window
        window_max_idx = self.index + search_window + 1
        if self.index < search_window and self.point_type != "average":
            logger.warn(
                "timepoint too close to 0 for a symmetric search window")
            return
        if self.name == "q":
            search_window = 9
            smoothing_window_len = 0
        search_region = ts[(self.index - search_window):(self.index +
                                                         search_window + 1)]

        # Smooth the timeseries if requested
        if smoothing_window_len > 0:
            search_region = smooth(search_region,
                                   window_len=smoothing_window_len)
        # find the actual time of the point
        if self.point_type == "max":
            t_ind = window_min_idx + search_region.argmax()
        elif self.point_type == "min":
            t_ind = window_min_idx + search_region.argmin()
        elif self.point_type == "inflection":
            diff = np.ediff1d(search_region, to_begin=0)
            diff2 = np.ediff1d(diff, to_begin=0)
            t_ind = window_min_idx + np.abs(diff2).argmax()
        elif self.point_type == "geom_trick":
            r_idx = unmarked_beat.r.index
            c_idx = unmarked_beat.c.index
            if not r_idx < c_idx:
                unmarked_beat.b.needs_attention = True
                return self
            roi = ts[r_idx:c_idx]
            line = np.interp(np.arange(len(roi)), [0, len(roi)],
                             [roi[0], roi[-1]])
            t_ind = r_idx + np.argmax(line - roi)

        # Average is a special case.
        elif self.point_type == "average":
            unmarked_point.value = ts.mean()
            unmarked_point.set_index(0)
            return

        # Check that we aren't hitting an edge of the search reg
        if t_ind in (window_min_idx, window_max_idx):
            bnum = unmarked_beat.id if unmarked_beat.id is not None else -1
            logger.warn("[%d] %s point detected at edge of search region",
                        bnum, self.name)
            unmarked_point.needs_attention = True
        unmarked_point.set_index(t_ind)

        # If this timepoint is tracked by beat id,
        if unmarked_beat.id is not None:
            index_array = getattr(self.physiodata, self.name + "_indices",
                                  None)
            assert index_array[unmarked_beat.id] == t_ind
        return True