コード例 #1
0
ファイル: vflutter.py プロジェクト: minho17/construe
def _vflut_gconst(pattern, _):
    """
    General constraints of the pattern, checked every time a new observation
    is added to the evidence. These constraints simply state that the majority
    of the leads must show a positive detection of a ventricular flutter.
    """
    if not pattern.evidence[o.Cardiac_Rhythm]:
        return
    hyp = pattern.hypothesis
    ##################
    beg = int(hyp.earlystart)
    if beg < 0:
        beg = 0
    end = int(hyp.earlyend)
    verify(not _contains_qrs(pattern), 'QRS detected during flutter')
    lpos = 0.
    ltot = 0.
    for lead in sig_buf.get_available_leads():
        if _is_VF(sig_buf.get_signal_fragment(beg, end, lead=lead)[0]):
            lpos += 1
        ltot += 1
    verify(lpos/ltot > 0.5)
    defls = pattern.evidence[o.Deflection]
    if len(defls) > 1:
        rrs = np.diff([defl.earlystart for defl in defls])
        hyp.meas = o.CycleMeasurements((np.mean(rrs), np.std(rrs)),
                                                                (0, 0), (0, 0))
コード例 #2
0
ファイル: regular.py プロジェクト: shuangte/construe
def _rhythm_obs_proc(pattern):
    """Observation procedure executed once the rhythm pattern has finished"""
    #Tachycardias should have at least 4 QRS complexes.
    if isinstance(pattern.hypothesis, o.Tachycardia):
        verify(len(pattern.evidence[o.QRS]) >= 4)
    #We asign the endpoint of the hypothesis.
    pattern.hypothesis.end.value = pattern.evidence[o.QRS][-1].time.value
コード例 #3
0
ファイル: rhythmblock.py プロジェクト: shuangte/construe
def _prev_rhythm_gconst(pattern, rhythm):
    """General constraints of a cardiac rhythm with the preceden one."""
    #We only accept the concatenation of the same rhythm for asystoles.
    verify(not isinstance(rhythm, o.Asystole) and
                                      type(pattern.hypothesis) != type(rhythm))
    #A block keeps the reference measures.
    pattern.hypothesis.meas = copy.copy(rhythm.meas)
コード例 #4
0
ファイル: afib.py プロジェクト: minho17/construe
def _prev_afib_exists_gconst(pattern, _):
    """
    Verification of the existence of a previous atrial fibrillation episode.
    """
    prhythms = pattern.evidence[o.Cardiac_Rhythm]
    verify(prhythms and isinstance(prhythms[0], o.Atrial_Fibrillation))
    pattern.hypothesis.morph = copy.deepcopy(prhythms[0].morph)
コード例 #5
0
ファイル: rhythmblock.py プロジェクト: shuangte/construe
def _prev_asyst_gconst(pattern, asyst):
    """
    Verification of the existence of a previous asystole episode.
    """
    verify(isinstance(asyst, o.Asystole))
    #A block keeps the reference measures.
    pattern.hypothesis.meas = copy.copy(asyst.meas)
コード例 #6
0
ファイル: regular.py プロジェクト: shuangte/construe
def _prev_rhythm_gconst(pattern, rhythm):
    """General constraints of a cardiac rhythm with the preceden one."""
    #We only accept the concatenation of the same rhythm for asystoles.
    verify(
        isinstance(pattern.hypothesis, o.Asystole)
        or type(pattern.hypothesis) != type(rhythm))
    #The rhythm measurements are initially taken from the previous rhythm.
    pattern.hypothesis.meas = o.CycleMeasurements(
        rhythm.meas.rr, (rhythm.meas.rt[0], C.QT_ERR_STD),
        (rhythm.meas.pq[0], C.QT_ERR_STD))
