Stimuli

External inputs, built with Stimulus(param, post, sym, [comp]; kwargs...); the type of param selects the model. Usage: Stimuli.

StimulusParameter typesWritesPresynaptic layer
PoissonStimulusPoissonFixed, PoissonInterval, PoissonVariableadds μ per input spike to gnone (one independent train per target)
PoissonStimulusLayerPoissonLayer, PoissonLayerHetadds W[i,j] per spike of layer neuron jN Poisson neurons, sparse weights
SpikeTimeStimulusSpikeTimeStimulusParameteradds W[i,j] per listed spikeN virtual neurons, sparse weights
CurrentStimulusCurrentNoisesets the current Inone
BalancedStimulusBalancedParameteradds Poisson E and I inputnone
StimulusGroup(shared Poisson parameter)its elements
EmptyStimulusEmptyParamnothing (placeholder)

Poisson stimulus

One independent Poisson process per targeted neuron:

\[g_n \leftarrow g_n + \mu\, k_n, \qquad k_n \sim \mathrm{Poisson}\big(\nu(t)\,\Delta t\big)\]

ParameterRate $\nu(t)$
PoissonFixed(; rate, μ)rate
PoissonInterval(; rate, intervals, μ)rate if int[1] < t < int[end] for some int in intervals, else 0
PoissonVariable(; variables, rate::Function, μ)rate(t, variables)
FieldDefaultUnitsMeaning
rate0 (PoissonFixed), required otherwiserate (Hz)rate per target neuron
intervals[]msPoissonInterval only: list of [start, end]
variablesrequiredPoissonVariable only: arguments of the rate function
μ1.0units of the target variableincrement per input spike
active[true]on/off switch, see set_active!
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
fixed = SNN.Stimulus(SNN.PoissonFixed(rate = 2kHz, μ = 1.0), E, :ge)
pulses = SNN.Stimulus(SNN.PoissonInterval(rate = 1kHz, intervals = [[100ms, 200ms]]), E, :ge; neurons = 1:20)
osc(t, v) = v[:r0] * (1 + sin(2π * t / v[:period]))
rhythm = SNN.Stimulus(SNN.PoissonVariable(variables = Dict{Symbol,Any}(:r0 => 1kHz, :period => 100ms), rate = osc), E, :ge)
model = SNN.compose(; E, fixed, pulses, rhythm)
SNN.monitor!(E, :fire)
SNN.sim!(; model, duration = 300ms)
SNNModels.PoissonFixed — Type
PoissonFixed(; rate = 0, μ = 1.0f0, active = [true])

Rate parameter of a PoissonStimulus with a constant rate. Every targeted neuron receives an independent Poisson spike train of rate rate.

Fields

  • rate::Float32 = 0: rate of the Poisson input per target neuron (library units, use Hz; e.g. rate = 10Hz).
  • μ::Float32 = 1.0: increment of the target variable per input spike.
  • active::Vector{Bool} = [true]: the stimulus is applied only if active[1].

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
stim = SNN.Stimulus(SNN.PoissonFixed(rate = 100Hz, μ = 0.5), E, :ge)
source
SNNModels.PoissonInterval — Type
PoissonInterval(; rate, intervals = Vector{Vector{Float32}}([]), μ = 1.0f0, active = [true])

Rate parameter of a PoissonStimulus that is on only inside given time intervals. The rate is rate when the current time t satisfies int[1] < t < int[end] for at least one interval int in intervals, and 0 otherwise.

Fields

  • rate::Float32 (required): rate per target neuron while active (use Hz).
  • intervals::Vector{Vector{Float32}} = []: list of [start, end] intervals in ms; can be replaced at runtime with set_intervals!.
  • μ::Float32 = 1.0: increment of the target variable per input spike.
  • active::Vector{Bool} = [true]: the stimulus is applied only if active[1].

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
param = SNN.PoissonInterval(rate = 50Hz, intervals = [[100ms, 200ms], [400ms, 500ms]])
stim = SNN.Stimulus(param, E, :ge)
source
SNNModels.PoissonStimulus — Type
PoissonStimulus(post::AbstractPopulation, sym::Symbol; param::PoissonStimulusParameter,
                neurons = :ALL, comp = nothing, p_post = -1, name = "Poisson")
Stimulus(param::PoissonStimulusParameter, post, sym; kwargs...)

Independent Poisson spike trains delivered directly to a target variable of post.

Each targeted neuron n receives its own Poisson process of rate $\nu(t)$ given by get_poisson_rate(param, time). There is no presynaptic population and no weight matrix: every input spike adds param.μ to the target variable g (the receptor or conductance selected by sym, and comp for multicompartment neurons).

Equations

At each step, for every targeted neuron $n$:

\[g_n \leftarrow g_n + \mu\, k_n, \qquad k_n \sim \mathrm{Poisson}(\nu(t)\,\Delta t)\]

Nothing is added when $\nu(t)\,\Delta t \le 0$ or when param.active[1] == false.

The counts are sampled sparsely, at a cost proportional to the number of input spikes (see stimulate!). Neurons written are logged in inbox (see attach_driver!).

Constructor arguments

  • post: target population.
  • sym::Symbol: target variable, resolved by synaptic_target of the population type (e.g. :ge/:glu and :gi/:gaba for generalized IF neurons).
  • param (required): PoissonFixed, PoissonInterval or PoissonVariable.
  • neurons = :ALL: all neurons of post; a Vector{Int} of indices; or :p_post to sample round(Int, p_post * post.N) neurons without replacement (if p_post is outside [0, 1] a warning is emitted and all neurons are used).
  • comp = nothing: compartment (multicompartment models, e.g. :d1).
  • p_post = -1: fraction of targeted neurons, used only with neurons = :p_post.
  • remaining keywords (e.g. name = "Poisson", id) are forwarded to the struct.

