step_rate_generator

step_rate_generator#

class brainpy.state.step_rate_generator(in_size=1, amplitude_times=(), amplitude_values=(), start=Quantity(0., 'ms'), stop=None, origin=Quantity(0., 'ms'), name=None)#

Piecewise-constant rate generator – NEST-compatible stimulation device.

Generate a deterministic piecewise-constant rate trace and gate it with a half-open activity window using NEST-compatible parameter semantics.

1. Model equations and schedule selection

Let \(\{(t_k, a_k)\}_{k=1}^{K}\) be configured change-time/rate pairs, where \(t_k\) are times in ms and \(a_k\) are rates in spikes/s (Hz). The scheduled rate is

\[\begin{split}A(t) = \begin{cases} 0, & t < t_1, \\ a_k, & t_k \le t < t_{k+1},\ k=1,\dots,K-1, \\ a_K, & t \ge t_K. \end{cases}\end{split}\]

The output is gated by

\[g(t) = \mathbf{1}\!\left[t \ge t_0+t_{\mathrm{start,rel}}\right] \cdot \mathbf{1}\!\left[t < t_0+t_{\mathrm{stop,rel}}\right],\]

with the second indicator omitted when stop is None. Final output:

\[r_{\mathrm{out}}(t) = g(t)\,A(t).\]

2. Timing semantics, assumptions, and constraints

This implementation chooses, at environment time t, the latest schedule entry satisfying t_k <= t. With discrete simulation time on a grid, this reproduces NEST-compatible step semantics where a configured change time marks the first step at which the new rate is emitted.

Enforced constraints:

  • len(amplitude_times) == len(amplitude_values).

  • amplitude_times are strictly increasing.

Accepted but not additionally constrained:

  • Unitless amplitude_times are interpreted as ms.

  • Unitless amplitude_values are interpreted as spikes/s.

  • NEST documentation recommends positive change times; positivity is not explicitly enforced here.

3. Computational implications

Each update() call uses u.math.searchsorted() to find the active plateau, then selects the pre-broadcast rate array for self.varshape and applies one boolean activity mask. Per-call complexity is \(O(\log K + \prod \mathrm{varshape})\), where \(K\) is the number of schedule entries.

Parameters:
  • in_size (Size, optional) – Output size/shape specification consumed by brainstate.nn.Dynamics. The emitted rate has shape self.varshape derived from in_size. Default is 1.

  • amplitude_times (Sequence, optional) – Ordered sequence of change times with length K. Each value may be a unitful time (typically ms) or a unitless numeric. Passed directly to u.math.asarray(), which validates unit consistency across all entries. Must be strictly increasing. Default is ().

  • amplitude_values (Sequence, optional) – Sequence of plateau rates with length K matching amplitude_times elementwise. Values represent spikes/s (Hz) and may be unitful or unitless. Each entry is converted via u.math.asarray() and expanded to the maximum ndim found across all entries (by prepending size-1 axes); the results are stacked to a shape that is broadcastable to (K, *varshape). Default is ().

  • start (ArrayLike, optional) – Relative start time \(t_{\mathrm{start,rel}}\) (typically ms), broadcast to self.varshape via braintools.init.param(). Effective lower bound is origin + start (inclusive). Default is 0. * u.ms.

  • stop (ArrayLike or None, optional) – Relative stop time \(t_{\mathrm{stop,rel}}\) (typically ms), broadcast to self.varshape when provided. Effective upper bound is origin + stop (exclusive). None means no upper bound. Default is None.

  • origin (ArrayLike, optional) – Time origin \(t_0\) (typically ms) added to start and stop, broadcast to self.varshape. Default is 0. * u.ms.

  • name (str or None, optional) – Optional node name passed to brainstate.nn.Dynamics.

Parameter Mapping

Table 27 Parameter mapping to model symbols#

Parameter

Default

Math symbol

Semantics

amplitude_times

()

\(t_k\)

Change times for piecewise-constant rate plateaus.

amplitude_values

()

\(a_k\)

Plateau rates (spikes/s) selected at and after each t_k.

start

0. * u.ms

\(t_{\mathrm{start,rel}}\)

Relative inclusive lower bound of the active output window.

stop

None

\(t_{\mathrm{stop,rel}}\)

Relative exclusive upper bound of the active output window.

origin

0. * u.ms

\(t_0\)

Global time offset added to start and stop.

Raises:
  • ValueError – If amplitude_times and amplitude_values lengths differ, or if amplitude_times is not strictly increasing.

  • TypeError – If u.math.asarray() detects unit inconsistency across entries, or if unitful/unitless arithmetic is invalid during broadcasting or time-window comparisons.

  • KeyError – At update time, if simulation time 't' is missing from brainstate.environ.

Notes

NEST recommends specifying amplitude_times on a grid of simulation resolution dt. Using off-grid change times is allowed but may shift the effective change by up to one dt step depending on floating-point rounding when comparing t >= amp_time. Use dc_generator when only a constant current drive is needed; use step_rate_generator when a rate-coded drive must take different values at different simulation intervals. Unlike step_current_generator, the emitted quantity is dimensionless (spikes/s) and is not multiplied by a unit before output.

See also

step_current_generator

Piecewise-constant current stimulation device.

dc_generator

Constant current stimulation device.

ac_generator

Sinusoidal current stimulation device.

References

Examples

>>> import brainpy
>>> import brainstate
>>> import saiunit as u
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     gen = brainpy.state.step_rate_generator(
...         amplitude_times=[10.0 * u.ms, 110.0 * u.ms, 210.0 * u.ms],
...         amplitude_values=[400.0, 1000.0, 200.0],
...         start=0.0 * u.ms,
...         stop=300.0 * u.ms,
...     )
...     with brainstate.environ.context(t=160.0 * u.ms):
...         rate = gen.update()
...     _ = rate.shape
>>> import brainpy
>>> import saiunit as u
>>> gen1 = brainpy.state.step_rate_generator(
...     amplitude_times=[0.0 * u.ms, 100.0 * u.ms, 200.0 * u.ms],
...     amplitude_values=[50.0, 0.0, 80.0],
... )
>>> gen2 = brainpy.state.step_rate_generator(
...     in_size=10,
...     amplitude_times=[50.0 * u.ms, 150.0 * u.ms],
...     amplitude_values=[120.0, 40.0],
...     start=40.0 * u.ms,
...     stop=180.0 * u.ms,
...     origin=10.0 * u.ms,
... )
update()[source]#

Compute scheduled rate at environment time t.

The implementation is fully compatible with jax.jit: the schedule look-up uses u.math.searchsorted() on the static amplitude_times array, while t remains a traced value throughout.

Returns:

out – Dimensionless rate array with shape self.varshape and values in spikes/s. For each output channel, value equals the latest scheduled plateau whose change time is <= t. Channels outside the active window [origin + start, origin + stop) are set to zero (or t >= origin + start when stop is None).

Return type:

jax.Array

Raises:

KeyError – If brainstate.environ has no 't' entry.

Notes

Both amplitude_times and t are divided by u.ms to obtain dimensionless arrays before calling u.math.searchsorted(). u.math.searchsorted(..., side='right') - 1 returns the index of the most-recently-passed change point, or -1 when t precedes all change times (zero rate). u.math.clip() keeps the index in bounds for the gather; u.math.where() then suppresses the result when the index is negative. Start is inclusive and stop is exclusive, matching NEST semantics.

See also

step_rate_generator

Class-level parameter definitions and model equations.

step_current_generator.update

Windowed piecewise-constant current update rule.

dc_generator.update

Windowed constant-current update rule.