本目录实现的是一个用于稳态视觉诱发电位(SSVEP, Steady-State Visual Evoked Potential)的目标频率识别程序。算法输入 EEG 脑电信号,输出每个 taskID 对应的刺激类别 stimID,取值范围为 0-7,对应刺激频率 [8, 9, 10, 11, 12, 13, 14, 15] Hz。
ssvepdetect.py:核心识别算法,包含滤波、参考模板构造、CCA/FBCCA 计算和分类逻辑。demo.py:数据读取、按taskID分组、调用识别器预测、生成结果文件。FinalResults/:整理后的最终预测结果。FinalResults.zip:最终结果压缩包。
- Python 3.11
- NumPy:矩阵运算、数组处理、正余弦模板生成。
- SciPy Signal:50Hz 陷波滤波、椭圆带通滤波、零相位滤波
filtfilt。 - scikit-learn:使用
sklearn.cross_decomposition.CCA做典型相关分析。 - CSV 标准库:读取 EEG 数据、写入预测结果。
- pathlib / re / sys:路径解析、文件批处理、命令行参数处理。
输入 CSV 文件包含 8 列:
CP3, CPZ, CP4, PO3, POZ, PO4, taskID, stimID
说明:
- 前 6 列是 EEG 通道数据。
taskID是任务编号,正式数据中为0-47,一共 48 个任务。stimID是目标类别。示例数据中是真实标签;正式数据中为-1,表示待预测答案。
程序不会把正式数据中的 stimID=-1 当作标签参与计算,也不会用它计算正确率。
算法主体是 CCA/FBCCA 类型的 SSVEP 识别方法。
整体流程:
EEG数据
-> 按 taskID 分组
-> 取 6 个脑电通道
-> 预处理滤波
-> 构造每个刺激频率的正余弦谐波参考模板
-> 计算 EEG 与每个频率模板的 CCA 相关系数
-> 多频带加权融合
-> 选择得分最高的频率类别作为预测 stimID
正式数据不能按固定行数简单切片,因为不同任务文件的采样长度不同:
S1-S6:每个taskID有 750 个采样点,约 3 秒。S7-S12:每个taskID有 250 个采样点,约 1 秒。
因此 demo.py 中使用 taskID 分组:
task_data = data[task_ids == task_id]
epoch = task_data[:, :6].transpose()这样可以保证每个 taskID=0..47 都单独预测一次。
对于每个刺激频率 f,构造正弦和余弦参考信号:
sin(2πfht), cos(2πfht)
其中:
f是刺激频率。h是谐波阶数。t是采样时间点。
完整 4 秒数据使用 5 阶谐波;短窗口正式数据使用 3 阶谐波。
预处理包含:
- 50Hz 工频陷波:去除电源干扰。
- 椭圆带通滤波:保留 SSVEP 相关频段。
filtfilt零相位滤波:避免普通滤波带来的相位偏移。
滤波器组使用 5 个子频带:
8-90 Hz
16-90 Hz
24-90 Hz
32-90 Hz
40-90 Hz
程序不是只在一个频带上做 CCA,而是使用 Filter Bank CCA(FBCCA)。
每个子频带都会计算一次 EEG 与模板的 CCA 相关系数 rho,然后进行加权融合:
score = Σ weight(m) * rho(m)^2
权重为:
weight(m) = m^(-1.25) + 0.25
最后选择 score 最大的频率索引作为预测类别。
正式数据比示例数据短。为了提高短数据的判断准确率,算法对不同长度自动选择配置:
-
当采样点数等于完整窗口 1000 点时:
- 使用全部 6 个通道:
CP3, CPZ, CP4, PO3, POZ, PO4 - 使用 5 阶谐波
- 使用全部 6 个通道:
-
当采样点数小于 1000 点时:
- 只使用枕区通道:
PO3, POZ, PO4 - 使用 3 阶谐波
- 只使用枕区通道:
这样做的原因是 SSVEP 主要出现在视觉皮层附近,枕区通道通常信噪比更高。短窗口数据更容易被其他通道噪声干扰,因此短窗口采用枕区通道能提高稳定性。
在 Demo 目录或上级目录运行:
C:/Python311/python.exe e:/Code/BCI-robot/脑机算法竞赛专用U盘资料/Demo/demo.py默认处理:
数据C1/Task1/S1.csv
也可以指定单个文件:
C:/Python311/python.exe e:/Code/BCI-robot/脑机算法竞赛专用U盘资料/Demo/demo.py S7.csv也可以指定整个正式数据目录进行批量处理:
C:/Python311/python.exe e:/Code/BCI-robot/脑机算法竞赛专用U盘资料/Demo/demo.py 数据C1单文件运行时:
result.csv:最近一次单文件预测结果,容易被覆盖。S*_pred.csv:将原始数据最后一列stimID回填为预测值后的完整数据。
批量运行时:
result_S1.csv到result_S12.csv:每个正式文件单独对应的 48 个预测值。result_all.csv:12 个正式文件的汇总结果,共12 × 48 = 576条。S1_pred.csv到S12_pred.csv:每个正式文件回填stimID后的完整数据。
整理后的最终文件位于:
FinalResults/
其中:
FinalResults/result_all.csv:总预测表。FinalResults/by_file_results/:每个文件单独的结果表。FinalResults/filled_data/:回填答案后的完整 CSV。
在带真实标签的示例数据上验证:
完整 1000 点窗口:
D1.csv 48/48
D2.csv 48/48
总计 96/96 = 100%
模拟正式短窗口时:
750 点窗口:
94/96 = 97.92%
250 点窗口:
80/96 = 83.33%
说明:
- 示例数据有真实标签,因此可以计算准确率。
- 正式数据的
stimID全部为-1,没有真实标签,因此不能计算真实提交准确率。 - 当前短窗口策略是在示例数据裁剪模拟中验证后采用的,用于提高正式短数据的预测稳定性。
- 不要用正式数据中的
stimID=-1计算准确率。 - 正式数据必须按
taskID分组预测,不能按固定 1000 行切片。 result.csv是临时文件,最终结果应优先使用FinalResults/中整理好的文件。- 如果重新运行
demo.py,部分结果文件可能被覆盖;提交前建议重新检查FinalResults/README.txt和result_all.csv。