Fields

  • id::String, name::String = "Poisson"
  • param::PoissonStimulusParameter
  • neurons::Vector{Int}: targeted neuron indices.
  • g::VFT: the target variable of post (shared, not copied); VFT and param follow the precision of post.
  • targets::Dict, records::Dict
  • inbox: log of the neurons of post written (see attach_driver!), or nothing.

The stimulus has no spike vector of its own (it is not a presynaptic population).

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
stim = SNN.PoissonStimulus(E, :ge; param = SNN.PoissonFixed(rate = 20Hz), neurons = :p_post, p_post = 0.5)
model = SNN.compose(; E, stim)
SNN.monitor!(E, :fire)
SNN.sim!(; model, duration = 100ms)
source
SNNModels.PoissonStimulusParameter — Type
PoissonStimulusParameter <: AbstractStimulusParameter

Supertype of the rate parameters of a PoissonStimulus: PoissonFixed, PoissonInterval and PoissonVariable. Each subtype defines get_poisson_rate(param, time) and has the fields μ (increment per input spike) and active (on/off switch).

source
SNNModels.PoissonVariable — Type
PoissonVariable(; variables::Dict{Symbol,Any}, rate::Function, μ = 1.0f0, active = [true])

Rate parameter of a PoissonStimulus whose rate is a function of time.

At every step the rate is rate(get_time(time), variables): rate must accept the current time (ms) and the variables dictionary and return a rate in library units (use Hz). variables can be changed at runtime with set_variable!(stim, key, value).

Fields

  • variables::Dict{Symbol,Any} (required): arguments passed to rate.
  • rate::Function (required): (t, variables) -> rate.
  • μ::Float32 = 1.0: increment of the target variable per input spike (units of the target variable, e.g. nS for a conductance).
  • active::Vector{Bool} = [true]: the stimulus is applied only if active[1].

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
osc(t, v) = v[:r0] * (1 + sin(2π * t / v[:period]))
param = SNN.PoissonVariable(variables = Dict{Symbol,Any}(:r0 => 10Hz, :period => 100ms), rate = osc)
stim = SNN.Stimulus(param, E, :ge)
source
SNNModels.Stimulus — Method
Stimulus(param::PoissonStimulusParameter, post::AbstractPopulation, sym::Symbol; kwargs...)
Stimulus(param::PoissonStimulusParameter, post::AbstractPopulation, sym::Symbol, comp; kwargs...)

Build a PoissonStimulus on post; equivalent to PoissonStimulus(post, sym; param, kwargs...) (with comp the compartment, as for the other stimulus types).

source
SNNModels._zt_poisson — Method
_zt_poisson(λ)

Draw k ~ Poisson(λ) conditioned on k >= 1: by inversion of the truncated cdf for λ < 1, by rejection of Poisson(λ) draws otherwise.

source
SNNModels.get_poisson_rate — Method
get_poisson_rate(param::PoissonStimulusParameter, time::Time)

Rate of a Poisson stimulus at the current time: param.rate(get_time(time), param.variables) for PoissonVariable, param.rate for PoissonFixed, and for PoissonInterval param.rate inside one of param.intervals (strict inequalities) and 0 outside.

source
SNNModels.stimulate! — Method
stimulate!(p::PoissonStimulus, param::PoissonStimulusParameter, time::Time, dt)

If param.active[1], add param.μ times a Poisson count of mean λ = get_poisson_rate(param, time) * dt to p.g[n] for every neuron n in p.neurons, drawn independently per neuron.

Sampling: a neuron receives at least one spike with probability 1 - exp(-λ), independently, so the next such neuron of p.neurons is found by a geometric gap floor(-log(1 - U) / λ), and its count is drawn from the zero-truncated Poisson distribution (_zt_poisson). Every count is exactly Poisson(λ) and independent; the cost per step is O(1 + λ n) for n targeted neurons. The rate is read at every step. Neurons written are logged in p.inbox (see attach_driver!). Uses the global RNG.

source

Poisson layer

N Poisson neurons connected through a sparse matrix built from conn; layer neuron $j$ fires with probability $\nu_j \Delta t$ and

\[g_i \leftarrow g_i + W_{ij} \quad \text{for every target } i \text{ of } j .\]

ParameterFieldDefaultUnitsMeaning
PoissonLayerraterequiredrate (Hz)rate of every layer neuron
N1number of layer neurons
active[true]false silences the layer
PoissonLayerHetratesrequiredrate (Hz)rate of each layer neuron (length N)
N1number of layer neurons
active[true]false silences the layer
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
layer = SNN.Stimulus(SNN.PoissonLayer(rate = 10Hz, N = 1000), E, :ge; conn = (p = 0.05, μ = 1.0))
het = SNN.Stimulus(SNN.PoissonLayerHet(N = 50, rates = collect(range(1Hz, 50Hz, length = 50))), E, :gi;
                   conn = (p = 0.2, μ = 0.5))
SNN.monitor!(layer, :fire)
model = SNN.compose(; E, layer, het)
SNN.sim!(; model, duration = 200ms)
length(SNN.spiketimes(layer))   # 1000 input neurons
SNNModels.PoissonLayer — Type
PoissonLayer(; rate, N = 1, active = [true])
PoissonLayer(rate::Real; N)

