py-neuromodulation 0.0.3__py3-none-any.whl → 0.0.5__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.
Files changed (233) hide show
  1. py_neuromodulation/ConnectivityDecoding/Automated Anatomical Labeling 3 (Rolls 2020).nii +0 -0
  2. py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m +34 -0
  3. py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py +95 -0
  4. py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py +107 -0
  5. py_neuromodulation/ConnectivityDecoding/mni_coords_cortical_surface.mat +0 -0
  6. py_neuromodulation/ConnectivityDecoding/mni_coords_whole_brain.mat +0 -0
  7. py_neuromodulation/ConnectivityDecoding/rmap_func_all.nii +0 -0
  8. py_neuromodulation/ConnectivityDecoding/rmap_struc.nii +0 -0
  9. py_neuromodulation/FieldTrip.py +589 -589
  10. py_neuromodulation/__init__.py +74 -13
  11. py_neuromodulation/_write_example_dataset_helper.py +83 -65
  12. py_neuromodulation/data/README +6 -0
  13. py_neuromodulation/data/dataset_description.json +8 -0
  14. py_neuromodulation/data/participants.json +32 -0
  15. py_neuromodulation/data/participants.tsv +2 -0
  16. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +5 -0
  17. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +11 -0
  18. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +11 -0
  19. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.eeg +0 -0
  20. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +18 -0
  21. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +35 -0
  22. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +13 -0
  23. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +2 -0
  24. py_neuromodulation/grid_cortex.tsv +40 -0
  25. py_neuromodulation/grid_subcortex.tsv +1429 -0
  26. py_neuromodulation/liblsl/libpugixml.so.1.12 +0 -0
  27. py_neuromodulation/liblsl/linux/bionic_amd64/liblsl.1.16.2.so +0 -0
  28. py_neuromodulation/liblsl/linux/bookworm_amd64/liblsl.1.16.2.so +0 -0
  29. py_neuromodulation/liblsl/linux/focal_amd46/liblsl.1.16.2.so +0 -0
  30. py_neuromodulation/liblsl/linux/jammy_amd64/liblsl.1.16.2.so +0 -0
  31. py_neuromodulation/liblsl/linux/jammy_x86/liblsl.1.16.2.so +0 -0
  32. py_neuromodulation/liblsl/linux/noble_amd64/liblsl.1.16.2.so +0 -0
  33. py_neuromodulation/liblsl/macos/amd64/liblsl.1.16.2.dylib +0 -0
  34. py_neuromodulation/liblsl/macos/arm64/liblsl.1.16.0.dylib +0 -0
  35. py_neuromodulation/liblsl/windows/amd64/liblsl.1.16.2.dll +0 -0
  36. py_neuromodulation/liblsl/windows/x86/liblsl.1.16.2.dll +0 -0
  37. py_neuromodulation/nm_IO.py +413 -417
  38. py_neuromodulation/nm_RMAP.py +496 -531
  39. py_neuromodulation/nm_analysis.py +993 -1074
  40. py_neuromodulation/nm_artifacts.py +30 -25
  41. py_neuromodulation/nm_bispectra.py +154 -168
  42. py_neuromodulation/nm_bursts.py +292 -198
  43. py_neuromodulation/nm_coherence.py +251 -205
  44. py_neuromodulation/nm_database.py +149 -0
  45. py_neuromodulation/nm_decode.py +918 -992
  46. py_neuromodulation/nm_define_nmchannels.py +300 -302
  47. py_neuromodulation/nm_features.py +144 -116
  48. py_neuromodulation/nm_filter.py +219 -219
  49. py_neuromodulation/nm_filter_preprocessing.py +79 -91
  50. py_neuromodulation/nm_fooof.py +139 -159
  51. py_neuromodulation/nm_generator.py +45 -37
  52. py_neuromodulation/nm_hjorth_raw.py +52 -73
  53. py_neuromodulation/nm_kalmanfilter.py +71 -58
  54. py_neuromodulation/nm_linelength.py +21 -33
  55. py_neuromodulation/nm_logger.py +66 -0
  56. py_neuromodulation/nm_mne_connectivity.py +149 -112
  57. py_neuromodulation/nm_mnelsl_generator.py +90 -0
  58. py_neuromodulation/nm_mnelsl_stream.py +116 -0
  59. py_neuromodulation/nm_nolds.py +96 -93
  60. py_neuromodulation/nm_normalization.py +173 -214
  61. py_neuromodulation/nm_oscillatory.py +423 -448
  62. py_neuromodulation/nm_plots.py +585 -612
  63. py_neuromodulation/nm_preprocessing.py +83 -0
  64. py_neuromodulation/nm_projection.py +370 -394
  65. py_neuromodulation/nm_rereference.py +97 -95
  66. py_neuromodulation/nm_resample.py +59 -50
  67. py_neuromodulation/nm_run_analysis.py +325 -435
  68. py_neuromodulation/nm_settings.py +289 -68
  69. py_neuromodulation/nm_settings.yaml +244 -0
  70. py_neuromodulation/nm_sharpwaves.py +423 -401
  71. py_neuromodulation/nm_stats.py +464 -480
  72. py_neuromodulation/nm_stream.py +398 -0
  73. py_neuromodulation/nm_stream_abc.py +166 -218
  74. py_neuromodulation/nm_types.py +193 -0
  75. py_neuromodulation/plots/STN_surf.mat +0 -0
  76. py_neuromodulation/plots/Vertices.mat +0 -0
  77. py_neuromodulation/plots/faces.mat +0 -0
  78. py_neuromodulation/plots/grid.mat +0 -0
  79. {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.5.dist-info}/METADATA +185 -182
  80. py_neuromodulation-0.0.5.dist-info/RECORD +83 -0
  81. {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.5.dist-info}/WHEEL +1 -2
  82. {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.5.dist-info/licenses}/LICENSE +21 -21
  83. docs/build/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -68
  84. docs/build/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -233
  85. docs/build/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
  86. docs/build/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -97
  87. docs/build/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
  88. docs/build/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -192
  89. docs/build/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
  90. docs/build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -68
  91. docs/build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -239
  92. docs/build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
  93. docs/build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -97
  94. docs/build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
  95. docs/build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -192
  96. docs/build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
  97. docs/source/_build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -76
  98. docs/source/_build/html/_downloads/0d0d0a76e8f648d5d3cbc47da6351932/plot_real_time_demo.py +0 -97
  99. docs/source/_build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -240
  100. docs/source/_build/html/_downloads/5d73cadc59a8805c47e3b84063afc157/plot_example_BIDS.py +0 -233
  101. docs/source/_build/html/_downloads/7660317fa5a6bfbd12fcca9961457fc4/plot_example_rmap_computing.py +0 -63
  102. docs/source/_build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
  103. docs/source/_build/html/_downloads/839e5b319379f7fd9e867deb00fd797f/plot_example_gridPointProjection.py +0 -210
  104. docs/source/_build/html/_downloads/ae8be19afe5e559f011fc9b138968ba0/plot_first_demo.py +0 -192
  105. docs/source/_build/html/_downloads/b8b06cacc17969d3725a0b6f1d7741c5/plot_example_sharpwave_analysis.py +0 -219
  106. docs/source/_build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -121
  107. docs/source/_build/html/_downloads/c31a86c0b68cb4167d968091ace8080d/plot_example_add_feature.py +0 -68
  108. docs/source/_build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
  109. docs/source/_build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -189
  110. docs/source/_build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
  111. docs/source/auto_examples/plot_0_first_demo.py +0 -189
  112. docs/source/auto_examples/plot_1_example_BIDS.py +0 -240
  113. docs/source/auto_examples/plot_2_example_add_feature.py +0 -76
  114. docs/source/auto_examples/plot_3_example_sharpwave_analysis.py +0 -219
  115. docs/source/auto_examples/plot_4_example_gridPointProjection.py +0 -210
  116. docs/source/auto_examples/plot_5_example_rmap_computing.py +0 -64
  117. docs/source/auto_examples/plot_6_real_time_demo.py +0 -121
  118. docs/source/conf.py +0 -105
  119. examples/plot_0_first_demo.py +0 -189
  120. examples/plot_1_example_BIDS.py +0 -240
  121. examples/plot_2_example_add_feature.py +0 -76
  122. examples/plot_3_example_sharpwave_analysis.py +0 -219
  123. examples/plot_4_example_gridPointProjection.py +0 -210
  124. examples/plot_5_example_rmap_computing.py +0 -64
  125. examples/plot_6_real_time_demo.py +0 -121
  126. packages/realtime_decoding/build/lib/realtime_decoding/__init__.py +0 -4
  127. packages/realtime_decoding/build/lib/realtime_decoding/decoder.py +0 -104
  128. packages/realtime_decoding/build/lib/realtime_decoding/features.py +0 -163
  129. packages/realtime_decoding/build/lib/realtime_decoding/helpers.py +0 -15
  130. packages/realtime_decoding/build/lib/realtime_decoding/run_decoding.py +0 -345
  131. packages/realtime_decoding/build/lib/realtime_decoding/trainer.py +0 -54
  132. packages/tmsi/build/lib/TMSiFileFormats/__init__.py +0 -37
  133. packages/tmsi/build/lib/TMSiFileFormats/file_formats/__init__.py +0 -36
  134. packages/tmsi/build/lib/TMSiFileFormats/file_formats/lsl_stream_writer.py +0 -200
  135. packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_file_writer.py +0 -496
  136. packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_to_edf_converter.py +0 -236
  137. packages/tmsi/build/lib/TMSiFileFormats/file_formats/xdf_file_writer.py +0 -977
  138. packages/tmsi/build/lib/TMSiFileFormats/file_readers/__init__.py +0 -35
  139. packages/tmsi/build/lib/TMSiFileFormats/file_readers/edf_reader.py +0 -116
  140. packages/tmsi/build/lib/TMSiFileFormats/file_readers/poly5reader.py +0 -294
  141. packages/tmsi/build/lib/TMSiFileFormats/file_readers/xdf_reader.py +0 -229
  142. packages/tmsi/build/lib/TMSiFileFormats/file_writer.py +0 -102
  143. packages/tmsi/build/lib/TMSiPlotters/__init__.py +0 -2
  144. packages/tmsi/build/lib/TMSiPlotters/gui/__init__.py +0 -39
  145. packages/tmsi/build/lib/TMSiPlotters/gui/_plotter_gui.py +0 -234
  146. packages/tmsi/build/lib/TMSiPlotters/gui/plotting_gui.py +0 -440
  147. packages/tmsi/build/lib/TMSiPlotters/plotters/__init__.py +0 -44
  148. packages/tmsi/build/lib/TMSiPlotters/plotters/hd_emg_plotter.py +0 -446
  149. packages/tmsi/build/lib/TMSiPlotters/plotters/impedance_plotter.py +0 -589
  150. packages/tmsi/build/lib/TMSiPlotters/plotters/signal_plotter.py +0 -1326
  151. packages/tmsi/build/lib/TMSiSDK/__init__.py +0 -54
  152. packages/tmsi/build/lib/TMSiSDK/device.py +0 -588
  153. packages/tmsi/build/lib/TMSiSDK/devices/__init__.py +0 -34
  154. packages/tmsi/build/lib/TMSiSDK/devices/saga/TMSi_Device_API.py +0 -1764
  155. packages/tmsi/build/lib/TMSiSDK/devices/saga/__init__.py +0 -34
  156. packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_device.py +0 -1366
  157. packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_types.py +0 -520
  158. packages/tmsi/build/lib/TMSiSDK/devices/saga/xml_saga_config.py +0 -165
  159. packages/tmsi/build/lib/TMSiSDK/error.py +0 -95
  160. packages/tmsi/build/lib/TMSiSDK/sample_data.py +0 -63
  161. packages/tmsi/build/lib/TMSiSDK/sample_data_server.py +0 -99
  162. packages/tmsi/build/lib/TMSiSDK/settings.py +0 -45
  163. packages/tmsi/build/lib/TMSiSDK/tmsi_device.py +0 -111
  164. packages/tmsi/build/lib/__init__.py +0 -4
  165. packages/tmsi/build/lib/apex_sdk/__init__.py +0 -34
  166. packages/tmsi/build/lib/apex_sdk/device/__init__.py +0 -41
  167. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API.py +0 -1009
  168. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_enums.py +0 -239
  169. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_structures.py +0 -668
  170. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_device.py +0 -1611
  171. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_dongle.py +0 -38
  172. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_event_reader.py +0 -57
  173. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_channel.py +0 -44
  174. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_config.py +0 -150
  175. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_const.py +0 -36
  176. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_impedance_channel.py +0 -48
  177. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_info.py +0 -108
  178. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/dongle_info.py +0 -39
  179. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/download_measurement.py +0 -77
  180. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/eeg_measurement.py +0 -150
  181. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/impedance_measurement.py +0 -129
  182. packages/tmsi/build/lib/apex_sdk/device/threads/conversion_thread.py +0 -59
  183. packages/tmsi/build/lib/apex_sdk/device/threads/sampling_thread.py +0 -57
  184. packages/tmsi/build/lib/apex_sdk/device/tmsi_channel.py +0 -83
  185. packages/tmsi/build/lib/apex_sdk/device/tmsi_device.py +0 -201
  186. packages/tmsi/build/lib/apex_sdk/device/tmsi_device_enums.py +0 -103
  187. packages/tmsi/build/lib/apex_sdk/device/tmsi_dongle.py +0 -43
  188. packages/tmsi/build/lib/apex_sdk/device/tmsi_event_reader.py +0 -50
  189. packages/tmsi/build/lib/apex_sdk/device/tmsi_measurement.py +0 -118
  190. packages/tmsi/build/lib/apex_sdk/sample_data_server/__init__.py +0 -33
  191. packages/tmsi/build/lib/apex_sdk/sample_data_server/event_data.py +0 -44
  192. packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data.py +0 -50
  193. packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data_server.py +0 -136
  194. packages/tmsi/build/lib/apex_sdk/tmsi_errors/error.py +0 -126
  195. packages/tmsi/build/lib/apex_sdk/tmsi_sdk.py +0 -113
  196. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/apex/apex_structure_generator.py +0 -134
  197. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/decorators.py +0 -60
  198. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/logger_filter.py +0 -42
  199. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/singleton.py +0 -42
  200. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/support_functions.py +0 -72
  201. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/tmsi_logger.py +0 -98
  202. py_neuromodulation/nm_EpochStream.py +0 -92
  203. py_neuromodulation/nm_across_patient_decoding.py +0 -927
  204. py_neuromodulation/nm_cohortwrapper.py +0 -435
  205. py_neuromodulation/nm_eval_timing.py +0 -239
  206. py_neuromodulation/nm_features_abc.py +0 -39
  207. py_neuromodulation/nm_stream_offline.py +0 -358
  208. py_neuromodulation/utils/_logging.py +0 -24
  209. py_neuromodulation-0.0.3.dist-info/RECORD +0 -188
  210. py_neuromodulation-0.0.3.dist-info/top_level.txt +0 -5
  211. tests/__init__.py +0 -0
  212. tests/conftest.py +0 -117
  213. tests/test_all_examples.py +0 -10
  214. tests/test_all_features.py +0 -63
  215. tests/test_bispectra.py +0 -70
  216. tests/test_bursts.py +0 -105
  217. tests/test_feature_sampling_rates.py +0 -143
  218. tests/test_fooof.py +0 -16
  219. tests/test_initalization_offline_stream.py +0 -41
  220. tests/test_multiprocessing.py +0 -58
  221. tests/test_nan_values.py +0 -29
  222. tests/test_nm_filter.py +0 -95
  223. tests/test_nm_resample.py +0 -63
  224. tests/test_normalization_settings.py +0 -146
  225. tests/test_notch_filter.py +0 -31
  226. tests/test_osc_features.py +0 -424
  227. tests/test_preprocessing_filter.py +0 -151
  228. tests/test_rereference.py +0 -171
  229. tests/test_sampling.py +0 -57
  230. tests/test_settings_change_after_init.py +0 -76
  231. tests/test_sharpwave.py +0 -165
  232. tests/test_target_channel_add.py +0 -100
  233. tests/test_timing.py +0 -80
