biosignal-device-interface 0.1.311__py3-none-any.whl → 0.2.1a2__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 (42) hide show
  1. biosignal_device_interface/constants/devices/__init__.py +3 -3
  2. biosignal_device_interface/constants/devices/core/base_device_constants.py +61 -51
  3. biosignal_device_interface/constants/devices/otb/otb_muovi_constants.py +129 -129
  4. biosignal_device_interface/constants/devices/otb/otb_quattrocento_constants.py +313 -0
  5. biosignal_device_interface/constants/devices/otb/otb_quattrocento_light_constants.py +59 -59
  6. biosignal_device_interface/constants/devices/otb/otb_syncstation_constants.py +233 -0
  7. biosignal_device_interface/constants/plots/color_palette.py +59 -59
  8. biosignal_device_interface/devices/__init__.py +17 -15
  9. biosignal_device_interface/devices/core/base_device.py +424 -410
  10. biosignal_device_interface/devices/otb/__init__.py +29 -21
  11. biosignal_device_interface/devices/otb/otb_muovi.py +290 -291
  12. biosignal_device_interface/devices/otb/otb_quattrocento.py +332 -0
  13. biosignal_device_interface/devices/otb/otb_quattrocento_light.py +210 -213
  14. biosignal_device_interface/devices/otb/otb_syncstation.py +407 -0
  15. biosignal_device_interface/gui/device_template_widgets/all_devices_widget.py +51 -43
  16. biosignal_device_interface/gui/device_template_widgets/core/base_device_widget.py +130 -121
  17. biosignal_device_interface/gui/device_template_widgets/core/base_multiple_devices_widget.py +108 -108
  18. biosignal_device_interface/gui/device_template_widgets/otb/otb_devices_widget.py +44 -36
  19. biosignal_device_interface/gui/device_template_widgets/otb/otb_muovi_plus_widget.py +158 -158
  20. biosignal_device_interface/gui/device_template_widgets/otb/otb_muovi_widget.py +158 -158
  21. biosignal_device_interface/gui/device_template_widgets/otb/otb_quattrocento_light_widget.py +174 -170
  22. biosignal_device_interface/gui/device_template_widgets/otb/otb_quattrocento_widget.py +260 -0
  23. biosignal_device_interface/gui/device_template_widgets/otb/otb_syncstation_widget.py +262 -0
  24. biosignal_device_interface/gui/plot_widgets/biosignal_plot_widget.py +501 -500
  25. biosignal_device_interface/gui/ui/devices_template_widget.ui +38 -38
  26. biosignal_device_interface/gui/ui/otb_muovi_plus_template_widget.ui +171 -171
  27. biosignal_device_interface/gui/ui/otb_muovi_template_widget.ui +171 -171
  28. biosignal_device_interface/gui/ui/otb_quattrocento_light_template_widget.ui +266 -266
  29. biosignal_device_interface/gui/ui/otb_quattrocento_template_widget.ui +415 -0
  30. biosignal_device_interface/gui/ui/otb_syncstation_template_widget.ui +732 -0
  31. biosignal_device_interface/gui/ui_compiled/devices_template_widget.py +56 -56
  32. biosignal_device_interface/gui/ui_compiled/otb_muovi_plus_template_widget.py +153 -153
  33. biosignal_device_interface/gui/ui_compiled/otb_muovi_template_widget.py +153 -153
  34. biosignal_device_interface/gui/ui_compiled/otb_quattrocento_light_template_widget.py +217 -217
  35. biosignal_device_interface/gui/ui_compiled/otb_quattrocento_template_widget.py +318 -0
  36. biosignal_device_interface/gui/ui_compiled/otb_syncstation_template_widget.py +495 -0
  37. biosignal_device_interface-0.2.1a2.dist-info/LICENSE +675 -0
  38. {biosignal_device_interface-0.1.311.dist-info → biosignal_device_interface-0.2.1a2.dist-info}/METADATA +6 -4
  39. biosignal_device_interface-0.2.1a2.dist-info/RECORD +46 -0
  40. {biosignal_device_interface-0.1.311.dist-info → biosignal_device_interface-0.2.1a2.dist-info}/WHEEL +1 -1
  41. biosignal_device_interface-0.1.311.dist-info/LICENSE +0 -395
  42. biosignal_device_interface-0.1.311.dist-info/RECORD +0 -36
