예제 #1
0
 def _def_gconst(pattern, _):
     """General constraints for the energy interval abstraction pattern"""
     verify(pattern.hypothesis.lateend < np.inf)
     #The margin to group consecutive fragments is 1 mm
     #Limits for the detection.
     beg = int(pattern.hypothesis.earlystart)
     end = int(pattern.hypothesis.lateend)
     #Now we get the energy accumulated in all leads.
     energy = None
     for lead in sig_buf.get_available_leads():
         lenerg, fbeg, fend = sig_buf.get_energy_fragment(
             beg, end, TWINDOW, lead)
         energy = lenerg if energy is None else energy + lenerg
     if energy is None:
         return 0.0
     #We get the already published fragments affecting our temporal support.
     conflictive = []
     published = SortedList(obs_buf.get_observations(o.Deflection))
     idx = published.bisect_left(pattern.hypothesis)
     if idx > 0 and published[idx - 1].lateend > beg:
         idx -= 1
     while (idx < len(published) and Iv(beg, end).overlap(
             Iv(published[idx].earlystart, published[idx].lateend))):
         conflictive.append(
             Iv(published[idx].earlystart - beg + fbeg,
                published[idx].lateend - beg + fbeg))
         idx += 1
     #We obtain the relative limits of the energy interval wrt the fragment
     iv_start = Iv(fbeg, fbeg + int(pattern.hypothesis.latestart - beg))
     iv_end = Iv(fend - int(end - pattern.hypothesis.earlyend), fend)
     #We look for the highest-level interval satisfying the limits.
     interval = None
     lev = 0
     while interval is None and lev <= 20:
         areas = [
             iv for iv in get_energy_intervals(energy, lev, group=TMARGIN)
             if iv.start in iv_start and iv.end in iv_end and all(
                 not iv.overlapm(ein) for ein in conflictive)
         ]
         #We sort the areas by energy, with the highest energy first.
         areas.sort(
             key=lambda interv: np.sum(energy[interv.start:interv.end + 1]),
             reverse=True)
         #Now we take the element indicated by the index.
         if len(areas) > int_idx:
             interval = areas[int_idx]
         else:
             lev += 1
     verify(interval is not None)
     pattern.hypothesis.start.set(interval.start + beg - fbeg,
                                  interval.start + beg - fbeg)
     pattern.hypothesis.end.set(interval.end + beg - fbeg,
                                interval.end + beg - fbeg)
     for lead in sig_buf.get_available_leads():
         pattern.hypothesis.level[lead] = lev
예제 #2
0
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))
예제 #3
0
def _characterize_signal(beg, end):
    """
    Characterizes the available signal in a specific time interval.

    Parameters
    ----------
    beg:
        Starting time point of the interval.
    end:
        Last time point of the interval.

    Returns
    -------
    out:
        sortedlist with one entry by lead. Each entry is a 5-size tuple with
        the lead, the signal samples, the relevant points to represent the
        samples, the baseline level estimation for the fragment, and the
        quality of the fragment in that lead.
    """
    siginfo = sortedcontainers.SortedList(key=lambda v: -v[4])
    for lead in sig_buf.get_available_leads():
        baseline, quality = characterize_baseline(lead, beg, end)
        sig = sig_buf.get_signal_fragment(beg, end, lead=lead)[0]
        if len(sig) == 0:
            return None
        #We build a signal simplification taking at most 9 points, and with
        #a minimum relevant deviation of 50 uV.
        points = DP.arrayRDP(sig, ph2dg(0.05), 9)
        siginfo.add((lead, sig, points, baseline, quality))
    return siginfo
