示例#1
0
def run(inp, opt, cfg):
    """
    http:#ocw.utm.my/file.php/38/SEB4223/07_ECG_Analysis_1_-_QRS_Detection.ppt%20%5BCompatibility%20Mode%5D.pdf
    """
    global hist_ppga, hist_hbi
    data = arr.interp_undefined(inp['pleth']['vals'])
    srate = inp['pleth']['srate']

    minlist, maxlist = arr.detect_peaks(data, srate)  # extract beats
    beat_res = [{'dt': idx / srate, 'val': 1} for idx in maxlist]

    ppga_res = []
    hbi_res = []
    ppga_perc_res = []
    hbi_perc_res = []
    spi_res = []
    for i in range(len(maxlist) - 1):
        dt = maxlist[i + 1] / srate

        hbi = (maxlist[i + 1] - maxlist[i]) / srate * 1000
        ppga = data[maxlist[i + 1]] - data[minlist[i]]

        #hbi_perc = hist_hbi.percentile(hbi) * 0.7 + st.norm.cdf(hbi, 754.7, 210.8) * 30
        hbi_perc = hist_hbi.percentile(hbi) * 0.7 + st.norm.cdf(hbi, 700,
                                                                100) * 30
        #ppga_perc = hist_ppga.percentile(ppga) * 0.7 + st.norm.cdf(ppga, 2.428, 1.896) * 30
        ppga_perc = hist_ppga.percentile(ppga) * 0.7 + st.norm.cdf(
            ppga, 1, 0.2) * 30
        # hbi_perc = hist_hbi.percentile(hbi) * 0.7 + hist_hbi_grp.percentile(hbi) * 0.3
        # ppga_perc = hist_ppga.percentile(ppga) * 0.7 + hist_ppga_grp.percentile(ppga) * 0.3

        spi = 100 - (0.7 * ppga_perc + 0.3 * hbi_perc)

        ppga_res.append({'dt': dt, 'val': ppga})
        hbi_res.append({'dt': dt, 'val': hbi})
        ppga_perc_res.append({'dt': dt, 'val': ppga_perc})
        hbi_perc_res.append({'dt': dt, 'val': hbi_perc})
        spi_res.append({'dt': dt, 'val': spi})

        hist_hbi.learn(hbi)
        hist_ppga.learn(ppga)

    return [beat_res, ppga_res, hbi_res, ppga_perc_res, hbi_perc_res, spi_res]
示例#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}]]
示例#3
0
ppgas = []

import os
idir = r'C:\Users\lucid80\Desktop\SPI_PLETH'
#odir = r'C:\Users\lucid80\Desktop\SPI_PLETH'
filenames = os.listdir(idir)
for filename in filenames:
    print(filename)
    ipath = os.path.join(idir, filename)
    vit = vitalfile.VitalFile(ipath, ['SPI', 'PLETH'])
    vals = vit.get_samples('PLETH')
    srate = 100
    for istart in range(0, len(vals), 60*srate):
        data = vals[istart:istart+60*srate]
        try:
            minlist, maxlist = arr.detect_peaks(data, 100)  # extract beats
            for i in range(len(maxlist) - 1):
                hbi = (maxlist[i + 1] - maxlist[i]) / srate * 1000
                ppga = data[maxlist[i + 1]] - data[minlist[i]]
                hbis.append(hbi)
                ppgas.append(ppga)
                hist_hbi.learn(hbi)
                hist_ppga.learn(ppga)
        except:
            pass
#   print('{}\t{}\t{}\t{}'.format(np.mean(hbis), np.std(hbis), np.mean(ppgas), np.std(ppgas)))
print(','.join(map(str, hist_hbi.bins)))
print(','.join(map(str, hist_ppga.bins)))


