Stimuli
External inputs, built with Stimulus(param, post, sym, [comp]; kwargs...); the type of param selects the model. Usage: Stimuli.
| Stimulus | Parameter types | Writes | Presynaptic layer |
|---|---|---|---|
PoissonStimulus | PoissonFixed, PoissonInterval, PoissonVariable | adds μ per input spike to g | none (one independent train per target) |
PoissonStimulusLayer | PoissonLayer, PoissonLayerHet | adds W[i,j] per spike of layer neuron j | N Poisson neurons, sparse weights |
SpikeTimeStimulus | SpikeTimeStimulusParameter | adds W[i,j] per listed spike | N virtual neurons, sparse weights |
CurrentStimulus | CurrentNoise | sets the current I | none |
BalancedStimulus | BalancedParameter | adds Poisson E and I input | none |
StimulusGroup | (shared Poisson parameter) | its elements | |
EmptyStimulus | EmptyParam | nothing (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)\]
| Parameter | Rate $\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) |
| Field | Default | Units | Meaning |
|---|---|---|---|
rate | 0 (PoissonFixed), required otherwise | rate (Hz) | rate per target neuron |
intervals | [] | ms | PoissonInterval only: list of [start, end] |
variables | required | PoissonVariable only: arguments of the rate function | |
μ | 1.0 | units of the target variable | increment 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, useHz; e.g.rate = 10Hz).μ::Float32 = 1.0: increment of the target variable per input spike.active::Vector{Bool} = [true]: the stimulus is applied only ifactive[1].
Example
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 10)
stim = SNN.Stimulus(SNN.PoissonFixed(rate = 100Hz, μ = 0.5), E, :ge)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 (useHz).intervals::Vector{Vector{Float32}} = []: list of[start, end]intervals in ms; can be replaced at runtime withset_intervals!.μ::Float32 = 1.0: increment of the target variable per input spike.active::Vector{Bool} = [true]: the stimulus is applied only ifactive[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)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 bysynaptic_targetof the population type (e.g.:ge/:gluand:gi/:gabafor generalized IF neurons).param(required):PoissonFixed,PoissonIntervalorPoissonVariable.neurons = :ALL: all neurons ofpost; aVector{Int}of indices; or:p_postto sampleround(Int, p_post * post.N)neurons without replacement (ifp_postis 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 withneurons = :p_post.- remaining keywords (e.g.
name = "Poisson",id) are forwarded to the struct.
Fields
id::String,name::String = "Poisson"param::PoissonStimulusParameterneurons::Vector{Int}: targeted neuron indices.g::VFT: the target variable ofpost(shared, not copied);VFTandparamfollow the precision ofpost.targets::Dict,records::Dictinbox: log of the neurons ofpostwritten (seeattach_driver!), ornothing.
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)SNNModels.PoissonStimulusParameter — Type
PoissonStimulusParameter <: AbstractStimulusParameterSupertype 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).
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 torate.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 ifactive[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)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).
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.
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.
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.
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 .\]
| Parameter | Field | Default | Units | Meaning |
|---|---|---|---|---|
PoissonLayer | rate | required | rate (Hz) | rate of every layer neuron |
N | 1 | number of layer neurons | ||
active | [true] | false silences the layer | ||
PoissonLayerHet | rates | required | rate (Hz) | rate of each layer neuron (length N) |
N | 1 | number 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 neuronsSNNModels.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 (useHz).N::Int32 = 1: number of neurons in the layer.active::Vector{Bool} = [true]: whenfalse(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))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 (lengthN, useHz). It is a vector, so it can be changed at runtime withset_variable!(stim, :rates, r).active::Vector{Bool} = [true]: whenfalse, 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))SNNModels.PoissonLayerParameter — Type
PoissonLayerParameter <: AbstractStimulusParameterSupertype of the parameters of a PoissonStimulusLayer: PoissonLayer (one rate for all layer neurons) and PoissonLayerHet (one rate per layer neuron).
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::PoissonLayerParameterg::VFT: target variable ofpost(shared);VFT,Wandparamfollow the precision ofpost.colptr,rowptr,I,J,index,W: sparse connectivity, as returned bydsparse(Iare postsynaptic indices,Wthe weights).fire::Vector{Bool}: spikes of the layer neurons in the last step (can be recorded withmonitor!(stim, :fire)).spikes::SpikeIndex: ascending list of the layer neurons that fired in the last step (spike_index(stim)).inbox: log of the neurons ofpostwritten (seeattach_driver!), ornothing.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)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 probabilitypmax(recomputed every step), each kept with probabilityrates[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.
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 SpikeTimeStimulusParameter | Default | Units | Meaning |
|---|---|---|---|
spiketimes | [] | ms | spike 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";idparam::SpikeTimeStimulusParameterrowptr,colptr,I,J,index,W: sparse connectivity fromdsparse.g::VFT: target variable ofpost(shared);VFTfollows the precision ofpost, as doWandparam.next_spike::VFT: time of the next spike (Infwhen exhausted).next_index::Vector{Int}: index of the next spike inparam(-1when exhausted).fire::Vector{Bool}: input neurons that fired in the last step (recordable withmonitor!(stim, :fire)).records::Dict,targets::Dictspiking: the input neurons flagged infire, cleared at the next step.inbox: log of the neurons ofpostwritten (seeattach_driver!), ornothing.
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)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): adddelayto all spike times.max_neuron(param): largest input neuron index (0 if empty).
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 toFloat32.SpikeTimeParameter(st::Spiketimes)(andVector{Vector{Float64}}): flattens one vector of spike times per input neuron (st[i]are the times of neuroni) 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 exactFloat64times; the other forms round toFloat32).
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])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]))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).
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.
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.)
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]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.
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.
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!).
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)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.
| Field | Default (CurrentNoise(N; ...)) | Units | Meaning |
|---|---|---|---|
I_base | 0, filled to length N | pA | baseline current, indexed by neuron id |
I_dist | Normal(0.0, 0.0) | pA | noise distribution |
α | 0.0, filled to length N | filter 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 stimulatedSNNModels.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)SNNModels.CurrentParameter — Type
CurrentParameter <: AbstractStimulusParameterSupertype of the parameters of a CurrentStimulus. The only subtype is CurrentNoise.
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 ofpostthat receives the current.neurons = :ALL:1:post.N, or a vector of neuron indices.param(required): aCurrentParameter.- remaining keywords (
name = "Current",id) are forwarded to the struct.
Fields
param::CurrentParameter;name::String = "Current";id::Stringneurons::Vector{Int}: stimulated neurons.randcache::Vector{Float32}: one random number per stimulated neuron.I::Vector{Float32}: the target field ofpost(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)SNNModels.Stimulus — Method
Stimulus(param::CurrentParameter, post::AbstractPopulation, sym::Symbol = :I; kwargs...)Build a CurrentStimulus; equivalent to CurrentStimulus(post, sym; param, kwargs...).
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].
Balanced stimulus
Poisson inhibition at rate $k_{IE} r_0$ and Poisson excitation fluctuating around $r_0$ (see BalancedParameter).
| Field | Default | Units | Meaning |
|---|---|---|---|
kIE | 1.0 | inhibitory rate / r0 | |
β | 0.0 | amplitude of the rate fluctuations | |
τ | 50ms | ms | correlation time of the fluctuations |
r0 | 1kHz | rate | baseline rate |
w | 1.0 | units of the target | increment per input spike |
wIE | 1.0 | extra factor on the inhibitory increment | |
same_input | false | one 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 tor0.β::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.
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.
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 ofpost(shared).fire::Vector{Bool} = zeros(Bool, 0): unused.r::Vector{Float32}: adaptive rate offset per neuron (initialised tor0).noise::Vector{Float32}: rate noise per neuron (initialised to 0).randcache_β::Vector{Float32}: uniform random numbers for the noise.records::Dict,targets::Dict
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.
SNNModels.stimulate! — Method
stimulate!(p::BalancedStimulus, param::BalancedParameter, time::Time, dt::Float32)One step of the balanced input (equations in BalancedParameter).
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
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)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.)
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.
SNNModels.set_active! — Method
set_active!(stim::StimulusGroup, active::Bool)Sets the active state for all stimuli within a StimulusGroup.
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.
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.
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.
Common interface
SNNModels.AbstractStimulusParameter — Type
AbstractStimulusParameter <: AbstractParameterSupertype 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.
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.
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.
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.
SNNModels.set_variable! — Method
set_variable!(stim::AbstractStimulus, var::Symbol, value)Change a parameter of a stimulus at runtime.
- If
stim.paramhas avariablesdictionary (e.g.PoissonVariable), setsstim.param.variables[var] = value. - Otherwise, if
stim.paramhas a fieldvar: 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 anArgumentError. (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)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).
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.