Exemplo n.º 1
0
def _find_peak(siginfo):
    """
    Obtains an estimation of the peak situation of a QRS complex, from the
    energy interval that forms the base evidence, a fragment of signal evidence,
    a reference time point, and the interval of valid points for the peak.
    """
    dist = lambda p : 1.0 + 2.0 * abs(p - C.QRS_BANN_DMAX)/ms2sp(150)
    dist = np.vectorize(dist)
    peak = None
    #For each lead, the peak will be the maximum deviation point wrt the
    #baseline, and applying the distance function just defined. We give more
    #importance to the first leads, as they supposedly have more quality.
    for _, sig, points, baseline, _ in siginfo:
        if len(points) < 3:
            continue
        peaks = points[sig_meas.get_peaks(sig[points])]
        if len(peaks) == 0:
            continue
        peakscore = abs(sig[peaks]-baseline)/dist(peaks)
        lpeak = peaks[peakscore.argmax()]
        if peak is None:
            peak = lpeak
        elif abs(peak-lpeak) <= C.TMARGIN:
            peak = lpeak if lpeak < peak else peak
    return peak
Exemplo n.º 2
0
def delineate_qrs(siginfo):
    """
    Performs the multi-lead delineation of a QRS complex enclosed in a
    specific time interval, returning an instance of the QRS class.

    Parameters
    ----------
    siginfo:
        List-like structure containing all the necessary information of the
        ECG signal in the searching time interval. Each entry in this list
        is assumed to be a tuple of the **LeadInfo** class, and the list is
        assumed to be ordered by the quality of the signal in each lead.

    Returns
    -------
    out:
        QRS object with all the attributes properly set. If the delineation
        cannot be performed, an InconsistencyError is raised.
    """
    verify(siginfo)
    qrs = QRS()
    #Peak point estimation.
    peak = _find_peak(siginfo)
    verify(peak is not None)
    #QRS start and end estimation
    #For each lead, we first check if it is a paced beat, whose delineation
    #process is different. In case of failure, we perform common delineation.
    limits = OrderedDict()
    for lead, sig, points, baseline, _ in siginfo:
        endpoints = _paced_qrs_delineation(sig, points, peak, baseline)
        if endpoints is None:
            endpoints = _qrs_delineation(sig, points, peak)
            if endpoints is None:
                continue
            limits[lead] = (False, endpoints)
        else:
            limits[lead] = (True, endpoints)
    #Now we combine the limits in all leads.
    start, end = _combine_limits(limits, siginfo, peak)
    verify(start is not None and end > start)
    #QRS waveform extraction for each lead.
    for lead, sig, points, baseline, _ in siginfo:
        #We constrain the area delineated so far.
        sig = sig[start:end+1]
        points = points[np.logical_and(points >= start,
                                       points <= end)] - start
        if len(points) == 0:
            continue
        if points[0] != 0:
            points = np.insert(points, 0, 0)
        if points[-1] != len(sig) - 1:
            points = np.append(points, len(sig) - 1)
        if len(points) < 3:
            continue
        #We define a distance function to evaluate the peaks
        dist = (lambda p : 1.0 + 2.0 * abs(start + p - C.QRS_BANN_DMAX)
                                                                   /ms2sp(150))
        dist = np.vectorize(dist)
        #We get the peak for this lead
        pks = points[sig_meas.get_peaks(sig[points])]
        if len(pks) == 0:
            continue
        peakscore = abs(sig[pks]-baseline)/dist(pks)
        peak = pks[peakscore.argmax()]
        #Now we get the shape of the QRS complex in this lead.
        shape = None
        #If there is a pace detection in this lead
        if lead in limits and limits[lead][0]:
            endpoints = limits[lead][1]
            shape = _get_paced_qrs_shape(sig, points,
                                     endpoints.start - start,
                                     min(endpoints.end-start,len(sig)))
            if shape is None:
                limits[lead] = (False, endpoints)
        if shape is None:
            shape = _get_qrs_shape(sig, points, peak, baseline)
        if shape is None:
            continue
        qrs.shape[lead] = shape
    #There must be a recognizable QRS waveform in at least one lead.
    verify(qrs.shape)
    #The detected shapes may constrain the delineation area.
    llim = min(qrs.shape[lead].waves[0].l for lead in qrs.shape)
    if llim > 0:
        start = start + llim
        for lead in qrs.shape:
            qrs.shape[lead].move(-llim)
    ulim = max(qrs.shape[lead].waves[-1].r for lead in qrs.shape)
    if ulim < end-start:
        end = start + ulim
    #The definitive peak is assigned to the first relevant wave
    #(each QRS shapeform has a specific peak point.)
    peak = start + min(s.waves[_reference_wave(s)].m
                                               for s in qrs.shape.itervalues())
    #Segmentation points set
    qrs.paced = any(v[0] for v in limits.itervalues())
    qrs.start, qrs.peak, qrs.end = start, peak, end
    ###################################################################
    #Amplitude conditions (between 0.5mV and 6.5 mV in at least one
    #lead or an identified pattern in most leads).
    ###################################################################
    verify(len(qrs.shape) > len(siginfo)/2.0 or
        C.QRS_MIN_AMP <= max(s.amplitude for s in qrs.shape.itervalues())
                                                              <= C.QRS_MAX_AMP)
    return qrs