Skip to content

Commit

Permalink
INIT: first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamindeleener committed Aug 25, 2015
1 parent ea80d71 commit 9e5ba27
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 2 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015 PolyCortex
Copyright (c) 2015 Benjamin De Leener

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
24 changes: 23 additions & 1 deletion README.md
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
```
28 changes: 28 additions & 0 deletions eeg_display.py
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)
1 change: 1 addition & 0 deletions pymuse/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__author__ = 'benjamindeleener'
35 changes: 35 additions & 0 deletions pymuse/io.py
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)
36 changes: 36 additions & 0 deletions pymuse/signal.py
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)
68 changes: 68 additions & 0 deletions pymuse/viz.py
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()

0 comments on commit 9e5ba27

Please sign in to comment.