EEG 脑电信号预处理与单次提取系统
EEG 脑电信号预处理与单次提取 技术方案,涵盖信号预处理流水线、特征提取算法、单次 trial 检测、实时实现以及代码示例。适用于 BCI(脑机接口)、癫痫检测、睡眠分期、神经反馈 等应用场景。
一、系统总体架构
1. 系统流程图
┌─────────────────────────────────────────────────────────────────┐
│ EEG 单次提取系统架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 电极帽(32-64导) ──▶ 放大器(24位ADC) ──▶ 数据采集卡 ──▶ PC/嵌入式 │
│ │
│ 原始EEG (0.5-100Hz, 24bit) │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ 预处理流水线 │ │
│ │ 1. 去直流偏移 (DC Removal) │ │
│ │ 2. 工频陷波 (50/60Hz Notch) │ │
│ │ 3. 带通滤波 (0.5-50Hz) │ │
│ │ 4. 坏导插补 (Bad Channel Interpolation)│ │
│ │ 5. 独立成分分析 (ICA) 去眼电/肌电 │ │
│ │ 6. 重参考 (Average Reference) │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ 单次 Trial 提取 │ │
│ │ 1. 事件检测 (Trigger Detection) │ │
│ │ 2. 时间窗口截取 (Epoching) │ │
│ │ 3. 基线校正 (Baseline Correction) │ │
│ │ 4. 伪迹拒绝 (Artifact Rejection) │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ 特征提取与分类 │ │
│ │ 1. 时域特征 (均值、方差、峰度) │ │
│ │ 2. 频域特征 (PSD, 频段功率) │ │
│ │ 3. 时频特征 (小波、STFT) │ │
│ │ 4. 空间特征 (CSP, 共空间模式) │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 输出:分类结果 / 检测事件 / 控制信号 │
│ │
└─────────────────────────────────────────────────────────────────┘
二、EEG 信号特性
| 参数 | 数值 | 说明 |
|---|---|---|
| 采样率 | 250-1000 Hz | 常用 500Hz |
| 通道数 | 8-128 导 | 常用 32 导 |
| 幅值范围 | ±100 μV | 微伏级信号 |
| 主要频段 | δ: 0.5-4Hz, θ: 4-8Hz, α: 8-13Hz, β: 13-30Hz, γ: 30-50Hz | 神经振荡 |
| 阻抗要求 | < 5 kΩ | 保证信号质量 |
三、核心算法实现(C 语言)
1. 数据结构定义
/**
******************************************************************************
* @file eeg_processor.h
* @brief EEG信号处理头文件
******************************************************************************
*/
#ifndef __EEG_PROCESSOR_H
#define __EEG_PROCESSOR_H
#include <stdint.h>
#include <stddef.h>
#include <math.h>
// 系统配置
#define EEG_SAMPLE_RATE 500 // 采样率 (Hz)
#define EEG_CHANNEL_NUM 32 // 通道数
#define EEG_BUFFER_SIZE (EEG_SAMPLE_RATE * 4) // 4秒缓冲
#define EEG_FILTER_ORDER 4 // 滤波器阶数
#define EEG_EPOCH_LENGTH (EEG_SAMPLE_RATE * 1) // 1秒epoch
// 频段定义
typedef enum {
EEG_DELTA = 0, // 0.5-4 Hz
EEG_THETA, // 4-8 Hz
EEG_ALPHA, // 8-13 Hz
EEG_BETA, // 13-30 Hz
EEG_GAMMA // 30-50 Hz
} EEG_Band;
// 预处理配置
typedef struct {
float notch_freq; // 陷波频率 (50/60Hz)
float bandpass_low; // 带通低频
float bandpass_high; // 带通高频
float artifact_threshold; // 伪迹阈值 (μV)
uint8_t use_ica; // 是否使用ICA
uint8_t use_car; // 是否使用共平均参考
} EEG_PreprocessConfig;
// EEG数据缓冲区
typedef struct {
float buffer[EEG_CHANNEL_NUM][EEG_BUFFER_SIZE];
uint16_t write_index;
uint16_t read_index;
uint8_t is_full;
} EEG_Buffer;
// 单次Trial数据
typedef struct {
float data[EEG_CHANNEL_NUM][EEG_EPOCH_LENGTH];
uint32_t timestamp; // 时间戳
uint16_t trigger_code; // 触发码
uint8_t is_valid; // 是否有效
} EEG_Epoch;
// 特征向量
typedef struct {
float time_features[8]; // 时域特征
float freq_features[5][5]; // 频域特征 [通道][频段]
float spatial_features[8]; // 空间特征
uint8_t feature_length; // 特征长度
} EEG_Features;
// 滤波器状态
typedef struct {
float b_coeffs[EEG_FILTER_ORDER + 1];
float a_coeffs[EEG_FILTER_ORDER + 1];
float delay[EEG_CHANNEL_NUM][EEG_FILTER_ORDER];
} EEG_FilterState;
#endif /* __EEG_PROCESSOR_H */
2. 预处理核心算法
/**
******************************************************************************
* @file eeg_preprocessor.c
* @brief EEG信号预处理实现
******************************************************************************
*/
#include "eeg_processor.h"
// 全局变量
static EEG_Buffer eeg_buffer;
static EEG_FilterState notch_filter[EEG_CHANNEL_NUM];
static EEG_FilterState bandpass_filter[EEG_CHANNEL_NUM];
static EEG_PreprocessConfig preprocess_cfg = {
.notch_freq = 50.0f,
.bandpass_low = 0.5f,
.bandpass_high = 50.0f,
.artifact_threshold = 100.0f, // ±100μV
.use_ica = 1,
.use_car = 1
};
/**
* @brief 初始化EEG缓冲区
*/
void EEG_Buffer_Init(void) {
memset(&eeg_buffer, 0, sizeof(EEG_Buffer));
eeg_buffer.write_index = 0;
eeg_buffer.read_index = 0;
eeg_buffer.is_full = 0;
}
/**
* @brief 添加新样本到缓冲区
* @param channel_data: 单时间点多通道数据
*/
void EEG_AddSample(float channel_data[EEG_CHANNEL_NUM]) {
for (uint8_t ch = 0; ch < EEG_CHANNEL_NUM; ch++) {
eeg_buffer.buffer[ch][eeg_buffer.write_index] = channel_data[ch];
}
eeg_buffer.write_index++;
if (eeg_buffer.write_index >= EEG_BUFFER_SIZE) {
eeg_buffer.write_index = 0;
eeg_buffer.is_full = 1;
}
}
/**
* @brief 设计巴特沃斯带通滤波器
* @param filter: 滤波器状态
* @param low_cut: 低频截止
* @param high_cut: 高频截止
* @param sample_rate: 采样率
*/
void EEG_DesignBandpass(EEG_FilterState* filter,
float low_cut, float high_cut, float sample_rate) {
// 简化版二阶IIR滤波器设计
float Q = 0.707f; // 品质因数
float omega_low = 2.0f * PI * low_cut / sample_rate;
float omega_high = 2.0f * PI * high_cut / sample_rate;
// 低通部分
float alpha_lp = sinf(omega_low) / (2.0f * Q);
float cos_lp = cosf(omega_low);
float a0_lp = 1.0f + alpha_lp;
// 高通部分
float alpha_hp = sinf(omega_high) / (2.0f * Q);
float cos_hp = cosf(omega_high);
float a0_hp = 1.0f + alpha_hp;
// 组合系数(简化实现)
for (int i = 0; i <= EEG_FILTER_ORDER; i++) {
filter->b_coeffs[i] = 1.0f;
filter->a_coeffs[i] = 1.0f;
}
}
/**
* @brief 应用IIR滤波器
* @param filter: 滤波器状态
* @param input: 输入样本
* @return 滤波后输出
*/
float EEG_ApplyFilter(EEG_FilterState* filter, float input, uint8_t channel) {
float output = 0.0f;
// 直接形式II转置
output = filter->b_coeffs[0] * input + filter->delay[channel][0];
for (int i = 0; i < EEG_FILTER_ORDER - 1; i++) {
filter->delay[channel][i] = filter->b_coeffs[i+1] * input
- filter->a_coeffs[i+1] * output
+ filter->delay[channel][i+1];
}
filter->delay[channel][EEG_FILTER_ORDER-1] = filter->b_coeffs[EEG_FILTER_ORDER] * input
- filter->a_coeffs[EEG_FILTER_ORDER] * output;
return output;
}
/**
* @brief 工频陷波 (50/60Hz)
* @param input: 输入信号
* @param freq: 陷波频率
* @return 陷波后信号
*/
float EEG_NotchFilter(float input, float freq) {
static float delay[3] = {0};
float output;
float w0 = 2.0f * PI * freq / EEG_SAMPLE_RATE;
float r = 0.95f; // 极点半径
// 二阶陷波器
output = input - 2.0f * r * cosf(w0) * delay[0] + r * r * delay[1];
delay[1] = delay[0];
delay[0] = output;
return output;
}
/**
* @brief 去直流偏移
* @param data: 通道数据
* @param length: 数据长度
*/
void EEG_RemoveDC(float* data, uint16_t length) {
float mean = 0.0f;
// 计算均值
for (uint16_t i = 0; i < length; i++) {
mean += data[i];
}
mean /= length;
// 减去均值
for (uint16_t i = 0; i < length; i++) {
data[i] -= mean;
}
}
/**
* @brief 共平均参考 (Common Average Reference)
* @param data: 多通道数据 [通道][时间]
* @param channels: 通道数
* @param length: 数据长度
*/
void EEG_ApplyCAR(float data[EEG_CHANNEL_NUM][EEG_EPOCH_LENGTH],
uint8_t channels, uint16_t length) {
float mean[EEG_EPOCH_LENGTH];
// 计算每个时间点的平均参考
for (uint16_t t = 0; t < length; t++) {
mean[t] = 0.0f;
for (uint8_t ch = 0; ch < channels; ch++) {
mean[t] += data[ch][t];
}
mean[t] /= channels;
}
// 减去平均参考
for (uint8_t ch = 0; ch < channels; ch++) {
for (uint16_t t = 0; t < length; t++) {
data[ch][t] -= mean[t];
}
}
}
/**
* @brief 伪迹检测与拒绝
* @param epoch: 单次epoch数据
* @return 1=有效, 0=伪迹
*/
uint8_t EEG_ArtifactRejection(EEG_Epoch* epoch) {
float max_amplitude = 0.0f;
float gradient;
for (uint8_t ch = 0; ch < EEG_CHANNEL_NUM; ch++) {
for (uint16_t t = 1; t < EEG_EPOCH_LENGTH; t++) {
// 幅度检测
if (fabsf(epoch->data[ch][t]) > max_amplitude) {
max_amplitude = fabsf(epoch->data[ch][t]);
}
// 梯度检测(肌肉伪迹)
gradient = fabsf(epoch->data[ch][t] - epoch->data[ch][t-1]);
if (gradient > 50.0f) { // 50μV/采样点
return 0;
}
}
}
// 幅度阈值检测
if (max_amplitude > preprocess_cfg.artifact_threshold) {
return 0;
}
return 1;
}
/**
* @brief 完整预处理流水线
* @param raw_data: 原始EEG数据
* @param processed_data: 处理后数据
*/
void EEG_PreprocessPipeline(float raw_data[EEG_CHANNEL_NUM][EEG_EPOCH_LENGTH],
float processed_data[EEG_CHANNEL_NUM][EEG_EPOCH_LENGTH]) {
// 1. 复制原始数据
memcpy(processed_data, raw_data, sizeof(float) * EEG_CHANNEL_NUM * EEG_EPOCH_LENGTH);
// 2. 逐通道处理
for (uint8_t ch = 0; ch < EEG_CHANNEL_NUM; ch++) {
// 去直流
EEG_RemoveDC(processed_data[ch], EEG_EPOCH_LENGTH);
// 工频陷波
for (uint16_t t = 0; t < EEG_EPOCH_LENGTH; t++) {
processed_data[ch][t] = EEG_NotchFilter(processed_data[ch][t],
preprocess_cfg.notch_freq);
}
// 带通滤波
for (uint16_t t = 0; t < EEG_EPOCH_LENGTH; t++) {
processed_data[ch][t] = EEG_ApplyFilter(&bandpass_filter[ch],
processed_data[ch][t], ch);
}
}
// 3. 空间滤波(共平均参考)
if (preprocess_cfg.use_car) {
EEG_ApplyCAR(processed_data, EEG_CHANNEL_NUM, EEG_EPOCH_LENGTH);
}
}
3. 单次 Trial 提取
/**
******************************************************************************
* @file eeg_epoching.c
* @brief 单次Trial提取实现
******************************************************************************
*/
#include "eeg_processor.h"
// 触发检测状态
typedef struct {
uint8_t trigger_active;
uint16_t pre_samples;
uint16_t post_samples;
uint32_t last_trigger_time;
} TriggerState;
static TriggerState trigger_state = {0};
/**
* @brief 初始化Epoch提取
* @param pre_time: 触发前时间 (ms)
* @param post_time: 触发后时间 (ms)
*/
void EEG_Epoch_Init(uint16_t pre_time, uint16_t post_time) {
trigger_state.pre_samples = (pre_time * EEG_SAMPLE_RATE) / 1000;
trigger_state.post_samples = (post_time * EEG_SAMPLE_RATE) / 1000;
trigger_state.trigger_active = 0;
}
/**
* @brief 检测触发信号
* @param trigger_channel: 触发通道数据
* @param length: 数据长度
* @return 触发位置数组
*/
void EEG_DetectTriggers(float* trigger_channel, uint16_t length,
uint16_t* trigger_positions, uint8_t* count) {
*count = 0;
float threshold = 2.0f; // 触发阈值 (μV)
for (uint16_t i = 1; i < length; i++) {
// 上升沿检测
if (trigger_channel[i] > threshold && trigger_channel[i-1] <= threshold) {
if (*count < 100) { // 限制最大触发数
trigger_positions[(*count)++] = i;
}
}
}
}
/**
* @brief 提取单次Epoch
* @param buffer: EEG数据缓冲区
* @param trigger_pos: 触发位置
* @param epoch: 输出的epoch
*/
void EEG_ExtractEpoch(EEG_Buffer* buffer, uint16_t trigger_pos, EEG_Epoch* epoch) {
uint16_t start_idx = (trigger_pos >= trigger_state.pre_samples)
? trigger_pos - trigger_state.pre_samples
: 0;
uint16_t end_idx = start_idx + trigger_state.pre_samples + trigger_state.post_samples;
if (end_idx > EEG_BUFFER_SIZE) {
end_idx = EEG_BUFFER_SIZE;
}
// 提取数据
uint16_t epoch_idx = 0;
for (uint16_t buf_idx = start_idx; buf_idx < end_idx; buf_idx++) {
for (uint8_t ch = 0; ch < EEG_CHANNEL_NUM; ch++) {
epoch->data[ch][epoch_idx] = buffer->buffer[ch][buf_idx];
}
epoch_idx++;
}
epoch->timestamp = trigger_pos;
epoch->is_valid = 1;
}
/**
* @brief 基线校正
* @param epoch: Epoch数据
* @param baseline_start: 基线开始 (样本)
* @param baseline_end: 基线结束 (样本)
*/
void EEG_BaselineCorrection(EEG_Epoch* epoch, uint16_t baseline_start, uint16_t baseline_end) {
float baseline_mean[EEG_CHANNEL_NUM];
// 计算基线均值
for (uint8_t ch = 0; ch < EEG_CHANNEL_NUM; ch++) {
baseline_mean[ch] = 0.0f;
for (uint16_t t = baseline_start; t < baseline_end; t++) {
baseline_mean[ch] += epoch->data[ch][t];
}
baseline_mean[ch] /= (baseline_end - baseline_start);
}
// 减去基线
for (uint8_t ch = 0; ch < EEG_CHANNEL_NUM; ch++) {
for (uint16_t t = 0; t < EEG_EPOCH_LENGTH; t++) {
epoch->data[ch][t] -= baseline_mean[ch];
}
}
}
4. 特征提取(P300/运动想象)
/**
******************************************************************************
* @file eeg_features.c
* @brief EEG特征提取实现
******************************************************************************
*/
#include "eeg_processor.h"
/**
* @brief 计算频带功率 (PSD)
* @param data: 单通道数据
* @param length: 数据长度
* @param band: 频段
* @return 频段功率
*/
float EEG_BandPower(float* data, uint16_t length, EEG_Band band) {
float power = 0.0f;
float freq_res = (float)EEG_SAMPLE_RATE / length;
// 简化的功率谱估计(使用Welch方法)
uint16_t segment_length = 128;
uint16_t overlap = 64;
uint16_t num_segments = (length - overlap) / (segment_length - overlap);
for (uint16_t seg = 0; seg < num_segments; seg++) {
uint16_t start = seg * (segment_length - overlap);
// 应用汉宁窗
float windowed_data[128];
for (uint16_t i = 0; i < segment_length; i++) {
float window = 0.5f * (1.0f - cosf(2.0f * PI * i / (segment_length - 1)));
windowed_data[i] = data[start + i] * window;
}
// 计算FFT功率(简化)
for (uint16_t bin = 0; bin < segment_length/2; bin++) {
float freq = bin * freq_res;
if ((band == EEG_DELTA && freq >= 0.5f && freq < 4.0f) ||
(band == EEG_THETA && freq >= 4.0f && freq < 8.0f) ||
(band == EEG_ALPHA && freq >= 8.0f && freq < 13.0f) ||
(band == EEG_BETA && freq >= 13.0f && freq < 30.0f) ||
(band == EEG_GAMMA && freq >= 30.0f && freq < 50.0f)) {
power += windowed_data[bin] * windowed_data[bin];
}
}
}
return power / num_segments;
}
/**
* @brief 提取P300特征
* @param epoch: Epoch数据
* @param features: 输出特征
*/
void EEG_ExtractP300Features(EEG_Epoch* epoch, EEG_Features* features) {
uint8_t p300_channels[] = {10, 11, 12, 13, 14}; // Pz, Cz, Fz等
uint16_t p300_start = 250 * EEG_SAMPLE_RATE / 1000; // 250ms
uint16_t p300_end = 500 * EEG_SAMPLE_RATE / 1000; // 500ms
features->feature_length = 0;
// 提取P300时间窗内的平均幅值
for (int i = 0; i < 5; i++) {
uint8_t ch = p300_channels[i];
float sum = 0.0f;
uint16_t count = 0;
for (uint16_t t = p300_start; t < p300_end; t++) {
sum += epoch->data[ch][t];
count++;
}
features->time_features[i] = sum / count;
features->feature_length++;
}
// 提取各频段功率
for (int ch_idx = 0; ch_idx < 5; ch_idx++) {
uint8_t ch = p300_channels[ch_idx];
for (EEG_Band band = EEG_DELTA; band <= EEG_GAMMA; band++) {
features->freq_features[ch_idx][band] =
EEG_BandPower(epoch->data[ch], EEG_EPOCH_LENGTH, band);
}
}
}
/**
* @brief 共空间模式 (CSP) 特征提取
* @param epoch1: 类别1数据
* @param epoch2: 类别2数据
* @param features: 输出特征
*/
void EEG_ExtractCSPFeatures(EEG_Epoch* epoch1, EEG_Epoch* epoch2, EEG_Features* features) {
// CSP算法简化实现
// 1. 计算两类数据的协方差矩阵
// 2. 求解广义特征值问题
// 3. 提取投影特征
// 这里简化为提取左右运动皮层的α节律功率差
uint8_t left_channels[] = {3, 4}; // C3, CP3
uint8_t right_channels[] = {5, 6}; // C4, CP4
float left_alpha_power = 0.0f;
float right_alpha_power = 0.0f;
for (int i = 0; i < 2; i++) {
left_alpha_power += EEG_BandPower(epoch1->data[left_channels[i]],
EEG_EPOCH_LENGTH, EEG_ALPHA);
right_alpha_power += EEG_BandPower(epoch1->data[right_channels[i]],
EEG_EPOCH_LENGTH, EEG_ALPHA);
}
// CSP特征:左右功率比
features->spatial_features[0] = left_alpha_power / right_alpha_power;
features->spatial_features[1] = right_alpha_power / left_alpha_power;
features->feature_length = 2;
}
5. 实时处理主循环
/**
******************************************************************************
* @file main.c
* @brief EEG实时处理主程序
******************************************************************************
*/
#include "eeg_processor.h"
#include <stdio.h>
// 全局变量
static EEG_Epoch current_epoch;
static EEG_Features extracted_features;
static uint8_t system_running = 0;
int main(void) {
// 系统初始化
EEG_Buffer_Init();
EEG_Epoch_Init(200, 800); // 200ms前,800ms后
// 初始化滤波器
for (uint8_t ch = 0; ch < EEG_CHANNEL_NUM; ch++) {
EEG_DesignBandpass(&bandpass_filter[ch],
preprocess_cfg.bandpass_low,
preprocess_cfg.bandpass_high,
EEG_SAMPLE_RATE);
}
printf("EEG处理系统启动...\n");
system_running = 1;
// 主循环
while (system_running) {
// 1. 读取新数据(从ADC或文件)
float new_sample[EEG_CHANNEL_NUM];
if (EEG_GetNewSample(new_sample)) {
EEG_AddSample(new_sample);
}
// 2. 检测触发
uint16_t trigger_positions[10];
uint8_t trigger_count;
EEG_DetectTriggers(eeg_buffer.buffer[0], EEG_BUFFER_SIZE,
trigger_positions, &trigger_count);
// 3. 处理每个触发
for (uint8_t i = 0; i < trigger_count; i++) {
// 提取epoch
EEG_ExtractEpoch(&eeg_buffer, trigger_positions[i], ¤t_epoch);
// 预处理
EEG_PreprocessPipeline(current_epoch.data, current_epoch.data);
// 基线校正
EEG_BaselineCorrection(¤t_epoch, 0, 50); // 前100ms
// 伪迹拒绝
if (EEG_ArtifactRejection(¤t_epoch)) {
// 特征提取
EEG_ExtractP300Features(¤t_epoch, &extracted_features);
// 分类决策
float decision = EEG_Classify(&extracted_features);
printf("检测到P300,决策值: %.2f\n", decision);
}
}
// 4. 更新显示
EEG_UpdateDisplay();
// 5. 延时
Delay_ms(10);
}
return 0;
}
参考代码 用于EEG脑电信号预处理和单次提取 www.youwenfan.com/contentcnw/112977.html
四、Python 验证脚本
"""
EEG预处理与单次提取验证脚本
用于验证C语言算法的正确性
"""
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
class EEGProcessor:
def __init__(self, fs=500, n_channels=32):
self.fs = fs
self.n_channels = n_channels
def generate_test_eeg(self, duration=10):
"""生成测试EEG信号(含P300)"""
t = np.linspace(0, duration, duration * self.fs)
eeg = np.zeros((self.n_channels, len(t)))
# 背景α节律 (10Hz)
for ch in range(self.n_channels):
eeg[ch] = 5 * np.sin(2 * np.pi * 10 * t) + np.random.randn(len(t)) * 2
# 添加P300 (300ms处,Pz通道)
p300_ch = 10 # Pz通道
p300_time = int(0.3 * self.fs)
p300_wave = 10 * np.exp(-np.square(np.arange(-50, 51) / 20))
eeg[p300_ch, p300_time:p300_time+101] += p300_wave
return eeg, t
def preprocess(self, eeg):
"""预处理流水线"""
# 1. 去直流
eeg = eeg - np.mean(eeg, axis=1, keepdims=True)
# 2. 50Hz陷波
b, a = signal.iirnotch(50, 30, self.fs)
eeg = signal.filtfilt(b, a, eeg, axis=1)
# 3. 0.5-50Hz带通
b, a = signal.butter(4, [0.5, 50], 'bandpass', fs=self.fs)
eeg = signal.filtfilt(b, a, eeg, axis=1)
# 4. 共平均参考
car = np.mean(eeg, axis=0, keepdims=True)
eeg = eeg - car
return eeg
def extract_epochs(self, eeg, triggers, pre=200, post=800):
"""提取单次epoch"""
epochs = []
pre_samples = int(pre * self.fs / 1000)
post_samples = int(post * self.fs / 1000)
for trig in triggers:
start = trig - pre_samples
end = trig + post_samples
if start >= 0 and end < eeg.shape[1]:
epoch = eeg[:, start:end]
epochs.append(epoch)
return np.array(epochs)
def extract_p300_features(self, epoch):
"""提取P300特征"""
# Pz通道,300-500ms时间窗
pz_ch = 10
start = int(0.3 * self.fs)
end = int(0.5 * self.fs)
# 平均幅值
feature = np.mean(epoch[pz_ch, start:end])
# α功率比
freqs, psd = signal.welch(epoch[pz_ch], self.fs, nperseg=128)
alpha_power = np.mean(psd[(freqs >= 8) & (freqs <= 13)])
return np.array([feature, alpha_power])
# 测试
if __name__ == "__main__":
processor = EEGProcessor(fs=500)
# 生成测试数据
eeg, t = processor.generate_test_eeg(duration=10)
# 预处理
eeg_clean = processor.preprocess(eeg)
# 检测触发(模拟)
triggers = [int(2.0 * processor.fs), int(5.0 * processor.fs)]
# 提取epoch
epochs = processor.extract_epochs(eeg_clean, triggers)
print(f"提取到 {len(epochs)} 个epochs")
print(f"Epoch形状: {epochs[0].shape}")
# 提取特征
features = processor.extract_p300_features(epochs[0])
print(f"P300特征: {features}")
# 可视化
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t[:1000], eeg[10, :1000])
plt.title("原始EEG (Pz通道)")
plt.xlabel("时间 (s)")
plt.ylabel("幅值 (μV)")
plt.subplot(2, 1, 2)
plt.plot(epochs[0][10, :200])
plt.title("P300 Epoch")
plt.xlabel("采样点")
plt.ylabel("幅值 (μV)")
plt.tight_layout()
plt.show()
五、实时系统部署
1. 嵌入式平台(STM32/FPGA)
// STM32实时处理配置
#define EEG_RT_THREAD_STACK_SIZE 1024
#define EEG_RT_THREAD_PRIORITY 3
// RT-Thread任务
void eeg_process_thread_entry(void* parameter) {
while (1) {
// 1. ADC采样
if (adc_dma_complete) {
// 2. 预处理
EEG_PreprocessPipeline(adc_buffer, processed_buffer);
// 3. 触发检测
if (detect_trigger(processed_buffer)) {
// 4. 特征提取
EEG_ExtractP300Features(¤t_epoch, &features);
// 5. 分类决策
decision = classify(&features);
// 6. 输出控制
output_control(decision);
}
}
rt_thread_delay(1); // 1ms延时
}
}
2. LabVIEW 集成
┌─────────────────────────────────────────────┐
│ LabVIEW EEG处理VI │
├─────────────────────────────────────────────┤
│ │
│ [DAQmx Read] ──▶ [预处理子VI] ──▶ [特征提取] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [触发检测] ──▶ [Epoch提取] ──▶ [分类决策] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [波形显示] ──▶ [频谱显示] ──▶ [结果输出] │
│ │
└─────────────────────────────────────────────┘
六、性能评估指标
| 指标 | 计算公式 | 目标值 |
|---|---|---|
| 分类准确率 | (TP+TN)/(TP+TN+FP+FN) | >85% |
| 假阳性率 | FP/(FP+TN) | <5% |
| 检测延迟 | 触发到输出时间 | <300ms |
| 信噪比改善 | SNR_out/SNR_in | >3dB |
| 特征稳定性 | 特征方差/均值 | <0.1 |
七、项目文件结构
EEG_SingleTrial_Extraction/
├── firmware/
│ ├── inc/
│ │ ├── eeg_processor.h
│ │ ├── eeg_preprocessor.h
│ │ ├── eeg_epoching.h
│ │ └── eeg_features.h
│ ├── src/
│ │ ├── eeg_preprocessor.c
│ │ ├── eeg_epoching.c
│ │ ├── eeg_features.c
│ │ └── main.c
│ └── stm32_project/
│ └── EEG_Processor.ioc
├── python/
│ ├── test_pipeline.py
│ ├── p300_detector.py
│ ├── mi_classifier.py
│ └── visualization.py
├── labview/
│ ├── EEG_Main.vi
│ ├── Preprocessing.vi
│ ├── FeatureExtraction.vi
│ └── Classification.vi
├── docs/
│ ├── Algorithm_Design.pdf
│ ├── API_Reference.md
│ └── Deployment_Guide.pdf
└── README.md
八、关键优化建议
1. 算法优化
- 定点运算:将float转为Q格式定点数,提升嵌入式性能
- 查表法:预计算sin/cos/exp等函数表
- SIMD指令:使用ARM NEON指令集加速
2. 实时性优化
- 双缓冲机制:DMA传输与处理并行
- 中断优先级:ADC中断 > 处理中断 > 通信中断
- 内存池:预分配内存,避免动态分配
3. 鲁棒性提升
- 多尺度检测:结合短时和长时特征
- 自适应阈值:根据历史数据动态调整
- 投票机制:多分类器融合决策

浙公网安备 33010602011771号