☰
脑电信号分析必知:相位锁定值(PLV)原理、计算与避坑全解析
2026/10/20 16:44:47 网站建设 项目流程

脑电信号分析里,“相位锁定值(Phase Locking Value,PLV)”一直是我在实际项目中用的比较多的一个指标。做认知神经科学实验、脑机接口分析、甚至是评估干预前后的脑网络变化,PLV都绕不开。这篇内容就来把PLV从概念到计算、从代码到避坑讲透,尤其是那些你拿着公式也未必能发现的小细节,我这里会和盘托出。适合刚接触脑网络分析的研究生,也适合做BCI或脑疾病数据分析的工程师参考。

1. 整体设计思路:为什么用PLV而不是简单算相关

1.1 PLV衡量的到底是什么

脑电图(EEG)记录的是头皮上多个电极点随时间变化的电位。传统的时域分析大多关注波形幅度。但脑功能连接研究中,我们常常关心的是两个脑区之间的“通信质量”——这种通信不一定是信号幅度有多大,而是两个区域在加工同一信息时,振荡节律是否能保持固定相位关系。

PLV就是用来量化这种相位同步程度的指标。它的核心思想很简单:如果两个电极位置的脑电信号在某个频带上相位差值始终接近一个常数,就认为这两个区域在这个频带上存在相位同步。

比如你让被试看一个闪烁的视觉刺激,视觉皮层和后顶叶区域的gamma频段振荡会出现稳定的相位锁定,这种锁定关系你用幅度相关是看不出来的,因为幅度可能忽大忽小,但相位差却保持着稳定。PLV的价值恰恰在于它能抓住这种“弱幅度、强锁定”的效应。

1.2 试次内与试次间PLV的取舍

PLV有两种常见计算方式,很多人第一次接触时容易混:

一种是试次间PLV(inter-trial PLV),对每个时间点,把多次试次的相位差向量求平均长度。这种计算适合事件相关设计,看的是跨试次重复出现的相位关系,常用于稳态诱发电位、事件相关同步/去同步分析。

另一种是试次内PLV(intra-trial PLV),对单次试次的整个时间窗内做平均。这种算法更适合分析连续任务中的脑区间连接,比如静息态数据、自由观看视频时的EEG、或者神经反馈训练前后的连接变化。

我自己的经验是,做静息态或长时间的连续任务时,优先用试次内PLV;做经典的刺激锁时实验,试次间PLV信息量更大。两者的计算代码差不了几行,但统计对策和结果解释逻辑完全不同。后面我会分别给出计算方式和对应的参数设置建议。

1.3 用PLV做功能连接的优势与局限

为什么在众多连接指标中选PLV?它有一个不可替代的优势——只依赖相位信息,对幅度差异不敏感。头皮EEG信号经过容积导体传播后,幅度受到颅骨、头皮组织衰减的影响很大,同一脑源在不同电极上记录的幅度可以差出好几倍。如果拿幅度来做连接分析,很容易被这种系统性的传导衰减带偏。PLV只关心相位差是否稳定,在脑电这种“幅度被糟蹋但相位相对保留”的信号上,稳定性要好得多。

但这同时是它的局限。相位差稳定不等于有真实的神经通信,也可能是两个电极记录到了同一个源头信号的体积传导,此时相位差可能非常稳定甚至趋于0。这也是PLV饱受诟病的地方——所谓的零延迟同步容易受共同源影响。缓解方案有两个方向:一是做源空间分析而不是传感器空间分析,二是用加权的PLV或者相位斜率指数替代。但我认为,在传感器空间做组间对比时,只要保证两组数据经过同样处理、参考方式相同,PLV的组间差异仍然是有解释力的,只是解释时要谨慎一点。

2. 核心细节解析:公式、滤波与参数选择

2.1 PLV的数学定义,以及和相干性的区别

先写试次内PLV的公式。假设两路信号分别为x(t)、y(t),经过窄带滤波后用希尔伯特变换求瞬时相位φx(t)和φy(t),那么相位差Δφ(t)=φx(t)−φy(t)。PLV的定义是:

PLV = | (1/N) * Σ exp(i * Δφ(t_n)) |

