Python-For-EEG基础代码讲解(1)

news2024/11/27 16:38:23

Python-For-EEG

我要演示脑电图信号的基本分析。

主题

1、基于时域分析,P300信号数据集

  1. Event-related potentials and 1-dimensional convolution(ERP,CNN)
  2. Long short-term memory(LSTM)

2、基于频域分析,DEAP和SSVEP数据集

  1. Spectral analysis and alpha asymmetry
  2. Canonical correlation analysis(CCA)

3、基于成分分析,运动想象数据集

  1. Event-related desynchronization(ERD)

数据集

所有数据集准备好

1. P300数据集
这是我个人的P300信号,我通过我的OpenBCI耳机在视觉上关注36个字母顺序的目标时获得的。当闪光灯在我所看的目标上闪烁时,在刺激开始后300ms会有一个信号上升。在数据集中,列是时间戳(128 samples per second), 16 channels of ‘Fp1’, ‘Fp2’, ‘F7’, ‘F3’, ‘F4’, ‘F8’, ‘C3’, ‘Cz’, ‘C4’, ‘T5’, ‘P3’, ‘P4’, ‘T6’, ‘POz’, ‘O1’, ‘O2’, 标记表示事件。标记格式将在笔记本中详细说明。

文件:p300-6trials-12rep-chaky.csv

2、DEAP和SSVEP数据集
ssvep数据集

在这里,我们记录了用户分别观看以6,10和15Hz闪烁的三个不同的圆圈。我们将使用滤波器组典型相关分析对信号进行分类。
文件:ssvep-10trials-3s-chaky-bigsquare.csv

DEAP 数据集

它基本上是一个数据集,关于参与者观看一些1分钟的情感视频,同时佩戴32个EEG通道。欲了解更多详情,请访问https://www.eecs.qmul.ac.uk/mmv/datasets/deap/

经过处理python版本DEAP数据

3、运动想象数据集

在这里,我们记录一个用户做想象中的左右运动。我们将探索与事件相关的去同步以解码类。

这里我们将演示处理脑电图信号的基本过程。为了简单起见,我们将处理一个相当简单的P300数据集。

我们还将访问事件相关电位和长短期记忆来解码信号。
注意:我们假设你对神经网络非常熟悉,所以我们将主要使用它,而不会有太多杂乱的解释。

导入基础包

import mne
from mne import create_info
from mne.io import RawArray

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, WeightedRandomSampler

cuda加速

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

加载数据

df = pd.read_csv("../data/p300-6trials-12rep-chaky.csv")
df.head()
#we don't need timestamps for modeling
df = df.drop(["timestamps"], axis=1)
df.columns = ['P4', 'Pz', 'P3', 'PO4', 'POz', 'PO3', 'O2', 'O1', 'Marker']   #channels named according to how we plug our eeg device
df.head()

让我们看看这个标记是如何生成的。格式如下:

  • 0:不发生任何事情
    — 1:表示非目标闪烁
  • 2:闪光到目标
print(df['Marker'].unique())

基础背景

如果你对数据不了解,首先,你需要了解脑电图实验。

在类似脑电图的实验中,你通常有一个会话(session)。(a record)

您通常拥有的数据以(通道,样本)(channels, samples)的形式存在。

例如,如果你用16个通道记录脑电图,采样率为128赫兹,5秒长,那么你最终会得到一个(16,128 x 5)的会话,因为1秒将有128个样本,即根据定义。

我们记录的一个附加通道是“marker”。

“marker”是一种记录中的映射器,用于以后识别某些事情发生的时间。

具有3个EEG通道+标记的数据可能看起来像这样

[
 .
 .
 .
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 1], <----- Some event1, like flashes or images happen here:
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 2], <----- Some event2 again but another target happen here:
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 [eeg_1, eeg_2, eeg_3, 0],
 .
 .
 .
]

因此,我们感兴趣的是在事件显示一段时间后(可能在event1显示后3秒)检索所有样本,这个过程称为“epoching”。

数据转换为原始MNE对象

