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], &current_epoch);
            
            // 预处理
            EEG_PreprocessPipeline(current_epoch.data, current_epoch.data);
            
            // 基线校正
            EEG_BaselineCorrection(&current_epoch, 0, 50);  // 前100ms
            
            // 伪迹拒绝
            if (EEG_ArtifactRejection(&current_epoch)) {
                // 特征提取
                EEG_ExtractP300Features(&current_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(&current_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. 鲁棒性提升

  • 多尺度检测:结合短时和长时特征
  • 自适应阈值:根据历史数据动态调整
  • 投票机制:多分类器融合决策
posted @ 2026-06-25 10:53  徐中翼  阅读(3)  评论(0)    收藏  举报