コード例 #7
0
def _verify_atrial_activity(pattern):
    """
    Checks if the atrial activity is consistent with the definition of atrial
    fibrillation (that is, absence of constant P Waves or flutter-like
    baseline activity.)
    """
    beats = pattern.evidence[o.QRS][-5:]
    obseq = pattern.obs_seq
    atr_sig = {lead: [] for lead in sig_buf.get_available_leads()}
    pw_lims = []
    idx = pattern.get_step(beats[0])
    #First we get all the signal fragments between ventricular observations,
    #which are the only recognized by this pattern. In these fragments is where
    #atrial activity may be recognized.
    for i in xrange(idx + 1, len(obseq)):
        if isinstance(obseq[i], o.QRS):
            beg = next(obs for obs in reversed(obseq[:i])
                       if obs is not None).lateend
            end = obseq[i].earlystart
            if end - beg > ms2sp(200):
                beg = end - ms2sp(200)
            pw_lims.append((beg, end))
    for i in xrange(len(beats) - 1):
        beg, end = beats[i].lateend, beats[i + 1].earlystart
        for lead in atr_sig:
            atr_sig[lead].append(
                sig_buf.get_signal_fragment(beg, end, lead=lead)[0] -
                characterize_baseline(lead, beg, end)[0])
    #Flutter check (only for atrial activity)
    aflut = set()
    for lead in atr_sig:
        sigfr = np.concatenate(atr_sig[lead])
        if len(sigfr) > 15 and _is_VF(sigfr):
            aflut.add(lead)
    #FIXME improve flutter check, now is quite poor.
    #aflut = frozenset()
    #P waveform check (only for leads where flutters were not found.)
    pwaves = []
    for beg, end in pw_lims:
        pwsig = _get_pwave_sig(beg, end)
        if pwsig is not None:
            for lead in aflut:
                pwsig.pop(lead, None)
            if not pwsig:
                continue
            for wave in pwaves:
                verify(
                    abs(wave.values()[0].pr - pwsig.values()[0].pr) > C.TMARGIN
                    or not signal_match(wave, pwsig))
            pwaves.append(pwsig)
コード例 #8
0
ファイル: rhythmblock.py プロジェクト: shuangte/construe
def _qrs_gconst(pattern, _):
    """
    General constraints to be added when a new cycle is observed, which
    currently coincides with the observation of the T waves or a QRS complex
    not followed by an observed T wave.
    """
    #We check that there are no missed beat forms.
    _check_missed_beats(pattern)
    beats = pattern.evidence[o.QRS]
    #Morphology check. We require the rhythm morphology to be matched
    #by the new beat in the sequence.
    ref = pattern.hypothesis.morph
    #We initialize the morphology with the first beat.
    if not ref:
        ref = copy.deepcopy(beats[0].shape)
        pattern.hypothesis.morph = ref
    verify(signal_match(ref, beats[-1].shape))
    #This comparison avoids positive matchings with extrasystoles,
    #but we only check it if the beat before the first block is advanced.
    if len(beats) == 3:
        refrr, stdrr = pattern.hypothesis.meas.rr
        if (beats[1].time.start - beats[0].time.start <
                                                min(0.9 * refrr, refrr-stdrr)):
            verify(beats[2].time.start - beats[0].time.start >
                                                      refrr * C.COMPAUSE_MAX_F)
            verify(beats[2].time.start - beats[1].time.start >
                                                    refrr + C.COMPAUSE_MIN_DUR)
    #We require a significant change in consecutive RR intervals.
    if len(beats) >= 3:
        rr = beats[-1].time.start - beats[-2].time.start
        prevrr = beats[-2].time.start - beats[-3].time.start
        verify(abs(prevrr-rr) >= C.RR_MAX_DIFF)
