Example #1
0
def stf_fit(p0, lsfunc):
    data = stf.get_trace()[stf.get_fit_start():stf.get_fit_end()]
    dt = stf.get_sampling_interval()
    x = np.arange(0, len(data) * dt, dt)

    plsq = leastsq(leastsq_stf, p0, args=(data, lsfunc, x))

    return plsq[0]
Example #2
0
def crop():

    si = stf.get_sampling_interval()
    start = stf.get_fit_start() * si
    end = stf.get_fit_end() * si
    spells.cut_sweeps(start, end - start)

    return
Example #3
0
def stf_fit( p0, lsfunc ):
    data = stf.get_trace()[ stf.get_fit_start() : stf.get_fit_end() ]
    dt = stf.get_sampling_interval()
    x = np.arange(0, len(data)*dt, dt)

    plsq = leastsq(leastsq_stf, p0, args=(data, lsfunc, x))
    
    return plsq[0]
Example #4
0
def monoexpfit(optimization=True, Tn=20):
    """
    Fits monoexponential function with offset to data between the fit cursors
    in the current trace of the active channel using a Chebyshev-Levenberg-
    Marquardt hybrid algorithm. Optimization requires Scipy. Setting optimization
    to False forces this function to use just the Chebyshev algorithm. The maximum
    order of the Chebyshev polynomials can be set using Tn.
    """

    # Get data
    fit_start = stf.get_fit_start()
    fit_end = stf.get_fit_end()
    y = np.double(stf.get_trace()[fit_start:fit_end])
    si = stf.get_sampling_interval()
    l = len(y)
    t = si * np.arange(0, l, 1, np.double)

    # Define monoexponential function
    def f(t, *p):
        return p[0] + p[1] * np.exp(-t / p[2])

    # Get initial values from Chebyshev transform fit
    init = chebexp(1, Tn)
    p0 = (init.get('Offset'), )
    p0 += (init.get('Amp_0'), )
    p0 += (init.get('Tau_0'), )

    # Optimize (if applicable)
    if optimization == True:
        # Optimize fit using Levenberg-Marquardt algorithm
        options = {"ftol": 2.22e-16, "xtol": 2.22e-16, "gtol": 2.22e-16}
        [p, pcov] = optimize.curve_fit(f, t, y, p0, **options)
    elif optimization == False:
        p = list(p0)
    fit = f(t, *p)

    # Calculate SSE
    SSE = np.sum((y - fit)**2)

    # Plot fit in a new window
    matrix = np.zeros((2, stf.get_size_trace())) * np.nan
    matrix[0, :] = stf.get_trace()
    matrix[1, fit_start:fit_end] = fit
    stf.new_window_matrix(matrix)

    # Create table of results
    retval = [("p0_Offset", p[0])]
    retval += [("p1_Amp_0", p[1])]
    retval += [("p2_Tau_0", p[2])]
    retval += [("SSE", SSE)]
    retval += [("dSSE", 1.0 - np.sum((y - f(t, *p0))**2) / SSE)]
    retval += [("Time fit begins", fit_start * si)]
    retval += [("Time fit ends", fit_end * si)]
    retval = dict(retval)
    stf.show_table(
        retval, "monoexpfit, Section #%i" % float(stf.get_trace_index() + 1))

    return
Example #5
0
def batch_integration():
    """
    Perform batch integration between the decay/fit cursors of all traces
    in the active window
    """
    n = int(stf.get_fit_end() + 1 - stf.get_fit_start())
    x = [i * stf.get_sampling_interval() for i in range(n)]
    dictlist = []
    for i in range(stf.get_size_channel()):
        stf.set_trace(i)
        y = stf.get_trace()[int(stf.get_fit_start()):int(stf.get_fit_end() +
                                                         1)]
        auc = np.trapz(y - stf.get_base(), x)
        dictlist += [("%i" % (i + 1), auc)]
    retval = dict(dictlist)
    stf.show_table(retval, "Area Under Curve")
    stf.set_trace(0)

    return
Example #6
0
def yvalue(origin, interval):

    stf.set_fit_start(origin, True)
    stf.set_fit_end(origin + interval, True)
    stf.measure()
    x = int(stf.get_fit_end(False))
    y = []
    for i in range(stf.get_size_channel()):
        stf.set_trace(i)
        y.append(stf.get_trace(i)[x])

    return y
