.. currentmodule:: brian

Electrophysiology: trace analysis
=================================
The electrophysiology library also contains methods to analyze intracellular
recordings.
To import the electrophysiology library::

  from brian.library.electrophysiology import *

There is a series of example scripts in the examples/electrophysiology folder.
Currently, most methods are related to the analysis of spike shape.

Miscellaneous
-------------
You can low-pass filter a trace as follows::

  v_lp=lowpass(v, tau)

where tau is the time constant (cut-off frequency 1/(2*pi*tau)) and v is
the trace (a vector of values). By default, tau is in units of the timestep.
Alternatively, one can specify the timestep::

  v_lp=lowpass(v, tau, dt=0.1*ms)

Spike analysis
--------------
Detecting spikes
^^^^^^^^^^^^^^^^
The following function returns the time indexes of spike peaks in a trace v::

  peaks=spike_peaks(v, vc=-10*mV)

where vc is the voltage criterion (we consider that there is a spike when v>vc).
The algorithm works as follows. First, we identify positive crossings of the
voltage criterion. Then, after each positive crossing, we look for the first
local maximum (that is, when the voltage first starts decreasing). The last
spike is treated differently because the peak may occur after the end of the
recording, in which case the last element is considered as the peak.

It is possible to omit the voltage criterion vc. In this case, it is guessed
with the following (rather complex) function::

  vc=find_spike_criterion(v)
  
The idea of this algorithm is to look at the trace in phase space
(v,dv/dt). In this space, spikes tend to circle around some area which contains
no trajectory. It appears that, somewhere in the middle of these circles,
there is a voltage vc for which trajectories are either increasing (dv>0,
upstroke of a spike) or decreasing (dv<0, downstroke of a spike) but never
still (dv=0). This means that a positive crossing of this voltage always leads
to a spike. We identify this voltage by looking for the largest interval of
voltages (v1,v2) for which there is no sign change of dv/dt (over two successive
timesteps), and we set vc=(v1+v2)/2, the middle of this interval.
  
As this method is rather complex, it is strongly advised to manually check
whether it gives reasonable results.

Voltage reset
^^^^^^^^^^^^^
The average voltage reset after a spike is calculated as the average
first minimum after a spike, with the following function::

  reset=reset_potential(v, peaks=None, full=False)
  
The time indexes of spike peaks can be given
(this may save some computation time).
With the ``full=True`` option, the standard deviation is also returned.

Spike threshold
^^^^^^^^^^^^^^^
There are 3 ways to measure the spike threshold. The first derivative method
uses a threshold criterion on the first derivative dv/dt to identify spike
onsets::

  onsets=spike_onsets(v, criterion=None, vc=None)
  
where ``criterion`` is the derivative criterion and ``vc`` is the voltage criterion
to detect spikes. Note that the criterion is in units of voltage per time step.
First, the algorithm detects spike peaks. Then for each spike,
we look for the last local maximum of dv/dt before the spike, which should be the
inflexion point of the spike.
Then we identify the last time before the inflexion point when dv/dt is smaller
than the criterion. The function returns the time indexes of the onsets, not
their values (which are ``v[onsets]``).
The derivative criterion may be automatically determined, using the following function::

  criterion=find_onset_criterion(v, guess=0.1, vc=None)
  
where ``guess`` is an optional initial guess for the optimization method.
The algorithm is simple: find the criterion that minimizes the variability
of onsets.

There are two other methods to measure spike thresholds, but they do not
always give very good results (perhaps the trace should be preliminary
filtered)::

  onsets2=spike_onsets_dv2(v, vc=None)
  onsets3=spike_onsets_dv3(v, vc=None)

The first one finds the maximum of the second derivative d2v/dt2, the second
one finds the maximum of d3v/dt3. These are global maxima in each interspike
interval (it could be that looking for the last local maximum gives better
results).

The following function returns the depolarization slope preceding each spike
as an array::

  slopes=slope_threshold(v, onsets=None, T=None)

In this function, spike onset indexes are passed through the ``onset``
keyword. The depolarization slope is calculated by linear regression over the
``T`` time bins preceding each spike. The result is in units of the time bin.

In a similar way, the following function returns the average membrane
potential preceding each spike as an array::

  vm_threshold(v, onsets=None, T=None):

Spike shape
^^^^^^^^^^^
The following function returns the average spike duration, defined as the time
from onset to reset (next voltage minimum):: 

  duration=spike_duration(v)

The onsets can be passed to save computation time, with the ``onsets``
keyword. With the option ``full=True``, the function returns:
the mean time from onset to peak, the mean time from onset down to same value
(note that this may not be meaningful for some neurons),
mean time from onset to next minimum, and standard deviations for these 3
values.

Note: this function may change.

The following function returns the average spike-triggered voltage::

  shape=spike_shape(v, onsets=None, before=100, after=100)
  
If ``onsets`` is unspecified, it is calculated with the ``spike_onsets``
function. Note that you can align spikes on other times, for example peaks.
The arguments ``before`` and ``after`` specify the number of time steps
before and after the triger times.

Note: this should not be specific to spikes, it's a stimulus-triggered average.

Spike mask
^^^^^^^^^^
It is often useful to discard spikes from the trace to analyse it. The following
function returns an array of booleans which are True in spikes::

  spike_mask(v, spikes=None, T=None)

The starting point of each spike (time bin) is given by the ``spikes`` variable
(default: onsets), and ``T`` is the duration of each spike in time bins.
This function can then be used to select the subthreshold trace or the spikes::

  v_subthreshold=v[-spike_mask(v,T=100)]
  v_spikes=v[spike_mask(v,T=100)]
