Esempio n. 1
0
def run(inp, opt, cfg):
    """
    calculate ppv from arterial waveform
    :param art: arterial waveform
    :return: max, min, upper envelope, lower envelope, respiratory rate, ppv
    """
    data = arr.interp_undefined(inp['pleth']['vals'])
    srate = inp['pleth']['srate']

    data = arr.resample_hz(data, srate, 100)
    srate = 100

    if len(data) < 30 * srate:
        return [{}, {}, {}, {}, {}, [], []]

    minlist, maxlist = arr.detect_peaks(data, srate)
    maxlist = maxlist[1:]

    # estimates the upper ue(n) and lower le(n) envelopes
    xa = np.array([data[idx] for idx in minlist])
    le = np.array([0] * len(data))
    for i in range(len(data)):
        be = np.array([b((i - idx) / (0.2 * srate)) for idx in minlist])
        s = sum(be)
        if s != 0:
            le[i] = np.dot(xa, be) / s

    xb = np.array([data[idx] for idx in maxlist])
    ue = np.array([0] * len(data))
    for i in range(len(data)):
        be = np.array([b((i - idx) / (0.2 * srate)) for idx in maxlist])
        s = sum(be)
        if s != 0:
            ue[i] = np.dot(xb, be) / s

    re = ue - le
    re[re < 0] = 0

    # estimates resp rate
    rr = arr.estimate_resp_rate(re, srate)

    # split by respiration
    nsamp_in_breath = int(srate * 60 / rr)
    m = int(len(data) / nsamp_in_breath)  # m segments exist
    pps = []
    for i in range(m - 1):
        imax = arr.max_idx(re, i * nsamp_in_breath, (i+2) * nsamp_in_breath)  # 50% overlapping
        imin = arr.min_idx(re, i * nsamp_in_breath, (i+2) * nsamp_in_breath)
        ppmax = re[imax]
        ppmin = re[imin]
        ppe = 2 * (ppmax - ppmin) / (ppmax + ppmin) * 100  # estimate
        if ppe > 50 or ppe < 0:
            continue

        pp = cfg['pp']
        if pp == 0:
            pp = ppe

        err = abs(ppe - pp)
        if err < 1:
            pp = ppe
        elif err < 25:
            pp = (pp + ppe) / 2
        else:
            pass  # dont update

        cfg['pp'] = pp

        pps.append({'dt': (i * nsamp_in_breath) / srate, 'val': pp})

    return [
        [{'dt': cfg['interval'], 'val': rr}],
        pps
    ]
