waveforms 3.0.0__tar.gz → 3.1.0__tar.gz
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.
- {waveforms-3.0.0/waveforms.egg-info → waveforms-3.1.0}/PKG-INFO +1 -1
- {waveforms-3.0.0 → waveforms-3.1.0}/tests/test_waveform.py +92 -1
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/__init__.py +4 -1
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/_waveform.pyi +2 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/_waveform.pyx +210 -1
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/version.py +1 -1
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/waveform.py +40 -2
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/waveform_parser.py +1 -1
- {waveforms-3.0.0 → waveforms-3.1.0/waveforms.egg-info}/PKG-INFO +1 -1
- {waveforms-3.0.0 → waveforms-3.1.0}/LICENSE +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/MANIFEST.in +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/README.md +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/pyproject.toml +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/setup.cfg +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/setup.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/src/waveform.h +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/tests/test_wavevstack.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/Waveform.g4 +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/WaveformLexer.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/WaveformListener.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/WaveformParser.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/__main__.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/distortion.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms/utils.py +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms.egg-info/SOURCES.txt +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms.egg-info/dependency_links.txt +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms.egg-info/entry_points.txt +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms.egg-info/requires.txt +0 -0
- {waveforms-3.0.0 → waveforms-3.1.0}/waveforms.egg-info/top_level.txt +0 -0
|
@@ -13,7 +13,8 @@ import waveforms as wf
|
|
|
13
13
|
|
|
14
14
|
PUBLIC_NAMES = {
|
|
15
15
|
"D", "Waveform", "WaveVStack", "chirp", "const", "cos", "cosh",
|
|
16
|
-
"coshPulse", "cosPulse", "cut", "drag", "
|
|
16
|
+
"coshPulse", "cosPulse", "cut", "drag", "drag_sin", "drag_sinx",
|
|
17
|
+
"exp", "function",
|
|
17
18
|
"gaussian", "general_cosine", "get_time_resolution", "hanning", "interp", "mixing",
|
|
18
19
|
"mollifier", "one", "poly", "registerBaseFunc", "registerDerivative",
|
|
19
20
|
"samplingPoints", "set_time_resolution", "sign", "sin", "sinc", "sinh", "square", "step",
|
|
@@ -134,6 +135,96 @@ def test_sampling_points_chirps_and_mixing():
|
|
|
134
135
|
assert np.all(np.isfinite(q(x)))
|
|
135
136
|
|
|
136
137
|
|
|
138
|
+
@pytest.mark.parametrize("constructor,extra", [
|
|
139
|
+
(wf.drag_sin, {}),
|
|
140
|
+
(wf.drag_sinx, {"tab": 0.47}),
|
|
141
|
+
])
|
|
142
|
+
def test_multi_frequency_drag_roundtrip_shift_and_parser(constructor, extra):
|
|
143
|
+
parameters = dict(
|
|
144
|
+
freq=5e9,
|
|
145
|
+
width=22.22e-9,
|
|
146
|
+
plateau=3e-9,
|
|
147
|
+
delta=-13.7e6,
|
|
148
|
+
block_freq=(-91e6, 37e6, 124e6),
|
|
149
|
+
phase=0.31,
|
|
150
|
+
t0=7e-9,
|
|
151
|
+
**extra,
|
|
152
|
+
)
|
|
153
|
+
wav = constructor(**parameters)
|
|
154
|
+
x = np.linspace(-2e-9, 40e-9, 8193)
|
|
155
|
+
values = wav(x)
|
|
156
|
+
assert np.all(np.isfinite(values))
|
|
157
|
+
assert np.all(values[(x < parameters["t0"])
|
|
158
|
+
| (x >= parameters["t0"] + parameters["width"]
|
|
159
|
+
+ parameters["plateau"])] == 0)
|
|
160
|
+
|
|
161
|
+
restored = wf.Waveform.from_bytes(wav.to_bytes())
|
|
162
|
+
assert restored == wav
|
|
163
|
+
assert np.array_equal(restored(x), values)
|
|
164
|
+
delay = 11e-9
|
|
165
|
+
assert np.allclose((wav >> delay)(x + delay), values)
|
|
166
|
+
|
|
167
|
+
expression = (
|
|
168
|
+
f"{constructor.__name__}(5e9, 22.22e-9, plateau=3e-9, "
|
|
169
|
+
"delta=-13.7e6, block_freq=(-91e6, 37e6, 124e6), "
|
|
170
|
+
f"phase=0.31, t0=7e-9{', tab=0.47' if extra else ''})"
|
|
171
|
+
)
|
|
172
|
+
assert wf.wave_eval(expression) == wav
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_drag_sin_scalar_block_frequency_and_argument_validation():
|
|
176
|
+
scalar = wf.drag_sin(5e9, 20e-9, block_freq=80e6)
|
|
177
|
+
sequence = wf.drag_sin(5e9, 20e-9, block_freq=(80e6,))
|
|
178
|
+
assert scalar.to_bytes() == sequence.to_bytes()
|
|
179
|
+
with pytest.raises(ValueError):
|
|
180
|
+
wf.drag_sin(5e9, 0)
|
|
181
|
+
with pytest.raises(ValueError):
|
|
182
|
+
wf.drag_sinx(5e9, 20e-9, tab=0)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_multi_frequency_drag_matches_v2_numerical_behavior():
|
|
186
|
+
parameters = dict(
|
|
187
|
+
freq=5e9,
|
|
188
|
+
width=22.22e-9,
|
|
189
|
+
plateau=3e-9,
|
|
190
|
+
delta=-13.7e6,
|
|
191
|
+
block_freq=(-91e6, 37e6, 124e6),
|
|
192
|
+
phase=0.31,
|
|
193
|
+
t0=7e-9,
|
|
194
|
+
)
|
|
195
|
+
fractions = np.array([0, 0.07, 0.19, 0.37, 0.51,
|
|
196
|
+
0.68, 0.83, 0.96, 0.999])
|
|
197
|
+
x = parameters["t0"] + fractions * (
|
|
198
|
+
parameters["width"] + parameters["plateau"]
|
|
199
|
+
)
|
|
200
|
+
expected_sin = np.array([
|
|
201
|
+
0,
|
|
202
|
+
0.20532545807257174,
|
|
203
|
+
0.6208384978963238,
|
|
204
|
+
-0.4333357461117501,
|
|
205
|
+
-0.08840393960186489,
|
|
206
|
+
-0.8620379323126761,
|
|
207
|
+
-0.5748645543753418,
|
|
208
|
+
-0.07489572316435908,
|
|
209
|
+
-0.00309835789254227,
|
|
210
|
+
])
|
|
211
|
+
expected_sinx = np.array([
|
|
212
|
+
0,
|
|
213
|
+
0.11971095177791738,
|
|
214
|
+
0.36196762048509773,
|
|
215
|
+
-0.03689065391238458,
|
|
216
|
+
-0.05154217041569324,
|
|
217
|
+
-0.19970252200405683,
|
|
218
|
+
-0.3351634210081106,
|
|
219
|
+
-0.04366647169944161,
|
|
220
|
+
-0.00180643635595232,
|
|
221
|
+
])
|
|
222
|
+
assert np.allclose(wf.drag_sin(**parameters)(x), expected_sin,
|
|
223
|
+
rtol=2e-13, atol=2e-13)
|
|
224
|
+
assert np.allclose(wf.drag_sinx(**parameters, tab=0.47)(x), expected_sinx,
|
|
225
|
+
rtol=2e-13, atol=2e-13)
|
|
226
|
+
|
|
227
|
+
|
|
137
228
|
def test_filters_and_chunked_sampling():
|
|
138
229
|
sample_rate = 1000
|
|
139
230
|
b, a = butter(3, 4.0, "lowpass", fs=sample_rate)
|
|
@@ -13,6 +13,8 @@ from .waveform import (
|
|
|
13
13
|
cosPulse,
|
|
14
14
|
cut,
|
|
15
15
|
drag,
|
|
16
|
+
drag_sin,
|
|
17
|
+
drag_sinx,
|
|
16
18
|
exp,
|
|
17
19
|
function,
|
|
18
20
|
gaussian,
|
|
@@ -41,7 +43,8 @@ from .waveform import (
|
|
|
41
43
|
|
|
42
44
|
__all__ = [
|
|
43
45
|
"D", "Waveform", "WaveVStack", "chirp", "const", "cos", "cosh",
|
|
44
|
-
"coshPulse", "cosPulse", "cut", "drag", "
|
|
46
|
+
"coshPulse", "cosPulse", "cut", "drag", "drag_sin", "drag_sinx",
|
|
47
|
+
"e", "exp", "function",
|
|
45
48
|
"gaussian", "general_cosine", "get_time_resolution", "hanning",
|
|
46
49
|
"interp", "mixing", "mollifier", "one", "pi", "poly",
|
|
47
50
|
"registerBaseFunc", "registerDerivative", "samplingPoints",
|
|
@@ -12,7 +12,7 @@ import struct
|
|
|
12
12
|
from bisect import bisect_left
|
|
13
13
|
from functools import lru_cache
|
|
14
14
|
from itertools import chain, product
|
|
15
|
-
from math import comb
|
|
15
|
+
from math import comb, factorial
|
|
16
16
|
|
|
17
17
|
import numpy as np
|
|
18
18
|
import scipy.special as special
|
|
@@ -36,6 +36,8 @@ SINH = 12
|
|
|
36
36
|
DRAG = 13
|
|
37
37
|
MOLLIFIER = 14
|
|
38
38
|
D_GAUSSIAN = 15
|
|
39
|
+
DRAG_SIN = 16
|
|
40
|
+
DRAG_SINX = 17
|
|
39
41
|
|
|
40
42
|
_zero = ((), ())
|
|
41
43
|
_one = ((((), ()),), (1.0,))
|
|
@@ -169,6 +171,179 @@ def _drag(t, t0, freq, width, delta, block_freq, phase):
|
|
|
169
171
|
return omega_x * np.cos(wt) + omega_y * np.sin(wt)
|
|
170
172
|
|
|
171
173
|
|
|
174
|
+
def _b_series_matrix(block_coefficients):
|
|
175
|
+
matrix = np.zeros((len(block_coefficients) + 1, 2, 2))
|
|
176
|
+
matrix[0] = np.identity(2)
|
|
177
|
+
for coefficient in block_coefficients:
|
|
178
|
+
rotation = np.array([[0, coefficient], [-coefficient, 0]])
|
|
179
|
+
matrix[1:] += matrix[:-1] @ rotation
|
|
180
|
+
return matrix
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _sin_power_derivatives(int power, int order, double angular_frequency):
|
|
184
|
+
matrix = np.zeros((order + 1, power + 1))
|
|
185
|
+
matrix[0, power] = 1
|
|
186
|
+
for derivative in range(1, order + 1):
|
|
187
|
+
if derivative % 2:
|
|
188
|
+
matrix[derivative, :-1] = (
|
|
189
|
+
matrix[derivative - 1, 1:] * np.arange(1, power + 1)
|
|
190
|
+
* angular_frequency
|
|
191
|
+
)
|
|
192
|
+
else:
|
|
193
|
+
matrix[derivative, :-2] = (
|
|
194
|
+
matrix[derivative - 2, 2:] * np.arange(1, power)
|
|
195
|
+
* np.arange(2, power + 1)
|
|
196
|
+
)
|
|
197
|
+
matrix[derivative] -= (
|
|
198
|
+
matrix[derivative - 2] * np.arange(power + 1) ** 2
|
|
199
|
+
)
|
|
200
|
+
matrix[derivative] *= angular_frequency ** 2
|
|
201
|
+
return matrix
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _edge_polynomial(derivatives, double x):
|
|
205
|
+
values = np.asarray(derivatives, dtype=float).copy()
|
|
206
|
+
values[0] -= 1
|
|
207
|
+
size = values.shape[0]
|
|
208
|
+
matrix = np.zeros((size, size))
|
|
209
|
+
for derivative in range(size):
|
|
210
|
+
for coefficient in range(size):
|
|
211
|
+
matrix[derivative, coefficient] = (
|
|
212
|
+
x ** (size + coefficient - derivative)
|
|
213
|
+
* factorial(size + coefficient)
|
|
214
|
+
/ factorial(size + coefficient - derivative)
|
|
215
|
+
)
|
|
216
|
+
coefficients = np.linalg.solve(matrix, values)
|
|
217
|
+
return np.poly1d((*np.flip(coefficients), *np.zeros_like(values[:-1]), 1))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@lru_cache(maxsize=128)
|
|
221
|
+
def _drag_sin_plan(double width, double delta, tuple block_freq):
|
|
222
|
+
frequencies = np.asarray(block_freq, dtype=float)
|
|
223
|
+
block_coefficients = (
|
|
224
|
+
np.empty(0) if frequencies.size == 0
|
|
225
|
+
else 1 / (2 * pi * (frequencies - delta))
|
|
226
|
+
)
|
|
227
|
+
power = max(((len(block_coefficients) + 2) >> 1) << 1, 2)
|
|
228
|
+
transform = _b_series_matrix(block_coefficients)
|
|
229
|
+
derivatives = _sin_power_derivatives(
|
|
230
|
+
power, len(block_coefficients), pi / width
|
|
231
|
+
)
|
|
232
|
+
peak_basis = np.ones(power + 1)
|
|
233
|
+
peak_basis[1::2] = 0
|
|
234
|
+
peak_derivatives = derivatives @ peak_basis
|
|
235
|
+
transformed_peak = np.einsum(
|
|
236
|
+
"ijk,ki->j",
|
|
237
|
+
transform,
|
|
238
|
+
np.array([peak_derivatives, np.zeros_like(peak_derivatives)]),
|
|
239
|
+
)
|
|
240
|
+
normalization = np.sqrt(np.sum(np.abs(transformed_peak) ** 2))
|
|
241
|
+
return transform, derivatives, np.arange(power + 1), normalization
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _drag_sin_derivatives(t, double t0, double width, double plateau,
|
|
245
|
+
derivatives, powers):
|
|
246
|
+
midpoint = t0 + width / 2
|
|
247
|
+
plateau_stop = midpoint + plateau
|
|
248
|
+
plateau_mask = (t > midpoint) & (t < plateau_stop)
|
|
249
|
+
adjusted = np.where(t >= plateau_stop, t - plateau, t)
|
|
250
|
+
angle = pi / width * (adjusted - t0)
|
|
251
|
+
sine = np.sin(angle)
|
|
252
|
+
cosine = np.cos(angle)
|
|
253
|
+
if np.any(plateau_mask):
|
|
254
|
+
sine = sine.copy()
|
|
255
|
+
cosine = cosine.copy()
|
|
256
|
+
sine[plateau_mask] = 0
|
|
257
|
+
cosine[plateau_mask] = 0
|
|
258
|
+
basis = sine ** powers.reshape((-1, 1))
|
|
259
|
+
basis[1::2] *= cosine
|
|
260
|
+
values = derivatives @ basis
|
|
261
|
+
if np.any(plateau_mask):
|
|
262
|
+
values[0, plateau_mask] = 1
|
|
263
|
+
return values
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _drag_omega_sin(t, double t0, double width, double delta,
|
|
267
|
+
tuple block_freq, double plateau):
|
|
268
|
+
transform, derivatives, powers, normalization = _drag_sin_plan(
|
|
269
|
+
width, delta, block_freq
|
|
270
|
+
)
|
|
271
|
+
values = _drag_sin_derivatives(
|
|
272
|
+
t, t0, width, plateau, derivatives, powers
|
|
273
|
+
)
|
|
274
|
+
components = np.array([values, np.zeros_like(values)])
|
|
275
|
+
return np.einsum("ijk,kim->jm", transform, components) / normalization
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@lru_cache(maxsize=128)
|
|
279
|
+
def _drag_sinx_plan(double width, double delta, tuple block_freq, double tab):
|
|
280
|
+
transform, derivatives, powers, _ = _drag_sin_plan(
|
|
281
|
+
width, delta, block_freq
|
|
282
|
+
)
|
|
283
|
+
angular_frequency = pi / width
|
|
284
|
+
|
|
285
|
+
left_basis = np.sin(angular_frequency * (1 - tab) * width / 2) ** powers
|
|
286
|
+
left_basis[1::2] *= np.cos(angular_frequency * (1 - tab) * width / 2)
|
|
287
|
+
left_polynomial = _edge_polynomial(
|
|
288
|
+
derivatives @ left_basis, -tab * width / 2
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
right_basis = np.sin(angular_frequency * (1 + tab) * width / 2) ** powers
|
|
292
|
+
right_basis[1::2] *= np.cos(angular_frequency * (1 + tab) * width / 2)
|
|
293
|
+
right_polynomial = _edge_polynomial(
|
|
294
|
+
derivatives @ right_basis, tab * width / 2
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
order = len(block_freq) + 1
|
|
298
|
+
left_derivatives = tuple(
|
|
299
|
+
np.polyder(left_polynomial, derivative) for derivative in range(order)
|
|
300
|
+
)
|
|
301
|
+
right_derivatives = tuple(
|
|
302
|
+
np.polyder(right_polynomial, derivative) for derivative in range(order)
|
|
303
|
+
)
|
|
304
|
+
return (transform, derivatives, powers, left_derivatives,
|
|
305
|
+
right_derivatives)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def _drag_omega_sinx(t, double t0, double width, double delta,
|
|
309
|
+
tuple block_freq, double plateau, double tab):
|
|
310
|
+
(transform, derivatives, powers, left_derivatives,
|
|
311
|
+
right_derivatives) = _drag_sinx_plan(width, delta, block_freq, tab)
|
|
312
|
+
values = _drag_sin_derivatives(
|
|
313
|
+
t, t0, width, plateau, derivatives, powers
|
|
314
|
+
)
|
|
315
|
+
midpoint = t0 + width / 2
|
|
316
|
+
plateau_stop = midpoint + plateau
|
|
317
|
+
left_mask = (t >= midpoint - tab * width / 2) & (t <= midpoint)
|
|
318
|
+
right_mask = ((t >= plateau_stop)
|
|
319
|
+
& (t <= plateau_stop + tab * width / 2))
|
|
320
|
+
for derivative in range(len(block_freq) + 1):
|
|
321
|
+
values[derivative, left_mask] = left_derivatives[derivative](
|
|
322
|
+
t[left_mask] - midpoint
|
|
323
|
+
)
|
|
324
|
+
values[derivative, right_mask] = right_derivatives[derivative](
|
|
325
|
+
t[right_mask] - plateau_stop
|
|
326
|
+
)
|
|
327
|
+
components = np.array([values, np.zeros_like(values)])
|
|
328
|
+
return np.einsum("ijk,kim->jm", transform, components)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _drag_sin(t, t0, freq, width, delta, block_freq, phase, plateau):
|
|
332
|
+
omega_x, omega_y = _drag_omega_sin(
|
|
333
|
+
t, t0, width, delta, block_freq, plateau
|
|
334
|
+
)
|
|
335
|
+
wt = 2 * pi * (freq + delta) * t - (2 * pi * delta * t0 + phase)
|
|
336
|
+
return omega_x * np.cos(wt) + omega_y * np.sin(wt)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _drag_sinx(t, t0, freq, width, delta, block_freq, phase, plateau, tab):
|
|
340
|
+
omega_x, omega_y = _drag_omega_sinx(
|
|
341
|
+
t, t0, width, delta, block_freq, plateau, tab
|
|
342
|
+
)
|
|
343
|
+
wt = 2 * pi * (freq + delta) * t - (2 * pi * delta * t0 + phase)
|
|
344
|
+
return omega_x * np.cos(wt) + omega_y * np.sin(wt)
|
|
345
|
+
|
|
346
|
+
|
|
172
347
|
@lru_cache(maxsize=64)
|
|
173
348
|
def _mollifier_poly(d):
|
|
174
349
|
polynomial = np.poly1d([-2, 0])
|
|
@@ -205,6 +380,8 @@ _base_functions = {
|
|
|
205
380
|
DRAG: _drag,
|
|
206
381
|
MOLLIFIER: _MOLLIFIER,
|
|
207
382
|
D_GAUSSIAN: _D_GAUSSIAN,
|
|
383
|
+
DRAG_SIN: _drag_sin,
|
|
384
|
+
DRAG_SINX: _drag_sinx,
|
|
208
385
|
}
|
|
209
386
|
|
|
210
387
|
|
|
@@ -280,6 +457,18 @@ def _encode_builtin_args(bytearray out, int opcode, args):
|
|
|
280
457
|
float(values[1]), _time_to_tick(values[2]),
|
|
281
458
|
float(values[3]), float(values[4]),
|
|
282
459
|
float(values[5]), _time_to_tick(values[6])))
|
|
460
|
+
elif opcode in (DRAG_SIN, DRAG_SINX):
|
|
461
|
+
t0, freq, width, delta, block_freq, phase, plateau = args[:7]
|
|
462
|
+
block_freq = tuple(float(value) for value in block_freq)
|
|
463
|
+
out.extend(struct.pack("<qdqddq", _time_to_tick(t0), float(freq),
|
|
464
|
+
_time_to_tick(width), float(delta),
|
|
465
|
+
float(phase), _time_to_tick(plateau)))
|
|
466
|
+
if opcode == DRAG_SINX:
|
|
467
|
+
out.extend(struct.pack("<d", float(args[7])))
|
|
468
|
+
out.extend(struct.pack("<I", len(block_freq)))
|
|
469
|
+
if block_freq:
|
|
470
|
+
out.extend(struct.pack(f"<{len(block_freq)}d", *block_freq))
|
|
471
|
+
out.extend(struct.pack("<q", _time_to_tick(args[-1])))
|
|
283
472
|
elif opcode in (MOLLIFIER, D_GAUSSIAN):
|
|
284
473
|
out.extend(struct.pack("<qiq", _time_to_tick(args[0]), int(args[1]),
|
|
285
474
|
_time_to_tick(args[2])))
|
|
@@ -318,6 +507,26 @@ def _decode_builtin_args(bytes data, Py_ssize_t pos, int opcode):
|
|
|
318
507
|
values[4] = None
|
|
319
508
|
values[-1] = _tick_to_time(values[-1])
|
|
320
509
|
return tuple(values), pos + 56
|
|
510
|
+
if opcode in (DRAG_SIN, DRAG_SINX):
|
|
511
|
+
t0, freq, width, delta, phase, plateau = struct.unpack_from(
|
|
512
|
+
"<qdqddq", data, pos
|
|
513
|
+
)
|
|
514
|
+
pos += 48
|
|
515
|
+
tab = None
|
|
516
|
+
if opcode == DRAG_SINX:
|
|
517
|
+
tab = struct.unpack_from("<d", data, pos)[0]
|
|
518
|
+
pos += 8
|
|
519
|
+
count = struct.unpack_from("<I", data, pos)[0]
|
|
520
|
+
pos += 4
|
|
521
|
+
block_freq = struct.unpack_from(f"<{count}d", data, pos)
|
|
522
|
+
pos += 8 * count
|
|
523
|
+
shift = struct.unpack_from("<q", data, pos)[0]
|
|
524
|
+
pos += 8
|
|
525
|
+
values = (_tick_to_time(t0), freq, _tick_to_time(width), delta,
|
|
526
|
+
block_freq, phase, _tick_to_time(plateau))
|
|
527
|
+
if opcode == DRAG_SINX:
|
|
528
|
+
values += (tab,)
|
|
529
|
+
return values + (_tick_to_time(shift),), pos
|
|
321
530
|
if opcode in (MOLLIFIER, D_GAUSSIAN):
|
|
322
531
|
first, order, shift = struct.unpack_from("<qiq", data, pos)
|
|
323
532
|
return (_tick_to_time(first), order, _tick_to_time(shift)), pos + 20
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Define version number here and read it from setup.py automatically"""
|
|
2
|
-
__version__ = "3.
|
|
2
|
+
__version__ = "3.1.0"
|
|
@@ -16,7 +16,8 @@ from numpy import e, inf, pi
|
|
|
16
16
|
from scipy.signal import sosfilt
|
|
17
17
|
|
|
18
18
|
from ._waveform import (
|
|
19
|
-
COS, COSH, D_GAUSSIAN, DRAG,
|
|
19
|
+
COS, COSH, D_GAUSSIAN, DRAG, DRAG_SIN, DRAG_SINX, ERF, EXP,
|
|
20
|
+
EXPONENTIALCHIRP, GAUSSIAN,
|
|
20
21
|
HYPERBOLICCHIRP, INTERP, LINEAR, LINEARCHIRP, MOLLIFIER, SINC, SINH,
|
|
21
22
|
PackedStack, PackedWaveform, basic, constant, get_time_resolution,
|
|
22
23
|
piecewise, quantize_time, registerBaseFunc, registerDerivative,
|
|
@@ -813,6 +814,42 @@ def drag(freq, width, plateau=0, delta=0, block_freq=None, phase=0, t0=0):
|
|
|
813
814
|
)
|
|
814
815
|
|
|
815
816
|
|
|
817
|
+
def _block_frequencies(block_freq):
|
|
818
|
+
if block_freq is None:
|
|
819
|
+
return ()
|
|
820
|
+
if np.isscalar(block_freq):
|
|
821
|
+
return (float(block_freq),)
|
|
822
|
+
return tuple(float(value) for value in block_freq)
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
def drag_sin(freq, width, plateau=0, delta=0, block_freq=None, phase=0,
|
|
826
|
+
t0=0):
|
|
827
|
+
"""Return a sine-power DRAG pulse with spectral blocking constraints."""
|
|
828
|
+
if width <= 0:
|
|
829
|
+
raise ValueError("width must be positive")
|
|
830
|
+
phase += pi * delta * (width + plateau)
|
|
831
|
+
core = _scalar(
|
|
832
|
+
DRAG_SIN, t0, freq, width, delta, _block_frequencies(block_freq),
|
|
833
|
+
phase, plateau,
|
|
834
|
+
)
|
|
835
|
+
return _piecewise((t0, t0 + width + plateau, inf), 0, core, 0)
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
def drag_sinx(freq, width, plateau=0, delta=0, block_freq=None, phase=0,
|
|
839
|
+
t0=0, tab=0.618):
|
|
840
|
+
"""Return a flat-top sine-power DRAG pulse with polynomial joins."""
|
|
841
|
+
if width <= 0:
|
|
842
|
+
raise ValueError("width must be positive")
|
|
843
|
+
if not 0 < tab <= 1:
|
|
844
|
+
raise ValueError("tab must be in the interval (0, 1]")
|
|
845
|
+
phase += pi * delta * (width + plateau)
|
|
846
|
+
core = _scalar(
|
|
847
|
+
DRAG_SINX, t0, freq, width, delta, _block_frequencies(block_freq),
|
|
848
|
+
phase, plateau, tab,
|
|
849
|
+
)
|
|
850
|
+
return _piecewise((t0, t0 + width + plateau, inf), 0, core, 0)
|
|
851
|
+
|
|
852
|
+
|
|
816
853
|
def chirp(f0, f1, T, phi0=0, type="linear"):
|
|
817
854
|
if f0 == f1:
|
|
818
855
|
return sin(f0, phi0)
|
|
@@ -941,7 +978,8 @@ def wave_eval(expr: str) -> Waveform:
|
|
|
941
978
|
|
|
942
979
|
__all__ = [
|
|
943
980
|
"D", "Waveform", "WaveVStack", "chirp", "const", "cos", "cosh",
|
|
944
|
-
"coshPulse", "cosPulse", "cut", "drag", "
|
|
981
|
+
"coshPulse", "cosPulse", "cut", "drag", "drag_sin", "drag_sinx",
|
|
982
|
+
"exp", "function",
|
|
945
983
|
"gaussian", "general_cosine", "get_time_resolution", "hanning",
|
|
946
984
|
"interp", "mixing", "mollifier", "one", "play", "poly",
|
|
947
985
|
"registerBaseFunc", "registerDerivative", "samplingPoints",
|
|
@@ -32,7 +32,7 @@ class WaveformVisitor:
|
|
|
32
32
|
self.extra_modules = tuple(extra_modules)
|
|
33
33
|
self.functions = [
|
|
34
34
|
'D', 'chirp', 'const', 'cos', 'cosh', 'coshPulse', 'cosPulse',
|
|
35
|
-
'cut', 'drag', 'exp', 'gaussian',
|
|
35
|
+
'cut', 'drag', 'drag_sin', 'drag_sinx', 'exp', 'gaussian',
|
|
36
36
|
'general_cosine', 'hanning', 'interp', 'mixing', 'mollifier',
|
|
37
37
|
'one', 'poly', 'samplingPoints', 'sign', 'sin', 'sinc', 'sinh',
|
|
38
38
|
'square', 'step', 't', 'zero'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|