N是时间窗内的采样点数。如果相位差始终为某个固定值,那么每个单位复向量都指向同一个方向,取平均后模长仍是1;如果相位差随机分布在0到2π,平均向量会互相抵消,模长趋近0。

试次间PLV稍有不同,它把每个试次当做一次“测量”,对每个时间点t计算exp(iΔφ_k(t))在所有试次k上的平均模长。这里N是试次数。

很多人会把PLV和相干性(Coherence)混淆。相干性计算的是互功率谱归一化后的幅度,它同时受相位一致性和幅度一致性影响。PLV只取相位部分,因此幅度调制不会干扰它。实际分析中,哪个指标更敏感取决于数据特性。如果两组条件之间的差异主要体现在相位上,PLV的检验功效通常优于相干性;如果差异同时体现在幅度上,相干性可能更稳健。我在做预实验时通常会两个指标都算一遍,然后观察是哪个指标出现了更清晰的条件间分离,再决定正式分析用哪个。

2.2 相位提取的关键:窄带滤波与希尔伯特变换

相位信息不能直接在宽带信号上提取,必须先把目标频带信号分离出来。窄带滤波是PLV计算中最容易翻车的一步。滤波器带宽怎么选?经典的做法是对目标频带做带通滤波,比如alpha频段用8-13Hz,gamma频段用30-45Hz,然后对滤波后的信号做希尔伯特变换得到解析信号,取虚部与实部的反正切就是瞬时相位。

这里有个关键细节:滤波器的阶数不能设置得太高。过高阶数会带来明显的边缘效应,信号首尾各一段会失真;但阶数太低,过渡带太宽,频带外的能量泄漏进来,相位估计也随之污染。我常用的方案是用scipy.signal里的零相位滤波filtfilt,配合butterworth滤波器,阶数设4-5阶,过渡带的实际顺序我一般在代码里单独检查一遍滤波前后频谱,确保通带纹波可以接受。实际测试中,同样的数据用2阶和5阶滤波,PLV结果可能差出0.1以上,这在组间检验里足以改变显著性结论。

希尔伯特变换本身不复杂,但有一点必须提醒:对滤波后的窄带信号做希尔伯特变换时,要保证信号足够长。瞬时相位在信号边缘会出现边界伪影,尤其是靠近首尾的50ms,相位估计极不稳定。我处理段落时通常每段数据前后留出至少1秒的缓冲,算完PLV后再把边缘部分切掉。

2.3 频带选择和时间窗设置的经验参数

PLV是一个频带相关的指标,所以你得先明确分析哪个频段。常规的做法是参考已有文献划分:delta(1-4Hz)、theta(4-8Hz)、alpha(8-13Hz)、beta(13-30Hz)、gamma(30-45Hz)。但实际数据里个体alpha峰值差异很大,统一用8-13Hz可能把部分人的alpha活动切到频带外。我个人的习惯是如果样本量足够,先做个体alpha峰检测,再决定是否用个体化频带。不过要注意,个体化频带会引入额外的自由度,需要在使用前明确假设。

时间窗设置也要注意。试次内PLV的时间窗如果太短(比如小于100ms),就会极大受瞬时相位估计误差影响,PLV值容易虚高。窗口越长,相位差被平均得越彻底,估计越稳定,但过长又会把非平稳的同步变化抹平。任务态EEG我通常用200-500ms的滑窗做时变PLV,静息态分析则用2秒的非重叠窗统计平均值。这里没有绝对标准,关键是你的选择要和实验设计的时间尺度匹配。

我先给一组常用参数的参考表:

参数项任务态PLV常用值静息态PLV常用值备注
滤波类型Butterworth带通Butterworth带通4阶filtfilt零相位
频带划分theta/alpha/betadelta/theta/alpha个体alpha峰建议单独估
时间窗长250ms滑窗,步长25ms2s非重叠窗边缘效应至少切掉0.5s
试次数≥30次视连续数据长度而定太少时统计功效不足
基线校正可选,做试次间PLV时建议不需要基线窗选刺激前200ms

3. 实操过程:从原始脑电到PLV矩阵的完整流程

3.1 预处理管线怎么搭

PLV的计算结果高度依赖预处理质量。我自己的分析管线通常是这样:

先做1-45Hz的带通滤波,去除直流漂移和高频噪声。然后做坏道剔除,参考选择上,我默认使用全脑平均参考。如果做试次间PLV,会再做刺激前200ms到刺激后500ms的分段;做静息态PLV则直接切成连续2秒的epoch。

眼电伪迹是脑电相位分析的头号杀手。眨眼和眼跳会在前额叶电极引起大幅低频电位,这些电位往往有相对固定的形态,如果不去除,会在前额区域形成虚假的强同步。ICA去伪迹是我会用的一步,用来识别和剔除眼动和心电成分。这时要注意:ICA对数据长度有一定要求,至少需要几分钟的连续数据才能稳定估计成分。数据太短时,别硬跑ICA,退而求其次用回归法或直接标记坏段剔除。

关于伪迹剔除,有一个反直觉的点:肌电伪迹常常落在beta和gamma频带,如果你做的是这两个频段的PLV,肌电会直接提高PLV值,而且是虚假地提高,因为肌电信号来自颅外肌肉,它同时出现在多个相邻电极上,产生了类似于“同步”的东西。我碰到过不少次这种情况:被试咬牙就导致gamma频段全脑连接显著上升。解决的方法有两个,一是严格监控实验过程中的肌电活动,事后对肌电伪迹段做方差阈值剔除;二是分析前先做SSP或使用更保守的回归方法去除肌电成分。坦白说,这类伪迹比较顽固,如果实在去除不干净,建议在论文里如实报告。

完整预处理参考代码如下:

import mne import numpy as np from scipy import signal raw = mne.io.read_raw_fif('subj01_raw.fif', preload=True) raw.filter(1.0, 45.0, fir_design='firwin') # 坏道插值 raw.info['bads'] = ['EEG 023'] raw.interpolate_bads(reset_bads=True) # 剔除非脑电通道,设置平均参考 raw.pick_types(eeg=True) raw.set_eeg_reference('average') # 分段 epochs = mne.Epochs(raw, events, tmin=-0.2, tmax=1.0, baseline=(-0.2, 0), reject=dict(eeg=150e-6), preload=True) # ICA去眼动 ica = mne.preprocessing.ICA(n_components=20, random_state=42) ica.fit(epochs) ica.exclude = [0, 1] # 通过画图确定眼动成分 epochs = ica.apply(epochs)

这里有几个小坑要特别提醒。reject=dict(eeg=150e-6)是按峰峰值剔除坏段,阈值需要先看数据分布再调整,有的被试噪声低80uV就够,有的被试基线不稳得放到200uV。baseline=(-0.2, 0)只在计算幅度等指标时需要,对试次间PLV的相位差没有实际作用,但保留也无妨。ICA的random_state建议固定,方便复现分析结果。

3.2 核心计算代码:试次内PLV和试次间PLV

接下来是重点:整个PLV计算的核心代码。用MNE统一管理epoch数据,再用SciPy处理滤波和希尔伯特变换。这里给出一个贴近实战的实现。

def compute_plv_intra_trial(epochs, ch_pair, f_band=(8, 13), fs=250): """ 试次内PLV:对每个试次的全部采样点计算相位差平均模长 epochs: mne.Epochs对象 ch_pair: 电极名称元组,比如('Fz', 'Cz') f_band: 目标频带 fs: 采样率 """ ch1, ch2 = ch_pair x = epochs.get_data(picks=[ch1])[:, 0, :] y = epochs.get_data(picks=[ch2])[:, 0, :] # 对每个试次做带通滤波 b, a = signal.butter(4, [f_band[0], f_band[1]], btype='bandpass', fs=fs) x_f = signal.filtfilt(b, a, x, axis=-1) y_f = signal.filtfilt(b, a, y, axis=-1) # 希尔伯特变换求瞬时相位 x_phase = np.angle(signal.hilbert(x_f, axis=-1)) y_phase = np.angle(signal.hilbert(y_f, axis=-1)) delta_phase = x_phase - y_phase plv = np.abs(np.mean(np.exp(1j * delta_phase), axis=-1)) return plv # 每个试次一个PLV值 def compute_plv_inter_trial(epochs, ch_pair, f_band=(8, 13), fs=250): """ 试次间PLV:对每个时间点,在试次方向求相位差平均模长 结果是一个随时间变化的PLV曲线 """ ch1, ch2 = ch_pair x = epochs.get_data(picks=[ch1])[:, 0, :] y = epochs.get_data(picks=[ch2])[:, 0, :] b, a = signal.butter(4, [f_band[0], f_band[1]], btype='bandpass', fs=fs) x_f = signal.filtfilt(b, a, x, axis=-1) y_f = signal.filtfilt(b, a, y, axis=-1) x_phase = np.angle(signal.hilbert(x_f, axis=-1)) y_phase = np.angle(signal.hilbert(y_f, axis=-1)) delta_phase = x_phase - y_phase # 对试次维度求平均 plv_t = np.abs(np.mean(np.exp(1j * delta_phase), axis=0)) return plv_t # 每个时间点一个PLV值

