py-neuromodulation 0.0.3__py3-none-any.whl → 0.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py_neuromodulation/ConnectivityDecoding/Automated Anatomical Labeling 3 (Rolls 2020).nii +0 -0
- py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m +34 -0
- py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py +106 -0
- py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py +119 -0
- py_neuromodulation/ConnectivityDecoding/mni_coords_cortical_surface.mat +0 -0
- py_neuromodulation/ConnectivityDecoding/mni_coords_whole_brain.mat +0 -0
- py_neuromodulation/ConnectivityDecoding/rmap_func_all.nii +0 -0
- py_neuromodulation/ConnectivityDecoding/rmap_struc.nii +0 -0
- py_neuromodulation/data/README +6 -0
- py_neuromodulation/data/dataset_description.json +8 -0
- py_neuromodulation/data/participants.json +32 -0
- py_neuromodulation/data/participants.tsv +2 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +5 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +11 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +11 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.eeg +0 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +18 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +35 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +13 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +2 -0
- py_neuromodulation/grid_cortex.tsv +40 -0
- py_neuromodulation/grid_subcortex.tsv +1429 -0
- py_neuromodulation/nm_settings.json +338 -0
- py_neuromodulation/nm_stream_offline.py +7 -6
- py_neuromodulation/plots/STN_surf.mat +0 -0
- py_neuromodulation/plots/Vertices.mat +0 -0
- py_neuromodulation/plots/faces.mat +0 -0
- py_neuromodulation/plots/grid.mat +0 -0
- {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.4.dist-info}/METADATA +182 -182
- py_neuromodulation-0.0.4.dist-info/RECORD +72 -0
- {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.4.dist-info}/WHEEL +1 -2
- docs/build/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -68
- docs/build/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -233
- docs/build/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
- docs/build/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -97
- docs/build/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
- docs/build/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -192
- docs/build/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
- docs/build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -68
- docs/build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -239
- docs/build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
- docs/build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -97
- docs/build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
- docs/build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -192
- docs/build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
- docs/source/_build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -76
- docs/source/_build/html/_downloads/0d0d0a76e8f648d5d3cbc47da6351932/plot_real_time_demo.py +0 -97
- docs/source/_build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -240
- docs/source/_build/html/_downloads/5d73cadc59a8805c47e3b84063afc157/plot_example_BIDS.py +0 -233
- docs/source/_build/html/_downloads/7660317fa5a6bfbd12fcca9961457fc4/plot_example_rmap_computing.py +0 -63
- docs/source/_build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
- docs/source/_build/html/_downloads/839e5b319379f7fd9e867deb00fd797f/plot_example_gridPointProjection.py +0 -210
- docs/source/_build/html/_downloads/ae8be19afe5e559f011fc9b138968ba0/plot_first_demo.py +0 -192
- docs/source/_build/html/_downloads/b8b06cacc17969d3725a0b6f1d7741c5/plot_example_sharpwave_analysis.py +0 -219
- docs/source/_build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -121
- docs/source/_build/html/_downloads/c31a86c0b68cb4167d968091ace8080d/plot_example_add_feature.py +0 -68
- docs/source/_build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
- docs/source/_build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -189
- docs/source/_build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
- docs/source/auto_examples/plot_0_first_demo.py +0 -189
- docs/source/auto_examples/plot_1_example_BIDS.py +0 -240
- docs/source/auto_examples/plot_2_example_add_feature.py +0 -76
- docs/source/auto_examples/plot_3_example_sharpwave_analysis.py +0 -219
- docs/source/auto_examples/plot_4_example_gridPointProjection.py +0 -210
- docs/source/auto_examples/plot_5_example_rmap_computing.py +0 -64
- docs/source/auto_examples/plot_6_real_time_demo.py +0 -121
- docs/source/conf.py +0 -105
- examples/plot_0_first_demo.py +0 -189
- examples/plot_1_example_BIDS.py +0 -240
- examples/plot_2_example_add_feature.py +0 -76
- examples/plot_3_example_sharpwave_analysis.py +0 -219
- examples/plot_4_example_gridPointProjection.py +0 -210
- examples/plot_5_example_rmap_computing.py +0 -64
- examples/plot_6_real_time_demo.py +0 -121
- packages/realtime_decoding/build/lib/realtime_decoding/__init__.py +0 -4
- packages/realtime_decoding/build/lib/realtime_decoding/decoder.py +0 -104
- packages/realtime_decoding/build/lib/realtime_decoding/features.py +0 -163
- packages/realtime_decoding/build/lib/realtime_decoding/helpers.py +0 -15
- packages/realtime_decoding/build/lib/realtime_decoding/run_decoding.py +0 -345
- packages/realtime_decoding/build/lib/realtime_decoding/trainer.py +0 -54
- packages/tmsi/build/lib/TMSiFileFormats/__init__.py +0 -37
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/__init__.py +0 -36
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/lsl_stream_writer.py +0 -200
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_file_writer.py +0 -496
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_to_edf_converter.py +0 -236
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/xdf_file_writer.py +0 -977
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/__init__.py +0 -35
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/edf_reader.py +0 -116
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/poly5reader.py +0 -294
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/xdf_reader.py +0 -229
- packages/tmsi/build/lib/TMSiFileFormats/file_writer.py +0 -102
- packages/tmsi/build/lib/TMSiPlotters/__init__.py +0 -2
- packages/tmsi/build/lib/TMSiPlotters/gui/__init__.py +0 -39
- packages/tmsi/build/lib/TMSiPlotters/gui/_plotter_gui.py +0 -234
- packages/tmsi/build/lib/TMSiPlotters/gui/plotting_gui.py +0 -440
- packages/tmsi/build/lib/TMSiPlotters/plotters/__init__.py +0 -44
- packages/tmsi/build/lib/TMSiPlotters/plotters/hd_emg_plotter.py +0 -446
- packages/tmsi/build/lib/TMSiPlotters/plotters/impedance_plotter.py +0 -589
- packages/tmsi/build/lib/TMSiPlotters/plotters/signal_plotter.py +0 -1326
- packages/tmsi/build/lib/TMSiSDK/__init__.py +0 -54
- packages/tmsi/build/lib/TMSiSDK/device.py +0 -588
- packages/tmsi/build/lib/TMSiSDK/devices/__init__.py +0 -34
- packages/tmsi/build/lib/TMSiSDK/devices/saga/TMSi_Device_API.py +0 -1764
- packages/tmsi/build/lib/TMSiSDK/devices/saga/__init__.py +0 -34
- packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_device.py +0 -1366
- packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_types.py +0 -520
- packages/tmsi/build/lib/TMSiSDK/devices/saga/xml_saga_config.py +0 -165
- packages/tmsi/build/lib/TMSiSDK/error.py +0 -95
- packages/tmsi/build/lib/TMSiSDK/sample_data.py +0 -63
- packages/tmsi/build/lib/TMSiSDK/sample_data_server.py +0 -99
- packages/tmsi/build/lib/TMSiSDK/settings.py +0 -45
- packages/tmsi/build/lib/TMSiSDK/tmsi_device.py +0 -111
- packages/tmsi/build/lib/__init__.py +0 -4
- packages/tmsi/build/lib/apex_sdk/__init__.py +0 -34
- packages/tmsi/build/lib/apex_sdk/device/__init__.py +0 -41
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API.py +0 -1009
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_enums.py +0 -239
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_structures.py +0 -668
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_device.py +0 -1611
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_dongle.py +0 -38
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_event_reader.py +0 -57
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_channel.py +0 -44
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_config.py +0 -150
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_const.py +0 -36
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_impedance_channel.py +0 -48
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_info.py +0 -108
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/dongle_info.py +0 -39
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/download_measurement.py +0 -77
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/eeg_measurement.py +0 -150
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/impedance_measurement.py +0 -129
- packages/tmsi/build/lib/apex_sdk/device/threads/conversion_thread.py +0 -59
- packages/tmsi/build/lib/apex_sdk/device/threads/sampling_thread.py +0 -57
- packages/tmsi/build/lib/apex_sdk/device/tmsi_channel.py +0 -83
- packages/tmsi/build/lib/apex_sdk/device/tmsi_device.py +0 -201
- packages/tmsi/build/lib/apex_sdk/device/tmsi_device_enums.py +0 -103
- packages/tmsi/build/lib/apex_sdk/device/tmsi_dongle.py +0 -43
- packages/tmsi/build/lib/apex_sdk/device/tmsi_event_reader.py +0 -50
- packages/tmsi/build/lib/apex_sdk/device/tmsi_measurement.py +0 -118
- packages/tmsi/build/lib/apex_sdk/sample_data_server/__init__.py +0 -33
- packages/tmsi/build/lib/apex_sdk/sample_data_server/event_data.py +0 -44
- packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data.py +0 -50
- packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data_server.py +0 -136
- packages/tmsi/build/lib/apex_sdk/tmsi_errors/error.py +0 -126
- packages/tmsi/build/lib/apex_sdk/tmsi_sdk.py +0 -113
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/apex/apex_structure_generator.py +0 -134
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/decorators.py +0 -60
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/logger_filter.py +0 -42
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/singleton.py +0 -42
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/support_functions.py +0 -72
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/tmsi_logger.py +0 -98
- py_neuromodulation-0.0.3.dist-info/RECORD +0 -188
- py_neuromodulation-0.0.3.dist-info/top_level.txt +0 -5
- tests/__init__.py +0 -0
- tests/conftest.py +0 -117
- tests/test_all_examples.py +0 -10
- tests/test_all_features.py +0 -63
- tests/test_bispectra.py +0 -70
- tests/test_bursts.py +0 -105
- tests/test_feature_sampling_rates.py +0 -143
- tests/test_fooof.py +0 -16
- tests/test_initalization_offline_stream.py +0 -41
- tests/test_multiprocessing.py +0 -58
- tests/test_nan_values.py +0 -29
- tests/test_nm_filter.py +0 -95
- tests/test_nm_resample.py +0 -63
- tests/test_normalization_settings.py +0 -146
- tests/test_notch_filter.py +0 -31
- tests/test_osc_features.py +0 -424
- tests/test_preprocessing_filter.py +0 -151
- tests/test_rereference.py +0 -171
- tests/test_sampling.py +0 -57
- tests/test_settings_change_after_init.py +0 -76
- tests/test_sharpwave.py +0 -165
- tests/test_target_channel_add.py +0 -100
- tests/test_timing.py +0 -80
- {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.4.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,589 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
(c) 2022 Twente Medical Systems International B.V., Oldenzaal The Netherlands
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
|
|
16
|
-
####### # # ##### #
|
|
17
|
-
# ## ## #
|
|
18
|
-
# # # # # # #
|
|
19
|
-
# # # # ##### #
|
|
20
|
-
# # # # #
|
|
21
|
-
# # # # #
|
|
22
|
-
# # # ##### #
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @file ${impedance_plotter.py}
|
|
26
|
-
* @brief Plotter object that displays impedance values in real-time.
|
|
27
|
-
*
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'''
|
|
32
|
-
|
|
33
|
-
from os.path import join, dirname, realpath, normpath, exists
|
|
34
|
-
from PySide2 import QtGui, QtCore, QtWidgets
|
|
35
|
-
import numpy as np
|
|
36
|
-
import pyqtgraph as pg
|
|
37
|
-
import time
|
|
38
|
-
import queue
|
|
39
|
-
import pandas as pd
|
|
40
|
-
import math
|
|
41
|
-
import datetime
|
|
42
|
-
import sys
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Plotter_dir = dirname(realpath(__file__)) # directory of this file
|
|
46
|
-
measurements_dir = join(Plotter_dir, '../../measurements') # directory with all measurements
|
|
47
|
-
modules_dir = normpath(join(Plotter_dir, '../..')) # directory with all modules
|
|
48
|
-
|
|
49
|
-
from TMSiSDK import tmsi_device
|
|
50
|
-
from TMSiSDK import sample_data_server
|
|
51
|
-
from TMSiSDK import sample_data
|
|
52
|
-
from TMSiSDK.device import DeviceInterfaceType, MeasurementType
|
|
53
|
-
|
|
54
|
-
from apex_sdk.device.tmsi_device import TMSiDevice
|
|
55
|
-
from apex_sdk.sample_data_server.sample_data_server import SampleDataServer as ApexSampleDataServer
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class ImpedanceViewer():
|
|
59
|
-
""" Class that creates a GUI to display the impedance values in a gridded
|
|
60
|
-
layout.
|
|
61
|
-
"""
|
|
62
|
-
def __init__(self, gui_handle, device, layout ='normal', file_storage = False, grid_type = 'none'):
|
|
63
|
-
""" Setting up the GUI's elements
|
|
64
|
-
"""
|
|
65
|
-
# Pass the device handle to the GUI
|
|
66
|
-
self.device = device
|
|
67
|
-
|
|
68
|
-
# Path to store the impedances, if a path is specified
|
|
69
|
-
self._save_impedances = file_storage
|
|
70
|
-
|
|
71
|
-
self.gui_handle = gui_handle
|
|
72
|
-
self.RealTimePlotWidget = self.gui_handle.RealTimePlotWidget
|
|
73
|
-
|
|
74
|
-
self.grid_type = grid_type
|
|
75
|
-
self._disable_channels = []
|
|
76
|
-
|
|
77
|
-
# Number of impedance channels
|
|
78
|
-
if isinstance(self.device, TMSiDevice):
|
|
79
|
-
self.n_chan = len(self.device.get_device_impedance_channels())
|
|
80
|
-
else:
|
|
81
|
-
self.n_chan = len(self.device.imp_channels)
|
|
82
|
-
|
|
83
|
-
# Set up UI and thread
|
|
84
|
-
self.initUI(layout)
|
|
85
|
-
self.setupThread()
|
|
86
|
-
|
|
87
|
-
def initUI(self, layout):
|
|
88
|
-
""" Method responsible for constructing the basic elements in the plot.
|
|
89
|
-
All viewboxes have a set size so that the information can be displayed
|
|
90
|
-
correctly.
|
|
91
|
-
"""
|
|
92
|
-
# Set view settings
|
|
93
|
-
self.RealTimePlotWidget.setBackground('w')
|
|
94
|
-
self.RealTimePlotWidget.showMaximized()
|
|
95
|
-
|
|
96
|
-
# Add viewbox for the legend
|
|
97
|
-
self.RealTimePlotWidget.vb_legend = self.RealTimePlotWidget.addViewBox()
|
|
98
|
-
legend = pg.LegendItem()
|
|
99
|
-
legend.setParentItem(self.RealTimePlotWidget.vb_legend)
|
|
100
|
-
|
|
101
|
-
# Add plot window for the channels
|
|
102
|
-
self.RealTimePlotWidget.window = self.RealTimePlotWidget.addPlot()
|
|
103
|
-
|
|
104
|
-
if layout!='head':
|
|
105
|
-
self.RealTimePlotWidget.window.getViewBox().invertY(True)
|
|
106
|
-
|
|
107
|
-
if self.n_chan <= 34:
|
|
108
|
-
self.RealTimePlotWidget.window.setAspectLocked(lock=True, ratio = 0.6)
|
|
109
|
-
else:
|
|
110
|
-
self.RealTimePlotWidget.window.setAspectLocked(lock=True, ratio = 1)
|
|
111
|
-
else:
|
|
112
|
-
self.RealTimePlotWidget.window.setAspectLocked(lock=True, ratio = 1)
|
|
113
|
-
|
|
114
|
-
# Add viewbox for the list of values
|
|
115
|
-
self.RealTimePlotWidget.vb_list = self.RealTimePlotWidget.addViewBox()
|
|
116
|
-
self.RealTimePlotWidget.vb_list.setMaximumSize(500,150000)
|
|
117
|
-
|
|
118
|
-
# Generate the legend by using dummy plots
|
|
119
|
-
self.legend_entries = []
|
|
120
|
-
legend_spots = self._generate_legend()
|
|
121
|
-
for i in range(len(legend_spots)):
|
|
122
|
-
|
|
123
|
-
lg_plt = pg.ScatterPlotItem(pos= [(0,0),(0,0)], size = 20,
|
|
124
|
-
pen = legend_spots[i]['pen'], brush = legend_spots[i]['brush'],
|
|
125
|
-
name = legend_spots[i]['name'])
|
|
126
|
-
legend.addItem(lg_plt, legend_spots[i]['name'])
|
|
127
|
-
lg_plt.clear()
|
|
128
|
-
|
|
129
|
-
# Ensure legend is displayed in the top left of the viewbox
|
|
130
|
-
self.RealTimePlotWidget.vb_legend.setMaximumWidth(legend.boundingRect().width() + 10)
|
|
131
|
-
legend.anchor((0,0), (0,0))
|
|
132
|
-
|
|
133
|
-
# Write the ticks to the plot
|
|
134
|
-
self.RealTimePlotWidget.window.hideAxis('left')
|
|
135
|
-
self.RealTimePlotWidget.window.hideAxis('bottom')
|
|
136
|
-
|
|
137
|
-
# Disable auto-scaling and menu
|
|
138
|
-
self.RealTimePlotWidget.window.hideButtons()
|
|
139
|
-
self.RealTimePlotWidget.window.setMenuEnabled(False)
|
|
140
|
-
self.RealTimePlotWidget.window.setMouseEnabled(x = False, y = False)
|
|
141
|
-
self.RealTimePlotWidget.vb_legend.setMouseEnabled(x = False, y = False)
|
|
142
|
-
self.RealTimePlotWidget.vb_list.setMouseEnabled(x = False, y = False)
|
|
143
|
-
|
|
144
|
-
# Initialise the standard format for the different indicators
|
|
145
|
-
self.spots = [{'pos': (0,0), 'size': 20, 'pen': 'k', 'brush': QtGui.QBrush(QtGui.QColor(128, 128, 128))} \
|
|
146
|
-
for i in range(self.n_chan)]
|
|
147
|
-
|
|
148
|
-
# Get channel names and units
|
|
149
|
-
if isinstance(self.device, TMSiDevice):
|
|
150
|
-
chs = [[i.get_channel_name(), i.get_channel_unit_name()] for i in self.device.get_device_impedance_channels()]
|
|
151
|
-
|
|
152
|
-
if layout=='head':
|
|
153
|
-
#read channel locations
|
|
154
|
-
chLocs=pd.read_csv(join(modules_dir, 'TMSiSDK','_resources', 'EEGchannelsTMSi.txt'), sep="\t", header=None)
|
|
155
|
-
chLocs.columns=['name', 'radius', 'theta']
|
|
156
|
-
|
|
157
|
-
#Plot a circle
|
|
158
|
-
theta=np.arange(0, 2.02*math.pi, math.pi/50)
|
|
159
|
-
x_circle = 0.5*np.cos(theta)
|
|
160
|
-
y_circle = 0.5*np.sin(theta)
|
|
161
|
-
self.h = pg.PlotCurveItem()
|
|
162
|
-
self.h.setData(x_circle, y_circle, pen=pg.mkPen((165, 165, 165), width=5))
|
|
163
|
-
self.RealTimePlotWidget.window.addItem(self.h)
|
|
164
|
-
|
|
165
|
-
#Plot a nose
|
|
166
|
-
y_nose = np.array([x_circle[2], 0.55, x_circle[-3]])
|
|
167
|
-
x_nose = np.array([y_circle[2], 0, y_circle[-3]])
|
|
168
|
-
self.n = pg.PlotCurveItem()
|
|
169
|
-
self.n.setData(x_nose, y_nose, pen=pg.mkPen((165, 165, 165), width=5))
|
|
170
|
-
self.RealTimePlotWidget.window.addItem(self.n)
|
|
171
|
-
|
|
172
|
-
#Plot ears
|
|
173
|
-
x_ears = np.array([0.49, 0.51, 0.52, 0.53, 0.54, 0.54, 0.55, 0.53, 0.51, 0.485])
|
|
174
|
-
y_ears = np.array([0.10, 0.1175, 0.1185, 0.1145, 0.0955, -0.0055, -0.0930, -0.1315, -0.1385, -0.12])
|
|
175
|
-
self.e = pg.PlotCurveItem()
|
|
176
|
-
self.e.setData(x_ears, y_ears, pen=pg.mkPen((165, 165, 165), width=5))
|
|
177
|
-
self.RealTimePlotWidget.window.addItem(self.e)
|
|
178
|
-
self.e = pg.PlotCurveItem()
|
|
179
|
-
self.e.setData(-x_ears, y_ears, pen=pg.mkPen((165, 165, 165), width=5))
|
|
180
|
-
self.RealTimePlotWidget.window.addItem(self.e)
|
|
181
|
-
|
|
182
|
-
# Set the position for each indicator
|
|
183
|
-
for i in range(self.n_chan):
|
|
184
|
-
if i == 0:
|
|
185
|
-
if isinstance(self.device, TMSiDevice):
|
|
186
|
-
self.spots[i]['pos'] = (0, -0.6)
|
|
187
|
-
else:
|
|
188
|
-
self.spots[i]['pos'] = (-0.05, -0.6)
|
|
189
|
-
elif i == self.n_chan - 1 and not isinstance(self.device, TMSiDevice):
|
|
190
|
-
self.spots[i]['pos'] = (0.05, -0.6)
|
|
191
|
-
else:
|
|
192
|
-
if isinstance(self.device, TMSiDevice):
|
|
193
|
-
idx_ch = np.where("'" + chs[i][0] + "'" == chLocs['name'])[0][0]
|
|
194
|
-
|
|
195
|
-
x=chLocs['radius'].values[idx_ch]*np.sin(np.deg2rad(chLocs['theta'].values[idx_ch]))
|
|
196
|
-
y=chLocs['radius'].values[idx_ch]*np.cos(np.deg2rad(chLocs['theta'].values[idx_ch]))
|
|
197
|
-
else:
|
|
198
|
-
x=chLocs['radius'].values[i-1]*np.sin(np.deg2rad(chLocs['theta'].values[i-1]))
|
|
199
|
-
y=chLocs['radius'].values[i-1]*np.cos(np.deg2rad(chLocs['theta'].values[i-1]))
|
|
200
|
-
|
|
201
|
-
self.spots[i]['pos'] = (x,y)
|
|
202
|
-
|
|
203
|
-
# Place the name of each channel below the respective indicator
|
|
204
|
-
if isinstance(self.device, TMSiDevice):
|
|
205
|
-
text = f'{chs[i][0]: ^10}'
|
|
206
|
-
else:
|
|
207
|
-
text = f'{self.device.imp_channels[i].name: ^10}'
|
|
208
|
-
t_item = pg.TextItem(text, (0, 0, 0), anchor=(0, 0))
|
|
209
|
-
t_item.setPos(self.spots[i]['pos'][0] -.03, self.spots[i]['pos'][1] - .02)
|
|
210
|
-
self.RealTimePlotWidget.window.addItem(t_item)
|
|
211
|
-
|
|
212
|
-
# Generate the channel conversion list
|
|
213
|
-
self.channel_conversion_list = np.arange(0,self.n_chan, dtype = int)
|
|
214
|
-
|
|
215
|
-
else:
|
|
216
|
-
self.channel_conversion_list = self.gui_handle.channel_conversion_list
|
|
217
|
-
|
|
218
|
-
# Insert dummy channels
|
|
219
|
-
self.dummy_chan = []
|
|
220
|
-
if '11' in self.grid_type:
|
|
221
|
-
if not self.grid_type[-1] == '2':
|
|
222
|
-
self.dummy_chan.append(10)
|
|
223
|
-
if not self.grid_type[-1] == '1':
|
|
224
|
-
dummy_chan=max(self.channel_conversion_list)
|
|
225
|
-
self.dummy_chan.append(dummy_chan)
|
|
226
|
-
|
|
227
|
-
# Insert PGND channel in channel conversion list
|
|
228
|
-
self.channel_conversion_list = np.hstack((self.channel_conversion_list, max(self.gui_handle.channel_conversion_list)+1))
|
|
229
|
-
# In case of 64 channel device with 32 channel grid, insert channels 33-64
|
|
230
|
-
if len(self.device.imp_channels) > 34 and max(self.channel_conversion_list) < 34:
|
|
231
|
-
self.channel_conversion_list = np.hstack((self.channel_conversion_list, np.arange(34, 66)))
|
|
232
|
-
|
|
233
|
-
row_count = -1
|
|
234
|
-
c_offset = 0
|
|
235
|
-
|
|
236
|
-
if '11' in self.grid_type:
|
|
237
|
-
# Set the position for each indicator
|
|
238
|
-
for i in range(len(self.device.imp_channels)):
|
|
239
|
-
if i == 0:
|
|
240
|
-
if len(self.device.imp_channels) > 34:
|
|
241
|
-
self.spots[i]['pos'] = (3, 8)
|
|
242
|
-
else:
|
|
243
|
-
self.spots[i]['pos'] = (3, 4)
|
|
244
|
-
elif i == len(self.device.imp_channels)-1:
|
|
245
|
-
if len(self.device.imp_channels) > 34:
|
|
246
|
-
self.spots[i]['pos'] = (4, 8)
|
|
247
|
-
else:
|
|
248
|
-
self.spots[i]['pos'] = (4, 4)
|
|
249
|
-
elif i-1 in self.dummy_chan:
|
|
250
|
-
row_count += 1
|
|
251
|
-
self.spots[i]['pos'] = (0, row_count)
|
|
252
|
-
c_offset = i-1
|
|
253
|
-
elif (i-1-c_offset) % 11 == 0:
|
|
254
|
-
row_count += 1
|
|
255
|
-
self.spots[i]['pos'] = (0, row_count)
|
|
256
|
-
else:
|
|
257
|
-
self.spots[i]['pos'] = (((i-c_offset-1)%11), row_count)
|
|
258
|
-
else:
|
|
259
|
-
# Set the position for each indicator
|
|
260
|
-
for i in range(self.n_chan):
|
|
261
|
-
if i == 0:
|
|
262
|
-
if self.n_chan > 34:
|
|
263
|
-
self.spots[i]['pos'] = (3, 8)
|
|
264
|
-
else:
|
|
265
|
-
self.spots[i]['pos'] = (3, 4)
|
|
266
|
-
elif i == self.n_chan - 1 and not isinstance(self.device, TMSiDevice):
|
|
267
|
-
if self.n_chan > 34:
|
|
268
|
-
self.spots[i]['pos'] = (4, 8)
|
|
269
|
-
else:
|
|
270
|
-
self.spots[i]['pos'] = (4, 4)
|
|
271
|
-
elif (i-1) % 8 == 0:
|
|
272
|
-
row_count += 1
|
|
273
|
-
self.spots[i]['pos'] = (((i-1)%8), row_count)
|
|
274
|
-
else:
|
|
275
|
-
if i == 0:
|
|
276
|
-
if len(self.device.imp_channels) > 34:
|
|
277
|
-
self.spots[i]['pos'] = (3, 8)
|
|
278
|
-
else:
|
|
279
|
-
self.spots[i]['pos'] = (3, 4)
|
|
280
|
-
elif i == len(self.device.imp_channels)-1:
|
|
281
|
-
if len(self.device.imp_channels) > 34:
|
|
282
|
-
self.spots[i]['pos'] = (4, 8)
|
|
283
|
-
else:
|
|
284
|
-
self.spots[i]['pos'] = (4, 4)
|
|
285
|
-
elif (i-1) % 8 == 0:
|
|
286
|
-
row_count += 1
|
|
287
|
-
self.spots[i]['pos'] = (((i-1)%8), row_count)
|
|
288
|
-
else:
|
|
289
|
-
self.spots[i]['pos'] = (((i-1)%8), row_count)
|
|
290
|
-
|
|
291
|
-
for i in range(self.n_chan):
|
|
292
|
-
# Place the name of each channel below the respective indicator
|
|
293
|
-
if isinstance(self.device, TMSiDevice):
|
|
294
|
-
text = f'{chs[self.channel_conversion_list[i]][0]: ^10}'
|
|
295
|
-
else:
|
|
296
|
-
text = f'{self.device.imp_channels[self.channel_conversion_list[i]].name: ^10}'
|
|
297
|
-
t_item = pg.TextItem(text, (128, 128, 128), anchor=(0, 0))
|
|
298
|
-
t_item.setPos(self.spots[i]['pos'][0] -.25, self.spots[i]['pos'][1] + .1)
|
|
299
|
-
self.RealTimePlotWidget.window.addItem(t_item)
|
|
300
|
-
|
|
301
|
-
# Add all indicators to the plot
|
|
302
|
-
self.c = pg.ScatterPlotItem(self.spots)
|
|
303
|
-
self.RealTimePlotWidget.window.addItem(self.c)
|
|
304
|
-
|
|
305
|
-
# Create a list with impedance values to display next to the plot
|
|
306
|
-
self.text_items = []
|
|
307
|
-
for i in range(self.n_chan):
|
|
308
|
-
# Display 33 names per list (66 impedance channels in SAGA64+)
|
|
309
|
-
list_split_idx = 33
|
|
310
|
-
num_column = np.floor(i/list_split_idx)
|
|
311
|
-
value = 5000
|
|
312
|
-
if isinstance(self.device, TMSiDevice):
|
|
313
|
-
text = f'{chs[self.channel_conversion_list[i]][0]}\t{value:>4}\t{chs[self.channel_conversion_list[i]][1][0]}'
|
|
314
|
-
else:
|
|
315
|
-
text = f'{self.device.imp_channels[self.channel_conversion_list[i]].name}\t{value:>4}\t{self.device.imp_channels[self.channel_conversion_list[i]].unit_name}'
|
|
316
|
-
t_item = pg.TextItem(text, (0, 0, 0),
|
|
317
|
-
anchor = (-num_column *1.2, -i*0.9 + list_split_idx * 0.9 * np.floor(i/list_split_idx)))
|
|
318
|
-
self.text_items.append(t_item)
|
|
319
|
-
self.RealTimePlotWidget.vb_list.addItem(t_item)
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
@QtCore.Slot(object)
|
|
323
|
-
def update_plot(self, data):
|
|
324
|
-
""" Method that updates the indicators according to the measured impedance values
|
|
325
|
-
"""
|
|
326
|
-
for i in range(len(self.spots)):
|
|
327
|
-
if isinstance(self.device, TMSiDevice):
|
|
328
|
-
if self.device.get_device_impedance_channels()[self.channel_conversion_list[i]].get_channel_name() in self._disable_channels:
|
|
329
|
-
self.spots[i]['brush'] = QtGui.QBrush(QtGui.QColor(175, 175, 175))
|
|
330
|
-
else:
|
|
331
|
-
self.spots[i]['brush'] = QtGui.QBrush(self._lookup_table(data[i]))
|
|
332
|
-
text = f"{self.device.get_device_impedance_channels()[self.channel_conversion_list[i]].get_channel_name()}\t{data[i]:>4}\t{self.device.get_device_impedance_channels()[self.channel_conversion_list[i]].get_channel_unit_name()[0]}"
|
|
333
|
-
else:
|
|
334
|
-
if self.device.imp_channels[self.channel_conversion_list[i]].name in self._disable_channels:
|
|
335
|
-
self.spots[i]['brush'] = QtGui.QBrush(QtGui.QColor(175, 175, 175))
|
|
336
|
-
else:
|
|
337
|
-
self.spots[i]['brush'] = QtGui.QBrush(self._lookup_table(data[i]))
|
|
338
|
-
text = f"{self.device.imp_channels[self.channel_conversion_list[i]].name}\t{data[i]:>4}\t{self.device.imp_channels[self.channel_conversion_list[i]].unit_name}"
|
|
339
|
-
self.text_items[i].setText(text)
|
|
340
|
-
self.c.setData(self.spots)
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
def _lookup_table(self, value):
|
|
344
|
-
"""Look up table to convert impedances to color coding is device specific"""
|
|
345
|
-
if isinstance(self.device, TMSiDevice):
|
|
346
|
-
return self._lookup_table_APEX(value)
|
|
347
|
-
else:
|
|
348
|
-
return self._lookup_table_SAGA(value)
|
|
349
|
-
|
|
350
|
-
def _lookup_table_SAGA(self, value):
|
|
351
|
-
"""Look up table to convert impedances to color coding"""
|
|
352
|
-
if value < 5:
|
|
353
|
-
color_code = QtGui.QColor(0, 255, 0)
|
|
354
|
-
elif value >= 5 and value < 10:
|
|
355
|
-
color_code = QtGui.QColor(0, 204, 0)
|
|
356
|
-
elif value >= 10 and value < 30:
|
|
357
|
-
color_code = QtGui.QColor(0, 153, 0)
|
|
358
|
-
elif value >= 30 and value < 50:
|
|
359
|
-
color_code = QtGui.QColor(0, 102, 0)
|
|
360
|
-
elif value >= 50 and value < 100:
|
|
361
|
-
color_code = QtGui.QColor(255, 255, 0)
|
|
362
|
-
elif value >= 100 and value < 200:
|
|
363
|
-
color_code = QtGui.QColor(204, 128, 0)
|
|
364
|
-
elif value >= 200 and value < 400:
|
|
365
|
-
color_code = QtGui.QColor(255, 0, 0)
|
|
366
|
-
elif value >= 400 and value < 500:
|
|
367
|
-
color_code = QtGui.QColor(153, 0, 0)
|
|
368
|
-
elif value == 500:
|
|
369
|
-
color_code = QtGui.QColor(0, 0, 0)
|
|
370
|
-
elif value == 5000:
|
|
371
|
-
color_code = QtGui.QColor(175, 175, 175)
|
|
372
|
-
elif value == 5100:
|
|
373
|
-
color_code = QtGui.QColor(204, 0, 102)
|
|
374
|
-
elif value == 5200:
|
|
375
|
-
color_code = QtGui.QColor(0, 0, 179)
|
|
376
|
-
return color_code
|
|
377
|
-
|
|
378
|
-
def _lookup_table_APEX(self, value):
|
|
379
|
-
"""Look up table to convert impedances to color coding"""
|
|
380
|
-
if value < 5:
|
|
381
|
-
color_code = QtGui.QColor(0, 255, 0)
|
|
382
|
-
elif value >= 5 and value < 10:
|
|
383
|
-
color_code = QtGui.QColor(0, 204, 0)
|
|
384
|
-
elif value >= 10 and value < 30:
|
|
385
|
-
color_code = QtGui.QColor(0, 153, 0)
|
|
386
|
-
elif value >= 30 and value < 50:
|
|
387
|
-
color_code = QtGui.QColor(0, 102, 0)
|
|
388
|
-
elif value >= 50 and value < 100:
|
|
389
|
-
color_code = QtGui.QColor(255, 255, 0)
|
|
390
|
-
elif value >= 100 and value < 200:
|
|
391
|
-
color_code = QtGui.QColor(204, 128, 0)
|
|
392
|
-
elif value >= 200 and value < 400:
|
|
393
|
-
color_code = QtGui.QColor(255, 0, 0)
|
|
394
|
-
elif value >= 400 and value < 1000:
|
|
395
|
-
color_code = QtGui.QColor(153, 0, 0)
|
|
396
|
-
else:
|
|
397
|
-
color_code = QtGui.QColor(38, 38, 38)
|
|
398
|
-
return color_code
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
def _generate_legend(self):
|
|
402
|
-
"""Generate the device specific legend"""
|
|
403
|
-
if isinstance(self.device, TMSiDevice):
|
|
404
|
-
return self._generate_APEX_legend()
|
|
405
|
-
else:
|
|
406
|
-
return self._generate_SAGA_legend()
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
def _generate_SAGA_legend(self):
|
|
410
|
-
""" Method that generates the dummy samples needed to plot the legend
|
|
411
|
-
"""
|
|
412
|
-
legend_spots = [{'pos': (0,0), 'size': 10, 'pen': 'k', 'brush': QtGui.QBrush() , 'name': ''} for i in range(12)]
|
|
413
|
-
legend_spots[0]['name'] = '0 - 5 k\u03A9'
|
|
414
|
-
legend_spots[0]['brush'] = QtGui.QBrush(QtGui.QColor(0, 255, 0))
|
|
415
|
-
legend_spots[1]['name'] = '5 - 10 k\u03A9'
|
|
416
|
-
legend_spots[1]['brush'] = QtGui.QBrush(QtGui.QColor(0, 204, 0))
|
|
417
|
-
legend_spots[2]['name'] = '10 - 30 k\u03A9'
|
|
418
|
-
legend_spots[2]['brush'] = QtGui.QBrush(QtGui.QColor(0, 153, 0))
|
|
419
|
-
legend_spots[3]['name'] = '30 - 50 k\u03A9'
|
|
420
|
-
legend_spots[3]['brush'] = QtGui.QBrush(QtGui.QColor(0, 102, 0))
|
|
421
|
-
legend_spots[4]['name'] = '50 - 100 k\u03A9'
|
|
422
|
-
legend_spots[4]['brush'] = QtGui.QBrush(QtGui.QColor(255, 255, 0))
|
|
423
|
-
legend_spots[5]['name'] = '100 - 200 k\u03A9'
|
|
424
|
-
legend_spots[5]['brush'] = QtGui.QBrush(QtGui.QColor(204, 128, 0))
|
|
425
|
-
legend_spots[6]['name'] = '200 - 400 k\u03A9'
|
|
426
|
-
legend_spots[6]['brush'] = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
|
427
|
-
legend_spots[7]['name'] = '400 - 500 k\u03A9'
|
|
428
|
-
legend_spots[7]['brush'] = QtGui.QBrush(QtGui.QColor(153, 0, 0))
|
|
429
|
-
legend_spots[8]['name'] = '≥ 500 k\u03A9 / Not connected'
|
|
430
|
-
legend_spots[8]['brush'] = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
|
431
|
-
legend_spots[9]['name'] = 'Disabled'
|
|
432
|
-
legend_spots[9]['brush'] = QtGui.QBrush(QtGui.QColor(175, 175, 175))
|
|
433
|
-
legend_spots[10]['name'] = 'Odd/Even error'
|
|
434
|
-
legend_spots[10]['brush'] = QtGui.QBrush(QtGui.QColor(204, 0, 102))
|
|
435
|
-
legend_spots[11]['name'] = 'PGND disconnected'
|
|
436
|
-
legend_spots[11]['brush'] = QtGui.QBrush(QtGui.QColor(0, 0, 179))
|
|
437
|
-
return legend_spots
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
def _generate_APEX_legend(self):
|
|
441
|
-
""" Method that generates the dummy samples needed to plot the legend
|
|
442
|
-
"""
|
|
443
|
-
legend_spots = [{'pos': (0,0), 'size': 10, 'pen': 'k', 'brush': QtGui.QBrush() , 'name': ''} for i in range(9)]
|
|
444
|
-
legend_spots[0]['name'] = '0 - 5 k\u03A9'
|
|
445
|
-
legend_spots[0]['brush'] = QtGui.QBrush(QtGui.QColor(0, 255, 0))
|
|
446
|
-
legend_spots[1]['name'] = '5 - 10 k\u03A9'
|
|
447
|
-
legend_spots[1]['brush'] = QtGui.QBrush(QtGui.QColor(0, 204, 0))
|
|
448
|
-
legend_spots[2]['name'] = '10 - 30 k\u03A9'
|
|
449
|
-
legend_spots[2]['brush'] = QtGui.QBrush(QtGui.QColor(0, 153, 0))
|
|
450
|
-
legend_spots[3]['name'] = '30 - 50 k\u03A9'
|
|
451
|
-
legend_spots[3]['brush'] = QtGui.QBrush(QtGui.QColor(0, 102, 0))
|
|
452
|
-
legend_spots[4]['name'] = '50 - 100 k\u03A9'
|
|
453
|
-
legend_spots[4]['brush'] = QtGui.QBrush(QtGui.QColor(255, 255, 0))
|
|
454
|
-
legend_spots[5]['name'] = '100 - 200 k\u03A9'
|
|
455
|
-
legend_spots[5]['brush'] = QtGui.QBrush(QtGui.QColor(204, 128, 0))
|
|
456
|
-
legend_spots[6]['name'] = '200 - 400 k\u03A9'
|
|
457
|
-
legend_spots[6]['brush'] = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
|
458
|
-
legend_spots[7]['name'] = '400 - 1000 k\u03A9'
|
|
459
|
-
legend_spots[7]['brush'] = QtGui.QBrush(QtGui.QColor(153, 0, 0))
|
|
460
|
-
legend_spots[8]['name'] = '≥ 1000 k\u03A9 / Not connected'
|
|
461
|
-
legend_spots[8]['brush'] = QtGui.QBrush(QtGui.QColor(38, 38, 38))
|
|
462
|
-
|
|
463
|
-
return legend_spots
|
|
464
|
-
|
|
465
|
-
def _update_active_channels(self):
|
|
466
|
-
self._disable_channels = []
|
|
467
|
-
# Update the channel selection based on the clicked checkboxes
|
|
468
|
-
for i in range(np.size(self.gui_handle._checkboxes,0)):
|
|
469
|
-
if not self.gui_handle._checkboxes[i].isChecked():
|
|
470
|
-
self._disable_channels.append(self.device.channels[self.gui_handle.active_channel_conversion_list[i]].name)
|
|
471
|
-
|
|
472
|
-
def setupThread(self):
|
|
473
|
-
""" Method that initialises the sampling thread of the device
|
|
474
|
-
"""
|
|
475
|
-
# Create a Thread
|
|
476
|
-
self.thread = QtCore.QThread()
|
|
477
|
-
# Instantiate the worker class
|
|
478
|
-
self.worker = SamplingThread(self)
|
|
479
|
-
|
|
480
|
-
# Move the worker to a Thread
|
|
481
|
-
self.worker.moveToThread(self.thread)
|
|
482
|
-
|
|
483
|
-
# Connect signals to slots
|
|
484
|
-
self.thread.started.connect(self.worker.update_samples)
|
|
485
|
-
self.worker.output.connect(self.update_plot)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
class SamplingThread(QtCore.QObject):
|
|
489
|
-
""" Class responsible for sampling the data from the device
|
|
490
|
-
"""
|
|
491
|
-
# Initialise the ouptut object
|
|
492
|
-
output = QtCore.Signal(object)
|
|
493
|
-
def __init__(self, main_class):
|
|
494
|
-
QtCore.QObject.__init__(self)
|
|
495
|
-
# Access initialised values from the GUI class
|
|
496
|
-
self.device = main_class.device
|
|
497
|
-
self._save_impedances = main_class._save_impedances
|
|
498
|
-
|
|
499
|
-
self.grid_type = main_class.grid_type
|
|
500
|
-
self.channel_conversion_list = main_class.channel_conversion_list
|
|
501
|
-
|
|
502
|
-
# Prepare Queue
|
|
503
|
-
self.q_sample_sets = queue.Queue(1000)
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
# Register the consumer to the sample server
|
|
507
|
-
if isinstance(self.device, TMSiDevice):
|
|
508
|
-
ApexSampleDataServer().register_consumer(self.device.get_id(), self.q_sample_sets)
|
|
509
|
-
else:
|
|
510
|
-
sample_data_server.registerConsumer(self.device.id, self.q_sample_sets)
|
|
511
|
-
|
|
512
|
-
# # Start measurement
|
|
513
|
-
self.sampling = True
|
|
514
|
-
|
|
515
|
-
@QtCore.Slot()
|
|
516
|
-
def update_samples(self):
|
|
517
|
-
""" Method that retrieves the sample data from the device. The method
|
|
518
|
-
gives the impedance value as output
|
|
519
|
-
"""
|
|
520
|
-
while self.sampling:
|
|
521
|
-
while not self.q_sample_sets.empty():
|
|
522
|
-
sd = self.q_sample_sets.get()
|
|
523
|
-
self.q_sample_sets.task_done()
|
|
524
|
-
|
|
525
|
-
# Retrieve the data from the queue and write it to a SampleSet object
|
|
526
|
-
for i in range(sd.num_sample_sets):
|
|
527
|
-
sample_set = sample_data.SampleSet(sd.num_samples_per_sample_set, sd.samples[i*sd.num_samples_per_sample_set:(i+1)*sd.num_samples_per_sample_set])
|
|
528
|
-
|
|
529
|
-
# Use the final measured impedance value and convert to integer value
|
|
530
|
-
impedance_values = [int(x) for x in sample_set.samples]
|
|
531
|
-
|
|
532
|
-
if isinstance(self.device, TMSiDevice):
|
|
533
|
-
impedance_values = [impedance_values[i*2] for i in self.channel_conversion_list]
|
|
534
|
-
else:
|
|
535
|
-
impedance_values = [impedance_values[i] for i in self.channel_conversion_list]
|
|
536
|
-
|
|
537
|
-
self.impedance_values = impedance_values
|
|
538
|
-
|
|
539
|
-
# Output sample data
|
|
540
|
-
self.output.emit(impedance_values)
|
|
541
|
-
|
|
542
|
-
# Pause the thread so that the update does not happen too fast
|
|
543
|
-
time.sleep(1)
|
|
544
|
-
|
|
545
|
-
def stop(self):
|
|
546
|
-
""" Method that is executed when the thread is terminated.
|
|
547
|
-
This stop event stops the measurement and closes the connection to
|
|
548
|
-
the device.
|
|
549
|
-
"""
|
|
550
|
-
self.sampling = False
|
|
551
|
-
|
|
552
|
-
if self._save_impedances:
|
|
553
|
-
store_imp = []
|
|
554
|
-
|
|
555
|
-
for i in range(len(self.impedance_values)):
|
|
556
|
-
if isinstance(self.device, TMSiDevice):
|
|
557
|
-
store_imp.append(f"{self.device.get_device_impedance_channels()[i].get_channel_name()}\t{self.impedance_values[self.channel_conversion_list[i]]}\t{self.device.get_device_impedance_channels()[self.channel_conversion_list[i]].get_channel_unit_name()[0]}")
|
|
558
|
-
else:
|
|
559
|
-
store_imp.append(f"{self.device.imp_channels[i].name}\t{self.impedance_values[self.channel_conversion_list[i]]}\t{self.device.imp_channels[self.channel_conversion_list[i]].unit_name}")
|
|
560
|
-
|
|
561
|
-
now = datetime.datetime.now()
|
|
562
|
-
filetime = now.strftime("%Y%m%d_%H%M%S")
|
|
563
|
-
filename = self._save_impedances + '-' + filetime
|
|
564
|
-
|
|
565
|
-
with open(filename + '.txt', 'w') as f:
|
|
566
|
-
for item in store_imp:
|
|
567
|
-
f.write(item + "\n")
|
|
568
|
-
|
|
569
|
-
if __name__ == "__main__":
|
|
570
|
-
# Initialise the TMSi-SDK first before starting using it
|
|
571
|
-
tmsi_device.initialize()
|
|
572
|
-
|
|
573
|
-
# Create the device object to interface with the SAGA-system.
|
|
574
|
-
dev = tmsi_device.create(tmsi_device.DeviceType.saga, DeviceInterfaceType.docked, DeviceInterfaceType.usb)
|
|
575
|
-
|
|
576
|
-
# Find and open a connection to the SAGA-system and print its serial number
|
|
577
|
-
dev.open()
|
|
578
|
-
print("handle 1 " + str(dev.info.ds_serial_number))
|
|
579
|
-
|
|
580
|
-
# Initialise the application
|
|
581
|
-
app = QtGui.QApplication(sys.argv)
|
|
582
|
-
# Define the GUI object and show it
|
|
583
|
-
window = ImpedancePlot(figurename = 'An Impedance Plot', device = dev, layout='normal')
|
|
584
|
-
window.show()
|
|
585
|
-
|
|
586
|
-
# Enter the event loop
|
|
587
|
-
# sys.exit(app.exec_())
|
|
588
|
-
app.exec_()
|
|
589
|
-
dev.close()
|