#import scipy.stats as st
示例#4
0
def run(inp, opt, cfg):
    ecg_data = arr.interp_undefined(inp['ecg']['vals'])
    ecg_srate = inp['ecg']['srate']

    pleth_data = arr.interp_undefined(inp['pleth']['vals'])
    pleth_srate = inp['pleth']['srate']
    pleth_data = arr.band_pass(pleth_data, pleth_srate, 0.5, 15)

    ecg_rlist = arr.detect_qrs(ecg_data, ecg_srate)
    pleth_minlist, pleth_maxlist = arr.detect_peaks(pleth_data, pleth_srate)

    dpleth = np.diff(pleth_data)
    pleth_dmaxlist = [
    ]  # index of the maximum slope between peak and nadir in pleth
    for i in range(len(pleth_minlist)):  # maxlist is one less than minlist
        dmax_idx = arr.max_idx(dpleth, pleth_minlist[i], pleth_maxlist[i + 1])
        pleth_dmaxlist.append(dmax_idx)

    pttmax_list = []
    pttmin_list = []
    pttdmax_list = []
    for i in range(len(ecg_rlist) - 1):
        if len(pleth_minlist) == 0:
            continue
        if len(pleth_maxlist) == 0:
            continue

        rpeak_dt = ecg_rlist[i] / ecg_srate
        rpeak_dt_next = ecg_rlist[i + 1] / ecg_srate
        if rpeak_dt < cfg['overlap']:
            continue

        # find first min in pleth after rpeak_dt in ecg
        found_minidx = 0
        for minidx in pleth_minlist:
            if minidx > rpeak_dt * pleth_srate:
                found_minidx = minidx
                break
            elif minidx > rpeak_dt_next * pleth_srate:
                break
        if found_minidx == 0:
            continue

        # find first dmax in pleth after rpeak_dt in ecg
        found_dmaxidx = 0
        for dmaxidx in pleth_dmaxlist:
            if dmaxidx > rpeak_dt * pleth_srate:
                found_dmaxidx = dmaxidx
                break
            elif dmaxidx > rpeak_dt_next * pleth_srate:
                break
        if found_dmaxidx == 0:
            continue

        # find first dmax in pleth after rpeak_dt in ecg
        found_maxidx = 0
        for maxidx in pleth_maxlist:
            if maxidx > rpeak_dt * pleth_srate:
                found_maxidx = maxidx
                break
            elif maxidx > rpeak_dt_next * pleth_srate:
                break
        if found_maxidx == 0:
            continue

        max_dt = found_maxidx / pleth_srate
        if max_dt > cfg['interval']:
            continue
        min_dt = found_minidx / pleth_srate
        dmax_dt = found_dmaxidx / pleth_srate

        pttmax_list.append({'dt': max_dt, 'val': (max_dt - rpeak_dt) * 1000})
        pttdmax_list.append({
            'dt': dmax_dt,
            'val': (dmax_dt - rpeak_dt) * 1000
        })
        pttmin_list.append({'dt': min_dt, 'val': (min_dt - rpeak_dt) * 1000})

    return [
        pttmin_list, pttdmax_list,
        arr.get_samples(ecg_data, ecg_srate, ecg_rlist), pttmax_list
    ]
示例#5
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
    ]
示例#6
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
    }]]
示例#7
0
def run(inp, opt, cfg):
    """
    calculate svv from arterial waveform
    :param art: arterial waveform
    :return: max, min, upper envelope, lower envelope, respiratory rate, ppv
    """
    data = arr.interp_undefined(inp['art1']['vals'])
    srate = inp['art1']['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:]  # make the same length

    # calculate each beat's std and put it at the peak time
    stds = []
    lzs = []
    for i in range(len(minlist) - 1):
        maxidx = maxlist[i]

        beat = data[minlist[i]:minlist[i + 1]]
        if max(beat) - min(beat) < 20:
            continue

        s = np.std(beat)
        stds.append({'dt': maxidx / srate, 'val': s})

        sbp = np.max(beat)
        dbp = beat[0]
        lz = (sbp - dbp) / (sbp + dbp)  # 0.1~0.3
        lzs.append({'dt': maxidx / srate, 'val': lz})

    # estimates resp rate
    rr = np.median([o['val'] for o in inp['vent_rr']])
    if not rr > 1:
        return [[], [], [], []]

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

    # std
    svv_stds = []
    for i in range(m - 1):  # 50% overlapping
        this_breath_stds = []
        for j in range(len(stds)):
            if i * nsamp_in_breath <= stds[j]['dt'] * srate < (
                    i + 2) * nsamp_in_breath:
                this_breath_stds.append(stds[j]['val'])
        svmax = np.max(this_breath_stds)
        svmin = np.min(this_breath_stds)

        svv_stde = 2 * (svmax - svmin) * 100 / (svmax + svmin)  # estimate
        if svv_stde > 40 or svv_stde < 0:
            continue
        svv_stds.append(svv_stde)

    svv_stde = np.median(svv_stds)
    if svv_stde < 0:
        svv_stde = 0

    svv_std = cfg['svv_std']
    if svv_std == 0 or svv_std is None:
        svv_std = svv_stde
    err = abs(svv_stde - svv_std)
    if err < 5:
        svv_std = svv_stde
    elif err < 25:
        svv_std = (svv_std + svv_stde) / 2
    else:
        pass  # dont update
    cfg['svv_std'] = svv_std

    # lz
    svv_lzs = []
    for i in range(m - 1):  # 50% overlapping
        this_breath_lzs = []
        for j in range(len(lzs)):
            if i * nsamp_in_breath <= lzs[j]['dt'] * srate < (
                    i + 2) * nsamp_in_breath:
                this_breath_lzs.append(lzs[j]['val'])
        svmax = np.max(this_breath_lzs)
        svmin = np.min(this_breath_lzs)

        svv_lze = 2 * (svmax - svmin) * 100 / (svmax + svmin)  # estimate

        if svv_lze > 40 or svv_lze < 0:
            continue
        svv_lzs.append(svv_lze)

    svv_lze = np.median(svv_lzs)
    if svv_lze < 0:
        svv_lze = 0

    svv_lz = cfg['svv_lz']
    if svv_lz == 0 or svv_lz is None:
        svv_lz = svv_lze
    err = abs(svv_lze - svv_lz)
    if err < 5:
        svv_lz = svv_lze
    elif err < 25:
        svv_lz = (svv_lz + svv_lze) / 2
    else:
        pass  # dont update
    cfg['svv_lz'] = svv_lz

    return [
        stds, [{
            'dt': cfg['interval'],
            'val': svv_std
        }], lzs, [{
            'dt': cfg['interval'],
            'val': svv_lz
        }]
    ]