【脑机接口社区】(1) MNE中数据结构Raw及其用法简介

1. 前言

最近在根据【脑机接口社区】的博客和公众号的推文学习python中mne库的用法,也算是真正开始上手EEG信号处理的代码了吧。本系列的推文所用的脑机接口均为OpenBCI,欢迎各位大佬一同交流!


2. 初始Raw对象结构

Raw对象主要是用来存储连续型的数据,其核心的数据主要为n_channels和n_times(时间×频率),其中也包括了Info对象。

  • Raw结构查看
# 引入python库
import mne
from mne.datasets import sample
import matplotlib.pyplot as plt

# sample的存放地址
data_path = sample.data_path()
# 该fif文件存放地址
fname = data_path + '/MEG/sample/sample_audvis_raw.fif'

"""
如果上述给定的地址中存在该文件,则直接加载本地文件,
如果不存在则在网上下载改数据
"""
raw = mne.io.read_raw_fif(fname)
print(raw.info)
  • 通过打印raw查看数据
<Info | 19 non-empty fields
    bads : list | 0 items
    ch_names : list | MEG 0113, MEG 0112, MEG 0111, MEG 0122, MEG 0123, EEG 053, EEG 052, EEG 051
    chs : list | 8 items (EEG: 8)
    comps : list | 0 items
    custom_ref_applied : bool | False
    dev_head_t : Transform | 3 items
    dig : Digitization | 0 items
    events : list | 0 items
    file_id : dict | 4 items
    highpass : float | 0.0 Hz
    hpi_meas : list | 0 items
    hpi_results : list | 0 items
    lowpass : float | 128.0 Hz
    meas_date : NoneType | unspecified
    meas_id : dict | 4 items
    nchan : int | 8
    proc_history : list | 0 items
    projs : list | 0 items
    sfreq : float | 256.0 Hz
    acq_pars : NoneType
    acq_stim : NoneType
    ctf_head_t : NoneType
    description : NoneType
    dev_ctf_t : NoneType
    device_info : NoneType
    experimenter : NoneType
    gantry_angle : NoneType
    helium_info : NoneType
    hpi_subsystem : NoneType
    kit_system_id : NoneType
    line_freq : NoneType
    proj_id : NoneType
    proj_name : NoneType
    subject_info : NoneType
    utc_offset : NoneType
    xplotter_layout : NoneType
>
  • 从上述信息中可以看出不良通道bads,通道名称ch_names,采样频率sfreq等等。

3. 从头创建Raw对象

  • 函数:mne.io.RawArray,其构造函数只接受矩阵和info对象
  • 创建一个Raw对象时,需要准备两种数,一种是data数据,一种是info数据,其中data数据是一个二维数据,格式为(n_channels,n_times)

(1)获取OpenBCI的脑电数据

  • 利用brainflow库进行数据的获取。以下代码用的是(SYNTHETIC_BOARD)合成板
import time
import numpy as np
import matplotlib
#matplotlib.use ('Agg')
from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds
import mne

BoardShim.enable_dev_board_logger ()
# use synthetic board for demo
params = BrainFlowInputParams ()
board = BoardShim (BoardIds.SYNTHETIC_BOARD.value, params)
board.prepare_session ()
board.start_stream ()
time.sleep (10) #获取10s的数据
data = board.get_board_data ()
board.stop_stream ()
board.release_session ()

eeg_channels = BoardShim.get_eeg_channels (BoardIds.SYNTHETIC_BOARD.value)
    eeg_data = data[eeg_channels, :]
  • 如果直接用脑机接口,可以将board = BoardShim (BoardIds.SYNTHETIC_BOARD.value, params)改成board = BoardShim (BoardIds.CYTON_BOARD_BOARD.value, params) 然后再改变端口,改变端口有两种办法,一种是暴力法,直接改boardshim库中的代码;另一种是采用另一种获取数据的代码。

方法一
boardshim.py >>> serial_port=‘COM3’
方法一

方法二

def main ():
	parser = argparse.ArgumentParser ()
    # use docs to check which parameters are required for specific board, e.g. for Cyton - set serial port
    parser.add_argument ('--ip-port', type = int, help  = 'ip port', required = False, default = 0)
    parser.add_argument ('--ip-protocol', type = int, help  = 'ip protocol, check IpProtocolType enum', required = False, default = 0)
    parser.add_argument ('--ip-address', type = str, help  = 'ip address', required = False, default = '')
    parser.add_argument ('--serial-port', type = str, help  = 'serial port', required = False, default = 'COM3')
    parser.add_argument ('--mac-address', type = str, help  = 'mac address', required = False, default = '')
    parser.add_argument ('--other-info', type = str, help  = 'other info', required = False, default = '')
    parser.add_argument ('--streamer-params', type = str, help  = 'other info', required = False, default = '')
    parser.add_argument ('--board-id', type = int, help  = 'board id, check docs to get a list of supported boards',default=0)
    parser.add_argument ('--log', action = 'store_true')
    args = parser.parse_args ()

    params = BrainFlowInputParams ()
    params.ip_port = args.ip_port
    params.serial_port = args.serial_port
    params.mac_address = args.mac_address
    params.other_info = args.other_info
    params.ip_address = args.ip_address
    params.ip_protocol = args.ip_protocol

    if (args.log):
        BoardShim.enable_dev_board_logger ()
    else:
        BoardShim.disable_board_logger ()

    board = BoardShim (args.board_id, params)
    board.prepare_session ()

    board.start_stream ()
    time.sleep (1)
    board.config_board ('/2') # enable analog mode only for Cyton Based Boards!
    time.sleep (5)
    data = board.get_board_data ()

