Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions Board.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
GANGLION = "Ganglion"
CYTON = "Cyton"
CYTON_DAISY = "Cyton-Daisy"
MUSE_2016_BLED = "Muse 2016 BLE Dongle"
MUSE_2_BLED = "Muse 2 BLE Dongle"
MUSE_S_BLED = "Muse S BLE Dongle"
MUSE_2016 = "Muse 2016"
MUSE_2 = "Muse 2"
MUSE_S = "Muse S"

Expand All @@ -41,7 +45,7 @@ def get_serial_port(board_id):
pass
else:
# didn't have the bad com port exeption
BoardShim.release_all_sessions()
board.release_session()
return params.serial_port

BoardShim.release_all_sessions()
Expand Down Expand Up @@ -138,12 +142,14 @@ def stop(self):


def get_board_id(data_type, hardware, model):
"""Gets the brainflow board_id from the given arguments
"""Gets the brainflow board_id from the given arguments. Note that BLED boards\
require a BLED112 dongle. Non BLED muse hardware is untested.

Args:
data_type (String): A string of either "Task live" or "Task simulate"
hardware (String): A string of either "Muse" or "OpenBCI"
model (String): A string of either "Muse 2", "Muse S", "Ganglion", "Cyton", or "Cyton-Daisy"
model (String): A string of either "Ganglion", "Cyton", or "Cyton-Daisy", "Muse 2016 BLE Dongle",
"Muse 2 BLE Dongle", "Muse S BLE Dongle", "Muse 2016", "Muse 2","Muse S"

Returns:
int: The board_id that brainflow uses internally to determine board type
Expand All @@ -158,10 +164,19 @@ def get_board_id(data_type, hardware, model):
elif model == CYTON_DAISY:
board_id = 2
elif hardware == MUSE:
if model == MUSE_2:
if model == MUSE_S_BLED:
board_id = 21
elif model == MUSE_2_BLED:
board_id = 22
elif model == MUSE_2016_BLED:
board_id = 42
elif model == MUSE_2:
board_id = 38
elif model == MUSE_S:
board_id = 21
board_id = 39
elif model == MUSE_2016:
board_id = 41

elif data_type == SIMULATE:
board_id = -1

