def filt(Signal=None, SamplingRate=1000., UpperCutoff=None, LowerCutoff=100., Order=4.): """ Filters an input EMG signal. If only input signal is provide, it returns the filtered EMG signal assuming a 1000Hz sampling frequency and a default high-pass filter with a cutoff frequency of 100Hz. Kwargs: Signal (array): input signal. SamplingRate (float): Sampling frequency (Hz). UpperCutoff (float): Low-pass filter cutoff frequency (Hz). LowerCutoff (float): High-pass filter cutoff frequency (Hz). Order (int): Filter order. Kwrvals: Signal (array): output filtered signal. Configurable fields:{"name": "emg.filt", "config": {"SamplingRate": "1000.", "LowerCutoff": "100.", "Order": "4."}, "inputs": ["Signal", "UpperCutoff"], "outputs": ["Signal"]} See Also: flt.zpdfr Notes: Example: Signal = load(...) SamplingRate = ... res = filt(Signal=Signal, SamplingRate=SamplingRate) plot(res['Signal']) References: .. [1] """ # Check if Signal is None: raise TypeError, "An input signal is needed." # Filter signal Signal = flt.zpdfr(Signal=Signal, SamplingRate=SamplingRate, UpperCutoff=UpperCutoff, LowerCutoff=LowerCutoff, Order=Order)['Signal'] # Output kwrvals = {} kwrvals['Signal'] = Signal return kwrvals
def filt(Signal=None, SamplingRate=1000., UpperCutoff=8., LowerCutoff=1., Order=4.): """ Filters an input BVP signal. If only input signal is provide, it returns the filtered signal assuming a 1000Hz sampling frequency and the default filter parameters: low-pass filter with cutoff frequency of 8Hz followed by a high-pass filter with cutoff frequency of 1Hz. Kwargs: Signal (array): input signal. SamplingRate (float): sampling frequency (Hz). UpperCutoff (float): Low-pass filter cutoff frequency (Hz). LowerCutoff (float): High-pass filter cutoff frequency (Hz). Order (int): Filter order. Kwrvals: Signal (array): output filtered signal. Configurable fields:{"name": "bvp.filt", "config": {"UpperCutoff": "8.", "SamplingRate": "1000.", "LowerCutoff": "1.", "Order": "4."}, "inputs": ["Signal"], "outputs": ["Signal"]} See Also: flt.zpdfr Notes: Example: References: .. [1] """ # Check if Signal is None: raise TypeError, "An input signal is needed." # Filter signal Signal = flt.zpdfr(Signal=Signal, SamplingRate=SamplingRate, UpperCutoff=UpperCutoff, LowerCutoff=LowerCutoff, Order=Order)['Signal'] # Output kwrvals = {} kwrvals['Signal'] = Signal return kwrvals
def hamilton(hand, Signal=None, SamplingRate=1000., Filter=True, init=(), Show=0, show2=0, show3=0, TH=None): """ Algorithm to detect ECG beat indexes. Kwargs: Signal (array): input filtered ECG signal. SamplingRate (float): Sampling frequency (Hz). Filter (dict): Filter parameters. Kwrvals: Signal (array): output filtered signal if Filter is defined. R (array): R peak indexes (or instants in seconds if sampling rate is defined). init (dict): dict with initial values of some variables npeaks (int): number of detected heart beats. indexqrs (int): most recent QRS complex index. indexnoise (int): most recent noise peak index. indexrr (int): most recent R-to-R interval index. qrspeakbuffer (array): 8 most recent QRS complexes. noisepeakbuffer (array): 8 most recent noise peaks. rrinterval (array): 8 most recent R-to-R intervals. DT (float): QRS complex detection threshold. offset (int): signal start in samples. Configurable fields:{"name": "models.hamilton", "config": {"SamplingRate": "1000."}, "inputs": ["Signal", "Filter", "init"], "outputs": ["Signal", "R", "init", "npeaks", "indexqrs", "indexnoise", "indexrr", "qrspeakbuffer", "noisepeakbuffer", "rrinterval", "DT", "offset"]} See Also: filt Notes: Example: References: .. [1] P.S. Hamilton, Open Source ECG Analysis Software Documentation, E.P.Limited http://www.eplimited.com/osea13.pdf """ # Check if Signal is None: raise TypeError("An input signal is needed.") # 0.1 - Choose sign of peaks (batch) # up = definepeak(Signal, SamplingRate) up = 1 if Filter: # 0.15 - Remove EMG, powerline and baseline shift emgsamples = 0.028 * SamplingRate movemg = np.ones(emgsamples) / emgsamples rawbase = prepro.medFIR(Signal, SamplingRate)['Signal'] rawend = ss.convolve(rawbase, movemg, mode='same') RawSignal = np.copy(rawend) else: RawSignal = np.copy(Signal) # 0.2 - Get transformed signal UpperCutoff = 16. LowerCutoff = 8. Order = 4 Signal = flt.zpdfr(Signal=Signal, SamplingRate=SamplingRate, UpperCutoff=UpperCutoff, LowerCutoff=LowerCutoff, Order=Order)['Signal'] Signal = abs(np.diff(Signal, 1) * SamplingRate) # Signal = flt.smooth(Signal=Signal, Window={'Length': 0.08*SamplingRate, 'Type': 'hamming', # 'Parameters': None})['Signal'] Signal = moving_average(Signal, int(0.15 * SamplingRate), cut=True) # 0.3 - Initialize Buffers if not init: init_ecg = 8 if len(Signal) / (1. * SamplingRate) < init_ecg: init_ecg = int(len(Signal) / (1. * SamplingRate)) qrspeakbuffer = np.zeros(init_ecg) noisepeakbuffer = np.zeros(init_ecg) print init_ecg rrinterval = SamplingRate * np.ones(init_ecg) a, b = 0, int(SamplingRate) all_peaks = np.array(peakd.sgndiff(Signal)['Peak']) nulldiffs = np.where(np.diff(Signal) == 0)[0] all_peaks = np.concatenate((all_peaks, nulldiffs)) all_peaks = np.array(sorted(frozenset(all_peaks))) for i in range(0, init_ecg): peaks = peakd.sgndiff(Signal=Signal[a:b])['Peak'] nulldiffs = np.where(np.diff(Signal[a:b]) == 0)[0] peaks = np.concatenate((peaks, nulldiffs)) peaks = np.array(sorted(frozenset(peaks))) try: qrspeakbuffer[i] = max(Signal[a:b][peaks]) except Exception as e: print e a += int(SamplingRate) b += int(SamplingRate) # Set Thresholds # Detection_Threshold = Average_Noise_Peak + TH*(Average_QRS_Peak-Average_Noise_Peak) ANP = np.median(noisepeakbuffer) AQRSP = np.median(qrspeakbuffer) if TH is None: TH = 0.45 # 0.45 for CVP, 0.475 for ECGIDDB, 0.35 for PTB # 0.3125 - 0.475 DT = ANP + TH * (AQRSP - ANP) init = {} init['qrspeakbuffer'] = qrspeakbuffer init['noisepeakbuffer'] = noisepeakbuffer init['rrinterval'] = rrinterval init['indexqrs'] = 0 init['indexnoise'] = 0 init['indexrr'] = 0 init['DT'] = DT init['npeaks'] = 0 beats = [] twaves = np.array([]) # ---> Heuristic Thresholds lim = int(np.ceil(0.2 * SamplingRate)) elapselim = int(np.ceil(0.36 * SamplingRate)) slopelim = 0.7 artlim = 2.75 diff_nr = int(np.ceil(0.01 * SamplingRate)) if diff_nr <= 1: diff_nr = 2 # ---> Peak Detection for f in all_peaks: # 1 - Checking if f-peak is larger than any peak following or preceding it by less than 200 ms peak_cond = np.array( (all_peaks > f - lim) * (all_peaks < f + lim) * (all_peaks != f)) peaks_within = all_peaks[peak_cond] if peaks_within.any() and max(Signal[peaks_within]) > Signal[f]: # # ---> Update noise buffer # init['noisepeakbuffer'][init['indexnoise']] = Signal[f] # init['indexnoise'] += 1 # # print 'NOISE' # if init['indexnoise'] == init_ecg: # init['indexnoise'] = 0 # # print 'TINY' continue # print 'DT', init['DT'] if Signal[f] > init['DT']: #---------------------FRANCIS--------------------- # 2 - look for both positive and negative slopes in raw signal # if f < diff_nr: # diff_now = np.diff(RawSignal[0:f+diff_nr]) # elif f + diff_nr >= len(RawSignal): # diff_now = np.diff(RawSignal[f-diff_nr:len(Signal)]) # else: # diff_now = np.diff(RawSignal[f-diff_nr:f+diff_nr]) # diff_signer = diff_now[ diff_now > 0] # # print 'diff signs:', diff_signer, '\n', diff_now # if len(diff_signer) == 0 or len(diff_signer) == len(diff_now): # print 'BASELINE SHIFT' # continue #RR INTERVALS if init['npeaks'] > 0: # 3 - in here we check point 3 of the Hamilton paper (checking whether T-wave or not) prev_rpeak = beats[init['npeaks'] - 1] elapsed = f - prev_rpeak # print 'elapsed', elapsed # if the previous peak was within 360 ms interval if elapsed < elapselim: # check current and previous slopes # print '---', f, prev_rpeak, diff_nr, '---' if f < diff_nr: diff_now = np.diff(Signal[0:f + diff_nr]) elif f + diff_nr >= len(Signal): diff_now = np.diff(Signal[f - diff_nr:len(Signal)]) else: diff_now = np.diff(Signal[f - diff_nr:f + diff_nr]) if prev_rpeak < diff_nr: diff_prev = np.diff(Signal[0:prev_rpeak + diff_nr]) elif prev_rpeak + diff_nr >= len(Signal): diff_prev = np.diff(Signal[prev_rpeak - diff_nr:len(Signal)]) else: diff_prev = np.diff( Signal[prev_rpeak - diff_nr:prev_rpeak + diff_nr]) slope_now = np.max(np.abs(diff_now)) slope_prev = np.max(np.abs(diff_prev)) # print 'diff_now', diff_now # print 'diff_prev', diff_prev # print '\tf -->', f, 'slopes: now -', slope_now, 'prev -', slope_prev, 'lim -', slopelim*slope_prev if slope_now < slopelim * slope_prev: # print 'T-WAVE' twaves = np.concatenate((twaves, [f])) continue if not hand or Signal[f] < artlim * np.median(qrspeakbuffer): # print 'GOT IT GOOD', f beats += [int(f)] else: continue # ---> Update R-R interval init['rrinterval'][init['indexrr']] = beats[ init['npeaks']] - beats[init['npeaks'] - 1] init['indexrr'] += 1 if init['indexrr'] == init_ecg: init['indexrr'] = 0 elif not hand or Signal[f] < artlim * np.median(qrspeakbuffer): # print 'GOT IT GOOD', f beats += [int(f)] else: continue # ---> Update QRS buffer init['npeaks'] += 1 qrspeakbuffer[init['indexqrs']] = Signal[f] init['indexqrs'] += 1 if init['indexqrs'] == init_ecg: init['indexqrs'] = 0 if Signal[f] <= init['DT']: RRM = np.median(init['rrinterval']) if len(beats) >= 2: elapsed = f - beats[init['npeaks'] - 1] if elapsed >= 1.5 * RRM and elapsed > elapselim: prev_rpeak = beats[init['npeaks'] - 1] rrpeak_cond = np.array( (all_peaks > prev_rpeak + lim) * (all_peaks < f + 1) * (all_peaks != twaves)) peaks_rr = all_peaks[rrpeak_cond] contender = peaks_rr[np.argmax(Signal[peaks_rr])] if Signal[contender] > 0.5 * init['DT']: # print 'GOT IT RR', contender, f beats += [int(contender)] # ---> Update R-R interval if init['npeaks'] > 0: init['rrinterval'][init['indexrr']] = beats[ init['npeaks']] - beats[init['npeaks'] - 1] init['indexrr'] += 1 if init['indexrr'] == init_ecg: init['indexrr'] = 0 # ---> Update QRS buffer init['npeaks'] += 1 qrspeakbuffer[init['indexqrs']] = Signal[contender] init['indexqrs'] += 1 if init['indexqrs'] == init_ecg: init['indexqrs'] = 0 else: # ---> Update noise buffer init['noisepeakbuffer'][init['indexnoise']] = Signal[f] init['indexnoise'] += 1 # print 'NOISE' if init['indexnoise'] == init_ecg: init['indexnoise'] = 0 else: # ---> Update noise buffer init['noisepeakbuffer'][init['indexnoise']] = Signal[f] init['indexnoise'] += 1 # print 'NOISE' if init['indexnoise'] == init_ecg: init['indexnoise'] = 0 else: # ---> Update noise buffer init['noisepeakbuffer'][init['indexnoise']] = Signal[f] init['indexnoise'] += 1 # print 'NOISE' if init['indexnoise'] == init_ecg: init['indexnoise'] = 0 if Show: fig = pl.figure() mngr = pl.get_current_fig_manager() mngr.window.setGeometry(950, 50, 1000, 800) ax = fig.add_subplot(211) ax.plot(Signal, 'b', label='Signal') ax.grid('on') ax.axis('tight') ax.plot(all_peaks, Signal[all_peaks], 'ko', ms=10, label='peaks') if np.any(np.array(beats)): ax.plot(np.array(beats), Signal[np.array(beats)], 'g^', ms=10, label='rpeak') range_aid = range(len(Signal)) ax.plot(range_aid, init['DT'] * np.ones(len(range_aid)), 'r--', label='DT') ax.legend(('Processed Signal', 'all peaks', 'R-peaks', 'DT'), 'best', shadow=True) ax = fig.add_subplot(212) ax.plot(RawSignal, 'b', label='Signal') ax.grid('on') ax.axis('tight') ax.plot(all_peaks, RawSignal[all_peaks], 'ko', ms=10, label='peaks') if np.any(np.array(beats)): ax.plot(np.array(beats), RawSignal[np.array(beats)], 'g^', ms=10, label='rpeak') pl.show() if raw_input('_') == 'q': sys.exit() pl.close() # --> Update Detection Threshold ANP = np.median(init['noisepeakbuffer']) AQRSP = np.median(qrspeakbuffer) init['DT'] = ANP + TH * (AQRSP - ANP) if show3: fig = pl.figure() mngr = pl.get_current_fig_manager() mngr.window.setGeometry(950, 50, 1000, 800) ax = fig.add_subplot(111) ax.plot(Signal, 'b', label='Signal') ax.grid('on') ax.axis('tight') if np.any(np.array(beats)): ax.plot(np.array(beats), Signal[np.array(beats)], 'g^', ms=10, label='rpeak') # 8 - Find the R-peak exactly search = int(np.ceil(0.15 * SamplingRate)) adjacency = int(np.ceil(0.03 * SamplingRate)) diff_nr = int(np.ceil(0.01 * SamplingRate)) if diff_nr <= 1: diff_nr = 2 rawbeats = [] for b in xrange(len(beats)): if beats[b] - search < 0: rawwindow = RawSignal[0:beats[b] + search] add = 0 elif beats[b] + search >= len(RawSignal): rawwindow = RawSignal[beats[b] - search:len(RawSignal)] add = beats[b] - search else: rawwindow = RawSignal[beats[b] - search:beats[b] + search] add = beats[b] - search # ----- get peaks ----- if up: w_peaks = peakd.sgndiff(Signal=rawwindow)['Peak'] else: w_peaks = peakd.sgndiff(Signal=rawwindow, a=1)['Peak'] zerdiffs = np.where(np.diff(rawwindow) == 0)[0] w_peaks = np.concatenate((w_peaks, zerdiffs)) if up: pospeaks = sorted(zip(rawwindow[w_peaks], w_peaks), reverse=True) else: pospeaks = sorted(zip(rawwindow[w_peaks], w_peaks)) try: twopeaks = [pospeaks[0]] except IndexError: twopeaks = [] # ----------- getting peaks ----------- for i in xrange(len(pospeaks) - 1): if abs(pospeaks[0][1] - pospeaks[i + 1][1]) > adjacency: twopeaks.append(pospeaks[i + 1]) break poslen = len(twopeaks) # print twopeaks, poslen, diff_nr, twopeaks[1][1]-diff_nr+1, twopeaks[1][1]+diff_nr-1 if poslen == 2: # --- get maximum slope for max peak --- if twopeaks[0][1] < diff_nr: diff_f = np.diff(rawwindow[0:twopeaks[0][1] + diff_nr]) elif twopeaks[0][1] + diff_nr >= len(rawwindow): diff_f = np.diff(rawwindow[twopeaks[0][1] - diff_nr:len(rawwindow)]) else: diff_f = np.diff(rawwindow[twopeaks[0][1] - diff_nr:twopeaks[0][1] + diff_nr]) max_f = np.max(np.abs(diff_f)) # --- get maximum slope for second peak --- if twopeaks[1][1] < diff_nr: diff_s = np.diff(rawwindow[0:twopeaks[1][1] + diff_nr - 1]) elif twopeaks[1][1] + diff_nr >= len(rawwindow): diff_s = np.diff(rawwindow[twopeaks[1][1] - diff_nr + 1:len(rawwindow)]) else: diff_s = np.diff(rawwindow[twopeaks[1][1] - diff_nr + 1:twopeaks[1][1] + diff_nr - 1]) # print diff_s, np.abs(diff_s) max_s = np.max(np.abs(diff_s)) if show2: print 'diffs, main', diff_f, max_f, '\nsec', diff_s, max_s if max_f > max_s: # print '\tbigup' assignup = [twopeaks[0][0], twopeaks[0][1]] else: # print '\tsmallup' assignup = [twopeaks[1][0], twopeaks[1][1]] rawbeats.append(assignup[1] + add) elif poslen == 1: rawbeats.append(twopeaks[0][1] + add) else: rawbeats.append(beats[b]) if show2: fig = pl.figure() mngr = pl.get_current_fig_manager() mngr.window.setGeometry(950, 50, 1000, 800) ax = fig.add_subplot(111) ax.plot(rawwindow, 'b') for i in xrange(poslen): ax.plot(twopeaks[i][1], twopeaks[i][0], 'bo', markersize=10) ax.plot(rawbeats[b] - add, rawwindow[rawbeats[b] - add], 'yo', markersize=7) ax.grid('on') ax.axis('tight') pl.show() raw_input('---') pl.close() # kwrvals kwrvals = {} kwrvals['Signal'] = RawSignal kwrvals['init'] = init kwrvals['R'] = sorted(list( frozenset(rawbeats))) #/SamplingRate if SamplingRate else beats return kwrvals
def filt(Signal=None, SamplingRate=1000., UpperCutoff=16., LowerCutoff=8., Order=4): """ Filters an input ECG signal. By default, the return is the filtered Signal assuming a 1000Hz sampling frequency and the following filter sequence: 1. 4th order low-pass filter with cutoff frequency of 16Hz; 2. 4th order high-pass filter with cutoff frequency of 8Hz; 3. d[]/dt; 4. 80ms Hamming Window Smooth. Kwargs: Signal (array): input signal. SamplingRate (float): Sampling frequency (Hz). UpperCutoff (float): Low-pass filter cutoff frequency (Hz). LowerCutoff (float): High-pass filter cutoff frequency (Hz). Order (int): Filter order. Kwrvals: Signal (array): output filtered signal. Configurable fields:{"name": "ecg.filt", "config": {"UpperCutoff": "16.", "SamplingRate": "1000.", "LowerCutoff": "8.", "Order": "4"}, "inputs": ["Signal"], "outputs": ["Signal"]} See Also: flt.zpdfr flt.smooth Notes: Example: Signal = load(...) SamplingRate = ... res = filt(Signal=Signal, SamplingRate=SamplingRate) plot(res['Signal']) References: .. [1] P.S. Hamilton, Open Source ECG Analysis Software Documentation, E.P.Limited http://www.eplimited.com/osea13.pdf """ # Check if Signal is None: raise TypeError, "An input signal is needed." # Filter signal Signal = flt.zpdfr(Signal=Signal, SamplingRate=SamplingRate, UpperCutoff=UpperCutoff, LowerCutoff=LowerCutoff, Order=Order)['Signal'] # d[]/dt Signal = abs(scipy.diff(Signal, 1) * SamplingRate) # Smooth Signal = flt.smooth(Signal=Signal, Window={ 'Length': 0.08 * SamplingRate, 'Type': 'hamming', 'Parameters': None })['Signal'] # Signal=Signal[0.1*SamplingRate:] # Output kwrvals = {} kwrvals['Signal'] = Signal return kwrvals
def KBKSCR(Signal=None, SamplingRate=1000.): """ Detects and extracts Skin Conductivity Responses (SCRs) information such as: SCRs amplitudes, onsets, peak instant, rise, and half-recovery times. Kwargs: Signal (array): input EDA signal. SamplingRate (float): Sampling frequency (Hz). Kwrvals: Signal (array): output filtered signal (see notes 1) Amplitude (array): signal pulses amplitudes (in the units of the input signal) Onset (array): indexes (or instants in seconds, see notes 2.a) of the SCRs onsets Peak (array): indexes (or instants in seconds, see notes 2.a) of the SCRs peaks TODO: Rise (array): SCRs rise times (in seconds) TODO: HalfRecovery (array): SCRs half-recovery times (in seconds) See Also: flt.zpdfr Notes: 1 - If the sampling rate is defined, then: a) keys 'onset', and 'peak' are converted to instants of occurrence in seconds. 2- Less sensitive than Gamboa algorithm, but does not solve the overlapping SCRs problem. Example: References: .. [1] K.H. Kim, S.W. Bang, and S.R. Kim "Emotion recognition system using short-term monitoring of physiological signals" Med. Biol. Eng. Comput., 2004, 42, 419-427 """ # Check if Signal is None: raise TypeError, "An input signal is needed." SamplingRate = float(SamplingRate) # Low-pass filter and Downsampling Order = 4 UpperCutoff = 20. Signal = flt.zpdfr(Signal=Signal, SamplingRate=SamplingRate, UpperCutoff=UpperCutoff, LowerCutoff=None, Order=Order)['Signal'] k = int(SamplingRate / UpperCutoff) Signal = Signal[::k] # Differentiation ResSignal = np.diff(Signal, 1) # Smoothing Convolution with Bartlett (20) ResSignal = flt.smooth(Signal=ResSignal, Window={ 'Length': 20, 'Type': 'bartlett', 'Parameters': None })['Signal'] # Double Thresholding zc = tls.zerocross(Signal=ResSignal)['ZC'] if (np.all(ResSignal[:zc[0]] > 0)): zc = zc[1:] if (np.all(ResSignal[zc[-1]:] > 0)): zc = zc[:-1] # Exclude SCRs with an amplitude smaller than 10% of the maximum thres = 0.1 * np.max(ResSignal) scrs, amps, ZC, pks = [], [], [], [] for i in range(0, len(zc) - 1, 2): scrs += [ResSignal[zc[i]:zc[i + 1]]] aux = scrs[-1].max() if (aux > thres): amps += [aux] ZC += [zc[i]] ZC += [zc[i + 1]] pks += [zc[i] + np.argmax(ResSignal[zc[i]:zc[i + 1]])] scrs, amps, ZC, pks = np.array(scrs), np.array(amps), np.array( ZC), np.array(pks) if SamplingRate: dt = 1 / UpperCutoff ZC *= dt pks *= dt # kwrvals kwrvals = {} kwrvals['Signal'] = Signal kwrvals['Amplitude'] = amps kwrvals['Onset'] = ZC[::2] # kwrvals['HalfRise']= kwrvals['Peak'] = pks # kwrvals['HalfRecovery']= # kwrvals['RiseTime']= # kwrvals['HalfDecayTime']= return kwrvals
def ssf(Signal=None, SamplingRate=1000., Filter={}): """ Determines Signal peaks. Kwargs: Signal (array): input signal SamplingRate (float): Sampling frequency (Hz) Filter (dict): Filter coefficients Kwrvals: Signal (array): Onset (array): SSF (array): See Also: Notes: Example: References: .. [1] W.Zong, T.Heldt, G.B. Moody, and R.G. Mark, "An Open-source Algorithm to Detect Onset of Arterial Blood Pressure Pulses", Computers in Cardiology 2003; 30:259-262 """ # Check if Signal is None: raise TypeError, "An input signal is needed." # Low-pass filter if Filter: Filter.update({'Signal': Signal}) if not Filter.has_key('SamplingRate'): Filter.update({'SamplingRate': SamplingRate}) y = flt.zpdfr(**Filter)['Signal'] else: y = flt.zpdfr(Signal=Signal, SamplingRate=SamplingRate, UpperCutoff=4., LowerCutoff=None, Order=2.)['Signal'] # Slope Sum Function dy = np.diff(y) du = dy du[du < 0] = 0 win = 0.250 * SamplingRate # original: 128 ms window ssf = flt.smooth(du, Window={ 'Length': win, 'Type': 'boxcar', 'Parameters': None })['Signal'] # Decision rule thres = 0.6 * 3. * np.mean( ssf[:10 * SamplingRate]) # a threshold base value is established # and is initialized at three times the mean SSF signal # (averaged over the first ten seconds of the recording). # actual threshold is taken to be 60% of the threshold base value win = np.int(0.150 * SamplingRate) # 150 ms threshold window refp = 0.300 * SamplingRate # eyeclosing (refractory) period, 300ms -> max 200 bpm value, slide, onset, dmm = 0, 0, [], [] # while(slide<len(ssf)): # try: # i = np.where(ssf[slide:]>thres)[0][0] # SSF signal crosses the threshold # except IndexError: # no i # break # prec = i-win # prec = prec if prec>0 else 0 # min = np.min(ssf[prec:i+1]) # try: # max = np.max(ssf[i:i+win+1]) # except IndexError: # i+win+1 > len(ssf) # break # if(max-min > value): # accept pulse detection criterion # dmm+=[max-min] # thres = 0.6*max # onset += [slide+np.where(ssf[slide:]>0.01*max)[0][0]] # slide = onset[-1] # slide += refp # slide window # kwrvals kwrvals = {} kwrvals['SSF'] = ssf kwrvals['Signal'] = y kwrvals['Onset'] = np.array(onset) # fig=pl.figure() # ax=fig.add_subplot(111) # ax.plot(kwrvals['Signal']-np.mean(kwrvals['Signal'])) # ax.plot(kwrvals['SSF']*50,'g') # ax.vlines(kwrvals['Onset'],-0.20,0.20,'r') # for a,b in zip(kwrvals['Onset'],dmm): # ax.text(a, 0.2, b) # ax.text(a, -0.2, a) # ax.axis('tight') # ax.grid('on') # fig.show() return kwrvals