224 lines
4.9 KiB
Modula-2
224 lines
4.9 KiB
Modula-2
COMMENT
|
|
This mod file is based on netstim.mod in NEURON
|
|
modified by Yi Zhou to generate Gaussian interval distributions
|
|
ENDCOMMENT
|
|
|
|
NEURON {
|
|
POINT_PROCESS GaussStim
|
|
RANGE x
|
|
RANGE interval, number, start, factor, refrac
|
|
RANGE N_backward, N_forward, N_normal, N_total
|
|
RANGE rnd
|
|
RANGE rand
|
|
}
|
|
|
|
PARAMETER {
|
|
interval = 10 (ms) <1e-9,1e9> : ideal time between spikes (ms)
|
|
number = 10000 <0,1e9> : maximum number of spikes
|
|
start = 10 (ms) : delay before first spiketime
|
|
factor = 4 : fraction of mean to compute std (= mean / factor)
|
|
refrac = 0.5 <0,3> : absolute refractory period (upper limit of firing = 1 kHz)
|
|
: refrac >= dt, otherwise x can't be reset to 0
|
|
}
|
|
|
|
ASSIGNED {
|
|
x : if x > 0, cell is in refractory period
|
|
event (ms) : spiketime of next event in absolute time
|
|
on
|
|
end (ms)
|
|
m (ms) : mean of Gaussian
|
|
diff (ms)
|
|
N_forward : swap spike whose value exceed forwardly one interval
|
|
N_backward : swap spike whose value exceed backwardly one interval
|
|
N_normal
|
|
N_total
|
|
rnd
|
|
rand
|
|
}
|
|
|
|
PROCEDURE seed(x) {
|
|
set_seed(x)
|
|
}
|
|
|
|
INITIAL {
|
|
on = 0
|
|
x = 0
|
|
diff = 0
|
|
m = interval / 2 : each T has normal distribution N(interval/2, interval/2/factor)
|
|
N_forward = 0
|
|
N_backward = 0
|
|
N_normal = 0
|
|
N_total = 0
|
|
|
|
if (start >= 0 && number > 0) {
|
|
:: generate the first spiketime
|
|
event = start + invl(m)
|
|
|
|
:: make sure first spiketime is not before 0
|
|
if (event < 0) {
|
|
event = 0
|
|
}
|
|
|
|
:: skip directly to next event
|
|
net_send(event, 3)
|
|
}
|
|
}
|
|
|
|
PROCEDURE init_sequence(t(ms)) {
|
|
:: Turn on spike generation if n_spikes_max > 0
|
|
:: - "on" is set to 1
|
|
:: - "event" is set to "t" (input of this call)
|
|
:: - "end" is set to "interval * n_spikes_max"
|
|
|
|
if (number > 0) {
|
|
on = 1
|
|
event = t
|
|
end = t + 1e-6 + interval * (number-1)
|
|
}
|
|
}
|
|
|
|
PROCEDURE event_time() {
|
|
:: Generate the next spiketime
|
|
:: - call invl which calls normrand()
|
|
|
|
:: define local variables
|
|
LOCAL diff2, T
|
|
|
|
:: BAD diff gets overwritten in invl :facepalm:
|
|
diff2 = diff
|
|
|
|
:: if n_spikes_max is larger than 0
|
|
if (number > 0) {
|
|
:: generate a new interval until next spiketime
|
|
T = invl(m)
|
|
|
|
:: BAD useless
|
|
rnd = T
|
|
|
|
:: if new spiketime T is equal to an existing spiketime
|
|
if (T == 0 && diff2 == 0) {
|
|
T = T + dt
|
|
}
|
|
|
|
:: compute absolute time of next event (relative to 0 ms)
|
|
event = event + diff2 + T
|
|
|
|
:: augment total counter
|
|
N_total = N_total + 1
|
|
}
|
|
|
|
:: if next event is after the end, turn off spike generation
|
|
if (event > end) {
|
|
on = 0 :: BAD not the role of this function
|
|
}
|
|
}
|
|
|
|
FUNCTION invl(mean (ms)) (ms) {
|
|
:: Returns a new interval invl
|
|
:: Warning: also sets the global variable diff
|
|
|
|
:: define local variable
|
|
LOCAL std
|
|
|
|
:: compute standard deviation
|
|
if (mean <= 0.) {
|
|
mean = .01 (ms)
|
|
}
|
|
std = mean / factor
|
|
|
|
:: generate new interval invl
|
|
invl = normrand(mean, std)
|
|
|
|
:: make sure invl is within 0 and max interval
|
|
if (invl >= interval) {
|
|
:: decrease invl by n*interval
|
|
invl = fmod(invl, interval)
|
|
:: augment forward counter
|
|
N_forward = N_forward + 1
|
|
} else if (invl < 0) {
|
|
:: increase invl by n*interval
|
|
invl = fmod(invl, interval) + interval
|
|
:: augment backward counter
|
|
N_backward = N_backward + 1
|
|
} else {
|
|
:: augment normal counter
|
|
N_normal = N_normal + 1
|
|
}
|
|
|
|
:: overwrite global variable diff
|
|
diff = interval - invl
|
|
}
|
|
|
|
NET_RECEIVE(w) {
|
|
:: EXTERNAL CALL
|
|
if (flag == 0) {
|
|
if (w > 0 && on == 0) {
|
|
:: turn on spike generation
|
|
init_sequence(t)
|
|
net_send(0, 1)
|
|
} else if (w < 0 && on == 1) {
|
|
:: turn off spike generation
|
|
on = 0
|
|
}
|
|
}
|
|
|
|
:: MAIN CALL
|
|
if (flag == 1 && on == 1) {
|
|
if (x == 0) { :: time to spike (refractory period has passed)
|
|
:: set x to random uniform number (useless, just needs to > 0)
|
|
rand = scop_random() : [0, 1] uniform
|
|
x = rand
|
|
|
|
:: output event to synapse
|
|
net_event(t)
|
|
|
|
:: generate next spiketime
|
|
event_time()
|
|
|
|
:: if next spiketime is between refrac and refrac+dt
|
|
if (event-t >= refrac && event-t <= refrac+dt) {
|
|
:: move next spiketime up by one dt (just after refrac)
|
|
event = event + dt
|
|
}
|
|
|
|
:: if spike generation is turned on
|
|
if (on == 1) {
|
|
:: skip directly to next event
|
|
net_send(event - t, 1)
|
|
}
|
|
|
|
:: refractory period call
|
|
net_send(refrac, 2)
|
|
} else if (x != 0) { :: time to spike (within refractory period)
|
|
:: output event to synapse
|
|
net_event(t) :: BAD even still emitted even though refractory period, should be deleted
|
|
|
|
:: generate next spiketime
|
|
event_time() : although this spike will be ignored, still call next spike (independent cycles)
|
|
|
|
:: if spike generation is turned on
|
|
if (on == 1) {
|
|
:: skip directly to next event
|
|
net_send(event - t, 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
:: REFRACTORY PERIOD CALL (END OF REFRACTORY PERIOD)
|
|
if (flag == 2) {
|
|
x = 0
|
|
}
|
|
|
|
:: INITIAL CALL
|
|
if (flag == 3) {
|
|
:: if spike generation is not yet turned on
|
|
if (on == 0) {
|
|
:: turn on spike generation
|
|
init_sequence(t)
|
|
|
|
:: call net_receive directly
|
|
net_send(0, 1)
|
|
}
|
|
}
|
|
}
|