试次内PLV返回的是一个长度为试次数的数组,后面做条件间比较时,可以直接用非参数检验或置换检验。试次间PLV返回的是一个时间序列,通常要在一段时间窗内再取平均,比如刺激后100到400ms的平均值,才作为这一条件的一个数值指标。如果你想画出PLV时频图,可以在每个时间点用滑窗的方式重复计算试次内PLV,得到随时间变化的连接强度曲线。

需要注意,以上代码把滤波函数放在了每个通道对的计算里。实际操作中,如果电极数量少则问题不大,但如果计算全脑两两连接,比如64个电极全连接,就是2016个通道对,每次都重新filter会浪费大量时间。一个好的习惯是提前对所有通道做完带通滤波和希尔伯特变换,把相位矩阵一次性算出来,之后任意通道对的PLV只是复指数平均的问题。数据量大时,这样能省下几十分钟到几小时。

3.3 统计检验:置换检验和多重比较校正

PLV值的分布不是正态的,尤其在通道对数量多、随机种子多的情况下,直接用t检验很容易出问题。我推荐的做法是使用基于排列的置换检验。基本的逻辑是:在条件A和条件B下分别得到某个通道对的PLV均值,合并所有试次后随机打乱条件标签,反复计算“打乱后的组间差异”,从而得到经验分布,再用真实差异去和这个分布比较,得到p值。这样做不依赖正态假设,而且对试次数偏少的情况也比较稳健。

不过,如果你做的是全脑连接分析,动辄上千个通道对,就需要对多重比较做校正。一种是Bonferroni校正,太保守;另一种是FDR校正,相对平衡。我自己的习惯是先用簇置换检验(cluster-based permutation test),它把空间相邻且时间相邻的显著通道聚集成簇,再通过置换得到簇水平的统计量,能有效处理脑电数据中通道间高度相关导致的多重比较问题。

实际操作流程是:对每个通道对独立做置换检验得到t值,设置一个初始阈值如p<0.05,找出超过阈值的通道对,按邻近关系聚类(电极空间距离小于某阈值),然后计算每个聚类的统计量(比如t值之和或均值),最后在置换循环中保留每次置换的最大等量聚类统计量,得到null分布。实现过程有点繁琐,但好处是对多重比较的校正相对温和,同时统计功效高。如果嫌手写麻烦,可以用MNE自带的mne.stats.permutation_cluster_test,前置条件是先把每个通道对的PLV时间序列整理成被试×通道对×时间的数组。

3.4 计算效率优化与代码调试经验

不少使用者在计算PLV时忽略了一个问题:相位矩阵的规模很容易把内存吃满。假设你有20个被试、64个通道、每个被试3万个采样点,那么存储一个频带的相位矩阵就是64×30000×20,float64预估约300MB,看着还不算大,但如果你再对多个频带做循环,并且保留了完整时间过程,内存就会快速膨胀。我在处理长时间连续EEG时,习惯把数据按频带分块处理,每次只保留当前频带的相位矩阵。如果数据量真的到了几百GB的规模,建议改用out-of-core的方式,逐块计算PLV并累加。

代码调试上有一个经典错误是滤波器的频率参数单位。signal.butter里用fs指定采样率后,Wn用的是Hz单位,这和以前旧版本里用的归一化频率不一样,迁移代码时特别容易踩雷。常见症状是:滤波后波形完全没有变化,或者整段信号变成高频噪声。我建议在任何滤波操作后,先画一下频谱图,确认通带位置正确再继续。

