From cfbf82884af19a62198b33dc7b69626ef6bd8e5b Mon Sep 17 00:00:00 2001 From: jdpigeon Date: Tue, 8 May 2018 20:07:49 -0400 Subject: [PATCH] Reconciled branch differences; added smart filenames to both record and recordlsl --- muselsl/muselsl/lsl_record.py | 9 ++++++--- muselsl/muselsl/muse-lsl.py | 24 +++++++++++++--------- muselsl/muselsl/muse.py | 30 +-------------------------- muselsl/muselsl/muse_record.py | 37 +++++++++++++++++++--------------- 4 files changed, 42 insertions(+), 58 deletions(-) diff --git a/muselsl/muselsl/lsl_record.py b/muselsl/muselsl/lsl_record.py index 0b2fd5a..6c768a9 100644 --- a/muselsl/muselsl/lsl_record.py +++ b/muselsl/muselsl/lsl_record.py @@ -2,10 +2,13 @@ import pandas as pd from pylsl import StreamInlet, resolve_byprop from sklearn.linear_model import LinearRegression +from time import time, strftime, gmtime -def record(duration, filename): - # dejitter timestamps - dejitter = False + +def record(duration, filename=None, dejitter=False): + if not filename: + filename = ("recording_%s.csv" % + strftime("%Y-%m-%d-%H.%M.%S", gmtime())) print("looking for an EEG stream...") streams = resolve_byprop('type', 'EEG', timeout=2) diff --git a/muselsl/muselsl/muse-lsl.py b/muselsl/muselsl/muse-lsl.py index 537c2e1..c336de7 100644 --- a/muselsl/muselsl/muse-lsl.py +++ b/muselsl/muselsl/muse-lsl.py @@ -5,7 +5,6 @@ import re import os import configparser -from time import time, strftime, gmtime class Program: @@ -28,7 +27,7 @@ def __init__(self): -a --address device MAC address -n --name device name (e.g. Muse-41D2) -b --backend pygatt backend to use. can be auto, gatt or bgapi - -i --interface The interfact to use, 'hci0' for gatt or a com port for bgapi. + -i --interface the interfact to use, 'hci0' for gatt or a com port for bgapi. viewlsl Visualize EEG data from an LSL stream. -w --window window length to display in seconds. @@ -40,6 +39,7 @@ def __init__(self): recordlsl Record EEG data from an LSL stream. -d --duration duration of the recording in seconds. -f --filename name of the recording file. + -dj --dejitter whether to apply dejitter correction to timestamps. ''') parser.add_argument('command', help='Command to run.') @@ -62,7 +62,7 @@ def list(self): help="pygatt backend to use. can be auto, gatt or bgapi.") parser.add_argument("-i", "--interface", dest="interface", type=str, default=None, - help="The interface to use, 'hci0' for gatt or a com port for bgapi.") + help="the interface to use, 'hci0' for gatt or a com port for bgapi.") args = parser.parse_args(sys.argv[2:]) import muse_stream muses = muse_stream.list_muses(args.backend, args.interface) @@ -107,10 +107,13 @@ def record(self): help="pygatt backend to use. can be auto, gatt or bgapi") parser.add_argument("-i", "--interface", dest="interface", type=str, default=None, - help="The interface to use, 'hci0' for gatt or a com port for bgapi") + help="the interface to use, 'hci0' for gatt or a com port for bgapi") + parser.add_argument("-f", "--filename", + dest="filename", type=str, default=None, + help="name of the recording file.") args = parser.parse_args(sys.argv[2:]) import muse_record - muse_record.record(args.address, args.backend, args.interface, args.name) + muse_record.record(args.address, args.backend, args.interface, args.name, args.filename) def viewlsl(self): parser = argparse.ArgumentParser( @@ -140,17 +143,18 @@ def viewlsl(self): def recordlsl(self): parser = argparse.ArgumentParser(description='Record data from Muse.') - default_fname = ("data_%s.csv" % - strftime("%Y-%m-%d-%H.%M.%S", gmtime())) parser.add_argument("-d", "--duration", dest="duration", type=int, default=60, help="duration of the recording in seconds.") parser.add_argument("-f", "--filename", - dest="filename", type=str, default=default_fname, - help="Name of the recording file.") + dest="filename", type=str, default=None, + help="name of the recording file.") + parser.add_argument("-dj", "--dejitter", + dest="dejitter", type=bool, default=False, + help="whether to apply dejitter correction to timestamps.") args = parser.parse_args(sys.argv[2:]) import lsl_record - lsl_record.record(args.duration, args.filename) + lsl_record.record(args.duration, args.filename, args.dejitter) if __name__ == '__main__': diff --git a/muselsl/muselsl/muse.py b/muselsl/muselsl/muse.py index 6fbb67f..f7ac8e3 100644 --- a/muselsl/muselsl/muse.py +++ b/muselsl/muselsl/muse.py @@ -67,14 +67,6 @@ def connect(self, interface=None, backend='auto'): self.adapter = pygatt.BGAPIBackend(serial_port=self.interface) self.adapter.start() - print('started') - - if self.address is None: - address = self.find_muse_address(self.name) - if address is None: - raise(ValueError("Can't find Muse Device")) - else: - self.address = address self.device = self.adapter.connect(self.address) # subscribes to EEG stream @@ -94,31 +86,11 @@ def connect(self, interface=None, backend='auto'): self._subscribe_gyro() return True - + except (pygatt.exceptions.NotConnectedError, pygatt.exceptions.NotificationTimeout): print('Connection to', self.address, 'failed') return False - def find_muse_address(self, name=None): - if self.backend == 'bluemuse': - print('Not supported by bluemuse backend.') - return None - - """look for ble device with a muse in the name""" - list_devices = self.adapter.scan(timeout=10.5) - for device in list_devices: - if name: - if device['name'] == name: - print('Found device %s : %s' % (device['name'], - device['address'])) - return device['address'] - - elif 'Muse' in device['name']: - print('Found device %s : %s' % (device['name'], - device['address'])) - return device['address'] - - return None def _write_cmd(self, cmd): """Wrapper to write a command to the Muse device. diff --git a/muselsl/muselsl/muse_record.py b/muselsl/muselsl/muse_record.py index 282f52c..8251d6a 100644 --- a/muselsl/muselsl/muse_record.py +++ b/muselsl/muselsl/muse_record.py @@ -3,19 +3,24 @@ import numpy as np import pandas as pd -full_time = [] -full_data = [] -def __process__(data, timestamps): - full_time.append(timestamps) - full_data.append(data) - -def record(address, backend, interface, name): +def record(address, backend, interface, name, filename): if backend == 'bluemuse': - raise(NotImplementedError('Direct record not supported with BlueMuse background. Use lslrecord with BlueMuse instead.')) - return + raise(NotImplementedError( + 'Direct record not supported with BlueMuse backend. Use lslrecord instead.')) + + if not filename: + filename = ("recording_%s.csv" % + strftime("%Y-%m-%d-%H.%M.%S", gmtime())) + + eeg_samples = [] + timestamps = [] + + def save_eeg(new_samples, new_timestamps): + eeg_samples.append(new_samples) + timestamps.append(new_timestamps) - muse = Muse(address, __process__) + muse = Muse(address, save_eeg) muse.connect() muse.start() @@ -29,10 +34,10 @@ def record(address, backend, interface, name): muse.stop() muse.disconnect() - full_time = np.concatenate(full_time) - full_data = np.concatenate(full_data, 1).T - res = pd.DataFrame(data=full_data, - columns=['TP9', 'AF7', 'AF8', 'TP10', 'Right AUX']) + timestamps = np.concatenate(timestamps) + eeg_samples = np.concatenate(eeg_samples, 1).T + recording = pd.DataFrame(data=eeg_samples, + columns=['TP9', 'AF7', 'AF8', 'TP10', 'Right AUX']) - res['timestamps'] = full_time - res.to_csv('dump.csv', float_format='%.3f') + recording['timestamps'] = timestamps + recording.to_csv(filename, float_format='%.3f')