Parameter of a PoissonStimulusLayer in which the N neurons of the input layer fire as independent Poisson processes with the same rate rate.

The connectivity between the layer and the target population is not part of the parameter: it is given by the conn keyword of Stimulus (see PoissonStimulusLayer). A target neuron with $K$ afferent layer neurons of weight $w$ receives in total $K$ independent trains of rate rate, i.e. a total input rate of $K$ times rate with increments $w$.

Fields

  • rate::Float32 (required): firing rate of each layer neuron (use Hz).
  • N::Int32 = 1: number of neurons in the layer.
  • active::Vector{Bool} = [true]: when false (set_active!), the layer does not fire.

The positional form is PoissonLayer(rate; N = 1). (Up to SNNModels 1.8.4 active was not read and the positional form required N.)

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
stim = SNN.Stimulus(SNN.PoissonLayer(rate = 10Hz, N = 200), E, :ge; conn = (p = 0.1, μ = 1.0))
source
SNNModels.PoissonLayerHet — Type
PoissonLayerHet(; N = 1, rates, active = [true])
PoissonLayerHet(rate::Real; N)

Parameter of a PoissonStimulusLayer in which layer neuron j fires as a Poisson process with its own rate rates[j].

Fields

  • N::Int32 = 1: number of neurons in the layer.
  • rates::Vector{Float32} (required): rate of each layer neuron (length N, use Hz). It is a vector, so it can be changed at runtime with set_variable!(stim, :rates, r).
  • active::Vector{Bool} = [true]: when false, the layer does not fire.

PoissonLayerHet(rate; N) builds rates = fill(rate, N).

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
param = SNN.PoissonLayerHet(N = 50, rates = collect(range(1Hz, 20Hz, length = 50)))
stim = SNN.Stimulus(param, E, :ge; conn = (p = 0.2, μ = 0.5))
source
SNNModels.PoissonStimulusLayer — Type
Stimulus(param::PoissonLayerParameter, post::AbstractPopulation, sym::Symbol, comp = nothing;
         conn::NamedTuple, name = "Poisson")
PoissonStimulusLayer(post, sym, comp = nothing; conn, param::PoissonLayerParameter, name = "Poisson")

A layer of param.N Poisson neurons connected to post through a sparse weight matrix.

The weight matrix $W$ (post.N x param.N) is generated with sparse_matrix(param.N, post.N, conn); conn is a connectivity NamedTuple such as (p = 0.1, μ = 1.0) (see sparse_matrix for the rules :Fixed, :Bernoulli, ... and the weight distribution). The PoissonStimulusLayer(post, sym, comp; conn, ...) form also accepts a matrix as conn.

Equations

At each step every layer neuron $j$ fires with probability $\nu_j\,\Delta t$ (Bernoulli approximation of a Poisson process, at most one spike per step), with $\nu_j$ = param.rate (PoissonLayer) or param.rates[j] (PoissonLayerHet). For each spike, all its targets $i$ are incremented:

\[g_i \leftarrow g_i + W_{ij}\]

The spikes are sampled sparsely, at one random draw per spike (see stimulate!).

Fields

  • N::Int: number of layer neurons; id, name = "Poisson"
  • param::PoissonLayerParameter
  • g::VFT: target variable of post (shared); VFT, W and param follow the precision of post.
  • colptr, rowptr, I, J, index, W: sparse connectivity, as returned by dsparse (I are postsynaptic indices, W the weights).
  • fire::Vector{Bool}: spikes of the layer neurons in the last step (can be recorded with monitor!(stim, :fire)).
  • spikes::SpikeIndex: ascending list of the layer neurons that fired in the last step (spike_index(stim)).
  • inbox: log of the neurons of post written (see attach_driver!), or nothing.
  • records::Dict, targets::Dict

param is required (the keyword struct constructor has no default for it).

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
stim = SNN.Stimulus(SNN.PoissonLayer(rate = 10Hz, N = 1000), E, :ge; conn = (p = 0.05, μ = 1.0))
SNN.monitor!(stim, :fire)
model = SNN.compose(; E, stim)
SNN.sim!(; model, duration = 100ms)
source
SNNModels.stimulate! — Method
stimulate!(p::PoissonStimulusLayer, param::Union{PoissonLayer,PoissonLayerHet}, time::Time, dt)

One step of a Poisson layer: layer neuron j fires with probability rate * dt (rates[j] * dt for PoissonLayerHet), independently, at most once per step; for each firing neuron the weights of its outgoing connections are added to p.g. p.fire and p.spikes hold the layer spikes of this step. The layer does not fire while param.active[1] is false. Targets written are logged in p.inbox (see attach_driver!).

Sampling (global RNG), with one random draw per spike:

  • PoissonLayer: the gap to the next spike of the Bernoulli(p) sequence is geometric, floor(log(1 - U) / log(1 - p)).
  • PoissonLayerHet: candidates drawn as above at the largest probability pmax (recomputed every step), each kept with probability rates[j] * dt / pmax; the cost grows with the largest rate.
  • From a probability of 0.2 on, every neuron is tested with one uniform draw.
source

Spike-time stimulus

Replays a sorted spike list (neurons[k] fires at spiketimes[k]) through a sparse matrix built from conn; SpikeTimeParameter sorts the list, SpikeTimeStimulusIdentity connects input j to neuron j.