Example #7
0
def blankstim():
    """
    Blank values between fit cursors in all traces in the active channel.
    Typically used to blank stimulus artifacts.
    """

    fit_start = stf.get_fit_start()
    fit_end = stf.get_fit_end()
    blanked_traces = []
    for i in range(stf.get_size_channel()):
        tmp = stf.get_trace(i)
        tmp[fit_start:fit_end] = np.nan
        blanked_traces.append(tmp)
    stf.new_window_list(blanked_traces)

    return
Example #8
0
def interpstim():
    """
    Interpolate values between fit cursors in all traces in the active channel.
    Typically used to remove stimulus artifacts.
    """

    x = np.array(
        [i * stf.get_sampling_interval() for i in range(stf.get_size_trace())])
    fit_start = int(stf.get_fit_start())
    fit_end = int(stf.get_fit_end())
    interp_traces = []
    for i in range(stf.get_size_channel()):
        tmp = stf.get_trace(i)
        tmp[fit_start:fit_end] = np.interp(x[fit_start:fit_end],
                                           [x[fit_start], x[fit_end]],
                                           [tmp[fit_start], tmp[fit_end]])
        interp_traces.append(tmp)
    stf.new_window_list(interp_traces)

    return
Example #9
0
def chebexp(n, Tn=20):
    """
    Fits sums of exponentials with offset to the current trace in the
    active channel using the Chebyshev tranform algorithm. The maximum
    order of the Chebyshev polynomials can be set using Tn.

    Reference:
    Malachowski, Clegg and Redford (2007) J Microsc 228(3): 282-95
    """

    # Get data trace between fit/decay cursors
    y = stf.get_trace()[stf.get_fit_start():stf.get_fit_end()].astype(
        np.double)
    si = np.double(stf.get_sampling_interval())
    l = len(y)
    N = np.double(l - 1)

    # Calculate time dimension with unit 1
    t = np.arange(0, l, 1, np.double)

    # Check the maximum order Chebyshev polynomials to generate
    if l < Tn:
        raise ValueError('Tn exceeds the number of data points')

    # Generate the polynomials T and coefficients d
    T0 = np.ones((l), np.double)
    R0 = np.sum(T0**2)
    d0 = np.sum((T0 * y) / R0)
    T = np.zeros((l, Tn), np.double)
    T[:, 0] = 1 - 2 * t / N
    T[:, 1] = 1 - 6 * t / (N - 1) + 6 * t**2 / (N * (N - 1))
    R = np.zeros((Tn), np.double)
    d = np.zeros((Tn), np.double)
    for j in range(Tn):
        if j > 1:
            A = (j + 1) * (N - j)
            B = 2 * (j + 1) - 1
            C = j * (N + j + 1)
            T[:, j] = (B * (N - 2 * t) * T[:, j - 1] - C * T[:, j - 2]) / A
        R[j] = np.sum(T[:, j]**2)
        d[j] = np.sum(T[:, j] * y / R[j])

    # Generate additional coefficients dn that describe the relationship
    # between the Chebyshev coefficients d and the constant k, which is
    # directly related to the exponent time constant
    dn = np.zeros((n, Tn), np.double)
    for i in range(1, n + 1):
        for j in range(1 + i, Tn - i + 1):
            if i > 1:
                dn[i - 1, j - 1] = (((N + j + 2) * dn[i - 2, j] /
                                     (2 * j + 3)) - dn[i - 2, j - 1] -
                                    ((N - j + 1) * dn[i - 2, j - 2] /
                                     (2 * j - 1))) / 2
            else:
                dn[i - 1,
                   j - 1] = (((N + j + 2) * d[j] / (2 * j + 3)) - d[j - 1] -
                             ((N - j + 1) * d[j - 2] / (2 * j - 1))) / 2
    for i in range(n):
        dn[i, :] = dn[i, :] * np.double(np.all(dn, 0))

    # Form the regression model to find the time constants of each exponent
    Mn = np.zeros((n, n), np.double)
    b = np.zeros(n, np.double)
    for i in range(n):
        b[i] = np.sum(d * dn[i, :])
        for m in range(n):
            Mn[i, m] = -np.sum(dn[i, :] * dn[m, :])

    # Solve the linear problem
    try:
        x = np.linalg.solve(Mn, b)
    except:
        x = np.linalg.lstsq(Mn, b)[0]
    k = np.roots(np.hstack((1, x)))
    if any(k != np.real(k)):
        raise ValueError("Result is not a sum of %d real exponents" % n)
    tau = -1 / np.log(1 + k)

    # Generate the Chebyshev coefficients df for each exponent
    df0 = np.zeros(n, np.double)
    df = np.zeros((n, Tn), np.double)
    for i in range(n):
        for j in range(Tn):
            df[i, j] = np.sum(np.exp(-t / tau[i]) * T[:, j] / R[j])
        df0[i] = np.sum(np.exp(-t / tau[i]) * T0 / R0)

    # Form the regression model to find the amplitude of each exponent
    Mf = np.zeros((n, n), np.double)
    b = np.zeros(n, np.double)
    for i in range(n):
        b[i] = np.sum(d * df[i, :])
        for m in range(n):
            Mf[i, m] = np.sum(df[i, :] * df[m, :])

    # Solve the linear problem
    try:
        a = np.linalg.solve(Mf, b)
    except:
        a = np.linalg.lstsq(Mf, b)[0]

    # Calculate the offset for the fit
    offset = d0 - np.sum(df0 * a.T)

    # Prepare output
    retval = [("Amp_%d" % i, a[i]) for i in range(n)]
    retval += [("Tau_%d" % i, si * tau[i]) for i in range(n)]
    retval += [("Offset", np.double(offset))]
    retval = dict(retval)

    return retval