如果不清楚端口是否连接成功,可以采用以下代码

def get_port():
    import serial.tools.list_ports
    port_list = list(serial.tools.list_ports.comports())
    if len(port_list) == 0:
        print('找不到串口')
    else:
        for i in range(0,len(port_list)):
            print(port_list[i])

(2)创建Raw对象

  • 创建info结构
  • 内容包括:通道类型ch_types和通道名称ch_names
  • 设置采样频率sfreq为合成板默认的频率256Hz
	# Creating MNE objects from brainflow data arrays
    ch_types = ['eeg', 'eeg', 'eeg', 'eeg', 'eeg', 'eeg', 'eeg', 'eeg']
    ch_names = ['MEG 0113', 'MEG 0112', 'MEG 0111', 'MEG 0122', 'MEG 0123', 'EEG 053', 'EEG 052', 'EEG 051']#通道一般自行设定
    sfreq = BoardShim.get_sampling_rate (BoardIds.SYNTHETIC_BOARD.value)
    info = mne.create_info (ch_names = ch_names, sfreq = sfreq, ch_types = ch_types)
  • 利用mne.io.RawArray类创建Raw对象
	raw = mne.io.RawArray (eeg_data, info)
  • 保存,载入刚才保存的数据并打印信息
    picks = mne.pick_types(
        info, meg=False, eeg=True, stim=False,
        include=ch_names
    )
    raw.save("raw.fif", picks=picks, overwrite=True)

    raw_fif_data = mne.io.read_raw_fif("raw.fif", preload=True, verbose='ERROR')
    print(raw_fif_data.info)

(3)展示数据信号图

scalings = {'eeg': 1000}#采用1000倍缩小。
#scalings = 'auto' 也可以采用自动缩放比例
raw.plot(n_channels=8, scalings=scalings, title='Data from arrays',
         show=True, block=True)

以下展示1000倍和8000倍缩小的数据波形。
1000倍缩小的图
8000倍缩放的图

4. 数据的相关绘制

  • 通常raw的数据访问方式如下:
    data, times = raw[picks, time_slice]
    picks:是根据条件挑选出来的索引;
    time_slice:时间切片
  • 想要获取raw中所有数据,以下两种方式均可:
    data,times=raw[:]
    data,times=raw[:,:]

(1)获取0-10秒内的良好的EEG数据

  • 根据type来选择 那些良好的EEG信号(良好的EEG信号,通过设置exclude=“bads”) channel,结果为 channels所对应的的索引
picks = mne.pick_types(raw.info, eeg=True, exclude='bads')
t_idx = raw.time_as_index([0., 10.])
data, times = raw[picks, t_idx[0]:t_idx[1]]
plt.plot(times,data.T)
plt.title("Sample channels")
plt.show()

  • 这图是真滴丑,应该需要改改颜色。

(2)获取采样频率sfreq

采样频率,也称为采样速度或者采样率,定义了每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示。
采样频率的倒数是采样周期或者叫作采样时间,它是采样之间的时间间隔。
通俗的讲采样频率是指计算机每秒钟采集多少个信号样本。


sfreq=raw.info['sfreq']
"""
获取索引为m到n的样本,每个样本从第k次到第h次.
data,times=raw[m:n,k:h]

其中data为索引为m到n的样本,每个样本从第k次到第h次.
times是以第k次采样的时间作为开始时间,第h次采样时的时间为结束时间的时间数组。
"""
data,times=raw[:3,int(sfreq*1):int(sfreq*3)]
plt.plot(times,data.T)
plt.title("Sample channels")

以下几幅图因为用的是合成板,所以无法确定通道的位置,因而借用以下脑机接口社区的图片

(3)绘制各通道的功率谱密度

raw.plot_psd()
plt.show()

(4)绘制SSP矢量图

raw.plot_projs_topomap()
plt.show()

(5)绘制通道频谱图作为topography

raw.plot_psd_topo()
plt.show()

(6)绘制电极位置

raw.plot_sensors()
plt.show()

  • 4
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值