コード例 #9
0
ファイル: bigeminy.py プロジェクト: shuangte/construe
def _ect0_gconst(pattern, qrs):
    """
    General constraints to be satisfied by the first ectopic QRS complex of
    the bigeminy, which is the abduction point of the pattern. These
    constraints ensure that the ectopic beat is really advanced. This is needed
    because the first ectopic beat is the abduction point, and therefore the
    reference RR cannot be calculated when establishing the temporal
    constraints for the first time.
    """
    if pattern.evidence[o.Cardiac_Rhythm]:
        mrr, stdrr = pattern.evidence[o.Cardiac_Rhythm][0].meas[0]
        if mrr > 0:
            ectrr = qrs.time.start - pattern.evidence[o.QRS][0].time.start
            mshort = min(0.1 * mrr, stdrr)
            verify(ectrr < mrr - mshort)
コード例 #10
0
def _couplet_gconst(pattern, _):
    """
    General constraints to be checked when the couplet finishes.
    """
    _check_missed_beats(pattern)
    #The second extrasystole cannot be in rhythm with contextual beats, or in
    #such case it must have a different shape.
    beats = pattern.evidence[o.QRS]
    mpt = beats[0].time.start + (beats[-1].time.start -
                                 beats[0].time.start) / 2.
    verify(
        abs(mpt - beats[2].time.start) >= C.ICOUPLET_RCHANGE
        or signal_unmatch(beats[2].shape, beats[-1].shape))
    pattern.hypothesis.meas = copy.copy(
        pattern.evidence[o.Cardiac_Rhythm][0].meas)
コード例 #11
0
def _p_gconst(pattern, defl):
    """
    General constraints of the P Wave abstraction pattern, once all the
    evidence has been observed.
    """
    pwave = pattern.hypothesis
    if ((defl is not None and defl.earlystart != defl.latestart)
                                               or not pattern.evidence[o.QRS]):
        return
    qrs = pattern.evidence[o.QRS][0]
    beg = pwave.earlystart
    if beg < 0:
        beg = 0
    #We try the delineation of the P-Wave
    endpoints = delineate_pwave(beg, int(pwave.latestart),
                                int(pwave.earlyend), int(pwave.lateend), pwave)
    verify(endpoints is not None)
    #Now we obtain the amplitudes, and we ensure the QRS amplitude is at
    #least twice the P Wave amplitude in each lead
    pwave.start.set(beg + endpoints.start, beg + endpoints.start)
    pwave.end.set(beg + endpoints.end, beg + endpoints.end)
    for lead in pwave.amplitude:
        verify(pwave.amplitude[lead] <= C.PWAVE_AMP[lead])
        verify(lead not in qrs.shape or
               pwave.amplitude[lead] < qrs.shape[lead].amplitude)
コード例 #12
0
ファイル: afib.py プロジェクト: minho17/construe
def _verify_afib_rhythm(rrs):
    """
    Checks the rhythm constraints of the atrial fibrillation patterns. If these
    constraints are not satisfied, an InconsistentStateError is raised.
    Otherwise, the procedure finishes and returns nothing.

    Parameters
    ----------
    rrs:
        RR sequence.
    """
    if len(rrs) > 3:
        verify(np.std(rrs)/np.median(rrs) > 0.08)
    if len(rrs) < C.AFIB_MIN_NQRS-1:
        #We ensure that there are not consecutive constant RRs. We usually
        #consider the last 3 RRs, but if we have only two, they cannot be very
        #similar.
        lastrr = rrs[-3:]
        if len(lastrr) == 2:
            verify(abs(lastrr[1]-lastrr[0]) > C.TMARGIN)
        else:
            verify(not np.all(np.abs(lastrr-np.mean(lastrr)) < C.TMARGIN))
    #Lian 2011 afib classification method.
    verify(is_afib_rhythm_lian(rrs))