Example #10
0
def EPSPtrains(latency=200,
               numStim=4,
               intvlList=[1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02]):

    # Initialize
    numTrains = len(intvlList)  # Number of trains
    intvlArray = np.array(intvlList) * 1000  # Units in ms
    si = stf.get_sampling_interval()  # Units in ms

    # Background subtraction
    traceBaselines = []
    subtractedTraces = []
    k = 1e-4
    x = [i * stf.get_sampling_interval() for i in range(stf.get_size_trace())]
    for i in range(numTrains):
        stf.set_trace(i)
        z = x
        y = stf.get_trace()
        traceBaselines.append(y)
        ridx = []
        if intvlArray[i] > 500:
            for j in range(numStim):
                ridx += range(
                    int(round(((intvlArray[i] * j) + latency - 1) / si)),
                    int(round(
                        ((intvlArray[i] * (j + 1)) + latency - 1) / si)) - 1)
        else:
            ridx += range(
                int(round((latency - 1) / si)),
                int(
                    round(((intvlArray[i] *
                            (numStim - 1)) + latency + 500) / si)) - 1)
        ridx += range(int(round(4999 / si)), int(round(5199 / si)))
        z = np.delete(z, ridx, 0)
        y = np.delete(y, ridx, 0)
        yi = np.interp(x, z, y)
        yf = signal.symiirorder1(yi, (k**2), 1 - k)
        traceBaselines.append(yf)
        subtractedTraces.append(stf.get_trace() - yf)
    stf.new_window_list(traceBaselines)
    stf.new_window_list(subtractedTraces)

    # Measure depolarization
    # Initialize variables
    a = []
    b = []

    # Set baseline start and end cursors
    stf.set_base_start(np.round(
        (latency - 50) / si))  # Average during 50 ms period before stimulus
    stf.set_base_end(np.round(latency / si))

    # Set fit start cursor
    stf.set_fit_start(np.round(latency / si))
    stf.set_fit_end(
        np.round(((intvlArray[1] * (numStim - 1)) + latency + 1000) /
                 si))  # Include a 1 second window after last stimulus

    # Start AUC calculations
    for i in range(numTrains):
        stf.set_trace(i)
        stf.measure()
        b.append(stf.get_base())
        n = int(stf.get_fit_end() + 1 - stf.get_fit_start())
        x = np.array([k * stf.get_sampling_interval() for k in range(n)])
        y = stf.get_trace()[int(stf.get_fit_start()):int(stf.get_fit_end() +
                                                         1)]
        a.append(np.trapz(y - b[i], x))  # Units in V.s

    return a