First we gonna use Python MNE as it provides many useful methods for achieving these tasks. So first, we gonna transform our pandas to mne type. Here is the function transforming df to raw mne.
首先,我们将使用Python MNE库,因为它为实现这些任务提供了许多有用的方法。首先,我们要把 pandas类型 数据 转换成 mne 类型。这是将df转换成raw的函数。

raw = df_to_raw(df)

以下是一些关于我的数据结构的简短总结:
https://mne.tools/stable/most_used_classes.html

  1. MNE.io.Raw
  • MNE.io.Raw 是你的整个session。在这个类中,您可以为整个session执行预处理,如’ filter '。
  1. MNE.Epochs
  • epoch是一个将整个session分割为较小窗口的方法。你可以按你喜欢的方式来epoching你的session。最常见的epoch是遵循marker/event通道

3.MNE.Evoked

  • Evoked是你从每个epochs得到的数据。你可以把epochs想象成 一系列的Evoked。

伪影移除

伪影是需要消除的噪音。频率受限伪影的两个例子是缓慢漂移和电源线噪声。下面我们将说明如何通过过滤来修复这些缺陷。

def df_to_raw(df):
    sfreq = 125  #our OpenBCI headset sampling rate
    ch_names = list(df.columns)
    ch_types = ['eeg'] * (len(df.columns) - 1) + ['stim']
    ten_twenty_montage = mne.channels.make_standard_montage('standard_1020')

    df = df.T  #mne looks at the tranpose() format
    df[:-1] *= 1e-6  #convert from uVolts to Volts (mne assumes Volts data)

    info = create_info(ch_names=ch_names, ch_types=ch_types, sfreq=sfreq)

    raw = mne.io.RawArray(df, info)
    raw.set_montage(ten_twenty_montage)

    #try plotting the raw data of its power spectral density
    raw.compute_psd().plot()

    return raw

电源噪声

电源噪声是由电网产生的噪声。它由50Hz(或60Hz,取决于你的地理位置)的尖峰组成。一些峰值也可能出现在谐波频率,即电力线频率的整数倍,例如100Hz, 150Hz,…(或120Hz, 180Hz,…)。

去除220V交流电50Hz电源噪声。我们还将去除它的谐波,即100Hz, 150Hz等。由于我们的信号是62.5Hz(根据奈奎斯特定理是125Hz / 2),我们不需要运行谐波,而只需截取50Hz信号。

raw.notch_filter(50) #250/2 based on Nyquist Theorem

设置从49 - 51赫兹的带阻滤波器

FIR滤波器参数

设计一种单通、零相位、无因果带阻滤波器
-有窗时域设计(firwin)方法
-汉明窗口0.0194通带纹波和53 dB阻带衰减
—下带边缘:49.38
-低转换带宽:0.50 Hz (- 6db截止频率:49.12 Hz)
—上通带边缘:50.62 Hz
—上转换带宽:0.50 Hz (- 6db截止频率:50.88 Hz)
-过滤器长度:825个样本(6.600秒)

#可以看到50Hz噪声被移除了, yay!
raw.compute_psd().plot()

漂移移除

低频漂移通常在1Hz以下。此外,由于P300,可以安全地假设没有有用的数据超过40Hz。

raw.filter(1, 40)
raw.compute_psd().plot();

过滤1个连续段的原始数据
设置从1 - 40赫兹的带通滤波器

FIR滤波器参数

设计一种单通、零相位、非因果带通滤波器
-有窗时域设计(firwin)方法
-汉明窗口0.0194通带纹波和53 dB阻带衰减
—下通带边缘:1.00
-低转换带宽:1.00 Hz (- 6db截止频率:0.50 Hz)
—上通带边缘:40.00 Hz
—转换带宽上限:10.00 Hz (- 6db截止频率:45.00 Hz)
-过滤器长度:413个样本(3.304秒)

Epoching

epoch是在事件发生时只提取相关脑电数据的过程。在这里,我们将在事件开始前-0.1秒提取到事件开始后0.6秒。这里我们选择0.6秒,因为我们知道P300发生在300毫秒左右,所以它是一个很好的中间值。

from mne import Epochs, find_events