コード例 #13
0
ファイル: afib.py プロジェクト: minho17/construe
def _qrs_gconst(pattern, _):
    """
    General constraints to be added when a new cycle is observed, which
    currently coincides with the observation of the T waves or a QRS complex
    not followed by an observed T wave.
    """
    #We update the measurements of the rhythm.
    _update_measures(pattern)
    #And check that there are no missed beat forms.
    _check_missed_beats(pattern)
    beats = pattern.evidence[o.QRS]
    #Morphology check. We require the rhythm morphology to be matched
    #by the new beat in the sequence.
    ref = pattern.hypothesis.morph
    #We initialize the morphology with the first beat.
    if not ref:
        ref = copy.deepcopy(beats[0].shape)
        pattern.hypothesis.morph = ref
    verify(signal_match(ref, beats[-1].shape))
    #TODO improve morphology updating.
    #_update_morphology(pattern)
    envrhythms = pattern.evidence[o.Cardiac_Rhythm]
    prevafib = envrhythms and isinstance(envrhythms[0], o.Atrial_Fibrillation)
    if len(beats) == 2 and envrhythms:
        refrr, stdrr = envrhythms[-1].meas.rr
        #The first RR cannot be within the mean +- 2*std of the previous RR.
        #There must be a rhythm change.
        verify(not refrr - 2*stdrr <= beats[1].time.start - beats[0].time.start
                                                            <= refrr + 2*stdrr)
    if len(beats) >= 3:
        verify(not beats[-1].paced)
        rpks = np.array([b.time.start for b in beats])
        rrs = np.diff(rpks)
        _verify_afib_rhythm(rrs)
        #With this check, we avoid false positives with bigeminies, checking
        #the RR constraints with even and odd rrs.
        if len(beats) >= 6:
            _verify_afib_rhythm(rrs[0::2])
            _verify_afib_rhythm(rrs[1::2])
            _verify_afib_rhythm(np.diff(rpks[0::2]))
    #Atrial activity is only checked at the beginning of the pattern and if
    #there are not previous atrial fibrillation episodes.
    if 1 < len(beats) < 32 and not prevafib:
        _verify_atrial_activity(pattern)
コード例 #14
0
ファイル: afib.py プロジェクト: minho17/construe
def _prev_afib_gconst(pattern, afib):
    """
    Verification of the existence of a previous atrial fibrillation episode.
    """
    verify(isinstance(afib, o.Atrial_Fibrillation))
    pattern.hypothesis.morph = copy.deepcopy(afib.morph)
コード例 #15
0
def _delimit_t(signal, baseline, ls_lim, ee_lim, qrs_shape):
    """
    This function performs the delineation of a possible T Wave present
    in the fragment. To obtain the endpoint of the T Wave, it uses a method
    based on the work by Zhang: 'An algorithm for robust and efficient location
    of T-wave ends in electrocardiograms'. To get the beginning, it uses a
    probabilistic approach with some basic morphology constraints. All the
    processing is made to a simplification of the signal fragment with at most
    7 points.
    """
    try:
        #We exclude the areas in which the slope of the signal exceeds limit.
        maxtslope = qrs_shape.maxslope * C.TQRS_MAX_DIFFR
        lidx, uidx = 0, len(signal)
        if ls_lim > 0:
            idx = np.where(
                np.max(np.abs(np.diff(signal[:ls_lim +
                                             1]))) > maxtslope)[0] + 1
            lidx = max(idx) if len(idx) > 0 else 0
        if ee_lim < len(signal) - 1:
            idx = np.where(
                np.max(np.abs(np.diff(signal[ee_lim:]))) > maxtslope
            )[0] + ee_lim
            uidx = min(idx) if len(idx) > 0 else len(signal) - 1
            if (uidx > 1 and
                    abs(signal[uidx] - baseline) > C.TWEND_BASELINE_MAX_DIFF):
                dfsign = np.sign(np.diff(signal[:uidx + 1]))
                signchange = ((np.roll(dfsign, 1) - dfsign) != 0).astype(int)
                if np.any(signchange):
                    uidx = np.where(signchange)[0][-1]
        verify(uidx >= lidx)
        signal = signal[lidx:uidx + 1]
        ls_lim -= lidx
        ee_lim -= lidx
        #Any T waveform should be representable with at most 7 points.
        points = DP.arrayRDP(signal,
                             max(ph2dg(0.02), qrs_shape.amplitude / 20.0), 7)
        n = len(points)
        verify(n >= 3)
        #1. Endpoint estimation
        epts = points[points >= ee_lim]
        verify(len(epts) > 0)
        Tend, dum = _zhang_tendpoint(signal, epts)
        #2. Onset point estimation.
        bpts = points[np.logical_and(points < Tend, points <= ls_lim)]
        score = {}
        #Range to normalize differences in the signal values
        rang = max(baseline, signal.max()) - min(signal.min(), baseline)
        #There must be between one and 3 peaks in the T Wave.
        for i in xrange(len(bpts)):
            sigpt = signal[points[i:np.where(points == Tend)[0][0] + 1]]
            npks = len(get_peaks(sigpt)) if len(sigpt) >= 3 else 0
            if (npks < 1 or npks > 2 or np.ptp(sigpt) <= ph2dg(0.05)):
                continue
            bl_dist = 1.0 - np.abs(signal[bpts[i]] - baseline) / rang
            tdur = sp2ms(Tend - bpts[i])
            score[bpts[i]] = bl_dist * _check_histogram(_TDUR_HIST, tdur)
        verify(score)
        Tbeg = max(score, key=score.get)
        verify(score[Tbeg] > 0)
        verify(np.max(np.abs(np.diff(signal[Tbeg:Tend + 1]))) <= maxtslope)
        return (Iv(Tbeg + lidx, Tend + lidx), dum)
    except InconsistencyError:
        return None