@@ -1,446 +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 ${hd_emg_plotter.py}
26
- * @brief Plotter object that displays an heatmap based on real-time computed
27
- * RMS values, designed for HD-EMG applications.
28
- *
29
- */
30
-
31
-
32
- '''
33
-
34
- from PySide2 import QtGui, QtCore, QtWidgets
35
- import numpy as np
36
- import pyqtgraph as pg
37
- import time
38
- import queue
39
- from scipy import signal, interpolate
40
- import sys
41
-
42
-
43
- from os.path import join, dirname, realpath, normpath
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
-
52
- from TMSiSDK.device import DeviceInterfaceType, ChannelType
53
-
54
-
55
- class HeatMapViewer():
56
- """ Class that creates a GUI to display the impedance values in a gridded
57
- layout.
58
- """
59
- def __init__(self, gui_handle, device, tail_orientation, signal_lim, grid_type = 'flex pcb grid'):
60
- """ Setting up the GUI's elements
61
- """
62
-
63
- if sys.platform == "linux" or sys.platform == "linux2":
64
- print('This plotter is not compatible with the current version of the TMSi Python Interface on Linux (Ubuntu 18.04 LTS)\n')
65
- return
66
-
67
- # Pass the device handle to the GUI
68
- self.device = device
69
-
70
- self.gui_handle = gui_handle
71
- self.RealTimePlotWidget = self.gui_handle.RealTimePlotWidget
72
-
73
- # Determine used number of channels
74
- if self.device.config.num_channels > 64:
75
- if '4-8' in grid_type or grid_type[-1] == '1' or grid_type[-1] == '2':
76
- self._EMG_chans = 32
77
- else:
78
- self._EMG_chans = 64
79
- else:
80
- self._EMG_chans = 32
81
-
82
- self._preprocess_wifi = False
83
- if self.device.info.dr_interface == DeviceInterfaceType.wifi:
84
- self._preprocess_wifi = True
85
-
86
- self.sample_rate = self.device.config.get_sample_rate(ChannelType.counter)
87
-
88
- # Orientation of the grid on the body
89
- self.tail_orientation = tail_orientation
90
-
91
- # Upper limit colorbar
92
- self.signal_lim = signal_lim
93
-
94
- # Type of used grid
95
- self.grid_type = grid_type
96
- if not '11' in self.grid_type:
97
- self.n_x = int(self._EMG_chans/8)
98
- self.n_y = 8
99
- else:
100
- self.n_x = int(np.ceil(self._EMG_chans/11))
101
- self.n_y = 11
102
-
103
- # Set up UI and thread
104
- self.initUI()
105
- self.setupThread()
106
-
107
- def initUI(self):
108
- """ Method responsible for constructing the basic elements in the plot.
109
- All viewboxes have a set size so that the information can be displayed
110
- correctly.
111
- """
112
- # Set view settings
113
- self.RealTimePlotWidget.setBackground('w')
114
- # self.showMaximized()
115
-
116
- # Add plot window for the channels
117
- self.RealTimePlotWidget.window = self.RealTimePlotWidget.addPlot()
118
- self.RealTimePlotWidget.window.setAspectLocked(lock=True, ratio = 1)
119
-
120
- # Write the ticks to the plot
121
- self.RealTimePlotWidget.window.hideAxis('left')
122
- self.RealTimePlotWidget.window.hideAxis('bottom')
123
-
124
- # Disable auto-scaling and menu
125
- self.RealTimePlotWidget.window.hideButtons()
126
- self.RealTimePlotWidget.window.setMenuEnabled(False)
127
- self.RealTimePlotWidget.window.setMouseEnabled(x = False, y = False)
128
-
129
- # Delete CREF channel from channel conversion list
130
- self.channel_conversion_list = np.delete(self.gui_handle.channel_conversion_list[:self._EMG_chans+1], 0)
131
-
132
- # Detect disabled channels
133
- self.channel_insertion_list = []
134
- offset=0
135
- for ch in range(self._EMG_chans+1):
136
- if not self.device.channels[ch-offset].name == self.device._config._channels[ch].alt_name:
137
- offset =offset + 1
138
- self.channel_insertion_list.append(ch)
139
-
140
- # Insert dummy channels
141
- self.dummy_chan = []
142
- if '11' in self.grid_type:
143
- if not self.grid_type[-1] == '2':
144
- self.dummy_chan.append(10)
145
- self.channel_conversion_list = np.insert(self.channel_conversion_list, 10, max(self.channel_conversion_list)+1)
146
- if not self.grid_type[-1] == '1':
147
- dummy_chan=max(self.channel_conversion_list)+1
148
- self.dummy_chan.append(dummy_chan)
149
- self.channel_conversion_list = np.append(self.channel_conversion_list, dummy_chan)
150
-
151
- # Ratio is slightly different between 32/64 channel setup
152
- # Number of rows/columns depends on grid-type
153
- if not '11' in self.grid_type:
154
- if self._EMG_chans == 32:
155
- self._x_interpolate = np.arange(0, int(self._EMG_chans/8) - 1 + .1, 0.1)
156
- self._y_interpolate = np.arange(0, int(self._EMG_chans/(self._EMG_chans/8)) - 1 + .1, 0.1)
157
- else:
158
- self._x_interpolate = np.arange(0, int(self._EMG_chans/8) - 1 + .2, 0.1)
159
- self._y_interpolate = np.arange(0, int(self._EMG_chans/(self._EMG_chans/8)) - 1 + .1, 0.1)
160
- else:
161
- self._x_interpolate = np.arange(0, self.n_x - 1 + .1, 0.1)
162
- self._y_interpolate = np.arange(0, self.n_y - 1 + .1, 0.1)
163
- self._dummy_val = np.zeros((len(self._x_interpolate), len(self._y_interpolate)))
164
-
165
- if self.tail_orientation == 'Right' or self.tail_orientation == 'right':
166
- self._dummy_val = np.rot90(self._dummy_val, 1)
167
- elif self.tail_orientation == 'Left' or self.tail_orientation == 'left':
168
- self._dummy_val = np.rot90(self._dummy_val, 3)
169
-
170
- # Create image item
171
- self.img = pg.ImageItem(image = self._dummy_val)
172
- self.RealTimePlotWidget.window.addItem(self.img)
173
-
174
- # Prepare a linear color map
175
- cm = pg.colormap.get('CET-R4')
176
-
177
- # Insert a Colorbar, non-interactive with a label
178
- self.bar = pg.ColorBarItem(values = (0, self.signal_lim), colorMap=cm, interactive = False, label = 'RMS (\u03BCVolt)', )
179
- self.bar.setImageItem(self.img, insert_in = self.RealTimePlotWidget.window)
180
-
181
- # Scale factor (number of interpolation points to cover a width of n columns)
182
- corr_x = len(self._x_interpolate) / max(self._x_interpolate)
183
-
184
- # Scale factor (number of interpolation points to cover a width of n rows)
185
- corr_y = len(self._y_interpolate) / max(self._y_interpolate)
186
-
187
- # Number of rows/columns depends on grid-type
188
- locs = np.array([[(i%self.n_y) * corr_y, int(i/self.n_y) * corr_x] for i in range(self.n_x*self.n_y)])
189
-
190
- # Text object required for the tail orientation
191
- tail_text = pg.TextItem('TAIL', (128, 128, 128), anchor=(0, 0))
192
- tail_text.setFont(QtGui.QFont("Times", 16, QtGui.QFont.ExtraBold))
193
-
194
- # Initialise the standard format for the different indicators
195
- if self.tail_orientation == 'Left' or self.tail_orientation == 'left':
196
- self.spots = [{'pos': locs[i], 'size': 5, 'pen': 'k', 'brush': QtGui.QBrush(QtGui.QColor(128, 128, 128))} \
197
- for i in range(self._EMG_chans+len(self.dummy_chan)) if self.channel_conversion_list[i] <= self._EMG_chans]
198
- tail_text.setPos(self.spots[0]['pos'][0] - 1 * corr_y, self.spots[0]['pos'][1] + 1.5 * corr_x)
199
-
200
- elif self.tail_orientation == 'Up' or self.tail_orientation == 'up':
201
- self.spots = [{'pos': [locs.T[1][-i-1], locs[::-1].T[0][-i-1]], 'size': 5, 'pen': 'k', 'brush': QtGui.QBrush(QtGui.QColor(128, 128, 128))} \
202
- for i in range(self._EMG_chans+len(self.dummy_chan)) if self.channel_conversion_list[i] <= self._EMG_chans]
203
- tail_text.setPos(self.spots[0]['pos'][0] - 2 * corr_y, self.spots[0]['pos'][1] - 0.5 * corr_x)
204
-
205
- elif self.tail_orientation == 'Right' or self.tail_orientation == 'right':
206
- self.spots = [{'pos': locs[::-1][i], 'size': 5, 'pen': 'k', 'brush': QtGui.QBrush(QtGui.QColor(128, 128, 128))} \
207
- for i in range(self._EMG_chans+len(self.dummy_chan)) if self.channel_conversion_list[i] <= self._EMG_chans]
208
- tail_text.setPos(self.spots[0]['pos'][0] + 0.5 * corr_y, self.spots[0]['pos'][1] - 1.5 * corr_x)
209
-
210
- elif self.tail_orientation == 'Down' or self.tail_orientation == 'down':
211
- self.spots = [{'pos': [locs[::-1].T[1][-i-1], locs.T[0][-i-1]], 'size': 5, 'pen': 'k', 'brush': QtGui.QBrush(QtGui.QColor(128, 128, 128))} \
212
- for i in range(self._EMG_chans+len(self.dummy_chan)) if self.channel_conversion_list[i] <= self._EMG_chans]
213
- tail_text.setPos(self.spots[0]['pos'][0] + 1 *corr_y, self.spots[0]['pos'][1] + 0.5 * corr_x)
214
-
215
- # Add the text object to the plot
216
- self.RealTimePlotWidget.window.addItem(tail_text)
217
-
218
- i_corr = 0
219
- # Set the position for each indicator
220
- for i in range(len(self.device._config._channels)):
221
- if i > (self.n_x*self.n_y) - 1:
222
- break
223
- # Select channel from conversion list and correct for dummy channels
224
- i_ch = self.channel_conversion_list[i]
225
- if i_ch <= (self._EMG_chans):
226
- # Place the name of each channel below the respective indicator
227
- # Text colour is red for disabled channels
228
- text = f'{self.device._config._channels[i_ch].alt_name: ^10}'
229
- if i_ch in self.channel_insertion_list:
230
- t_item = pg.TextItem(text, (255, 0, 0), anchor=(0, 0))
231
- else:
232
- t_item = pg.TextItem(text, (128, 128, 128), anchor=(0, 0))
233
- t_item.setPos(self.spots[i-i_corr]['pos'][0] -.25, self.spots[i-i_corr]['pos'][1] + .1)
234
- self.RealTimePlotWidget.window.addItem(t_item)
235
- else:
236
- i_corr = i_corr + 1
237
-
238
-
239
- # Add all indicators to the plot
240
- self.c = pg.ScatterPlotItem(self.spots)
241
- self.RealTimePlotWidget.window.addItem(self.c)
242
-
243
- self.RealTimePlotWidget.window.invertY(True)
244
-
245
-
246
- @QtCore.Slot(object)
247
- def update_plot(self, data):
248
- """ Method that updates the indicators according to the measured impedance values
249
- """
250
- self.img.setImage(data, autoRange=False, autoLevels=False)
251
-
252
- def _update_scale(self, type_flag):
253
- """Method that creates a different range in which the heatmap is presented"""
254
-
255
- data = self.img.image
256
- if type_flag == 'scale':
257
- self.signal_lim = np.nanmax(data)
258
- elif type_flag == 'range':
259
- self.signal_lim = int(self.gui_handle.set_range_box.currentText())
260
-
261
- self.bar.setLevels(low = 0, high = self.signal_lim)
262
-
263
-
264
- def setupThread(self):
265
- """ Method that initialises the sampling thread of the device
266
- """
267
- # Create a Thread
268
- self.thread = QtCore.QThread()
269
- # Instantiate the worker class
270
- self.worker = SamplingThread(self)
271
-
272
- # Move the worker to a Thread
273
- self.worker.moveToThread(self.thread)
274
-
275
- # Connect signals to slots
276
- self.thread.started.connect(self.worker.update_samples)
277
- self.worker.output.connect(self.update_plot)
278
-
279
-
280
- class SamplingThread(QtCore.QObject):
281
- """ Class responsible for sampling the data from the device
282
- """
283
- # Initialise the ouptut object
284
- output = QtCore.Signal(object)
285
- def __init__(self, main_class):
286
- QtCore.QObject.__init__(self)
287
-
288
- # Access initialised values from the GUI class
289
- self.device = main_class.device
290
- self.sample_rate = main_class.sample_rate
291
- self._EMG_chans = main_class._EMG_chans
292
- self.grid_type = main_class.grid_type
293
- self.channel_conversion_list = main_class.channel_conversion_list
294
- self._preprocess_wifi = main_class._preprocess_wifi
295
-
296
- self.window_buffer = np.zeros((self._EMG_chans+len(main_class.dummy_chan), self.sample_rate * 5))
297
- self.window_rms_size = self.sample_rate // 4
298
- self._add_final = 0
299
-
300
- self.sos = signal.butter(2, 10, 'highpass', fs=self.sample_rate, output='sos')
301
- z_sos0 = signal.sosfilt_zi(self.sos)
302
- self.z_sos = np.repeat(z_sos0[:, np.newaxis, :], (self._EMG_chans+len(main_class.dummy_chan)), axis=1)
303
-
304
- self.n_x=main_class.n_x
305
- self.n_y=main_class.n_y
306
- self._x_grid = np.arange(0, self.n_x, dtype=int)
307
- self._y_grid = np.arange(0, self.n_y, dtype=int)
308
-
309
- self._x_interpolate = main_class._x_interpolate
310
- self._y_interpolate = main_class._y_interpolate
311
-
312
- self.tail_orientation = main_class.tail_orientation
313
- self.channel_insertion_list = main_class.channel_insertion_list
314
- self.dummy_chan = main_class.dummy_chan
315
-
316
- # Prepare Queue
317
- self.q_sample_sets = queue.Queue(1000)
318
-
319
- # Register the consumer to the sample server
320
- sample_data_server.registerConsumer(self.device.id, self.q_sample_sets)
321
-
322
- # Start measurement
323
- self.sampling = True
324
-
325
- @QtCore.Slot()
326
- def update_samples(self):
327
- """ Method that retrieves the sample data from the device. The method
328
- gives the impedance value as output
329
- """
330
-
331
- while self.sampling:
332
- while not self.q_sample_sets.empty():
333
-
334
- # Retrieve sample data from the sample_data_server queue
335
- sd = self.q_sample_sets.get()
336
- self.q_sample_sets.task_done()
337
-
338
- # Reshape the samples retrieved from the queue
339
- samples = np.reshape(sd.samples, (sd.num_samples_per_sample_set, sd.num_sample_sets), order = 'F')
340
- self.new_samples = sd.num_sample_sets
341
-
342
- conversion_list = self.channel_conversion_list
343
- # Missing samples are registered as NaN. This crashes the filter.
344
- # Therefore, copies are inserted for the filtered data
345
- if self._preprocess_wifi:
346
- find_nan = np.isnan(samples)
347
- if find_nan.any():
348
- idx_nan = np.where(np.isnan(samples))
349
- samples[idx_nan] = samples[idx_nan[0], idx_nan[1][0]-1]
350
-
351
- # Insert disabled channels to maintain proper channel positions
352
- if len(self.channel_insertion_list) == 1:
353
- samples = np.insert(samples, self.channel_insertion_list, 0, axis=0)
354
- else:
355
- for ch in self.channel_insertion_list:
356
- samples = np.insert(samples, ch, 0, axis=0)
357
-
358
- # Insert dummy channels
359
- for ch in self.dummy_chan:
360
- samples = np.insert(samples, self._EMG_chans+1, np.nan, axis=0)
361
-
362
- # Fill the window buffer with the reshaped sample set
363
- self.window_buffer[:, self._add_final:(self._add_final + self.new_samples)] = samples[conversion_list,:]
364
-
365
- if self._add_final + self.new_samples > self.window_rms_size:
366
- filt_data, self.z_sos = signal.sosfilt(self.sos, self.window_buffer[:, 0:self.window_rms_size], zi = self.z_sos)
367
-
368
- if self._preprocess_wifi:
369
- if np.isnan(filt_data).any():
370
- print('The filter crashed due to lost samples; resetting filter...')
371
- self.sos = signal.butter(2, 10, 'highpass', fs=self.sample_rate, output='sos')
372
- z_sos0 = signal.sosfilt_zi(self.sos)
373
- self.z_sos = np.repeat(z_sos0[:, np.newaxis, :], self._EMG_chans, axis=1)
374
-
375
- rms_data = np.sqrt(np.mean(filt_data**2, axis = 1))
376
-
377
- # Reshape to 2d
378
- rms_data = np.reshape(rms_data, (self.n_x,self.n_y)).T
379
-
380
- # Interpolation functions and mapping of dummy channels
381
- # Dummy channels are NaN, apply dubble filter to handle this
382
- nan_map = np.zeros_like(rms_data)
383
- nan_map[ np.isnan(rms_data) ] = 1
384
-
385
- rms_filled = rms_data.copy()
386
- rms_filled[ np.isnan(rms_data) ] = 0
387
-
388
- f = interpolate.interp2d(self._x_grid, self._y_grid, rms_filled, kind='linear')
389
- f_nan = interpolate.interp2d(self._x_grid, self._y_grid, nan_map, kind='linear')
390
-
391
- heatmap = f(self._x_interpolate, self._y_interpolate)
392
- nan_heatmap = f_nan( self._x_interpolate, self._y_interpolate )
393
- heatmap[ nan_heatmap>0 ] = np.nan
394
-
395
- # Rotate heatmap based on tail orientation
396
- if self.tail_orientation == 'Left' or self.tail_orientation == 'left':
397
- output_heatmap = heatmap
398
- elif self.tail_orientation == 'Up' or self.tail_orientation == 'up':
399
- output_heatmap = np.rot90(heatmap, 1)
400
- elif self.tail_orientation == 'Right' or self.tail_orientation == 'right':
401
- output_heatmap = np.rot90(heatmap, 2)
402
- elif self.tail_orientation == 'Down' or self.tail_orientation == 'down':
403
- output_heatmap = np.rot90(heatmap, 3)
404
-
405
- self._add_final = 0
406
-
407
- self.window_buffer = np.hstack((self.window_buffer[:,self.window_rms_size:], np.zeros(((self._EMG_chans+len(self.dummy_chan)), self.window_rms_size)) ))
408
- self.output.emit(output_heatmap)
409
-
410
- else:
411
- self._add_final += self.new_samples
412
-
413
- # Pause the thread so that the update does not happen too fast
414
- time.sleep(0.01)
415
-
416
- def stop(self):
417
- """ Method that is executed when the thread is terminated.
418
- This stop event stops the measurement and closes the connection to
419
- the device.
420
- """
421
- # self.device.stop_measurement()
422
- self.sampling = False
423
-
424
-
425
-
426
- if __name__ == "__main__":
427
- # Initialise the TMSi-SDK first before starting using it
428
- tmsi_device.initialize()
429
-
430
- # Create the device object to interface with the SAGA-system.
431
- dev = tmsi_device.create(tmsi_device.DeviceType.saga, DeviceInterfaceType.docked, DeviceInterfaceType.usb)
432
-
433
- # Find and open a connection to the SAGA-system and print its serial number
434
- dev.open()
435
- print("handle 1 " + str(dev.info.ds_serial_number))
436
-
437
- # Initialise the application
438
- app = QtWidgets.QApplication(sys.argv)
439
- # Define the GUI object and show it
440
- window = HDEMGPlot(figurename = 'An HDEMG Heatmap Plot', device = dev, tail_orientation='up')
441
- window.show()
442
-
443
- # Enter the event loop
444
- # sys.exit(app.exec_())
445
- app.exec_()
446
- dev.close()