Field of SpikeTimeStimulusParameterDefaultUnitsMeaning
spiketimes[]msspike times, sorted
neurons[]input neuron of each spike
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
param = SNN.SpikeTimeParameter([30ms, 10ms, 20ms], [1, 2, 1])   # sorted by time
stim = SNN.SpikeTimeStimulus(E, :ge; param, conn = (p = 0.5, μ = 2.0))
one_to_one = SNN.SpikeTimeStimulusIdentity(E, :gi; param = SNN.SpikeTimeParameter([5ms], [3]))
SNN.monitor!(stim, :fire)
model = SNN.compose(; E, stim, one_to_one)
SNN.sim!(; model, duration = 50ms)
SNN.update_spikes!(stim, SNN.SpikeTimeParameter([5ms, 15ms], [2, 2]), SNN.get_time(model.time))
SNN.sim!(; model, duration = 50ms)
SNNModels.SpikeTimeStimulus — Type
SpikeTimeStimulus(post::AbstractPopulation, sym::Symbol, comp = nothing;
                  conn, param::SpikeTimeStimulusParameter, N = nothing, name = "SpikeTime")
Stimulus(param::SpikeTimeStimulusParameter, post, sym, comp = nothing; conn, kwargs...)

Deliver a predefined list of spikes from N virtual input neurons to post through a sparse weight matrix.

conn is a connectivity NamedTuple (e.g. (p = 0.1, μ = 1.0), see sparse_matrix) or a weight matrix of size post.N x N. N defaults to max_neuron(param), the largest input neuron index in param. For one-to-one input use SpikeTimeStimulusIdentity.

Equations

At each step, every spike $k$ with $t_k \le t$ that has not been delivered yet (spikes are consumed in order) makes its input neuron $j =$ neurons[k] fire and increments its targets $i$:

\[g_i \leftarrow g_i + W_{ij}\]

Since the clock is advanced before stimuli are called, a spike at $t_k$ is delivered in the first step whose end time is $\ge t_k$; the timing resolution is dt.

Fields

  • N::Int: number of input neurons; name = "SpikeTime"; id
  • param::SpikeTimeStimulusParameter
  • rowptr, colptr, I, J, index, W: sparse connectivity from dsparse.
  • g::VFT: target variable of post (shared); VFT follows the precision of post, as do W and param.
  • next_spike::VFT: time of the next spike (Inf when exhausted).
  • next_index::Vector{Int}: index of the next spike in param (-1 when exhausted).
  • fire::Vector{Bool}: input neurons that fired in the last step (recordable with monitor!(stim, :fire)).
  • records::Dict, targets::Dict
  • spiking: the input neurons flagged in fire, cleared at the next step.
  • inbox: log of the neurons of post written (see attach_driver!), or nothing.

To reuse the stimulus with new spikes call update_spikes! or shift_spikes!, which also rewind next_index/next_spike.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
param = SNN.SpikeTimeParameter([10ms, 20ms, 30ms], [1, 2, 1])
stim = SNN.SpikeTimeStimulus(E, :ge; param, conn = (p = 0.5, μ = 2.0))
model = SNN.compose(; E, stim)
SNN.sim!(; model, duration = 50ms)
source
SNNModels.SpikeTimeStimulusParameter — Type
SpikeTimeStimulusParameter(; spiketimes = [], neurons = [])
SpikeTimeStimulusParameter(spiketimes::Vector{Float32}, neurons::Vector{Int})

List of input spikes for a SpikeTimeStimulus: spike k is emitted by input neuron neurons[k] at time spiketimes[k] (ms).

SpikeTimeStimulus walks through the list in order, so spiketimes must be sorted in increasing order. The direct constructors do not sort; prefer SpikeTimeParameter, which sorts the spikes by time and converts the times to Float32.

Fields

  • spiketimes::VFT = []: spike times (ms), sorted (VFT = Vector{Float32} by default).
  • neurons::Vector{Int} = []: index of the input neuron of each spike (same length).

Related functions

  • SpikeTimeParameter(spiketimes, neurons), SpikeTimeParameter(; spiketimes, neurons), SpikeTimeParameter(st::Spiketimes): build a sorted parameter.
  • shift_spikes!(param, delay): add delay to all spike times.
  • max_neuron(param): largest input neuron index (0 if empty).
source
SNNModels.SpikeTimeParameter — Method
SpikeTimeParameter(spiketimes::Vector, neurons::Vector{Int})
SpikeTimeParameter(; neurons = Int[], spiketimes = Float32[])
SpikeTimeParameter(st::Spiketimes)
SpikeTimeParameter(st::Vector{Vector{Float64}})

Build a SpikeTimeStimulusParameter.

  • SpikeTimeParameter(spiketimes, neurons): asserts equal lengths, sorts the pairs by spike time and converts the times to Float32.
  • SpikeTimeParameter(st::Spiketimes) (and Vector{Vector{Float64}}): flattens one vector of spike times per input neuron (st[i] are the times of neuron i) and sorts by time.
  • The keyword form SpikeTimeParameter(; neurons, spiketimes) passes the vectors unchanged: it does NOT sort, and it keeps their element type (use it for exact Float64 times; the other forms round to Float32).

Example

using SpikingNeuralNetworks
SNN.@load_units
param = SNN.SpikeTimeParameter([30ms, 10ms, 20ms], [1, 2, 3])
param.spiketimes, param.neurons   # (Float32[10, 20, 30], [2, 3, 1])
source
SNNModels.SpikeTimeStimulusIdentity — Method
SpikeTimeStimulusIdentity(post::AbstractPopulation, sym::Symbol, comp = nothing;
                          param::SpikeTimeStimulusParameter, kwargs...)

