Skip to content

Commit ecde7fa

Browse files
authored
Merge pull request #9 from NsquaredLab/sessantaquattro-implementation
Add Sessantaquattro Device Support
2 parents 6c9cd8c + fe0bb56 commit ecde7fa

14 files changed

Lines changed: 1444 additions & 2770 deletions

biosignal_device_interface/constants/devices/core/base_device_constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class DeviceType(Enum):
2121
OTB_MUOVI = auto(), "OT Bioelettronica Muovi"
2222
OTB_MUOVI_PLUS = auto(), "OT Bioelettronica Muovi Plus"
2323
OTB_SYNCSTATION = auto(), "OT Bioelettronica SyncStation"
24+
OTB_SESSANTAQUATTRO = auto(), "OT Bioelettronica Sessantaquattro"
2425

2526

2627
class OTBDeviceType(Enum):
@@ -36,6 +37,7 @@ class OTBDeviceType(Enum):
3637
MUOVI = auto(), "Muovi"
3738
MUOVI_PLUS = auto(), "Muovi Plus"
3839
SYNCSTATION = auto(), "SyncStation"
40+
SESSANTAQUATTRO = auto(), "Sessantaquattro"
3941

4042

4143
class DeviceChannelTypes(Enum):
@@ -58,4 +60,6 @@ class DeviceChannelTypes(Enum):
5860
OTBDeviceType.MUOVI_PLUS: "Muovi Plus",
5961
DeviceType.OTB_SYNCSTATION: "SyncStation",
6062
OTBDeviceType.SYNCSTATION: "SyncStation",
63+
DeviceType.OTB_SESSANTAQUATTRO: "Sessantaquattro",
64+
OTBDeviceType.SESSANTAQUATTRO: "Sessantaquattro",
6165
}
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
"""
2+
Constants for the Sessantaquattro device.
3+
4+
Developer: Dominik I. Braun
5+
Contact: dome.braun@fau.de
6+
Last Update: 2025-09-16
7+
"""
8+
9+
from typing import Dict
10+
from aenum import Enum, auto
11+
12+
from biosignal_device_interface.constants.devices.core.base_device_constants import (
13+
DeviceChannelTypes,
14+
)
15+
16+
17+
class SessantaquattroSamplingFrequencyMode(Enum):
18+
"""Enum class for the sampling frequency of the Sessantaquattro device."""
19+
20+
_init_ = "value __doc__"
21+
22+
NONE = 0, "No sampling frequency set."
23+
LOW = auto(), "500 Hz (2000 Hz - Accelerometer)"
24+
MEDIUM = auto(), "1000 Hz (4000 Hz - Accelerometer)"
25+
HIGH = auto(), "2000 Hz (8000 Hz - Accelerometer)"
26+
ULTRA = auto(), "4000 Hz (16000 Hz - Accelerometer)"
27+
28+
29+
class SessantaquattroDetectionMode(Enum):
30+
"""
31+
Enum class for the working mode of the Sessantaquattro device.
32+
"""
33+
34+
_init_ = "value __doc__"
35+
36+
NONE = 0, "No working mode set."
37+
MONOPOLAR = auto(), ("Monopolar Mode")
38+
BIPOLAR = auto(), ("Bipolar Mode")
39+
DIFFERENTIAL = auto(), ("Differential Mode")
40+
ACCELEROMETER = auto(), ("Accelerometer Mode")
41+
UNDEFINED = auto(), ("Undefined Mode")
42+
IMPEDANCE_ADVANCED = auto(), ("Impedance Check Advanced")
43+
IMPEDANCE = auto(), ("Impedance Check")
44+
TEST = auto(), ("Test Mode")
45+
46+
47+
class SessantaquattroChannelMode(Enum):
48+
"""
49+
Enum class for the channel mode of the Sessantaquattro device.
50+
"""
51+
52+
_init_ = "value __doc__"
53+
54+
NONE = 0, "No channel mode set."
55+
LOW = auto(), (
56+
"8 bioelec. + 2 AUX + 2 accessory (if MODE=001: 4 bio + 2 AUX + 2 acc)"
57+
)
58+
MEDIUM = auto(), (
59+
"16 bioelec. + 2 AUX + 2 accessory (if MODE=001: 8 bio + 2 AUX + 2 acc)"
60+
)
61+
HIGH = auto(), (
62+
"32 bioelec. + 2 AUX + 2 accessory (if MODE=001: 16 bio + 2 AUX + 2 acc)"
63+
)
64+
ULTRA = auto(), (
65+
"64 bioelec. + 2 AUX + 2 accessory (if MODE=001: 32 bio + 2 AUX + 2 acc)"
66+
)
67+
68+
69+
class SessantaquattroResolutionMode(Enum):
70+
"""
71+
Enum class for the resolution mode of the Sessantaquattro device.
72+
"""
73+
74+
_init_ = "value __doc__"
75+
76+
NONE = 0, "No resolution mode set."
77+
LOW = auto(), ("16 Bits Resolution")
78+
HIGH = auto(), ("24 Bits Resolution")
79+
80+
81+
class SessantaquattroGainMode(Enum):
82+
"""
83+
Enum class for the gain mode of the Sessantaquattro device.
84+
"""
85+
86+
_init_ = "value __doc__"
87+
88+
NONE = 0, "No gain mode set."
89+
DEFAULT = auto(), (
90+
"Gain x2 (for 24 bits resolution) / Gain x8 (for 16 bits resolution)"
91+
)
92+
LOW = auto(), ("Gain x4")
93+
MEDIUM = auto(), ("Gain x6")
94+
HIGH = auto(), ("Gain x8")
95+
96+
97+
class SessantaquattroTriggerMode(Enum):
98+
"""
99+
Enum class for the trigger mode of the Sessantaquattro device.
100+
"""
101+
102+
_init_ = "value __doc__"
103+
104+
NONE = 0, "No trigger mode set."
105+
DEFAULT = auto(), (
106+
"The data transfer is controlled from GO/STOP bit, REC has no effect."
107+
)
108+
INTERNAL = auto(), (
109+
"The data transfer ist triggered by the internal signal (phototransistor)"
110+
)
111+
EXTERNAL = auto(), (
112+
"The data transfer is triggered by the external signal (from the adapter)"
113+
)
114+
SDCARD = auto(), (
115+
"SDCARD: SD card acquisition starts/stops with the hardware button or with the REC bit."
116+
)
117+
118+
119+
class SessantaquattroRecordingMode(Enum):
120+
"""
121+
Enum class for the recording mode of the Sessantaquattro device.
122+
"""
123+
124+
_init_ = "value __doc__"
125+
126+
NONE = 0, "No recording mode set."
127+
STOP = auto(), ("Stop the recording. Works only if TRIG = 3 (SDCARD).")
128+
START = auto(), ("Start the recording. Works only if TRIG = 3 (SDCARD).")
129+
130+
131+
def _get_sampling_frequency(
132+
detection_mode: SessantaquattroDetectionMode,
133+
sampling_freq_mode: SessantaquattroSamplingFrequencyMode,
134+
) -> int:
135+
"""Get sampling frequency for given detection and sampling frequency modes."""
136+
if detection_mode == SessantaquattroDetectionMode.ACCELEROMETER:
137+
base_freq = 2000
138+
else:
139+
base_freq = 500
140+
141+
multiplier = 2 ** (sampling_freq_mode.value - 1)
142+
return base_freq * multiplier
143+
144+
145+
def _get_biosignal_channel_count(
146+
sampling_freq_mode: SessantaquattroSamplingFrequencyMode,
147+
detection_mode: SessantaquattroDetectionMode,
148+
) -> int:
149+
"""Get biosignal channel count for given modes."""
150+
base_channels = 8 * (2 ** (sampling_freq_mode.value - 1))
151+
152+
# Bipolar mode has half the channels
153+
if detection_mode == SessantaquattroDetectionMode.BIPOLAR:
154+
return base_channels // 2
155+
156+
return base_channels
157+
158+
159+
# Generate dictionaries using functions
160+
SESSANTAQUATTRO_DETECTION_MODE_CHARACTERISTICS_DICT: Dict[
161+
SessantaquattroDetectionMode, Dict[SessantaquattroSamplingFrequencyMode, int]
162+
] = {
163+
detection_mode: {
164+
sampling_freq: _get_sampling_frequency(detection_mode, sampling_freq)
165+
for sampling_freq in SessantaquattroSamplingFrequencyMode
166+
if sampling_freq != SessantaquattroSamplingFrequencyMode.NONE
167+
}
168+
for detection_mode in SessantaquattroDetectionMode
169+
if detection_mode != SessantaquattroDetectionMode.NONE
170+
}
171+
172+
SESSANTAQUATTRO_CHANNEL_MODE_CHARACTERISTICS_DICT: Dict[
173+
SessantaquattroSamplingFrequencyMode,
174+
Dict[SessantaquattroDetectionMode, Dict[DeviceChannelTypes, int]],
175+
] = {
176+
sampling_freq: {
177+
detection_mode: {
178+
DeviceChannelTypes.BIOSIGNAL: _get_biosignal_channel_count(
179+
sampling_freq, detection_mode
180+
),
181+
DeviceChannelTypes.AUXILIARY: 4,
182+
}
183+
for detection_mode in SessantaquattroDetectionMode
184+
if detection_mode != SessantaquattroDetectionMode.NONE
185+
}
186+
for sampling_freq in SessantaquattroSamplingFrequencyMode
187+
if sampling_freq != SessantaquattroSamplingFrequencyMode.NONE
188+
}
189+
190+
SESSANTAQUATTRO_GAIN_MODE_CHARACTERISTICS_DICT: Dict[
191+
SessantaquattroResolutionMode, Dict[SessantaquattroGainMode, float]
192+
] = {
193+
SessantaquattroResolutionMode.LOW: {
194+
SessantaquattroGainMode.DEFAULT: 286.1e-6, # Gain8, 16-bit (in mV, originally 286.1 nV)
195+
SessantaquattroGainMode.LOW: 572.2e-6, # Gain4, 16-bit (in mV, originally 572.2 nV)
196+
SessantaquattroGainMode.MEDIUM: 381.5e-6, # Gain6, 16-bit (in mV, originally 381.5 nV)
197+
SessantaquattroGainMode.HIGH: 286.1e-6, # Gain8, 16-bit (in mV, originally 286.1 nV)
198+
},
199+
SessantaquattroResolutionMode.HIGH: {
200+
SessantaquattroGainMode.DEFAULT: 71.5e-6, # Gain8, 24-bit (in mV, originally 71.5 nV)
201+
SessantaquattroGainMode.LOW: 143.0e-6, # Gain4, 24-bit (in mV, originally 143.0 nV)
202+
SessantaquattroGainMode.MEDIUM: 95.4e-6, # Gain6, 24-bit (in mV, originally 95.4 nV)
203+
SessantaquattroGainMode.HIGH: 71.5e-6, # Gain8, 24-bit (in mV, originally 71.5 nV)
204+
},
205+
}
206+
207+
SESSANTAQUATTRO_AUXILIARY_LSB_DICT: Dict[SessantaquattroResolutionMode, float] = {
208+
SessantaquattroResolutionMode.LOW: 146.48e-6, # in mV (originally 146.48 nV)
209+
SessantaquattroResolutionMode.HIGH: 572.2e-6, # in mV (originally 572.2 nV)
210+
}
211+
212+
SESSANTAQUATTRO_SAMPLES_PER_FRAME_DICT: Dict[SessantaquattroChannelMode, int] = {
213+
SessantaquattroChannelMode.LOW: 48,
214+
SessantaquattroChannelMode.MEDIUM: 28,
215+
SessantaquattroChannelMode.HIGH: 16,
216+
SessantaquattroChannelMode.ULTRA: 8,
217+
}
218+
219+
if __name__ == "__main__":
220+
# Print the generated dictionaries for verification
221+
import pprint
222+
223+
print("Sessantaquattro Detection Mode Characteristics Dictionary:")
224+
pprint.pprint(SESSANTAQUATTRO_DETECTION_MODE_CHARACTERISTICS_DICT)
225+
226+
print("\nSessantaquattro Channel Mode Characteristics Dictionary:")
227+
pprint.pprint(SESSANTAQUATTRO_CHANNEL_MODE_CHARACTERISTICS_DICT)

