pyglaze 0.4.1__py3-none-any.whl → 0.4.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.
- pyglaze/__init__.py +1 -1
- pyglaze/datamodels/pulse.py +1 -1
- pyglaze/device/ampcom.py +17 -12
- pyglaze/device/configuration.py +22 -2
- pyglaze/devtools/mock_device.py +2 -0
- {pyglaze-0.4.1.dist-info → pyglaze-0.4.5.dist-info}/METADATA +1 -1
- {pyglaze-0.4.1.dist-info → pyglaze-0.4.5.dist-info}/RECORD +10 -10
- {pyglaze-0.4.1.dist-info → pyglaze-0.4.5.dist-info}/WHEEL +0 -0
- {pyglaze-0.4.1.dist-info → pyglaze-0.4.5.dist-info}/licenses/LICENSE +0 -0
- {pyglaze-0.4.1.dist-info → pyglaze-0.4.5.dist-info}/top_level.txt +0 -0
pyglaze/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.4.
|
|
1
|
+
__version__ = "0.4.5"
|
pyglaze/datamodels/pulse.py
CHANGED
|
@@ -174,7 +174,7 @@ class Pulse:
|
|
|
174
174
|
"""
|
|
175
175
|
extrema = [scan._get_min_or_max_idx(wrt_max=wrt_max) for scan in scans] # noqa: SLF001
|
|
176
176
|
n_before = min(extrema)
|
|
177
|
-
n_after = min(len(scan) - index
|
|
177
|
+
n_after = min(len(scan) - index for scan, index in zip(scans, extrema))
|
|
178
178
|
roughly_aligned = [
|
|
179
179
|
cls._from_slice(scan, slice(index - n_before, index + n_after))
|
|
180
180
|
for index, scan in zip(extrema, scans)
|
pyglaze/device/ampcom.py
CHANGED
|
@@ -15,6 +15,8 @@ from bitstring import BitArray
|
|
|
15
15
|
from serial import serialutil
|
|
16
16
|
|
|
17
17
|
from pyglaze.device.configuration import (
|
|
18
|
+
BYTES_PER_CHANNEL,
|
|
19
|
+
N_CHANNELS,
|
|
18
20
|
DeviceConfiguration,
|
|
19
21
|
Interval,
|
|
20
22
|
LeDeviceConfiguration,
|
|
@@ -78,7 +80,7 @@ class _LeAmpCom:
|
|
|
78
80
|
|
|
79
81
|
We expect to receive 3 arrays of floats (delays, X and Y), each with self.scanning_points elements.
|
|
80
82
|
"""
|
|
81
|
-
return self.scanning_points *
|
|
83
|
+
return self.scanning_points * N_CHANNELS * BYTES_PER_CHANNEL
|
|
82
84
|
|
|
83
85
|
@property
|
|
84
86
|
def serial_number_bytes(self: _LeAmpCom) -> int:
|
|
@@ -150,9 +152,11 @@ class _LeAmpCom:
|
|
|
150
152
|
angle = np.arctan2(np.array(Ys), np.array(Xs))
|
|
151
153
|
return r, np.rad2deg(angle)
|
|
152
154
|
|
|
153
|
-
def _encode_send_response(
|
|
155
|
+
def _encode_send_response(
|
|
156
|
+
self: _LeAmpCom, command: str, *, check_ack: bool = True
|
|
157
|
+
) -> str:
|
|
154
158
|
self._encode_and_send(command)
|
|
155
|
-
return self._get_response(command)
|
|
159
|
+
return self._get_response(command, check_ack=check_ack)
|
|
156
160
|
|
|
157
161
|
def _encode_and_send(self: _LeAmpCom, command: str) -> None:
|
|
158
162
|
self.__ser.write(command.encode(self.ENCODING))
|
|
@@ -180,13 +184,13 @@ class _LeAmpCom:
|
|
|
180
184
|
@_BackoffRetry(
|
|
181
185
|
backoff_base=1e-2, max_tries=3, logger=logging.getLogger(LOGGER_NAME)
|
|
182
186
|
)
|
|
183
|
-
def _get_response(self: _LeAmpCom, command: str) -> str:
|
|
187
|
+
def _get_response(self: _LeAmpCom, command: str, *, check_ack: bool = True) -> str:
|
|
184
188
|
response = self.__ser.read_until().decode(self.ENCODING).strip()
|
|
185
189
|
|
|
186
190
|
if len(response) == 0:
|
|
187
191
|
msg = f"Command: '{command}'. Empty response received"
|
|
188
192
|
raise serialutil.SerialException(msg)
|
|
189
|
-
if response[: len(self.OK_RESPONSE)] != self.OK_RESPONSE:
|
|
193
|
+
if check_ack and response[: len(self.OK_RESPONSE)] != self.OK_RESPONSE:
|
|
190
194
|
msg = f"Command: '{command}'. Expected response '{self.OK_RESPONSE}', received: '{response}'"
|
|
191
195
|
raise DeviceComError(msg)
|
|
192
196
|
return response
|
|
@@ -220,13 +224,14 @@ class _LeAmpCom:
|
|
|
220
224
|
]
|
|
221
225
|
|
|
222
226
|
def _get_status(self: _LeAmpCom) -> _LeStatus:
|
|
223
|
-
|
|
224
|
-
|
|
227
|
+
response = self._encode_send_response(self.STATUS_COMMAND, check_ack=False)
|
|
228
|
+
|
|
229
|
+
if response == _LeStatus.SCANNING.value:
|
|
225
230
|
return _LeStatus.SCANNING
|
|
226
|
-
if
|
|
231
|
+
if response == _LeStatus.IDLE.value:
|
|
227
232
|
return _LeStatus.IDLE
|
|
228
|
-
msg = f"Unknown status: {
|
|
229
|
-
raise
|
|
233
|
+
msg = f"Unknown status: {response}"
|
|
234
|
+
raise DeviceComError(msg)
|
|
230
235
|
|
|
231
236
|
|
|
232
237
|
class _LeStatus(Enum):
|
|
@@ -238,8 +243,8 @@ def _serial_factory(config: DeviceConfiguration) -> serial.Serial | LeMockDevice
|
|
|
238
243
|
if "mock_device" in config.amp_port:
|
|
239
244
|
return _mock_device_factory(config)
|
|
240
245
|
|
|
241
|
-
return serial.
|
|
242
|
-
|
|
246
|
+
return serial.serial_for_url(
|
|
247
|
+
url=config.amp_port,
|
|
243
248
|
baudrate=config.amp_baudrate,
|
|
244
249
|
timeout=config.amp_timeout_seconds,
|
|
245
250
|
)
|
pyglaze/device/configuration.py
CHANGED
|
@@ -11,6 +11,14 @@ if TYPE_CHECKING:
|
|
|
11
11
|
T = TypeVar("T", bound="DeviceConfiguration")
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
# Serial protocol constants for timeout calculation
|
|
15
|
+
SERIAL_BITS_PER_BYTE = 10 # 8 data bits + start + stop bits
|
|
16
|
+
N_CHANNELS = 3 # delays, X, Y arrays transmitted
|
|
17
|
+
BYTES_PER_CHANNEL = 4 # 32-bit float = 4 bytes
|
|
18
|
+
TIMEOUT_SAFETY_FACTOR = 2.5 # Safety multiplier for network/processing delays
|
|
19
|
+
TIMEOUT_BASELINE_S = 0.05 # Fixed additive latency
|
|
20
|
+
|
|
21
|
+
|
|
14
22
|
@dataclass
|
|
15
23
|
class Interval:
|
|
16
24
|
"""An interval with a lower and upper bounds between 0 and 1 to scan."""
|
|
@@ -50,9 +58,10 @@ class Interval:
|
|
|
50
58
|
class DeviceConfiguration(ABC):
|
|
51
59
|
"""Base class for device configurations."""
|
|
52
60
|
|
|
53
|
-
amp_timeout_seconds: float
|
|
61
|
+
amp_timeout_seconds: float | None
|
|
54
62
|
amp_port: str
|
|
55
63
|
amp_baudrate: ClassVar[int]
|
|
64
|
+
n_points: int
|
|
56
65
|
|
|
57
66
|
@property
|
|
58
67
|
@abstractmethod
|
|
@@ -92,11 +101,22 @@ class LeDeviceConfiguration(DeviceConfiguration):
|
|
|
92
101
|
n_points: int = 1000
|
|
93
102
|
scan_intervals: list[Interval] = field(default_factory=lambda: [Interval(0.0, 1.0)])
|
|
94
103
|
integration_periods: int = 10
|
|
95
|
-
amp_timeout_seconds: float =
|
|
104
|
+
amp_timeout_seconds: float | None = None
|
|
96
105
|
modulation_frequency: int = 10000 # Hz
|
|
97
106
|
|
|
98
107
|
amp_baudrate: ClassVar[int] = 1000000 # bit/s
|
|
99
108
|
|
|
109
|
+
def __post_init__(self: LeDeviceConfiguration) -> None:
|
|
110
|
+
"""Calculate dynamic timeout if not explicitly set."""
|
|
111
|
+
if self.amp_timeout_seconds is None:
|
|
112
|
+
# Calculate timeout based on data transfer requirements
|
|
113
|
+
bytes_to_receive = self.n_points * N_CHANNELS * BYTES_PER_CHANNEL
|
|
114
|
+
bits_to_transfer = bytes_to_receive * SERIAL_BITS_PER_BYTE
|
|
115
|
+
transfer_time = bits_to_transfer / self.amp_baudrate
|
|
116
|
+
self.amp_timeout_seconds = (
|
|
117
|
+
transfer_time + TIMEOUT_BASELINE_S
|
|
118
|
+
) * TIMEOUT_SAFETY_FACTOR
|
|
119
|
+
|
|
100
120
|
@property
|
|
101
121
|
def _sweep_length_ms(self: LeDeviceConfiguration) -> float:
|
|
102
122
|
return self.n_points * self._time_constant_ms
|
pyglaze/devtools/mock_device.py
CHANGED
|
@@ -154,6 +154,8 @@ class LeMockDevice(MockDevice):
|
|
|
154
154
|
self._scan_start_time = time.time()
|
|
155
155
|
elif msg == "R":
|
|
156
156
|
self._scan_has_finished()
|
|
157
|
+
elif msg == "H":
|
|
158
|
+
self.state = _LeMockState.RECEIVED_STATUS_REQUEST
|
|
157
159
|
elif msg == "s":
|
|
158
160
|
self.state = _LeMockState.RECEIVED_SERIAL_NUMBER_REQUEST
|
|
159
161
|
elif msg == "v":
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
pyglaze/__init__.py,sha256=
|
|
1
|
+
pyglaze/__init__.py,sha256=ErkLkI2TDBX1OIqi2GGa20CPeu4ZculEi-XffRbLU6M,22
|
|
2
2
|
pyglaze/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
pyglaze/datamodels/__init__.py,sha256=DJLByl2C7pC4RM4Uh6PW-McM5RIGBjcopzGywCKhSlI,111
|
|
4
|
-
pyglaze/datamodels/pulse.py,sha256=
|
|
4
|
+
pyglaze/datamodels/pulse.py,sha256=ZGYJTZCVEx-KkjJdHHexbdAlzXfOMIA1KtsaADQ-qCg,23188
|
|
5
5
|
pyglaze/datamodels/waveform.py,sha256=T0wV7saJNPowwQs518VLypul-p1bg_1REPTflw8UNzM,5810
|
|
6
6
|
pyglaze/device/__init__.py,sha256=rxF1h54dHTwq5JVvLjxDeirY4njMfr8c9qs0yJ5GRhE,119
|
|
7
|
-
pyglaze/device/ampcom.py,sha256=
|
|
8
|
-
pyglaze/device/configuration.py,sha256=
|
|
7
|
+
pyglaze/device/ampcom.py,sha256=0SO4SpFu-bjHN_8hObp-jHUTb3a-r_Op74-_AssZGyc,10933
|
|
8
|
+
pyglaze/device/configuration.py,sha256=CKi7wgE1OKPNOf0OXdb-Gq7kaY5rFDZJo7jEA4xC-CY,5857
|
|
9
9
|
pyglaze/devtools/__init__.py,sha256=9EW20idoaZv_5GuSgDmfpTPjfCZ-Rl27EV3oJebmwnQ,90
|
|
10
|
-
pyglaze/devtools/mock_device.py,sha256=
|
|
10
|
+
pyglaze/devtools/mock_device.py,sha256=H4aItDp9NPbgXr0OiHJm8LUX94cLvdltoLWGH38vATQ,9967
|
|
11
11
|
pyglaze/devtools/thz_pulse.py,sha256=WUAz3QTdw_ak0yVyU1zzABrqyCzWhUFRUHP5K_i3ppU,963
|
|
12
12
|
pyglaze/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
pyglaze/helpers/_types.py,sha256=p9xSAP5Trr1FcCWl7ynCWqDOUZKgMQYzMUXSwDpAKHg,599
|
|
@@ -19,8 +19,8 @@ pyglaze/scanning/_asyncscanner.py,sha256=cS-XOGWaFsYJ5ShkchyHQo8HtPCADGEGnf-isHx
|
|
|
19
19
|
pyglaze/scanning/_exceptions.py,sha256=vS28Dijj76jVuF6cSDBKqM9SQIa9rbIyUaHF-RA3PyM,213
|
|
20
20
|
pyglaze/scanning/client.py,sha256=xgsZLRFVe_rcLQD7AIcztKZ_wY6mp3v4ID3Zq40SbP0,2459
|
|
21
21
|
pyglaze/scanning/scanner.py,sha256=69Bawx3m6toHH3bhHSRduVN527-aeveFI9l6WcaKWs8,7712
|
|
22
|
-
pyglaze-0.4.
|
|
23
|
-
pyglaze-0.4.
|
|
24
|
-
pyglaze-0.4.
|
|
25
|
-
pyglaze-0.4.
|
|
26
|
-
pyglaze-0.4.
|
|
22
|
+
pyglaze-0.4.5.dist-info/licenses/LICENSE,sha256=LCP3sGBX7LxuQopcjeug1fW4tngWCHF4zB7QCgB28xM,1504
|
|
23
|
+
pyglaze-0.4.5.dist-info/METADATA,sha256=3mg1CyUifbIFnE5aS_6u31sFDjEcIFq2Ys9GoTHPA9E,3508
|
|
24
|
+
pyglaze-0.4.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
25
|
+
pyglaze-0.4.5.dist-info/top_level.txt,sha256=X7d5rqVVuWNmtK4-Uh4sgOLlqye8vaHZOr5RYba0REo,8
|
|
26
|
+
pyglaze-0.4.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|