原始訊號進,命令出
解碼的核心,是一種反覆執行的轉換:一段原始電壓進去,一個離散的命令出來。把它想像成一條工廠流水線。輸送帶永不停歇——新鮮的大腦訊號不斷到來——而在末端,一件成品(一次游標移動、一個字母、一次機械手抓握)滾落下來。這條流水線的任務,就是讓輸送帶平穩運轉,每秒數十次地把雜亂的電訊號變成乾淨的決策。
輸入是你的感測器所傳來的任何東西——來自頭皮的腦電圖(EEG,electroencephalography)、來自皮層表面的皮層腦電圖(ECoG,electrocorticography),或來自皮層內電極陣列的尖峰放電。輸出則是現實世界中的一個動作。兩者之間的一切就是流水線,而從業者的功力,正體現在每一階段如何搭建、以及整體執行有多快。
四個階段
幾乎每一個解碼器,無論簡單還是花俏,都是這四個階段依序排列的某種版本。掌握它們一次,你就能讀懂遇到的任何流水線。
線上與離線
執行解碼器有兩個世界。離線分析是從容的:你有一份錄製好、存在磁碟上的資料集,可以反覆回放、偷看未來、試上一百個模型、消磨整個下午。線上(即時)解碼則毫無這份從容。訊號是即時到來的,使用者在等待,迴路必須在時機溜走之前閉合。
正是這一條約束——端到端地跟上即時訊號——塑造了一切。你只能用過去、絕不能用未來,所以非因果濾波器被排除在外。從視窗到命令的整體延遲通常必須落在大約 100 毫秒以內才感覺跟手,這就限制了你的特徵和模型能有多重。而且它必須無人看管地執行,所以流水線得優雅地處理壞樣本,而不是直接崩潰。
一段流水線虛擬碼
下面就是把整條流水線寫成的一個小迴圈。先講直覺:我們抓取訊號最新的一片,把它清洗乾淨,擠出特徵,問訓練好的分類器它意味著什麼,然後發出命令——接著馬上再來一圈。請留意,前面那四個階段,在迴圈裡恰好各佔一行。
# Real-time decoding loop. Runs as long as the BCI is on.
while bci_is_running:
window = stream.read(samples=250) # newest 1 s @ 250 Hz (past only)
if has_artifact(window):
continue # skip bad chunk, don't crash
clean = bandpass(window, low=8, high=30) # keep mu/beta band (8-30 Hz)
feats = band_power(clean) # extract features: power per channel
intent = classifier.predict(feats) # classify -> e.g. 'left' / 'right'
send_command(intent) # issue command; user sees feedback
# loop repeats every step -> a fresh decision many times per second