4. 常见问题与排查技巧实录

4.1 参考电极和体积传导对PLV的影响

头皮EEG的参考设置会强烈影响PLV。如果使用单极参考(比如乳突参考),那么所有电极的信号都减去参考点的电位,这个公共参考信号会同时出现在每个通道里,抬升所有电极对之间的虚假同步,PLV整体偏高,而且这种抬高在各通道对之间并不均匀。做组间比较时,只要两组都用了相同参考,统计差异仍然可信,但如果你想把PLV的绝对值作为某种生理强度来解释,就要小心参考的干扰。

体积传导效应是另一个绕不开的问题。相邻电极记录到的可能是同一皮层源的电位扩散,此时两通道之间的相位差几乎恒定,PLV很高。这不是真正的功能连接。遇到这种情况,常见的应对措施包括:在做连接分析时剔除头部中线附近的相邻电极对;或者使用一种空间滤波器如电流源密度(CSD)变换,将头皮电位转化为电流源密度估计,能在一定程度上压制体积传导带来的零延迟同步。

我实际项目里曾经遇到过大概这样的情况:某一组被试在Fz-Cz通道对上的alpha频段PLV显著高于另一组,初看似乎说明额中央区alpha同步增强。后来用CSD变换重新计算,差异完全消失了。这个教训提醒我,任何传感器空间的PLV结果在解释前,都要先考虑体积传导的可能贡献。

4.2 伪迹导致的相位突变问题

眼动、眨眼、肌肉紧张都会带来瞬时的大幅相位扰动。由于PLV对相位差的高度敏感性,即使只混入很少量的伪迹段,也可能把PLV拉得很高或者拉得很低,取决于伪迹出现的相位。更高的风险在于,不同被试或不同条件下的伪迹数量往往不一致,从而在组间引入系统性偏差。

我在实验中遇到过一个典型场景:某组被试因为任务难度更高,全程更紧张,嘴唇和颈部肌肉持续处于半收缩状态,导致所有beta/gamma频段的肌电幅度明显高于另一组。如果不在分析阶段控制肌电伪迹,最终得到的“beta频段连接增强”很可能只是肌肉紧张程度的组间差异。对此我更推荐做严格的伪迹统计:为每位被试计算伪迹段占比,并在组间比较时把这个比例作为协变量做敏感性分析。如果结果在引入协变量后仍然稳健,结论的说服力才足够。

4.3 试次数太少时PLV的统计偏差与兜底方案

试次数对PLV的影响是很多人容易忽略的。试次间PLV在试次数极少的时候,其估计值会系统性偏高。原因很简单:如果只有5个试次,即使相位之间完全无关,只要这些试次恰好落在彼此接近的位置,平均向量模长就会显得比较大。换一种更直观的说法——PLV的统计分布受试次数制约,样本量越小,零假设下的PLV期望值越高。

一个可用的兜底方案是计算置换检验时,把“随机相位”下的PLV分布作为零分布,而不是简单地和固定数值0比较。也可以对PLV做某种变换,比如把原始PLV值转换为与试次数无关的统计量,从理论上修正偏差,但在实际应用中这种非参转换的适用条件比较苛刻。最稳妥的方案还是提前做好实验设计,保证每个条件下有效试次不少于30个,如果实在达不到,建议在结果部分报告经置换检验校正后的置信区间,而不是直接给出一个看似可信的PLV数值。

4.4 结果解释时的常见误读

PLV高代表两个脑区之间“沟通更强”,这个说法在严格意义上并不成立。PLV只能说明两个位置的信号相位差保持稳定,可能是因果关系(一个区域驱动另一个),也可能是共同的调制源,还有可能是完全独立的两个振荡器恰好保持频率锁定。更准确的说法是,“这两个记录位置在该频带上出现了相位同步”,至于这种同步的机制,需要结合溯源分析和信息流方向性指标来判断。

另一个常见误读是把PLV当成数值越大越好的指标。实际上,在某些认知任务中,任务难度增加可能导致alpha频段去同步,这时PLV下降反而是认知加工的体现。我在解读自己的数据时,习惯先建立明确的假设:预测实验条件会使哪个频带、哪个电极对的PLV上升或下降,然后再进行检验。这样即使结果是零效应也更能说明问题。