Esempio n. 2
0
def run(inp, opt, cfg):
    """
    calculate ppv from arterial waveform
    :param art: arterial waveform
    :return: max, min, upper envelope, lower envelope, respiratory rate, ppv
    """
    global last_ppv

    data = arr.interp_undefined(inp['pleth']['vals'])
    srate = inp['pleth']['srate']

    data = arr.resample_hz(data, srate, 100)
    srate = 100

    if len(data) < 30 * srate:
        print('hr < 30')
        return

    # beat detection
    minlist, maxlist = arr.detect_peaks(data, srate)
    maxlist = maxlist[1:]

    # beat lengths
    beatlens = []
    beats_128 = []
    beats_128_valid = []
    for i in range(0, len(minlist) - 1):
        beatlen = minlist[i + 1] - minlist[i]  # in samps
        if not 30 < beatlen < 300:
            beats_128.append(None)
            continue

        pp = data[maxlist[i]] - data[minlist[i]]  # pulse pressure
        if not 20 < pp < 100:
            beats_128.append(None)
            continue

        beatlens.append(beatlen)
        beat = data[minlist[i]:minlist[i + 1]]
        resampled = arr.resample(beat, 128)
        beats_128.append(resampled)
        beats_128_valid.append(resampled)

    if not beats_128_valid:
        return

    avgbeat = np.array(beats_128_valid).mean(axis=0)

    meanlen = np.mean(beatlens)
    stdlen = np.std(beatlens)
    if stdlen > meanlen * 0.2:  # irregular rhythm
        return

    # remove beats with correlation < 0.9
    pulse_vals = []
    for i in range(0, len(minlist) - 1):
        if not beats_128[i]:
            continue
        if np.corrcoef(avgbeat, beats_128[i])[0, 1] < 0.9:
            continue
        pp = data[maxlist[i]] - data[minlist[i]]  # pulse pressure
        pulse_vals.append({'dt': minlist[i] / srate, 'val': pp})

    # estimates the upper env(n) and lower env(n) envelopes
    xa = np.array([data[idx] for idx in minlist])
    lower_env = np.array([0.0] * len(data))
    for i in range(len(data)):
        be = np.array([b((i - idx) / (0.2 * srate)) for idx in minlist])
        s = sum(be)
        if s != 0:
            lower_env[i] = np.dot(xa, be) / s

    xb = np.array([data[idx] for idx in maxlist])
    upper_env = np.array([0.0] * len(data))
    for i in range(len(data)):
        be = np.array([b((i - idx) / (0.2 * srate)) for idx in maxlist])
        s = sum(be)
        if s != 0:
            upper_env[i] = np.dot(xb, be) / s

    pulse_env = upper_env - lower_env
    pulse_env[pulse_env < 0.0] = 0.0

    # estimates resp rate
    rr = arr.estimate_resp_rate(pulse_env, srate)

    # split by respiration
    nsamp_in_breath = int(srate * 60 / rr)
    m = int(len(data) / nsamp_in_breath)  # m segments exist
    raw_pps = []
    pps = []
    for ibreath in np.arange(0, m - 1, 0.5):
        pps_breath = []
        for ppe in pulse_vals:
            if ibreath * nsamp_in_breath < ppe['dt'] * srate < (
                    ibreath + 1) * nsamp_in_breath:
                pps_breath.append(ppe['val'])
        if len(pps_breath) < 4:
            continue

        pp_min = min(pps_breath)
        pp_max = max(pps_breath)

        ppv = 2 * (pp_max - pp_min) / (pp_max + pp_min) * 100  # estimate
        if not 0 < ppv < 50:
            continue

            #       raw_pps.append({'dt': (ibreath * nsamp_in_breath) / srate, 'val': pp})
        #
        # kalman filter
        if last_ppv == 0:  # first time
            last_ppv = ppv
        elif abs(last_ppv - ppv) <= 1.0:
            ppv = last_ppv
        elif abs(last_ppv - ppv) <= 25.0:  # ppv cannot be changed abruptly
            ppv = (ppv + last_ppv) * 0.5
            last_ppv = ppv
        else:
            continue  # no update

        pps.append({
            'dt': ((ibreath + 1) * nsamp_in_breath) / srate,
            'val': int(ppv)
        })

    return [pps, pulse_vals, [{'dt': cfg['interval'], 'val': rr}]]