コード例 #16
0
ファイル: regular.py プロジェクト: shuangte/construe
def _check_missed_beats(pattern):
    """
    Checks if a rhythm pattern has missed a QRS complex in the identification,
    by looking for a waveform "identical" to the last observed in the interval
    between the last two observations.
    """
    qrs = pattern.evidence[o.QRS][-1]
    obseq = pattern.obs_seq
    idx = obseq.index(qrs)
    if idx > 0:
        prevobs = next(
            (obs for obs in reversed(obseq[:idx]) if obs is not None), None)
        if prevobs is not None:
            if isinstance(prevobs, o.QRS):
                limit = max(prevobs.lateend,
                            prevobs.earlystart + qrs.lateend - qrs.earlystart)
            else:
                limit = prevobs.lateend
        else:
            limit = pattern.hypothesis.earlystart
        ulimit = qrs.earlystart - C.TACHY_RR.start
        if limit >= ulimit:
            return
        sig = {}
        #We take the signal fragment with maximum correlation with the QRS
        #signal in each lead, and we check if the two fragments can be
        #clustered as equal QRS complexes.
        qshape = {}
        corr = -np.Inf
        delay = 0
        leads = sig_buf.get_available_leads()
        for lead in leads:
            qshape[lead] = o.QRSShape()
            sigfr = sig_buf.get_signal_fragment(qrs.earlystart,
                                                qrs.lateend + 1,
                                                lead=lead)[0]
            qshape[lead].sig = sigfr - sigfr[0]
            qshape[lead].amplitude = np.ptp(qshape[lead].sig)
            sig[lead] = sig_buf.get_signal_fragment(limit, ulimit,
                                                    lead=lead)[0]
            lcorr, ldelay = xcorr_valid(sig[lead], qshape[lead].sig)
            if lcorr > corr:
                corr, delay = lcorr, ldelay
        if 0 <= delay < len(sig[lead]):
            sshape = {}
            for lead in leads:
                sshape[lead] = o.QRSShape()
                sshape[lead].sig = (
                    sig[lead][delay:delay + len(qshape[lead].sig)] -
                    sig[lead][delay])
                sshape[lead].amplitude = np.ptp(sshape[lead].sig)
            if isinstance(pattern.hypothesis, o.RegularCardiacRhythm):
                qref = pattern.evidence[o.QRS][-2]
                rr = float(qrs.earlystart - qref.earlystart)
                loc = (limit + delay - qref.earlystart) / rr
                #Check for one and two missed beats in regular positions
                if 0.45 <= loc <= 0.55:
                    verify(signal_unmatch(sshape, qshape), 'Missed beat')
                elif 0.28 <= loc <= 0.38 and not signal_unmatch(
                        sshape, qshape):
                    corr = -np.Inf
                    delay = 0
                    for lead in leads:
                        sig[lead] = sig_buf.get_signal_fragment(
                            int(qref.earlystart + 0.61 * rr),
                            min(
                                int(qref.earlystart + 0.71 * rr) +
                                len(qshape[lead].sig), int(qrs.earlystart)),
                            lead=lead)[0]
                        lcorr, ldelay = xcorr_valid(sig[lead],
                                                    qshape[lead].sig)
                        if lcorr > corr:
                            corr, delay = lcorr, ldelay
                    sshape = {}
                    for lead in leads:
                        sshape[lead] = o.QRSShape()
                        sshape[lead].sig = (
                            sig[lead][delay:delay + len(qshape[lead].sig)] -
                            sig[lead][delay])
                        sshape[lead].amplitude = np.ptp(sshape[lead].sig)
                    verify(signal_unmatch(sshape, qshape), 'Two missed beats')
                elif 0.61 <= loc <= 0.71 and not signal_unmatch(
                        sshape, qshape):
                    corr = -np.Inf
                    delay = 0
                    for lead in leads:
                        sig[lead] = sig_buf.get_signal_fragment(
                            int(qref.earlystart + 0.28 * rr),
                            min(
                                int(qref.earlystart + 0.38 * rr) +
                                len(qshape[lead].sig), int(qrs.earlystart)),
                            lead=lead)[0]
                        lcorr, ldelay = xcorr_valid(sig[lead],
                                                    qshape[lead].sig)
                        if lcorr > corr:
                            corr, delay = lcorr, ldelay
                    sshape = {}
                    for lead in leads:
                        sshape[lead] = o.QRSShape()
                        sshape[lead].sig = (
                            sig[lead][delay:delay + len(qshape[lead].sig)] -
                            sig[lead][delay])
                        sshape[lead].amplitude = np.ptp(sshape[lead].sig)
                    verify(signal_unmatch(sshape, qshape), 'Two missed beats')
            else:
                verify(signal_unmatch(sshape, qshape), 'Missed beat')
