Open In Colab   Open in Kaggle

Tutorial: LIF Neuron Part I#

Week 0, Day 1: Python Workshop 1

By Neuromatch Academy

Content creators: Marco Brigham and the CCNSS team

Content reviewers: Michael Waskom, Karolina Stosio, Spiros Chavlis

Production editors: Ella Batty, Spiros Chavlis


Tutorial objectives#

During NMA, you will be using code to learn computational neuroscience in an interactive (and hopefully fun) way. This tutorial and the next are to help you get up to speed on Python before the course, so that during the course you can focus on the computational neuroscience concepts.

In this notebook, we’ll practice basic operations with Python variables, control flow, plotting, and take a sneak peek at np.array, the workhorse of scientific computation in Python.

Each new concept in Python will unlock a different aspect of our implementation of a Leaky Integrate-and-Fire (LIF) neuron. And as if it couldn’t get any better, we’ll visualize the evolution of its membrane potential in time, and extract its statistical properties!


Setup#

Please execute the cell(s) below to initialize the notebook environment.

Install and import feedback gadget#

Hide code cell source
# @title Install and import feedback gadget

!pip3 install vibecheck datatops --quiet

from vibecheck import DatatopsContentReviewContainer
def content_review(notebook_section: str):
    return DatatopsContentReviewContainer(
        "",  # No text prompt
        notebook_section,
        {
            "url": "https://pmyvdlilci.execute-api.us-east-1.amazonaws.com/klab",
            "name": "neuromatch-precourse",
            "user_key": "8zxfvwxw",
        },
    ).render()


feedback_prefix = "W0D1_T1"
# Imports
import numpy as np
import matplotlib.pyplot as plt

Figure settings#

Hide code cell source
# @title Figure settings
import logging
logging.getLogger('matplotlib.font_manager').disabled = True
import ipywidgets as widgets  # interactive display
%config InlineBackend.figure_format = 'retina'
plt.style.use("https://raw.githubusercontent.com/NeuromatchAcademy/course-content/master/nma.mplstyle")

Section 1: Python basics & the LIF model#

Video 1: Python basics & the LIF model#

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_Python_basics_and_the_LIF_model_Video")

Section 1.1: The LIF Model#

A membrane equation and a reset condition define our leaky-integrate-and-fire (LIF) neuron:

(1)#\[\begin{align} \tau_m\,\frac{d}{dt}\,V(t) &= E_{L} - V(t) + R\,I(t) &\text{if }\quad V(t) \leq V_{th} \\ \\ V(t) &= V_{reset} &\text{otherwise} \end{align}\]

where $V(t)$ is the membrane potential, $\tau_m$ is the membrane time constant, $E_{L}$ is the leak potential, $R$ is the membrane resistance, $I(t)$ is the synaptic input current, $V_{th}$ is the firing threshold, and $V_{reset}$ is the reset voltage. We can also write $V_m$ for membrane potential, which is more convenient for plot labels.

The membrane equation describes the time evolution of membrane potential \(V(t)\) in response to synaptic input and leaking of charge across the cell membrane. This is an ordinary differential equation (ODE), a concept we will learn more about in future days.

Note that, in this tutorial the neuron model will not implement a spiking mechanism.

Section 1.2: Comments in code#

Video 2: Nano recap of comments and strings#

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_Nano_recap_of_comments_and_strings_Video")

Coding Exercise 1: Defining parameters#

We start by defining and initializing the main simulation variables for our LIF neuron.

In the code cell below, please modify the code to print the simulation parameters.

# t_max = 150e-3   # second
# dt = 1e-3        # second
# tau = 20e-3      # second
# el = -60e-3      # milivolt
# vr = -70e-3      # milivolt
# vth = -50e-3     # milivolt
# r = 100e6        # ohm
# i_mean = 25e-11  # ampere

# print(t_max, dt, tau, el, vr, vth, r, i_mean)

SAMPLE OUTPUT

0.15 0.001 0.02 -0.06 -0.07 -0.05 100000000.0 2.5e-10

Click for solution

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_Defining_Parameters_Ecercise")

We needed to remove the #’s at the start of each line - otherwise the code is read as comments and not actually run. Sometimes when you’re writing code, you may want to “comment out” sections of code for debugging purposes. Note that we tried to use descriptive variable names, in this case that correspond to the math notation we use. We also used comments to denote units within the code - this makes it much easier to understand!

Section 1.3: Math operations#

Coding Exercise 2: Simulating an input current#

synaptic input

We need to simulate the synaptic input \(I(t)\) that goes into our model neuron. We will start with a sinusoidal model to simulate this input (visualized above), using the equation:

(2)#\[\begin{equation} I(t)=I_{mean}\left(1+\sin\left(\frac{2 \pi}{0.01}\,t\right)\right) \end{equation}\]

where \(I_{mean}\) is the mean current input and \(t\) is the time.

In the next cell, you will compute the values of synaptic input \(I(t)\) between \(t=0\) and \(t=0.009\) with step \(\Delta t=0.001\).


New coding concepts:

  • We use a for loop in the code below. We will dive deeper into for loops later, but essentially for loops allow us to run the same code block multiple times. In this case, we loop over steps so the variable step equals something new each time. We use the following syntax:

    for step in range(10):
    

    This means that step will take each integer value between 0 and 9.

  • You can use np.pi as the value of \(\pi\) and np.sin(x) to get the sine of x. These come from a package called numpy, which we’ll learn about later.


\(^{\dagger}\)Generally, the range python function returns a sequence of numbers, starting from 0 (by default), and increments by 1 (by default), and stops before a specified number.

Syntax:

range(start, stop, step)