예제 #4
0
def save_video(interp, fname, last=None, interval=50):
    """
    Saves a video with the sequence of interpretations as they were generated
    by the interpretation process, beginning with *interp* and using *last* as
    last frame. Video is stored in *fname* path. Duration of each frame is
    controlled by *interval*, in milliseconds.
    """
    interplist = []
    queue = deque([interp])
    while queue:
        head = queue.popleft()
        interplist.append(head)
        queue.extend(head.child)
    interplist.sort(key=lambda i:int(str(i)))
    if last is not None:
        interplist.append(last)
    sig = sig_buf.get_signal(sig_buf.get_available_leads()[0])
    fig = figure(figsize=(18, 3), dpi=100, tight_layout=True)

    def update_figure(idx):
        print(str(idx) + '/' + str(len(interplist)))
        intplt = interplist[idx]
        plot_observations(sig, intplt, fig, False)
        fig.gca().set_xbound(lower=0, upper=len(sig))
        return fig

    ani = animation.FuncAnimation(fig, update_figure, len(interplist),
                                  interval=interval, repeat=False)
    ani.save(fname, bitrate=2048)
예제 #5
0
파일: energy.py 프로젝트: minho17/construe
def get_combined_energy(start, end, max_level, group=ms2sp(80)):
    """
    This function obtains the energy intervals between two time points combined
    in a multilead fashion. And grouping by a distance criteria.

    Parameters
    ----------
    start:
        Start time point to get the observations with respect to the signal
        buffer.
    end:
        Finish time point to get the observations wrt the signal buffer.
    max_level:
        Maximum level to search for energy intervals. See the description of
        the level in the *get_energy_intervals* function.
    group:
        Distance used to group close observations.

    Returns
    -------
    out:
        Sorte list of *EnergyInterval* observations.
    """
    #Dictionaries to store the energy intervals for each lead
    dicts = {}
    for lead in sig_buf.get_available_leads():
        dicts[lead] = {}
        for i in range(max_level + 1):
            dicts[lead][i] = []
    #Energy intervals detection and combination
    idx = start
    while idx < end:
        wfs = {}
        for lead in dicts:
            wfs[lead] = get_deflection_observations(start + idx,
                                                    start + idx + TWINDOW,
                                                    lead=lead,
                                                    max_level=max_level,
                                                    group=group)
            for i in range(max_level + 1):
                if dicts[lead][i] and wfs[lead][i]:
                    if (wfs[lead][i][0].earlystart - dicts[lead][i][-1].lateend
                            <= group):
                        dicts[lead][i][-1].end.cpy(wfs[lead][i][0].start)
                        wfs[lead][i].pop(0)
                dicts[lead][i].extend(wfs[lead][i])
        idx += TWINDOW
    #Remove overlapping intervals
    combine_energy_intervals(list(dicts.values()))
    #Now we flatten the dictionaries, putting all the intervals in a sequence
    #sorted by the earlystart value.
    return SortedList(w for w in it.chain.from_iterable(
        it.chain.from_iterable(dic.values() for dic in dicts.values())))
예제 #6
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)
예제 #7
0
 def __onclick(self, event):
     """Manager to the click event on the figure."""
     #Left click
     if event.button in (1, 2, 3) and event.inaxes:
         trans = event.inaxes.transData
         #Distance from nodes (in pixels)
         for node in self.drnodes.copy():
             posit = self.pos[node]
             xn, yn = trans.transform(posit)
             dx, dy = (event.x - xn, event.y - yn)
             dist = sqrt(dx * dx + dy * dy)
             #Nodes have a 10-pixel radius
             if dist < 10:
                 #The clicked button will define the action
                 #Button 1: plot
                 #If the branch is already plot, we just show it
                 if event.button == 1:
                     if node in self._subfigs:
                         mgr = Gcf.get_fig_manager(
                             self._subfigs[node].fig.number)
                         mgr.window.activateWindow()
                         mgr.window.raise_()
                     else:
                         #Else plot the observations
                         signal = sig_buf.get_signal(
                             sig_buf.get_available_leads()[0])
                         #We have to keep a reference to the object to avoid
                         #garbage collection and loosing the event manager
                         #see http://matplotlib.org/users/event_handling.html
                         obsview = ObservationVisualizer(signal, node)
                         mgr = Gcf.get_fig_manager(obsview.fig.number)
                         mgr.window.move(0, 0)
                         obsview.fig.canvas.set_window_title(str(node))
                         self._subfigs[node] = obsview
                         obsview.draw()
                 #Button 2: Add child nodes of the selected one to the plot.
                 elif event.button == 2:
                     pyperclip.copy(str(node))
                     stack = [node]
                     while stack:
                         n = stack.pop()
                         self.drnodes.add(n)
                         if n is node or not n.is_firm:
                             stack.extend(self.graph[n].keys())
                     self.redraw()
                 #Button 3: Copy the branch name to the clipboard
                 elif event.button == 3:
                     pyperclip.copy(str(node))
