diff --git a/.gitignore b/.gitignore
index 77156f6..72212cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,4 @@ build/
.pytest_cache/
.DS_Store
temp.txt
-*.pyc
+*.pyc
\ No newline at end of file
diff --git a/README.md b/README.md
index ab28ea5..9c1a770 100755
--- a/README.md
+++ b/README.md
@@ -35,3 +35,9 @@
[prefix (default: /rtbio)]
--filename [filename]
[filename (default: temp.txt)]
+
+
+To run from Python:
+- You can use the `art-bio.yaml` file to intitialize the Anaconda environment with the necessary packages
+- Run from terminal with for example the command `python art-bio.py -d biosignalsplux -c recg ws` to try the banana demo
+- The biosignalsplux library files for Win64/Python 3.8 are included by default, for other platforms copy the files from the corresponding folder at [https://github.com/biosignalsplux/python-samples/tree/master/PLUX-API-Python3](https://github.com/biosignalsplux/python-samples/tree/master/PLUX-API-Python3) to the `devices/pluxlib` folder.
\ No newline at end of file
diff --git a/argparser.py b/argparser.py
index e31faf2..c15761b 100644
--- a/argparser.py
+++ b/argparser.py
@@ -46,13 +46,21 @@ def getSamplingFrequency(args):
def getFilename(args):
if '--filename' in args:
- index = next(i for i, arg in enumerate(args) if arg == '--filename' or arg == '-f')
+ index = next(i for i, arg in enumerate(args) if arg == '--filename')
try:
return args[index+1]
except IndexError:
raise ValueError('filename is empty')
return None
+def getPort(args):
+ if '--port' in args:
+ index = next(i for i, arg in enumerate(args) if arg == '--port')
+ try:
+ return args[index+1]
+ except IndexError:
+ raise ValueError('port is empty')
+ return None
source_types = ['ecg', 'eda', 'eeg', 'emg']
diff --git a/art-bio.py b/art-bio.py
index be0ec6d..ca654ae 100644
--- a/art-bio.py
+++ b/art-bio.py
@@ -1,3 +1,4 @@
+# coding=UTF-8
readme = '''
🐍 rt-bio : A Real-Time BIOsignal feature extraction tool 🦆
https://github.com/vatte/rt-bio
@@ -42,6 +43,7 @@
import argparser as parser
from devices import *
+from devices.Biosignalsplux import Biosignalsplux
from init_sources import init_sources
from router import Router
@@ -58,6 +60,7 @@
router.osc_address = '127.0.0.1:4810'
router.osc_prefix = '/rtbio'
router.filename = 'temp.txt'
+router.ws_port = 5678
args = sys.argv
@@ -82,6 +85,10 @@
device_list = OpenBCI.list_devices(None)
for i, dev in enumerate(device_list):
print('[{}] {}'.format(i, dev))
+ elif(device_name == 'biosignalsplux'):
+ device_list = Biosignalsplux.list_devices(None)
+ for i, dev in enumerate(device_list):
+ print('[{}] {}'.format(i, dev))
else:
raise ValueError('No such device: ' + device_name)
print('exiting...')
@@ -102,6 +109,11 @@
if filename_arg:
router.filename = filename_arg
+#get ws port from args
+port_arg = parser.getPort(args)
+if port_arg:
+ router.ws_port = port_arg
+
#get sampling_frequency from args
sampling_frequency_arg = parser.getSamplingFrequency(args)
@@ -134,6 +146,14 @@
def noDigital():
raise ValueError('openbci has no digital output defined')
router.digital_out_func = noDigital
+elif device_name == 'biosignalsplux':
+ device = Biosignalsplux(device_index)
+ if 'biosignalsplux' in config:
+ channels = {}
+ for k in config['biosignalsplux']:
+ channels[k] = [ int(c) for c in config['biosignalsplux'][k].split(',') ]
+ device.channel_map = channels
+
else:
raise ValueError('No such device: ' + device_name)
@@ -145,15 +165,34 @@ def noDigital():
#start streaming
device.start(sampling_frequency, sources.keys())
+## filter experiment here for powerline
+# from scipy import signal
+
+# b,a = signal.iirnotch(50, 25, 100)
+
+# print("B: " + str(b) + "A: " + str(a))
+
+# z = [0, 0, 0, 0, 0, 0, 0, 0]
+# for i, zz in enumerate(z):
+# z[i] = signal.lfilter_zi(b, a)
+
try:
while True:
# Read samples
samples = device.read()
+ #print(samples)
for source in samples.keys():
features = []
for i, channel in enumerate(samples[source]):
- features.append(sources[source][i].add_data(channel))
+ #for j, s in enumerate(channel):
+ #y, z[i] = signal.lfilter(b,a,[s], zi = z[i])
+ #channel[j] = y[0]
+ if source != 'unknown' and source in sources:
+ features.append(sources[source][i].add_data(channel))
router.route_data(source, connections, features, samples[source])
-except KeyboardInterrupt:
+except (Exception, KeyboardInterrupt) as e:
device.close()
+ if router.ws_server:
+ router.ws_server.stop()
+ raise(e)
diff --git a/art-bio.yaml b/art-bio.yaml
new file mode 100644
index 0000000..0f3ec35
--- /dev/null
+++ b/art-bio.yaml
@@ -0,0 +1,31 @@
+name: art-bio
+channels:
+ - defaults
+dependencies:
+ - blas=1.0=mkl
+ - ca-certificates=2021.10.26=haa95532_2
+ - certifi=2021.10.8=py38haa95532_0
+ - icc_rt=2019.0.0=h0cc432a_1
+ - intel-openmp=2021.4.0=haa95532_3556
+ - mkl=2021.4.0=haa95532_640
+ - mkl-service=2.4.0=py38h2bbff1b_0
+ - mkl_fft=1.3.1=py38h277e83a_0
+ - mkl_random=1.2.2=py38hf11a4ad_0
+ - numpy=1.21.2=py38hfca59bb_0
+ - numpy-base=1.21.2=py38h0829f74_0
+ - openssl=1.1.1l=h2bbff1b_0
+ - pip=21.0.1=py38haa95532_0
+ - pyserial=3.5=py38haa95532_0
+ - python=3.8.12=h6244533_0
+ - scipy=1.7.1=py38hbe87c03_2
+ - six=1.16.0=pyhd3eb1b0_0
+ - sqlite=3.36.0=h2bbff1b_0
+ - vc=14.2=h21ff451_1
+ - vs2015_runtime=14.27.29016=h5e58377_2
+ - wheel=0.37.0=pyhd3eb1b0_1
+ - wincertstore=0.2=py38haa95532_2
+ - pip:
+ - bitalino==1.2.1
+ - python-osc==1.8.0
+ - setuptools==57.5.0
+ - websockets==10.1
diff --git a/biosignals.bat b/biosignals.bat
new file mode 100644
index 0000000..b94e080
--- /dev/null
+++ b/biosignals.bat
@@ -0,0 +1,5 @@
+@ECHO on
+call C:\Users\MTG-user\anaconda3\Scripts\activate.bat activate art-bio
+cd C:\Users\MTG-user\Desktop\art-bio-biosignalsplux
+python art-bio.py -d biosignalsplux -c reeg ws -c recg ws -c reda ws -c reeg file -c recg file -c reda file --filename readings.txt
+PAUSE
\ No newline at end of file
diff --git a/config.ini b/config.ini
index 905c137..3b8861b 100644
--- a/config.ini
+++ b/config.ini
@@ -1,7 +1,12 @@
#bitalino channel configuration for custom setups
#analog inputs are starting with index 0
[bitalino]
-emg: 0
+emg: 0,4
ecg: 1
eda: 2
-eeg: 3
\ No newline at end of file
+eeg: 3
+
+[biosignalsplux]
+eeg: 0,1
+ecg: 2
+eda: 3
\ No newline at end of file
diff --git a/devices/Biosignalsplux.py b/devices/Biosignalsplux.py
new file mode 100644
index 0000000..a1d26a3
--- /dev/null
+++ b/devices/Biosignalsplux.py
@@ -0,0 +1,133 @@
+# biosignalsplux
+
+import glob
+import sys
+import platform
+import time
+
+from threading import Thread
+
+sys.path.append('devices/pluxlib') #add the plux library for your platform to this folder
+import plux
+
+from .Device import Device
+
+class Biosignalsplux(Device):
+
+ def __init__(self, dev_i = 0):
+
+ #default channel numbers for biosignalsplux
+ self.channel_map = {
+ 'emg': [0],
+ 'ecg': [1],
+ 'eda': [2],
+ 'eeg': [3]
+ }
+
+ # find device
+ print('Looking for biosignalsplux device')
+ retries = 0
+ self.device_list = []
+
+ while retries < 3 and len(self.device_list) == 0:
+ self.device_list = self.list_devices()
+
+ if len(self.device_list) == 0:
+ raise Exception('No biosignalsplux device found')
+
+ try:
+ device_address = self.device_list[dev_i]
+ except IndexError:
+ raise Exception('No biosignalsplux found with index ' + str(dev_i))
+
+ print("Connecting to " + device_address)
+
+ class PluxDevice(plux.SignalsDev):
+ def __init__(self, address):
+ plux.MemoryDev.__init__(address)
+ self.started = True
+ self.in_samples = []
+
+ def onRawFrame(self, nSeq, data): # onRawFrame takes three arguments
+ self.in_samples.append(data)
+ if not self.started:
+ return True
+ return False
+
+ # Connect to biosignalsplux
+ self.device = PluxDevice(device_address)
+
+ #find all devices
+ def list_devices(self):
+ devices = []
+ for mac in plux.BaseDev.findDevices():
+ devices.append(mac[0])
+ return devices
+
+ #start streaming
+ def start(self, fs, channels):
+ self.fs = fs
+ self.channels = []
+ chans = []
+ #order channels for biosignalsplux
+ for c in self.channel_map.keys():
+ if c in channels:
+ for index in self.channel_map[c]:
+ chans.append(index)
+ chans.sort()
+ self.n_chans = chans[-1] + 1
+ for c in range(self.n_chans):
+ found = False
+ for k in self.channel_map:
+ if c in self.channel_map[k]:
+ self.channels.append(k)
+ found = True
+ break
+ if not found:
+ self.channels.append('unknown')
+ print(self.channels)
+
+ codes = [ 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF] #codes for biosignalsplux device for different n_chans
+
+ # Start Acquisition
+ self.started = True
+ self.device.started = True
+ self.device.start(fs, codes[self.n_chans-1], 16)
+
+ def myfunc():
+ self.device.loop()
+
+ t = Thread(target=myfunc)
+ t.start()
+
+
+
+ #read samples (blocking)
+ def read(self):
+ samples = {}
+
+ while len(self.device.in_samples) == 0:
+ time.sleep(0.01)
+
+ for i, c in enumerate(self.channels):
+ if not c in samples:
+ samples[c] = []
+ samples[c].append([s[i] for s in self.device.in_samples])
+ #if 'eeg' in samples:
+ # samples['eeg'] = [ [ [samples['eeg'][i][j] for i in range(len(samples['eeg'])) ] for j in range(len(samples['eeg'][0]))] ]
+ #print(samples)
+ self.device.in_samples = [] # clear the sample buffer
+ return samples
+
+ #stop streaming
+ def stop(self):
+ # Stop acquisition
+ self.started = False
+ self.device.started = False
+
+ #close connection
+ def close(self):
+ if self.started:
+ self.started = False
+ self.device.started = False
+
\ No newline at end of file
diff --git a/devices/pluxlib/LibFT4222-64.dll b/devices/pluxlib/LibFT4222-64.dll
new file mode 100644
index 0000000..b385fcb
Binary files /dev/null and b/devices/pluxlib/LibFT4222-64.dll differ
diff --git a/devices/pluxlib/LibFT4222AB-64.dll b/devices/pluxlib/LibFT4222AB-64.dll
new file mode 100644
index 0000000..0defcf9
Binary files /dev/null and b/devices/pluxlib/LibFT4222AB-64.dll differ
diff --git a/devices/pluxlib/msvcp100.dll b/devices/pluxlib/msvcp100.dll
new file mode 100644
index 0000000..6f0cdf1
Binary files /dev/null and b/devices/pluxlib/msvcp100.dll differ
diff --git a/devices/pluxlib/msvcr100.dll b/devices/pluxlib/msvcr100.dll
new file mode 100644
index 0000000..b1c3a5e
Binary files /dev/null and b/devices/pluxlib/msvcr100.dll differ
diff --git a/devices/pluxlib/plux.pyd b/devices/pluxlib/plux.pyd
new file mode 100644
index 0000000..2fd7818
Binary files /dev/null and b/devices/pluxlib/plux.pyd differ
diff --git a/examples/banana_demo/banana.jpg b/examples/banana_demo/banana.jpg
new file mode 100644
index 0000000..d078ecb
Binary files /dev/null and b/examples/banana_demo/banana.jpg differ
diff --git a/examples/banana_demo/banana.png b/examples/banana_demo/banana.png
new file mode 100644
index 0000000..ba6f3a1
Binary files /dev/null and b/examples/banana_demo/banana.png differ
diff --git a/examples/banana_demo/heart.png b/examples/banana_demo/heart.png
new file mode 100644
index 0000000..28dced8
Binary files /dev/null and b/examples/banana_demo/heart.png differ
diff --git a/examples/banana_demo/lungs1.png b/examples/banana_demo/lungs1.png
new file mode 100644
index 0000000..ea2904b
Binary files /dev/null and b/examples/banana_demo/lungs1.png differ
diff --git a/examples/banana_demo/superbanana.wav b/examples/banana_demo/superbanana.wav
new file mode 100644
index 0000000..9b39993
Binary files /dev/null and b/examples/banana_demo/superbanana.wav differ
diff --git a/examples/banana_demo/superbanana2.wav b/examples/banana_demo/superbanana2.wav
new file mode 100644
index 0000000..ac8513f
Binary files /dev/null and b/examples/banana_demo/superbanana2.wav differ
diff --git a/examples/banana_demo/visualize_banana.html b/examples/banana_demo/visualize_banana.html
new file mode 100644
index 0000000..348c08f
--- /dev/null
+++ b/examples/banana_demo/visualize_banana.html
@@ -0,0 +1,190 @@
+
+
+
+ Raw data visualizer
+
+
+
+ Grab the banana! Firmly, but gently...
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/banana_demo/visualize_biosignals.html b/examples/banana_demo/visualize_biosignals.html
new file mode 100644
index 0000000..14a4019
--- /dev/null
+++ b/examples/banana_demo/visualize_biosignals.html
@@ -0,0 +1,422 @@
+
+
+
+ Raw data visualizer
+
+
+
+
+
+ La sesión ha iniciado.
+
+
+
+ Ritmo cardíaco
+
+ Respiración
+
+
+ Alpha
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/receive_eda_to_pd.pd b/examples/receive_eda_to_pd.pd
index 89d466e..735eb8c 100644
--- a/examples/receive_eda_to_pd.pd
+++ b/examples/receive_eda_to_pd.pd
@@ -1,31 +1,167 @@
-#N canvas 363 113 450 300 10;
-#X obj 40 80 mrpeach/udpreceive 4810;
+#N canvas 141 134 1477 835 10;
#X obj 40 105 mrpeach/unpackOSC;
#X floatatom 40 154 5 0 0 0 - - -;
-#N canvas 0 23 450 300 smooth-more 0;
+#N canvas 0 23 1215 808 smooth-more 0;
#X obj 301 138 f;
#X obj 252 222 +;
#X obj 243 137 t f b;
#X obj 234 52 inlet;
#X obj 247 262 outlet;
-#X obj 302 192 * 0.95;
-#X obj 242 163 * 0.05;
-#X connect 0 0 5 0;
+#X obj 242 163 * 0.01;
+#X obj 302 192 * 0.99;
+#X connect 0 0 6 0;
#X connect 1 0 0 1;
#X connect 1 0 4 0;
-#X connect 2 0 6 0;
+#X connect 2 0 5 0;
#X connect 2 1 0 0;
#X connect 3 0 2 0;
-#X connect 5 0 1 1;
-#X connect 6 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 1 1;
#X restore 40 177 pd smooth-more;
#X floatatom 40 200 5 0 0 0 - - -;
#X obj 40 130 route /rtbio/eda/raw /rtbio/eda/edr;
#X obj 143 155 print EDR:;
#X text 35 26 COMMAND: art-bio -c reda osc;
-#X connect 0 0 1 0;
-#X connect 1 0 5 0;
+#N canvas 0 50 450 250 (subpatch) 0;
+#X array array1 1000 float 1;
+#A 0 35335.8 35380.2 35424.9 35469.7 35514.6 35559.4 35603.9 35648.6
+35693.6 35738.1 35782.2 35826.3 35870.7 35915.6 35960.3 36005 36049.1
+36093.4 36137.9 36182.3 36226.1 36269.6 36313.5 36357.3 36401 36444.7
+36488.2 36531.5 36574.8 36617.8 36661.1 36705 36748.2 36791.3 36834.5
+36877.5 36920.7 36963.6 37006.6 37049.8 37091.7 37134.4 37176.2 37218.2
+37261.1 37302.7 37344.8 37387.1 37429.2 37471.2 37512.5 37555 37596.3
+37638.3 37679.8 37721.3 37762.3 37804.6 37845.9 37887.4 37927.8 37968.3
+38008.6 38050.3 38091.9 38132.8 38172.7 38213.2 38253.7 38294.7 38334.8
+38375.4 38416.2 38456.8 38497.7 38537.7 38578.4 38618 38657.9 38696.9
+38736.8 38777.5 38817.4 38857.3 38895.9 38935.3 38975 39015.1 39055.9
+39096.9 39136.1 39175.5 39213.7 39252.8 39292.4 39332.9 39373.5 39413.2
+39452 39490.8 39530.7 39571.1 39611.8 39651.8 39691.7 39731 39769.7
+39809.4 39850.1 39890.1 39930 39968.6 40007.4 40046.8 40086.7 40126
+40164.9 40203.3 40242.1 40280.6 40318.8 40357.9 40396.8 40435 40472.6
+40509.7 40546.6 40583.8 40621.7 40659.4 40696.5 40733.5 40770 40806.7
+40843.1 40879.4 40916 40951.3 40986.8 41022.8 41057.8 41092.7 41127.7
+41162.4 41197.8 41232.5 41267.2 41301 41334.6 41369.4 41404 41437.7
+41472 41506.3 41539.6 41573.4 41607.7 41641.6 41675.3 41708 41740.8
+41773.8 41806.4 41839.1 41872 41904.3 41935.9 41967.5 41999.7 42031.2
+42063.3 42095.4 42127.4 42159 42190.1 42220.8 42251.8 42282.9 42313.7
+42344.2 42374.4 42404.8 42434.9 42465 42494.2 42524 42553.8 42583.4
+42613 42642.1 42670.6 42699.5 42728.7 42757.9 42786.4 42814.9 42843.4
+42870.9 42898.6 42926.6 42954.8 42982.9 43010.4 43038 43064.2 43092.2
+43120.1 43147.2 43174.8 43202.3 43229.8 43257 43284.4 43311.5 43338.1
+43364.4 43391.4 43418.4 43444.9 43472 43499.2 43525.6 43551 43577.8
+43603.9 43630.9 43657.7 43684.6 43710.3 43736.6 43763.3 43790.3 43817.3
+43844.1 43870.5 43896.2 43922.5 43948.2 43974.5 44000.8 44027.2 44053.2
+44079.3 44105.6 44131 44157 44182.5 44207.8 44233.5 44259.5 44285 44310.6
+44336.4 44361.3 44386.2 44411.8 44437.4 44462.9 44487.7 44512.9 44538
+44562.4 44586.6 44611.6 44636.4 44660.5 44685.2 44710.1 44734.4 44759
+44783.4 44807 44831.7 44856.1 44880.3 44904.3 44928.5 44952.4 44975.9
+44999.8 45023.8 45047.1 45071 45094.5 45117 45139.8 45163.2 45186.7
+45210.3 45233.9 45256.5 45279.9 45302.2 45325.4 45348.5 45369.9 45391.6
+45414.2 45436.6 45459.2 45481.6 45503.5 45525.6 45547.7 45569.7 45591.8
+45613.8 45635.5 45657.3 45678.7 45699.5 45721.4 45743.1 45764.9 45786.3
+45807.1 45827.6 45848.8 45869.9 45890.6 45911.4 45932.2 45952.1 45972.6
+45993.4 46013.4 46032.2 46051.1 46070.9 46091.3 46110.8 46131.3 46151.3
+46170.4 46189.9 46209.6 46229.2 46248.4 46268 46287.2 46306 46323.4
+46342.5 46362.1 46381.5 46400.4 46417.1 46434.4 46452.5 46471.4 46490.1
+46508.9 46527 46544.4 46561.3 46579.4 46597.8 46616.6 46634.8 46652.1
+46669.5 46686.7 46704.2 46722.2 46739.7 46756.9 46773.8 46790.6 46807.3
+46824.7 46841.8 46858.5 46875.4 46891.5 46907.8 46924.9 46942.1 46958.9
+46975.3 46991.1 47006.8 47022.3 47038.1 47054.7 47070.8 47086.5 47101.5
+47117.3 47132.7 47149 47164.9 47180.8 47196.6 47211.9 47227.7 47243.3
+47258.8 47274.5 47289.9 47305.3 47320.7 47335.6 47350.8 47365.9 47380.5
+47395.4 47410.4 47425.5 47440.2 47455.3 47469.6 47484.2 47498.8 47513
+47526.3 47541 47555.2 47569.7 47584 47598.5 47612.5 47626.8 47641 47655.3
+47669.5 47683.8 47697.8 47712.1 47725.9 47739.9 47753 47767.3 47780.9
+47794.9 47808.7 47822.5 47836.2 47850.3 47863.7 47877.4 47889.9 47903.6
+47917 47930.5 47943.8 47956.8 47969.8 47982.7 47995.7 48008.8 48022.5
+48035.1 48047.7 48060.3 48073.8 48086.8 48099.6 48112.3 48124.9 48137.3
+48150.3 48162.9 48175.6 48188.4 48201.5 48213.8 48225.9 48238.6 48250.9
+48263.7 48277 48289.6 48302.1 48314.6 48325.6 48338.3 48351.1 48363.8
+48376 48388.6 48400.6 48411.3 48423.8 48436.6 48448.5 48458.9 48470.9
+48482.5 48494.6 48506.4 48518.5 48530.9 48542.8 48554.8 48566.5 48578.3
+48589.8 48600.6 48611.8 48623 48634.3 48645.5 48657 48668.2 48679.2
+48689.8 48700.4 48710.8 48721.4 48732.1 48741.9 48752.2 48762.2 48772.3
+48782.5 48792.3 48802.4 48811.5 48821.7 48831.3 48840.8 48850.1 48860.1
+48870.2 48880.1 48890.1 48900 48909.4 48918.7 48928.4 48937.5 48947.2
+48956.7 48966.1 48975.4 48984.5 48993.5 49002.1 49010.8 49019.7 49028.6
+49037.4 49046.3 49055 49063.5 49071.2 49079.3 49087.1 49095.6 49103.9
+49112.5 49119.2 49127.4 49135.8 49143.1 49151.3 49159.7 49168.5 49176.6
+49184.6 49193 49201.5 49209.6 49217.6 49225.8 49233.7 49241.5 49249.2
+49256.9 49264.9 49272.4 49280.5 49288.6 49296.4 49304.2 49312 49320.4
+49328.2 49333.4 49341.3 49347.1 49354.3 49361.4 49369.8 49378.5 49387
+49394.8 49401.6 49408.2 49414.6 49422.1 49429.5 49437.9 49445.9 49453
+49459 49465.3 49471.1 49479.3 49487.1 49494.7 49501 49507.3 49513.9
+49520.7 49528.2 49535.3 49540.5 49547.4 49553.3 49559.7 49565.6 49572.3
+49578.4 49584.6 49591.2 49596.2 49602.1 49608.2 49614 49620.3 49626.6
+49632.7 49638.1 49643.4 49649.1 49654 49659.6 49665.2 49670.8 49676.1
+49681.4 49686.5 49691.3 49696.8 49701.5 49706.5 49711.3 49715.9 49720.4
+49725.2 49729.9 49733.9 49738 49741.9 49744.6 49748.4 49752.4 49756.5
+49760.3 49763.1 49765.2 49768 49771.5 49774.9 49777.9 49780.2 49781.5
+49784.4 49787.1 49789.6 49792.4 49794.9 49797.4 49799.8 49801.5 49803.4
+49805.4 49806.7 49808.7 49810.7 49811.9 49813.7 49815.1 49816.4 49818.1
+49820.1 49821.7 49822.8 49824 49824.9 49826.2 49827.5 49829 49829.6
+49829.7 49830.4 49829.9 49831 49831.8 49832.6 49833 49833 49833.5 49834.2
+49834.6 49835.5 49834.1 49834.3 49834.8 49834.7 49835.2 49835.5 49835.9
+49835.7 49836 49836 49835.9 49834.5 49834.8 49834.5 49834.3 49834.4
+49834.3 49834.1 49834 49833.8 49832.9 49832 49831.2 49830.5 49829.9
+49829.3 49828.6 49827.9 49826.9 49825.9 49825 49823.9 49822.7 49821.7
+49820.9 49819.9 49818.7 49817.5 49815.7 49814.4 49812.7 49811.2 49810
+49808.1 49805.5 49803.8 49801.5 49799.9 49797.4 49795.3 49793.6 49791.3
+49788.6 49786.5 49784.8 49782.8 49780.4 49777.7 49775.6 49773.3 49770.5
+49768.4 49766.2 49763.6 49760.6 49757.8 49754.8 49751.4 49748.8 49745.4
+49742.9 49740.2 49737.8 49735.2 49731.5 49728.9 49726.1 49723.5 49721
+49717.5 49713.9 49711.4 49708.6 49705.8 49703 49699.8 49696.8 49693.8
+49690.3 49687.3 49684.3 49681.3 49678.3 49675.1 49671.8 49667.5 49664.1
+49660.3 49657.2 49654.1 49651.2 49648.5 49645.3 49642.4 49638.4 49635.4
+49631.6 49628.5 49624.7 49621.6 49618.5 49614.5 49611.1 49607.9 49604.6
+49600.8 49597.3 49593.5 49590 49586.5 49583 49579.1 49575.1 49571.2
+49567.2 49563.2 49559.2 49555.4 49551.5 49547.6 49543.5 49538.9 49534.7
+49530.8 49526.3 49521.9 49517.9 49514 49509.8 49505.8 49501.2 49497.2
+49493.3 49489 49485.4 49481.3 49477.3 49472.4 49468.6 49462 49458.3
+49454.4 49450 49446.4 49442.6 49438.7 49433.3 49429.1 49424.9 49419
+49415.1 49411.1 49407.3 49403.3 49399.3 49395.4 49391 49387 49383.1
+49378.1 49372.8 49368.8 49364.6 49360.4 49355.9 49351.5 49345.2 49341.1
+49336.5 49331.8 49327.1 49322.9 49318.2 49312.4 49308.3 49303.9 30538
+30568.7 30599.5 30630 30661.5 30693.2 30723.6 30755.7 30788.7 30821.3
+30855 30888.6 30923.4 30958.7 30992.8 31027.6 31062.3 31097.4 31132.9
+31168.5 31204.4 31240.2 31276.5 31313.1 31349.9 31386.9 31424.4 31462.2
+31499.6 31537.5 31575 31612.2 31651.7 31690.2 31728.3 31767.4 31807
+31846.2 31885.7 31926.1 31966.8 32007.4 32048.2 32089.6 32131.4 32174.4
+32216.7 32259.2 32302.8 32345.9 32389.6 32433.9 32478 32520.6 32563.7
+32607 32651.7 32695.5 32739.6 32783.6 32827.8 32871.3 32915.5 32957.8
+33000.9 33044.1 33088.3 33132.7 33176.5 33220.7 33264.1 33306.5 33350.6
+33394.3 33437.7 33480.5 33523.8 33566.1 33610 33652.9 33696.9 33740.1
+33783.5 33827.3 33870 33914.1 33956.3 34002 34046.2 34090.8 34135 34177.4
+34222.4 34265.5 34310.1 34355 34399.7 34443.9 34487.7 34532.2 34577.9
+34622.9 34667.5 34712.4 34756 34800.8 34845.5 34889.3 34933.4 34977.8
+35022.3 35067.3 35112 35156.2 35201.1 35246.2 35290.8;
+#X coords 0 65000 999 0 600 400 1 0 0;
+#X restore 432 136 graph;
+#X obj 223 413 tabwrite array1;
+#X obj 270 309 + 1;
+#X obj 203 313 0;
+#X obj 191 235 t b;
+#X obj 232 499 print;
+#X obj 310 344 % 1000;
+#X obj 47 263 send eda;
+#X obj 365 59 r data;
+#X obj 36 327 send fundamental;
+#X obj 36 295 / 80;
+#X obj 41 80 mrpeach/udpreceive 4811;
+#X connect 0 0 4 0;
+#X connect 1 0 2 0;
#X connect 2 0 3 0;
-#X connect 3 0 4 0;
-#X connect 5 0 2 0;
-#X connect 5 1 6 0;
+#X connect 3 0 11 0;
+#X connect 3 0 8 0;
+#X connect 3 0 14 0;
+#X connect 3 0 17 0;
+#X connect 4 0 1 0;
+#X connect 4 1 5 0;
+#X connect 9 0 13 0;
+#X connect 10 0 9 0;
+#X connect 10 0 8 1;
+#X connect 11 0 10 0;
+#X connect 13 0 10 1;
+#X connect 15 0 4 0;
+#X connect 17 0 16 0;
+#X connect 18 0 0 0;
diff --git a/examples/receive_eeg_to_pd.pd b/examples/receive_eeg_to_pd.pd
index f6fbb80..6cf816d 100644
--- a/examples/receive_eeg_to_pd.pd
+++ b/examples/receive_eeg_to_pd.pd
@@ -1,4 +1,4 @@
-#N canvas 159 56 1212 620 10;
+#N canvas 58 261 1247 635 10;
#X obj 37 48 mrpeach/unpackOSC;
#X floatatom 37 134 10 0 0 0 - - -;
#X floatatom 102 134 10 0 0 0 - - -;
@@ -10,39 +10,47 @@
#N canvas 0 50 1377 540 graph 0;
#N canvas 350 172 1009 430 (subpatch) 0;
#X array \$0_array 500 float 1;
-#A 0 -76 -87 -65 -205 -281 -428 -464 -150 87 506 506 506 506 506 506
-506 506 506 506 506 506 506 506 506 506 506 238 55 -136 165 -100 -145
--180 -84 -119 -135 130 53 -40 132 212 243 341 85 328 323 188 506 251
-233 166 -48 -163 -252 -241 -199 -185 -119 -182 -181 -204 -281 -324
--281 -269 -313 -50 -236 -218 -189 -277 -339 -261 -190 -398 -452 -426
--344 -245 -181 -277 -241 -281 -248 -299 -91 -42 8 -12 -93 -189 -165
--206 -194 -203 -147 -129 -81 -40 -101 -143 15 24 22 12 83 23 -150 -104
--224 -124 -1 -205 -196 -180 -279 -229 -215 -295 -208 -188 -44 -148
--157 -210 -250 -305 -177 -180 -127 -262 -235 -186 -23 24 64 65 197
-341 327 175 162 112 6 28 147 53 -71 -128 -127 -254 -85 -76 -96 -512
--512 -512 -512 -512 -512 -512 -512 -512 -512 -512 -512 -467 -243 -288
-121 11 105 266 386 476 506 388 506 506 506 506 506 267 506 453 506
-492 506 506 506 167 -33 -115 -63 -139 -349 -512 -512 -512 -512 -512
--512 -512 -512 -512 -75 506 506 506 506 506 506 506 506 506 506 506
-506 506 506 506 506 506 506 506 506 506 506 506 506 476 348 213 246
-283 199 85 71 100 138 217 134 208 163 223 64 49 99 110 167 105 191
-187 164 229 316 331 206 263 199 69 -60 -161 -186 -402 -287 -151 -168
--298 -244 -229 -174 -203 -168 -288 -304 -415 -383 -336 -328 -333 -166
--167 -261 -458 -467 -447 -341 -302 -250 -251 -301 -478 -186 -289 -128
--305 -209 -212 -111 -178 -154 -383 -512 -428 -344 -190 -187 -123 -28
-66 101 72 75 129 52 -25 -112 -261 -377 -410 -477 -499 -303 -282 -316
--276 -237 -107 -200 -210 -220 -98 -88 -50 -33 -73 -72 39 63 -18 106
-46 243 -62 17 62 231 -512 -512 -512 -512 -512 -512 -512 -512 -353 -512
--512 -512 -433 -328 -257 -157 -68 -133 -58 182 75 277 418 149 -184
--512 -512 92 -276 -42 -147 -127 -316 -360 -280 -37 -409 -96 102 78
--61 309 326 -156 -100 -128 -208 -187 -336 -260 -136 -466 -323 -428
--319 111 -319 -208 -42 97 -221 -177 -130 -217 -180 -83 81 -17 66 60
-10 169 181 129 276 335 394 287 143 337 177 211 342 346 391 106 126
-506 468 399 494 441 370 437 329 485 432 443 506 354 506 317 215 506
-368 287 372 408 396 18 91 36 222 214 29 289 321 338 314 244 238 219
-49 86 192 352 76 333 273 159 179 150 111 480 177 101 134 155 161 217
-53 225 177 130 22 82 119 225 -13 -98 -51 -80;
-#X coords 0 400 499 -400 500 100 1 0 0;
+#A 0 64920 -466 64928 -464 64932 -463 64930 -464 64948 -464 64936 -466
+-465 -465 -464 -463 64924 -462 64936 -466 64936 -460 -466 -463 -466
+-465 64932 -465 64932 64920 -464 -466 64928 -462 64928 -465 64928 -466
+-465 -460 -465 -461 -462 -463 -462 64940 64936 64936 64936 64936 64936
+-464 64912 -466 -465 -464 -466 -464 64928 -465 64936 -464 -462 -464
+64924 -462 64936 -466 -460 -466 64928 -460 -466 -464 64928 -466 64940
+-464 -465 -464 -465 -466 64928 -463 64952 -466 -465 -466 -466 -464
+64920 -461 -465 -465 -466 64912 64916 64932 64936 -462 64940 -465 -464
+-466 -465 64936 64920 -461 -459 -466 -464 -464 -465 61280 64932 64928
+64928 -466 64936 -466 64924 -465 -465 -466 64940 -466 -464 -466 -465
+-465 -466 64944 64928 64924 64940 64920 64936 64932 64932 -463 -459
+-465 -465 -467 -467 -466 -466 -464 -466 -466 -465 -465 -466 64920 64928
+-459 -464 -466 64928 64925 64928 64932 64940 -465 64950 -464 -466 -466
+-466 -465 64920 -465 64936 -465 -464 -467 64916 -460 -464 -464 64928
+-460 -464 -465 -465 -465 -461 -464 64940 64944 64940 64936 -465 -465
+-465 64924 -464 64924 -461 -465 64932 64932 -464 -462 -466 -466 64924
+64928 64928 64928 64936 64924 64924 64936 64924 64924 64940 64920 64944
+64928 -466 -466 -462 -465 -466 -464 -465 64928 64936 -461 -464 -465
+-464 -465 -465 -465 -466 -466 64932 64936 64936 64948 -455 -464 -464
+-466 64928 64928 64944 64932 -462 -465 -465 -465 -466 -465 -466 -465
+64916 64920 -465 64920 64928 64924 64924 64928 64916 64932 64940 -455
+-464 -466 -465 -464 64936 64932 -465 -465 64944 -464 -466 -465 64928
+64936 64944 64928 64936 64924 64928 64928 -465 -465 64920 64928 -464
+64920 64932 64940 64928 64952 64932 64932 64932 64924 64924 64920 64932
+64944 64924 64932 64928 64936 64936 64928 64940 64933 64936 64940 -461
+-465 -465 -465 -466 64934 -463 -465 -465 -464 -464 -465 -464 -466 64920
+64912 64936 64936 64940 64924 64940 64932 64936 64932 64938 64940 64932
+-459 -466 -464 -465 -466 -466 -465 -466 -466 -466 -464 -465 -465 -465
+-466 -464 -466 -467 -466 -464 -466 -465 -466 -464 -465 -466 -464 -465
+-466 -464 -465 -465 -466 -465 -466 -466 -465 -465 -464 -465 -466 64928
+64940 64932 64936 64936 64940 64946 64948 64932 64936 64944 64928 64928
+64944 64928 64936 64936 64940 64932 64940 64928 64944 64932 64936 64936
+64944 64928 -464 -465 -466 -465 -465 -464 64924 64928 64940 64928 64944
+64932 64936 64928 64944 64936 64940 64932 64928 64936 64936 64940 64932
+64944 64932 64936 64940 64940 64932 64928 64920 64936 64920 64936 64936
+64936 64944 64936 64941 64936 64932 64928 64936 64940 64940 64936 64936
+64936 64928 64920 64936 64936 64944 64940 64928 64928 64928 64920 64940
+64932 64924 64924 64932 64932 64932 64912 -465 64944 -465 64932 -465
+64932 -463 -462 -465 -463 -462 -465 44308 64936 64928 64932 -464 64936
+-465 -465 -466;
+#X coords 0 65000 499 0 690 170 1 0 0;
#X restore 304 124 graph;
#X obj 172 301 + 1;
#X obj 155 258 0;
@@ -59,34 +67,41 @@
#X connect 4 0 2 1;
#X connect 6 0 7 0;
#X connect 7 0 3 0;
-#X coords 0 -1 1 1 510 130 1 300 100;
+#X coords 0 0 1 100000 700 200 1 300 100;
#X restore 299 189 pd graph;
#N canvas 0 23 450 300 baseline 0;
#X obj 84 90 f;
#X obj 107 42 inlet;
#X obj 146 126 +;
-#X obj 146 102 * 0.001;
-#X obj 177 127 * 0.999;
#X obj 69 49 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X text 39 50 init;
#X obj 156 185 outlet;
-#X connect 0 0 4 0;
-#X connect 0 0 3 0;
+#X obj 146 102 * 0.001;
+#X obj 178 127 * 0.999;
+#X connect 0 0 6 0;
+#X connect 0 0 7 0;
#X connect 1 0 0 1;
-#X connect 1 0 3 0;
-#X connect 2 0 4 0;
+#X connect 1 0 6 0;
+#X connect 2 0 5 0;
#X connect 2 0 7 0;
-#X connect 3 0 2 0;
-#X connect 4 0 2 1;
-#X connect 5 0 0 0;
+#X connect 3 0 0 0;
+#X connect 6 0 2 0;
+#X connect 7 0 2 1;
#X coords 0 -1 1 1 60 40 1 30 30;
#X restore 52 157 pd baseline;
#X obj 45 205 -;
#X floatatom 45 235 5 0 0 0 - - -;
+#X obj 70 318 s alpha;
+#X floatatom 80 200 5 0 0 0 - - -;
+#X obj 464 67 s data;
+#X obj 187 219 vsl 50 300 100 300 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 16998 1;
#X connect 0 0 6 0;
+#X connect 0 0 13 0;
#X connect 1 0 8 0;
#X connect 1 0 9 0;
+#X connect 1 0 14 0;
#X connect 5 0 0 0;
#X connect 6 0 1 0;
#X connect 6 1 2 0;
@@ -94,4 +109,6 @@
#X connect 6 3 4 0;
#X connect 6 4 7 0;
#X connect 8 0 9 1;
+#X connect 8 0 12 0;
#X connect 9 0 10 0;
+#X connect 10 0 11 0;
diff --git a/examples/visualize.html b/examples/visualize.html
index 45fc613..5c27e35 100644
--- a/examples/visualize.html
+++ b/examples/visualize.html
@@ -3,7 +3,7 @@
Raw data visualizer
-
+
diff --git a/init_sources.py b/init_sources.py
index d2bcae2..78b731c 100644
--- a/init_sources.py
+++ b/init_sources.py
@@ -19,10 +19,7 @@ def init_sources(connections, channel_map, fs):
elif source == 'emg':
sources[source].append(MusclePower(fs))
elif source == 'eeg':
- #have to get eeg chan numbers from somewhere FIX THIS
- num_chans = 1 if fs == 100 else 8
- print('number of chans {}'.format(num_chans))
- sources[source].append(Oscillations(fs, num_chans, 256, 0.8,
+ sources[source].append(Oscillations(fs, 256, 0.8,
{
'theta': [4.0, 8.0],
'alpha': [8.0, 13.0],
diff --git a/physiology/HeartRate.py b/physiology/HeartRate.py
index a1ab578..a5be043 100755
--- a/physiology/HeartRate.py
+++ b/physiology/HeartRate.py
@@ -10,27 +10,35 @@
class HeartRate(DataCollector):
def __init__(self, _Fs, _filter_r):
- DataCollector.__init__(self, _Fs)
self.filter_r = _filter_r
+ self.Fs = _Fs
+ self.initialize()
+
+
+ def initialize(self):
+ DataCollector.__init__(self, self.Fs)
+
+ #todo: stores unnecessarily all the previous data
+
self.clead = []
self.filtered_clead = []
- self.emg_filter_r = int(0.5*_Fs/34)
- self.clead_filter_r = int(0.5*_Fs/24)
+ self.emg_filter_r = int(0.5*self.Fs/34)
+ self.clead_filter_r = int(0.5*self.Fs/24)
self.initialized = False
self.init_time = 5
self.beats = []
self.last = 0
- self.detect_interval = int(0.2*_Fs)
+ self.detect_interval = int(0.2*self.Fs)
self.r = 0
self.rr = 0
self.RR = [0, 0, 0, 0, 0]
self.r_i = -1
- self.f_interval = int(_Fs*0.35)
- self.f_interval2 = int(_Fs*0.05)
+ self.f_interval = int(self.Fs*0.35)
+ self.f_interval2 = int(self.Fs*0.05)
def add_data(self, new_data):
self.data.extend(new_data)
@@ -57,6 +65,16 @@ def add_data(self, new_data):
ibis = self.detect_beats(0)
elif self.initialized:
ibis = self.detect_beats(last_clead_i)
+
+ #if len(ibis) > 0:
+ # print(ibis)
+
+ #reinitialize if no beats are detected for duration of self.init_time
+ if len(self.filtered_clead) - self.last > self.init_time * self.Fs:
+ print('re-initializing...')
+ self.initialize()
+ print(len(self.filtered_clead), self.last)
+
return {'ibi': ibis}
diff --git a/physiology/Oscillations.py b/physiology/Oscillations.py
index 62d91a6..25bf652 100644
--- a/physiology/Oscillations.py
+++ b/physiology/Oscillations.py
@@ -1,25 +1,20 @@
import numpy as np
class Oscillations:
- def __init__(self, sample_rate, num_chans, fft_size, overlap, freqs):
+ def __init__(self, sample_rate, fft_size, overlap, freqs):
self.idx = 0
self.sample_rate = sample_rate
- self.num_chans = num_chans
self.fft_size = fft_size
self.overlap = overlap
self.hanning = np.hanning(fft_size)
self.pad = np.zeros(fft_size)
self.freqs = freqs
- self.spectdata = [np.zeros(fft_size) for _ in range(num_chans)]
+ self.spectdata = np.zeros(fft_size)
def add_data(self, samples):
freqs = None
for i in range(len(samples)):
- #out = []
- #for c in samples:
- # out.append(c[i])
- #freqs = self.add_samples(out)
- freqs_in = self.add_samples(samples[i])
+ freqs_in = self.add_sample(samples[i])
#freqs = freqs_in if freqs_in != None else freqs
if freqs_in != None:
if freqs == None:
@@ -32,36 +27,34 @@ def add_data(self, samples):
return freqs
- def add_samples(self, samples):
- for i, sample in enumerate(samples):
- self.spectdata[i][self.idx] = sample
+ def add_sample(self, sample):
+ self.spectdata[self.idx] = sample
self.idx += 1
if self.idx >= self.fft_size:
- result = [[] for i in range(self.num_chans)]
+ #result = [[] for i in range(self.num_chans)]
freqpower = {}
for f in self.freqs:
- freqpower[f] = [0 for _ in range(len(samples))]
- raw_electrodes = [[] for _ in range(len(self.spectdata))]
- for i, electrode_data in enumerate(self.spectdata):
- windowed = electrode_data * self.hanning
- padded = np.append(windowed, self.pad)
- spectrum = np.fft.fft(padded)
- autopower = abs(spectrum * np.conj(spectrum))
- result[i] = autopower[:self.fft_size]
-
- powerspect = 10.0 * np.log10(np.power(abs(spectrum),2))
- freqC = np.fft.fftfreq(len(padded), 1.0/self.sample_rate)
-
- for f in self.freqs:
- freq = self.freqs[f]
- start = np.where((freqC <= freq[0]) & (freqC >= 0))[0][-1]
- stop = np.where((freqC >= freq[1]) & (freqC >= 0))[0][0]
- freqpower[f][i] = np.mean(powerspect[start:stop]) + np.mean(powerspect[-stop-1:-start-1])
-
- self.idx = int(self.fft_size * self.overlap)
- raw_electrodes[i] = [float(electrode_data[a]) for a in range(self.idx, len(electrode_data))]
- if self.idx > 0:
- electrode_data[:self.idx] = electrode_data[-self.idx:]
+ freqpower[f] = 0
+ #raw_electrode = []
+ windowed = self.spectdata * self.hanning
+ padded = np.append(windowed, self.pad)
+ spectrum = np.fft.fft(padded)
+ autopower = abs(spectrum * np.conj(spectrum))
+ result = autopower[:self.fft_size]
+
+ powerspect = 10.0 * np.log10(np.power(abs(spectrum),2))
+ freqC = np.fft.fftfreq(len(padded), 1.0/self.sample_rate)
+
+ for f in self.freqs:
+ freq = self.freqs[f]
+ start = np.where((freqC <= freq[0]) & (freqC >= 0))[0][-1]
+ stop = np.where((freqC >= freq[1]) & (freqC >= 0))[0][0]
+ freqpower[f] = np.mean(powerspect[start:stop]) + np.mean(powerspect[-stop-1:-start-1])
+
+ self.idx = int(self.fft_size * self.overlap)
+ #raw_electrode = [float(self.spectdata[a]) for a in range(self.idx, len(self.spectdata))]
+ if self.idx > 0:
+ self.spectdata[:self.idx] = self.spectdata[-self.idx:]
return freqpower
return None
diff --git a/router.py b/router.py
index c518ee5..7eae571 100644
--- a/router.py
+++ b/router.py
@@ -15,10 +15,14 @@ def __init__(self):
self.osc_prefix = None
self.osc_address = None
self.filename = None
+ self.ws_port = None
def digital_out():
pass
self.digital_out_func = digital_out
+ #self.current_time = time.time()
+ self.ini_time = 0
+
def init_destinations(self, connections):
destinations = []
@@ -31,54 +35,63 @@ def init_destinations(self, connections):
self.osc_client = udp_client.SimpleUDPClient(address_port[0], int(address_port[1]))
if 'file' in destinations:
self.file_handle = open(self.filename, 'w')
- print("initializing file " + self.filename)
+ print("initializing file" + self.filename)
+
+ self.ini_time = time.time()
+ self.file_handle.write('{}: {}\n'.format('initial time',self.ini_time))
+
+
if 'ws' in destinations:
- self.ws_server = WSServer()
+ self.ws_server = WSServer(self.ws_port)
def route_data(self, source, connections, features, raw_data):
source_connections = []
+
+ current_time = time.time()
+
if source in connections:
source_connections += connections[source]
- current_time = time.time()
-
+
+
# raw data
if 'r' + source in connections:
source_connections += connections['r' + source]
- for destination in connections['r' + source]:
- osc_dest = '/{}/raw'.format(source)
- if destination == 'osc':
- for i, channel in enumerate(raw_data):
+ for destination in connections['r' + source]:
+ for i, channel in enumerate(raw_data):
+ src = source
+ if i > 0:
+ src += str(i)
+
+ osc_dest = '/{}/raw'.format(src)
+ if destination == 'osc':
for data in channel:
osc_address = self.osc_prefix + osc_dest
- if i > 0:
- osc_address += str(i)
self.osc_client.send_message(osc_address, data)
- elif destination == 'file':
- self.file_handle.write('{} {}: {}\n'.format(current_time, osc_dest, str(raw_data)))
- elif destination == 'ws':
- self.ws_server.add_message('{}|{}/{}'.format(current_time, osc_dest, str(raw_data)))
+ elif destination == 'file':
+ self.file_handle.write('{} {}: {}\n'.format(current_time-self.ini_time, osc_dest, str(raw_data)))
+ elif destination == 'ws':
+ self.ws_server.add_message('{}|{}/{}'.format(current_time, osc_dest, str(raw_data)))
# features
if features:
for destination in source_connections:
for i, features_chan in enumerate(features):
- for feature in features_chan.keys():
- osc_dest = '/{}/{}'.format(source, feature)
- if i > 0:
- osc_dest += str(i)
- for data in features_chan[feature]:
- if destination == 'osc':
- self.osc_client.send_message(self.osc_prefix + osc_dest, data)
- elif destination == 'file':
- self.file_handle.write('{} {}: {}\n'.format(current_time, osc_dest, str(data)))
- elif destination == 'ws':
- self.ws_server.add_message('{}|{}/{}'.format(current_time, osc_dest, str(raw_data)))
- elif destination == 'digital':
- if self.digital_out_func:
- self.digital_out_func()
-
-
-
+ src = source
+ if i > 0:
+ src += str(i)
+ if features_chan:
+ for feature in features_chan.keys():
+ osc_dest = '/{}/{}'.format(src, feature)
+ for data in features_chan[feature]:
+ if destination == 'osc':
+ self.osc_client.send_message(self.osc_prefix + osc_dest, data)
+ elif destination == 'file':
+ self.file_handle.write('{} {}: {}\n'.format(current_time-self.ini_time, osc_dest, str(data)))
+ elif destination == 'ws':
+ self.ws_server.add_message('{}|{}/{}'.format(current_time, osc_dest, str(data)))
+ elif destination == 'digital':
+ if self.digital_out_func:
+ self.digital_out_func()
diff --git a/wsserver.py b/wsserver.py
index 61a6187..ede4c46 100644
--- a/wsserver.py
+++ b/wsserver.py
@@ -2,20 +2,28 @@
import asyncio
import websockets
from threading import Thread
-
+import ssl
+import pathlib
all_websockets = []
+
class WSServer():
- def __init__(self):
+ def __init__(self, port = 5678):
self.all_websockets = []
- self.run()
+ self.loop = None
+ #self.ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+ #path_cert = pathlib.Path(__file__).with_name("cert.pem")
+ #path_key = pathlib.Path(__file__).with_name("key.pem")
+ #self.ssl_context.load_cert_chain(path_cert, keyfile=path_key)
+
+ self.run(port)
def add_message(self, message):
for websocket in self.all_websockets:
websocket.art_bio_messages.append(message)
- def run(self):
+ def run(self, port):
async def data(websocket, path):
self.all_websockets.append(websocket)
websocket.art_bio_messages = []
@@ -27,15 +35,22 @@ async def data(websocket, path):
await asyncio.sleep(0.1)
def run_server(loop):
+ print('websocket server starting on port ' + str(port))
asyncio.set_event_loop(loop)
- server = websockets.serve(data, '127.0.0.1', 5678)
+ #server = websockets.serve(data, '127.0.0.1', port, ssl=self.ssl_context)
+ server = websockets.serve(data, '127.0.0.1', port)
loop.run_until_complete(server)
loop.run_forever()
- loop = asyncio.new_event_loop()
- thread = Thread(target = run_server, args=(loop,))
+ self.loop = asyncio.new_event_loop()
+ thread = Thread(target = run_server, args=(self.loop,))
thread.start()
+ def stop(self):
+ self.loop.call_soon_threadsafe(self.loop.stop)
+ self.loop.call_soon_threadsafe(self.loop.close)
+ #self.loop.close()
+
if __name__ == "__main__":
wsserver = WSServer()
@@ -44,4 +59,4 @@ def run_server(loop):
while True:
wsserver.add_message('/ecg/raw/[1 2 3 4 5]')
- time.sleep(1)
\ No newline at end of file
+ time.sleep(1)