SpikeTimeStimulus with one input neuron per neuron of post and one-to-one connections of weight 1: input neuron j excites only neuron j of post, adding 1 to its target variable per spike. N = post.N; the connectivity is a sparse identity matrix (no dense N x N matrix is built). Extra keywords (e.g. name) are forwarded.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
stim = SNN.SpikeTimeStimulusIdentity(E, :ge; param = SNN.SpikeTimeParameter([5ms, 10ms], [3, 7]))
source
SNNModels.Stimulus — Method
Stimulus(param::SpikeTimeStimulusParameter, post::AbstractPopulation, sym::Symbol, comp = nothing; kwargs...)

Build a SpikeTimeStimulus; equivalent to SpikeTimeStimulus(post, sym, comp; param, kwargs...) (the keyword conn is required).

source
SNNModels.max_neuron — Method
max_neuron(param::SpikeTimeStimulusParameter)

Largest input neuron index in param.neurons, or 0 if there are no spikes. Used as the default number of input neurons N of a SpikeTimeStimulus.

source
SNNModels.next_neuron — Method
next_neuron(p::SpikeTimeStimulus)

Return the input neuron of the next pending spike, param.neurons[next_index]; return [] once all spikes have been delivered (next_index == -1). (Up to SNNModels 1.8.4 it returned [] while the last spike was still pending and threw a BoundsError after the last spike.)

source
SNNModels.shift_spikes! — Method
shift_spikes!(stimulus::SpikeTimeStimulus, delay::Number)

Add delay (ms) to all spike times of stimulus.param and rewind the stimulus to the first spike (next_index = 1, next_spike = spiketimes[1]). Spikes shifted to times earlier than the current simulation time are all delivered at the next step. With an empty spike list the stimulus is marked as exhausted.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
stim = SNN.SpikeTimeStimulusIdentity(E, :ge; param = SNN.SpikeTimeParameter([5ms, 10ms], [3, 7]))
SNN.shift_spikes!(stim, 100ms)
stim.param.spiketimes  # Float32[105, 110]
source
SNNModels.shift_spikes! — Method
shift_spikes!(param::SpikeTimeStimulusParameter, delay::Number)

Add delay (ms) to all spike times of param, in place. The state of a stimulus that uses param is not rewound; use shift_spikes!(stimulus, delay) for that.

source
SNNModels.shift_spikes! — Method
shift_spikes!(spiketimes::Vector{Float32}, delay::Number)

Add Float32(delay) (ms, may be negative) to every element of spiketimes, in place.

source
SNNModels.stimulate! — Method
stimulate!(s::SpikeTimeStimulus, param::SpikeTimeStimulusParameter, time::Time, dt)

Clear the flags of s.fire set in the previous step, then deliver every pending spike with time <= get_time(time): mark its input neuron in s.fire, add the weights of its outgoing connections to s.g, and advance next_index/next_spike (set to -1/Inf after the last spike). dt is unused. Every neuron of post whose input is incremented is logged in s.inbox (see attach_driver!).

source
SNNModels.update_spikes! — Function
update_spikes!(stim, spikes, start_time = 0.0f0)

Replace the spike list of a SpikeTimeStimulus with spikes and rewind it.

spikes must have fields spiketimes and neurons (e.g. a SpikeTimeStimulusParameter). The new times are spikes.spiketimes .+ start_time, sorted by time (with their neurons). stim.next_index is set to 1 and stim.next_spike to the first new spike time (an empty list marks the stimulus as exhausted). (Up to SNNModels 1.8.4 the spikes were not sorted and an empty list raised a BoundsError.) The input-neuron count stim.N and the weight matrix are not changed, so the new neuron indices must be <= stim.N. Returns stim.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
stim = SNN.SpikeTimeStimulusIdentity(E, :ge; param = SNN.SpikeTimeParameter([5ms], [1]))
SNN.update_spikes!(stim, SNN.SpikeTimeParameter([1ms, 2ms], [4, 5]), 1000ms)
source

Current stimulus

Sets the external current (:I by default) of the targeted neurons:

\[I_i \leftarrow (1-\alpha_i)\,\big(I^{base}_i + \xi_i\big) + \alpha_i\, I_i, \qquad \xi_i \sim \texttt{I\_dist}\]

$\alpha = 0$ gives white noise per step; $0 < \alpha < 1$ a filtered process.

FieldDefault (CurrentNoise(N; ...))UnitsMeaning
I_base0, filled to length NpAbaseline current, indexed by neuron id
I_distNormal(0.0, 0.0)pAnoise distribution
α0.0, filled to length Nfilter coefficient in $[0, 1]$
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10, param = SNN.IFParameter(C = 281pF, gl = 40nS))
noise = SNN.CurrentNoise(E; I_base = 600pA, I_dist = SNN.SNNModels.Normal(0.0, 100.0), α = 0.9)
stim = SNN.CurrentStimulus(E; neurons = [1, 2, 3], param = noise)
model = SNN.compose(; E, stim)
SNN.monitor!(E, [:v, :fire, :I])
SNN.sim!(; model, duration = 200ms)
SNN.getvariable(E, :I)[4, end]   # 0: neuron 4 is not stimulated
SNNModels.CurrentNoise — Type
CurrentNoise(N::Union{Number,AbstractPopulation}; I_base = 0, I_dist = Normal(0.0, 0.0), α = 0.0)
CurrentNoise(; I_base = zeros(Float32, 0), I_dist = Normal(0.0, 0.0), α = ones(Float32, 0))

