The Hodgkin-Huxley model is one of the earliest mathematical descriptions of neural spiking. It was originally developed on data from the squid giant axon. Today, Hodgkin-Huxley like dynamics are also used to simulate the spiking of a variety of neuron types. I’ve recently written a script to simulate Hodgkin-Huxley dynamics in Julia. Here I am sharing that code and I will go through the most important elements. As I just started to learn Julia I will also mention some of the things I learned about Julia in the process.

using Plots gr() # Hyperparameters tmin = 0.0 tmax = 1000.0 dt = 0.01 T = tmin:dt:tmax # Parameters gK = 35.0 gNa = 40.0 gL = 0.3 Cm = 1.0 EK = -77.0 ENa = 55.0 El = -65.0 # Potassium ion-channel rate functions alpha_n(Vm) = (0.02 * (Vm - 25.0)) / (1.0 - exp((-1.0 * (Vm - 25.0)) / 9.0)) beta_n(Vm) = (-0.002 * (Vm - 25.0)) / (1.0 - exp((Vm - 25.0) / 9.0)) # Sodium ion-channel rate functions alpha_m(Vm) = (0.182*(Vm + 35.0)) / (1.0 - exp((-1.0 * (Vm + 35.0)) / 9.0)) beta_m(Vm) = (-0.124 * (Vm + 35.0)) / (1.0 - exp((Vm + 35.0) / 9.0)) alpha_h(Vm) = 0.25 * exp((-1.0 * (Vm + 90.0)) / 12.0) beta_h(Vm) = (0.25 * exp((Vm + 62.0) / 6.0)) / exp((Vm + 90.0) / 12.0) # n, m & h steady-states n_inf(Vm=0.0) = alpha_n(Vm) / (alpha_n(Vm) + beta_n(Vm)) m_inf(Vm=0.0) = alpha_m(Vm) / (alpha_m(Vm) + beta_m(Vm)) h_inf(Vm=0.0) = alpha_h(Vm) / (alpha_h(Vm) + beta_h(Vm)) # Conductances GK(gK, n) = gK * (n ^ 4.0) GNa(gNa, m) = gNa * (m ^ 3.0) * h GL(gL) = gL # Differential equations function dv(Vm, GK, GNa, GL, Cm, EK, ENa, El, I, dt); ((I - (GK * (v - EK)) - (GNa * (v - ENa)) - (GL * (v - El))) / Cm) * dt end dn(n, Vm, dt) = ((alpha_n(Vm) * (1.0 - n)) - (beta_n(Vm) * n)) * dt dm(m, Vm, dt) = ((alpha_m(Vm) * (1.0 - m)) - (beta_m(Vm) * m)) * dt dh(h, Vm, dt) = ((alpha_h(Vm) * (1.0 - h)) - (beta_h(Vm) * h)) * dt I = T * 0.002 # Initial conditions and setup v = -65 m = m_inf(v) n = n_inf(v) h = h_inf(v) v_result = Array{Float64}(undef, length(T)) m_result = Array{Float64}(undef, length(T)) n_result = Array{Float64}(undef, length(T)) h_result = Array{Float64}(undef, length(T)) v_result[1] = v m_result[1] = m n_result[1] = n h_result[1] = h for t = 1:length(T)-1 GKt = GK(gK, n) GNat = GNa(gNa, m) GLt = GL(gL) dvt = dv(v, GKt, GNat, GLt, Cm, EK, ENa, El, I[t], dt) dmt = dm(m, v, dt) dnt = dn(n, v, dt) dht = dh(h, v, dt) global v = v + dvt global m = m + dmt global n = n + dnt global h = h + dht v_result[t+1] = v m_result[t+1] = m n_result[t+1] = n h_result[t+1] = h end p1 = plot(T, v_result, xlabel="time (ms)", ylabel="voltage (mV)", legend=false, dpi=300)

## The Parameters

There are seven parameters that define the Hodgkin-Huxley model. The maximum potassium, sodium and leak conductances `gK`

, `gNa`

and `gL`

. Then there are the equilibrium potentials for potassium, sodium and leak, `EK`

, E`Na`

and `El`

. Finally, there is `Cm`

, the membrane capacitance. In a nutshell, the models comes down to calculating the fraction of sodium and potassium channels that are open at a time point. Together with the maximum conductance, the membrane potential and the equilibrium potential, the fraction of open channels tells us how much current is flowing at the time. The amount of current filtered by the membrane capacitance in turn tells us by how much the voltage changes. The fraction of open channels is given by `n`

, `m`

and `h`

.

## Differential Equations

We need to track the change of the voltage (`v`

), potassium channel activation (`n`

), sodium channel activation (`m`

) and sodium channel inactivation (h). Let’s consider the potassium channels first. Active potassium channels can stay active or transition to the inactive state and inactive sodium channels. Since these potassium channels are voltage gated, the chance that they transition depends on the voltage. The function `alpha_n`

gives the transition rate from inactive to active and `beta_n`

gives the transition rate from active to inactive. For the sodium channels, the situation is almost identical. However, they can also be in a third state, that corresponds to depolarization induced inactivation.

Now that we are able to keep track of the states of our channels we can calculate the conductances. GK calculates the potassium conductance, GNa the sodium conductance and GL the leak conductance. Those conductances are then used in the `dv`

function to calculate the currents based on the voltage. And that’s basically it. The integration method is simple forward euler inside the for loop.

## Julia Notes From a Beginner

This is my very first Julia script so I have some thoughts. This is a completely non-optimized script and it is extremely fast, despite the for loop. From what I learned so far,` for`

loops in Julia are known to be fast and they can allegedly outperform vectorized solutions. This is very different from Python, where we strictly avoid `for`

loops, especially when concerned about performance.

For now I am confused by the scope and the use of the `global`

keyword. Scope seems to operate similar to Python, where functions and for loops have seamless access to variables in the outer scope. Assigning variables on the other hand seems to be a problem inside the for loop, unless the `global`

keyword is used.

Generally I am very happy with the Julia syntax. I think I could even code Python and Julia back to back. One major problem is of course indices starting at 1 but I get the difference in convention. I’m looking forward to my next script.