pulsepacket_generator#
- class brainpy.state.pulsepacket_generator(in_size=1, pulse_times=None, activity=0, sdev=Quantity(0., 'ms'), start=Quantity(0., 'ms'), stop=None, origin=Quantity(0., 'ms'), rng_seed=0, sdev_tolerance=10.0, name=None)#
Gaussian pulse-packet spike generator compatible with NEST.
Description
pulsepacket_generatorre-implements NEST’s stimulation device with the same name and emits integer per-step spike multiplicities.1. Pulse model and grid projection
For each configured pulse center \(t_c\) (ms), this model generates exactly
activitysampled spike times per output generator:\[x_{i,j} \sim \mathcal{N}(t_c, \mathrm{sdev}^2), \quad i=1,\dots,N,\ j=1,\dots,\mathrm{activity},\]where \(N=\prod \mathrm{varshape}\) is the number of independent generators. For
sdev == 0, the Gaussian draw degenerates to the deterministic value \(x_{i,j}=t_c\).Sampled times are converted to NEST-like integer tics and delivery steps:
\[\tau = \left\lfloor x \cdot 1000 + 0.5 \right\rfloor,\qquad k = \left\lceil \tau / \Delta\tau \right\rceil,\]where \(\Delta\tau\) is the resolution in tics per simulation step. Samples with
tau < tau_noware discarded; the remaining samples are queued and emitted as multiplicity counts at their delivery steps.2. NEST update ordering (source-equivalent)
This implementation mirrors
models/pulsepacket_generator.cpp:Keep indices
start_center_idx/stop_center_idxinto sortedpulse_timesfor a moving window of centers around current time.At each update step, extend the right edge of that center window while
center_time - t <= tolerance.For each newly entered center, sample
activityGaussian times, keep only samples withsample_time >= t, convert them to integer steps, and append to a per-generator queue.Sort each queue.
Emit (pop) all queued spikes whose integer step is in the current delivery interval and return per-step multiplicity.
As in NEST,
tolerance = sdev * 10forsdev > 0andtolerance = 1.0 msotherwise.3. Timing semantics (CURRENT_GENERATOR shift)
NEST classifies this model as
CURRENT_GENERATORinget_type(). Therefore activity is evaluated with theStimulationDevicecurrent-generator shift:\[t_{\min} < (n + 2) \le t_{\max},\]where
nis the current simulation step andt_min = origin + start,t_max = origin + stop(in steps).This differs from regular spike generators and is intentionally preserved for behavioral parity.
4. Assumptions, constraints, and computational implications
Enforced constraints:
activityis an integer scalar withactivity >= 0.sdevis a scalar in ms withsdev >= 0.stop >= startafter scalar conversion.sdev_tolerance > 0.
Runtime constraints:
If
dtis available, finiteorigin,start, andstopmust be exact grid multiples (absolute tolerance1e-12intime / dt).pulse_timesare flattened to 1-D and sorted ascending before use.
Computational implications:
Let
C_newbe newly entered pulse centers in one step. New pulse generation costs \(O(C_{\mathrm{new}} \cdot N \cdot \mathrm{activity})\) sampling plus per-queue sort when new events are appended.Emission costs \(O(N + M_{\mathrm{pop}})\) where \(M_{\mathrm{pop}}\) is number of emitted queued spikes in the step.
Memory is proportional to the total number of queued future spikes across all output generators.
- Parameters:
in_size (
Size, optional) – Output size specification consumed bybrainstate.nn.Dynamics.self.varshapederived from this value is the exact shape returned byupdate(). Each element is one independent output generator. Default is1.pulse_times (
Sequence[ArrayLike]orArrayLikeorNone, optional) – Pulse center times in ms. Accepted inputs are any array-like values flattenable to shape(K,)after conversion, or asaiunit.Quantityconvertible tou.ms.Nonecreates an empty schedule. Values are sorted internally in ascending order. Default isNone.activity (
ArrayLike, optional) – Scalar integer count per pulse center, shape()after conversion. Parsed through nearest-integer check with absolute tolerance1e-12and must satisfyactivity >= 0. Default is0.sdev (
ArrayLike, optional) – Scalar standard deviation in ms, shape()after conversion. Accepts unitful time convertible tou.msor scalar numeric. Must satisfysdev >= 0. Default is0.0 * u.ms.start (
ArrayLike, optional) – Scalar relative start time in ms, shape()after conversion. Effective lower bound isorigin + startunder current-generator semantics and must be grid-representable whendtis available. Default is0.0 * u.ms.stop (
ArrayLikeorNone, optional) – Scalar relative stop time in ms, shape()after conversion.Nonemaps to+inf. When finite, must satisfystop >= startand be grid-representable whendtis available. Default isNone.origin (
ArrayLike, optional) – Scalar origin offset in ms, shape()after conversion. Added tostartandstopto form absolute activity bounds. Must be grid-representable when finite anddtis available. Default is0.0 * u.ms.rng_seed (
int, optional) – Seed used to initializenumpy.random.default_rngininit_state(). Default is0.sdev_tolerance (
float, optional) – Positive multiplicative factor used to compute tolerance windowsdev * sdev_tolerancewhensdev > 0. NEST default is10.0.name (
str, optional) – Optional node name passed tobrainstate.nn.Dynamics.
Parameter Mapping
Table 39 Parameter mapping to model symbols# Parameter
Default
Math symbol
Semantics
pulse_timesNone\(t_c\)
Pulse-center schedule in ms (internally sorted ascending).
activity0\(n_{\mathrm{spk}}\)
Number of sampled spikes generated per center and output train.
sdev0.0 * u.ms\(\sigma_t\)
Temporal jitter standard deviation in ms.
start0.0 * u.ms\(t_{\mathrm{start,rel}}\)
Relative lower activity bound (with CURRENT_GENERATOR shift).
stopNone\(t_{\mathrm{stop,rel}}\)
Relative upper activity bound;
Nonemaps to+\infty.origin0.0 * u.ms\(t_0\)
Global offset added to
startandstop.sdev_tolerance10.0\(\kappa\)
Tolerance factor for center-window inclusion,
\kappa \sigma_t.in_size1Defines
self.varshape/ number of independent generators.rng_seed0Seed for NumPy RNG used for Gaussian pulse sampling.
- Raises:
ValueError – If
activityis negative or non-integral; ifsdevis negative; ifstop < start; ifsdev_tolerance <= 0; if scalar conversion fails due to non-scalar input shape; if backend data has fewer than three values; if finiteorigin/start/stopare not grid multiples whendtis available; or if simulation resolution is non-positive.TypeError – If time-valued arguments cannot be converted to
u.ms-compatible values or numeric arrays.KeyError – At runtime, if required simulation context entries (for example
dtfrombrainstate.environ.get_dt()) are unavailable.
Notes
set(activity=...)andset(sdev=...)trigger pulse re-generation behavior by clearing queued spikes, matching NEST.Stimulation-backend parameter order in NEST is
[activity, sdev_ms, pulse_time_0_ms, ...]and is exposed viaset_data_from_stimulation_backend().Pulse times that are too far in the past (
sample_time < t) are silently discarded during generation; no error is raised.Outputs are integer multiplicities
0, 1, 2, ...per step, matching NESTSpikeEventmultiplicity semantics rather than binary spike flags.
See also
poisson_generatorIndependent Poisson spike trains at fixed rate.
mip_generatorCorrelated spike trains via Multiple Interaction Process.
inhomogeneous_poisson_generatorPoisson generator with time-varying rate.
gamma_sup_generatorSuperposition of stationary gamma-process trains.
Examples
>>> import brainpy >>> import brainstate >>> import saiunit as u >>> with brainstate.environ.context(dt=0.1 * u.ms): ... gen = brainpy.state.pulsepacket_generator( ... in_size=(2, 3), ... pulse_times=[10.0 * u.ms, 20.0 * u.ms], ... activity=5, ... sdev=1.5 * u.ms, ... start=0.0 * u.ms, ... stop=40.0 * u.ms, ... rng_seed=7, ... ) ... with brainstate.environ.context(t=10.0 * u.ms): ... counts = gen.update() ... _ = counts.shape
>>> import brainpy >>> import saiunit as u >>> gen = brainpy.state.pulsepacket_generator(activity=3, sdev=0.5 * u.ms) >>> gen.set_data_from_stimulation_backend([4.0, 0.8, 5.0, 15.0, 25.0]) >>> params = gen.get() >>> _ = params['activity'], params['pulse_times']
References
- get()[source]#
Return current public parameter values.
- Returns:
out –
dictwith keyspulse_times,activity,sdev,start,stop, andorigin. Time values are returned in milliseconds as Pythonfloatvalues, andpulse_timesis a Pythonlist[float].- Return type:
- init_state(batch_size=None, **kwargs)[source]#
Initialize runtime state for stochastic pulse generation.
- Parameters:
- Raises:
ValueError – If
dtis available and finite timing parameters are not grid multiples, or if computed simulation resolution is non-positive.TypeError – If environment times cannot be converted to scalar milliseconds.
Notes
Re-initialization resets queues and deterministic random state from
rng_seed; pending queued spikes are discarded.
- set(*, pulse_times=<object object>, activity=<object object>, sdev=<object object>, start=<object object>, stop=<object object>, origin=<object object>)[source]#
Set public parameters with NEST-compatible update semantics.
- Parameters:
pulse_times (
Sequence[ArrayLike]orArrayLikeorobject, optional) – New pulse-center schedule in ms. Any provided value is converted to a flattenedfloat64array and sorted ascending. Pass_UNSET(default) to keep current pulse times.activity (
ArrayLikeorobject, optional) – New scalar integer spikes-per-center value, shape()after conversion, withactivity >= 0. Pass_UNSETto keep the current value.sdev (
ArrayLikeorobject, optional) – New scalar temporal jitter standard deviation in ms, shape()after conversion, withsdev >= 0. Pass_UNSETto keep the current value.start (
ArrayLikeorobject, optional) – New scalar relative start time in ms, shape()after conversion. Pass_UNSETto keep the current value.stop (
ArrayLikeorNoneorobject, optional) – New scalar relative stop time in ms, shape()after conversion.Nonemaps to+inf. Pass_UNSETto keep the current value.origin (
ArrayLikeorobject, optional) – New scalar origin offset in ms, shape()after conversion. Pass_UNSETto keep the current value.
- Raises:
ValueError – If integer/scalar validation fails, if
activity < 0,sdev < 0,stop < start, or if finite time bounds are not aligned to the simulation grid whendtis available.TypeError – If provided values cannot be converted to expected numeric/time forms.
Notes
Matching NEST behavior, changing either
activityorsdevtriggers pulse re-generation state reset by clearing queued spikes.
- set_data_from_stimulation_backend(input_param)[source]#
Update parameters from stimulation-backend payload.
- Parameters:
input_param (
Sequence[float]ornumpy.ndarray) – One-dimensional backend payload with shape(M,)andM >= 3in NEST order:[activity, sdev_ms, pulse_time_0_ms, ...]. Entries are parsed asfloat64.sdevandpulse_timesare interpreted in ms.- Raises:
ValueError – If payload length is between 1 and 2 (inclusive), since at least
activity,sdev, and one pulse time are required by this backend contract.TypeError – If payload cannot be cast to numeric
float64values.
- update()[source]#
Advance one simulation step and emit spike multiplicities.
- Returns:
out – JAX array of dtype
int64and shapeself.varshape. Each element is the number of spikes emitted by one output generator in the current step. Returns all zeros when inactive or when no spikes are due.- Return type:
jax.Array- Raises:
ValueError – If runtime
dtis non-positive, if finite activity bounds are not grid multiples, or if cached time-step conversion becomes invalid.TypeError – If runtime time values cannot be converted to scalar milliseconds.
KeyError – If required simulation context entries are missing.
Notes
If state has not been initialized explicitly,
update()performs lazy initialization by callinginit_state().