Parameter of a CurrentStimulus: a constant current plus noise, optionally low-pass filtered.

Equations

At every step, for each stimulated neuron $i$ (with one independent draw $\xi_i \sim$ I_dist per stimulated neuron):

\[I_i \leftarrow (1 - \alpha_i)\,(I^{base}_i + \xi_i) + \alpha_i\, I_i\]

With $\alpha_i = 0$ the current is redrawn independently every step (white noise around I_base); with $0 < \alpha_i < 1$ it is an AR(1) (exponentially filtered) process with correlation time $\Delta t / (1 - \alpha_i)$. The noise amplitude is not scaled with dt: the standard deviation of I_dist is the per-step standard deviation.

Fields

  • I_base::Vector{Float32}: baseline current per neuron (pA), indexed by neuron id, so its length must be the size of the target population.
  • I_dist::Distribution{Univariate,Continuous} = Normal(0.0, 0.0): noise distribution (pA).
  • α::Vector{Float32}: filter coefficient per neuron (dimensionless, in $[0, 1]$), indexed by neuron id.

The convenience constructor CurrentNoise(N; I_base, I_dist, α) takes the population (or its size) and fills I_base and α with the given scalars (default α = 0.0). The keyword struct defaults are empty vectors, to be filled by the user.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
param = SNN.CurrentNoise(E; I_base = 100pA, I_dist = SNN.SNNModels.Normal(0.0, 20.0), α = 0.9)
stim = SNN.Stimulus(param, E)
source
SNNModels.CurrentStimulus — Type
CurrentStimulus(post::AbstractPopulation, sym::Symbol = :I; neurons = :ALL, param::CurrentParameter, kwargs...)
Stimulus(param::CurrentParameter, post::AbstractPopulation, sym::Symbol = :I; kwargs...)

A stimulus that writes an external current into the field sym (default :I) of the population post, for the neurons in neurons. The update rule is defined by the parameter type (see CurrentNoise).

The stimulus writes (does not add to) the target vector, so two current stimuli on the same field and neurons overwrite each other. Neurons that are not in neurons are never modified. The current keeps its last value after the stimulus stops being called.

Since SNNModels 1.8.4 a subset of neurons is handled correctly: the per-step random numbers are indexed by position in neurons, while I, I_base and α are indexed by neuron id.

Constructor arguments

  • post: target population; sym = :I: field of post that receives the current.
  • neurons = :ALL: 1:post.N, or a vector of neuron indices.
  • param (required): a CurrentParameter.
  • remaining keywords (name = "Current", id) are forwarded to the struct.

Fields

  • param::CurrentParameter; name::String = "Current"; id::String
  • neurons::Vector{Int}: stimulated neurons.
  • randcache::Vector{Float32}: one random number per stimulated neuron.
  • I::Vector{Float32}: the target field of post (shared, not copied).
  • records::Dict, targets::Dict

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10, param = SNN.IFParameter(C = 281pF, gl = 40nS))
stim = SNN.CurrentStimulus(E; neurons = [1, 2, 3], param = SNN.CurrentNoise(E; I_base = 500pA))
model = SNN.compose(; E, stim)
SNN.monitor!(E, [:v, :fire])
SNN.sim!(; model, duration = 100ms)
source
SNNModels.Stimulus — Method
Stimulus(param::CurrentParameter, post::AbstractPopulation, sym::Symbol = :I; kwargs...)

Build a CurrentStimulus; equivalent to CurrentStimulus(post, sym; param, kwargs...).

source
SNNModels.stimulate! — Method
stimulate!(p::CurrentStimulus, param::CurrentNoise, time::Time, dt::Float32)

Draw one noise sample per stimulated neuron from param.I_dist and set, for each i = p.neurons[k], p.I[i] = (I_base[i] + ξ[k]) * (1 - α[i]) + p.I[i] * α[i].

source

Balanced stimulus

Poisson inhibition at rate $k_{IE} r_0$ and Poisson excitation fluctuating around $r_0$ (see BalancedParameter).

FieldDefaultUnitsMeaning
kIE1.0inhibitory rate / r0
β0.0amplitude of the rate fluctuations
τ50msmscorrelation time of the fluctuations
r01kHzratebaseline rate
w1.0units of the targetincrement per input spike
wIE1.0extra factor on the inhibitory increment
same_inputfalseone rate process shared by all neurons
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 100)
stim = SNN.Stimulus(SNN.BalancedParameter(r0 = 2kHz, kIE = 0.5), E, :ge)
model = SNN.compose(; E, stim)
SNN.monitor!(E, [:fire])
SNN.sim!(; model, duration = 200ms)
SNNModels.BalancedParameter — Type
BalancedParameter(; kIE = 1.0, β = 0.0, τ = 50ms, r0 = 1kHz, w = 1.0, wIE = 1.0, same_input = false)

Parameter of a BalancedStimulus: Poisson excitatory input with a slowly fluctuating rate and Poisson inhibitory input with a fixed rate, delivered to every neuron of the target population.

Equations

Per step ($\Delta t$ = dt), for each neuron $n$:

\[g^{I}_n \leftarrow g^{I}_n + w\, w_{IE}\, k^{I}_n, \qquad k^{I}_n \sim \mathrm{Poisson}(k_{IE}\, r_0\, \Delta t)\]

