izhikevich#
- class brainpy.state.izhikevich(in_size, a=0.02, b=0.2, c=Quantity(-65., "mV"), d=Quantity(8., "mV"), I_e=Quantity(0., "pA"), V_th=Quantity(30., "mV"), V_min=None, consistent_integration=True, V_initializer=Constant(value=-65. mV), U_initializer=None, spk_fun=ReluGrad(alpha=0.3, width=1.0), spk_reset='hard', name=None)#
Izhikevich neuron model (NEST-compatible).
This model is a brainpy.state re-implementation of the NEST simulator
izhikevichmodel, using NEST-standard parameterization. It implements the simple spiking neuron model introduced by Izhikevich [1], which reproduces spiking and bursting behavior of known types of cortical neurons through a two-dimensional system of ordinary differential equations.1. Mathematical Formulation
The model is defined by the following coupled differential equations:
\[\frac{dV_{\text{m}}}{dt} = 0.04\, V_{\text{m}}^2 + 5\, V_{\text{m}} + 140 - U_{\text{m}} + I_{\text{e}}\]\[\frac{dU_{\text{m}}}{dt} = a\,(b\, V_{\text{m}} - U_{\text{m}})\]where:
\(V_{\text{m}}\) is the membrane potential (mV)
\(U_{\text{m}}\) is the recovery variable (mV), representing the combined effects of sodium channel inactivation and potassium channel activation
\(I_{\text{e}}\) is the total input current (pA): external constant current plus synaptic current
\(a\) is the time scale of the recovery variable (dimensionless)
\(b\) describes the sensitivity of \(U_{\text{m}}\) to subthreshold fluctuations of \(V_{\text{m}}\) (dimensionless)
2. Spike Emission and Reset
A spike is emitted when \(V_{\text{m}}\) reaches the threshold \(V_{\text{th}}\). At this point the state variables undergo an instantaneous reset:
\[\begin{split}&\text{if}\; V_m \geq V_{th}:\\ &\quad V_m \leftarrow c\\ &\quad U_m \leftarrow U_m + d\end{split}\]where:
\(c\) is the after-spike reset value for \(V_{\text{m}}\) (mV)
\(d\) is the after-spike increment of \(U_{\text{m}}\) (mV)
Each incoming spike adds to \(V_{\text{m}}\) by the synaptic weight associated with the spike (delta-coupling, instantaneous PSC).
3. Integration Scheme
This model offers two forms of Euler integration, selected by the boolean parameter
consistent_integration:Standard forward Euler (
consistent_integration = True, default): Both \(V_{\text{m}}\) and \(U_{\text{m}}\) are updated based on their values at the beginning of the time step:\[\begin{split}V_{n+1} &= V_n + h \cdot f(V_n, U_n, I_n) + \Delta V_{\text{syn}}\\ U_{n+1} &= U_n + h \cdot a \cdot (b \cdot V_n - U_n)\end{split}\]where \(h\) is the time step and \(\Delta V_{\text{syn}}\) is the delta synaptic input.
Published Izhikevich (2003) numerics (
consistent_integration = False): The membrane potential is updated in two half-steps of size \(h/2\), and the recovery variable uses the updated \(V_{\text{m}}\):\[\begin{split}V_{\text{mid}} &= V_n + \frac{h}{2} \cdot f(V_n, U_n, I_n)\\ V_{n+1} &= V_{\text{mid}} + \frac{h}{2} \cdot f(V_{\text{mid}}, U_n, I_n)\\ U_{n+1} &= U_n + h \cdot a \cdot (b \cdot V_{n+1} - U_n)\end{split}\]This scheme is recommended only for replicating published results and requires \(h = 1.0\,\text{ms}\) for consistency with the original paper. For a detailed analysis of the numerical differences, see [2].
4. Synaptic Input
Synaptic input enters via two channels:
Spike (delta) input — delivered through
add_delta_input()or thedeltakeyword; added directly to \(V_{\text{m}}\) at the integration step as an instantaneous voltage jump.Current input — delivered through the
xargument ofupdate(). Following NEST ring-buffer semantics, the current applied at simulation step k takes effect at step k + 1 (one-step delay). This is stored in theIstate variable.
5. Physical Units and Numerical Assumptions
The original Izhikevich model uses dimensionless equations with implicit units. This implementation follows NEST conventions:
Membrane potential \(V_{\text{m}}\) in mV
Recovery variable \(U_{\text{m}}\) in mV
Input current \(I_{\text{e}}\) in pA (with implicit resistance R=1)
Time constants \(a\), \(b\) are dimensionless
Time step \(h\) in ms
The coefficients 0.04 and 5 in the voltage equation have implicit units that make the equation dimensionally consistent when \(V_{\text{m}}\) is in mV and time in ms.
6. Computational Considerations
The quadratic voltage term can lead to numerical instability if the time step is too large. Use \(h \leq 1.0\,\text{ms}\) for stability.
The
V_minparameter prevents unphysical negative voltage divergence.The model uses
float64precision internally for all integration steps to match NEST numerical accuracy.
- Parameters:
in_size (
int,tupleofint) – Number of neurons or shape of the neuron population. Determines the shape of all state variables and parameters (varshape).a (
float,array_like, optional) – Time scale of the recovery variable \(U_{\text{m}}\). Dimensionless. Default: 0.02. Typical values: 0.02 (regular spiking), 0.1 (fast spiking).b (
float,array_like, optional) – Sensitivity of \(U_{\text{m}}\) to subthreshold fluctuations of \(V_{\text{m}}\). Dimensionless. Default: 0.2. Typical values: 0.2 (regular spiking), 0.25 (chattering).c (
Quantity (voltage),array_like, optional) – After-spike reset value of \(V_{\text{m}}\). Default: -65 mV. Typical values: -65 mV (regular spiking), -50 mV (chattering).d (
Quantity (voltage),array_like, optional) – After-spike increment of \(U_{\text{m}}\). Default: 8 mV. Typical values: 8 mV (regular spiking), 2 mV (fast spiking).I_e (
Quantity (current),array_like, optional) – Constant external input current. Default: 0 pA. Positive values provide tonic excitation.V_th (
Quantity (voltage),array_like, optional) – Spike threshold voltage. Default: 30 mV. NEST uses 30 mV as the practical threshold for the Izhikevich model.V_min (
Quantity (voltage),array_like, optional) – Absolute lower bound for \(V_{\text{m}}\). Default: None (no bound). When set, prevents unphysical negative voltage divergence. Typical value: -100 mV.consistent_integration (
bool, optional) – Integration scheme selector. Default: True. - True: standard forward Euler (recommended). - False: published Izhikevich (2003) half-step numerics (requires dt=1ms).V_initializer (
callable, optional) – Initialization function for \(V_{\text{m}}\). Default:Constant(-65 mV). Must accept(shape, batch_size)and return voltage values.U_initializer (
callable, optional) – Initialization function for \(U_{\text{m}}\). Default: None (uses \(U_0 = b \cdot V_0\), matching NEST). Must accept(shape, batch_size)and return voltage values.spk_fun (
callable, optional) – Surrogate gradient function for differentiable spike generation. Default:ReluGrad(). Must map(V - V_th) / scaleto [0, 1] with defined gradient.spk_reset (
str, optional) – Spike reset mode. Default: ‘hard’. - ‘hard’: stop gradient at reset (matches NEST dynamics). - ‘soft’: allow gradient flow through reset.name (
str, optional) – Name of the neuron population. Default: None.
Parameter Mapping
NEST Parameter
brainpy.state
Math Equivalent
Description
aa\(a\)
Time scale of recovery variable \(U_{\text{m}}\)
bb\(b\)
Sensitivity of \(U_{\text{m}}\) to \(V_{\text{m}}\)
cc\(c\)
After-spike reset value of \(V_{\text{m}}\) (mV)
dd\(d\)
After-spike increment of \(U_{\text{m}}\) (mV)
I_eI_e\(I_{\text{e}}\)
Constant input current (pA)
V_thV_th\(V_{\text{th}}\)
Spike threshold (mV)
V_minV_min\(V_{\text{min}}\)
Lower bound for \(V_{\text{m}}\) (mV, optional)
consistent_integrationconsistent_integration–
Forward Euler (True) vs. published numerics (False)
- V#
Membrane potential \(V_{\text{m}}\) in mV. Shape:
(*varshape,)or(batch_size, *varshape).- Type:
HiddenState
- U#
Recovery variable \(U_{\text{m}}\) in mV. Shape:
(*varshape,)or(batch_size, *varshape).- Type:
HiddenState
- I#
Buffered input current from the previous time step in pA (one-step delayed ring buffer, matching NEST semantics). Shape:
(*varshape,)or(batch_size, *varshape).- Type:
ShortTermState
Examples
Example 1: Regular spiking (RS) neuron
>>> import brainpy.state as bp >>> import brainstate >>> import saiunit as u >>> >>> # Create a regular spiking neuron >>> neuron = bp.izhikevich(1, a=0.02, b=0.2, c=-65*u.mV, d=8*u.mV) >>> neuron.init_state() >>> >>> # Simulate with constant input >>> with brainstate.environ.context(dt=1.0*u.ms): ... spikes = [] ... for _ in range(100): ... spk = neuron.update(x=10.0*u.pA) ... spikes.append(spk)
Example 2: Fast spiking (FS) neuron
>>> # Create a fast spiking neuron >>> neuron = bp.izhikevich(1, a=0.1, b=0.2, c=-65*u.mV, d=2*u.mV) >>> neuron.init_state()
Example 3: Chattering (CH) neuron
>>> # Create a chattering neuron >>> neuron = bp.izhikevich(1, a=0.02, b=0.2, c=-50*u.mV, d=2*u.mV) >>> neuron.init_state()
Example 4: Population with heterogeneous parameters
>>> import jax.numpy as jnp >>> >>> # Create 100 neurons with random parameter variation >>> key = jax.random.PRNGKey(0) >>> a_vals = jax.random.uniform(key, (100,), minval=0.01, maxval=0.1) >>> neuron = bp.izhikevich(100, a=a_vals, b=0.2, c=-65*u.mV, d=8*u.mV) >>> neuron.init_state()
References
See also
iaf_psc_deltaLeaky integrate-and-fire with delta-shaped PSCs
iaf_psc_expLeaky integrate-and-fire with exponential PSCs
mat2_psc_expMulti-timescale adaptive threshold with exponential PSCs
aeif_psc_expAdaptive exponential integrate-and-fire model
- get_spike(V=None)[source]#
Compute spike output using the surrogate gradient function.
This method applies the surrogate gradient function (
spk_fun) to the scaled voltage difference \((V - V_{\text{th}}) / (V_{\text{th}} - c)\), producing a differentiable spike indicator for gradient-based learning. The scaling factor normalizes the voltage range to approximately [0, 1] for typical surrogate functions.- Parameters:
V (
ArrayLike, optional) – Membrane potential to test for spike emission (with units of voltage, typically mV). Shape:(*varshape,)or(batch_size, *varshape). Default: None (usesself.V.value).- Returns:
Surrogate-differentiable spike indicator. Shape matches input
V. Values are in [0, 1] for typical surrogate functions, with gradients defined even at the threshold crossing.- Return type:
ArrayLike
Notes
The scaling uses the voltage reset range \((V_{\text{th}} - c)\) to normalize the input to the surrogate function.
This method is called automatically by
update()but can also be used standalone for custom spike detection logic.The returned spike indicator is differentiable for gradient-based training, unlike a hard threshold (
V >= V_th).
- init_state(batch_size=None, **kwargs)[source]#
Initialize state variables for the Izhikevich neuron.
This method initializes the membrane potential \(V_{\text{m}}\), recovery variable \(U_{\text{m}}\), and buffered input current \(I\). By default, \(V_{\text{m}}\) is initialized to -65 mV and \(U_{\text{m}}\) is initialized to \(b \cdot V_0\) (matching NEST behavior). The buffered current \(I\) is initialized to zero.
- Parameters:
Notes
If
U_initializeris None (default), \(U_{\text{m}}\) is initialized to \(b \cdot V_0\) where \(V_0\) is the initial value of \(V_{\text{m}}\). This matches NEST’s default initialization:u_ = b * v_.The buffered current
Iis always initialized to zero with units of pA, implementing NEST’s ring buffer semantic (one-step delay).
- update(x=Quantity(0., 'pA'))[source]#
Advance the neuron state by one simulation step.
This method implements the NEST
izhikevich::updatefunction, integrating the differential equations for one time step and handling spike emission and reset. The update follows NEST semantics exactly, including the one-step delayed ring buffer for current input.Update Sequence:
Read current state (\(V_{\text{old}}\), \(U_{\text{old}}\)) and buffered current \(I\) from the previous step.
Integrate \(V_{\text{m}}\) and \(U_{\text{m}}\) using forward Euler (or published half-step scheme if
consistent_integration=False).Add delta (spike) input directly to \(V_{\text{m}}\).
Apply the lower bound
V_minif specified.Detect threshold crossing (\(V \geq V_{\text{th}}\)) and apply reset: \(V \leftarrow c\), \(U \leftarrow U + d\).
Buffer the new external current
xfor the next step (one-step delay, NEST ring-buffer semantic).Return surrogate-differentiable spike output.
Integration Details:
Standard Euler (
consistent_integration=True): Both \(V\) and \(U\) are updated using their values at the start of the step.Published Izhikevich numerics (
consistent_integration=False): \(V\) is updated in two half-steps, and \(U\) uses the final \(V\) value.
Current Input Timing:
Following NEST conventions, the current
xprovided at simulation step k is buffered and takes effect at step k + 1. This one-step delay matches NEST’s ring buffer implementation for synaptic and external currents.- Parameters:
x (
Quantity (current),array_like, optional) – External current input in pA (or compatible current unit). Shape: scalar,(*varshape,), or(batch_size, *varshape). Default: 0 pA. This current is buffered and applied at the next time step.- Returns:
Surrogate-differentiable spike output for the current time step. Shape:
(*varshape,)or(batch_size, *varshape). Values are in [0, 1] for typical surrogate functions, with defined gradients for backpropagation.- Return type:
ArrayLike
Notes
The integration is performed in
float64precision to match NEST numerical accuracy.Units are stripped during integration (NEST uses dimensionless arithmetic internally) and restored after integration.
Delta (spike) inputs are summed via
sum_delta_inputs()and added directly to the membrane potential as an instantaneous voltage jump.The spike detection uses the voltage before reset (
V_new) to compute the surrogate gradient, while the state variables are updated to their post-reset values (V_post,U_post).If
V_minis set, it is enforced after integration but before spike detection and reset.