Esempio n. 1
0
 def processData(self, data):
     s = self.stateGroup.state()
     events = functions.zeroCrossingEvents(data,
                                           minLength=s['minLength'],
                                           minPeak=s['minPeak'],
                                           minSum=s['minSum'])
     events = events[:s['eventLimit']]
     return events
Esempio n. 2
0
 def process(self, data, display=True):
     
     rp = self.ctrls['risePower'].value()
     stimTime = self.ctrls['stimulusTime'].value()
     times = data.xvals('Time')
     dt = times[1] - times[0]
     data1 = data.view(np.ndarray)
     if stimTime > times[-1]:
         raise Exception("stimulusTime is larger than length of input data.")
     stimInd = np.argwhere(times>=stimTime)[0][0]
     
     # 1. make sure offset is removed
     offset = np.median(data1[:stimInd])
     data2 = data1 - offset
     
     # 2. check for zero-crossing events within 4ms after stimulus
     cross = functions.zeroCrossingEvents(data2[stimInd:])
     maxInd = 4e-3 / dt
     minLength = self.ctrls['minDirectDuration'].value() / dt
     gotEvent = None
     for start, length, sum, peak in cross:
         if start > maxInd:
             break
         if length < minLength:
             continue
         if gotEvent is None or length > gotEvent[1]:
             gotEvent = (start+stimInd, length)
     #if len(cross) == 0: ## must be a single large event
         #gotEvent = (0, len(data2)-stimInd)
     
     fitParams = dict(
         directFitAmp1=0., directFitAmp2=0., directFitTime=0., 
         directFitRise=0., directFitDecay1=0., directFitDecay2=0.,
         directFitPeakTime=0., directFitPeak=0., directFitSubtracted=False,
         directFitValid=False,
         )
     
     # 3. if there is no large event near stimulus, return original data
     if gotEvent is None:
         if display:
             self.plotItem.clear()
         return {'output': data, 'fitParams': fitParams, 'plot': self.plotItem}
     
     #print "============"
     #print stimInd
     #print gotEvent
     #print cross[:20]
     
     # 4. guess amplitude, tau from detected event
     evStart = gotEvent[0]
     evEnd = evStart + gotEvent[1]
     evRgn = data2[evStart:evEnd]
     #pg.plot(evRgn)
     mx = evRgn.max()
     mn = evRgn.min()
     ampGuess = mx if abs(mx) > abs(mn) else mn
     tauGuess = gotEvent[1] * dt
     if ampGuess < 0:
         ampBound = [None, 0]
     else:
         ampBound = [0, None]
     
     # 5. fit
     guess = [ampGuess*2, ampGuess*2, stimTime, 1e-3, tauGuess*0.5, tauGuess*2]
     bounds = [
         ampBound, ampBound,
         [stimTime, stimTime+4e-3],
         [1e-4, 100e-3],
         [1e-3, 1],
         [5e-3, 10],
     ]
     #print guess
     #print bounds
     endInd = evStart + gotEvent[1] * 10
     fitYData = data2[stimInd:endInd]
     fitXData = times[stimInd:endInd]
     fit = functions.fitDoublePsp(x=fitXData, y=fitYData, guess=guess, bounds=bounds, risePower=rp)
     
     # 6. subtract fit from original data (offset included), return
     y = functions.doublePspFunc(fit, times, rp)
     
     if display:
         self.plotItem.setData(x=fitXData, y=y[stimInd:endInd], pen=self.ctrls['plotColor'].color())        
         
     ## prepare list of fit params for output
     (xMax, yMax) = functions.doublePspMax(fit)
     xMax -= fit[2]  ## really interested in time-to-peak, not the exact peak time.
     
     fitParams = dict(
         directFitAmp1=fit[0], directFitAmp2=fit[1], directFitTime=fit[2], 
         directFitRise=fit[3], directFitDecay1=fit[4], directFitDecay2=fit[5],
         directFitPeakTime=xMax, directFitPeak=yMax, directFitSubtracted=None, directFitValid=True,
         )
         
     if self.ctrls['subtractDirect'].isChecked():
         out = metaarray.MetaArray(data-y, info=data.infoCopy())
         fitParams['directFitSubtracted'] = True
     else:
         out = data
         fitParams['directFitSubtracted'] = False
         
         
     return {'fitParams': fitParams, 'output': out, 'plot': self.plotItem}