The excitatory rate $r^{E}$ is driven by a noise variable $\eta$ and an adaptive offset $r$ ($u$ uniform on $[-1/2, 1/2]$, $[x]_+ = \max(x, 0)$, and $R(x)$ = $x$ if $x > 0$ else 1):

\[\eta \leftarrow (\eta - u)(1 - \Delta t/\tau) + u, \qquad r^{E} = \Big[\tfrac{r_0}{2}\, R(\beta\,\eta) + r\Big]_+, \qquad r \leftarrow r + \frac{r_0 - r^{E}}{400\,\mathrm{ms}}\,\Delta t\]

and the excitatory target of neuron $n$ receives $w\,k^{E}_n$ with $k^{E}_n \sim \mathrm{Poisson}(r^{E}_n\,\Delta t)$ (one draw per neuron and step). With same_input = true a single rate process ($\eta$, $r$, $r^E$ shared by all neurons) is used and every neuron draws its own Poisson count at that rate. Note the rule $R(x)$ (1 for $x \le 0$), transcribed from the code.

Fields

  • kIE::Float32 = 1.0: ratio of the inhibitory rate to r0.
  • β::Float32 = 0.0: amplitude of the rate fluctuations (dimensionless).
  • τ::Float32 = 50ms: correlation time of the rate noise.
  • r0::Float32 = 1kHz: baseline rate (library units: 1kHz = 1 per ms).
  • w::Float32 = 1.0: increment per input spike (excitatory and inhibitory).
  • wIE::Float32 = 1.0: extra factor on the inhibitory increment.
  • same_input::Bool = false: use a single excitatory rate process shared by all neurons instead of one per neuron.

Reference not given in the code.

source
SNNModels.BalancedStimulus — Type
BalancedStimulus(post::AbstractPopulation, sym_e::Symbol, sym_i::Symbol, target = nothing;
                 param::BalancedParameter, name = "Balanced")
Stimulus(param::BalancedParameter, post, sym, target = nothing; kwargs...)

Balanced excitatory and inhibitory Poisson drive to all post.N neurons of post, with rates defined by BalancedParameter. sym_e and sym_i select the excitatory and inhibitory target variables (target is the compartment for multicompartment models).

param may also be a number, the baseline rate r0 (library units, e.g. 2kHz), used with the other defaults of BalancedParameter.

Changed after SNNModels 1.8.4

Up to 1.8.4: the default same_input = false threw UndefVarError: randcache; same_input = true added all excitatory draws to neuron 1; the per-neuron branch added N Poisson draws per step to each neuron (rate multiplied by N); Stimulus(param, post, sym) used sym as both the excitatory and the inhibitory target; a numeric param referred to the undefined BSParam.

Fields

  • id::String; param::BalancedParameter; name::String = "Balanced"
  • N::Int32: number of target neurons (post.N).
  • ge::Vector{Float32}, gi::Vector{Float32}: excitatory and inhibitory targets of post (shared).
  • fire::Vector{Bool} = zeros(Bool, 0): unused.
  • r::Vector{Float32}: adaptive rate offset per neuron (initialised to r0).
  • noise::Vector{Float32}: rate noise per neuron (initialised to 0).
  • randcache_β::Vector{Float32}: uniform random numbers for the noise.
  • records::Dict, targets::Dict
source
SNNModels.Stimulus — Method
Stimulus(param::BalancedParameter, post::AbstractPopulation, sym_e::Symbol, sym_i::Symbol, target = nothing; kwargs...)
Stimulus(param::BalancedParameter, post::AbstractPopulation, sym::Symbol, target = nothing; kwargs...)

Build a BalancedStimulus. In the second form sym is the excitatory target and the inhibitory one is its counterpart (:ge -> :gi, :glu -> :gaba, :he -> :hi, :AMPA -> :GABAa); other symbols raise an ArgumentError.

source

Stimulus groups

A StimulusGroup bundles stimuli; MultiCompartmentStimulusGroup makes one per compartment.

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Tripod(N = 10)
param = SNN.PoissonInterval(rate = 100Hz, intervals = [[0ms, 50ms]])
group = SNN.MultiCompartmentStimulusGroup(param, E, :glu, [:d1, :d2])
model = SNN.compose(; E, group)
SNN.sim!(; model, duration = 100ms)
SNN.set_intervals!(group, [[100ms, 150ms]])
SNN.sim!(; model, duration = 100ms)
SNNModels.StimulusGroup — Type
StimulusGroup(; id = randstring(12), name = "StimulusGroup", param::AbstractStimulusParameter,
              elements::Vector{AbstractStimulus}, targets = Dict(), records = Dict())

A container of stimuli handled as one model component. It is a subtype of AbstractStimulusGroup, not of AbstractStimulus: when a model is simulated, sim! and train! unpack the group and run each element as an ordinary stimulus. The helper methods set_variable!, set_intervals!, set_active!, record and stimulate! broadcast to all elements.

param is any AbstractStimulusParameter (up to SNNModels 1.8.4 it was restricted to PoissonStimulusParameter). The usual way to build a group is MultiCompartmentStimulusGroup.

Fields

  • id::String, name::String = "StimulusGroup"
  • param::AbstractStimulusParameter: parameter shared by the elements.
  • elements::Vector{AbstractStimulus}: the grouped stimuli.
  • targets::Dict, records::Dict
source
SNNModels.MultiCompartmentStimulusGroup — Method
MultiCompartmentStimulusGroup(param::AbstractStimulusParameter, post::AbstractPopulation,
                              sym::Symbol, comps::AbstractVector; name = "StimulusGroup", kwargs...)