コード例 #17
0
ファイル: regular.py プロジェクト: shuangte/construe
def _cycle_finished_gconst(pattern, _):
    """
    General constraints to be added when a new cycle is observed, which
    currently coincides with the observation of the T waves or a QRS complex
    not followed by an observed T wave.
    """
    #We update the measurements and the morphology of the rhythm.
    _update_measures(pattern)
    _update_morphology(pattern)
    #And check that there are no missed beat forms.
    _check_missed_beats(pattern)
    beats = pattern.evidence[o.QRS]
    rrs = np.diff([b.time.start for b in beats[-32:]])
    #HINT with this check, we avoid overlapping between sinus rhythms and
    #tachycardias and bradycardias at the beginning of the pattern.
    if len(beats) == 3:
        if pattern.automata is SINUS_PATTERN:
            verify(np.any(rrs < C.BRADY_RR.start))
        elif pattern.automata is BRADYCARDIA_PATTERN:
            if (pattern.evidence[o.Cardiac_Rhythm] and isinstance(
                    pattern.evidence[o.Cardiac_Rhythm][0], o.Sinus_Rhythm)):
                verify(any([rr not in C.SINUS_RR for rr in rrs]))
    elif len(beats) == 4:
        if pattern.automata is SINUS_PATTERN:
            verify(np.any(rrs > C.TACHY_RR.end))
        elif pattern.automata is TACHYCARDIA_PATTERN:
            if (pattern.evidence[o.Cardiac_Rhythm] and isinstance(
                    pattern.evidence[o.Cardiac_Rhythm][0], o.Sinus_Rhythm)):
                verify(any([rr not in C.SINUS_RR for rr in rrs]))
    #We impose some constraints in the evolution of the RR interval and
    #of the amplitude
    #TODO remove these lines to enable full check
    ######################################################################
    if len(beats) >= 3:
        #The coefficient of variation within a regular rhythm has to be low
        verify(np.std(rrs) / np.mean(rrs) <= C.RR_MAX_CV)
        #RR evolution
        meanrr, stdrr = pattern.hypothesis.meas.rr
        verify(meanrr - 2 * stdrr <= rrs[-1] <= meanrr + 2 * stdrr
               or abs(rrs[-1] - rrs[-2]) <= C.RR_MAX_DIFF
               or 0.8 * rrs[-2] <= rrs[-1] <= 1.2 * rrs[-2])
    return
    #######################################################################
    #Morphology check. We require the rhythm morphology to be matched
    #by the new beat in the sequence.
    ref = pattern.hypothesis.morph
    #We initialize the morphology with the first beat.
    if not ref:
        for lead in beats[0].shape:
            ref[lead] = o.QRSShape()
            ref[lead].tag = beats[0].shape[lead].tag
            ref[lead].energy = beats[0].shape[lead].energy
    beat = beats[-1]
    #The leads matching morphology should sum more energy than the
    #unmatching.
    menerg = 0.0
    uenerg = 0.0
    perfect_match = False
    for lead in beat.shape:
        if lead in ref:
            bshape = beat.shape[lead]
            #If there is a "perfect" match in one lead, we accept clustering
            if (bshape.tag == ref[lead].tag
                    and 0.75 <= bshape.energy / ref[lead].energy <= 1.25):
                perfect_match = True
                break
            #If there are at least 10 beats in the sequence, we require
            #match from the beat to the rhythm, else we are ok in both
            #directions.
            match = bshape.tag in QRS_SHAPES[ref[lead].tag]
            if len(beats) < 10:
                match = bool(match or ref[lead].tag in QRS_SHAPES[bshape.tag])
            if match:
                menerg += ref[lead].energy
            else:
                uenerg += ref[lead].energy
    #If the matched energy is lower than unmatched, the hypothesis is
    #refuted.
    verify(perfect_match or menerg > uenerg)
    _update_morphology(pattern)
    if len(beats) >= 3:
        #RR evolution
        rr_prev = beats[-2].time.start - beats[-3].time.start
        rr_act = beats[-1].time.start - beats[-2].time.start
        verify(abs(rr_act - rr_prev) <= C.RR_MAX_DIFF)
