-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ea80d71
commit 9e5ba27
Showing
7 changed files
with
192 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,24 @@ | ||
# pyMuse | ||
Python tools associated with Muse headband | ||
|
||
This repository contains tools for getting Muse signals using Python. | ||
|
||
## Installation & dependences | ||
You will need some tools to get started with Muse headset and pyMuse: | ||
* Muse SDK --> https://sites.google.com/a/interaxon.ca/muse-developer-site/download | ||
* Python 2.7 | ||
* matplotlib --> pip install matplotlib | ||
* numpy --> pip install numpy | ||
* liblo and pyliblo --> https://github.com/marionleborgne/cloudbrain#install-liblo | ||
|
||
Don't hesitate to go on [Muse Developer website](https://sites.google.com/a/interaxon.ca/muse-developer-site/home) to get information. | ||
|
||
## Getting started | ||
1. Connect your Muse headset with your computer by bluetooth | ||
2. Start MuseIO (in a terminal): | ||
``` | ||
muse-io --osc osc.udp://localhost:5001,osc.udp://localhost:5002 | ||
``` | ||
3. Start EEG display script (in a new terminal): | ||
``` | ||
python eeg_display.py | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
__author__ = 'benjamindeleener' | ||
|
||
import sys | ||
import time | ||
from pymuse.io import MuseServer | ||
from pymuse.viz import MuseViewer | ||
from pymuse.signal import MuseSignal | ||
from liblo import ServerError | ||
|
||
|
||
def main(): | ||
signal = MuseSignal(length=2000, do_fft=False) | ||
viewer = MuseViewer(signal, signal_boundaries=[600, 1200]) | ||
|
||
try: | ||
server = MuseServer(signal, viewer) | ||
except ServerError, err: | ||
print str(err) | ||
sys.exit(1) | ||
|
||
viewer.show() | ||
|
||
server.start() | ||
|
||
if __name__ == "__main__": | ||
main() | ||
while 1: | ||
time.sleep(0.01) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__author__ = 'benjamindeleener' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
__author__ = 'benjamindeleener' | ||
from liblo import * | ||
|
||
|
||
class MuseServer(ServerThread): | ||
# listen for messages on port 5001 | ||
def __init__(self, signal, viewer): | ||
self.signal = signal | ||
self.viewer = viewer | ||
|
||
ServerThread.__init__(self, 5001) | ||
|
||
# receive accelrometer data | ||
@make_method('/muse/acc', 'fff') | ||
def acc_callback(self, path, args): | ||
acc_x, acc_y, acc_z = args | ||
# print "%s %f %f %f" % (path, acc_x, acc_y, acc_z) | ||
|
||
# receive EEG data | ||
@make_method('/muse/eeg', 'ffff') | ||
def eeg_callback(self, path, args): | ||
self.signal.add_l_ear(args[0]) | ||
self.signal.add_l_forehead(args[1]) | ||
self.signal.add_r_forehead(args[2]) | ||
self.signal.add_r_ear(args[3]) | ||
print args | ||
|
||
self.viewer.refresh() | ||
|
||
# handle unexpected messages | ||
@make_method(None, None) | ||
def fallback(self, path, args, types, src): | ||
test = args | ||
# print "Unknown message \n\t Source: '%s' \n\t Address: '%s' \n\t Types: '%s ' \n\t Payload: '%s'" % | ||
# (src.url, path, types, args) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
__author__ = 'benjamindeleener' | ||
from numpy import fft | ||
|
||
|
||
class MuseSignal(object): | ||
def __init__(self, length=200, do_fft=False): | ||
self.length = length | ||
self.do_fft = do_fft | ||
self.l_ear, self.l_forehead, self.r_forehead, self.r_ear = [0.0] * self.length, [0.0] * self.length, [ | ||
0.0] * self.length, [0.0] * self.length | ||
self.l_ear_fft, self.l_forehead_fft, self.r_forehead_fft, self.r_ear_fft = [0.0] * self.length, [0.0] * self.length, [ | ||
0.0] * self.length, [0.0] * self.length | ||
|
||
def add_l_ear(self, s): | ||
self.l_ear.append(s) | ||
del self.l_ear[0] | ||
if self.do_fft: | ||
self.l_ear_fft = fft.fft(self.l_ear) | ||
|
||
def add_l_forehead(self, s): | ||
self.l_forehead.append(s) | ||
del self.l_forehead[0] | ||
if self.do_fft: | ||
self.l_forehead_fft = fft.fft(self.l_forehead) | ||
|
||
def add_r_forehead(self, s): | ||
self.r_forehead.append(s) | ||
del self.r_forehead[0] | ||
if self.do_fft: | ||
self.r_forehead_fft = fft.fft(self.r_forehead) | ||
|
||
def add_r_ear(self, s): | ||
self.r_ear.append(s) | ||
del self.r_ear[0] | ||
if self.do_fft: | ||
self.r_ear_fft = fft.fft(self.r_ear) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
__author__ = 'benjamindeleener' | ||
import matplotlib.pyplot as plt | ||
from datetime import datetime | ||
|
||
class MuseViewer(object): | ||
def __init__(self, signal, signal_boundaries=None): | ||
self.refresh_freq = 0.15 | ||
self.last_refresh = datetime.now() | ||
self.signal = signal | ||
if signal_boundaries is not None: | ||
self.low, self.high = signal_boundaries[0], signal_boundaries[1] | ||
else: | ||
self.low, self.high = 600, 1200 | ||
|
||
self.x_data = range(0, self.signal.length, 1) | ||
self.figure, (self.ax1, self.ax2, self.ax3, self.ax4) = plt.subplots(4, 1, sharex=True, figsize=(15, 10)) | ||
self.ax1.set_title('Left ear') | ||
self.ax2.set_title('Left forehead') | ||
self.ax3.set_title('Right forehead') | ||
self.ax4.set_title('Right ear') | ||
|
||
if self.signal.do_fft: | ||
self.ax1_plot, = self.ax1.plot(self.x_data[0:len(self.x_data)/2], self.signal.l_ear_fft[0:len(self.x_data)/2]) | ||
self.ax2_plot, = self.ax2.plot(self.x_data[0:len(self.x_data)/2], self.signal.l_forehead_fft[0:len(self.x_data)/2]) | ||
self.ax3_plot, = self.ax3.plot(self.x_data[0:len(self.x_data)/2], self.signal.r_forehead_fft[0:len(self.x_data)/2]) | ||
self.ax4_plot, = self.ax4.plot(self.x_data[0:len(self.x_data)/2], self.signal.r_ear_fft[0:len(self.x_data)/2]) | ||
|
||
self.ax1.set_ylim([0, 10000]) | ||
self.ax2.set_ylim([0, 10000]) | ||
self.ax3.set_ylim([0, 10000]) | ||
self.ax4.set_ylim([0, 10000]) | ||
else: | ||
self.ax1_plot, = self.ax1.plot(self.x_data, self.signal.l_ear) | ||
self.ax2_plot, = self.ax2.plot(self.x_data, self.signal.l_forehead) | ||
self.ax3_plot, = self.ax3.plot(self.x_data, self.signal.r_forehead) | ||
self.ax4_plot, = self.ax4.plot(self.x_data, self.signal.r_ear) | ||
|
||
self.ax1.set_ylim([self.low, self.high]) | ||
self.ax2.set_ylim([self.low, self.high]) | ||
self.ax3.set_ylim([self.low, self.high]) | ||
self.ax4.set_ylim([self.low, self.high]) | ||
|
||
plt.ion() | ||
|
||
def show(self): | ||
plt.show(block=False) | ||
|
||
def refresh(self): | ||
time_now = datetime.now() | ||
if (time_now - self.last_refresh).total_seconds() > self.refresh_freq: | ||
self.last_refresh = time_now | ||
pass | ||
else: | ||
return | ||
|
||
if self.signal.do_fft: | ||
self.ax1_plot.set_ydata(self.signal.l_ear_fft[0:len(self.x_data)/2]) | ||
self.ax2_plot.set_ydata(self.signal.l_forehead_fft[0:len(self.x_data)/2]) | ||
self.ax3_plot.set_ydata(self.signal.r_forehead_fft[0:len(self.x_data)/2]) | ||
self.ax4_plot.set_ydata(self.signal.r_ear_fft[0:len(self.x_data)/2]) | ||
else: | ||
self.ax1_plot.set_ydata(self.signal.l_ear) | ||
self.ax2_plot.set_ydata(self.signal.l_forehead) | ||
self.ax3_plot.set_ydata(self.signal.r_forehead) | ||
self.ax4_plot.set_ydata(self.signal.r_ear) | ||
|
||
self.figure.canvas.draw() | ||
self.figure.canvas.flush_events() |