biosignal_device_interface/devices/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
OTBMuoviWidget,
66
OTBMuoviPlusWidget,
77
OTBQuattrocentoLightWidget,
8+
OTBSessantaquattroWidget,
89
OTBMuovi,
910
OTBQuattrocento,
1011
OTBQuattrocentoLight,
12+
OTBSessantaquattro,
1113
OTBSyncStationWidget,
1214
OTBDevicesWidget,
1315
)

biosignal_device_interface/devices/otb/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
)
55
from biosignal_device_interface.devices.otb.otb_muovi import OTBMuovi
66
from biosignal_device_interface.devices.otb.otb_syncstation import OTBSyncStation
7+
from biosignal_device_interface.devices.otb.otb_sessantaquattro import (
8+
OTBSessantaquattro,
9+
)
710

811
# Widgets
912
# All OTB Devices Widget
@@ -27,3 +30,6 @@
2730
from biosignal_device_interface.gui.device_template_widgets.otb.otb_syncstation_widget import (
2831
OTBSyncStationWidget,
2932
)
33+
from biosignal_device_interface.gui.device_template_widgets.otb.otb_sessantaquattro_widget import (
34+
OTBSessantaquattroWidget,
35+
)

biosignal_device_interface/devices/otb/otb_muovi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ def _stop_streaming(self) -> None:
212212
def clear_socket(self) -> None:
213213
if self._client_socket is not None:
214214
self._client_socket.readAll()
215+
self._received_bytes = bytearray()
215216

216217
def _read_data(self) -> None:
217218
super()._read_data()

0 commit comments

Comments
 (0)