Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Realtime decoding #615

Closed
wants to merge 82 commits into from
Closed
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
26a2424
Initial MNE real-time commit
chdinh Dec 1, 2012
939214c
[cleanup]
chdinh Dec 1, 2012
7a0a6a0
read real-time header info
chdinh Dec 1, 2012
77ba0dd
set alias
chdinh Dec 4, 2012
9992248
cleanup and some coding python guide lines
chdinh Dec 4, 2012
bda771b
read meas info
chdinh Dec 4, 2012
5cb2481
almost - read raw buffer doesn't receive all data jet
chdinh Dec 4, 2012
42f3713
working raw buffer reading
chdinh Dec 4, 2012
300a0fb
code style
chdinh Dec 4, 2012
9bab472
cleanup
chdinh Dec 4, 2012
c4b00ce
WIP: realtime
mluessi Jan 14, 2013
975293e
BaseEpochs, various enh
mluessi Jan 17, 2013
0e24371
rt rebase, fixes, example
mluessi Apr 23, 2013
d3dac3d
update setup
mluessi Apr 26, 2013
a7a9793
Small example for real-time decoding
jasmainak Jun 1, 2013
415d3d0
Added missing coma in setup.py
jasmainak Jun 2, 2013
817aa10
Simplified the example a lot. The real-time plot remains
jasmainak Jun 2, 2013
86a63e9
Added real-time plotting to example real-time decoding script
jasmainak Jun 3, 2013
dab8274
Fixed issue of accessing private function by using list comprehension…
jasmainak Jun 5, 2013
6b77d04
Removed redundant variable
jasmainak Jun 5, 2013
81a16c1
Some thoughts to how the real-time decoding can be structured
jasmainak Jun 5, 2013
c837a09
Trying to convert the newly created example into class/method format.…
jasmainak Jun 6, 2013
3b2e130
Fixed PEP8 for compute_rt_decoder.py and now plotting only last 5 poi…
jasmainak Jun 6, 2013
359d21b
Misc. changes - added new name to __init__.py and comment for waitfor…
jasmainak Jun 7, 2013
f296bdd
Modified classifier.py so that it is general enough to take clf from …
jasmainak Jun 7, 2013
989ce13
Added iter_evoked() method to class _BaseEpochs. This will allow Evok…
jasmainak Jun 13, 2013
1f12421
Modified iterate_evoked() function to allow iterating over RtEpochs a…
jasmainak Jun 14, 2013
f907eed
Added a keyword argument return_event_id=False to next() in RtEpochs …
jasmainak Jun 15, 2013
0b79bdd
Modified the code to return actual event-ids rather than the dictiona…
jasmainak Jun 19, 2013
9117d41
Always return event_id in _pop_epoch()
jasmainak Jun 19, 2013
582314b
Modified classifier.py to add the Scaler class which subtracts the me…
jasmainak Jun 22, 2013
16b96f1
Fix small bug in Scaler class
jasmainak Jun 22, 2013
15ed925
Added PSDEstimator class to classifier.py
jasmainak Jun 22, 2013
5c39300
Added FilterEstimator (which won't work as of now). Will have to figu…
jasmainak Jun 22, 2013
968813c
Added a class to concatenate time-series across channels
jasmainak Jun 24, 2013
d622b8a
Added file for testing pipeline and also added TODOs to the classifie…
jasmainak Jun 24, 2013
c42de91
Testing reshaping of 3d epochs into 2d epochs
jasmainak Jun 26, 2013
7cca9fc
3d array to 2d array reshaping verified
jasmainak Jun 26, 2013
959c0ec
Corrected concatenation of channels. transpose is not required. Also,…
jasmainak Jun 26, 2013
444ab7b
Uses iter_evoked() method in epochs that was newly introduced and pip…
jasmainak Jun 26, 2013
c9f9ced
Remove confusing duplicate of decoding example
jasmainak Jun 26, 2013
ef92821
Modified real-time decoding example to show standard deviation across…
jasmainak Jun 30, 2013
4f0035b
Removed redundant variables trnum and tsnum
jasmainak Jun 30, 2013
fed2fad
The only option for the FilterEstimator class seems to be to duplicat…
jasmainak Jun 30, 2013
bb687b4
Misc. fixes to FilterEstimator
jasmainak Jun 30, 2013
4432a14
Added docstrings to FilterEstimator and also updated the example to i…
jasmainak Jun 30, 2013
ff71dcd
Updated docstrings
jasmainak Jul 1, 2013
11c11bf
Small fixes
jasmainak Jul 2, 2013
02b3097
Removed offline_testing folder
jasmainak Jul 4, 2013
5b98f7e
Updated Scaler class to have division by std. deviation as well
jasmainak Jul 4, 2013
a2c9d36
Added more structure to PSDEstimator class and also fit_transform met…
jasmainak Jul 4, 2013
b20c6dd
Commit to save changes before attempting a rebase w.r.t. to master
jasmainak Jul 5, 2013
54fda72
FIXES
Jul 6, 2013
34b3d09
FIXES 2
Jul 6, 2013
c209354
FIX 3
Jul 6, 2013
75ffaa8
FIX 4
Jul 6, 2013
6f89571
Implementation of MockRtClient together with modified examples
jasmainak Jul 9, 2013
15ce5b1
Misc. fixes and change in API for sending buffers from mock rt_client
jasmainak Jul 10, 2013
46808c7
Added TransformerMixin to MNE-Python
jasmainak Jul 10, 2013
609c1bc
Use tmin instead of tmin_samp as argument to send_data() in RtMockClient
jasmainak Jul 10, 2013
65bfd9b
Added unit test for mock client, but the test doesn't work yet
jasmainak Jul 11, 2013
ebd0e45
Modified the test to directly check if the epoch_queue is the same as…
jasmainak Jul 12, 2013
c67ab1c
Reverted to checking equality of epochs. Some issue with calibration …
jasmainak Jul 12, 2013
30ac8f3
Addressing @agramfort 's comments and adding test_Scaler(). More test…
jasmainak Jul 14, 2013
35b7729
Unit tests + fixes
jasmainak Jul 14, 2013
6655885
PSDEstimator Unit test works, but mockclient still has problems
jasmainak Jul 15, 2013
1d9e910
Calibration + Unit tests
jasmainak Jul 16, 2013
22c86b1
Unit tests pass
jasmainak Jul 16, 2013
248d79e
Added test for iter_evoked()
jasmainak Jul 16, 2013
0269e98
MISC : cleanup in realtime
agramfort Jul 16, 2013
97bbb69
MISC : rename examples so they get plotted in the examples gallery
agramfort Jul 16, 2013
6331f2f
API : simplify RtEpochs (no consume_epochs, max n_epochs but just a t…
agramfort Jul 16, 2013
57d8fd2
addressing mainak's remarks
agramfort Jul 16, 2013
abad851
Merge pull request #1 from agramfort/realtime
jasmainak Jul 17, 2013
a5792ff
Remove redundant n_epochs from moving average example
jasmainak Jul 17, 2013
e6aed0c
Created decoding module
jasmainak Jul 17, 2013
23eb2f4
Updated authors list
jasmainak Jul 17, 2013
4669780
Updated whats_new.rst
jasmainak Jul 18, 2013
146f4f1
Modified realtime examples for sphinx docs
jasmainak Jul 18, 2013
62a1fd0
Python Reference + Fix
jasmainak Jul 18, 2013
49f40f3
Addressing @agramfort's comments
jasmainak Jul 18, 2013
a68c208
Forgotten tests folder
jasmainak Jul 18, 2013
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions examples/realtime/README.txt
@@ -0,0 +1,5 @@
Real-time M/EEG Acquisition
---------------------------

Receive data from an MNE Real-time server (mne_rt_server, part of MNE-CPP),
compute real-time moving averages, etc.
112 changes: 112 additions & 0 deletions examples/realtime/plot_compute_rt_decoder.py
@@ -0,0 +1,112 @@
"""
=======================
Decoding real-time data
=======================

Supervised machine learning applied to MEG data in sensor space.
Here the classifier is updated every 5 trials and the decoding
accuracy is plotted
"""
# Authors: Mainak Jas <mainak@neuro.hut.fi>
#
# License: BSD (3-clause)

print __doc__

import mne
from mne.realtime import MockRtClient, RtEpochs
from mne.datasets import sample

import numpy as np
import pylab as pl

# Fiff file to simulate the realtime client
data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
raw = mne.fiff.Raw(raw_fname, preload=True)

tmin, tmax = -0.2, 0.5
event_id = dict(aud_l=1, vis_l=3)

tr_percent = 60 # Training percentage
min_trials = 10 # minimum trials after which decoding should start

# select gradiometers
picks = mne.fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
stim=True, exclude=raw.info['bads'])

# create the mock-client object
rt_client = MockRtClient(raw)

# create the real-time epochs object
rt_epochs = RtEpochs(rt_client, event_id, tmin, tmax, picks=picks, decim=1,
reject=dict(grad=4000e-13, eog=150e-6))

# start the acquisition
rt_epochs.start()

# send raw buffers
rt_client.send_data(rt_epochs, picks, tmin=0, tmax=90, buffer_size=1000)

# Decoding in sensor space using a linear SVM
n_times = len(rt_epochs.times)

from sklearn import preprocessing
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
from sklearn.cross_validation import cross_val_score, ShuffleSplit

from mne.realtime.classifier import ConcatenateChannels, FilterEstimator

scores_x, scores, std_scores = [], [], []

pl.ion()

filt = FilterEstimator(rt_epochs.info, 1, 40)
scaler = preprocessing.StandardScaler()
concatenator = ConcatenateChannels()
clf = SVC(C=1, kernel='linear')

concat_classifier = Pipeline([('filter', filt), ('concat', concatenator),
('scaler', scaler), ('svm', clf)])

for ev_num, ev in enumerate(rt_epochs.iter_evoked()):

print "Just got epoch %d" % (ev_num + 1)

if ev_num == 0:
X = ev.data[None, ...]
y = int(ev.comment)
else:
X = np.concatenate((X, ev.data[None, ...]), axis=0)
y = np.append(y, int(ev.comment))

if ev_num >= min_trials:

cv = ShuffleSplit(len(y), 5, test_size=0.2, random_state=42)
scores_t = cross_val_score(concat_classifier, X, y, cv=cv,
n_jobs=1) * 100

std_scores.append(scores_t.std())
scores.append(scores_t.mean())
scores_x.append(ev_num)

# Plot accuracy
pl.clf()

pl.plot(scores_x[-5:], scores[-5:], '+', label="Classif. score")
pl.hold(True)
pl.plot(scores_x[-5:], scores[-5:])
pl.axhline(50, color='k', linestyle='--', label="Chance level")
hyp_limits = (np.asarray(scores[-5:]) - np.asarray(std_scores[-5:]),
np.asarray(scores[-5:]) + np.asarray(std_scores[-5:]))
pl.fill_between(scores_x[-5:], hyp_limits[0], y2=hyp_limits[1],
color='b', alpha=0.5)
pl.xlabel('Trials')
pl.ylabel('Classification score (% correct)')
pl.ylim([30, 105])
pl.title('Real-time decoding')
pl.show()

# time.sleep() isn't used because of known issues with the Spyder
pl.waitforbuttonpress(0.1)
73 changes: 73 additions & 0 deletions examples/realtime/plot_compute_rt_moving_average.py
@@ -0,0 +1,73 @@
"""
========================================================
Compute real-time evoked responses using moving averages
========================================================

This example demonstrates how to connect to an MNE Real-time server
using the RtClient and use it together with RtEpochs to compute
evoked responses using moving averages.

Note: The MNE Real-time server (mne_rt_server), which is part of mne-cpp,
has to be running on the same computer.
"""

print __doc__

# Authors: Martin Luessi <mluessi@nmr.mgh.harvard.edu>
# Mainak Jas <mainak@neuro.hut.fi>
#
# License: BSD (3-clause)

import mne
from mne.datasets import sample
from mne.realtime import RtEpochs, MockRtClient

import pylab as pl

# Fiff file to simulate the realtime client
data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
raw = mne.fiff.Raw(raw_fname, preload=True)

# select gradiometers
picks = mne.fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,
stim=True, exclude=raw.info['bads'])