Esempio n. 3
0
def processEventFits(events, startEvent, stopEvent, opts):
    ## This function does all the processing work for EventFitter.
    dt = opts['dt']
    origTau = opts['tau']
    multiFit = opts['multiFit']
    waveform = opts['waveform']
    tvals = opts['tvals']
    
    nFields = len(events.dtype.fields)
    
    dtype = [(n, events[n].dtype) for n in events.dtype.names]
    output = np.empty(len(events), dtype=dtype + [
        ('fitAmplitude', float), 
        ('fitTime', float),
        ('fitRiseTau', float), 
        ('fitDecayTau', float), 
        ('fitTimeToPeak', float),
        ('fitError', float),
        ('fitFractionalError', float),
        ('fitLengthOverDecay', float),
    ])
    
    offset = 0 ## not all input events will produce output events; offset keeps track of the difference.

    outputState = {
        'guesses': [],
        'eventData': [], 
        'indexes': [], 
        'xVals': [],
        'yVals': []
    }
    
    for i in range(startEvent, stopEvent):
        start = events[i]['time']
        #sliceLen = 50e-3
        sliceLen = dt*300. ## Ca2+ events are much longer than 50ms
        if i+1 < len(events):
            nextStart = events[i+1]['time']
            sliceLen = min(sliceLen, nextStart-start)
                
        guessLen = events[i]['len']*dt
        tau = origTau
        if tau is not None:
            guessLen += tau*2.
        #print i, guessLen, tau, events[i]['len']*dt

        #sliceLen = 50e-3
        sliceLen = guessLen
        if i+1 < len(events):  ## cut slice back if there is another event coming up
            nextStart = events[i+1]['time']
            sliceLen = min(sliceLen, nextStart-start)
        
        
        ## Figure out from where to pull waveform data that will be fitted
        startIndex = np.argwhere(tvals>=start)[0][0]
        stopIndex = startIndex + int(sliceLen/dt)
        eventData = waveform[startIndex:stopIndex]
        times = tvals[startIndex:stopIndex]
        #print i, startIndex, stopIndex, dt
        if len(times) < 4:  ## PSP fit requires at least 4 points; skip this one
            offset += 1
            continue
        
        ## reconvolve this chunk of the signal if it was previously deconvolved
        if tau is not None:
            eventData = functions.expReconvolve(eventData, tau=tau, dt=dt)
        #print i, len(eventData)
        ## Make guesses as to the shape of the event
        mx = eventData.max()
        mn = eventData.min()
        if mx > -mn:
            peakVal = mx
        else:
            peakVal = mn
        guessAmp = peakVal * 2  ## fit converges more reliably if we start too large
        guessRise = guessLen/4.
        guessDecay = guessLen/2.
        guessStart = times[0]
        
        zc = functions.zeroCrossingEvents(eventData - (peakVal/3.))
        ## eliminate events going the wrong direction
        if len(zc) > 0:
            if guessAmp > 0:
                zc = zc[zc['peak']>0]
            else:
                zc = zc[zc['peak']<0]
        #print zc    
        ## measure properties for the largest event within 10ms of start
        zc = zc[zc['index'] < 10e-3/dt]
        if len(zc) > 0:
            if guessAmp > 0:
                zcInd = np.argmax(zc['sum']) ## the largest event in this clip
            else:
                zcInd = np.argmin(zc['sum']) ## the largest event in this clip
            zcEv = zc[zcInd]
            #guessLen = dt*zc[zcInd]['len']
            guessRise = .1e-3 #dt*zcEv['len'] * 0.2
            guessDecay = dt*zcEv['len'] * 0.8 
            guessStart = times[0] + dt*zcEv['index'] - guessRise*3.
            
            ## cull down the data set if possible
            cullLen = zcEv['index'] + zcEv['len']*3
            if len(eventData) > cullLen:
                eventData = eventData[:cullLen]
                times = times[:cullLen]
                
            
        ## fitting to exponential rise * decay
        ## parameters are [amplitude, x-offset, rise tau, fall tau]
        guess = [guessAmp, guessStart, guessRise, guessDecay]
        #guess = [amp, times[0], guessLen/4., guessLen/2.]  ## careful! 
        bounds = [
            sorted((guessAmp * 0.1, guessAmp)),
            sorted((guessStart-min(guessRise, 0.01), guessStart+guessRise*2)), 
            sorted((dt*0.5, guessDecay)),
            sorted((dt*0.5, guessDecay * 50.))
        ]
        yVals = eventData.view(np.ndarray)
        
        fit = functions.fitPsp(times, yVals, guess=guess, bounds=bounds, multiFit=multiFit)
        
        computed = functions.pspFunc(fit, times)
        peakTime = functions.pspMaxTime(fit[2], fit[3])
        diff = (yVals - computed)
        err = (diff**2).sum()
        fracError = diff.std() / computed.std()
        lengthOverDecay = (times[-1] - fit[1]) / fit[3]  # ratio of (length of data that was fit : decay constant)
        output[i-offset] = tuple(events[i]) + tuple(fit) + (peakTime, err, fracError, lengthOverDecay)
        #output['fitTime'] += output['time']
            
        #print fit
        #self.events.append(eventData)
        
        outputState['guesses'].append(guess)
        outputState['eventData'].append(eventData)
        outputState['indexes'].append(i)
        outputState['xVals'].append(times)
        outputState['yVals'].append(computed)
        

    if offset > 0:
        output = output[:-offset]
        
    outputState['output'] = output
        
    return outputState
Esempio n. 4
0
 def processData(self, data):
     s = self.stateGroup.state()
     events = functions.zeroCrossingEvents(data, minLength=s['minLength'], minPeak=s['minPeak'], minSum=s['minSum'])
     events = events[:s['eventLimit']]
     return events