: sgate.mod
: draws from netstim.mod 2212 2008-09-08 14:32:26Z hines
: Passes a fraction of "input" events that arrive while it is on.
: The fraction fluctuates between 1 (100%) and 1-depth (0<=depth<=1)
: and is governed by
: p(t) = 1 + depth*(cos(2*PI*(t-start)/period) - 1)/2
: p(t) = 1 + depth*(cos(2*PI*(t-phase)/period) - 1)/2
: where
: depth = modulation depth (0..1, 1 == pass all, 0 == pass none, 0.5 = pass half)
: period = duration of a modulation cycle
: start = time at which modulation begins
: Gate is on for "number" modulation cycles
COMMENT
Supplied (written?) by Ted Carnevale
This mechanism can be combined with a NetStim that has noise=1
to implement a non-homogeneous Poisson process.
Quoting from http://en.wikipedia.org/wiki/Non-homogeneous_Poisson_process
retrieved on 5/1/2012:
"To simulate a non-homogeneous Poisson process with intensity function λ(t),
choose a sufficiently large λ so that λ(t) = λ p(t) and simulate a Poisson
process with rate parameter λ. Accept an event from the Poisson simulation at
time t with probability p(t)."
This statement cited Ross, Sheldon M. (2006). Simulation. Academic Press. p. 32.
Note: fifth edition is planned for 11/29/2012
ENDCOMMENT
NEURON {
ARTIFICIAL_CELL SGate : "Stochastic Gate"
RANGE period, number, start, phase
RANGE depth, gid, randi
THREADSAFE : only true if every instance has its own distinct Random
POINTER donotuse
}
UNITS {
PI = (pi) (1)
}
PARAMETER {
period = 100 (ms) <1e-9,1e9>: duration of a modulation cycle (msec)
number = 1 <0,1e9> : number of modulation cycles
start = 50 (ms) : start of first cycle
depth = 0 <0,1> : modulation depth
phase = 0 (ms): peak of first cycle
gid = 0
randi = 0
}
ASSIGNED {
on (1)
donotuse
numtogo (1) : how many modulation cycles remain to be launched
r (1)
}
INITIAL {
if (period < 0) { period = 1e9 }
if (number < 0) { number = 0 }
if (start < 0) { start = 0 }
if (phase < 0) { phase = 0 }
if (depth < 0) { depth = 0 }
if (depth > 1) { depth = 1 }
on = 0 : off--no events pass
if (number > 0) {
numtogo = number
net_send(start, 1) : to turn gate on
}
}
PROCEDURE seed(x) {
set_seed(x)
}
VERBATIM
#ifndef NRN_VERSION_GTEQ_8_2_0
double nrn_random_pick(void*);
void* nrn_random_arg(int argpos);
#define RANDCAST
#else
#define RANDCAST (Rand*)
#endif
ENDVERBATIM
FUNCTION erand() {
VERBATIM
if (_p_donotuse) {
/*
:Supports separate independent but reproducible streams for
: each instance. However, the corresponding hoc Random
: distribution MUST be set to Random.uniform(0,1)
*/
_lerand = nrn_random_pick(RANDCAST _p_donotuse);
}else{
/* only can be used in main thread */
if (_nt != nrn_threads) {
hoc_execerror("multithread random in NetStim"," only via hoc Random");
}
ENDVERBATIM
: the old standby. Cannot use if reproducible parallel sim
: independent of nhost or which host this instance is on
: is desired, since each instance on this cpu draws from
: the same stream
erand = scop_random()
VERBATIM
}
ENDVERBATIM
}
PROCEDURE noiseFromRandom() {
VERBATIM
{
void** pv = (void**)(&_p_donotuse);
if (ifarg(1)) {
*pv = nrn_random_arg(1);
}else{
*pv = (void*)0;
}
}
ENDVERBATIM
}
: p(t) = 1 + depth*(cos(2*PI*(t-phase)/period) - 1)/2
FUNCTION p(t (ms)) {
p = 0
if (on == 1) {
p = 1 + depth*(cos(2*PI*(t-phase)/period) - 1)/2
}
}
: flag action
: 0 if ON, decide whether to pass event
: 1 decide whether to start a modulation cycle
NET_RECEIVE (w) {
if (flag == 0) { : external event
if (on == 1) {
: decide whether to pass this event
r = erand()
if (r < p(t)) { net_event(t) }
}
} else if (flag == 1) {
if (numtogo>0) { : launch a new cycle
on = 1
numtogo = numtogo-1
net_send(period, 1) : to end this cycle
} else { : all done
on = 0
}
}
}