原始信号进,命令出
解码的核心,是一种反复运行的转换:一段原始电压进去,一个离散的命令出来。把它想象成一条工厂流水线。传送带永不停歇——新鲜的大脑信号不断到来——而在末端,一件成品(一次光标移动、一个字母、一次机械手抓握)滚落下来。这条流水线的任务,就是让传送带平稳运转,每秒数十次地把杂乱的电信号变成干净的决策。
输入是你的传感器所传来的任何东西——来自头皮的脑电图(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