Single cell injection of discrete square current pulse(s)

Hello, Marcel. I am working with a network of synaptically interconnected excitatory PYR neurons and inhibitory PVN neurons. A small tonic external current Iapp is being injected into all PYR cells to drive network activity. What I wish to do now is inject a brief strong pulse of current into one PYR cell of the network. I tried coding this by making Iapp variable time-dependent in one of the cells. This naïve effort gave syntax errors. Can you suggest a solution? Unfortunately, the guide on input stimuli (Input stimuli — Brian 2 2.7.1 documentation) did not seem to offer a clear answer to my problem.


Here is some of the code. I have removed some components (incl. synaptic currents) here to focus on the problem at hand.

N1 = 5000 *# number of PYR neurons in network*
eqs_pyr = """
Iapp : amp
k = (int(v<vt) * klow) + (int(v>=vt) * khigh) : siemens/volt
dv/dt = (k*(v-vr)*(v-vt)+Iapp)/C_pyr : volt
"""
reset = '''
v = c
'''
PYR = NeuronGroup(N1, model=eqs_pyr, reset=reset, threshold='v >= vpeak', method = 'euler')
#create one cell, PYR1, into which a current pulse can be applied**
PYR1 = PYR[:4999]
PYR2 = PYR[1:]

I would like to add Ipulse to the PYR eqs to give

eqs_pyr = """
Iapp : amp
Ipulse : amp
k = (int(v<vt) * klow) + (int(v>=vt) * khigh) : siemens/volt
dv/dt = (k*(v-vr)*(v-vt)+Iapp + Ipulse)/C_pyr : volt
"""

So how do I, e.g., step Ipulse up from 0 during, e.g., a 20 msec window in the middle of the run in PYR1 only? Alternatively, do built-in Brian2 functions offer a method for current-clamp pulse injection?

Hi @MitchG_HunterCollege. In general, I’d say there are three general approaches to inject a pulse current (in the below example: 20ms injection of 1nA after 100ms):

  1. A TimedArray:
Iapp = TimedArray([0, 0, 0, 0, 0, 1, 0]*nA, dt=20*ms)  # for times beyond the end of the array, the last value is used
eqs_pyr = """
Iapp : amp
k = (int(v<vt) * klow) + (int(v>=vt) * khigh) : siemens/volt
dv/dt = (k*(v-vr)*(v-vt)+Iapp + Ipulse(t))/C_pyr : volt
"""
  1. A time-dependent equation:
eqs_pyr = """
Iapp : amp
Ipulse = int(t>=100*ms and t < 120*ms)*1*nA : amp
k = (int(v<vt) * klow) + (int(v>=vt) * khigh) : siemens/volt
dv/dt = (k*(v-vr)*(v-vt)+Iapp + Ipulse)/C_pyr : volt
"""
  1. Multiple run calls
eqs_pyr = """
Iapp : amp
Ipulse : amp
k = (int(v<vt) * klow) + (int(v>=vt) * khigh) : siemens/volt
dv/dt = (k*(v-vr)*(v-vt)+Iapp + Ipulse)/C_pyr : volt
"""
# ...
run(100*ms)
PYR.Ipulse = 1*nA
run(20*ms)
PYR.Ipulse = 0*nA
run(remaining_time)

If you want to inject the current only in a subset of neurons, there are again a few options:

For variant 3 from above, you simply just set the current for the respective neuron, i.e. PYR1.Ipulse = 1*nA instead of PYR1.Ipulse (note that in your example code, both PYR1 and PYR2 have 4999 neurons – but I guess this was a typo).

For all variants, you can introduce a new variable that decides whether a neuron should receive input. E.g. for variant 2 this would look like this:

eqs_pyr = """
Iapp : amp
receives_pulse : boolean (constant)
Ipulse = int(receives_pulse) * int(t>=100*ms and t < 120*ms) * 1*nA: amp
k = (int(v<vt) * klow) + (int(v>=vt) * khigh) : siemens/volt
dv/dt = (k*(v-vr)*(v-vt)+Iapp + Ipulse)/C_pyr : volt
"""
# ...
PYR1.receives_pulse = True

For variant 1, you can have different inputs for different cells – this could be useful for complex inputs (different inputs to different neurons at different times), here it is a bit unnecessarily complex, since the input is zero for most cells:

inputs = np.zeros((7, 5000))*nA  # input for most neurons is zero
inputs[5][3675] = 1*nA  # neuron 3675 receives a current pulse
Iapp = TimedArray(inputs, dt=20*ms)  # for times beyond the end of the array, the last value is used
eqs_pyr = """
Iapp : amp
k = (int(v<vt) * klow) + (int(v>=vt) * khigh) : siemens/volt
dv/dt = (k*(v-vr)*(v-vt)+Iapp + Ipulse(t, i))/C_pyr : volt
"""

Hope that clears things up and gives you a few options for more complex inputs :blush:

1 Like