JNeuron is able to quickly calculate extracellular potentials from a single neuron by solving the cable equation to find the spatially distributed current along a neuron, then finding the relationship between these currents and voltage at a point in extracellular space.
Realistic extracellular potentials are not generated by a single neuron, but tens of thousands of nearby neurons, all superimposed. Therefore, many neurons will need to be used to find realistic voltage signals. Datasets that model these phenomena usually do not contain thousands of different neurons; instead they have several template neurons, and modify the shapes to make each neuron unique. Then the potenials can be found that are generated from this population of randomly permutaed neurons. In this process, solving the cable equations is much more computationally expensive than finding the extracellular potentials.
If all of the neurons are modified such that they maintain the same branching architecture, the cable equation that governs the spatial distribution of current is the same; what varies is the coefficients relating the time varying currents at each node and the voltage at some point in extracellular space. JNeuron can take advantage of this design by solving the cable equation only once to get the current vs time profile at each node during an action potential, then using the extracellular cofficients of each neuron to generate the extracellular waveform shape of each neuron. Then a realistic voltage signal is created by generating tens of thousands of spike trains, and replacing each spike with the appropriate extracellular voltage.
In [ ]:
using JNeuron, DSP
In [ ]:
#Import Neuron and assign HH and Passive channels everywhere
myimport=input("./examples/data/cell2.asc");
blank_neuron=instantiate(myimport);
set_nsegs!(blank_neuron);
template_neuron=add(blank_neuron,(HH(),Passive()));
In [ ]:
#Find current at each node when this neuron fires an action potential
mynetwork=Network(template_neuron,15.0)
i_nodes=JNeuron.runc(mynetwork,true);
i_nodes=JNeuron.runc(mynetwork,false);
In [ ]:
#Create extracellular electrode
mye=Extracellular([500.0,125.0,0.0])
#Find the voltage waveforms of every neuron in a 10000 neuron population
neuron_num=10000
voltage_waveforms=JNeuron.nete(template_neuron,i_nodes,mye,neuron_num);
In [ ]:
#Find potential at extracellular electrode, and time stamps of nearby neurons
sim_time=1000.0 #ms
(voltage_extracellular, time_stamps)=JNeuron.extrap(voltage_waveforms,sim_time);
In [ ]:
#Find LFP and high frequency component
r=Highpass(100, fs=40000) #sampling frequency of simulation with .025ms time step is 40k
dm = Butterworth(4)
spikes=filt(digitalfilter(r,dm),voltage_extracellular)
r=Lowpass(300, fs=40000)
dm = Butterworth(4)
LFP=filt(digitalfilter(r,dm),voltage_extracellular)
In [ ]:
#Create extracellular electrodes at different depths
mye1=Extracellular([500.0,125.0,0.0])
mye2=Extracellular([500.0,125.0,100.0])
#Find the voltage waveforms of every neuron in a 10000 neuron population
neuron_num=10000
voltage_waveforms=JNeuron.nete(template_neuron,i_nodes,[mye1,mye2],neuron_num);
In [ ]:
#Find potential at extracellular electrode, and time stamps of nearby neurons
sim_time=1000.0 #ms
(voltage_extracellular, time_stamps)=JNeuron.extrap(voltage_waveforms,sim_time);
In [ ]:
#Find LFP and high frequency component
r=Highpass(100, fs=40000) #sampling frequency of simulation with .025ms time step is 40k
dm = Butterworth(4)
spikes_1=filt(digitalfilter(r,dm),voltage_extracellular[:,1])
spikes_2=filt(digitalfilter(r,dm),voltage_extracellular[:,2])
r=Lowpass(300, fs=40000)
dm = Butterworth(4)
LFP_1=filt(digitalfilter(r,dm),voltage_extracellular[:,1])
LFP_2=filt(digitalfilter(r,dm),voltage_extracellular[:,2])