Author : Alexandre Gramfort
This tutorial describes how to define epochs-of-interest (trials) from your recorded MEG-data, and how to apply the different preprocessing steps.
Subsequently, you will find information how to compute an event related potential (ERP)/ event related field (ERF) and how to handle the three channels that record the signal at each sensor location. It explains how to visualize the axial magnetometer and planar gradiometer signals.
In MNE the preprocessing of data refers to the reading of the data, segmenting the data around interesting events such as triggers, temporal filtering and optionally rereferencing.
MNE works by loading data in memory only if needed when extracting epochs. The raw data do not need to fit in memory unless you want to filter continuous data (see below). In the introduction, the filtering of continuous data is optional.
Preprocessing involves several steps including identifying individual trials (called Epochs in MNE) from the dataset (called Raw), filtering and rejection of bad epochs. This tutorial covers how to identify trials using the trigger signal. Defining data segments of interest can be done according to a specified trigger channel and the use of an array of events
.
When analyzing EEG or MEG signals, the aim is to investigate the modulation of the measured brain signals with respect to a certain event. However, due to intrinsic and extrinsic noise in the signals - which in single trials is often higher than the signal evoked by the brain - it is typically required to average data from several trials to increase the signal-to-noise ratio(SNR). One approach is to repeat a given event in your experiment and average the corresponding EEG/MEG signals. The assumption is that the noise is independent of the events and thus reduced when averaging, while the effect of interest is time-locked to the event. The approach results in ERPs and ERFs for respectively EEG and MEG. Timelock analysis can be used to calculate ERPs/ ERFs.
The MEG dataset used in this tutorial are recorded during electrical stimulation of the Median Nerve (MN) of the left hand.
The MEG signals were recorded with the NatMEG 306 sensor Neuromag Triux system. The Neuromag MEG system has 306 channels located at 102 unique locations in the dewar. Of these, 102 channels are axial magnetometer sensors that measure the magnetic field in the radial direction, i.e. orthogonal to the scalp. The other 2*102 channels are planar gradiometers, which measure the magnetic field gradient tangential to the scalp. The planar gradient MEG data has the advantage that the amplitude typically is the largest directly above a source.
# add plot inline in the page (not necessary in Spyder)
%matplotlib inline
First, load the mne package:
import mne
We set the log-level to 'WARNING' so the output is less verbose
mne.set_log_level('WARNING')
data_path = '/Users/alex/Sync/karolinska_teaching/'
raw_fname = data_path + '/meg/somstim_raw.fif'
print raw_fname
Read data from file:
raw = mne.fiff.Raw(raw_fname)
print raw
raw.ch_names[:20:3]
print raw.info
Look at the channels in raw:
data, times = raw[:, :10]
print data.shape
Read and plot a segment of raw data
start, stop = raw.time_as_index([100, 115]) # 100 s to 115 s data segment
data, times = raw[:306, start:stop]
print data.shape
print times.shape
print times.min(), times.max()
Where are my magnetometers?
picks = mne.fiff.pick_types(raw.info, meg='mag', exclude=[])
print picks
Take some magnetometer data and plot it
picks = mne.fiff.pick_types(raw.info, meg='mag', exclude=[])
data, times = raw[picks[:10], start:stop]
import matplotlib.pyplot as plt
plt.plot(times, data.T)
plt.xlabel('time (s)')
plt.ylabel('MEG data (T)')
len(mne.fiff.pick_types(raw.info, meg='grad', eeg=False, exclude='bads'))
raw.info['bads'] # there is no channel marked as bad here
Save a segment of 150s of raw data (MEG only):
picks = mne.fiff.pick_types(raw.info, meg=True, eeg=False, stim=True, exclude=[])
# raw.save('somsen_short_raw.fif', tmin=0., tmax=150., picks=picks, overwrite=True)
Otherwise you can use mne_process_raw
in the terminal with something like
mne_process_raw --raw somstim_raw.fif --highpass 1 --lowpass 40 --save somstim_raw_1_40_raw.fif --projoff --decim 4 --digtrig STI101
# raw_beta = mne.fiff.Raw(raw_fname, preload=True) # reload data with preload for filtering
# keep beta band
# raw_beta.filter(13.0, 30.0, method='iir')
# save the result
# raw_beta.save('somsen_beta_raw.fif', overwrite=True)
# print raw_beta.info
First extract events:
events = mne.find_events(raw, stim_channel='STI101', verbose=True)
print events[:5] # events is a 2d array
len(events[events[:, 2] == 1])
len(events)
Where are they coming from?
d, t = raw[raw.ch_names.index('STI101'), :]
d.shape
raw.ch_names.index('STI101')
raw.ch_names[315:322]
plt.plot(d[0,:100000])
Events are stored as 2D numpy array where the first column is the time instant and the last one is the event number. It is therefore easy to manipulate.
using the raw.info['sfreq']
attribute in the measurement info and the events array estimate the mean interstimulus interval
def fix_info(raw):
raw.info['chs'][raw.ch_names.index('BIO001')]['kind'] = mne.fiff.constants.FIFF.FIFFV_EOG_CH
raw.info['chs'][raw.ch_names.index('BIO002')]['kind'] = mne.fiff.constants.FIFF.FIFFV_EOG_CH
raw.info['chs'][raw.ch_names.index('BIO003')]['kind'] = mne.fiff.constants.FIFF.FIFFV_ECG_CH
raw.info['chs'][raw.ch_names.index('BIO004')]['kind'] = mne.fiff.constants.FIFF.FIFFV_ECG_CH
fix_info(raw)
# check it worked
print mne.fiff.pick_types(raw.info, meg=False, eog=True, ecg=True)
We shall define epochs parameters. The first is set the event_id that is a Python dictionary to relate a condition name to the corresponding trigger number.
event_id = dict(som=1) # event trigger and conditions
print event_id
Then the pre and post stimulus time intervals. Times are always in seconds and relative to the stim onset.
tmin = -0.1 # start of each epoch (200ms before the trigger)
tmax = 0.3 # end of each epoch (500ms after the trigger)
Mark some channels as bad (not necessary here):
# raw.info['bads'] = ['MEG 2443']
# print raw.info['bads']
The variable raw.info[‘bads’] is just a python list.
Pick the good channels:
picks = mne.fiff.pick_types(raw.info, meg=True, eeg=True, eog=True,
stim=False, exclude='bads')
Alternatively one can restrict to magnetometers or gradiometers with:
mag_picks = mne.fiff.pick_types(raw.info, meg='mag', eog=True, exclude='bads')
grad_picks = mne.fiff.pick_types(raw.info, meg='grad', eog=True, exclude='bads')
Define the baseline period:
baseline = (None, 0) # means from the first instant to t = 0
Define peak-to-peak rejection parameters for gradiometers, magnetometers and EOG:
reject = dict(grad=4000e-13, mag=4e-12, eog=150e-6)
Read epochs:
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
picks=picks, baseline=baseline, reject=reject)
print epochs
or if you want to preload
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
picks=picks, baseline=baseline, reject=reject,
preload=True) # now data are in memory
print epochs
epochs.plot_drop_log()
Get the single epochs as a 3d array:
epochs_data = epochs['som'].get_data()
print epochs_data.shape
epochs_data is a 3D array of dimension (367 epochs, 308 channels, 401 time instants).
Scipy supports reading and writing of matlab files. You can save your single trials with:
# from scipy import io
# io.savemat('epochs_data.mat', dict(epochs_data=epochs_data), oned_as='row')
or if you want to keep all the information about the data you can save your epochs in a fif file:
# epochs.save('somstim-epo.fif')
Compute evoked responses for somatosensory responses by averaging and plot it:
evoked = epochs['som'].average()
print evoked
evoked.save('somtim-ave.fif') # save it to disk
fig = evoked.plot()
import numpy as np
# Ugly hack due to acquisition problem when specifying the channel types
layout = mne.layouts.read_layout('Vectorview-mag.lout')
layout.names = mne.utils._clean_names(layout.names, remove_whitespace=True)
fig = evoked.plot_topomap(times=np.linspace(0.05, 0.12, 5), ch_type='mag', layout=layout)
fig = evoked.plot_topomap(times=np.linspace(0.05, 0.12, 5), ch_type='grad')
evoked.data.shape
Save the figure in high resolution pdf
# next line not necessary in Spyder
%matplotlib qt4
import numpy as np
evoked.plot_topomap(times=np.linspace(0.035, 0.1, 5), ch_type='mag', layout=layout)
plt.savefig('som_topo.pdf')
!open som_topo.pdf
# next line not necessary in Spyder
%matplotlib inline
It is also possible to read evoked data stored in a fif file. Let's load the online average provided by the Neuromag system
evoked_fname = data_path + '/meg/somstim_avg.fif'
evoked1 = mne.fiff.read_evoked(evoked_fname, baseline=(None, 0), proj=True)
# fix acquisition
fix_info(evoked1)
Plot it:
fig = evoked1.plot()
The following cell gives you a full summary script of what's above
import numpy as np
import mne
data_path = '/Users/alex/Sync/karolinska_teaching/'
raw_fname = data_path + '/MEG/somstim_raw.fif'
raw = mne.fiff.Raw(raw_fname)
events = mne.find_events(raw, stim_channel='STI101', verbose=True)
print np.mean(np.diff(events[:, 0]) / raw.info['sfreq'])
#%% fix
def fix_info(raw):
raw.info['chs'][raw.ch_names.index('BIO001')]['kind'] = mne.fiff.constants.FIFF.FIFFV_EOG_CH
raw.info['chs'][raw.ch_names.index('BIO002')]['kind'] = mne.fiff.constants.FIFF.FIFFV_EOG_CH
raw.info['chs'][raw.ch_names.index('BIO003')]['kind'] = mne.fiff.constants.FIFF.FIFFV_ECG_CH
raw.info['chs'][raw.ch_names.index('BIO004')]['kind'] = mne.fiff.constants.FIFF.FIFFV_ECG_CH
fix_info(raw)
#%% compute the Epochs
event_id = dict(som=1) # event trigger and conditions
tmin = -0.1 # start of each epoch (200ms before the trigger)
tmax = 0.3 # end of each epoch (500ms after the trigger)
baseline = (None, 0) # means from the first instant to t = 0
reject = dict(grad=4000e-13, mag=4e-12, eog=150e-6)
picks = mne.fiff.pick_types(raw.info, meg=True, eog=True, exclude='bads')
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
picks=picks, baseline=baseline, reject=reject,
preload=True)
epochs.plot_drop_log()
evoked = epochs['som'].average()
evoked.plot()
evoked.plot_topomap(times=np.linspace(0.05, 0.12, 5), ch_type='mag')