예제 #8
0
def _contains_qrs(pattern):
    """
    Checks if inside the flutter fragment there is a waveform "identical" to
    the first environment QRS complex.
    """
    qrs = pattern.evidence[o.QRS][0]
    #We limit the duration of the QRS to check this condition.
    if qrs.lateend - qrs.earlystart not in C.NQRS_DUR:
        return False
    defls = pattern.evidence[o.Deflection]
    if len(defls) > 1:
        limit = (defls[-3].lateend if len(defls) > 2 else qrs.lateend)
        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,
                                                    defls[-1].earlystart,
                                                    lead=lead)[0]
            if len(sig[lead]) > 0 and len(qshape[lead].sig) > 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)
            return not signal_unmatch(sshape, qshape)
    return False
예제 #9
0
def _update_morphology(pattern):
    """
    Updates the reference morphology of the hypothesis of the pattern from
    the morphology of the beats that are part of the rhythm.
    """
    beats = pattern.evidence[o.QRS]
    for lead in sig_buf.get_available_leads():
        #We get the most common pattern as the reference.
        ctr = Counter(b.shape[lead].tag for b in beats if lead in b.shape)
        if ctr:
            mc = ctr.most_common(2)
            #If the most common is not unique, we move on
            if len(mc) == 2 and mc[0][1] == mc[1][1]:
                continue
            tag = mc[0][0]
            energy = np.mean([
                b.shape[lead].energy for b in beats
                if lead in b.shape and b.shape[lead].tag == tag
            ])
            if not lead in pattern.hypothesis.morph:
                pattern.hypothesis.morph[lead] = o.QRSShape()
            pattern.hypothesis.morph[lead].tag = tag
            pattern.hypothesis.morph[lead].energy = energy
예제 #10
0
print('Finished in {0:.3f} seconds'.format(time.time() - t0))
print('Created {0} interpretations ({1} kept alive)'.format(
    interp.counter, interp.ndescendants))

#plotter.save_video(interp, '/tmp/vid.mp4', cntr.best.node)

#Best explanation
print(cntr.best)
be = cntr.best.node
be.recover_all()
#print('List of resulting observations:')
#pp(list(be.get_observations()))

#Drawing of the best explanation
brview = plotter.plot_observations(
    sig_buf.get_signal(sig_buf.get_available_leads()[0]), be)
if args.o is not None:
    if args.video:
        plotter.save_video(interp, args.o, last=be)
    else:
        brview.fig.set_size_inches((12, 6))
        brview.fig.gca().set_xbound(
            lower=0,
            upper=len(sig_buf.get_signal(sig_buf.get_available_leads()[0])))
        brview.fig.savefig(args.o)
