pyglaze 0.1.0__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 -0
- pyglaze/datamodels/__init__.py +4 -0
- pyglaze/datamodels/pulse.py +551 -0
- pyglaze/datamodels/waveform.py +165 -0
- pyglaze/device/__init__.py +15 -0
- pyglaze/device/_delayunit_data/carmen-nonuniform-2023-10-20.pickle +0 -0
- pyglaze/device/_delayunit_data/g1-linearized-2023-04-04.pickle +0 -0
- pyglaze/device/_delayunit_data/g2-linearized-2023-04-04.pickle +0 -0
- pyglaze/device/_delayunit_data/g2-nonuniform-2023-04-04.pickle +0 -0
- pyglaze/device/_delayunit_data/mock_delay.pickle +0 -0
- pyglaze/device/ampcom.py +447 -0
- pyglaze/device/configuration.py +266 -0
- pyglaze/device/delayunit.py +151 -0
- pyglaze/device/identifiers.py +41 -0
- pyglaze/devtools/__init__.py +3 -0
- pyglaze/devtools/mock_device.py +367 -0
- pyglaze/devtools/thz_pulse.py +35 -0
- pyglaze/helpers/__init__.py +0 -0
- pyglaze/helpers/types.py +20 -0
- pyglaze/helpers/utilities.py +80 -0
- pyglaze/interpolation/__init__.py +3 -0
- pyglaze/interpolation/interpolation.py +24 -0
- pyglaze/py.typed +0 -0
- pyglaze/scanning/__init__.py +4 -0
- pyglaze/scanning/_asyncscanner.py +146 -0
- pyglaze/scanning/client.py +59 -0
- pyglaze/scanning/scanner.py +256 -0
- pyglaze-0.1.0.dist-info/LICENSE +28 -0
- pyglaze-0.1.0.dist-info/METADATA +82 -0
- pyglaze-0.1.0.dist-info/RECORD +32 -0
- pyglaze-0.1.0.dist-info/WHEEL +5 -0
- pyglaze-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from serial import serialutil
|
|
7
|
+
from typing_extensions import Self
|
|
8
|
+
|
|
9
|
+
from ._asyncscanner import _AsyncScanner
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pyglaze.datamodels import UnprocessedWaveform
|
|
13
|
+
from pyglaze.device.configuration import DeviceConfiguration
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ScannerStartupError(Exception):
|
|
17
|
+
"""Raised when the scanner could not be started."""
|
|
18
|
+
|
|
19
|
+
def __init__(self: ScannerStartupError) -> None:
|
|
20
|
+
super().__init__(
|
|
21
|
+
"Scanner could not be started. Please check the internal server error messages."
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class GlazeClient:
|
|
27
|
+
"""Open a connection to and start continuously scanning using the Glaze device.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
config: Configuration to use for scans
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
config: DeviceConfiguration
|
|
34
|
+
_scanner: _AsyncScanner = field(init=False)
|
|
35
|
+
|
|
36
|
+
def __enter__(self: Self) -> Self:
|
|
37
|
+
"""Start the scanner and return the client."""
|
|
38
|
+
self._scanner = _AsyncScanner()
|
|
39
|
+
try:
|
|
40
|
+
self._scanner.start_scan(self.config)
|
|
41
|
+
except (TimeoutError, serialutil.SerialException) as e:
|
|
42
|
+
self.__exit__(e)
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
def __exit__(self: GlazeClient, *args: object) -> None:
|
|
46
|
+
"""Stop the scanner and close the connection."""
|
|
47
|
+
if self._scanner.is_scanning:
|
|
48
|
+
self._scanner.stop_scan()
|
|
49
|
+
# Exit is only called with arguments when an error occurs - hence raise.
|
|
50
|
+
if args[0]:
|
|
51
|
+
raise
|
|
52
|
+
|
|
53
|
+
def read(self: GlazeClient, n_pulses: int) -> list[UnprocessedWaveform]:
|
|
54
|
+
"""Read a number of pulses from the Glaze system.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
n_pulses: The number of terahertz pulses to read from the CCS server.
|
|
58
|
+
"""
|
|
59
|
+
return self._scanner.get_scans(n_pulses)
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING, Generic, TypeVar
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from pyglaze.datamodels import UnprocessedWaveform
|
|
9
|
+
from pyglaze.device.ampcom import _ForceAmpCom, _LeAmpCom
|
|
10
|
+
from pyglaze.device.configuration import (
|
|
11
|
+
DeviceConfiguration,
|
|
12
|
+
ForceDeviceConfiguration,
|
|
13
|
+
LeDeviceConfiguration,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from pyglaze.helpers.types import FloatArray
|
|
18
|
+
|
|
19
|
+
TConfig = TypeVar("TConfig", bound=DeviceConfiguration)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _ScannerImplementation(ABC, Generic[TConfig]):
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def __init__(self: _ScannerImplementation, config: TConfig) -> None:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def config(self: _ScannerImplementation) -> TConfig:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
@config.setter
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def config(self: _ScannerImplementation, new_config: TConfig) -> None:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def scan(self: _ScannerImplementation) -> UnprocessedWaveform:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def update_config(self: _ScannerImplementation, new_config: TConfig) -> None:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Scanner:
|
|
47
|
+
"""A synchronous scanner for Glaze terahertz devices."""
|
|
48
|
+
|
|
49
|
+
def __init__(self: Scanner, config: TConfig) -> None:
|
|
50
|
+
self._scanner_impl: _ScannerImplementation[DeviceConfiguration] = (
|
|
51
|
+
_scanner_factory(config)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def config(self: Scanner) -> DeviceConfiguration:
|
|
56
|
+
"""Configuration used in the scan."""
|
|
57
|
+
return self._scanner_impl.config
|
|
58
|
+
|
|
59
|
+
@config.setter
|
|
60
|
+
def config(self: Scanner, new_config: DeviceConfiguration) -> None:
|
|
61
|
+
self._scanner_impl.config = new_config
|
|
62
|
+
|
|
63
|
+
def scan(self: Scanner) -> UnprocessedWaveform:
|
|
64
|
+
"""Perform a scan.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
UnprocessedWaveform: A raw waveform.
|
|
68
|
+
"""
|
|
69
|
+
return self._scanner_impl.scan()
|
|
70
|
+
|
|
71
|
+
def update_config(self: Scanner, new_config: DeviceConfiguration) -> None:
|
|
72
|
+
"""Update the DeviceConfiguration used in the scan.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
new_config (DeviceConfiguration): New configuration for scanner
|
|
76
|
+
"""
|
|
77
|
+
self._scanner_impl.update_config(new_config)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class ForceScanner(_ScannerImplementation[ForceDeviceConfiguration]):
|
|
81
|
+
"""Perform synchronous terahertz scanning using a given DeviceConfiguration.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
config: A DeviceConfiguration to use for the scan.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(self: ForceScanner, config: ForceDeviceConfiguration) -> None:
|
|
89
|
+
self._config: ForceDeviceConfiguration
|
|
90
|
+
self._ampcom: _ForceAmpCom
|
|
91
|
+
self.config = config
|
|
92
|
+
self._phase_estimator = _LockinPhaseEstimator()
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def config(self: ForceScanner) -> ForceDeviceConfiguration:
|
|
96
|
+
"""The device configuration to use for the scan.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
DeviceConfiguration: a DeviceConfiguration.
|
|
100
|
+
"""
|
|
101
|
+
return self._config
|
|
102
|
+
|
|
103
|
+
@config.setter
|
|
104
|
+
def config(self: ForceScanner, new_config: ForceDeviceConfiguration) -> None:
|
|
105
|
+
amp = _ForceAmpCom(new_config)
|
|
106
|
+
if getattr(self, "_config", None):
|
|
107
|
+
if (
|
|
108
|
+
self._config.integration_periods != new_config.integration_periods
|
|
109
|
+
or self._config.modulation_frequency != new_config.modulation_frequency
|
|
110
|
+
):
|
|
111
|
+
amp.write_period_and_frequency()
|
|
112
|
+
if self._config.sweep_length_ms != new_config.sweep_length_ms:
|
|
113
|
+
amp.write_sweep_length()
|
|
114
|
+
if self._config.modulation_waveform != new_config.modulation_waveform:
|
|
115
|
+
amp.write_waveform()
|
|
116
|
+
if (
|
|
117
|
+
self._config.min_modulation_voltage != new_config.min_modulation_voltage
|
|
118
|
+
or self._config.max_modulation_voltage
|
|
119
|
+
!= new_config.max_modulation_voltage
|
|
120
|
+
):
|
|
121
|
+
amp.write_modulation_voltage()
|
|
122
|
+
if self._config.scan_intervals != new_config.scan_intervals:
|
|
123
|
+
amp.write_list()
|
|
124
|
+
else:
|
|
125
|
+
amp.write_all()
|
|
126
|
+
|
|
127
|
+
self._config = new_config
|
|
128
|
+
self._ampcom = amp
|
|
129
|
+
|
|
130
|
+
def scan(self: ForceScanner) -> UnprocessedWaveform:
|
|
131
|
+
"""Perform a scan.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Unprocessed scan.
|
|
135
|
+
"""
|
|
136
|
+
_, responses = self._ampcom.start_scan()
|
|
137
|
+
|
|
138
|
+
time = responses[:, 0]
|
|
139
|
+
radius = responses[:, 1]
|
|
140
|
+
theta = responses[:, 2]
|
|
141
|
+
self._phase_estimator.update_estimate(radius=radius, theta=theta)
|
|
142
|
+
|
|
143
|
+
return UnprocessedWaveform.from_polar_coords(
|
|
144
|
+
time, radius, theta, self._phase_estimator.phase_estimate
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
def update_config(self: ForceScanner, new_config: ForceDeviceConfiguration) -> None:
|
|
148
|
+
"""Update the DeviceConfiguration used in the scan.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
new_config: A DeviceConfiguration to use for the scan.
|
|
152
|
+
"""
|
|
153
|
+
self.config = new_config
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class LeScanner(_ScannerImplementation[LeDeviceConfiguration]):
|
|
157
|
+
"""Perform synchronous terahertz scanning using a given DeviceConfiguration.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
config: A DeviceConfiguration to use for the scan.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
def __init__(self: LeScanner, config: LeDeviceConfiguration) -> None:
|
|
164
|
+
self._config: LeDeviceConfiguration
|
|
165
|
+
self._ampcom: _LeAmpCom
|
|
166
|
+
self.config = config
|
|
167
|
+
self._phase_estimator = _LockinPhaseEstimator()
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def config(self: LeScanner) -> LeDeviceConfiguration:
|
|
171
|
+
"""The device configuration to use for the scan.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
DeviceConfiguration: a DeviceConfiguration.
|
|
175
|
+
"""
|
|
176
|
+
return self._config
|
|
177
|
+
|
|
178
|
+
@config.setter
|
|
179
|
+
def config(self: LeScanner, new_config: LeDeviceConfiguration) -> None:
|
|
180
|
+
amp = _LeAmpCom(new_config)
|
|
181
|
+
if getattr(self, "_config", None):
|
|
182
|
+
if (
|
|
183
|
+
self._config.integration_periods != new_config.integration_periods
|
|
184
|
+
or self._config.n_points != new_config.n_points
|
|
185
|
+
):
|
|
186
|
+
amp.write_list_length_and_integration_periods_and_use_ema()
|
|
187
|
+
if self._config.scan_intervals != new_config.scan_intervals:
|
|
188
|
+
amp.write_list()
|
|
189
|
+
else:
|
|
190
|
+
amp.write_all()
|
|
191
|
+
|
|
192
|
+
self._config = new_config
|
|
193
|
+
self._ampcom = amp
|
|
194
|
+
|
|
195
|
+
def scan(self: LeScanner) -> UnprocessedWaveform:
|
|
196
|
+
"""Perform a scan.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Unprocessed scan.
|
|
200
|
+
"""
|
|
201
|
+
_, responses = self._ampcom.start_scan()
|
|
202
|
+
|
|
203
|
+
time = responses[:, 0]
|
|
204
|
+
radius = responses[:, 1]
|
|
205
|
+
theta = responses[:, 2]
|
|
206
|
+
self._phase_estimator.update_estimate(radius=radius, theta=theta)
|
|
207
|
+
|
|
208
|
+
return UnprocessedWaveform.from_polar_coords(
|
|
209
|
+
time, radius, theta, self._phase_estimator.phase_estimate
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def update_config(self: LeScanner, new_config: LeDeviceConfiguration) -> None:
|
|
213
|
+
"""Update the DeviceConfiguration used in the scan.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
new_config: A DeviceConfiguration to use for the scan.
|
|
217
|
+
"""
|
|
218
|
+
self.config = new_config
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _scanner_factory(config: DeviceConfiguration) -> _ScannerImplementation:
|
|
222
|
+
if isinstance(config, ForceDeviceConfiguration):
|
|
223
|
+
return ForceScanner(config)
|
|
224
|
+
if isinstance(config, LeDeviceConfiguration):
|
|
225
|
+
return LeScanner(config)
|
|
226
|
+
|
|
227
|
+
msg = f"Unsupported configuration type: {type(config).__name__}"
|
|
228
|
+
raise TypeError(msg)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class _LockinPhaseEstimator:
|
|
232
|
+
def __init__(
|
|
233
|
+
self: _LockinPhaseEstimator, r_threshold_for_update: float = 2.0
|
|
234
|
+
) -> None:
|
|
235
|
+
self.phase_estimate: float | None = None
|
|
236
|
+
self.r_threshold_for_update = r_threshold_for_update
|
|
237
|
+
self._radius_of_est: float | None = None
|
|
238
|
+
|
|
239
|
+
def update_estimate(
|
|
240
|
+
self: _LockinPhaseEstimator, radius: FloatArray, theta: FloatArray
|
|
241
|
+
) -> None:
|
|
242
|
+
r_argmax = np.argmax(radius)
|
|
243
|
+
r_max = radius[r_argmax]
|
|
244
|
+
theta_at_max = theta[r_argmax]
|
|
245
|
+
if self._radius_of_est is None:
|
|
246
|
+
self._set_estimates(theta_at_max, r_max)
|
|
247
|
+
return
|
|
248
|
+
|
|
249
|
+
if r_max > self.r_threshold_for_update * self._radius_of_est:
|
|
250
|
+
self._set_estimates(theta_at_max, r_max)
|
|
251
|
+
|
|
252
|
+
def _set_estimates(
|
|
253
|
+
self: _LockinPhaseEstimator, phase: float, radius: float
|
|
254
|
+
) -> None:
|
|
255
|
+
self.phase_estimate = phase
|
|
256
|
+
self._radius_of_est = radius
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Glaze Technologies
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pyglaze
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pyglaze is a library used to operate the devices of Glaze Technologies
|
|
5
|
+
Author: GLAZE Technologies ApS
|
|
6
|
+
License: BSD 3-Clause License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024, Glaze Technologies
|
|
9
|
+
|
|
10
|
+
Redistribution and use in source and binary forms, with or without
|
|
11
|
+
modification, are permitted provided that the following conditions are met:
|
|
12
|
+
|
|
13
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
14
|
+
list of conditions and the following disclaimer.
|
|
15
|
+
|
|
16
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
17
|
+
this list of conditions and the following disclaimer in the documentation
|
|
18
|
+
and/or other materials provided with the distribution.
|
|
19
|
+
|
|
20
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
21
|
+
contributors may be used to endorse or promote products derived from
|
|
22
|
+
this software without specific prior written permission.
|
|
23
|
+
|
|
24
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
25
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
26
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
27
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
28
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
29
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
30
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
31
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
32
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
33
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34
|
+
Project-URL: Homepage, https://www.glazetech.dk/
|
|
35
|
+
Project-URL: Documentation, https://glazetech.github.io/pyglaze/latest
|
|
36
|
+
Project-URL: Repository, https://github.com/GlazeTech/pyglaze
|
|
37
|
+
Project-URL: Issues, https://github.com/GlazeTech/pyglaze/issues
|
|
38
|
+
Requires-Python: <3.13,>=3.9
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE
|
|
41
|
+
Requires-Dist: numpy <2.0.0,>=1.26.4
|
|
42
|
+
Requires-Dist: pyserial >=3.5
|
|
43
|
+
Requires-Dist: scipy >=1.7.3
|
|
44
|
+
Requires-Dist: bitstring >=4.1.2
|
|
45
|
+
Requires-Dist: typing-extensions >=4.12.2
|
|
46
|
+
|
|
47
|
+
# Pyglaze
|
|
48
|
+
Pyglaze is a python library used to operate the devices of [Glaze Technologies](https://www.glazetech.dk/).
|
|
49
|
+
|
|
50
|
+
Documentation can be found [here](https://glazetech.github.io/pyglaze/latest/).
|
|
51
|
+
|
|
52
|
+
# Installation
|
|
53
|
+
|
|
54
|
+
To install the latest version of the package, simply run
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
pip install pyglaze
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
# Usage
|
|
61
|
+
See [our documentation](https://glazetech.github.io/pyglaze/latest/) for usage.
|
|
62
|
+
|
|
63
|
+
# Developers
|
|
64
|
+
|
|
65
|
+
To install the API with development tools in editable mode, first clone the repository from our [public GitHub repository](https://github.com/GlazeTech/pyglaze). Then, from the root of the project, run
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
python -m pip install --upgrade pip
|
|
69
|
+
pip install -e . --config-settings editable_mode=strict
|
|
70
|
+
pip install -r requirements-dev.txt
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Documentation - local build
|
|
74
|
+
To build and serve the documentation locally
|
|
75
|
+
|
|
76
|
+
1. Checkout the repository (or a specific version)
|
|
77
|
+
2. Install `mkdocs`
|
|
78
|
+
3. Run `mkdocs serve` while standing in the project root.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# Bug reporting or feature requests
|
|
82
|
+
Please create an issue [here](https://github.com/GlazeTech/pyglaze/issues) and we will look at it ASAP!
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
pyglaze/__init__.py,sha256=pU56ZDjCDnUbINe39hYuKXHy9UI9Tf4xjWgnxBlxEDk,22
|
|
2
|
+
pyglaze/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
pyglaze/datamodels/__init__.py,sha256=DJLByl2C7pC4RM4Uh6PW-McM5RIGBjcopzGywCKhSlI,111
|
|
4
|
+
pyglaze/datamodels/pulse.py,sha256=8N0wHHtV2c31E8LKzPOfxWYHialPGXQfXAoX_h7dkBA,20488
|
|
5
|
+
pyglaze/datamodels/waveform.py,sha256=n31DhJHFeBNZ3hHqQUiCGXssm5Dc8wV6tGPkhmFYB4Q,5809
|
|
6
|
+
pyglaze/device/__init__.py,sha256=NbN0I1U3mc_kNz-HyRCGRQQSi5z5peEZOIrH3z-m52Y,445
|
|
7
|
+
pyglaze/device/ampcom.py,sha256=_cPfgXb78uuj-GZkNPNDjifhQvqfkAxYycY8n_E2bvk,16767
|
|
8
|
+
pyglaze/device/configuration.py,sha256=8_q7l4DTsU_dfrZd384XYGyzmA8ZuOho98pFulzByeY,8511
|
|
9
|
+
pyglaze/device/delayunit.py,sha256=TO1FRhB3TepJn4QRNP-AKykWJVD9sx0Q9crL3xMudIk,4415
|
|
10
|
+
pyglaze/device/identifiers.py,sha256=-LBAhlYsxBGSMevUIqW3KxckdOzOT9HcKIBOjT3XN-U,1022
|
|
11
|
+
pyglaze/device/_delayunit_data/carmen-nonuniform-2023-10-20.pickle,sha256=5qcz-YwPfP5s2f5xlQ02er4dtZULWxXXJsac5tQsJRE,20400
|
|
12
|
+
pyglaze/device/_delayunit_data/g1-linearized-2023-04-04.pickle,sha256=N2QX4WSCrh7QihOqfczIYgk_XPx1IxY2zxp0gs9H0RY,209
|
|
13
|
+
pyglaze/device/_delayunit_data/g2-linearized-2023-04-04.pickle,sha256=eJ1A-NsZxN3pDd0UsqCyY9-pEzcXAYdsu_vxBx8ODq0,210
|
|
14
|
+
pyglaze/device/_delayunit_data/g2-nonuniform-2023-04-04.pickle,sha256=1Tyd22YzAqw2r6BPVemfE1XuJ8jZj8XYQik5Ne8-s9g,1784
|
|
15
|
+
pyglaze/device/_delayunit_data/mock_delay.pickle,sha256=tu-Uqytg8bWarBaXXRMD4jVU6MUr1Sz6dswJ6_6nbOA,207
|
|
16
|
+
pyglaze/devtools/__init__.py,sha256=9EW20idoaZv_5GuSgDmfpTPjfCZ-Rl27EV3oJebmwnQ,90
|
|
17
|
+
pyglaze/devtools/mock_device.py,sha256=TglmqvwX3FtdcE8cB_-3RNu2_QFtuJ-1chW8WTED3rc,13049
|
|
18
|
+
pyglaze/devtools/thz_pulse.py,sha256=xp-T9psdOrUMtSUFu8HEwQJVu_aMixJdZHtg_BCVu_k,923
|
|
19
|
+
pyglaze/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
pyglaze/helpers/types.py,sha256=p9xSAP5Trr1FcCWl7ynCWqDOUZKgMQYzMUXSwDpAKHg,599
|
|
21
|
+
pyglaze/helpers/utilities.py,sha256=n_x9Tqm305MUorS29O6CoJM8Mi4apo2bsN_odrRaVAw,2423
|
|
22
|
+
pyglaze/interpolation/__init__.py,sha256=WCxHPsiI7zvJykp-jfytoEbO4Tla-YIF6A7fjDfcDvU,72
|
|
23
|
+
pyglaze/interpolation/interpolation.py,sha256=rQWzPD7W8TXETps7VZI0gcfAOCWO8pGL1HhhBnyxaMw,735
|
|
24
|
+
pyglaze/scanning/__init__.py,sha256=uCBaeDTufOrC9KWf30ICqcmvFg_YT85olb3M9jkvZRg,99
|
|
25
|
+
pyglaze/scanning/_asyncscanner.py,sha256=n4PhRBSZLFSSeGgBkgVwFsdY4rnduXJnQo6TQ0ujVkw,5224
|
|
26
|
+
pyglaze/scanning/client.py,sha256=3qrQStkeLQzCeu4yMHJ_ENLGQ7E5GMc4CP9J55rk-ug,1817
|
|
27
|
+
pyglaze/scanning/scanner.py,sha256=TGHTO4qoLeKzb_hCuqEEAlKicbDvozY-3GiSfxiatXI,8226
|
|
28
|
+
pyglaze-0.1.0.dist-info/LICENSE,sha256=LCP3sGBX7LxuQopcjeug1fW4tngWCHF4zB7QCgB28xM,1504
|
|
29
|
+
pyglaze-0.1.0.dist-info/METADATA,sha256=OJ_Ck2MLNZ8ropSBGxuzRlDx8akLD_c2sEptwscCHuI,3498
|
|
30
|
+
pyglaze-0.1.0.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
|
31
|
+
pyglaze-0.1.0.dist-info/top_level.txt,sha256=X7d5rqVVuWNmtK4-Uh4sgOLlqye8vaHZOr5RYba0REo,8
|
|
32
|
+
pyglaze-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyglaze
|