コード例 #18
0
ファイル: regular.py プロジェクト: shuangte/construe
 def _pair_gconst(pattern, _):
     """
     General constraints to be satisfied when a regular rhythm consists
     of only two beats.
     """
     if pattern.evidence[o.Cardiac_Rhythm]:
         _check_missed_beats(pattern)
         prhythm = pattern.evidence[o.Cardiac_Rhythm][0]
         rhythm = pattern.hypothesis
         #Previous rhythm cannot be a regular rhythm.
         verify(not isinstance(prhythm, o.RegularCardiacRhythm))
         mrr, stdrr = prhythm.meas.rr
         beats = pattern.evidence[o.QRS]
         rr = beats[-1].time.start - beats[0].time.start
         verify(rr in rr_bounds)
         #Avoid duplicate hypotheses with overlapping rhythms.
         if pattern.automata is SINUS_PATTERN:
             verify(C.TACHY_RR.end < rr < C.BRADY_RR.start)
         maxvar = max(C.TMARGIN, min(C.RR_MAX_DIFF, 2.5 * stdrr))
         verify(rr in Iv(mrr - maxvar, mrr + maxvar))
         #Besides being in rhythm, the two beats must share the morphology.
         verify(signal_match(beats[0].shape, beats[1].shape))
         #The amplitude difference is also constrained
         for lead in beats[0].shape:
             if lead in beats[1].shape:
                 samp, qamp = (beats[0].shape[lead].amplitude,
                               beats[1].shape[lead].amplitude)
                 verify(
                     min(samp, qamp) /
                     max(samp, qamp) >= C.MISSED_QRS_MAX_DIFF)
         rhythm.meas = o.CycleMeasurements(
             (rr, stdrr), (prhythm.meas.rt[0], C.QT_ERR_STD),
             (prhythm.meas.pq[0], C.QT_ERR_STD))
