rate_neuron_opn#
- class brainpy.state.rate_neuron_opn(*args, **kwargs)#
NEST-compatible
rate_neuron_opnoutput-noise rate-neuron template.rate_neuron_opnimplements the NEST template modelrate_neuron_opn<TNonlinearities>with the deterministic dynamics\[\tau \frac{dX(t)}{dt} = -X(t) + \mu + I_\mathrm{net}(t),\]and output noise applied after the nonlinearity:
\[X_\mathrm{noisy}(t) = X(t) + \sqrt{\frac{\tau}{h}}\,\sigma\,\xi(t),\]where \(X(t)\) is the deterministic rate state, \(\tau\) is the time constant, \(\mu\) is the mean drive, \(\sigma\ge 0\) is the output-noise strength, \(h\) is the simulation time step, and \(\xi(t)\sim\mathcal{N}(0,1)\) is standard Gaussian white noise approximated as piecewise constant over \(h\).
With default callables this is equivalent to NEST
lin_rate_opn:input(h) = g * hmult_coupling_ex(rate) = g_ex * (theta_ex - rate)mult_coupling_in(rate) = g_in * (theta_in + rate)
Mathematical Description
1. Continuous-Time Deterministic Dynamics
The deterministic rate state \(X(t)\) evolves according to
\[\tau \frac{dX(t)}{dt} = -X(t) + \mu + I_\mathrm{net}(t),\]where \(\tau>0\) is the time constant and \(I_\mathrm{net}(t)\) is the network input decomposed as
\[I_\mathrm{net}(t) = H_\mathrm{ex}(X_\mathrm{noisy}) \cdot g(I_\mathrm{ex}(t)) + H_\mathrm{in}(X_\mathrm{noisy}) \cdot g(I_\mathrm{in}(t)),\]where:
\(I_\mathrm{ex}(t)\) and \(I_\mathrm{in}(t)\) are excitatory and inhibitory synaptic input branches.
\(g(\cdot)\) is the input nonlinearity. Default: \(g(h)=g\,h\).
\(H_\mathrm{ex}(X_\mathrm{noisy})\) and \(H_\mathrm{in}(X_\mathrm{noisy})\) are optional multiplicative coupling factors dependent on the noisy rate. Default: \(H_\mathrm{ex}=g_\mathrm{ex}(\theta_\mathrm{ex}-X_\mathrm{noisy})\), \(H_\mathrm{in}=g_\mathrm{in}(\theta_\mathrm{in}+X_\mathrm{noisy})\). Only active if
mult_coupling=True.
The
linear_summationswitch controls whether the nonlinearity is applied to the summed input or to individual synaptic branches:linear_summation=True: \(I_\mathrm{net}(t) = H\cdot g(I_\mathrm{ex}+I_\mathrm{in})\).linear_summation=False: \(I_\mathrm{net}(t) = H_\mathrm{ex}\cdot g(I_\mathrm{ex}) + H_\mathrm{in}\cdot g(I_\mathrm{in})\).
2. Output Noise (Postsynaptic Noise Model)
Output noise is added after the deterministic dynamics, creating a noisy observation of the rate:
\[X_\mathrm{noisy}(t) = X(t) + \sqrt{\frac{\tau}{h}}\,\sigma\,\xi(t),\]where \(\xi(t)\sim\mathcal{N}(0,1)\) is standard Gaussian white noise. The scaling factor \(\sqrt{\tau/h}\) ensures that the noise amplitude is independent of the discretization time step \(h\) in the limit \(h\to 0\).
Critical difference from input-noise model: The noisy rate \(X_\mathrm{noisy}\) is used for multiplicative coupling evaluation (if
mult_coupling=True) and as the outgoing signal to downstream neurons, but the noise does not feed back into the deterministic dynamics. This contrasts with the input-noise variant (rate_neuron_ipn) where noise enters the differential equation directly.3. Discrete-Time Integration
For time step \(h=dt\) (in ms), the deterministic part uses exponential Euler integration (exact for the linear ODE):
\[X_{n+1} = P_1 X_n + P_2 (\mu + I_\mathrm{net,n}),\]where
\[P_1 = \exp(-h/\tau), \quad P_2 = 1 - P_1 = -\mathrm{expm1}(-h/\tau).\]Output noise is added independently at each step:
\[X_\mathrm{noisy,n} = X_n + \sqrt{\frac{\tau}{h}}\,\sigma\,\xi_n,\]where \(\xi_n\sim\mathcal{N}(0,1)\) is drawn at each step.
4. Update Ordering (Matching NEST ``rate_neuron_opn_impl.h``)
Per simulation step:
Draw noise sample \(\xi_n\sim\mathcal{N}(0,1)\), compute \(\mathrm{noise}_n = \sigma\,\xi_n\).
Compute noisy rate: \(X_\mathrm{noisy,n} = X_n + \sqrt{\tau/h}\,\mathrm{noise}_n\).
Propagate deterministic intrinsic dynamics: \(X' = P_1 X_n + P_2 (\mu + \mu_\mathrm{ext})\).
Read delayed and instantaneous event buffers.
Apply network input according to NEST semantics:
linear_summation=True: nonlinearity applied to summed branch input during update.linear_summation=False: nonlinearity applied per incoming event while buffering (handled in event processing).
If
mult_coupling=True, multiplicative coupling factors \(H_\mathrm{ex}(X_\mathrm{noisy,n})\) and \(H_\mathrm{in}(X_\mathrm{noisy,n})\) are evaluated at the noisy rate (matching NESTrate_neuron_opn_impl.h).Store updated
rate,noise, and exposenoisy_rateas outgoing delayed/instantaneous event value.
5. Stability Constraints and Computational Implications
Construction enforces \(\tau>0\), \(\sigma\ge 0\).
The deterministic dynamics are unconditionally stable (exponential relaxation to \(\mu + I_\mathrm{net}\) with time constant \(\tau\)).
Output noise does not affect stability but may violate rate bounds; no automatic rectification is provided (unlike
rate_neuron_ipn).Noise variance scales as \(\tau\sigma^2/h\) per step. For fixed \(\tau\) and \(\sigma\), this diverges as \(h\to 0\), reflecting the white-noise nature of \(\xi(t)\).
The exponential Euler scheme is numerically stable for all \(h>0\).
Per-call cost is \(O(\prod\mathrm{varshape})\) with vectorized NumPy operations in
float64for coefficient evaluation and state update.
- Parameters:
in_size (
Size) – Population shape specification (tuple of int or single int). All per-neuron parameters are broadcast toself.varshape. For example,in_size=10creates 10 neurons,in_size=(4, 5)creates a 4×5 grid.tau (
ArrayLike, optional) – Time constant \(\tau\) (brainunit quantity with ms dimension). Scalar or array broadcastable toself.varshape. Must be \(>0\). Controls the exponential relaxation rate of the deterministic dynamics. Default:10.0 * u.ms.sigma (
ArrayLike, optional) – Output-noise scale \(\sigma\) (dimensionless scalar or array). Broadcastable toself.varshape. Must be \(\ge 0\). Determines the standard deviation of the Gaussian noise added to the output rate. Default:1.0.mu (
ArrayLike, optional) – Mean drive \(\mu\) (dimensionless scalar or array). Broadcastable toself.varshape. External constant input to the rate dynamics, added to the network input. Default:0.0.g (
ArrayLike, optional) – Linear gain parameter \(g\) (dimensionless scalar or array). Broadcastable toself.varshape. Used by the default input nonlinearity \(g(h)=g\,h\). Ignored ifinput_nonlinearityis provided. Default:1.0.mult_coupling (
bool, optional) – Enable multiplicative coupling (rate-dependent synaptic efficacy). IfTrue, applies \(H_\mathrm{ex}(X_\mathrm{noisy})\) and \(H_\mathrm{in}(X_\mathrm{noisy})\) to synaptic inputs, evaluated at the noisy rate. IfFalse, \(H_\mathrm{ex}=H_\mathrm{in}=1\). Default:False.g_ex (
ArrayLike, optional) – Excitatory multiplicative coupling gain \(g_\mathrm{ex}\) (dimensionless scalar or array). Broadcastable toself.varshape. Only used ifmult_coupling=True. Default:1.0.g_in (
ArrayLike, optional) – Inhibitory multiplicative coupling gain \(g_\mathrm{in}\) (dimensionless scalar or array). Broadcastable toself.varshape. Only used ifmult_coupling=True. Default:1.0.theta_ex (
ArrayLike, optional) – Excitatory coupling reference rate \(\theta_\mathrm{ex}\) (dimensionless scalar or array). Broadcastable toself.varshape. Only used ifmult_coupling=True. Default:0.0.theta_in (
ArrayLike, optional) – Inhibitory coupling reference rate \(\theta_\mathrm{in}\) (dimensionless scalar or array). Broadcastable toself.varshape. Only used ifmult_coupling=True. Default:0.0.linear_summation (
bool, optional) – NEST switch controlling where the input nonlinearity is applied. IfTrue, the nonlinearity is applied to the sum of excitatory and inhibitory inputs (post-summation). IfFalse, the nonlinearity is applied separately to each input branch before summation (per-branch). Default:True.input_nonlinearity (
Callable[[ArrayLike],ArrayLike]orCallable[[rate_neuron_opn,ArrayLike],ArrayLike]orNone, optional) – Custom input nonlinearity \(g(\cdot)\) replacing the default \(g(h)=g\,h\). Callable signature can bef(h)(receives float64 NumPy array of shapestate_shape, returns array of same shape) orf(model, h)(receives model instance and array, returns array). Must be vectorized and compatible with NumPy broadcasting. IfNone, uses default linear gain. Default:None.mult_coupling_ex_fn (
Callable[[ArrayLike],ArrayLike]orCallable[[rate_neuron_opn,ArrayLike],ArrayLike]orNone, optional) – Custom excitatory multiplicative coupling function \(H_\mathrm{ex}(X_\mathrm{noisy})\). Callable signature can bef(rate)orf(model, rate). Must return array of same shape as input. Evaluated at the noisy rate. IfNone, uses default \(g_\mathrm{ex}(\theta_\mathrm{ex}-X_\mathrm{noisy})\). Default:None.mult_coupling_in_fn (
Callable[[ArrayLike],ArrayLike]orCallable[[rate_neuron_opn,ArrayLike],ArrayLike]orNone, optional) – Custom inhibitory multiplicative coupling function \(H_\mathrm{in}(X_\mathrm{noisy})\). Callable signature can bef(rate)orf(model, rate). Must return array of same shape as input. Evaluated at the noisy rate. IfNone, uses default \(g_\mathrm{in}(\theta_\mathrm{in}+X_\mathrm{noisy})\). Default:None.rate_initializer (
Callable, optional) – Initializer for the deterministicratestate variable \(X_0\). Callable compatible withbraintools.initAPI (signature:(shape, batch_size) -> ArrayLike). Default:braintools.init.Constant(0.0).noise_initializer (
Callable, optional) – Initializer for thenoisestate variable (records last noise sample \(\sigma\,\xi_{n-1}\)). Callable compatible withbraintools.initAPI. Default:braintools.init.Constant(0.0).noisy_rate_initializer (
Callable, optional) – Initializer for thenoisy_ratestate variable \(X_\mathrm{noisy,0}\) and outgoing event values. Callable compatible withbraintools.initAPI. Default:braintools.init.Constant(0.0).name (
strorNone, optional) – Module name for identification in hierarchies. IfNone, auto-generates a unique name. Default:None.
Parameter Mapping
The following table maps NEST
rate_neuron_opn/lin_rate_opnparameters to brainpy.state equivalents:NEST Parameter
brainpy.state
Default
tautau10 ms
sigmasigma1.0
mumu0.0
g(nonlinearity gain)g1.0
mult_couplingmult_couplingFalse
g_ex,g_ing_ex,g_in1.0
theta_ex,theta_intheta_ex,theta_in0.0
linear_summationlinear_summationTrue
- rate#
Deterministic rate state \(X_n\) (float64 array of shape
self.varshapeor(batch_size,) + self.varshape). This is the noise-free rate variable.- Type:
brainstate.ShortTermState
- noise#
Last noise sample \(\sigma\,\xi_{n-1}\) (float64 array, same shape as
rate). Records the noise term used in the previous step.- Type:
brainstate.ShortTermState
- noisy_rate#
Noisy rate \(X_\mathrm{noisy,n} = X_n + \sqrt{\tau/h}\,\mathrm{noise}_n\) (float64 array, same shape as
rate). This is the outgoing signal sent to downstream neurons and used for multiplicative coupling evaluation.- Type:
brainstate.ShortTermState
- instant_rate#
Noisy rate value for instantaneous event propagation (float64 array, same shape as
rate). Set tonoisy_rateafter each update.- Type:
brainstate.ShortTermState
- delayed_rate#
Noisy rate value for delayed projections (float64 array, same shape as
rate). Set tonoisy_rateafter each update.- Type:
brainstate.ShortTermState
- _step_count#
Internal step counter for delayed event scheduling (int64 scalar). Incremented by 1 after each
updatecall.- Type:
brainstate.ShortTermState
- _delayed_ex_queue#
Internal queue mapping
step_idx(int) to accumulated excitatory delayed events (float64 array of shapestate_shape).- Type:
- _delayed_in_queue#
Internal queue mapping
step_idx(int) to accumulated inhibitory delayed events (float64 array of shapestate_shape).- Type:
- Raises:
ValueError – If
tau <= 0(checked during__init__via_validate_parameters).ValueError – If
sigma < 0(checked during__init__via_validate_parameters).ValueError – If
instant_rate_eventscontain non-zerodelay_steps(checked duringupdatevia_accumulate_instant_events).ValueError – If
delayed_rate_eventscontain negativedelay_steps(checked duringupdatevia_schedule_delayed_events).ValueError – If event tuples have length other than 2, 3, or 4 (checked during
updatevia_extract_event_fields).
Notes
Runtime Events
Events can be provided to
update()viainstant_rate_eventsanddelayed_rate_eventsparameters. Each event can be specified as:Scalar: Treated as
ratevalue withweight=1.0.Tuple:
(rate, weight)or(rate, weight, delay_steps)or(rate, weight, delay_steps, multiplicity).Dict: Keys
'rate'/'coeff'/'value'(event value),'weight'(synaptic weight),'delay_steps'/'delay'(integer delay in time steps),'multiplicity'(event count).
Sign Convention: Events with
weight >= 0contribute to the excitatory branch; events withweight < 0contribute to the inhibitory branch.Linear Summation Semantics: For
linear_summation=False, event values are transformed by the input nonlinearity during buffering (matching NEST event handlers). Forlinear_summation=True, the nonlinearity is applied to the summed input during the update step.Comparison to ``rate_neuron_ipn``
The
_opnvariant uses output noise (applied after nonlinearity and transmitted to downstream neurons), while_ipnuses input noise (applied before dynamics propagation, directly affecting the state evolution). This leads to different stationary distributions, noise scaling, and stability properties. In_opn, noise does not feed back into the deterministic dynamics.Examples
Minimal output-noise rate neuron:
>>> from brainpy import state as bst >>> import brainunit as u >>> model = bst.rate_neuron_opn(in_size=10, tau=20*u.ms, sigma=0.5) >>> model.init_all_states(batch_size=1) >>> rate = model(x=0.1) # external drive >>> print(rate.shape) (1, 10)
Multiplicative coupling with custom nonlinearity:
>>> import numpy as np >>> def tanh_nonlin(h): ... return np.tanh(h) >>> model = bst.rate_neuron_opn( ... in_size=5, ... tau=10*u.ms, ... sigma=0.3, ... mult_coupling=True, ... g_ex=1.5, theta_ex=1.0, ... input_nonlinearity=tanh_nonlin ... )
Accessing noisy rate output:
>>> model = bst.rate_neuron_opn(in_size=3, tau=10*u.ms, sigma=0.2) >>> model.init_all_states() >>> rate_deterministic = model.update(x=0.5) # propagates deterministic dynamics >>> rate_noisy = model.noisy_rate.value # includes output noise >>> print(rate_noisy.shape) (3,)
References
See also
rate_neuron_ipnInput-noise variant of the rate neuron template.
lin_rateDeterministic linear rate neuron (
sigma=0).
- init_state(**kwargs)[source]#
Initialize all state variables for simulation.
This method must be called before the first
update()call. It creates all internal state variables (rate,noise,noisy_rate,instant_rate,delayed_rate,_step_count) and resets the delayed event queues.- Parameters:
**kwargs – Unused compatibility parameters accepted by the base-state API.
Notes
Initialized State Variables
This method initializes the following state variables:
rate (
brainstate.ShortTermState): Deterministic rate state \(X_n\) (float64 array). Initialized usingrate_initializer.noise (
brainstate.ShortTermState): Last noise sample \(\sigma\,\xi_{n-1}\) (float64 array). Initialized usingnoise_initializer.noisy_rate (
brainstate.ShortTermState): Noisy rate \(X_\mathrm{noisy,n} = X_n + \sqrt{\tau/h}\,\mathrm{noise}_n\) (float64 array). Initialized usingnoisy_rate_initializer.instant_rate (
brainstate.ShortTermState): Noisy rate value for instantaneous event propagation (float64 array). Initialized as a copy ofnoisy_rate.delayed_rate (
brainstate.ShortTermState): Noisy rate value for delayed projections (float64 array). Initialized as a copy ofnoisy_rate._step_count (
brainstate.ShortTermState): Internal step counter for delayed event scheduling (int64 scalar). Initialized to0._delayed_ex_queue (dict): Internal queue mapping
step_idx(int) to accumulated excitatory delayed events (float64 array). Initialized as empty dict._delayed_in_queue (dict): Internal queue mapping
step_idx(int) to accumulated inhibitory delayed events (float64 array). Initialized as empty dict.
Array Precision
All state arrays are float64 NumPy arrays. All parameters (
tau,sigma,mu, etc.) are coerced to float64 during initialization.Repeated Calls
Calling
init_state()multiple times will overwrite existing state variables and clear the delayed event queues. This can be used to reset the model to initial conditions.Examples
Initialize a single population:
>>> from brainpy import state as bst >>> import brainunit as u >>> model = bst.rate_neuron_opn(in_size=10, tau=20*u.ms) >>> model.init_state() >>> print(model.rate.value.shape) (10,)
Custom initializers:
>>> import braintools >>> model = bst.rate_neuron_opn( ... in_size=5, ... tau=10*u.ms, ... rate_initializer=braintools.init.Normal(0.5, 0.1), ... noisy_rate_initializer=braintools.init.Normal(0.5, 0.1) ... ) >>> model.init_state() >>> print(model.rate.value.mean()) # approximately 0.5
See also
updatePerform one simulation step after initialization.
- property receptor_types#
Receptor type dictionary for projection compatibility.
- Returns:
{'RATE': 0}. Rate neurons have a single receptor type.- Return type:
dict[str,int]
- property recordables#
List of state variable names that can be recorded.
- update(x=0.0, noise=None)[source]#
Advance the output-noise rate dynamics by one step.
Network coupling arrives continuously through the substrate’s delta channel (seam-(H)): \(h=\sum_\mathrm{delta} w\,r_\mathrm{pre}\) is read from
sum_delta_inputs(0.0)and the external drive fromsum_current_inputs(x, rate). Output noise is added to form the noisy rate \(X_\mathrm{noisy}\) before the multiplicative coupling factors are evaluated. The whole step lowers underbrainstate.transform.for_loop/jit.- Parameters:
x (
ArrayLike, optional) – External drive added tomu(broadcast toself.varshape).noise (
ArrayLike, optional) – Externally supplied \(\xi_n\); drawn from \(\mathcal{N}(0,1)\) whenNone.
- Returns:
rate_new – Updated rate \(X_{n+1}\) (shape
self.rate.value.shape).- Return type:
ArrayLike