Build a StimulusGroup with one stimulus per compartment in comps, each created with Stimulus(param, post, sym, comp; name, kwargs...). All elements share the same parameter object, so changing it (for instance with set_variable!) affects all compartments. comps may contain nothing for a point neuron ([nothing] gives a group with one element). It works with every stimulus parameter whose Stimulus method takes the compartment (Poisson, Poisson layer, spike-time stimuli; pass conn for the last two). (Up to SNNModels 1.8.4 the compartment was passed as a keyword and only Poisson parameters worked.)

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Tripod(N = 10)
group = SNN.MultiCompartmentStimulusGroup(SNN.PoissonFixed(rate = 10Hz), E, :glu, [:d1, :d2])
model = SNN.compose(; E, group)
SNN.sim!(; model, duration = 10ms)
source
SNNModels.neurons — Method
neurons(stim::StimulusGroup)

Return the neuron indices targeted by the stimuli of the group, concatenated over the elements (elements without a neurons field contribute nothing). (Up to SNNModels 1.8.4 the result was a vector of index vectors.)

source
SNNModels.record — Method
record(stim::StimulusGroup, args...)

Applies the record function to all stimuli within a StimulusGroup. This is a convenience function to broadcast the operation to all elements of the group.

source
SNNModels.set_active! — Method
set_active!(stim::StimulusGroup, active::Bool)

Sets the active state for all stimuli within a StimulusGroup.

source
SNNModels.set_intervals! — Method
set_intervals!(stim::StimulusGroup, intervals)

Sets the activity intervals for all stimuli within a StimulusGroup. This is a convenience function to broadcast the operation to all elements of the group.

source
SNNModels.set_variable! — Method
set_variable!(stim::StimulusGroup, var::Symbol, value)

Sets the value of a variable for all stimuli within a StimulusGroup. This is a convenience function to broadcast the operation to all elements of the group.

source
SNNModels.stimulate! — Method
stimulate!(stim::StimulusGroup, param, time, dt)

Applies the stimulate! function to all stimuli within a StimulusGroup, delivering the stimulation for the current time step.

source

Common interface

SNNModels.AbstractStimulusParameter — Type
AbstractStimulusParameter <: AbstractParameter

Supertype of all stimulus parameter types. The parameter object stored in the param field of a stimulus selects, by dispatch, the stimulate! method that is called once per time step by sim! and train!, and the generic Stimulus constructor that builds the stimulus.

Loaded subtypes: PoissonStimulusParameter (PoissonFixed, PoissonInterval, PoissonVariable), PoissonLayerParameter (PoissonLayer, PoissonLayerHet), CurrentParameter (CurrentNoise), SpikeTimeStimulusParameter, BalancedParameter.

source
SNNModels.neurons — Method
neurons(stim::AbstractStimulus)

Return the indices of the postsynaptic neurons targeted by stim (its neurons field). Stimuli without a neurons field (PoissonStimulusLayer, SpikeTimeStimulus, BalancedStimulus) return nothing with a warning; for those the targets are defined by the connectivity matrix or by the whole population.

source
SNNModels.set_active! — Method
set_active!(stim::AbstractStimulus, active::Bool)

Switch a stimulus on or off by writing stim.param.active[1] = active. Warns and does nothing if the parameter has no active field.

The stimulate! methods of PoissonStimulus (all PoissonStimulusParameters) and of PoissonStimulusLayer (PoissonLayer, PoissonLayerHet) read the flag.

source
SNNModels.set_intervals! — Method
set_intervals!(stim::AbstractStimulus, intervals)

Replace the activity intervals of a stimulus whose parameter has an intervals field (PoissonInterval): the vector is emptied and intervals (a vector of [start, end] vectors, in ms) is appended. Warns and does nothing otherwise.

source
SNNModels.set_variable! — Method
set_variable!(stim::AbstractStimulus, var::Symbol, value)

Change a parameter of a stimulus at runtime.

  • If stim.param has a variables dictionary (e.g. PoissonVariable), sets stim.param.variables[var] = value.
  • Otherwise, if stim.param has a field var: an array field (e.g. active, I_base, rates) is updated in place (getfield(stim.param, var) .= value); a scalar field of a mutable parameter (PoissonFixed.rate, PoissonInterval.rate, PoissonLayer.rate) is replaced (setproperty!); a scalar field of an immutable parameter raises an ArgumentError. (Up to SNNModels 1.8.4 the scalar case threw a broadcast error; the Poisson parameter types were immutable.)
  • Otherwise a warning is emitted and nothing changes.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
f(t, v) = v[:r]
stim = SNN.Stimulus(SNN.PoissonVariable(variables = Dict{Symbol,Any}(:r => 5Hz), rate = f), E, :ge)
SNN.set_variable!(stim, :r, 20Hz)
source
SNNModels.stimulate! — Function
stimulate!(stim, param, time::Time, dt::Float32)

Advance the stimulus stim by one time step. Called by sim! and train! for every stimulus of the model, after the clock has been advanced (update_time!) and before the populations are integrated. The method is selected by the type of param (normally stim.param). Each stimulus type documents what its stimulate! method writes into the target population (conductance increments, current values).

source
SNNModels.EmptyStimulus — Type
EmptyStimulus(; param = EmptyParam(), records = Dict())

Placeholder stimulus that does nothing. sim! and train! use [EmptyStimulus()] as the default stimulus vector when none is given; its stimulate! method is a no-op.

source