aeif_psc_delta#
- class brainpy.state.aeif_psc_delta(in_size, V_peak=Quantity(0., "mV"), V_reset=Quantity(-60., "mV"), t_ref=Quantity(0., "ms"), g_L=Quantity(30., "nS"), C_m=Quantity(281., "pF"), E_L=Quantity(-70.6, "mV"), Delta_T=Quantity(2., "mV"), tau_w=Quantity(144., "ms"), a=Quantity(4., "nS"), b=Quantity(80.5, "pA"), V_th=Quantity(-50.4, "mV"), I_e=Quantity(0., "pA"), gsl_error_tol=1e-06, refractory_input=False, V_initializer=Constant(value=-70.6 mV), w_initializer=Constant(value=0. pA), spk_fun=ReluGrad(alpha=0.3, width=1.0), spk_reset='hard', ref_var=False, name=None)#
NEST-compatible
aeif_psc_deltaneuron model.Current-based adaptive exponential integrate-and-fire neuron with delta-shaped synaptic input. Implements NEST
models/aeif_psc_delta.{h,cpp}semantics with adaptive RKF45 integration, in-loop spike handling, and optional refractory input buffering.1. Mathematical Formulation
The model combines exponential spike-initiation current (AdEx), spike-triggered and subthreshold adaptation current \(w\), and delta-function synaptic input that directly jumps the membrane voltage.
Membrane dynamics:
\[C_m \frac{dV}{dt} = -g_L (V - E_L) + g_L \Delta_T \exp\!\left(\frac{V - V_{th}}{\Delta_T}\right) - w + I_e + I_{\mathrm{stim}}.\]Adaptation dynamics:
\[\tau_w \frac{dw}{dt} = a (V - E_L) - w.\]Incoming delta spikes are interpreted as instantaneous voltage jumps:
\[V \leftarrow V + J \sum_k \delta(t - t_k).\]Here \(J\) is the synaptic weight in millivolts.
2. Refractory and Spike Handling
During refractory integration (when
refractory_step_count > 0), NEST clamps the effective membrane voltage toV_resetand sets \(dV/dt = 0\). Outside refractory, the RHS uses \(\min(V, V_{\mathrm{peak}})\) as the effective voltage to prevent unbounded exponential growth.Threshold detection uses:
V_peakifDelta_T > 0(exponential regime),V_thifDelta_T == 0(IAF-like limit).
On each detected spike:
Vis reset toV_reset,adaptation jump
w <- w + bis applied immediately,refractory counter is set to
ceil(t_ref / dt) + 1ift_ref > 0.
Spike handling occurs inside the adaptive RKF45 substep loop. With
t_ref = 0, multiple spikes can occur within one simulation step, matching NEST behavior.3. Refractory Input Buffering
If
refractory_input=True(NESTrefractory_inputflag), delta spikes arriving during refractory are accumulated intorefractory_spike_bufferwith NEST’s exponential discount factor:\[\mathrm{buffer} \leftarrow \mathrm{buffer} + J \cdot \exp(-r \cdot \Delta t / \tau_m),\]where \(r\) is the current refractory step count. The buffered input is applied when the neuron exits refractory.
4. Update Order per Simulation Step
Integrate ODEs on interval \((t, t+\Delta t]\) via adaptive RKF45.
- Inside integration loop:
Apply arriving delta jump to
V(if not refractory).Apply refractory clamp (
V <- V_resetif refractory).Apply refractory buffering logic if
refractory_input=True.Threshold detection and spike/reset/adaptation handling.
After loop: Decrement refractory counter once.
Apply arriving spike weights directly to
Vas delta-function pulses.Store external current input
xinto one-step delayedI_stim.
5. Numerical Integration Details
The model uses adaptive Runge-Kutta-Fehlberg 4(5) (RKF45) with local error control. The step size
integration_stepis adjusted per neuron to satisfy the tolerancegsl_error_tol, matching NEST’s GSL solver behavior. Minimum step size is clamped to1e-8 msto prevent infinite loops.The exponential term is computed using the effective voltage \(V_{\mathrm{eff}}\):
\[\begin{split}V_{\mathrm{eff}} = \begin{cases} V_{\mathrm{reset}} & \text{if refractory}, \\ \min(V, V_{\mathrm{peak}}) & \text{otherwise}. \end{cases}\end{split}\]Overflow protection: the model validates that \((V_{\mathrm{peak}} - V_{\mathrm{th}}) / \Delta_T\) does not exceed
log(DBL_MAX / 1e20)to prevent numerical overflow at spike time.6. Differences from NEST
Spike output format: NEST emits spike events; brainpy.state returns a binary array (0/1) per simulation step. Internal dynamics (adaptation increments, refractory handling) match NEST exactly.
Surrogate gradients: brainpy.state uses
spk_fun(e.g.,ReluGrad()) for differentiable spike generation; NEST does not support gradient-based learning.Spike reset mode:
spk_reset='hard'(default) matches NEST;'soft'is available but non-canonical.
- Parameters:
in_size (
int,tupleofint) – Shape of the neuron population. Can be an integer (1D) or tuple (multi-dimensional).V_peak (
ArrayLike, optional) – Spike detection threshold in millivolts. Used whenDelta_T > 0. Default:0.0 * u.mV. Can be scalar or array matchingin_size.V_reset (
ArrayLike, optional) – Reset potential in millivolts. Default:-60.0 * u.mV. Must satisfyV_reset < V_peak.t_ref (
ArrayLike, optional) – Absolute refractory period in milliseconds. Default:0.0 * u.ms(no refractoriness). Must be non-negative.g_L (
ArrayLike, optional) – Leak conductance in nanosiemens. Default:30.0 * u.nS. Must be positive.C_m (
ArrayLike, optional) – Membrane capacitance in picofarads. Default:281.0 * u.pF. Must be positive.E_L (
ArrayLike, optional) – Leak reversal potential in millivolts. Default:-70.6 * u.mV.Delta_T (
ArrayLike, optional) – Exponential slope factor in millivolts. Default:2.0 * u.mV. Set to0.0for IAF-like limit. Must be non-negative.tau_w (
ArrayLike, optional) – Adaptation time constant in milliseconds. Default:144.0 * u.ms. Must be positive.a (
ArrayLike, optional) – Subthreshold adaptation coupling in nanosiemens. Default:4.0 * u.nS.b (
ArrayLike, optional) – Spike-triggered adaptation increment in picoamperes. Default:80.5 * u.pA.V_th (
ArrayLike, optional) – Spike initiation threshold in millivolts (used in exponential term). Default:-50.4 * u.mV. Must satisfyV_th <= V_peak.I_e (
ArrayLike, optional) – Constant external current in picoamperes. Default:0.0 * u.pA.gsl_error_tol (
ArrayLike, optional) – RKF45 local error tolerance (unitless). Default:1e-6. Must be positive.refractory_input (
bool, optional) – If True, accumulate delta spikes arriving during refractory with NEST’s exponential discount factor and apply when refractory ends. Default:False.V_initializer (
Callable, optional) – Membrane potential initializer. Default:braintools.init.Constant(-70.6 * u.mV).w_initializer (
Callable, optional) – Adaptation current initializer. Default:braintools.init.Constant(0.0 * u.pA).spk_fun (
Callable, optional) – Surrogate gradient function for differentiable spike generation. Default:braintools.surrogate.ReluGrad().spk_reset (
str, optional) – Spike reset mode. Options:'hard'(stop gradient),'soft'(V -= V_th). Default:'hard'.ref_var (
bool, optional) – If True, exposeself.refractoryas a boolean state variable. Default:False.name (
str, optional) – Name of the neuron group.
Parameter Mapping
Parameter
Default
Math equivalent
Description
in_size(required)
—
Population shape
V_peak0 mV
\(V_{\mathrm{peak}}\)
Spike detection threshold (if \(\Delta_T > 0\))
V_reset-60 mV
\(V_{\mathrm{reset}}\)
Reset potential
t_ref0 ms
\(t_{\mathrm{ref}}\)
Absolute refractory duration
g_L30 nS
\(g_{\mathrm{L}}\)
Leak conductance
C_m281 pF
\(C_{\mathrm{m}}\)
Membrane capacitance
E_L-70.6 mV
\(E_{\mathrm{L}}\)
Leak reversal potential
Delta_T2 mV
\(\Delta_T\)
Exponential slope factor
tau_w144 ms
\(\tau_w\)
Adaptation time constant
a4 nS
\(a\)
Subthreshold adaptation coupling
b80.5 pA
\(b\)
Spike-triggered adaptation increment
V_th-50.4 mV
\(V_{\mathrm{th}}\)
Spike initiation threshold (in exponential term)
I_e0 pA
\(I_{\mathrm{e}}\)
Constant external current
gsl_error_tol1e-6
—
RKF45 local error tolerance
refractory_inputFalse—
If True, buffer spikes during refractory with NEST discounting
V_initializerConstant(-70.6 mV)
—
Membrane initializer
w_initializerConstant(0 pA)
—
Adaptation current initializer
spk_funReluGrad()
—
Surrogate spike function
spk_reset'hard'—
Reset mode; hard reset matches NEST behavior
ref_varFalse—
If True, expose boolean refractory indicator
State Variables
- Vbrainstate.HiddenState
Membrane potential \(V_m\) in millivolts. Shape:
(*in_size,).- wbrainstate.HiddenState
Adaptation current in picoamperes. Shape:
(*in_size,).- refractory_step_countbrainstate.ShortTermState
Remaining refractory grid steps (int32). Shape:
(*in_size,).- integration_stepbrainstate.ShortTermState
Persistent RKF45 internal step size in milliseconds. Shape:
(*in_size,).- I_stimbrainstate.ShortTermState
One-step delayed current buffer in picoamperes. Shape:
(*in_size,).- last_spike_timebrainstate.ShortTermState
Last emitted spike time in milliseconds (\(t+\Delta t\) on spike). Shape:
(*in_size,).- refractorybrainstate.ShortTermState, optional
Boolean refractory indicator. Only present if
ref_var=True. Shape:(*in_size,).
- Raises:
ValueError – If
V_reset >= V_peak.ValueError – If
Delta_T < 0.ValueError – If
V_peak < V_th.ValueError – If
C_m <= 0.ValueError – If
t_ref < 0.ValueError – If
tau_w <= 0.ValueError – If
gsl_error_tol <= 0.ValueError – If
(V_peak - V_th) / Delta_Texceedslog(DBL_MAX / 1e20)(overflow protection).ValueError – During integration: if
V < -1e3or|w| > 1e6(numerical instability).
Examples
Basic usage with delta-function input:
>>> import brainpy.state as bst >>> import saiunit as u >>> import brainstate as bs >>> import jax.numpy as jnp >>> >>> # Create 100 AdEx neurons >>> neu = bst.aeif_psc_delta(100, V_peak=0.*u.mV, V_reset=-60.*u.mV, t_ref=2.*u.ms) >>> >>> # Initialize state >>> with bs.environ.context(dt=0.1*u.ms): ... neu.init_all_states() ... ... # Simulate with delta input ... for i in range(100): ... # Delta spike input (+1 mV jump) ... neu.add_delta_input('external', lambda: jnp.ones(100) * 1.0 * u.mV) ... spk = neu.step_run(i, 0.0*u.pA) ... print(f"t={i*0.1:.1f}ms: {spk.sum():.0f} spikes")
With refractory input buffering:
>>> # Enable refractory buffering >>> neu = bst.aeif_psc_delta( ... 100, ... V_peak=0.*u.mV, ... V_reset=-60.*u.mV, ... t_ref=5.*u.ms, ... refractory_input=True ... ) >>> >>> with bs.environ.context(dt=0.1*u.ms): ... neu.init_all_states() ... ... # Spikes arriving during refractory are buffered and discounted ... for i in range(100): ... neu.add_delta_input('external', lambda: jnp.ones(100) * 2.0 * u.mV) ... spk = neu.step_run(i, 0.0*u.pA)
IAF-like limit (Delta_T = 0):
>>> # Delta_T=0 disables exponential term >>> neu = bst.aeif_psc_delta( ... 100, ... Delta_T=0.0*u.mV, ... V_th=-55.*u.mV, ... V_peak=-55.*u.mV, # Must equal V_th when Delta_T=0 ... a=0.0*u.nS, # No subthreshold adaptation ... b=0.0*u.pA # No spike-triggered adaptation ... )
See also
aeif_psc_alphaAdEx with alpha-function synaptic currents
aeif_psc_expAdEx with exponential synaptic currents
aeif_cond_alphaAdEx with conductance-based synapses
Notes
The default
t_ref=0matches NEST and allows multiple spikes per simulation step.Returned spike tensor is binary per simulation step (spike/no-spike), while internal adaptation dynamics follow NEST in-loop spike/reset behavior.
With
Delta_T > 0, the exponential term can cause rapid voltage growth near spike threshold. The adaptive RKF45 integrator automatically reduces step size to maintain accuracy.For gradient-based learning, use surrogate functions like
ReluGrad(),SigmoidGrad(), orSuperSpike()via thespk_funparameter.
References
- get_spike(V=None)[source]#
Generate differentiable spike output using surrogate gradient function.
Computes spike probability via the surrogate function
spk_funapplied to normalized membrane potential. Used for gradient-based learning.- Parameters:
V (
ArrayLike, optional) – Membrane potential in millivolts. If None, usesself.V.value. Shape:(*in_size,).- Returns:
spike – Differentiable spike output in range [0, 1]. Shape matches
V. Forward pass: approximately binary (0 or 1). Backward pass: uses surrogate gradient fromspk_fun.- Return type:
ArrayLike
Notes
The membrane potential is normalized as:
\[v_{\mathrm{scaled}} = \frac{V - V_{\mathrm{th}}}{V_{\mathrm{th}} - V_{\mathrm{reset}}}.\]The surrogate function is then applied:
spk_fun(v_scaled).
- init_state(**kwargs)[source]#
Initialize all state variables for the neuron population.
Creates and initializes state variables: membrane potential
V, adaptation currentw, refractory counter, integration step size, delayed current buffer, and spike timing. Optionally creates boolean refractory indicator ifref_var=True.- Parameters:
**kwargs (
dict) – Additional keyword arguments (ignored, for API compatibility).
Notes
Vandware initialized usingV_initializerandw_initializer.last_spike_timestarts at-1e7 ms(far past, indicating no recent spikes).refractory_step_countstarts at 0 (not refractory).integration_stepstarts at the global simulation timestepdt.I_stim(delayed current buffer) starts at 0 pA.If
ref_var=True,refractoryboolean array starts atFalse.
- update(x=Quantity(0., 'pA'))[source]#
Advance neuron state by one simulation timestep using adaptive RKF45 integration.
Integrates membrane and adaptation dynamics over interval \((t, t+\Delta t]\) using adaptive Runge-Kutta-Fehlberg 4(5) with per-neuron step size control. Handles delta-function input, refractory clamping, spike detection, and reset within the integration loop to match NEST semantics.
- Parameters:
x (
ArrayLike, optional) – External current input in picoamperes. Shape:(*in_size,)or broadcastable. Default:0.0 * u.pA.- Returns:
spike – Binary spike indicator (0 or 1) for this timestep. Shape:
(*in_size,). Value is 1 if any spike occurred during the integration interval, 0 otherwise.- Return type:
ArrayLike- Raises:
ValueError – If membrane potential drops below -1e3 mV (numerical instability).
ValueError – If adaptation current magnitude exceeds 1e6 pA (numerical instability).
Notes
Integration algorithm:
For each neuron, iterate RKF45 substeps until
t_localreachesdt.- At each substep:
Compute RKF45 stages using
_vector_field.Compute higher-order and error estimates.
Accept or reject substep based on local error vs
gsl_error_tol.On acceptance: apply spike detection, reset, and refractory handling via
_event_fn.
After integration loop, decrement refractory counter once.
Apply arriving spike weights directly to
Vas delta-function pulses.Store current input
xintoI_stimfor next timestep (one-step delay).
Delta input handling:
Delta inputs (accumulated via
sum_delta_inputs) are applied as instantaneous voltage jumps after integration. Spike weights go directly intoVas delta function pulses, not through synaptic state variables.Refractory clamping:
During refractory (
refractory_step_count > 0), the effective voltage in the RHS is clamped toV_resetand \(dV/dt = 0\). The adaptation currentwcontinues to evolve normally.Multiple spikes per step:
With
t_ref = 0, multiple spikes can occur within one simulation step. The returned binary spike indicator is 1 if any spike occurred, but internal state (adaptation increments, refractory handling) reflects all spikes that occurred during integration.