Example #11
0
def wcp(V_step=-5, step_start=10, step_duration=20):
    """
    Measures whole cell properties. Specifically, this function returns the
    voltage clamp step estimates of series resistance, input resistance, cell
    membrane resistance, cell membrane capacitance, cell surface area and
    specific membrane resistance.
    
    The series (or access) resistance is obtained my dividing the voltage step
    by the peak amplitude of the current transient (Ogden, 1994): Rs = V / Ip
    
    The input resistance is obtained by dividing the voltage step by the average
    amplitude of the steady-state current (Barbour, 2014): Rin = V / Iss
    
    The cell membrane resistance is calculated by subtracting the series
    resistance from the input resistance (Barbour, 1994): Rm = Rin - Rs
    
    The cell membrane capacitance is estimated by dividing the transient charge
    by the size of the voltage-clamp step (Taylor et al. 2012): Cm = Q / V
    
    The cell surface area is estimated by dividing the cell capacitance by the
    specific cell capacitance, c (1.0 uF/cm^2; Gentet et al. 2000; Niebur, 2008):
    Area = Cm / c
    
    The specific membrane resistance is calculated by multiplying the cell
    membrane resistance with the cell surface area: rho = Rm * Area

    Users should be aware of the approximate nature of determining cell
    capacitance and derived parameters from the voltage-clamp step method
    (Golowasch, J. et al., 2009)

    References:
    Barbour, B. (2014) Electronics for electrophysiologists. Microelectrode
     Techniques workshop tutorial.
     www.biologie.ens.fr/~barbour/electronics_for_electrophysiologists.pdf
    Gentet, L.J., Stuart, G.J., and Clements, J.D. (2000) Direct measurement
     of specific membrane capacitance in neurons. Biophys J. 79(1):314-320
    Golowasch, J. et al. (2009) Membrane Capacitance Measurements Revisited:
     Dependence of Capacitance Value on Measurement Method in Nonisopotential
     Neurons. J Neurophysiol. 2009 Oct; 102(4): 2161-2175.
    Niebur, E. (2008), Scholarpedia, 3(6):7166. doi:10.4249/scholarpedia.7166
     www.scholarpedia.org/article/Electrical_properties_of_cell_membranes
     (revision #13938, last accessed 30 April 2018)
    Ogden, D. Chapter 16: Microelectrode electronics, in Ogden, D. (ed.)
     Microelectrode Techniques. 1994. 2nd Edition. Cambridge: The Company
     of Biologists Limited.
    Taylor, A.L. (2012) What we talk about when we talk about capacitance
     measured with the voltage-clamp step method J Comput Neurosci.
     32(1):167-175
    """

    # Error checking
    if stf.get_yunits() != "pA":
        raise ValueError('The recording is not voltage clamp')

    # Prepare variables from input arguments
    si = stf.get_sampling_interval()
    t0 = step_start / si
    l = step_duration / si

    # Set cursors and update measurements
    stf.set_base_start((step_start - 1) / si)
    stf.set_base_end(t0 - 1)
    stf.set_peak_start(t0)
    stf.set_peak_end((step_start + 1) / si)
    stf.set_fit_start(t0)
    stf.set_fit_end(t0 + l - 1)
    stf.set_peak_direction("both")
    stf.measure()

    # Calculate series resistance (Rs) from initial transient
    b = stf.get_base()
    Rs = 1000 * V_step / (stf.get_peak() - b)  # in Mohm

    # Calculate charge delivered during the voltage clamp step
    n = int(stf.get_fit_end() + 1 - stf.get_fit_start())
    x = [i * stf.get_sampling_interval() for i in range(n)]
    y = stf.get_trace()[int(stf.get_fit_start()):int(stf.get_fit_end() + 1)]
    Q = np.trapz(y - b, x)

    # Set cursors and update measurements
    stf.set_base_start(t0 + l - 1 - (step_duration / 4) / si)
    stf.set_base_end(t0 + l - 1)
    stf.measure()

    # Measure steady state current and calculate input resistance
    I = stf.get_base() - b
    Rin = 1000 * V_step / I  # in Mohm

    # Calculate cell membrane resistance
    Rm = Rin - Rs  # in Mohm

    # Calculate voltage-clamp step estimate of the cell capacitance
    t = x[-1] - x[0]
    Cm = (Q - I * t) / V_step  # in pF

    # Estimate membrane surface area, where the capacitance per unit area is 1.0 uF/cm^2
    A = Cm * 1e-06 / 1.0  # in cm^2

    # Calculate specific membrane resistance
    rho = 1e+03 * Rm * A  # in kohm.cm^2; usually 10 at rest

    # Create table of results
    retval = []
    retval += [("Holding current (pA)", b)]
    retval += [("Series resistance (Mohm)", Rs)]
    retval += [("Input resistance (Mohm)", Rin)]
    retval += [("Cell resistance (Mohm)", Rm)]
    retval += [("Cell capacitance (pF)", Cm)]
    retval += [("Surface area (um^2)", A * 1e+04**2)]
    retval += [("Membrane resistivity (kohm.cm^2)", rho)]
    retval = dict(retval)
    stf.show_table(retval, "Whole-cell properties")

    return retval