Spaces:
Sleeping
Sleeping
Commit
·
f9f7de7
1
Parent(s):
ce1d18e
stable version
Browse files- portiloop/capture.py +175 -21
- portiloop/notebooks/tests.ipynb +4 -4
portiloop/capture.py
CHANGED
@@ -59,18 +59,18 @@ FRONTEND_CONFIG = [
|
|
59 |
0x3E, # ID (RO)
|
60 |
0x95, # CONFIG1 [95] [1, DAISY_EN(bar), CLK_EN, 1, 0, DR[2:0]] : Datarate = 500 SPS
|
61 |
0xD0, # CONFIG2 [C0] [1, 1, 0, INT_CAL, 0, CAL_AMP0, CAL_FREQ[1:0]]
|
62 |
-
|
63 |
0x00, # No lead-off
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
0xFF, # LOFF_SENSP Lead-off on all positive pins?
|
75 |
0xFF, # LOFF_SENSN Lead-off on all negative pins?
|
76 |
0x00, # Normal lead-off
|
@@ -82,7 +82,10 @@ FRONTEND_CONFIG = [
|
|
82 |
|
83 |
EDF_PATH = Path.home() / 'workspace' / 'edf_recording'
|
84 |
|
85 |
-
def mod_config(config, datarate):
|
|
|
|
|
|
|
86 |
possible_datarates = [(250, 0x06),
|
87 |
(500, 0x05),
|
88 |
(1000, 0x04),
|
@@ -99,6 +102,39 @@ def mod_config(config, datarate):
|
|
99 |
new_cf1 = config[1] & 0xF8
|
100 |
new_cf1 = new_cf1 | j
|
101 |
config[1] = new_cf1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
return config
|
103 |
|
104 |
def filter_24(value):
|
@@ -133,15 +169,15 @@ class LiveDisplay():
|
|
133 |
self.pp.update(disp_list)
|
134 |
|
135 |
|
136 |
-
def _capture_process(p_data_o, p_msg_io, duration, frequency, python_clock
|
137 |
"""
|
138 |
Args:
|
139 |
p_data_o: multiprocessing.Pipe: captured datapoints are put here
|
140 |
p_msg_io: mutliprocessing.Pipe: to communicate with the parent process
|
141 |
duration: float: max duration of the experiment in seconds
|
142 |
frequency: float: sampling frequency
|
143 |
-
ptyhon_clock: bool
|
144 |
-
time_msg_in: float
|
145 |
"""
|
146 |
if duration <= 0:
|
147 |
duration = np.inf
|
@@ -160,9 +196,10 @@ def _capture_process(p_data_o, p_msg_io, duration, frequency, python_clock=True,
|
|
160 |
|
161 |
config = FRONTEND_CONFIG
|
162 |
if python_clock: # set ADS to 2 * frequency
|
163 |
-
|
164 |
else: # set ADS to frequency
|
165 |
-
|
|
|
166 |
|
167 |
frontend.write_regs(0x00, config)
|
168 |
data = frontend.read_regs(0x00, len(config))
|
@@ -247,12 +284,88 @@ class Capture:
|
|
247 |
self.samples_per_datarecord_array = self.frequency
|
248 |
self.physical_max = 5
|
249 |
self.physical_min = -5
|
250 |
-
self.signal_labels = ['
|
251 |
self._lock_msg_out = Lock()
|
252 |
self._msg_out = None
|
253 |
self._t_capture = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
|
255 |
-
#
|
256 |
|
257 |
self.b_capture = widgets.ToggleButtons(
|
258 |
options=['Stop', 'Start'],
|
@@ -305,6 +418,8 @@ class Capture:
|
|
305 |
indent=False
|
306 |
)
|
307 |
|
|
|
|
|
308 |
self.b_capture.observe(self.on_b_capture, 'value')
|
309 |
self.b_clock.observe(self.on_b_clock, 'value')
|
310 |
self.b_frequency.observe(self.on_b_frequency, 'value')
|
@@ -312,6 +427,12 @@ class Capture:
|
|
312 |
self.b_record.observe(self.on_b_record, 'value')
|
313 |
self.b_display.observe(self.on_b_display, 'value')
|
314 |
self.b_filename.observe(self.on_b_filename, 'value')
|
|
|
|
|
|
|
|
|
|
|
|
|
315 |
|
316 |
self.display_buttons()
|
317 |
|
@@ -319,7 +440,8 @@ class Capture:
|
|
319 |
self.b_capture.close()
|
320 |
|
321 |
def display_buttons(self):
|
322 |
-
display(widgets.VBox([self.
|
|
|
323 |
self.b_duration,
|
324 |
self.b_filename,
|
325 |
widgets.HBox([self.b_record, self.b_display]),
|
@@ -333,6 +455,12 @@ class Capture:
|
|
333 |
self.b_record.disabled = False
|
334 |
self.b_display.disabled = False
|
335 |
self.b_clock.disabled = False
|
|
|
|
|
|
|
|
|
|
|
|
|
336 |
|
337 |
def disable_buttons(self):
|
338 |
self.b_frequency.disabled = True
|
@@ -341,6 +469,30 @@ class Capture:
|
|
341 |
self.b_record.disabled = True
|
342 |
self.b_display.disabled = True
|
343 |
self.b_clock.disabled = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
|
345 |
def on_b_capture(self, value):
|
346 |
val = value['new']
|
@@ -460,7 +612,9 @@ class Capture:
|
|
460 |
p_msg_io_2,
|
461 |
self.duration,
|
462 |
self.frequency,
|
463 |
-
python_clock
|
|
|
|
|
464 |
)
|
465 |
self._p_capture.start()
|
466 |
|
|
|
59 |
0x3E, # ID (RO)
|
60 |
0x95, # CONFIG1 [95] [1, DAISY_EN(bar), CLK_EN, 1, 0, DR[2:0]] : Datarate = 500 SPS
|
61 |
0xD0, # CONFIG2 [C0] [1, 1, 0, INT_CAL, 0, CAL_AMP0, CAL_FREQ[1:0]]
|
62 |
+
0xE8, # 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
|
63 |
0x00, # No lead-off
|
64 |
+
0x60, # CH1SET [60] [PD1, GAIN1[2:0], SRB2, MUX1[2:0]]
|
65 |
+
0x60, # CH2SET 66
|
66 |
+
0x60, # CH3SET
|
67 |
+
0x60, # CH4SET
|
68 |
+
0x60, # CH5SET
|
69 |
+
0x60, # CH6SET
|
70 |
+
0x60, # CH7SET
|
71 |
+
0x60, # CH8SET
|
72 |
+
0x04, # BIAS_SENSP 04
|
73 |
+
0x04, # BIAS_SENSN 04
|
74 |
0xFF, # LOFF_SENSP Lead-off on all positive pins?
|
75 |
0xFF, # LOFF_SENSN Lead-off on all negative pins?
|
76 |
0x00, # Normal lead-off
|
|
|
82 |
|
83 |
EDF_PATH = Path.home() / 'workspace' / 'edf_recording'
|
84 |
|
85 |
+
def mod_config(config, datarate, channel_modes):
|
86 |
+
|
87 |
+
# datarate:
|
88 |
+
|
89 |
possible_datarates = [(250, 0x06),
|
90 |
(500, 0x05),
|
91 |
(1000, 0x04),
|
|
|
102 |
new_cf1 = config[1] & 0xF8
|
103 |
new_cf1 = new_cf1 | j
|
104 |
config[1] = new_cf1
|
105 |
+
|
106 |
+
# bias:
|
107 |
+
|
108 |
+
assert len(channel_modes) == 8
|
109 |
+
config[13] = 0x00 # clear BIAS_SENSP
|
110 |
+
config[14] = 0x00 # clear BIAS_SENSN
|
111 |
+
bias_active = False
|
112 |
+
for chan_i, chan_mode in enumerate(channel_modes):
|
113 |
+
n = 5 + chan_i
|
114 |
+
mod = config[n] & 0x78 # clear PDn and MUX[2:0]
|
115 |
+
if chan_mode == 'simple':
|
116 |
+
pass # PDn = 0 and normal electrode (000)
|
117 |
+
elif chan_mode == 'disabled':
|
118 |
+
mod = mod | 0x81 # PDn = 1 and input shorted (001)
|
119 |
+
elif chan_mode == 'bias in':
|
120 |
+
bit_i = 1 << chan_i
|
121 |
+
config[13] = config[13] | bit_i
|
122 |
+
config[14] = config[14] | bit_i
|
123 |
+
bias_active = True
|
124 |
+
elif chan_mode == 'bias out':
|
125 |
+
mod = mod | 0x06 # MUX[2:0] = BIAS_DRP (110)
|
126 |
+
bias_active = True
|
127 |
+
else:
|
128 |
+
assert False, f"Wrong key: {chan_mode}."
|
129 |
+
config[n] = mod
|
130 |
+
print(f"DEBUG: new config[{n}]:{hex(config[n])}")
|
131 |
+
print(f"DEBUG: new config[13]:{hex(config[13])}")
|
132 |
+
print(f"DEBUG: new config[14]:{hex(config[14])}")
|
133 |
+
if bias_active:
|
134 |
+
config[3] = config[3] | 0x04 # PD_BIAS bar = 1
|
135 |
+
else:
|
136 |
+
config[3] = config[3] & 0xFB # PD_BIAS bar = 0
|
137 |
+
print(f"DEBUG: new config[3]:{hex(config[3])}")
|
138 |
return config
|
139 |
|
140 |
def filter_24(value):
|
|
|
169 |
self.pp.update(disp_list)
|
170 |
|
171 |
|
172 |
+
def _capture_process(p_data_o, p_msg_io, duration, frequency, python_clock, time_msg_in, channel_states):
|
173 |
"""
|
174 |
Args:
|
175 |
p_data_o: multiprocessing.Pipe: captured datapoints are put here
|
176 |
p_msg_io: mutliprocessing.Pipe: to communicate with the parent process
|
177 |
duration: float: max duration of the experiment in seconds
|
178 |
frequency: float: sampling frequency
|
179 |
+
ptyhon_clock: bool: if True, the Coral clock is used, otherwise, the ADS interrupts are used
|
180 |
+
time_msg_in: float: min time between attempts to recv incomming messages
|
181 |
"""
|
182 |
if duration <= 0:
|
183 |
duration = np.inf
|
|
|
196 |
|
197 |
config = FRONTEND_CONFIG
|
198 |
if python_clock: # set ADS to 2 * frequency
|
199 |
+
datarate = 2 * frequency
|
200 |
else: # set ADS to frequency
|
201 |
+
datarate = frequency
|
202 |
+
config = mod_config(config, datarate, channel_states)
|
203 |
|
204 |
frontend.write_regs(0x00, config)
|
205 |
data = frontend.read_regs(0x00, len(config))
|
|
|
284 |
self.samples_per_datarecord_array = self.frequency
|
285 |
self.physical_max = 5
|
286 |
self.physical_min = -5
|
287 |
+
self.signal_labels = ['ch1', 'ch2', 'ch3', 'ch4', 'ch5', 'ch6', 'ch7', 'ch8']
|
288 |
self._lock_msg_out = Lock()
|
289 |
self._msg_out = None
|
290 |
self._t_capture = None
|
291 |
+
self.channel_states = ['disabled', 'simple', 'disabled', 'disabled', 'disabled', 'disabled', 'disabled', 'disabled']
|
292 |
+
|
293 |
+
# widgets ===============================
|
294 |
+
|
295 |
+
# CHANNELS ------------------------------
|
296 |
+
|
297 |
+
self.b_radio_ch1 = widgets.RadioButtons(
|
298 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
299 |
+
value='disabled',
|
300 |
+
disabled=True
|
301 |
+
)
|
302 |
+
|
303 |
+
self.b_radio_ch2 = widgets.RadioButtons(
|
304 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
305 |
+
value='simple',
|
306 |
+
disabled=False
|
307 |
+
)
|
308 |
+
|
309 |
+
self.b_radio_ch3 = widgets.RadioButtons(
|
310 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
311 |
+
value='disabled',
|
312 |
+
disabled=False
|
313 |
+
)
|
314 |
+
|
315 |
+
self.b_radio_ch4 = widgets.RadioButtons(
|
316 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
317 |
+
value='disabled',
|
318 |
+
disabled=False
|
319 |
+
)
|
320 |
+
|
321 |
+
self.b_radio_ch5 = widgets.RadioButtons(
|
322 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
323 |
+
value='disabled',
|
324 |
+
disabled=False
|
325 |
+
)
|
326 |
+
|
327 |
+
self.b_radio_ch6 = widgets.RadioButtons(
|
328 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
329 |
+
value='disabled',
|
330 |
+
disabled=False
|
331 |
+
)
|
332 |
+
|
333 |
+
self.b_radio_ch7 = widgets.RadioButtons(
|
334 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
335 |
+
value='disabled',
|
336 |
+
disabled=False
|
337 |
+
)
|
338 |
+
|
339 |
+
self.b_radio_ch8 = widgets.RadioButtons(
|
340 |
+
options=['disabled', 'simple', 'bias in', 'bias out'],
|
341 |
+
value='disabled',
|
342 |
+
disabled=True
|
343 |
+
)
|
344 |
+
|
345 |
+
self.b_accordion_channels = widgets.Accordion(
|
346 |
+
children=[
|
347 |
+
widgets.GridBox([
|
348 |
+
widgets.Label('CH1'),
|
349 |
+
widgets.Label('CH2'),
|
350 |
+
widgets.Label('CH3'),
|
351 |
+
widgets.Label('CH4'),
|
352 |
+
widgets.Label('CH5'),
|
353 |
+
widgets.Label('CH6'),
|
354 |
+
widgets.Label('CH7'),
|
355 |
+
widgets.Label('CH8'),
|
356 |
+
self.b_radio_ch1,
|
357 |
+
self.b_radio_ch2,
|
358 |
+
self.b_radio_ch3,
|
359 |
+
self.b_radio_ch4,
|
360 |
+
self.b_radio_ch5,
|
361 |
+
self.b_radio_ch6,
|
362 |
+
self.b_radio_ch7,
|
363 |
+
self.b_radio_ch8
|
364 |
+
], layout=widgets.Layout(grid_template_columns="repeat(8, 90px)"))
|
365 |
+
])
|
366 |
+
self.b_accordion_channels.set_title(index = 0, title = 'Channels')
|
367 |
|
368 |
+
# OTHERS ------------------------------
|
369 |
|
370 |
self.b_capture = widgets.ToggleButtons(
|
371 |
options=['Stop', 'Start'],
|
|
|
418 |
indent=False
|
419 |
)
|
420 |
|
421 |
+
# CALLBACKS ----------------------
|
422 |
+
|
423 |
self.b_capture.observe(self.on_b_capture, 'value')
|
424 |
self.b_clock.observe(self.on_b_clock, 'value')
|
425 |
self.b_frequency.observe(self.on_b_frequency, 'value')
|
|
|
427 |
self.b_record.observe(self.on_b_record, 'value')
|
428 |
self.b_display.observe(self.on_b_display, 'value')
|
429 |
self.b_filename.observe(self.on_b_filename, 'value')
|
430 |
+
self.b_radio_ch2.observe(self.on_b_radio_ch2, 'value')
|
431 |
+
self.b_radio_ch3.observe(self.on_b_radio_ch3, 'value')
|
432 |
+
self.b_radio_ch4.observe(self.on_b_radio_ch4, 'value')
|
433 |
+
self.b_radio_ch5.observe(self.on_b_radio_ch5, 'value')
|
434 |
+
self.b_radio_ch6.observe(self.on_b_radio_ch6, 'value')
|
435 |
+
self.b_radio_ch7.observe(self.on_b_radio_ch7, 'value')
|
436 |
|
437 |
self.display_buttons()
|
438 |
|
|
|
440 |
self.b_capture.close()
|
441 |
|
442 |
def display_buttons(self):
|
443 |
+
display(widgets.VBox([self.b_accordion_channels,
|
444 |
+
self.b_frequency,
|
445 |
self.b_duration,
|
446 |
self.b_filename,
|
447 |
widgets.HBox([self.b_record, self.b_display]),
|
|
|
455 |
self.b_record.disabled = False
|
456 |
self.b_display.disabled = False
|
457 |
self.b_clock.disabled = False
|
458 |
+
self.b_radio_ch2.disabled = False
|
459 |
+
self.b_radio_ch3.disabled = False
|
460 |
+
self.b_radio_ch4.disabled = False
|
461 |
+
self.b_radio_ch5.disabled = False
|
462 |
+
self.b_radio_ch6.disabled = False
|
463 |
+
self.b_radio_ch7.disabled = False
|
464 |
|
465 |
def disable_buttons(self):
|
466 |
self.b_frequency.disabled = True
|
|
|
469 |
self.b_record.disabled = True
|
470 |
self.b_display.disabled = True
|
471 |
self.b_clock.disabled = True
|
472 |
+
self.b_radio_ch2.disabled = True
|
473 |
+
self.b_radio_ch3.disabled = True
|
474 |
+
self.b_radio_ch4.disabled = True
|
475 |
+
self.b_radio_ch5.disabled = True
|
476 |
+
self.b_radio_ch6.disabled = True
|
477 |
+
self.b_radio_ch7.disabled = True
|
478 |
+
|
479 |
+
def on_b_radio_ch2(self, value):
|
480 |
+
self.channel_states[1] = value['new']
|
481 |
+
|
482 |
+
def on_b_radio_ch3(self, value):
|
483 |
+
self.channel_states[2] = value['new']
|
484 |
+
|
485 |
+
def on_b_radio_ch4(self, value):
|
486 |
+
self.channel_states[3] = value['new']
|
487 |
+
|
488 |
+
def on_b_radio_ch5(self, value):
|
489 |
+
self.channel_states[4] = value['new']
|
490 |
+
|
491 |
+
def on_b_radio_ch6(self, value):
|
492 |
+
self.channel_states[5] = value['new']
|
493 |
+
|
494 |
+
def on_b_radio_ch7(self, value):
|
495 |
+
self.channel_states[6] = value['new']
|
496 |
|
497 |
def on_b_capture(self, value):
|
498 |
val = value['new']
|
|
|
612 |
p_msg_io_2,
|
613 |
self.duration,
|
614 |
self.frequency,
|
615 |
+
python_clock,
|
616 |
+
1.0,
|
617 |
+
self.channel_states)
|
618 |
)
|
619 |
self._p_capture.start()
|
620 |
|
portiloop/notebooks/tests.ipynb
CHANGED
@@ -11,12 +11,12 @@
|
|
11 |
{
|
12 |
"data": {
|
13 |
"application/vnd.jupyter.widget-view+json": {
|
14 |
-
"model_id": "
|
15 |
"version_major": 2,
|
16 |
"version_minor": 0
|
17 |
},
|
18 |
"text/plain": [
|
19 |
-
"VBox(children=(
|
20 |
]
|
21 |
},
|
22 |
"metadata": {},
|
@@ -9870,7 +9870,7 @@
|
|
9870 |
" };\n",
|
9871 |
" };\n",
|
9872 |
"})();\n",
|
9873 |
-
"</script><svg id=\"
|
9874 |
],
|
9875 |
"text/plain": [
|
9876 |
"<IPython.core.display.HTML object>"
|
@@ -9882,7 +9882,7 @@
|
|
9882 |
{
|
9883 |
"data": {
|
9884 |
"application/javascript": [
|
9885 |
-
"window.appendLearningCurve([{\"x\":
|
9886 |
],
|
9887 |
"text/plain": [
|
9888 |
"<IPython.core.display.Javascript object>"
|
|
|
11 |
{
|
12 |
"data": {
|
13 |
"application/vnd.jupyter.widget-view+json": {
|
14 |
+
"model_id": "93964096f2f144cd84cacc5a487c74b4",
|
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": {},
|
|
|
9870 |
" };\n",
|
9871 |
" };\n",
|
9872 |
"})();\n",
|
9873 |
+
"</script><svg id=\"425ebc5e-c3c2-4c33-a0b3-d9476bf53630\" class=\"learning-curve\"></svg><script> window.setupLearningCurve({\"id\": \"425ebc5e-c3c2-4c33-a0b3-d9476bf53630\", \"width\": 600, \"height\": 1690, \"lineConfig\": {\"line-1\": {\"name\": \"line-1\", \"color\": \"#1f77b4\"}}, \"facetConfig\": {\"ch1\": {\"name\": \"ch1\", \"limit\": [null, null]}, \"ch2\": {\"name\": \"ch2\", \"limit\": [null, null]}, \"ch3\": {\"name\": \"ch3\", \"limit\": [null, null]}, \"ch4\": {\"name\": \"ch4\", \"limit\": [null, null]}, \"ch5\": {\"name\": \"ch5\", \"limit\": [null, null]}, \"ch6\": {\"name\": \"ch6\", \"limit\": [null, null]}, \"ch7\": {\"name\": \"ch7\", \"limit\": [null, null]}, \"ch8\": {\"name\": \"ch8\", \"limit\": [null, null]}}, \"xAxisConfig\": {\"name\": \"iteration\", \"limit\": [null, null]}, \"max_window_len\": 500});</script>"
|
9874 |
],
|
9875 |
"text/plain": [
|
9876 |
"<IPython.core.display.HTML object>"
|
|
|
9882 |
{
|
9883 |
"data": {
|
9884 |
"application/javascript": [
|
9885 |
+
"window.appendLearningCurve([{\"x\": 6712.0, \"y\": {\"ch1\": {\"line-1\": 0.0}, \"ch2\": {\"line-1\": -0.37083743463008817}, \"ch3\": {\"line-1\": -4.500000536441867}, \"ch4\": {\"line-1\": 0.0}, \"ch5\": {\"line-1\": 0.0}, \"ch6\": {\"line-1\": 0.0}, \"ch7\": {\"line-1\": 0.0}, \"ch8\": {\"line-1\": 0.0}}}, {\"x\": 6713.0, \"y\": {\"ch1\": {\"line-1\": 0.0}, \"ch2\": {\"line-1\": -0.19814338661949474}, \"ch3\": {\"line-1\": -4.500000536441867}, \"ch4\": {\"line-1\": 0.0}, \"ch5\": {\"line-1\": 0.0}, \"ch6\": {\"line-1\": 0.0}, \"ch7\": {\"line-1\": 0.0}, \"ch8\": {\"line-1\": 0.0}}}, {\"x\": 6714.0, \"y\": {\"ch1\": {\"line-1\": 0.0}, \"ch2\": {\"line-1\": -0.20779719445671968}, \"ch3\": {\"line-1\": -4.500000536441867}, \"ch4\": {\"line-1\": 0.0}, \"ch5\": {\"line-1\": 0.0}, \"ch6\": {\"line-1\": 0.0}, \"ch7\": {\"line-1\": 0.0}, \"ch8\": {\"line-1\": 0.0}}}, {\"x\": 6715.0, \"y\": {\"ch1\": {\"line-1\": 0.0}, \"ch2\": {\"line-1\": -0.40018241407661603}, \"ch3\": {\"line-1\": -4.500000536441867}, \"ch4\": {\"line-1\": 0.0}, \"ch5\": {\"line-1\": 0.0}, \"ch6\": {\"line-1\": 0.0}, \"ch7\": {\"line-1\": 0.0}, \"ch8\": {\"line-1\": 0.0}}}, {\"x\": 6716.0, \"y\": {\"ch1\": {\"line-1\": 0.0}, \"ch2\": {\"line-1\": -0.4082268963130589}, \"ch3\": {\"line-1\": -4.500000536441867}, \"ch4\": {\"line-1\": 0.0}, \"ch5\": {\"line-1\": 0.0}, \"ch6\": {\"line-1\": 0.0}, \"ch7\": {\"line-1\": 0.0}, \"ch8\": {\"line-1\": 0.0}}}, {\"x\": 6717.0, \"y\": {\"ch1\": {\"line-1\": 0.0}, \"ch2\": {\"line-1\": -0.2183457873279795}, \"ch3\": {\"line-1\": -4.500000536441867}, \"ch4\": {\"line-1\": 0.0}, \"ch5\": {\"line-1\": 0.0}, \"ch6\": {\"line-1\": 0.0}, \"ch7\": {\"line-1\": 0.0}, \"ch8\": {\"line-1\": 0.0}}}]);"
|
9886 |
],
|
9887 |
"text/plain": [
|
9888 |
"<IPython.core.display.Javascript object>"
|