@@ -1,213 +1,210 @@
1
- """
2
- 1) Quattrocento Light class for real-time interface to
3
- Quattrocento using OT Biolab Light.
4
-
5
- 2) Quattrocento class for direct real-time interface to
6
- Quattrocento without using OT Biolab Light.
7
-
8
- Developer: Dominik I. Braun
9
- Contact: dome.braun@fau.de
10
- Last Update: 2023-06-05
11
- """
12
-
13
- # Python Libraries
14
- from __future__ import annotations
15
- from typing import TYPE_CHECKING, Union, Dict
16
- from PySide6.QtNetwork import QTcpSocket, QHostAddress
17
- from PySide6.QtCore import QIODevice
18
- import numpy as np
19
-
20
-
21
- from biosignal_device_interface.devices.core.base_device import BaseDevice
22
- from biosignal_device_interface.constants.devices.core.base_device_constants import (
23
- DeviceType,
24
- )
25
- from biosignal_device_interface.constants.devices.otb.otb_quattrocento_light_constants import (
26
- COMMAND_START_STREAMING,
27
- COMMAND_STOP_STREAMING,
28
- CONNECTION_RESPONSE,
29
- QUATTROCENTO_LIGHT_STREAMING_FREQUENCY_DICT,
30
- QUATTROCENTO_SAMPLING_FREQUENCY_DICT,
31
- QuattrocentoLightSamplingFrequency,
32
- QuattrocentoLightStreamingFrequency,
33
- )
34
-
35
-
36
- if TYPE_CHECKING:
37
- # Python Libraries
38
- from PySide6.QtWidgets import QMainWindow, QWidget
39
- from aenum import Enum
40
-
41
-
42
- class OTBQuattrocentoLight(BaseDevice):
43
- """
44
- QuattrocentoLight device class derived from BaseDevice class.
45
- The QuattrocentoLight is using a TCP/IP protocol to communicate with the device.
46
-
47
- This class directly interfaces with the OT Biolab Light software from
48
- OT Bioelettronica. The configured settings of the device have to
49
- match the settings from the OT Biolab Light software!
50
- """
51
-
52
- def __init__(
53
- self,
54
- parent: Union[QMainWindow, QWidget] = None,
55
- ) -> None:
56
- super().__init__(parent)
57
-
58
- # Device Parameters
59
- self._device_type: DeviceType = DeviceType.OTB_QUATTROCENTO_LIGHT
60
-
61
- # Device Information
62
- self._number_of_channels: int = 408 # Fix value
63
- self._auxiliary_channel_start_index: int = 384 # Fix value
64
- self._number_of_auxiliary_channels: int = 16 # Fix value
65
- self._conversion_factor_biosignal: float = 5 / (2**16) / 150 * 1000 # in mV
66
- self._conversion_factor_auxiliary: float = 5 / (2**16) / 0.5 # in mV
67
- self._bytes_per_sample: int = 2 # Fix value
68
- # Quattrocento unique parameters
69
- self._streaming_frequency: int | None = None
70
-
71
- # Connection Parameters
72
- self._interface: QTcpSocket = QTcpSocket()
73
-
74
- # Configuration Parameters
75
- self._grids: list[int] | None = None
76
- self._grid_size: int = 64 # TODO: This is only valid for the big electrodes
77
- self._streaming_frequency_mode: QuattrocentoLightStreamingFrequency | None = (
78
- None
79
- )
80
- self._sampling_frequency_mode: QuattrocentoLightSamplingFrequency | None = None
81
-
82
- def _connect_to_device(self) -> bool:
83
- super()._connect_to_device()
84
-
85
- self._received_bytes: bytearray = bytearray()
86
- return self._make_request()
87
-
88
- def _make_request(self) -> bool:
89
- super()._make_request()
90
- # Signal self.connect_toggled is emitted in _read_data
91
- self._interface.connectToHost(
92
- QHostAddress(self._connection_settings[0]),
93
- self._connection_settings[1],
94
- QIODevice.ReadWrite,
95
- )
96
-
97
- if not self._interface.waitForConnected(1000):
98
- self._disconnect_from_device()
99
- return False
100
-
101
- self._interface.readyRead.connect(self._read_data)
102
-
103
- return True
104
-
105
- def _disconnect_from_device(self) -> None:
106
- super()._disconnect_from_device()
107
-
108
- self._interface.disconnectFromHost()
109
- self._interface.readyRead.disconnect(self._read_data)
110
- self._interface.close()
111
-
112
- def configure_device(
113
- self, params: Dict[str, Union[Enum, Dict[str, Enum]]] # type: ignore
114
- ) -> None:
115
- super().configure_device(params)
116
-
117
- # Configure the device
118
- self._number_of_biosignal_channels = len(self._grids) * self._grid_size
119
- self._biosignal_channel_indices = np.array(
120
- [
121
- i * self._grid_size + j
122
- for i in self._grids
123
- for j in range(self._grid_size)
124
- ]
125
- )
126
-
127
- self._auxiliary_channel_indices = np.array(
128
- [
129
- i + self._auxiliary_channel_start_index
130
- for i in range(self._number_of_auxiliary_channels)
131
- ]
132
- )
133
-
134
- self._streaming_frequency = QUATTROCENTO_LIGHT_STREAMING_FREQUENCY_DICT[
135
- self._streaming_frequency_mode
136
- ]
137
- self._sampling_frequency = QUATTROCENTO_SAMPLING_FREQUENCY_DICT[
138
- self._sampling_frequency_mode
139
- ]
140
-
141
- self._samples_per_frame = self._sampling_frequency // self._streaming_frequency
142
-
143
- self._buffer_size = (
144
- self._bytes_per_sample * self._number_of_channels * self._samples_per_frame
145
- )
146
-
147
- self._is_configured = True
148
- self.configure_toggled.emit(True)
149
-
150
- def _start_streaming(self) -> None:
151
- super()._start_streaming()
152
-
153
- self._interface.write(COMMAND_START_STREAMING)
154
-
155
- def _stop_streaming(self) -> None:
156
- super()._stop_streaming()
157
-
158
- self._interface.write(COMMAND_STOP_STREAMING)
159
- self._interface.waitForBytesWritten(1000)
160
-
161
- def clear_socket(self) -> None:
162
- super().clear_socket()
163
-
164
- self._interface.readAll()
165
-
166
- def _read_data(self) -> None:
167
- super()._read_data()
168
-
169
- # Wait for connection response
170
- if not self._is_connected and (
171
- self._interface.bytesAvailable() == len(CONNECTION_RESPONSE)
172
- and self._interface.readAll() == CONNECTION_RESPONSE
173
- ):
174
- self._is_connected = True
175
- self.connect_toggled.emit(True)
176
- return
177
- if not self._is_streaming:
178
- self.clear_socket()
179
- return
180
-
181
- while self._interface.bytesAvailable() > self._buffer_size:
182
- packet = self._interface.read(self._buffer_size)
183
- if not packet:
184
- continue
185
-
186
- self._received_bytes.extend(packet)
187
-
188
- while len(self._received_bytes) >= self._buffer_size:
189
- data_to_process = self._received_bytes[: self._buffer_size]
190
- self._process_data(data_to_process)
191
- self._received_bytes = self._received_bytes[self._buffer_size :]
192
-
193
- def _process_data(self, input: bytearray) -> None:
194
- super()._process_data(input)
195
-
196
- # Decode the data
197
- decoded_data = np.frombuffer(input, dtype=np.int16)
198
-
199
- # Reshape it to the correct format
200
- processed_data = decoded_data.reshape(
201
- self._number_of_channels, -1, order="F"
202
- ).astype(np.float32)
203
-
204
- # Emit the data
205
- self.data_available.emit(processed_data)
206
-
207
- biosignal_data = self._extract_biosignal_data(processed_data)
208
- self.biosignal_data_available.emit(biosignal_data)
209
- auxiliary_data = self._extract_auxiliary_data(processed_data)
210
- self.auxiliary_data_available.emit(auxiliary_data)
211
-
212
- def get_device_information(self) -> Dict[str, Enum | int | float | str]: # type: ignore
213
- return super().get_device_information()
1
+ """
2
+ Quattrocento Light class for real-time interface to
3
+ Quattrocento using OT Biolab Light.
4
+
5
+ Developer: Dominik I. Braun
6
+ Contact: dome.braun@fau.de
7
+ Last Update: 2023-06-05
8
+ """
9
+
10
+ # Python Libraries
11
+ from __future__ import annotations
12
+ from typing import TYPE_CHECKING, Union, Dict
13
+ from PySide6.QtNetwork import QTcpSocket, QHostAddress
14
+ from PySide6.QtCore import QIODevice
15
+ import numpy as np
16
+
17
+
18
+ from biosignal_device_interface.devices.core.base_device import BaseDevice
19
+ from biosignal_device_interface.constants.devices.core.base_device_constants import (
20
+ DeviceType,
21
+ )
22
+ from biosignal_device_interface.constants.devices.otb.otb_quattrocento_light_constants import (
23
+ COMMAND_START_STREAMING,
24
+ COMMAND_STOP_STREAMING,
25
+ CONNECTION_RESPONSE,
26
+ QUATTROCENTO_LIGHT_STREAMING_FREQUENCY_DICT,
27
+ QUATTROCENTO_SAMPLING_FREQUENCY_DICT,
28
+ QuattrocentoLightSamplingFrequency,
29
+ QuattrocentoLightStreamingFrequency,
30
+ )
31
+
32
+
33
+ if TYPE_CHECKING:
34
+ # Python Libraries
35
+ from PySide6.QtWidgets import QMainWindow, QWidget
36
+ from aenum import Enum
37
+
38
+
39
+ class OTBQuattrocentoLight(BaseDevice):
40
+ """
41
+ QuattrocentoLight device class derived from BaseDevice class.
42
+ The QuattrocentoLight is using a TCP/IP protocol to communicate with the device.
43
+
44
+ This class directly interfaces with the OT Biolab Light software from
45
+ OT Bioelettronica. The configured settings of the device have to
46
+ match the settings from the OT Biolab Light software!
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ parent: Union[QMainWindow, QWidget] = None,
52
+ ) -> None:
53
+ super().__init__(parent)
54
+
55
+ # Device Parameters
56
+ self._device_type: DeviceType = DeviceType.OTB_QUATTROCENTO_LIGHT
57
+
58
+ # Device Information
59
+ self._number_of_channels: int = 408 # Fix value
60
+ self._auxiliary_channel_start_index: int = 384 # Fix value
61
+ self._number_of_auxiliary_channels: int = 16 # Fix value
62
+ self._conversion_factor_biosignal: float = 5 / (2**16) / 150 * 1000 # in mV
63
+ self._conversion_factor_auxiliary: float = 5 / (2**16) / 0.5 # in mV
64
+ self._bytes_per_sample: int = 2 # Fix value
65
+ # Quattrocento unique parameters
66
+ self._streaming_frequency: int | None = None
67
+
68
+ # Connection Parameters
69
+ self._interface: QTcpSocket = QTcpSocket()
70
+
71
+ # Configuration Parameters
72
+ self._grids: list[int] | None = None
73
+ self._grid_size: int = 64 # TODO: This is only valid for the big electrodes
74
+ self._streaming_frequency_mode: QuattrocentoLightStreamingFrequency | None = (
75
+ None
76
+ )
77
+ self._sampling_frequency_mode: QuattrocentoLightSamplingFrequency | None = None
78
+
79
+ def _connect_to_device(self) -> bool:
80
+ super()._connect_to_device()
81
+
82
+ self._received_bytes: bytearray = bytearray()
83
+ return self._make_request()
84
+
85
+ def _make_request(self) -> bool:
86
+ super()._make_request()
87
+ # Signal self.connect_toggled is emitted in _read_data
88
+ self._interface.connectToHost(
89
+ QHostAddress(self._connection_settings[0]),
90
+ self._connection_settings[1],
91
+ QIODevice.ReadWrite,
92
+ )
93
+
94
+ if not self._interface.waitForConnected(1000):
95
+ self._disconnect_from_device()
96
+ return False
97
+
98
+ self._interface.readyRead.connect(self._read_data)
99
+
100
+ return True
101
+
102
+ def _disconnect_from_device(self) -> None:
103
+ super()._disconnect_from_device()
104
+
105
+ self._interface.disconnectFromHost()
106
+ self._interface.readyRead.disconnect(self._read_data)
107
+ self._interface.close()
108
+
109
+ def configure_device(
110
+ self, params: Dict[str, Union[Enum, Dict[str, Enum]]] # type: ignore
111
+ ) -> None:
112
+ super().configure_device(params)
113
+
114
+ # Configure the device
115
+ self._number_of_biosignal_channels = len(self._grids) * self._grid_size
116
+ self._biosignal_channel_indices = np.array(
117
+ [
118
+ i * self._grid_size + j
119
+ for i in self._grids
120
+ for j in range(self._grid_size)
121
+ ]
122
+ )
123
+
124
+ self._auxiliary_channel_indices = np.array(
125
+ [
126
+ i + self._auxiliary_channel_start_index
127
+ for i in range(self._number_of_auxiliary_channels)
128
+ ]
129
+ )
130
+
131
+ self._streaming_frequency = QUATTROCENTO_LIGHT_STREAMING_FREQUENCY_DICT[
132
+ self._streaming_frequency_mode
133
+ ]
134
+ self._sampling_frequency = QUATTROCENTO_SAMPLING_FREQUENCY_DICT[
135
+ self._sampling_frequency_mode
136
+ ]
137
+
138
+ self._samples_per_frame = self._sampling_frequency // self._streaming_frequency
139
+
140
+ self._buffer_size = (
141
+ self._bytes_per_sample * self._number_of_channels * self._samples_per_frame
142
+ )
143
+
144
+ self._is_configured = True
145
+ self.configure_toggled.emit(True)
146
+
147
+ def _start_streaming(self) -> None:
148
+ super()._start_streaming()
149
+
150
+ self._interface.write(COMMAND_START_STREAMING)
151
+
152
+ def _stop_streaming(self) -> None:
153
+ super()._stop_streaming()
154
+
155
+ self._interface.write(COMMAND_STOP_STREAMING)
156
+ self._interface.waitForBytesWritten(1000)
157
+
158
+ def clear_socket(self) -> None:
159
+ super().clear_socket()
160
+
161
+ self._interface.readAll()
162
+
163
+ def _read_data(self) -> None:
164
+ super()._read_data()
165
+
166
+ # Wait for connection response
167
+ if not self.is_connected and (
168
+ self._interface.bytesAvailable() == len(CONNECTION_RESPONSE)
169
+ and self._interface.readAll() == CONNECTION_RESPONSE
170
+ ):
171
+ self.is_connected = True
172
+ self.connect_toggled.emit(True)
173
+ return
174
+ if not self._is_streaming:
175
+ self.clear_socket()
176
+ return
177
+
178
+ while self._interface.bytesAvailable() > self._buffer_size:
179
+ packet = self._interface.read(self._buffer_size)
180
+ if not packet:
181
+ continue
182
+
183
+ self._received_bytes.extend(packet)
184
+
185
+ while len(self._received_bytes) >= self._buffer_size:
186
+ data_to_process = self._received_bytes[: self._buffer_size]
187
+ self._process_data(data_to_process)
188
+ self._received_bytes = self._received_bytes[self._buffer_size :]
189
+
190
+ def _process_data(self, input: bytearray) -> None:
191
+ super()._process_data(input)
192
+
193
+ # Decode the data
194
+ decoded_data = np.frombuffer(input, dtype=np.int16)
195
+
196
+ # Reshape it to the correct format
197
+ processed_data = decoded_data.reshape(
198
+ self._number_of_channels, -1, order="F"
199
+ ).astype(np.float32)
200
+
201
+ # Emit the data
202
+ self.data_available.emit(processed_data)
203
+
204
+ biosignal_data = self._extract_biosignal_data(processed_data)
205
+ self.biosignal_data_available.emit(biosignal_data)
206
+ auxiliary_data = self._extract_auxiliary_data(processed_data)
207
+ self.auxiliary_data_available.emit(auxiliary_data)
208
+
209
+ def get_device_information(self) -> Dict[str, Enum | int | float | str]: # type: ignore
210
+ return super().get_device_information()