Esempio n. 3
0
def run(inp, opt, cfg):
    """
    calculate ppv from arterial waveform
    :param art: arterial waveform
    :return: max, min, upper envelope, lower envelope, respiratory rate, ppv
    """
    global last_ppv, last_spv

    data = arr.interp_undefined(inp['ART']['vals'])
    srate = inp['ART']['srate']

    data = arr.resample_hz(data, srate, 100)
    srate = 100

    if len(data) < 30 * srate:
        print('hr < 30')
        return

    # beat detection
    minlist, maxlist = arr.detect_peaks(data, srate)
    maxlist = maxlist[1:]

    # beat lengths
    beatlens = []
    beats_128 = []
    beats_128_valid = []
    for i in range(0, len(minlist) - 1):
        beatlen = minlist[i + 1] - minlist[i]  # in samps
        if not 30 < beatlen < 300:
            beats_128.append(None)
            continue

        pp = data[maxlist[i]] - data[minlist[i]]  # pulse pressure
        if not 20 < pp < 100:
            beats_128.append(None)
            continue

        beatlens.append(beatlen)
        beat = data[minlist[i]:minlist[i + 1]]
        resampled = arr.resample(beat, 128)
        beats_128.append(resampled)
        beats_128_valid.append(resampled)

    if not beats_128_valid:
        return

    avgbeat = np.array(beats_128_valid).mean(axis=0)

    meanlen = np.mean(beatlens)
    stdlen = np.std(beatlens)
    if stdlen > meanlen * 0.2:  # irregular rhythm
        return

    # remove beats with correlation < 0.9
    pp_vals = []
    sp_vals = []
    for i in range(0, len(minlist) - 1):
        if beats_128[i] is None or not len(beats_128[i]):
            continue
        if np.corrcoef(avgbeat, beats_128[i])[0, 1] < 0.9:
            continue
        pp = data[maxlist[i]] - data[minlist[i]]  # pulse pressure
        sp = data[maxlist[i]]
        pp_vals.append({'dt': minlist[i] / srate, 'val': pp})
        sp_vals.append({'dt': minlist[i] / srate, 'val': sp})

    dtstart = time.time()

    # estimates resp rate
    # upper env
    idx_start = max(min(minlist), min(maxlist))
    idx_end = min(max(minlist), max(maxlist))
    xa = scipy.interpolate.CubicSpline(
        maxlist, [data[idx] for idx in maxlist])(np.arange(idx_start, idx_end))

    # lower env
    xb = scipy.interpolate.CubicSpline(
        minlist, [data[idx] for idx in minlist])(np.arange(idx_start, idx_end))
    rr = arr.estimate_resp_rate(xa - xb, srate)

    dtend = time.time()
    #print('rr {}'.format(rr))

    # split by respiration
    nsamp_in_breath = int(srate * 60 / rr)
    m = int(len(data) / nsamp_in_breath)  # m segments exist

    raw_pps = []
    raw_sps = []
    ppvs = []
    spvs = []
    for ibreath in np.arange(0, m - 1, 0.5):
        pps_breath = []
        sps_breath = []

        for ppe in pp_vals:
            if ibreath * nsamp_in_breath < ppe['dt'] * srate < (
                    ibreath + 1) * nsamp_in_breath:
                pps_breath.append(ppe['val'])

        for spe in sp_vals:
            if ibreath * nsamp_in_breath < spe['dt'] * srate < (
                    ibreath + 1) * nsamp_in_breath:
                sps_breath.append(spe['val'])

        if len(pps_breath) < 4:
            continue

        if len(sps_breath) < 4:
            continue

        pp_min = min(pps_breath)
        pp_max = max(pps_breath)
        sp_min = min(sps_breath)
        sp_max = max(sps_breath)

        ppv = (pp_max - pp_min) / (pp_max + pp_min) * 200
        if not 0 < ppv < 50:
            continue

        spv = (sp_max - sp_min) / (sp_max + sp_min) * 200
        if not 0 < spv < 50:
            continue

        # kalman filter
        if last_ppv == 0:  # first time
            last_ppv = ppv
        elif abs(last_ppv - ppv) <= 1.0:
            ppv = last_ppv
        elif abs(last_ppv - ppv) <= 25.0:  # ppv cannot be changed abruptly
            ppv = (ppv + last_ppv) * 0.5
            last_ppv = ppv
        else:
            continue

        if last_spv == 0:  # first time
            last_spv = spv
        elif abs(last_spv - spv) <= 1.0:
            spv = last_spv
        elif abs(last_spv - spv) <= 25.0:  # ppv cannot be changed abruptly
            spv = (spv + last_spv) * 0.5
            last_spv = spv
        else:
            continue

        ppvs.append(ppv)
        spvs.append(spv)

    median_ppv = np.median(ppvs)
    median_spv = np.median(spvs)

    return [[{
        'dt': cfg['interval'],
        'val': median_ppv
    }], [{
        'dt': cfg['interval'],
        'val': median_spv
    }], [{
        'dt': cfg['interval'],
        'val': rr
    }]]