noise_generator#

class brainpy.state.noise_generator(in_size=1, mean=Quantity(0., 'pA'), std=Quantity(0., 'pA'), noise_dt=None, std_mod=Quantity(0., 'pA'), frequency=Quantity(0., 'Hz'), phase=0.0, start=Quantity(0., 'ms'), stop=None, origin=Quantity(0., 'ms'), seed=None, name=None)#

Gaussian white-noise current generator compatible with NEST.

Generate a piecewise-constant Gaussian current with optional sinusoidal modulation of the noise standard deviation and a NEST-style activity window.

1. Stochastic process and update rule

Let \(\delta\) be the configured noise update period. For each channel and noise interval index \(j\), this implementation samples

\[A_j = \mu + \xi_j \sigma_{\mathrm{eff}}(t_j), \qquad \xi_j \sim \mathcal{N}(0, 1),\]

then emits \(I(t)=A_j\) for \(t_j \le t < t_j + \delta\) while the generator is active. The effective standard deviation is

\[\sigma_{\mathrm{eff}}(t) = \sqrt{\max\!\left(\sigma^2 + \sigma_{\mathrm{mod}}^2 \sin(\omega t + \phi),\, 0\right)}, \qquad \omega = \frac{2\pi f}{1000}.\]

The non-negativity clamp follows the implementation exactly: maximum(., 0) is applied before sqrt so modulation never yields invalid real values.

2. Variance approximation and assumptions

For an LIF membrane receiving the unmodulated process (\(\sigma_{\mathrm{mod}}=0\)) with \(\delta \ll \tau_m\), the asymptotic membrane potential variance is approximated by

\[\Sigma^2 = \frac{\delta \tau_m \sigma^2}{2 C_m^2}.\]

This approximation assumes linear subthreshold dynamics, stationary statistics, and sufficiently small update period relative to membrane time constant. Increasing \(\delta\) increases drive variance linearly and shifts the spectrum away from ideal white-noise behavior.

3. Timing semantics and computational implications

The activity window is half-open: \([t_0 + t_{\mathrm{start,rel}},\ t_0 + t_{\mathrm{stop,rel}})\). Therefore, start is inclusive and stop is exclusive.

Noise amplitudes are refreshed when step_counter % round(noise_dt / dt) == 0. If noise_dt is None, then noise_dt = dt and updates occur every simulation step.

This implementation is vectorized over self.varshape and performs one PRNG split and one Gaussian draw per update() call, followed by a mask that either accepts the new sample or retains the previous amplitude. Work per call is \(O(\prod \mathrm{varshape})\).

Parameters:
  • in_size (Size, optional) – Output size/shape specification for brainstate.nn.Dynamics. The generated current shape is self.varshape derived from in_size. Default is 1.

  • mean (ArrayLike, optional) – Mean current \(\mu\) (typically pA). Scalars or arrays are accepted and broadcast to self.varshape by braintools.init.param(). Default is 0. * u.pA.

  • std (ArrayLike, optional) – Baseline standard deviation \(\sigma\) (typically pA), broadcast to self.varshape. Default is 0. * u.pA.

  • noise_dt (ArrayLike or None, optional) – Noise refresh interval \(\delta\) (typically ms). None means use simulation dt at runtime. Values are converted to integer steps by round(noise_dt / dt); valid execution requires this rounded value to be at least 1 for every channel. Default is None.

  • std_mod (ArrayLike, optional) – Modulation amplitude \(\sigma_{\mathrm{mod}}\) (typically pA) for the sinusoidal term in \(\sigma_{\mathrm{eff}}\). Broadcast to self.varshape. Default is 0. * u.pA.

  • frequency (ArrayLike, optional) – Modulation frequency \(f\) in Hz (or unitless values interpreted as Hz), broadcast to self.varshape. Converted internally to rad/ms using \(\omega = 2\pi f/1000\). Default is 0. * u.Hz.

  • phase (ArrayLike, optional) – Modulation phase in degrees, broadcast to self.varshape. Converted internally as \(\phi = \mathrm{phase}\cdot 2\pi/360\). Default is 0..

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

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

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

  • seed (int or None, optional) – PRNG seed used by jax.random.PRNGKey() in init_state(). None selects deterministic fallback seed 0. Default is None.

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

Parameter Mapping

Table 25 Parameter mapping to model symbols#

Parameter

Default

Math symbol

Semantics

mean

0. * u.pA

\(\mu\)

Mean of the Gaussian current samples.

std

0. * u.pA

\(\sigma\)

Baseline standard deviation of the noise process.

noise_dt

None

\(\delta\)

Interval between sample refreshes; defaults to simulation dt.

std_mod

0. * u.pA

\(\sigma_{\mathrm{mod}}\)

Amplitude of sinusoidal modulation in variance term.

frequency

0. * u.Hz

\(f\)

Modulation frequency converted to \(\omega=2\pi f/1000\).

phase

0.

\(\phi_{\mathrm{deg}}\)

Modulation phase in degrees, converted to radians in update.

start

0. * u.ms

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

Relative lower activity bound added to origin.

stop

None

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

