iaf_psc_alpha#

class brainpy.state.iaf_psc_alpha(in_size, E_L=Quantity(-70., "mV"), C_m=Quantity(250., "pF"), tau_m=Quantity(10., "ms"), t_ref=Quantity(2., "ms"), V_th=Quantity(-55., "mV"), V_reset=Quantity(-70., "mV"), tau_syn_ex=Quantity(2., "ms"), tau_syn_in=Quantity(2., "ms"), I_e=Quantity(0., "pA"), V_min=None, V_initializer=Constant(value=-70. mV), spk_fun=ReluGrad(alpha=0.3, width=1.0), spk_reset='hard', ref_var=False, name=None)#

NEST-compatible iaf_psc_alpha neuron model.

Description

iaf_psc_alpha is a current-based leaky integrate-and-fire neuron with hard threshold/reset, fixed absolute refractory period, and alpha-shaped excitatory/inhibitory current kernels. The implementation mirrors NEST models/iaf_psc_alpha.{h,cpp} update order and propagator formulas.

1. Continuous-Time Dynamics

The membrane dynamics are

\[\frac{dV_m}{dt} = -\frac{V_m - E_L}{\tau_m} + \frac{I_\text{syn} + I_e}{C_m}\]

with \(I_\text{syn} = I_{\text{syn,ex}} + I_{\text{syn,in}}\).

Each alpha current channel is represented by a two-state linear system:

\[\frac{d\,dI_X}{dt} = -\frac{dI_X}{\tau_{\text{syn},X}}, \qquad \frac{dI_X}{dt} = dI_X - \frac{I_X}{\tau_{\text{syn},X}}, \quad X \in \{\mathrm{ex}, \mathrm{in}\}.\]

This is equivalent to the normalized alpha kernel

\[i_X(t) = \frac{e}{\tau_{\text{syn},X}}\, t\, e^{-t/\tau_{\text{syn},X}} \Theta(t),\]

which peaks at 1 when \(t=\tau_{\text{syn},X}\). Incoming spike weight \(w\) (pA) is split by sign so \(w_+=\max(w,0)\) drives excitatory state and \(w_-=\min(w,0)\) drives inhibitory state.

2. Exact Discrete Propagator and NEST Update Order

For fixed step \(h=dt\), exact linear propagation is applied to \(y_3=V_m-E_L\), synaptic states, and a one-step delayed current buffer \(y_0\):

\[dI_{X,n+1} = P_{11,X}\, dI_{X,n} + \frac{e}{\tau_{\text{syn},X}} w_{X,n},\]
\[I_{X,n+1} = P_{21,X}\, dI_{X,n} + P_{22,X}\, I_{X,n},\]
\[y_{3,n+1} = y_{3,n} + \big(e^{-h/\tau_m}-1\big) y_{3,n} + P_{30}(y_{0,n} + I_e) + \sum_{X \in \{\mathrm{ex},\mathrm{in}\}} \left(P_{31,X} dI_{X,n} + P_{32,X} I_{X,n}\right).\]

Here \(P_{11,X}=P_{22,X}=e^{-h/\tau_{\text{syn},X}}\), \(P_{21,X}=h\,e^{-h/\tau_{\text{syn},X}}\), and \(P_{30}=\tau_m(1-e^{-h/\tau_m})/C_m\).

Internal state (NEST notation):

  • \(y_0\) – buffered external current for next step,

  • \(dI_{ex}, I_{ex}\) and \(dI_{in}, I_{in}\) – alpha-kernel states,

  • \(y_3 = V_m - E_L\),

  • \(r\) – refractory countdown in grid steps.

Per-step update order:

  1. Update membrane potential if not refractory.

  2. Update synaptic alpha states.

  3. Add arriving spike input to \(dI_{ex}\) / \(dI_{in}\).

  4. Perform threshold test, reset, refractory assignment, spike emission.

  5. Store buffered external current for the next step.

3. Near-Singular Regime :math:`tau_m approx tau_{text{syn}}`

Direct formulas for \(P_{31}\) and \(P_{32}\) contain divisions by \((\tau_m-\tau_{\text{syn}})\), which are ill-conditioned near equality. The helper _alpha_propagator_p31_p32() follows NEST’s IAFPropagatorAlpha behavior and switches to stable limits:

\[P_{32}^{\mathrm{sing}} = \frac{h}{C_m} e^{-h/\tau_m}, \qquad P_{31}^{\mathrm{sing}} = \frac{h^2}{2C_m} e^{-h/\tau_m},\]

preventing cancellation/underflow artifacts around \(\tau_m=\tau_{\text{syn}}\).

4. Assumptions, Constraints, and Computational Implications

  • C_m > 0, tau_m > 0, tau_syn_ex > 0, tau_syn_in > 0, t_ref >= 0, and V_reset < V_th are enforced at construction.

  • update(x=...) uses one-step delayed current buffering (NEST ring-buffer semantics): current provided at step n contributes at step n+1 through y0.

  • The update path is vectorized over self.varshape and performs \(O(\prod \mathrm{varshape})\) floating-point work per call.

  • Internal coefficient math is in float64 via NumPy conversion, while exposed states remain in BrainUnit quantities.

Parameters:
  • in_size (Size) – Population shape specification. All per-neuron parameters are broadcast to self.varshape derived from in_size.

  • E_L (ArrayLike, optional) – Resting potential \(E_L\) in mV; scalar or array broadcastable to self.varshape. Default is -70. * u.mV.

  • C_m (ArrayLike, optional) – Membrane capacitance \(C_m\) in pF; broadcastable to self.varshape and strictly positive. Default is 250. * u.pF.

  • tau_m (ArrayLike, optional) – Membrane time constant \(\tau_m\) in ms; broadcastable and strictly positive. Default is 10. * u.ms.

  • t_ref (ArrayLike, optional) – Absolute refractory period \(t_{ref}\) in ms; broadcastable and nonnegative. Converted to integer step counts by ceil(t_ref / dt). Default is 2. * u.ms.

  • V_th (ArrayLike, optional) – Spike threshold \(V_{th}\) in mV; broadcastable to self.varshape. Default is -55. * u.mV.

  • V_reset (ArrayLike, optional) – Reset potential \(V_{reset}\) in mV; broadcastable and must satisfy V_reset < V_th elementwise. Default is -70. * u.mV.

  • tau_syn_ex (ArrayLike, optional) – Excitatory alpha time constant \(\tau_{\text{syn,ex}}\) in ms; broadcastable and strictly positive. Default is 2. * u.ms.

  • tau_syn_in (ArrayLike, optional) – Inhibitory alpha time constant \(\tau_{\text{syn,in}}\) in ms; broadcastable and strictly positive. Default is 2. * u.ms.

  • I_e (ArrayLike, optional) – Constant injected current \(I_e\) in pA; scalar or array broadcastable to self.varshape. Default is 0. * u.pA.

  • V_min (ArrayLike or None, optional) – Optional lower voltage clamp \(V_{min}\) in mV. When provided, membrane candidate update is clipped with max(V, V_min) before thresholding. None disables clipping. Default is None.

  • V_initializer (Callable, optional) – Initializer for membrane state V. Called by init_state(). Default is braintools.init.Constant(-70. * u.mV).

  • spk_fun (Callable, optional) – Surrogate spike nonlinearity used by get_spike(). Default is braintools.surrogate.ReluGrad().

  • spk_reset (str, optional) – Reset policy inherited from Neuron. 'hard' matches NEST hard reset semantics. Default is 'hard'.

  • ref_var (bool, optional) – If True, allocates boolean state self.refractory for external inspection of refractory condition. Default is False.

  • name (str or None, optional) – Optional node name.

Parameter Mapping

Table 3 Parameter mapping to model symbols#

Parameter

Type / shape / unit

Default

Math symbol

Semantics

in_size

Size; scalar/tuple

required

Defines neuron population shape self.varshape.

E_L

ArrayLike, broadcastable to self.varshape (mV)

-70. * u.mV

\(E_L\)

Resting membrane potential.

C_m

ArrayLike, broadcastable (pF), > 0

250. * u.pF

\(C_m\)

Membrane capacitance used in subthreshold integration.

tau_m

ArrayLike, broadcastable (ms), > 0

10. * u.ms

\(\tau_m\)

Leak time constant in membrane propagator.

t_ref

ArrayLike, broadcastable (ms), >= 0

2. * u.ms

\(t_{ref}\)

Absolute refractory duration.