def getEpochs(raw, event_id, tmin, tmax, picks):

    #epoching
    events = find_events(raw)
    epochs = Epochs(raw, events=events, event_id=event_id, 
                    tmin=tmin, tmax=tmax, baseline=None, preload=True,verbose=False, picks=picks)  #8 channels
    print('sample drop %: ', (1 - len(epochs.events)/len(events)) * 100)

    return epochs
    
#this one requires expertise to specify the right tmin, tmax
event_id = {'Non-Target': 1, 'Target' : 2}
tmin = -0.1
tmax = 0.6
eeg_channels = mne.pick_types(raw.info, eeg=True)
picks= eeg_channels
epochs = getEpochs(raw, event_id, tmin, tmax, picks)   
    

今天先到这,下一集继续讲!好的话给个赞,所有资料在这里

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/607834.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode_双指针_中等_82.删除排序链表中的重复元素 II

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回已排序的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&…

oracle19c SYSAUX表空间使用率高

今早手机收到一个信息&#xff0c;某客户的19c环境sysaux使用率超过了80%告警了。既然有事了还是需要登录查看下的 SYS > SET LINES 120 pagesize 199; SYS > COL OCCUPANT_NAME FORMAT A30; SYS > SELECT * FROM (SELECT OCCUPANT_NAME,SPACE_USAGE_KBYTES FROM V$S…

【逆向基础】JS逆向入门:小白也可以看懂

文章目录 前言一、接口抓包二、逆向分析3. 接口验证总结 前言 出于对数据安全的考虑&#xff0c;现代化的网站/APP通常会对数据接口做加密处理。而分析这些接口的加密算法并实现模拟调用的过程就叫做「逆向」。逆向对于爬虫工程师来说是一个永远绕不开的话题&#xff0c;也逐渐…

《嵌入式存储器架构、电路与应用》----学习记录(四)

第5章 新型嵌入式存储器 在现有主流嵌入式存储器中&#xff0c;SRAM虽然读写速度非常快&#xff0c;但是单元面积太大&#xff0c;无法在片上实现高密度集成&#xff1b;DRAM由于要制造电容&#xff0c;所采用的工艺无法在先进的CMOS工艺中实现&#xff0c;不利于做嵌入式存储…

六一专辑||C++实现动态烟花代码

首先&#xff0c;祝大家儿童节快乐&#xff01; 在这篇文章中&#xff0c;将用烟花致以大家最好的祝福&#xff01; 烟花代码将会用到 Easyx 图形库&#xff0c;可以去官网下载&#xff1a;easyx.cnhttp://easyx.cn/ 代码思路 1 烟花结构体 2 初始化烟花 3 烟花上升 4 烟…

设置主机名和host映射

这里写目录标题 设置主机名设置host映射主机名解析过程分析 设置主机名 为了方便记忆。可以给linux系统主机名&#xff0c;也可以根据需要修改主机名 指令hostname来查看主机名 修改主机名 vim /etc/hostname 进入之后修改就行 修改之后重启生效 设置host映射 如何通过主机…

分布式锁实现原理

为什么需要分布式锁&#xff1f; 本地锁synchronized只能锁住当前服务进程&#xff0c;一个本地锁只能锁一个服务&#xff0c;如果是分布式服务情况下使用本地锁&#xff0c;那么多少服务就会有多少进程同时执行&#xff0c;就是去了锁的效果&#xff0c;为了到达分布式情况下…

3.9 流水作业调度问题

博主简介&#xff1a;一个爱打游戏的计算机专业学生博主主页&#xff1a; 夏驰和徐策所属专栏&#xff1a;算法设计与分析 1.我对流水调度问题的理解 流水作业调度问题是动态规划中的一个经典问题&#xff0c;它涉及将一系列作业分配给多个工作站以最小化总完成时间。该问题的…

go test 包外测试

之前文章有介绍过 go test coverage 单测覆盖率 和Go test基础用法&#xff0c;今天这里主要介绍 go 单测中比较特殊的一种场景&#xff1a;包外测试。初次看到这个名字&#xff0c;我还以为就是单独创建一个新目录&#xff0c;所有的单测用例统一都汇总到这个目录下&#xff0…

【P48】JMeter 断言持续时间(Duration Assertion)

