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:

Please download the data from

Next, you need the ccs_eeg_utils.py file which you can add to your python code e.g. via

import sys
sys.path.insert(0,'.')

Load data & plot continuous EEG

# Load the data
from mne_bids import (BIDSPath,read_raw_bids)

# path where to save the datasets.
bids_root = "../local/bids"
subject_id = '030' # recommend subject 30 for now


bids_path = BIDSPath(subject=subject_id,task="P3",session="P3",
                     datatype='eeg', suffix='eeg',
                     root=bids_root)

# read the file
raw = read_raw_bids(bids_path)
# fix the annotations readin
ccs_eeg_utils.read_annotations_core(bids_path,raw)

Task: Extract a single channel and plot the whole timeseries.

Note

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
plt.plot(raw[10,:][0].T)

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"
wanted_keys = [e for e in evts_dict.keys() if "stimulus" in e]
# subset the large event-dictionairy
evts_dict_stim=dict((k, evts_dict[k]) for k in wanted_keys if k in evts_dict)

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()).

Note

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

target = ["stimulus:{}{}".format(k,k) for k in [1,2,3,4,5]]
distractor = ["stimulus:{}{}".format(k,j) for k in [1,2,3,4,5] for j in [1,2,3,4,5] if k!=j]

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