Spaces:
Sleeping
Sleeping
Yann Bouteiller
commited on
Commit
·
da5fc70
1
Parent(s):
45a88e4
updated version
Browse files- portiloop/capture.py +25 -18
- portiloop/detection.py +1 -1
- portiloop/notebooks/tests.ipynb +5 -39
- setup.py +2 -2
portiloop/capture.py
CHANGED
@@ -4,7 +4,6 @@ import sys
|
|
4 |
from time import sleep
|
5 |
import time
|
6 |
import numpy as np
|
7 |
-
import matplotlib.pyplot as plt
|
8 |
import os
|
9 |
from pathlib import Path
|
10 |
from datetime import datetime, timedelta
|
@@ -14,7 +13,6 @@ import shutil
|
|
14 |
from threading import Thread, Lock
|
15 |
import alsaaudio
|
16 |
|
17 |
-
import matplotlib.pyplot as plt
|
18 |
from EDFlib.edfwriter import EDFwriter
|
19 |
from scipy.signal import firwin
|
20 |
|
@@ -63,8 +61,8 @@ DEFAULT_FRONTEND_CONFIG = [
|
|
63 |
FRONTEND_CONFIG = [
|
64 |
0x3E, # ID (RO)
|
65 |
0x95, # CONFIG1 [95] [1, DAISY_EN(bar), CLK_EN, 1, 0, DR[2:0]] : Datarate = 500 SPS
|
66 |
-
|
67 |
-
|
68 |
0x00, # No lead-off
|
69 |
0x60, # CH1SET [60] [PD1, GAIN1[2:0], SRB2, MUX1[2:0]]
|
70 |
0x60, # CH2SET 66
|
@@ -76,8 +74,8 @@ FRONTEND_CONFIG = [
|
|
76 |
0x60, # CH8SET
|
77 |
0x04, # BIAS_SENSP 04
|
78 |
0x04, # BIAS_SENSN 04
|
79 |
-
|
80 |
-
|
81 |
0x00, # Normal lead-off
|
82 |
0x00, # Lead-off positive status (RO)
|
83 |
0x00, # Lead-off negative status (RO)
|
@@ -133,24 +131,20 @@ def mod_config(config, datarate, channel_modes):
|
|
133 |
elif chan_mode == 'disabled':
|
134 |
mod = mod | 0x81 # PDn = 1 and input shorted (001)
|
135 |
elif chan_mode == 'with bias':
|
|
|
136 |
bit_i = 1 << chan_i
|
137 |
config[13] = config[13] | bit_i
|
138 |
-
config[14] = config[14] | bit_i
|
139 |
-
bias_active = True
|
140 |
elif chan_mode == 'bias out':
|
141 |
-
mod = mod | 0x06 # MUX[2:0] = BIAS_DRP (110)
|
142 |
bias_active = True
|
|
|
143 |
else:
|
144 |
assert False, f"Wrong key: {chan_mode}."
|
145 |
config[n] = mod
|
146 |
-
print(f"DEBUG: new config[{n}]:{hex(config[n])}")
|
147 |
-
print(f"DEBUG: new config[13]:{hex(config[13])}")
|
148 |
-
print(f"DEBUG: new config[14]:{hex(config[14])}")
|
149 |
if bias_active:
|
150 |
-
config[3] = config[3] |
|
151 |
-
|
152 |
-
|
153 |
-
print(f"DEBUG: new config[3]:{hex(config[3])}")
|
154 |
return config
|
155 |
|
156 |
|
@@ -399,6 +393,17 @@ def _capture_process(p_data_o, p_msg_io, duration, frequency, python_clock, time
|
|
399 |
p_data_o.close()
|
400 |
|
401 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
402 |
class Capture:
|
403 |
def __init__(self, detector_cls=None, stimulator_cls=None):
|
404 |
# {now.strftime('%m_%d_%Y_%H_%M_%S')}
|
@@ -441,10 +446,12 @@ class Capture:
|
|
441 |
self._test_stimulus = False
|
442 |
|
443 |
mixers = alsaaudio.mixers()
|
444 |
-
if
|
|
|
|
|
|
|
445 |
self.mixer = alsaaudio.Mixer(control='PCM')
|
446 |
else:
|
447 |
-
assert len(mixers) > 0, 'No ALSA mixer found'
|
448 |
warnings.warn(f"Could not find mixer PCM, using {mixers[0]} instead.")
|
449 |
self.mixer = alsaaudio.Mixer(control=mixers[0])
|
450 |
self.volume = self.mixer.getvolume()[0] # we will set the same volume on all channels
|
|
|
4 |
from time import sleep
|
5 |
import time
|
6 |
import numpy as np
|
|
|
7 |
import os
|
8 |
from pathlib import Path
|
9 |
from datetime import datetime, timedelta
|
|
|
13 |
from threading import Thread, Lock
|
14 |
import alsaaudio
|
15 |
|
|
|
16 |
from EDFlib.edfwriter import EDFwriter
|
17 |
from scipy.signal import firwin
|
18 |
|
|
|
61 |
FRONTEND_CONFIG = [
|
62 |
0x3E, # ID (RO)
|
63 |
0x95, # CONFIG1 [95] [1, DAISY_EN(bar), CLK_EN, 1, 0, DR[2:0]] : Datarate = 500 SPS
|
64 |
+
0xC0, # CONFIG2 [C0] [1, 1, 0, INT_CAL, 0, CAL_AMP0, CAL_FREQ[1:0]]
|
65 |
+
0xE0, # CONFIG3 [E0] [PD_REFBUF(bar), 1, 1, BIAS_MEAS, BIASREF_INT, PD_BIAS(bar), BIAS_LOFF_SENS, BIAS_STAT] : Power-down reference buffer, no bias
|
66 |
0x00, # No lead-off
|
67 |
0x60, # CH1SET [60] [PD1, GAIN1[2:0], SRB2, MUX1[2:0]]
|
68 |
0x60, # CH2SET 66
|
|
|
74 |
0x60, # CH8SET
|
75 |
0x04, # BIAS_SENSP 04
|
76 |
0x04, # BIAS_SENSN 04
|
77 |
+
0x00, # LOFF_SENSP Lead-off on all positive pins?
|
78 |
+
0x00, # LOFF_SENSN Lead-off on all negative pins?
|
79 |
0x00, # Normal lead-off
|
80 |
0x00, # Lead-off positive status (RO)
|
81 |
0x00, # Lead-off negative status (RO)
|
|
|
131 |
elif chan_mode == 'disabled':
|
132 |
mod = mod | 0x81 # PDn = 1 and input shorted (001)
|
133 |
elif chan_mode == 'with bias':
|
134 |
+
bias_active = True
|
135 |
bit_i = 1 << chan_i
|
136 |
config[13] = config[13] | bit_i
|
137 |
+
# config[14] = config[14] | bit_i
|
|
|
138 |
elif chan_mode == 'bias out':
|
|
|
139 |
bias_active = True
|
140 |
+
mod = mod | 0x06 # MUX[2:0] = BIAS_DRP (110)
|
141 |
else:
|
142 |
assert False, f"Wrong key: {chan_mode}."
|
143 |
config[n] = mod
|
|
|
|
|
|
|
144 |
if bias_active:
|
145 |
+
config[3] = config[3] | 0x1c
|
146 |
+
for n, c in enumerate(config):
|
147 |
+
print(f"DEBUG: new config[{n}]:\t{c:08b}\t({hex(c)})")
|
|
|
148 |
return config
|
149 |
|
150 |
|
|
|
393 |
p_data_o.close()
|
394 |
|
395 |
|
396 |
+
class DummyAlsaMixer:
|
397 |
+
def __init__(self):
|
398 |
+
self.volume = 50
|
399 |
+
|
400 |
+
def getvolume(self):
|
401 |
+
return [self.volume]
|
402 |
+
|
403 |
+
def setvolume(self, volume):
|
404 |
+
self.volume = volume
|
405 |
+
|
406 |
+
|
407 |
class Capture:
|
408 |
def __init__(self, detector_cls=None, stimulator_cls=None):
|
409 |
# {now.strftime('%m_%d_%Y_%H_%M_%S')}
|
|
|
446 |
self._test_stimulus = False
|
447 |
|
448 |
mixers = alsaaudio.mixers()
|
449 |
+
if len(mixers) <= 0:
|
450 |
+
warnings.warn(f"No ALSA mixer found.")
|
451 |
+
self.mixer = DummyAlsaMixer()
|
452 |
+
elif 'PCM' in mixers:
|
453 |
self.mixer = alsaaudio.Mixer(control='PCM')
|
454 |
else:
|
|
|
455 |
warnings.warn(f"Could not find mixer PCM, using {mixers[0]} instead.")
|
456 |
self.mixer = alsaaudio.Mixer(control=mixers[0])
|
457 |
self.volume = self.mixer.getvolume()[0] # we will set the same volume on all channels
|
portiloop/detection.py
CHANGED
@@ -137,7 +137,7 @@ class SleepSpindleRealTimeDetector(Detector):
|
|
137 |
output_data_y = self.interpreters[idx].get_tensor(output_details[1]['index'])
|
138 |
|
139 |
output_scale, output_zero_point = output_details[1]["quantization"]
|
140 |
-
output_data_y =
|
141 |
|
142 |
if self.verbose:
|
143 |
print(f"Computed output {output_data_y} in {end_time - start_time} seconds")
|
|
|
137 |
output_data_y = self.interpreters[idx].get_tensor(output_details[1]['index'])
|
138 |
|
139 |
output_scale, output_zero_point = output_details[1]["quantization"]
|
140 |
+
output_data_y = (int(output_data_y) - output_zero_point) * output_scale
|
141 |
|
142 |
if self.verbose:
|
143 |
print(f"Computed output {output_data_y} in {end_time - start_time} seconds")
|
portiloop/notebooks/tests.ipynb
CHANGED
@@ -2,46 +2,12 @@
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
-
"execution_count":
|
6 |
-
"id": "
|
7 |
"metadata": {
|
8 |
"scrolled": false
|
9 |
},
|
10 |
-
"outputs": [
|
11 |
-
{
|
12 |
-
"data": {
|
13 |
-
"application/vnd.jupyter.widget-view+json": {
|
14 |
-
"model_id": "5bd498c14c0b47ef8fc0c7b25d6197c0",
|
15 |
-
"version_major": 2,
|
16 |
-
"version_minor": 0
|
17 |
-
},
|
18 |
-
"text/plain": [
|
19 |
-
"VBox(children=(Accordion(children=(GridBox(children=(Label(value='CH1'), Label(value='CH2'), Label(value='CH3'…"
|
20 |
-
]
|
21 |
-
},
|
22 |
-
"metadata": {},
|
23 |
-
"output_type": "display_data"
|
24 |
-
},
|
25 |
-
{
|
26 |
-
"name": "stdout",
|
27 |
-
"output_type": "stream",
|
28 |
-
"text": [
|
29 |
-
"DEBUG:/home/mendel/software/portiloop-software/portiloop/sounds/stimulus.wav\n",
|
30 |
-
"PID capture: 4311\n",
|
31 |
-
"DEBUG: new config[5]:0xe1\n",
|
32 |
-
"DEBUG: new config[6]:0xe1\n",
|
33 |
-
"DEBUG: new config[7]:0xe1\n",
|
34 |
-
"DEBUG: new config[8]:0xe1\n",
|
35 |
-
"DEBUG: new config[9]:0xe1\n",
|
36 |
-
"DEBUG: new config[10]:0xe1\n",
|
37 |
-
"DEBUG: new config[11]:0xe1\n",
|
38 |
-
"DEBUG: new config[12]:0xe1\n",
|
39 |
-
"DEBUG: new config[13]:0x0\n",
|
40 |
-
"DEBUG: new config[14]:0x0\n",
|
41 |
-
"DEBUG: new config[3]:0xe8\n"
|
42 |
-
]
|
43 |
-
}
|
44 |
-
],
|
45 |
"source": [
|
46 |
"from portiloop.capture import Capture\n",
|
47 |
"from portiloop.detection import SleepSpindleRealTimeDetector\n",
|
@@ -56,7 +22,7 @@
|
|
56 |
{
|
57 |
"cell_type": "code",
|
58 |
"execution_count": null,
|
59 |
-
"id": "
|
60 |
"metadata": {},
|
61 |
"outputs": [],
|
62 |
"source": []
|
@@ -64,7 +30,7 @@
|
|
64 |
],
|
65 |
"metadata": {
|
66 |
"kernelspec": {
|
67 |
-
"display_name": "Python 3
|
68 |
"language": "python",
|
69 |
"name": "python3"
|
70 |
},
|
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
+
"execution_count": null,
|
6 |
+
"id": "16651843",
|
7 |
"metadata": {
|
8 |
"scrolled": false
|
9 |
},
|
10 |
+
"outputs": [],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
"source": [
|
12 |
"from portiloop.capture import Capture\n",
|
13 |
"from portiloop.detection import SleepSpindleRealTimeDetector\n",
|
|
|
22 |
{
|
23 |
"cell_type": "code",
|
24 |
"execution_count": null,
|
25 |
+
"id": "cded6bbc",
|
26 |
"metadata": {},
|
27 |
"outputs": [],
|
28 |
"source": []
|
|
|
30 |
],
|
31 |
"metadata": {
|
32 |
"kernelspec": {
|
33 |
+
"display_name": "Python 3",
|
34 |
"language": "python",
|
35 |
"name": "python3"
|
36 |
},
|
setup.py
CHANGED
@@ -8,13 +8,13 @@ setup(
|
|
8 |
install_requires=['wheel',
|
9 |
'EDFlib-Python',
|
10 |
'numpy',
|
11 |
-
'matplotlib',
|
12 |
'portilooplot',
|
13 |
'ipywidgets',
|
14 |
'python-periphery',
|
15 |
'spidev',
|
16 |
'pylsl-coral',
|
17 |
'scipy',
|
18 |
-
'pycoral'
|
|
|
19 |
]
|
20 |
)
|
|
|
8 |
install_requires=['wheel',
|
9 |
'EDFlib-Python',
|
10 |
'numpy',
|
|
|
11 |
'portilooplot',
|
12 |
'ipywidgets',
|
13 |
'python-periphery',
|
14 |
'spidev',
|
15 |
'pylsl-coral',
|
16 |
'scipy',
|
17 |
+
'pycoral',
|
18 |
+
'pyalsaaudio'
|
19 |
]
|
20 |
)
|