COMMENT Total current is b + weighted events that decay with time constants taue and taui. Total current is integrated, and when this passes 1, then fire. That is taue * de/dt + e = 0 taui * di/dt + i = 0 where an event at time t1 causes e or i to be incremented by amount w, depending on sign of w, i.e. if (w > 0) then e += w else i += w and taum*dm/dt + m = ae*e + ai*i + b where fire if m crosses 1 in a positive direction and after firing m is reset to 0 Requires that taue <= taui, but taum can be larger or smaller than either or both of the synaptic time constants. ENDCOMMENT NEURON { ARTIFICIAL_CELL IF3 RANGE taue, taui, taum, e, i, m, b RANGE nself, nexcite, ninhibit GLOBAL eps, refrac } PARAMETER { : specify limits on these taue = 3 (ms) < 1e-9, 1e9 > taui = 10 (ms) < 1e-9, 1e9 > taum = 30 (ms) < 1e-9, 1e9 > b = 0 eps = 1e-6 refrac = 5 (ms) } ASSIGNED { e i m enew inew mnew t0 (ms) nself nexcite ninhibit ae ai be bi on } : argument is the interval since last update PROCEDURE newstates(d(ms)) { LOCAL ee, ei, em ee = exp(-d/taue) ei = exp(-d/taui) em = exp(-d/taum) enew = e*ee inew = i*ei mnew = b + (m - b)*em + ae*e*(taue/(taum - taue))*(em - ee) + ai*i*(taui/(taum - taui))*(em - ei) } FUNCTION M() { if (on) { newstates(t - t0) M = mnew }else{ M = 0 } } FUNCTION E() { newstates(t - t0) E = enew } FUNCTION I() { newstates(t - t0) I = inew } PROCEDURE update() { e = enew i = inew m = mnew t0 = t } PROCEDURE factors() { LOCAL tp : force all exponential solution ( no x*exp(-x) ) : and force assertion for correctness of algorithm : i.e. taue is smallest and only one that is excitatory if (taue >= taui) { taui = taue + 0.01 } if (taum == taue) { taum = taue + 0.01 } if (taum == taui) { taum = taui + 0.01 } : normalize so the peak magnitude of m is 1 when single e of 1 tp = log(taue/taum)/((1/taum) - (1/taue)) be = 1/(exp(-tp/taum) - exp(-tp/taue)) ae = be*((taum/taue) - 1) : normalize so the peak magnitude of m is -1 when single i of -1 tp = log(taui/taum)/((1/taum) - (1/taui)) bi = 1/(exp(-tp/taum) - exp(-tp/taui)) ai = bi*((taum/taui) - 1) } FUNCTION tf(bb) (ms) { if (bb > 1) { tf = taum*log((bb-m)/(bb-1)) } else { tf = 1e9 } } FUNCTION firetimebound() (ms) { LOCAL h, temp h = ae*e + ai*i if (b>1) { if (h>0) { firetimebound = tf(h+b) } else { : take net inhibitory current into account, at least partially temp = tf(b) : too early temp = tf(b + h*exp(-temp/taui)) : too late : later than too early, but not too late firetimebound = tf(b + h*exp(-temp/taui)) } } else { : this compound conditional can be simplified : if ((h+b-m > 0) && (h+b > 1)) { : h+b-m > 0 implies h+b > m, but h+b > 1 guarantees h+b > m since 1 >= m if (h+b > 1) { firetimebound = tf(h+b) } else { firetimebound = 1e9 } } : printf("firetimebound=%g\n", firetimebound) } LOCAL total, nexttotal INITIAL { factors() e = 0 i = 0 m = 0 t0 = t on = 1 net_send(firetimebound(), 1) nself=0 nexcite=0 ninhibit=0 total = 0 nexttotal = 1000 } NET_RECEIVE (w) { newstates(t-t0) update() :printf("event %g t=%g e=%g i=%g m=%g\n", flag, t, e, i, m) if (flag == 1) { :determine whether to fire or try again nself = nself + 1 if (m > 1-eps) { : time to fire if (m > 1+eps) { : oops! printf("m>1 error in IF3 mechanism--m = %g\n", m) : how to quit? } :printf("fire %g\n", t) net_event(t) on = 0 m = 0 net_send(refrac, 2) : start refractory state total = total + 1 if (total == nexttotal) { : printf("IF3 total spikes %g at %g\n", total, t) nexttotal = nexttotal + 1000 } }else{ : try again net_send(firetimebound(), 1) } }else if (flag == 2) { : end of refractory period on = 1 m = 0 net_send(firetimebound(), 1) } else { if (w > 0) { nexcite = nexcite + 1 e = e + w } else { ninhibit = ninhibit + 1 i = i + w } :printf("w=%g e=%g i=%g\n", w, e, i) if (on) { net_move(firetimebound() + t) } } }