#Drawing of the search tree
#label_fncs = {}
##label_fncs['n'] = lambda br: str(br)
#label_fncs['e'] = lambda br: ''
#brview = plotter.plot_branch(interp, label_funcs=label_fncs, target=be,
#                             full_tree=True)
예제 #11
0
def _qrs_gconst(pattern, rdef):
    """
    Checks the general constraints of the QRS pattern transition.
    """
    #We ensure that the abstracted evidence has been observed.
    if rdef.earlystart != rdef.lateend:
        return
    #The energy level of the observed interval must be low
    hyp = pattern.hypothesis
    #First we try a guided QRS observation
    _guided_qrs_observation(hyp)
    if hyp.shape:
        hyp.freeze()
        return
    #Hypothesis initial limits
    beg = int(hyp.earlystart)
    if beg < 0:
        beg = 0
    end = int(hyp.lateend)
    #1. Signal characterization.
    siginfo = _characterize_signal(beg, end)
    verify(siginfo is not None)
    #2. Peak point estimation.
    peak = _find_peak(rdef, siginfo, beg, hyp.time)
    verify(peak is not None)
    #3. 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)
    #4. 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(beg + start + p - rdef.earlystart) /
                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
        hyp.shape[lead] = shape
    #There must be a recognizable QRS waveform in at least one lead.
    verify(hyp.shape)
    #5. The detected shapes may constrain the delineation area.
    llim = min(hyp.shape[lead].waves[0].l for lead in hyp.shape)
    if llim > 0:
        start = start + llim
        for lead in hyp.shape:
            hyp.shape[lead].move(-llim)
    ulim = max(hyp.shape[lead].waves[-1].r for lead in hyp.shape)
    if ulim < end - start:
        end = start + ulim
    #6. 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 hyp.shape.itervalues())
    #7. Segmentation points set
    hyp.paced = any(v[0] for v in limits.itervalues())
    hyp.time.value = Iv(beg + peak, beg + peak)
    hyp.start.value = Iv(beg + start, beg + start)
    hyp.end.value = Iv(beg + end, beg + end)
    ###################################################################
    #Amplitude conditions (between 0.5mV and 6.5 mV in at least one
    #lead or an identified pattern in most leads).
    ###################################################################
    verify(
        len(hyp.shape) > len(sig_buf.get_available_leads()) / 2.0
        or ph2dg(0.5) <= max(s.amplitude
                             for s in hyp.shape.itervalues()) <= ph2dg(6.5))
    hyp.freeze()
예제 #12
0
ltime = (pekbfs.last_time, t0)
while pekbfs.best is None:
    IN.get_more_evidence()
    acq_time = IN.get_acquisition_point()
    #HINT debug code
    fstr = 'Int: {0:05d} '
    for i in range(int(sp2ms(acq_time - pekbfs.last_time) / 1000.0)):
        fstr += '-'
    fstr += ' Acq: {1}'
    print(fstr.format(int(pekbfs.last_time), acq_time))
    #End of debug code
    pekbfs.step()
    if pekbfs.last_time > ltime[0]:
        ltime = (pekbfs.last_time, time.time())
    if ms2sp((time.time() - ltime[1]) * 1000.0) > MAX_DELAY:
        print('Pruning search')
        if pekbfs.open:
            prevopen = pekbfs.open
        pekbfs.prune()
print('Finished in {0:.3f} seconds'.format(time.time() - t0))
print('Created {0} interpretations'.format(interp.counter))
be = pekbfs.best
brview = plotter.plot_observations(
    sig_buf.get_signal(sig_buf.get_available_leads()[0]), pekbfs.best)

#Branches draw
label_fncs = {}
label_fncs['n'] = lambda br: str(br)
label_fncs['e'] = lambda br: ''
#brview = plotter.plot_branch(interp, label_funcs=label_fncs, target=pekbfs.best)
예제 #13
0
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')
예제 #14
0
    cntr.step(filt)
    if cntr.last_time > ltime[0]:
        ltime = (cntr.last_time, time.time())
    #If the distance between acquisition time and interpretation time is
    #excessive, the search tree is pruned.
    if ms2sp((time.time() - ltime[1]) * 1000.0) * TFACTOR > MAX_DELAY:
        print('Pruning search')
        cntr.prune()
print('Finished in {0:.3f} seconds'.format(time.time() - t0))
print('Created {0} interpretations ({1} kept alive)'.format(
    interp.counter, interp.ndescendants))

#plotter.save_video(interp, '/tmp/vid.mp4', cntr.best.node)

#Best explanation
print(cntr.best)
be = cntr.best.node
be.recover_all()
#print('List of resulting observations:')
#pp(list(be.get_observations()))

#Drawing of the best explanation
brview = plotter.plot_observations(
    sig_buf.get_signal(sig_buf.get_available_leads()[0]), be)
#Drawing of the search tree
#label_fncs = {}
##label_fncs['n'] = lambda br: str(br)
#label_fncs['e'] = lambda br: ''
#brview = plotter.plot_branch(interp, label_funcs=label_fncs, target=be,
#                             full_tree=True)