跳轉到

1952:Hodgkin–Huxley 神經模擬 — 手搖計算機的動作電位#

副標題:三週的手搖計算,算出神經衝動的一生。

案發現場#

1952 年,普利茅斯的魷魚巨軸突成為命案現場。 直徑近一毫米的神經纖維,每次興奮都伴隨電壓尖峰。 靜息約負六十毫伏,興奮衝到正四十毫伏再回落。 問題:這 100 毫伏的來回,兇手是誰? 嫌疑人名單很長:膜電容、鈉離子、鉀離子、漏電流。 電壓鉗剛成熟,可固定電壓測離子流,證據湧入。 Hodgkin 與 Huxley 決定把證據寫成一個動力系統。 沒有電腦,唯一工具是手搖計算機。 Huxley 每天搖數小時,Hodgkin 負責核對曲線。 賭注是聖杯:神經訊號是電現象還是化學現象?

偵查過程#

線索一:電壓鉗的口供#

電壓鉗釘住膜電位,離子通道無所遁形。 去外液鈉,早期內向電流消失,證明它是鈉電流。 阻斷鉀,晚期外向電流消失,證明它是鉀電流。 剩下本底小電流,歸為漏電流 \(I_L\) 。 每種電流等於電導乘驅動力,驅動力是膜電位與平衡電位之差。 鈉平衡為 \(E_{Na}\) ,鉀平衡為 \(E_K\) ,漏電平衡為 \(E_L\) 。 電導是電壓與時間的函數,這是最難的一鎖。

線索二: \(m\) 、 \(h\) 、 \(n\) 三名嫌犯#

鈉通道設三個活化門 \(m\) 加一個失活門 \(h\) 。 鉀通道設四個活化門 \(n\) ,每門皆一階動力學。 速率 \(\alpha\) 與 \(\beta\) 全由電壓鉗曲線擬合,共六組函數。 電壓是唯一的鑰匙,門的開關全聽它指揮。 | 變量 | 通道 | 冪次 | 意義 | |------|------|------|------| | \(m\) | 鈉活化 | 三次方 | 去極化迅速打開 | | \(h\) | 鈉失活 | 一次方 | 持續去極化後關閉 | | \(n\) | 鉀活化 | 四次方 | 較慢打開,負責復極化 |

線索三:手搖三週的積分#

膜方程一條,耦合三個門方程,步進更新 \(V\) 、 \(m\) 、 \(h\) 、 \(n\) 。 步長必須很小,否則上升支陡峭前緣失真。 Huxley 算了三週,才得到一條完整動作電位曲線。 曲線與實驗幾乎重合:閾值、不應期、傳導速度全對。 模型還預言不應期與陽極反彈等現象。 1952 年四篇系列論文即本案卷宗。 完整膜方程可用獨立公式寫出如下。

\[ C\dot V = I - g_{Na}m^3h(V-E_{Na}) - g_Kn^4(V-E_K) - g_L(V-E_L) \]

其中 \(C\) 為膜電容, \(I\) 為外加電流, \(g\) 為最大電導。 門變量動力學形式統一,獨立公式如下。

\[ \dot m = \alpha_m(V)(1-m) - \beta_m(V)m \]

其中 \(\alpha_m\) 為開門速率, \(\beta_m\) 為關門速率。

結案報告#

1952 年模型破解動作電位之謎:電壓依賴電導驅動非線性波。 閾值來自鈉電流正回饋,復極化來自鈉失活加鉀外流。 兩人獲 1963 年諾貝爾生理學或醫學獎。 遺產深遠:簡化模型、多房室模型、全腦模擬皆其子孫。 計算神經科學就此誕生:數值模擬可發現生理真相。

證據與工具#

魷魚軸突攝氏 6.3 度經典參數表如下。 | 參數 | 數值 | 單位 | |------|------|------| | \(C\) | 約 1.0 | 微法每平方公分 | | \(g_{Na}\) | 約 120 | 毫西門子每平方公分 | | \(g_K\) | 約 36 | 毫西門子每平方公分 | | \(E_{Na}\) | 約 50 | 毫伏 | | \(E_K\) | 約負 77 | 毫伏 | 重現建議:顯式尤拉或龍格庫塔,步長 0.01 毫秒。 外加短脈衝 \(I\) ,觀察是否越過閾值。 繪 \(V\) 、 \(m\) 、 \(h\) 、 \(n\) 四曲線,確認鈉快鉀慢。 原文獻:1952 年《生理學期刊》四連篇,必讀卷宗。 因果鏈:電壓鉗提供證詞,手搖機完成推理,Nobel 1963 年蓋章。 後續 FitzHugh–Nagumo 把四維化簡為二維,保留興奮與恢復。 多房室模型把軸突延伸為樹突樹,全腦模擬皆其後裔。 本案檔案編號 HH-1952 ,狀態已結案,方程至今仍在放電。 改變外液鈉鉀濃度,可直接驗證平衡電位 Nernst 預言。

補充:程式實作#