# select the left-auditory condition
event_id, tmin, tmax = 1, -0.2, 0.5

# the number of epochs to average
n_epochs = 30
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, this is no longer required. should delete this too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go ahead !

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok fixed this.

what all is left to have this branch merged? We have unit tests and
examples - what else? can we go for a good hard review and aim to have this
merged soon?

On Wed, Jul 17, 2013 at 1:51 PM, Alexandre Gramfort <
notifications@github.com> wrote:

In examples/realtime/plot_compute_rt_moving_average.py:

+import pylab as pl
+
+# Fiff file to simulate the realtime client
+data_path = sample.data_path()
+raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
+raw = mne.fiff.Raw(raw_fname, preload=True)
+
+# select gradiometers
+picks = mne.fiff.pick_types(raw.info, meg='grad', eeg=False, eog=True,

  •                        stim=True, exclude=raw.info['bads'])
    
    +# select the left-auditory condition
    +event_id, tmin, tmax = 1, -0.2, 0.5
    +
    +# the number of epochs to average
    +n_epochs = 30

go ahead !


Reply to this email directly or view it on GitHubhttps://github.com//pull/615/files#r5239140
.


# create the mock-client object
rt_client = MockRtClient(raw)

# create the real-time epochs object
rt_epochs = RtEpochs(rt_client, event_id, tmin, tmax, picks=picks,
decim=1, reject=dict(grad=4000e-13, eog=150e-6))

# start the acquisition
rt_epochs.start()

# send raw buffers
rt_client.send_data(rt_epochs, picks, tmin=0, tmax=150, buffer_size=1000)

# make the plot interactive
pl.ion()

evoked = None

for ii, ev in enumerate(rt_epochs.iter_evoked()):

print "Just got epoch %d" % (ii + 1)

if evoked is None:
evoked = ev
else:
evoked += ev

pl.figure(1)

evoked.plot()
pl.show()
pl.waitforbuttonpress(0.1)