V_th and V_reset

ArrayLike, broadcastable (mV), with V_reset < V_th

-55. * u.mV, -70. * u.mV

\(V_{th}\), \(V_{reset}\)

Threshold and post-spike reset levels.

tau_syn_ex and tau_syn_in

ArrayLike, broadcastable (ms), each > 0

2. * u.ms

\(\tau_{\text{syn,ex}}\), \(\tau_{\text{syn,in}}\)

Alpha kernel time constants for excitatory/inhibitory currents.

I_e

ArrayLike, broadcastable (pA)

0. * u.pA

\(I_e\)

Constant external current added every step.

V_min

ArrayLike broadcastable (mV) or None

None

\(V_{min}\)

Optional lower bound on membrane candidate update.

V_initializer

Callable

Constant(-70. * u.mV)

Initializer used for membrane state V.

spk_fun

Callable

ReluGrad()

Surrogate spike function returned by update().

spk_reset

str

'hard'

Reset mode inherited from Neuron.

ref_var

bool

False

Allocate boolean state self.refractory when enabled.

name

str | None

None

Optional node name.

Raises:
  • ValueError – If parameter constraints are violated: C_m <= 0, tau_m <= 0, tau_syn_ex <= 0, tau_syn_in <= 0, t_ref < 0, or V_reset >= V_th.

  • TypeError – If provided quantities are not unit-compatible with expected units (mV, ms, pF, pA) during conversion/broadcasting.

  • KeyError – At runtime, if required simulation context entries (for example t or dt) are missing when update() is called.

  • AttributeError – If update() is called before init_state() creates required state holders.

Notes

  • State variables are V, I_syn_ex, I_syn_in, dI_syn_ex, dI_syn_in, y0, refractory_step_count, and last_spike_time. refractory is added only when ref_var=True.

  • Spike weights from sum_delta_inputs are interpreted in pA: positive values are excitatory and negative values are inhibitory.

  • update(x=...) stores x into y0 for the next step, matching NEST current-event buffering semantics.

Examples

>>> import brainpy
>>> import brainstate
>>> import saiunit as u
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     neu = brainpy.state.iaf_psc_alpha(in_size=(2,), I_e=220.0 * u.pA)
...     neu.init_state()
...     with brainstate.environ.context(t=1.0 * u.ms):
...         spk = neu.update()
...     _ = spk.shape
>>> import brainpy
>>> import brainstate
>>> import saiunit as u
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     neu = brainpy.state.iaf_psc_alpha(in_size=1, tau_syn_ex=1.5 * u.ms)
...     neu.init_state()
...     with brainstate.environ.context(t=0.0 * u.ms):
...         _ = neu.update(x=200.0 * u.pA)
...     with brainstate.environ.context(t=0.1 * u.ms):
...         spk_next = neu.update()
...     _ = spk_next

References

get_spike(V=None)[source]#

Evaluate surrogate spike output for a voltage tensor.

Parameters:

V (ArrayLike or None, optional) – Voltage input in mV, broadcast-compatible with self.varshape. If None, uses current membrane state self.V.value.

Returns:

out – Surrogate spike output from self.spk_fun with the same shape as V (or self.V.value when V is None).

Return type:

dict

init_state(**kwargs)[source]#

Initialize runtime states for membrane, synapses, and refractoriness.

Parameters:

**kwargs – Unused compatibility parameters accepted by the base-state API.

Raises:
  • ValueError – If initializers cannot broadcast to self.varshape.

  • TypeError – If initializer outputs are incompatible with expected unit/array conversions for voltage, current, or integer refractory states.

update(x=Quantity(0., 'pA'))[source]#

Advance the neuron by one simulation step.

Parameters:

x (ArrayLike, optional) – Continuous current input in pA for this step. x is accumulated through sum_current_inputs() and stored in y0 for use on the next call (one-step delayed buffering).

Returns:

out – Spike output tensor from get_spike(), shape self.V.value.shape. On threshold crossings, v_out is nudged above threshold by 1e-12 mV-equivalent to preserve positive surrogate activation.

Return type:

jax.Array

Raises:
  • KeyError – If simulation context does not provide t or dt.

  • AttributeError – If required states are missing because init_state() was not called.

  • TypeError – If x or stored states are not unit-compatible with expected pA / mV conversions.