對應程式:1952-hodgkin_huxley.py

理論呼應#

本文斷言動作電位來自電壓依賴電導的非線性回饋,而非單一離子作案。

程式以顯式尤拉積分耦合膜電位與三個門變量,重演閾值與復極化。

核心膜方程為 \(C \dot V = I - I_{Na} - I_K - I_L\) ,各離子流皆為電導乘驅動力。

鈉活化變量 \(m\) 上升最快,鉀活化變量 \(n\) 落後跟上,正好呼應鈉快鉀慢的證詞。

案發現場只剩一條電壓曲線會說話,門變量的時間差就是它留下的腳印。

如何執行#

在本文所屬目錄下執行以下指令即可重現全部數字。

python3 _code/1952-hodgkin_huxley.py

程式只依賴 numpy ,已固定亂數種子,任何機器重跑都應一致。

預設步長為 dt = 0.01 毫秒,總時長 50 毫秒,外加脈衝持續 5 毫秒。

實測結果抄錄#

以下數字為本次實際執行所得,未經修飾,直接抄錄關鍵行。

V_peak=40.681 mV

V_rest_init=-65.000 mV

V_rest_end=-64.994 mV

驗證行顯示峰值大於零毫伏且靜息維持在負六十五毫伏附近。

程式最後印出 ALL CHECKS PASS ,表示閾值穿越與靜息回落皆成立。

由此可見手搖三週的積分結論,今日幾秒即可重演驗證。

動手實驗#

讀者可把外加電流 10.0 改為 3.0 或 20.0 ,觀察閾值上下動作電位如何消失或提前出現。

完整程式如下:

# -*- coding: utf-8 -*-
"""1952 Hodgkin-Huxley 單房室模型 (對應 wiki: 計算模擬學 / HH 動作電位)
只用 numpy,固定種子。電流脈衝 I=10 uA/cm^2 持續 5ms,Euler dt=0.01ms 跑 50ms。
驗證:產生動作電位(V 峰值 > 0 mV)且靜息約 -65 mV。
"""
import numpy as np

np.random.seed(0)

# --- 參數 (經典 HH) ---
C = 1.0        # uF/cm^2
gNa = 120.0    # mS/cm^2
gK = 36.0
gL = 0.3
ENa = 50.0     # mV
EK = -77.0
EL = -54.387

dt = 0.01      # ms
T = 50.0       # ms
steps = int(T / dt)

def alpha_m(V): return 0.1 * (V + 40.0) / (1.0 - np.exp(-(V + 40.0) / 10.0)) if abs(V + 40.0) > 1e-7 else 1.0
def beta_m(V):  return 4.0 * np.exp(-(V + 65.0) / 18.0)
def alpha_h(V): return 0.07 * np.exp(-(V + 65.0) / 20.0)
def beta_h(V):  return 1.0 / (1.0 + np.exp(-(V + 35.0) / 10.0))
def alpha_n(V): return 0.01 * (V + 55.0) / (1.0 - np.exp(-(V + 55.0) / 10.0)) if abs(V + 55.0) > 1e-7 else 0.1
def beta_n(V):  return 0.125 * np.exp(-(V + 65.0) / 80.0)

V = -65.0
m = alpha_m(V) / (alpha_m(V) + beta_m(V))
h = alpha_h(V) / (alpha_h(V) + beta_h(V))
n = alpha_n(V) / (alpha_n(V) + beta_n(V))

Vs = np.empty(steps)
for i in range(steps):
    t = i * dt
    I = 10.0 if 5.0 <= t < 10.0 else 0.0  # 10 uA/cm^2 持續 5ms
    INa = gNa * m**3 * h * (V - ENa)
    IK = gK * n**4 * (V - EK)
    IL = gL * (V - EL)
    V = V + dt * (I - INa - IK - IL) / C
    m = m + dt * (alpha_m(V) * (1 - m) - beta_m(V) * m)
    h = h + dt * (alpha_h(V) * (1 - h) - beta_h(V) * h)
    n = n + dt * (alpha_n(V) * (1 - n) - beta_n(V) * n)
    Vs[i] = V

V_peak = float(np.max(Vs))
V_rest_init = float(Vs[0])
V_rest_end = float(np.mean(Vs[-500:]))  # 最後 5ms 平均
ok_peak = V_peak > 0.0
ok_rest = (-75.0 < V_rest_end < -60.0) and (-75.0 < V_rest_init < -60.0)

print(f"V_peak={V_peak:.3f} mV (驗證 > 0 mV: {'PASS' if ok_peak else 'FAIL'})")
print(f"V_rest_init={V_rest_init:.3f} mV, V_rest_end={V_rest_end:.3f} mV (驗證約 -65 mV: {'PASS' if ok_rest else 'FAIL'})")
print(f"VERIFY: V_peak={V_peak:.6f}, V_rest_end={V_rest_end:.6f}")
assert ok_peak, "未產生動作電位"
assert ok_rest, "靜息電位偏離 -65 mV"
print("ALL CHECKS PASS")