Relative upper activity bound added to origin.

origin

0. * u.ms

\(t_0\)

Global time offset for both activity boundaries.

Raises:
  • ValueError – If in_size is invalid or if array-like parameters cannot be broadcast to self.varshape by braintools.init.param().

  • KeyError – If runtime environment keys such as 't' or 'dt' are missing when update() is called.

  • TypeError – If unitful/unitless arithmetic is incompatible (for example invalid combinations among time, frequency, and current parameters).

  • ZeroDivisionError – If round(noise_dt / dt) evaluates to 0 so modulo scheduling in update() attempts division by zero.

Notes

NEST describes independent random currents per target neuron. In this implementation, one generator instance emits one current vector per call; downstream targets reading the same channel receive the same value for that step. Use separate generator instances to guarantee independent streams.

See also

dc_generator

Constant current stimulation device.

ac_generator

Sinusoidal current stimulation device.

step_current_generator

Piecewise-constant current stimulation device.

References

Examples

Basic usage: unmodulated white-noise drive injected into a single neuron.

>>> import brainpy
>>> import brainstate
>>> import saiunit as u
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     stim = brainpy.state.noise_generator(
...         in_size=1,
...         mean=0.0 * u.pA,
...         std=100.0 * u.pA,
...         noise_dt=0.2 * u.ms,
...         seed=42,
...     )
...     neuron = brainpy.state.iaf_psc_delta(1)
...     neuron.init_state()
...     with brainstate.environ.context(t=1.0 * u.ms):
...         current = stim.update()
...         _ = neuron.update(x=current)

Sinusoidally modulated noise: variance oscillates at gamma frequency (40 Hz) within a restricted activity window.

>>> import brainpy
>>> import saiunit as u
>>> gen = brainpy.state.noise_generator(
...     in_size=4,
...     mean=50.0 * u.pA,
...     std=80.0 * u.pA,
...     noise_dt=1.0 * u.ms,
...     std_mod=40.0 * u.pA,
...     frequency=40.0 * u.Hz,
...     phase=0.0,
...     start=10.0 * u.ms,
...     stop=110.0 * u.ms,
...     seed=0,
... )
init_state(batch_size=None, **kwargs)[source]#

Initialize RNG and internal state buffers for piecewise noise updates.

Parameters:
  • batch_size (int or None, optional) – Optional batch dimension forwarded to braintools.init.param() when allocating current_amp. None keeps unbatched state. Default is None.

  • **kwargs (Any) – Extra keyword arguments accepted for API compatibility with brainstate.nn.Dynamics. They are currently unused.

Raises:
  • TypeError – If seed cannot be interpreted by jax.random.PRNGKey().

  • ValueError – If batch_size or shape metadata is incompatible with braintools.init.param().

Notes

The PRNG key is stored as a plain Python/JAX attribute rather than a brainstate.ShortTermState, meaning it is not managed by the brainstate state-management system and will not be checkpointed automatically. Reproducible runs therefore require re-calling init_state with the same seed before each simulation.

See also

noise_generator.update

Uses _rng_key, current_amp, and _step_counter populated by this method.

Examples

>>> import brainstate
>>> import saiunit as u
>>> from brainpy.state import noise_generator
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     gen = noise_generator(
...         in_size=2,
...         std=50.0 * u.pA,
...         seed=7,
...     )
...     gen.init_state()
update()[source]#

Advance the generator one simulation step and return current output.

Returns:

out – Current-like quantity with shape self.varshape. If active, values equal the cached piecewise-constant amplitude sampled from mean + N(0,1) * effective_std; otherwise values are zero.

Return type:

jax.Array

Raises:
  • KeyError – If environment keys 't' or 'dt' are missing.

  • TypeError – If unit conversions/comparisons are invalid (for example incompatible units in noise_dt, dt, or time bounds).

  • ZeroDivisionError – If round(noise_dt / dt) is 0 and modulo scheduling is evaluated with zero divisor.

Notes

The update proceeds in four phases each call:

  1. Step schedulingnoise_dt is resolved to a whole number of simulation steps dt_steps = round(noise_dt / dt). A boolean flag need_update = (step_counter % dt_steps) == 0 gates whether a new amplitude is drawn.

  2. Effective standard deviation – computed as

    \[\sigma_{\mathrm{eff}} = \sqrt{\max\!\left(\sigma^2 + \sigma_{\mathrm{mod}}^2 \sin(\omega t + \phi),\, 0\right)}\]

    using u.math.maximum() before u.math.sqrt() so the radicand is always non-negative.

  3. Sample drawnoise = jax.random.normal(subkey, varshape); the PRNG key is advanced every call regardless of need_update.

  4. Masked updatecurrent_amp retains its previous value on steps where need_update is False, avoiding redundant draws while keeping the sample schedule deterministic.

The activity window is origin + start <= t < origin + stop (lower-bounded only when stop is None). While inactive the output is exactly zero regardless of current_amp.

See also

noise_generator.init_state

Must be called before the first update.

noise_generator

Class-level parameter definitions and model equations.

ac_generator.update

Windowed sinusoidal-current update rule.