Модель integrate-and-fire: симуляция спайков

Самая популярная учебная модель нейрона: мембрана как RC-цепь плюс правило «достиг порога — спайк и сброс».

Leaky integrate-and-fire (LIF) — модель, где подпороговый потенциал описывается линейным уравнением с утечкой, а спайк добавляется вручную при достижении порога.

Уравнение модели

Подпороговая динамика мембраны:

$$ \tau_m \frac{dV}{dt} = -\big(V - V_{rest}\big) + R_m\, I $$

Когда $V$ достигает порога $V_{th}$, фиксируем спайк и сбрасываем $V \leftarrow V_{reset}$. Здесь $\tau_m$ — постоянная времени мембраны, $R_m$ — сопротивление, $I$ — входной ток. Чем больше $I$, тем быстрее $V$ доходит до порога и тем выше частота спайков.

Численное интегрирование

Заменяем производную конечной разностью с шагом $\Delta t$: $V_{n+1} = V_n + \frac{\Delta t}{\tau_m}\big(-(V_n - V_{rest}) + R_m I\big)$. Это метод Эйлера.

Как работает под капотом

Симулируем 200 мс при постоянном токе и считаем спайки:

tau = 10.0      # мс
R_m = 10.0      # МОм (условные единицы)
V_rest, V_th, V_reset = -70.0, -50.0, -75.0
dt, I, T_end = 0.1, 2.6, 200.0

V = V_rest
spikes = []
steps = int(T_end / dt)
for i in range(steps):
    t = i * dt
    V += (-(V - V_rest) + R_m * I) / tau * dt
    if V >= V_th:
        V = V_reset
        spikes.append(round(t, 1))

print("Спайков за 200 мс:", len(spikes))
print("Первые моменты (мс):", spikes[:5])
isi = spikes[1] - spikes[0]
print("Межспайковый интервал:", round(isi, 1), "мс")
print("Частота разрядов:", round(1000.0 / isi), "Гц")

Вывод:

Спайков за 200 мс: 12
Первые моменты (мс): [14.5, 30.9, 47.3, 63.7, 80.1]
Межспайковый интервал: 16.4 мс
Частота разрядов: 61 Гц

F-I кривая: частота от тока

Главный результат — зависимость частоты от силы тока. Ниже некоторого порога тока нейрон молчит, выше — частота растёт:

def rate(I, tau=10.0, R_m=10.0, dt=0.1, T_end=200.0):
    V, V_rest, V_th, V_reset = -70.0, -70.0, -50.0, -75.0
    n = 0
    for i in range(int(T_end / dt)):
        V += (-(V - V_rest) + R_m * I) / tau * dt
        if V >= V_th:
            V = V_reset
            n += 1
    return n / (T_end / 1000.0)   # спайков в секунду

for I in (1.5, 2.0, 2.5, 3.0, 4.0):
    print(f"I={I}: {rate(I):.0f} Гц")

Вывод:

I=1.5: 0 Гц
I=2.0: 0 Гц
I=2.5: 55 Гц
I=3.0: 80 Гц
I=4.0: 120 Гц

Виден порог: при $R_m I \le V_{th} - V_{rest} = 20$ мВ (то есть $I \le 2.0$) потенциал не дотягивает до порога — спайков нет. Это прямая иллюстрация принципа «всё или ничего» в численной модели.

Частые ошибки

  • Слишком крупный шаг $\Delta t$: метод Эйлера расходится, частота «врёт». Берите $\Delta t \ll \tau_m$.
  • Забыть сброс $V \leftarrow V_{reset}$ — нейрон «зависнет» над порогом и будет спайкать каждый шаг.
  • Ожидать спайков при подпороговом токе: ниже порога LIF честно молчит.

Итог

  • LIF: $\tau_m \dot V = -(V - V_{rest}) + R_m I$ плюс правило порога и сброса.
  • Интегрируем методом Эйлера с малым шагом.
  • F-I кривая имеет порог по току и далее почти линейно растёт.
Проверьте себя
1. Что делает модель LIF при достижении порога V_th?
AПлавно снижает V
BФиксирует спайк и сбрасывает V к V_reset
CУвеличивает ток
DОстанавливает симуляцию
2. Почему при I=2.0 в примере 0 спайков?
AОшибка кода
BR_m·I не превышает V_th−V_rest=20 мВ, порог не достигается
CСлишком большой шаг
DНейрон устал
3. Что произойдёт при слишком большом шаге Δt в методе Эйлера?
AТочность вырастет
BРешение может расходиться и частота исказится
CНичего
DСпайки исчезнут навсегда