Expand Down
19 changes: 3 additions & 16 deletions graph_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,8 @@ def __init__(
# save file should be an ok file name to save to with approriate ending ('.csv')
self.save_file = save_file
self.board_id = get_board_id(data_type, hardware, model)

self.exg_channels = BoardShim.get_exg_channels(self.board_id)
self.marker_channels = BoardShim.get_marker_channel(self.board_id)

self.sampling_rate = BoardShim.get_sampling_rate(self.board_id)
self.update_speed_ms = 50
self.window_size = 5
Expand All @@ -99,8 +98,6 @@ def __init__(

self.chan_num = len(self.exg_channels)
self.exg_channels = np.array(self.exg_channels)
self.marker_channels = np.array(self.marker_channels)
print('board decription {}'.format(BoardShim.get_board_descr(board_id)))

logger.debug('EXG channels is {}'.format(self.exg_channels))

Expand Down Expand Up @@ -130,7 +127,8 @@ def __init__(
def _init_timeseries(self):
self.plots = list()
self.curves = list()
for i in range(self.chan_num+1):
num_curves = self.chan_num
for i in range(num_curves):
p = self.graphWidget.addPlot(row=i, col=0)
p.showAxis("left", False)
p.setMenuEnabled("left", False)
Expand Down Expand Up @@ -184,15 +182,6 @@ def update(self):
FilterTypes.BUTTERWORTH.value,
0,
)
DataFilter.perform_bandpass(
data[channel],
self.sampling_rate,
51.0,
100.0,
2,
FilterTypes.BUTTERWORTH.value,
0,
)
DataFilter.perform_bandstop(
data[channel],
self.sampling_rate,
Expand All @@ -212,8 +201,6 @@ def update(self):
0,
)
self.curves[count].setData(data[channel].tolist())
self.curves[len(self.exg_channels)].setData(data[self.marker_channels].tolist())
logger.debug('Marker channel data was {}'.format(data[self.marker_channels].tolist()))
logger.debug('Graph window finished updating (successfully got data from board and applied it to graphs)')

def closeEvent(self, event):
Expand Down
42 changes: 28 additions & 14 deletions impedance_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,22 @@
from PyQt5.QtGui import QPainter, QBrush, QPen, QPolygon
import numpy as np
import statistics as stats
from multiprocessing import Process, Queue
import logging
log_file = "boiler.log"
logging.basicConfig(level=logging.INFO, filemode="a")

f = logging.Formatter(
"Logger: %(name)s: %(levelname)s at: %(asctime)s, line %(lineno)d: %(message)s"
)
stdout = logging.StreamHandler(sys.stdout)
boiler_log = logging.FileHandler(log_file)
stdout.setFormatter(f)
boiler_log.setFormatter(f)

logger = logging.getLogger("ImpedWindow")
logger.addHandler(boiler_log)
logger.addHandler(stdout)
logger.info("Program started at {}".format(time.time()))

from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds
from brainflow.data_filter import DataFilter, FilterTypes
Expand All @@ -48,6 +63,7 @@ def __init__(
board_id=None,
):
super().__init__()
logger.info('Initializing impedance window')

# Ensures that the user has not provided a muse, leading to
# hard to debug errors later.
Expand Down Expand Up @@ -181,6 +197,7 @@ def init_hardware(self):

# let's start eeg receiving!
# self.start_data_stream()
logger.info("Initializing hardware")

self.board = Board(board_id=self.board_id, serial_port=self.serial_port, manual_mode = True)
print(
Expand All @@ -196,6 +213,7 @@ def init_hardware(self):
# This wild string puts Cyton-Daisy into impedance mode.
# DO NOT CHANGE
# Think Pulse
logger.info("Configuring Cyton")
self.board.board.config_board(
"x1040010Xx2040010Xx3040010Xx4040010Xx5040010Xx6040010Xx7040010Xx8040010XxQ040010XxW040010XxE040010XxR040010XxT040010XxY040010XxU040010XxI040010X"
)
Expand All @@ -214,6 +232,7 @@ def init_hardware(self):
# ganglion impedances based on
# https://github.com/OpenBCI/brainflow/blob/master/tests/python/ganglion_resist.py
# expected result: 5 seconds of resistance data(unknown sampling rate) after that 5 seconds of exg data
logger.info("Configuring Ganglion")
self.board.board.config_board("z")
print('sent board z, not yet start stream')
self.board.board.start_stream(45000, None)
Expand All @@ -230,31 +249,26 @@ def init_hardware(self):

resistance_channels = BoardShim.get_resistance_channels (BoardIds.GANGLION_BOARD.value)
print (resistance_channels)
else:
logger.error('Impedance window cannote run using this hardware (Board ID: {}). Try an OpenBCI ganglion or cyton instead.'.format(self.board_id))

def closeEvent(self, event):
# this code will autorun just before the window closes
# we will check whether streams are running, if they are we will close them
print("close event works")
logger.info("Closing window")
self.finished = True
self.parent.impedance_window_open = False
self.on_end()


def loop_start(self):
print("starting loop")
logger.info("starting loop")
self.loop_running = True
self.loop_timer.timeout.disconnect()
self.loop_timer.timeout.connect(self.start_iteration)
self.loop_timer.start(1000)
self.update()

# def loop_end(self):
# print("ending loop")
# self.loop_running = False
# self.update()
# self.loop_timer.timeout.disconnect()
# self.loop_timer.timeout.connect(self.start_iteration)
# self.loop_timer.start(1000)

def start_iteration(self):
# called by hitting enter
Expand All @@ -274,14 +288,14 @@ def start_iteration(self):
# use stdev as proxy.
chan_rms_uV = np.sqrt(np.sum(self.data ** 2))
self.impedances[count] = ((stats.sqrt( 2.0 ) * (chan_rms_uV) * 1.0e-6) / 6.0e-9 - 2200)/1000
print(self.impedances)
logger.debug("Imedances: {}".format(self.impedances))
"""
HERE
"""
# need to do some smoothing from the past 6 seconds to take out instantaneous
self.loop_start()
else:
print("exiting")
logger.info("exiting")

def filter_custom(self, chan):
DataFilter.perform_highpass(
Expand Down Expand Up @@ -313,7 +327,7 @@ def display_instructions(self):

def keyPressEvent(self, event):
if event.key() == Qt.Qt.Key_Space:
print("received user input")
logger.info("received user input")
elif event.key() == Qt.Qt.Key_Return or event.key == Qt.Qt.Key_Enter:
if self.hardware_connected and not self.running_test:
self.running_test = True
Expand All @@ -323,7 +337,7 @@ def keyPressEvent(self, event):
def paintEvent(self, event):
# here is where we draw stuff on the screen
# you give drawing instructions in pixels - here I'm getting pixel values based on window size
print("paint event runs")
logger.info("paint event runs")
painter = QPainter(self)
if self.loop_running:
radius = self.geometry().width() // 18
Expand Down
70 changes: 9 additions & 61 deletions main_menu.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,5 @@
"""
TO DO:
Main Menu:
Add in hardware/model:
unicorn
muse (2/S)
Compartmentalize the board id grab in utils (pass in hardware/model/datatype)

Impedence menu
Look for muse impedance check scripts
Confirm that the OpenBCI Impedence checks are working properly

For time sync - add back in pyLSL?

Render GA ERPs in results window from the either the baseline or the session
Choose from baseline/session

Logisitics:
Send Paul another Muse and possibly an arduino + light?

M todo
order of events lets you try and fauil tomopen graph wo selecting com port
one dropdown for hardware (<-eden no likey)
implement impedanece for all,not just cyton daisy

add support for non openbci hardware
add option to not import tensorflow
in train model, has hard coded 16 channel # (fix)



opens windows:
graph window - shows live timeseries
-potentially make it configurable
- label on garph which line is which channel by chcking hardware
impedance window
-curently hacked together, obnly cyton daiusy
-implement with other
arduino
-debug requires putting in 1
-preset for neuorstimduino
- need dosc for how to upload script to arduino using arduino ide, attach led
- currently provides a way to turn led on arduino on and off on command
baseline
- basically like the oddball window
- outputs eeg file in brainflow format
- new plan: use pylsl sender to constantly grab brainflow and events and send them together, so ww can be sure of times
saving
- sqlite prob overkill
- use numpy
- later maybe add sqlite to use if run for long time
remove unecessary windows
- we don't need a model window with tensorflow to train a thing. this isn't koalacademy
ADD SIMULATE AS HARDWARE OPTION
make board id happen in menu window so not passing raw srtrings between windows

This is the main menu. It starts all the other programs as directed by the user.

"""

Expand All @@ -69,7 +15,8 @@
import time
import os
import logging
from Board import BCI, CONNECT, CYTON, CYTON_DAISY, GANGLION, MUSE, MUSE_2, MUSE_S, SIMULATE, get_board_id
from Board import BCI, CONNECT, CYTON, CYTON_DAISY, GANGLION, MUSE, MUSE_2, MUSE_S, MUSE_2016, \
MUSE_S_BLED, MUSE_2_BLED, MUSE_2016_BLED, SIMULATE, get_board_id


# Creates the global logger
Expand Down Expand Up @@ -97,7 +44,7 @@
# results not implemented yet
from graph_window import graph_win

if False: # debugging... remebeber to put the tf imports back in session_window
if False: # debugging... remember to put the tf imports back in session_window
import tensorflow as tf

if sys.platform == "win32":
Expand Down Expand Up @@ -358,9 +305,7 @@ def handle_hardware_choice(self):
if self.hardware_dropdown.currentText() == BCI:
self.model_dropdown.addItems([GANGLION, CYTON, CYTON_DAISY])
elif self.hardware_dropdown.currentText() == MUSE:
self.model_dropdown.addItems([MUSE_2, MUSE_S])
elif self.hardware_dropdown.currentText() == "Blueberry":
self.model_dropdown.addItem("Prototype")
self.model_dropdown.addItems([MUSE_2016_BLED, MUSE_2_BLED, MUSE_S_BLED])

def handle_model_choice(self):
"""Handles changes to the model dropdown"""
Expand Down Expand Up @@ -400,7 +345,10 @@ def handle_type_choice(self):
self.data_type = self.type_dropdown.currentText()
self.graph_window_button.setEnabled(True)
self.baseline_window_button.setEnabled(True)
self.impedance_window_button.setEnabled(True)
if self.hardware_dropdown.currentText() != MUSE:
self.impedance_window_button.setEnabled(True)
else:
logger.info('Impedance window is not available for Muse hardware. Try OpenBCI instead.')
if self.data_type == CONNECT:
self.title.setText("Select BCI Hardware Port")
self.bci_port.setEnabled(True)
Expand Down