在实际工作中,我发现把PLV结果直接可视化会暴露很多统计分析阶段看不见的问题。比如画出每个通道对的PLV矩阵热图,常常能看到头皮下沿或前额区域有一条对称的高亮带,这多半是眼电或肌电的残留伪迹造成的规则模式。还有一个有效的习惯是,把单个被试的PLV矩阵和全组平均的PLV矩阵并排放置,观察单个被试的极端值对整体结果的拉动,如果单个被试移除后整组显著性消失,就得回头检查该被试的数据质量或考虑离群点的影响。

5. 进一步扩展:从二元PLV到全脑连接分析

当分析对象不止一对电极时,PLV的计算很快就变成一个全连接矩阵的问题。对N个电极,最终得到N×N的对称矩阵,每个值是电极对之间的相位同步强度。随后可以在这个矩阵上计算图论指标,比如聚类系数、特征路径长度、节点度等,用于比较不同实验条件下的脑网络拓扑差异。

做全脑连接矩阵时需要注意不要走进相对较大的坑:矩阵节点之间的平均PLV受试次数影响是不均匀的。换句话说,试次数多的被试可能整体PLV偏低(因为估计更保守),试次数少的被试整体PLV虚高。如果试次数在不同被试间波动较大,需要在计算图论指标前对各被试的矩阵做标准化,比如除以该被试所有通道对PLV的均值,或者使用度矩阵的相对阈值。

这里我补充一个实操建议:在计算组平均连接矩阵时,先做个体水平z变换(Fisher z变换),再对z值做平均,组矩阵会更接近正态分布,后续使用的参数统计也更有依据。PLV的原始值范围是0到1,平均值之后仍然限于这个区间,但z变换能把数据映射到无界空间,更适合做线性模型的输入。

相位同步分析如果和事件相关电位结合,可以做出更细的结论。例如,在某个时间窗出现ERP成分,同时该时间窗的PLV升高,说明诱发电位和相位重置可能有关系。我经常把ERP波形和试次间PLV曲线画在一起,观察两者之间是否存在时程上的耦合。这种分析不需要额外统计模型,先用肉眼观察趋势,再有选择地假设检验。

此外,还可根据实际项目选择是否做多频带联合PLV分析。有些认知过程会在两个频带内同时产生同步,比如theta-gamma嵌套,此时可以计算跨频带PLV(交叉频率耦合的一种形式),它的相位差定义为低频相位与高频振幅包络相位的关系。这类分析比单频带PLV更进一步,代码上也不复杂,只是需要额外做一次包络提取,概念上容易绕晕。如果读者接触到了交叉频率耦合,建议先回到单频带PLV把流程跑通,再考虑扩展。

对于希望在脑机接口中应用PLV的同行,有一点要提醒:PLV计算对数据长度要求相对较高,单次试次数过少时估计很不稳定,而且计算全脑连接矩阵再提取特征,计算量也会成倍增加。BCI领域更常用的是锁相值在一段时间窗内的均值作为特征,再结合分类器选择最优通道对。这里的关键是做好特征的稳定性评估,不能只看分类准确率,还要看测试集和训练集上PLV特征分布的漂移情况。

我这几年做脑电数据分析,踩过最多的坑几乎都不是在算法本身,而是在数据预处理和参数选择这两个环节。PLV这个指标本身不算复杂,但它对输入数据的质量极其敏感。滤波边缘效应、参考方式、伪迹残留,任意一个环节稍微粗糙,得到的连接矩阵就不具备可解释性。现在的分析工具和库越来越强大,反而容易让人忽略每一个参数背后的数据含义。

最后分享一个个人习惯:每跑完一套PLV分析,我都会把所有中间过程重新可视化一遍——原信号、滤波后的信号、瞬时相位、相位差分布、最终PLV。虽然这样会多花不少时间,但能直观确认每一环节的合理性。如果哪一步看起来不对,马上回去查,而不是等组间统计结果出来再说。分析连接指标,本质上是在跟数据里的不确定性打交道,多一次确认,结果就多一分底气。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询