Signal processing and analysis of human brain potentials (EEG) [Exercise 1]
Overview
In this exercise we will install the mne-python toolbox, download a example dataset, make some basic visualizations and epoch, average and visualize the resulting ERPs.
Install MNE toolbox
run pip install mne
or if you like conda: conda install -c conda-forge mne
similarly, install pip install mne-bids
, a tool to load the EEG data easily.
Test the installation by import mne
Download data
We will be using a typical P3 oddball dataset. We expect a positive response over parietal/central electrodes (Cz/Pz) starting at 300-400ms, something like this.
If you want to read the details you can find it here. You can also investigate the sub-030_task-P3_eeg.json
for a task description which is one of the files you will download next:
Next, you need the ccs_eeg_utils.py file which you can add to your python code e.g. via
import sys
0,'.') sys.path.insert(
Load data & plot continuous EEG
# Load the data
from mne_bids import (BIDSPath,read_raw_bids)
# path where to save the datasets.
= "../local/bids"
bids_root = '030' # recommend subject 30 for now
subject_id
= BIDSPath(subject=subject_id,task="P3",session="P3",
bids_path ='eeg', suffix='eeg',
datatype=bids_root)
root
# read the file
= read_raw_bids(bids_path)
raw # fix the annotations readin
ccs_eeg_utils.read_annotations_core(bids_path,raw)
Task: Extract a single channel and plot the whole timeseries.
You can directly interact with the raw
object, e.g. raw[1:10,1:5000]
, which extracts the first 10 channels and 5000 samples.
You can also use raw.get_data()
to get the whole data as a numpy array.
For now we can use simple matplotlib to visualize the data, e.g.:
from matplotlib import pyplot as plt
10,:][0].T) plt.plot(raw[
Question: What is the range of the data (in sense of min-y to max-y in µ-volt)?
Task: Have a look at raw.info
and note down what the sampling frequency is (how many EEG-samples per second)
Epoching
Task: We will epoch the data now. Formost we will cut the raw data to one channel using raw.pick(["Cz"])
- note that this will permanently change the raw
object and removes alle other channels from memory. If you want rather a copy you could use raw_subselect = raw.copy().pick(["Cz"]))
.
Task Let’s investigate the annotation markers. Have a look at raw.annotations. These values reflect the values in the bids *_events.tsv
file (have a look at this file via ../local/bids/sub-030/sub-030_task-P3_events.tsv
). BIDS is a new standard to share neuroimaging and other physiological data. It is not really a fileformat, but more of a folder & filename structure with some additional json files. I highly recommend to put your data into bids-format as soon as possible. It helps you stay organized and on top of things!
Task MNE-speciality: We have to convert annotations to events with evts,evts_dict = mne.events_from_annotations(raw)
. Have a look at evts - it shows you the sample, the duration and event-id (with the look-up table evts_dict). In this case we only want to look at stimulus evoked responses, so we subset the event table (note: this could be done after epoching too)
# get all keys which contain "stimulus"
= [e for e in evts_dict.keys() if "stimulus" in e]
wanted_keys # subset the large event-dictionairy
=dict((k, evts_dict[k]) for k in wanted_keys if k in evts_dict) evts_dict_stim
Task Epoch the data with epochs = mne.Epochs(raw,evts,evts_dict_stim,tmin=-0.1,tmax=1)
Task Now that we have the epochs we should plot them. Plot all trials ‘manually’, (without using mne’s functionality) (epochs.get_data()
).
You should plot one line per trial.
Question What is the scale-range of the epoched data now?
My first ERP
Task But which epochs belong to targets and which to distractors? This is hidden in the event-description. Using the following lines you can find out which indices belong to which trial-types
= ["stimulus:{}{}".format(k,k) for k in [1,2,3,4,5]]
target = ["stimulus:{}{}".format(k,j) for k in [1,2,3,4,5] for j in [1,2,3,4,5] if k!=j] distractor
Now index the epochs evoked = epochs[index].average()
and average them. You can then plot them either via evoked.plot()
or with mne.viz.plot_compare_evokeds([evokedA,evokedB])
.
Question What is the unit/scale of the data now? Set it into context to the other two scales you reported before