-
Notifications
You must be signed in to change notification settings - Fork 261
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #962 from OpenBCI/development
GUI 5.0.4
- Loading branch information
Showing
27 changed files
with
824 additions
and
621 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
|
@@ -25,3 +25,4 @@ libBoardController.so | |
libDataHandler.so | ||
libGanglionLib.so | ||
libGanglionScan.so | ||
libunicorn.so |
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
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,147 @@ | ||
############################################################################# | ||
## BrainFlow + LSL ## | ||
## Use BrainFlow to read data from board send it as an LSL stream ## | ||
############################################################################# | ||
|
||
# Install dependencies with: | ||
# pip install --upgrade numpy brainflow pylsl | ||
|
||
# Here are example commands using Cyton and get_exg_channels()from BrainFlow. This has only been tested with Cyton + Dongle, for now. | ||
|
||
# Mac: | ||
# python3 Networking-Test-Kit/LSL/brainflow_lsl.py --board-id 2 --serial-port /dev/cu.usbserial-DM00D7TW --name test --data-type EXG --channel-names 1,2,3,4,5,6,7,8 --uid brainflow | ||
|
||
# Windows: | ||
# python3 Networking-Test-Kit/LSL/brainflow_lsl.py --board-id 2 --serial-port COM3 --name test --data-type EXG --channel-names 1,2,3,4,5,6,7,8 --uid brainflow | ||
|
||
import argparse | ||
import time | ||
import numpy as np | ||
|
||
from queue import Queue | ||
|
||
import brainflow | ||
from brainflow.board_shim import BoardShim, BrainFlowInputParams | ||
from brainflow.data_filter import DataFilter, FilterTypes, AggOperations | ||
|
||
from pylsl import StreamInfo, StreamOutlet, local_clock | ||
|
||
def channel_select(board, board_id, data_type): | ||
switcher = { | ||
'EXG': board.get_exg_channels(board_id), | ||
# can add more | ||
} | ||
|
||
return switcher.get(data_type, "error") | ||
|
||
def main(): | ||
BoardShim.enable_dev_board_logger() | ||
|
||
parser = argparse.ArgumentParser() | ||
|
||
# brainflow params - use docs to check which parameters are required for specific board, e.g. for Cyton set serial port | ||
parser.add_argument('--timeout', type=int, help='timeout for device discovery or connection', required=False, default=0) | ||
parser.add_argument('--ip-address', type=str, help='ip address', required=False, default='') | ||
parser.add_argument('--board-id', type=int, help='board id, check docs to get a list of supported boards', required=True) | ||
parser.add_argument('--serial-port', type=str, help='serial port', required=False, default='') | ||
parser.add_argument('--streamer-params', type=str, help='streamer params', required=False, default='') | ||
|
||
# LSL params | ||
parser.add_argument('--name', type=str, help='name', required=True) | ||
parser.add_argument('--data-type', type=str, help='data type', required=True) | ||
parser.add_argument('--channel-names', type=str, help='channel names', required=True) | ||
parser.add_argument('--uid', type=str, help='uid', required=True) | ||
|
||
args = parser.parse_args() | ||
|
||
# brainflow initialization | ||
params = BrainFlowInputParams() | ||
params.serial_port = args.serial_port | ||
params.ip_address = args.ip_address | ||
board = BoardShim(args.board_id, params) | ||
|
||
# LSL initialization | ||
channel_names = args.channel_names.split(',') | ||
n_channels = len(channel_names) | ||
srate = board.get_sampling_rate(args.board_id) | ||
info = StreamInfo(args.name, args.data_type, n_channels, srate, 'double64', args.uid) | ||
outlet = StreamOutlet(info) | ||
fw_delay = 0 | ||
|
||
# prepare session | ||
board.prepare_session() | ||
|
||
# send commands to the board for every channel. Cyton has 8 Channels. Here, we turn off every channel except for 1 and 8. | ||
# This is here for testing purposes. | ||
#board.config_board("x1000110X") #Lower the gain to 1x on channel 1 | ||
#board.config_board("x1061000X") | ||
#board.config_board("x2161000X") | ||
#board.config_board("x3161000X") | ||
#board.config_board("x4161000X") | ||
#board.config_board("x5161000X") | ||
#board.config_board("x6161000X") | ||
#board.config_board("x7161000X") | ||
#board.config_board("x8060110X") | ||
|
||
# start stream | ||
board.start_stream(45000, args.streamer_params) | ||
time.sleep(1) | ||
start_time = local_clock() | ||
sent_samples = 0 | ||
queue = Queue(maxsize = 5*srate) | ||
chans = channel_select(board, args.board_id, args.data_type) | ||
|
||
# Vars for filters | ||
applyBandStop = True | ||
applyBandPass = True | ||
bandStopFrequency = 60.0 | ||
bp_lowerBound = 5.0 | ||
bp_upperBound = 50.0 | ||
bp_centerFreq = (bp_upperBound + bp_lowerBound) / 2.0; | ||
bp_bandWidth = bp_upperBound - bp_lowerBound | ||
|
||
|
||
# read data with brainflow and send it via LSL | ||
print("Now sending data...") | ||
while True: | ||
data = board.get_board_data()[chans] | ||
|
||
# It's best to apply filters on the receiving end, but this is here just for testing purposes. | ||
""" | ||
for chan in range(len(chans)): | ||
if applyBandStop: | ||
DataFilter.perform_bandstop(data[chan], | ||
BoardShim.get_sampling_rate(args.board_id), | ||
bandStopFrequency, | ||
4.0, | ||
2, | ||
FilterTypes.BUTTERWORTH.value, | ||
0); | ||
if applyBandPass: | ||
DataFilter.perform_bandpass( | ||
data[chan], | ||
BoardShim.get_sampling_rate(args.board_id), | ||
bp_centerFreq, | ||
bp_bandWidth, | ||
2, | ||
FilterTypes.BUTTERWORTH.value, | ||
0); | ||
""" | ||
|
||
for i in range(len(data[0])): | ||
queue.put(data[:,i].tolist()) | ||
elapsed_time = local_clock() - start_time | ||
required_samples = int(srate * elapsed_time) - sent_samples | ||
if required_samples > 0 and queue.qsize() >= required_samples: | ||
mychunk = [] | ||
|
||
for i in range(required_samples): | ||
mychunk.append(queue.get()) | ||
stamp = local_clock() - fw_delay | ||
outlet.push_chunk(mychunk, stamp) | ||
sent_samples += required_samples | ||
time.sleep(1) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
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 |
---|---|---|
@@ -0,0 +1,58 @@ | ||
"""Example program to show how to read a multi-channel time series from LSL.""" | ||
import time | ||
from pylsl import StreamInlet, resolve_stream | ||
from time import sleep | ||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
from matplotlib import style | ||
from collections import deque | ||
|
||
# first resolve an EEG stream on the lab network | ||
print("looking for an EEG stream...") | ||
streams = resolve_stream('type', 'EXG') | ||
|
||
# create a new inlet to read from the stream | ||
inlet = StreamInlet(streams[0]) | ||
duration = 10 | ||
|
||
sleep(0) | ||
|
||
def testLSLSamplingRate(): | ||
start = time.time() | ||
numSamples = 0 | ||
numChunks = 0 | ||
|
||
while time.time() <= start + duration: | ||
# get chunks of samples | ||
chunk, timestamp = inlet.pull_chunk() | ||
if timestamp: | ||
numChunks += 1 | ||
for sample in chunk: | ||
numSamples += 1 | ||
|
||
print( "Number of Chunks == {}".format(numChunks) ) | ||
print( "Avg Sampling Rate == {}".format(numSamples / duration) ) | ||
|
||
|
||
# testLSLSamplingRate() | ||
|
||
print("gathering data to plot...") | ||
|
||
def testLSLPulseData(): | ||
start = time.time() | ||
raw_pulse_signal = [] | ||
|
||
while time.time() <= start + duration: | ||
chunk, timestamp = inlet.pull_chunk() | ||
if timestamp: | ||
for sample in chunk: | ||
print(sample) | ||
raw_pulse_signal.append(sample[0]) | ||
|
||
# print(raw_pulse_signal) | ||
print( "Avg Sampling Rate == {}".format(len(raw_pulse_signal) / duration) ) | ||
plt.plot(raw_pulse_signal) | ||
plt.ylabel('raw analog signal') | ||
plt.show() | ||
|
||
testLSLPulseData() |
Oops, something went wrong.