Parameters:

  • start: Optional. An integer number specifying at which position to start. Default is 0

  • stop: Required. An integer number specifying at which position to stop (not included).

  • step: Optional. An integer number specifying the incrementation. Default is 1

# Loop for 10 steps, variable 'step' takes values from 0 to 9
for step in range(10):

  # Compute value of t
  t = step * dt

  # Compute value of i at this time step
  i = ...

  # Print value of i
  print(i)

SAMPLE OUTPUT

2.5e-10
3.969463130731183e-10
4.877641290737885e-10
4.877641290737885e-10
3.9694631307311837e-10
2.5000000000000007e-10
1.0305368692688176e-10
1.2235870926211617e-11
1.223587092621159e-11
1.0305368692688186e-10

Click for solution

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_Simulating_an_Input_Current_Ecercise")

Section 1.4: Print formatting#

Print formatting is handy for displaying simulation parameters in a clean and organized form. Python 3.6 introduced the new string formatting f-strings. Since we are dealing with type float variables, we use f'{x:.3f}' for formatting x to three decimal points, and f'{x:.4e}' for four decimal points but in exponential notation.

x = 3.14159265e-1
print(f'{x:.3f}')
--> 0.314

print(f'{x:.4e}')
--> 3.1416e-01

Coding Exercise 3: Printing pretty numbers#

Repeat the loop from the previous exercise and print the t values with three decimal points, and synaptic input \(I(t)\) with four decimal points in exponential notation.

# Initialize step_end
step_end = 10

# Loop for step_end steps
for step in range(step_end):

  # Compute value of t
  t = step * dt

  # Compute value of i at this time step
  i = i_mean * (1 + np.sin((t * 2 * np.pi) / 0.01))

  # Print value of t and i
  print(...)

SAMPLE OUTPUT

0.000 2.5000e-10
0.001 3.9695e-10
0.002 4.8776e-10
0.003 4.8776e-10
0.004 3.9695e-10
0.005 2.5000e-10
0.006 1.0305e-10
0.007 1.2236e-11
0.008 1.2236e-11
0.009 1.0305e-10

Click for solution

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_Printing_Pretty_Numbers_Ecercise")

Section 2: For loops & discrete time integration#

Video 3: For loops & discrete time integration#

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_For_Loops_and_Discrete_time_integration_Video")

Section 2.1: For Loops#

A for loop implements the indented code block multiple times (with the variable being looped over equaling something new each time). The following three formulations are all equivalent and loop for three steps:

for step in [0, 1, 2]:
  print(step)

for step in range(3):
  print(step)

start = 0
end = 3
stepsize = 1

for step in range(start, end, stepsize):
  print(step)

Section 2.2: Discrete time integration with spikes#

Video 4: Nano recap of discrete time integration#

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_Nano_recap_of_Discrete_time_integration_Video")

In the next exercises, we will simulate the evolution of the membrane equation in discrete time steps, with a sufficiently small \(\Delta t\).

We start by writing the time derivative \(d/dt\,V(t)\) in the membrane equation without taking the limit \(\Delta t \to 0\):

(3)#\[\begin{equation} \tau_m\,\frac{V\left(t+\Delta t\right)-V\left(t\right)}{\Delta t} = E_{L} - V(t) + R\,I(t) \qquad\qquad (1) \end{equation}\]

The value of membrane potential \(V\left(t+\Delta t\right)\) can be expressed in terms of its previous value \(V(t)\) by simple algebraic manipulation. For small enough values of \(\Delta t\), this provides a good approximation of the continuous-time integration.

This operation is an integration since we obtain a sequence \(\{V(t), V(t+\Delta t), V(t+2\Delta t),...\}\) starting from the ODE. Notice how the ODE describes the evolution of \(\frac{d}{dt}\,V(t)\), the derivative of \(V(t)\), but not directly the evolution of \(V(t)\). For the evolution of \(V(t)\) we need to integrate the ODE, and in this tutorial, we will do a discrete-time integration using the Euler method. See Numerical methods for ordinary differential equations for additional details.

Coding Exercise 4: Simulating membrane potential#

Compute the values of \(V(t)\) between \(t=0\) and \(t=0.01\) with step \(\Delta t=0.001\) and \(V(0)=E_L\).

We need to reorganize the Eq. (1) to isolate \(V\left( t+\Delta t \right)\) on the left side, and express it as function of \(V(t)\) and the other terms:

(4)#\[\begin{equation} V(t + \Delta t) = V(t) + \frac{\Delta t}{\tau_m}\left( E_L -V(t) + R I(t) \right) \end{equation}\]
#################################################
## TODO for students: fill out compute v code ##
# Fill out code and comment or remove the next line
raise NotImplementedError("Student exercise: You need to fill out code to compute v")
#################################################

# Initialize step_end and v0
step_end = 10
v = el

# Loop for step_end steps
for step in range(step_end):
  # Compute value of t
  t = step * dt

  # Compute value of i at this time step
  i = i_mean * (1 + np.sin((t * 2 * np.pi) / 0.01))

  # Compute v
  v = ...

  # Print value of t and v
  print(f"{t:.3f} {v:.4e}")

SAMPLE OUTPUT

0.000 -5.8750e-02
0.001 -5.6828e-02
0.002 -5.4548e-02
0.003 -5.2381e-02
0.004 -5.0778e-02
0.005 -4.9989e-02
0.006 -4.9974e-02
0.007 -5.0414e-02
0.008 -5.0832e-02
0.009 -5.0775e-02

Click for solution

Submit your feedback#

Hide code cell source
# @title Submit your feedback
content_review(f"{feedback_prefix}_Simulating_membrane_potential_Exercise")

Section 3: Plotting#

Video 5: Intro to plotting#

Submit your feedback#