文章目录 一、断言持续时间&#xff08;Duration Assertion&#xff09;参数说明二、测试计划设计 一、断言持续时间&#xff08;Duration Assertion&#xff09;参数说明 可以控制取样器的执行是否超过某个时间&#xff0c;如果超时则报错&#xff0c;持续时间断言器也叫超时…

21天学会C++:Day6----内联函数

CSDN的uu们&#xff0c;大家好。这里是C入门的第六讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 知识引入 2. 知识点讲解 2.1 内联函数的使用 2.2 内联函数的特性 2.2 …

强大Excel 插件 Zbrainsoft Dose for Excel 3.6.2 Crack

强大的 Excel 插件 Zbrainsoft Dose for Excel 3.6.2 如果您厌倦了在Excel中消除重复的行&#xff0c;比较工作表或执行困难的活动&#xff0c;那么Dose for Excel是您需要的强大便捷解决方案&#xff0c;只需单击几下即可将所有这些复杂的杂务简化。它具有 100 多个强大的新功…

pytorch实战 -- 自动微分

autograd——自动求导系统 import torch torch.manual_seed(7) <torch._C.Generator at 0x7f3c1f9e0490> torch.autograd.backward(tensors, grad_tensorsNone, retain_graphNone, create_graphFalse) 功能&#xff1a;自动求取梯度 tensors&#xff1a;用于求导的张量&…

axios-CancelToken方法取消请求-控制多次同样api调用取消上一次接口调用

前言 开发当中看到了axios取消方法&#xff0c;经过查阅&#xff0c;axios这个包是提供了取消请求的方法的。 移动端当是tab栏类的页面&#xff0c;或者是下拉刷新和上拉加载是一个接口是&#xff0c;会出现20条情况&#xff08;接口调用2次&#xff09;。 pc端同一个按钮&am…

【欢迎您,xxx--JavaScript】

login.html <body><form action"index.html">用户名&#xff1a;<input type"text" name"usname"><input type"submit" value"登录"></form> </body> index.html <body><di…

BERT在GLUE数据集构建任务

0 Introduction 谷歌开源的BERT项目在Github上&#xff0c;视频讲解可以参考B站上的一个视频 1 GLUE部分基准数据集介绍 GLUE数据集官网GLUE数据集下载&#xff0c;建议下载运行这个download_glue_data.py文件进行数据集的下载&#xff0c;如果链接无法打开&#xff0c;运行…

七、Gitee码云的注册及使用(二)

1、创建远程仓库 (1)登录Gitee.com&#xff0c;点击右上角 号&#xff0c;再点击新建仓库。 (2)填写仓库名称&#xff0c;路径&#xff0c;仓库介绍 (3)选择是否开源 (4)初始化仓库 开源许可证&#xff1a;主要包括开源是否可以随意转载&#xff0c;开源但不能商业使用&…

yolov8改进大作战,开箱即用,提供yolov8魔术师专栏代码

1.yolov8魔术师专栏介绍 开箱即用&#xff1a;提供 yolov8魔术师专栏 代码&#xff0c;方便直接使用&#xff0c;无需自己重新添加引起的一些bug问题&#xff1a; https://blog.csdn.net/m0_63774211/category_12289773.html?spm1001.2014.3001.5482 专栏内容如下&#xff…

【深入浅出Spring Security(五)】自定义过滤器进行前后端登录认证

自定义过滤器 一、自定义过滤器自定义登录认证过滤器自定义 LoginFilter配置 LoginFilter测试 二、总结 一、自定义过滤器 在【深入浅出Spring Security&#xff08;二&#xff09;】Spring Security的实现原理 中小编阐述了默认加载的过滤器&#xff0c;里面有些过滤器有时并…

OpenGL实现第一个窗口-三角形

1.简介 此代码是基于QtOpenGL实现的&#xff0c;但是大部分的代码是OpenGL&#xff0c;Qt封装了一些类&#xff0c;方便使用。 2.准备工作 QOpenGLWidget提供了三个便捷的虚函数&#xff0c;可以重写&#xff0c;用来重写实现典型的OpenGL任务。不需要GLFW。 paintGL&#…