コード例 #19
0
def _t_gconst(pattern, defl):
    """
    T Wave abstraction pattern general constraints, checked when all the
    evidence has been observed.
    """
    twave = pattern.hypothesis
    if defl.earlystart != defl.latestart or not pattern.evidence[o.QRS]:
        return
    qrs = pattern.evidence[o.QRS][0]
    #Wave limits
    beg = int(twave.earlystart)
    end = int(twave.lateend)
    ls_lim = int(twave.latestart - beg)
    ee_lim = int(twave.earlyend - beg)
    #Start and end estimation.
    endpoints = {}
    for lead in sorted(qrs.shape,
                       key=lambda l: qrs.shape[l].amplitude,
                       reverse=True):
        baseline, _ = characterize_baseline(lead, beg, end)
        sig = sig_buf.get_signal_fragment(beg, end, lead=lead)[0]
        verify(len(sig) == end - beg + 1)
        ep = _delimit_t(sig, baseline, ls_lim, ee_lim, qrs.shape[lead])
        if ep is not None:
            endpoints[lead] = ep
    verify(endpoints)
    limits = max(endpoints.iteritems(), key=lambda ep: ep[1][1])[1][0]
    #We verify that in all leads the maximum slope of the T wave fragment does
    #not exceed the threshold.
    for lead in endpoints:
        sig = sig_buf.get_signal_fragment(beg + limits.start,
                                          beg + limits.end,
                                          lead=lead)[0]
        verify(
            np.max(np.abs(np.diff(sig))) <= qrs.shape[lead].maxslope *
            C.TQRS_MAX_DIFFR)
        #Amplitude measure
        if lead in endpoints:
            mx, mn = np.amax(sig), np.amin(sig)
            pol = (1.0 if max(mx - sig[0], mx - sig[-1]) >=
                   -min(mn - sig[0], mn - sig[1]) else -1.0)
            twave.amplitude[lead] = pol * np.ptp(sig)
    twave.start.value = Iv(beg + limits.start, beg + limits.start)
    twave.end.value = Iv(beg + limits.end, beg + limits.end)
    #The duration of the T Wave must be greater than the QRS
    #(with a security margin)
    verify(twave.earlyend - twave.latestart > qrs.earlyend - qrs.latestart -
           C.TMARGIN)
    #The overlapping between the energy interval and the T Wave must be at
    #least the half of the duration of the energy interval.
    verify(
        Iv(twave.earlystart, twave.lateend).intersection(
            Iv(defl.earlystart, defl.lateend)).length >=
        (defl.lateend - defl.earlystart) / 2.0)
    #If the Deflection is a R-Deflection, we require a margin before
    #the end of the twave.
    if isinstance(defl, o.RDeflection):
        verify(twave.lateend - defl.time.end > C.TW_RDEF_MIN_DIST)
コード例 #20
0
ファイル: bigeminy.py プロジェクト: shuangte/construe
def _prev_rhythm_gconst(_, rhythm):
    """General constraints of a cardiac rhythm with the preceden one."""
    #A bigeminy cannot be preceded by another bigeminy or an extrasystole.
    verify(not isinstance(rhythm, (o.Bigeminy, o.Extrasystole)))
コード例 #21
0
ファイル: afib.py プロジェクト: minho17/construe
def _prev_rhythm_gconst(_, rhythm):
    """General constraints of a cardiac rhythm with the precedent one."""
    #An atrial fibrillation cannot be immediately preceded by another afib.
    verify(not isinstance(rhythm, o.Atrial_Fibrillation))