waveforms 2.1.1__tar.gz → 2.2.1__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.
Files changed (30) hide show
  1. {waveforms-2.1.1 → waveforms-2.2.1}/PKG-INFO +1 -1
  2. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/__init__.py +4 -3
  3. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/_waveform.pyi +13 -7
  4. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/_waveform.pyx +30 -0
  5. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/distortion.py +39 -25
  6. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/multy_drag.py +0 -16
  7. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/version.py +1 -1
  8. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/waveform.py +242 -107
  9. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/waveform_parser.py +12 -13
  10. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms.egg-info/PKG-INFO +1 -1
  11. {waveforms-2.1.1 → waveforms-2.2.1}/LICENSE +0 -0
  12. {waveforms-2.1.1 → waveforms-2.2.1}/MANIFEST.in +0 -0
  13. {waveforms-2.1.1 → waveforms-2.2.1}/README.md +0 -0
  14. {waveforms-2.1.1 → waveforms-2.2.1}/pyproject.toml +0 -0
  15. {waveforms-2.1.1 → waveforms-2.2.1}/setup.cfg +0 -0
  16. {waveforms-2.1.1 → waveforms-2.2.1}/setup.py +0 -0
  17. {waveforms-2.1.1 → waveforms-2.2.1}/src/waveform.h +0 -0
  18. {waveforms-2.1.1 → waveforms-2.2.1}/tests/test_multi_drag.py +0 -0
  19. {waveforms-2.1.1 → waveforms-2.2.1}/tests/test_waveform.py +0 -0
  20. {waveforms-2.1.1 → waveforms-2.2.1}/tests/test_wavevstack.py +0 -0
  21. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/WaveformLexer.py +0 -0
  22. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/WaveformListener.py +0 -0
  23. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/WaveformParser.py +0 -0
  24. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/__main__.py +0 -0
  25. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms/utils.py +0 -0
  26. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms.egg-info/SOURCES.txt +0 -0
  27. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms.egg-info/dependency_links.txt +0 -0
  28. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms.egg-info/entry_points.txt +0 -0
  29. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms.egg-info/requires.txt +0 -0
  30. {waveforms-2.1.1 → waveforms-2.2.1}/waveforms.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: waveforms
3
- Version: 2.1.1
3
+ Version: 2.2.1
4
4
  Summary: Edit waveforms used in experiment
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -4,7 +4,8 @@ from .multy_drag import drag_sin, drag_sinx
4
4
  from .version import __version__
5
5
  from .waveform import (D, Waveform, WaveVStack, chirp, const, cos, cosh,
6
6
  coshPulse, cosPulse, cut, drag, exp, function, gaussian,
7
- general_cosine, hanning, interp, mixing, one, poly,
8
- registerBaseFunc, registerDerivative, samplingPoints,
9
- sign, sin, sinc, sinh, square, step, t, zero)
7
+ general_cosine, hanning, interp, mixing, mollifier, one,
8
+ poly, registerBaseFunc, registerDerivative,
9
+ samplingPoints, sign, sin, sinc, sinh, square, step, t,
10
+ zero)
10
11
  from .waveform_parser import wave_eval
@@ -2,6 +2,7 @@ from typing import Callable
2
2
 
3
3
  import numpy as np
4
4
  from numpy import e, inf, pi
5
+ from numpy.typing import NDArray
5
6
 
6
7
  NDIGITS: int = ...
7
8
  __TypeIndex: int = ...
@@ -28,7 +29,7 @@ def is_const(x: tuple[tuple, tuple]) -> bool:
28
29
  pass
29
30
 
30
31
 
31
- def basic_wave(Type, *args, shift=0) -> tuple[tuple, tuple]:
32
+ def basic_wave(Type: int, *args, shift: float = 0) -> tuple[tuple, tuple]:
32
33
  pass
33
34
 
34
35
 
@@ -48,12 +49,15 @@ def pow(x: tuple[tuple, tuple], n: int) -> tuple[tuple, tuple]:
48
49
  pass
49
50
 
50
51
 
51
- def calc_parts(bounds: tuple,
52
- seq: tuple,
53
- x: np.ndarray,
54
- function_lib: dict,
55
- min=-inf,
56
- max=inf) -> tuple[list[np.ndarray], type]:
52
+ def calc_parts(
53
+ bounds: tuple,
54
+ seq: tuple,
55
+ x: np.ndarray,
56
+ function_lib: dict,
57
+ min=-inf,
58
+ max=inf
59
+ ) -> tuple[list[tuple[int, int, NDArray[np.float64 | np.complex128] | int
60
+ | float | complex]], type]:
57
61
  pass
58
62
 
59
63
 
@@ -103,6 +107,8 @@ HYPERBOLICCHIRP: int = ...
103
107
  COSH: int = ...
104
108
  SINH: int = ...
105
109
  DRAG: int = ...
110
+ MOLLIFIER: int = ...
111
+ D_GAUSSIAN: int = ...
106
112
 
107
113
 
108
114
  def simplify(expr: tuple[tuple, tuple], eps: float) -> tuple[tuple, tuple]:
@@ -295,6 +295,11 @@ def _GAUSSIAN(t, std_sq2):
295
295
  return np.exp(-(t / std_sq2)**2)
296
296
 
297
297
 
298
+ def _D_GAUSSIAN(t, std_sq2, n):
299
+ return (-1)**n / std_sq2**n * special.hermite(n)(
300
+ t / std_sq2) * np.exp(-(t / std_sq2)**2)
301
+
302
+
298
303
  def _ERF(t, std_sq2):
299
304
  return special.erf(t / std_sq2)
300
305
 
@@ -351,6 +356,19 @@ def _drag(t: np.ndarray, t0: float, freq: float, width: float, delta: float,
351
356
  return Omega_x * np.cos(wt) + Omega_y * np.sin(wt)
352
357
 
353
358
 
359
+ def _mollifier(t: np.ndarray, r: float, d: int):
360
+ x = t / r
361
+ if d == 0:
362
+ return np.exp(1 / (np.abs(x)**2 - 1) + 1)
363
+ else:
364
+ p = np.poly1d([-2, 0])
365
+ for n in range(1, d):
366
+ p = np.poly1d([1, 0, -2, 0, 1]) * p.deriv() + np.poly1d(
367
+ [-4 * n, 0, 4 * n - 2, 0]) * p
368
+ return np.exp(1 / (np.abs(x)**2 - 1) +
369
+ 1) * p(x) / (1 - x**2)**(2 * d) / r**d
370
+
371
+
354
372
  LINEAR = registerBaseFunc(_LINEAR)
355
373
  GAUSSIAN = registerBaseFunc(_GAUSSIAN)
356
374
  ERF = registerBaseFunc(_ERF)
@@ -364,6 +382,8 @@ HYPERBOLICCHIRP = registerBaseFunc(_HYPERBOLICCHIRP)
364
382
  COSH = registerBaseFunc(_COSH)
365
383
  SINH = registerBaseFunc(_SINH)
366
384
  DRAG = registerBaseFunc(_drag)
385
+ MOLLIFIER = registerBaseFunc(_mollifier)
386
+ D_GAUSSIAN = registerBaseFunc(_D_GAUSSIAN)
367
387
 
368
388
 
369
389
  def _d_LINEAR(shift, *args):
@@ -433,6 +453,14 @@ def _d_HYPERBOLICCHIRP(shift, f0, k, phi0):
433
453
  shift)), (-1, 1)), ), (2 * pi * f0, ))
434
454
 
435
455
 
456
+ def _d_MOLLIFIER(shift, r, d):
457
+ return (((((MOLLIFIER, r, d + 1, shift), ), (1, )), ), (1, ))
458
+
459
+
460
+ def _d_D_GAUSSIAN(shift, std_sq2, n):
461
+ return (((((D_GAUSSIAN, std_sq2, n + 1, shift), ), (1, )), ), (1, ))
462
+
463
+
436
464
  # register derivative
437
465
  registerDerivative(LINEAR, _d_LINEAR)
438
466
  registerDerivative(GAUSSIAN, _d_GAUSSIAN)
@@ -446,6 +474,8 @@ registerDerivative(SINH, _d_SINH)
446
474
  registerDerivative(LINEARCHIRP, _d_LINEARCHIRP)
447
475
  registerDerivative(EXPONENTIALCHIRP, _d_EXPONENTIALCHIRP)
448
476
  registerDerivative(HYPERBOLICCHIRP, _d_HYPERBOLICCHIRP)
477
+ registerDerivative(MOLLIFIER, _d_MOLLIFIER)
478
+ registerDerivative(D_GAUSSIAN, _d_D_GAUSSIAN)
449
479
 
450
480
 
451
481
  def _cos_power_n(x, n):
@@ -1,8 +1,9 @@
1
1
  import warnings
2
- from itertools import repeat, zip_longest
3
- from typing import Sequence
2
+ from itertools import zip_longest
3
+ from typing import Sequence, cast
4
4
 
5
5
  import numpy as np
6
+ from numpy.typing import NDArray
6
7
  from scipy.fftpack import fft, fftfreq, ifft, ifftshift
7
8
  from scipy.optimize import curve_fit
8
9
  from scipy.signal import fftconvolve, lfilter, lfiltic, tf2zpk, zpk2sos, zpk2tf
@@ -55,7 +56,7 @@ def zDistortKernel(dt: float, params: Sequence[tuple]) -> np.ndarray:
55
56
  for tau, A in params:
56
57
  H += (1j * A * omega * tau) / (1j * omega * tau + 1)
57
58
 
58
- ker = ifftshift(ifft(1 / H)).real
59
+ ker = cast(NDArray[np.complex128], ifftshift(ifft(1 / H))).real
59
60
  return ker
60
61
 
61
62
 
@@ -98,11 +99,14 @@ def exp_decay_filter_old(amp, tau, sample_rate):
98
99
  return b, a
99
100
 
100
101
 
101
- def exp_decay_filter(amp: float | Sequence[float],
102
- tau: float | Sequence[float],
103
- sample_rate: float,
104
- inv: bool = False,
105
- output='ba') -> tuple[np.ndarray, np.ndarray]:
102
+ def exp_decay_filter(
103
+ amp: float | Sequence[float],
104
+ tau: float | Sequence[float],
105
+ sample_rate: float,
106
+ inv: bool = False,
107
+ output='ba'
108
+ ) -> NDArray[np.float64] | tuple[NDArray[np.float64], NDArray[
109
+ np.float64]] | tuple[NDArray[np.float64], NDArray[np.float64], float]:
106
110
  """
107
111
  exp decay filter
108
112
 
@@ -137,7 +141,9 @@ def exp_decay_filter(amp: float | Sequence[float],
137
141
 
138
142
  if isinstance(amp, (int, float, complex)):
139
143
  amp = [amp]
140
- tau = [tau]
144
+ tau = [cast(float, tau)]
145
+ amp = cast(Sequence[float], amp)
146
+ tau = cast(Sequence[float], tau)
141
147
  numerator, denominator = np.poly1d([0.0]), np.poly1d([1.0])
142
148
  for i, (A, t) in enumerate(zip(amp, tau)):
143
149
  denominator = denominator * np.poly1d([1, -1 / t])
@@ -148,18 +154,22 @@ def exp_decay_filter(amp: float | Sequence[float],
148
154
  numerator = numerator + n
149
155
  numerator = numerator + denominator
150
156
 
151
- z = np.exp(-numerator.roots / sample_rate)
152
- p = np.exp(-denominator.roots / sample_rate)
157
+ z = cast(NDArray[np.float64], np.exp(-numerator.roots / sample_rate))
158
+ p = cast(NDArray[np.float64], np.exp(-denominator.roots / sample_rate))
153
159
  if inv:
154
160
  z, p = p, z
155
- k = numerator(0) / denominator(0) * np.prod(1 - p) / np.prod(1 - z)
161
+ k = cast(float,
162
+ numerator(0) / denominator(0) * np.prod(1 - p) / np.prod(1 - z))
156
163
 
157
164
  if output == 'sos':
158
- return zpk2sos(z, p, k)
165
+ return cast(NDArray[np.float64], zpk2sos(z, p, k))
159
166
  elif output == 'ba':
160
- return zpk2tf(z, p, k)
167
+ return cast(tuple[NDArray[np.float64], NDArray[np.float64]],
168
+ zpk2tf(z, p, k))
161
169
  elif output == 'zpk':
162
170
  return z, p, k
171
+ else:
172
+ raise ValueError(f"Invalid output type: {output}")
163
173
 
164
174
 
165
175
  def reflection_filter(f, A, tau):
@@ -251,7 +261,8 @@ def stable_filter(exp_decay_filters: list, sample_rate: float):
251
261
  """
252
262
  filters = []
253
263
  for amp, tau in exp_decay_filters:
254
- a, b = exp_decay_filter(amp, tau, sample_rate)
264
+ a, b = cast(tuple[NDArray[np.float64], NDArray[np.float64]],
265
+ exp_decay_filter(amp, tau, sample_rate))
255
266
  filters.append((b, a))
256
267
 
257
268
  b, a = combine_filters(filters)
@@ -262,14 +273,15 @@ def stable_filter(exp_decay_filters: list, sample_rate: float):
262
273
  return False
263
274
 
264
275
 
265
- def predistort(sig: np.ndarray,
266
- filters: list = None,
267
- ker: np.ndarray = None,
268
- initial: float = 0.0,
269
- initial_x: np.ndarray | None = None,
270
- initial_y: np.ndarray | None = None,
271
- zi: np.ndarray | None = None,
272
- return_zf: bool = False) -> np.ndarray:
276
+ def predistort(
277
+ sig: np.ndarray,
278
+ filters: list | None = None,
279
+ ker: np.ndarray | None = None,
280
+ initial: float = 0.0,
281
+ initial_x: np.ndarray | None = None,
282
+ initial_y: np.ndarray | None = None,
283
+ zi: np.ndarray | None = None,
284
+ return_zf: bool = False) -> np.ndarray | tuple[np.ndarray, np.ndarray]:
273
285
  if filters is not None:
274
286
  b, a = combine_filters(filters)
275
287
  z, p, k = tf2zpk(b, a)
@@ -315,7 +327,8 @@ def predistort(sig: np.ndarray,
315
327
  def distort(points, params, sample_rate, initial=0.0):
316
328
  filters = []
317
329
  for amp, tau in np.asarray(params).reshape(-1, 2):
318
- b, a = exp_decay_filter(amp, abs(tau), sample_rate)
330
+ b, a = cast(tuple[NDArray[np.float64], NDArray[np.float64]],
331
+ exp_decay_filter(amp, abs(tau), sample_rate))
319
332
  filters.append((b, a))
320
333
  return predistort(points, filters, initial=initial)
321
334
 
@@ -342,6 +355,7 @@ def phase_curve(t, params, df_dphi, pulse_width, start, wav, sample_rate):
342
355
 
343
356
  if __name__ == '__main__':
344
357
  import matplotlib.pyplot as plt
358
+
345
359
  from waveforms import square
346
360
 
347
361
  data = np.load('Z_distortion.npz')
@@ -354,7 +368,7 @@ if __name__ == '__main__':
354
368
  wav = 0.1 * (square(2e-6) << 1e-6)
355
369
 
356
370
  def f(t, *params):
357
- return phase_curve(t, params, df_dphi, 10e-9, 25e-9)
371
+ return phase_curve(t, params, df_dphi, 10e-9, 25e-9, wav, sample_rate)
358
372
 
359
373
  params = [-0.03, 0.1e-6, 0.02, 0.3e-6]
360
374
  popt, pcov = curve_fit(f, x, y, p0=params)
@@ -230,19 +230,3 @@ def drag_sinx(freq,
230
230
  bounds=(round(t0,
231
231
  NDIGITS), round(t0 + width + plateau,
232
232
  NDIGITS), +inf))
233
-
234
-
235
- def _mollifier(x, width):
236
- return np.exp(1 / ((x / width)**2 - 1))
237
-
238
-
239
- def _format_MOLLIFIER(shift, *args):
240
- width, *_ = args
241
- return f'\\exp\\frac{{1}}{{\\left(\\frac{{t-{shift:.{NDIGITS}f}}}{{{width:.{NDIGITS}f}}}\\right)^2-1}}'
242
-
243
-
244
- MOLLIFIER = registerBaseFunc(_mollifier)
245
- registerDerivative(
246
- MOLLIFIER,
247
- lambda x, width: 2 * x / width**2 * _mollifier(x, width),
248
- )
@@ -1,2 +1,2 @@
1
1
  """Define version number here and read it from setup.py automatically"""
2
- __version__ = "2.1.1"
2
+ __version__ = "2.2.1"
@@ -1,16 +1,21 @@
1
+ from __future__ import annotations
2
+
1
3
  from fractions import Fraction
4
+ from typing import Generator, Iterable, cast
2
5
 
3
6
  import numpy as np
4
7
  from numpy import e, inf, pi
8
+ from numpy.typing import NDArray
5
9
  from scipy.signal import sosfilt
6
10
 
7
- from ._waveform import (_D, COS, COSH, DRAG, ERF, EXP, EXPONENTIALCHIRP,
8
- GAUSSIAN, HYPERBOLICCHIRP, INTERP, LINEAR, LINEARCHIRP,
9
- NDIGITS, SINC, SINH, _baseFunc, _baseFunc_latex,
10
- _const, _half, _one, _zero, add, basic_wave,
11
- calc_parts, filter, is_const, merge_waveform, mul, pow,
12
- registerBaseFunc, registerBaseFuncLatex,
13
- registerDerivative, shift, simplify, wave_sum)
11
+ from ._waveform import (_D, COS, COSH, D_GAUSSIAN, DRAG, ERF, EXP,
12
+ EXPONENTIALCHIRP, GAUSSIAN, HYPERBOLICCHIRP, INTERP,
13
+ LINEAR, LINEARCHIRP, MOLLIFIER, NDIGITS, SINC, SINH,
14
+ _baseFunc, _baseFunc_latex, _const, _half, _one, _zero,
15
+ add, basic_wave, calc_parts, filter, is_const,
16
+ merge_waveform, mul, pow, registerBaseFunc,
17
+ registerBaseFuncLatex, registerDerivative, shift,
18
+ simplify, wave_sum)
14
19
 
15
20
 
16
21
  def _test_spec_num(num, spec):
@@ -124,13 +129,13 @@ class Waveform:
124
129
  self.start = None
125
130
  self.stop = None
126
131
  self.sample_rate = None
127
- self.filters = None
132
+ self.filters: tuple[np.ndarray, float] | None = None
128
133
  self.label = None
129
134
 
130
135
  @staticmethod
131
136
  def _begin(bounds, seq):
132
137
  for i, s in enumerate(seq):
133
- if s is not _zero:
138
+ if s != _zero:
134
139
  if i == 0:
135
140
  return -inf
136
141
  return bounds[i - 1]
@@ -140,7 +145,7 @@ class Waveform:
140
145
  def _end(bounds, seq):
141
146
  N = len(bounds)
142
147
  for i, s in enumerate(seq[::-1]):
143
- if s is not _zero:
148
+ if s != _zero:
144
149
  if i == 0:
145
150
  return inf
146
151
  return bounds[N - i - 1]
@@ -160,12 +165,14 @@ class Waveform:
160
165
  else:
161
166
  return min(self.stop, self._end(self.bounds, self.seq))
162
167
 
163
- def sample(self,
164
- sample_rate=None,
165
- out=None,
166
- chunk_size=None,
167
- function_lib=None,
168
- filters=None):
168
+ def sample(
169
+ self,
170
+ sample_rate=None,
171
+ out: np.ndarray | None = None,
172
+ chunk_size=None,
173
+ function_lib=None,
174
+ filters: tuple[np.ndarray, float] | None = None
175
+ ) -> np.ndarray | Iterable[np.ndarray]:
169
176
  if sample_rate is None:
170
177
  sample_rate = self.sample_rate
171
178
  if self.start is None or self.stop is None or sample_rate is None:
@@ -176,7 +183,8 @@ class Waveform:
176
183
  filters = self.filters
177
184
  if chunk_size is None:
178
185
  x = np.arange(self.start, self.stop, 1 / sample_rate)
179
- sig = self.__call__(x, out=out, function_lib=function_lib)
186
+ sig = cast(np.ndarray,
187
+ self.__call__(x, out=out, function_lib=function_lib))
180
188
  if filters is not None:
181
189
  sos, initial = filters
182
190
  if not isinstance(sos, np.ndarray):
@@ -184,27 +192,34 @@ class Waveform:
184
192
  elif not sos.flags.writeable:
185
193
  sos = sos.copy()
186
194
  if initial:
187
- sig = sosfilt(sos, sig - initial) + initial
195
+ sig = cast(np.ndarray, sosfilt(sos,
196
+ sig - initial)) + initial
188
197
  else:
189
- sig = sosfilt(sos, sig)
190
- return sig
198
+ sig = cast(np.ndarray, sosfilt(sos, sig))
199
+ return cast(np.ndarray, sig)
191
200
  else:
192
201
  return self._sample_iter(sample_rate, chunk_size, out,
193
202
  function_lib, filters)
194
203
 
195
- def _sample_iter(self, sample_rate, chunk_size, out, function_lib,
196
- filters):
197
- start = self.start
204
+ def _sample_iter(
205
+ self, sample_rate, chunk_size, out: np.ndarray | None, function_lib,
206
+ filters: tuple[np.ndarray, float] | None
207
+ ) -> Generator[np.ndarray, None, None]:
208
+ start = cast(float, self.start)
198
209
  start_n = 0
199
210
  if filters is not None:
200
211
  sos, initial = filters
212
+ if not isinstance(sos, np.ndarray):
213
+ sos = np.array(sos)
214
+ elif not sos.flags.writeable:
215
+ sos = sos.copy()
201
216
  # zi = sosfilt_zi(sos)
202
217
  zi = np.zeros((sos.shape[0], 2))
203
218
  length = chunk_size / sample_rate
204
- while start < self.stop:
205
- if start + length > self.stop:
206
- length = self.stop - start
207
- stop = self.stop
219
+ while start < cast(float, self.stop):
220
+ if start + length > cast(float, self.stop):
221
+ length = cast(float, self.stop) - start
222
+ stop = cast(float, self.stop)
208
223
  size = round((stop - start) * sample_rate)
209
224
  else:
210
225
  stop = start + length
@@ -213,13 +228,17 @@ class Waveform:
213
228
 
214
229
  if filters is None:
215
230
  if out is not None:
216
- yield self.__call__(x,
217
- out=out[start_n:],
218
- function_lib=function_lib)
231
+ yield cast(
232
+ np.ndarray,
233
+ self.__call__(x,
234
+ out=out[start_n:],
235
+ function_lib=function_lib))
219
236
  else:
220
- yield self.__call__(x, function_lib=function_lib)
237
+ yield cast(np.ndarray,
238
+ self.__call__(x, function_lib=function_lib))
221
239
  else:
222
- sig = self.__call__(x, function_lib=function_lib)
240
+ sig = cast(np.ndarray,
241
+ self.__call__(x, function_lib=function_lib))
223
242
  if initial:
224
243
  sig -= initial
225
244
  sig, zi = sosfilt(sos, sig, zi=zi)
@@ -227,7 +246,7 @@ class Waveform:
227
246
  sig += initial
228
247
  if out is not None:
229
248
  out[start_n:start_n + size] = sig
230
- yield sig
249
+ yield cast(np.ndarray, sig)
231
250
 
232
251
  start = stop
233
252
  start_n += chunk_size
@@ -379,22 +398,22 @@ class Waveform:
379
398
  return Waveform(*merge_waveform(self.bounds, self.seq, other.bounds,
380
399
  other.seq, oper))
381
400
 
382
- def __pow__(self, n):
401
+ def __pow__(self, n) -> Waveform:
383
402
  return Waveform(self.bounds, tuple(pow(w, n) for w in self.seq))
384
403
 
385
- def __add__(self, other):
404
+ def __add__(self, other) -> Waveform:
386
405
  if isinstance(other, Waveform):
387
406
  return self._comb(other, add)
388
407
  else:
389
408
  return self + const(other)
390
409
 
391
- def __radd__(self, v):
410
+ def __radd__(self, v) -> Waveform:
392
411
  return const(v) + self
393
412
 
394
- def __ior__(self, other):
413
+ def __ior__(self, other) -> Waveform:
395
414
  return self | other
396
415
 
397
- def __or__(self, other):
416
+ def __or__(self, other) -> Waveform:
398
417
  if isinstance(other, (int, float, complex)):
399
418
  other = const(other)
400
419
  w = self.marker + other.marker
@@ -407,10 +426,10 @@ class Waveform:
407
426
 
408
427
  return self._comb(other, _or)
409
428
 
410
- def __iand__(self, other):
429
+ def __iand__(self, other) -> Waveform:
411
430
  return self & other
412
431
 
413
- def __and__(self, other):
432
+ def __and__(self, other) -> Waveform:
414
433
  if isinstance(other, (int, float, complex)):
415
434
  other = const(other)
416
435
  w = self.marker + other.marker
@@ -429,7 +448,7 @@ class Waveform:
429
448
  return Waveform(w.bounds,
430
449
  tuple(_zero if s == _zero else _one for s in w.seq))
431
450
 
432
- def mask(self, edge=0):
451
+ def mask(self, edge: float = 0) -> Waveform:
433
452
  w = self.marker
434
453
  in_wave = w.seq[0] == _zero
435
454
  bounds = []
@@ -457,31 +476,31 @@ class Waveform:
457
476
  bounds.append(b)
458
477
  return Waveform(tuple(bounds), tuple(seq))
459
478
 
460
- def __mul__(self, other):
479
+ def __mul__(self, other) -> Waveform:
461
480
  if isinstance(other, Waveform):
462
481
  return self._comb(other, mul)
463
482
  else:
464
483
  return self * const(other)
465
484
 
466
- def __rmul__(self, v):
485
+ def __rmul__(self, v) -> Waveform:
467
486
  return const(v) * self
468
487
 
469
- def __truediv__(self, other):
488
+ def __truediv__(self, other) -> Waveform:
470
489
  if isinstance(other, Waveform):
471
490
  raise TypeError('division by waveform')
472
491
  else:
473
492
  return self * const(1 / other)
474
493
 
475
- def __neg__(self):
494
+ def __neg__(self) -> Waveform:
476
495
  return -1 * self
477
496
 
478
- def __sub__(self, other):
497
+ def __sub__(self, other) -> Waveform:
479
498
  return self + (-other)
480
499
 
481
- def __rsub__(self, v):
500
+ def __rsub__(self, v) -> Waveform:
482
501
  return v + (-self)
483
502
 
484
- def __rshift__(self, time):
503
+ def __rshift__(self, time) -> Waveform:
485
504
  return Waveform(
486
505
  tuple(round(bound + time, NDIGITS) for bound in self.bounds),
487
506
  tuple(shift(expr, time) for expr in self.seq))
@@ -502,16 +521,22 @@ class Waveform:
502
521
  for start, stop, part in parts:
503
522
  out[start:stop] += part
504
523
 
505
- def __call__(self,
506
- x,
507
- frag=False,
508
- out=None,
509
- accumulate=False,
510
- function_lib=None):
524
+ def __call__(
525
+ self,
526
+ x,
527
+ frag=False,
528
+ out: np.ndarray | list | None = None,
529
+ accumulate=False,
530
+ function_lib=None
531
+ ) -> NDArray[np.float64 | np.complex128] | list[
532
+ tuple[int, int, NDArray[np.float64 | np.complex128]] | int
533
+ | float | complex] | np.float64:
511
534
  if function_lib is None:
512
535
  function_lib = _baseFunc
513
536
  if isinstance(x, (int, float, complex)):
514
- return self.__call__(np.array([x]), function_lib=function_lib)[0]
537
+ return cast(
538
+ NDArray[np.float64],
539
+ self.__call__(np.array([x]), function_lib=function_lib))[0]
515
540
  parts, dtype = calc_parts(self.bounds, self.seq, x, function_lib,
516
541
  self.min, self.max)
517
542
  if not frag:
@@ -522,8 +547,9 @@ class Waveform:
522
547
  self._fill_parts(parts, out)
523
548
  else:
524
549
  if out is None:
525
- return parts
550
+ return cast(list, parts)
526
551
  else:
552
+ out = cast(list, out)
527
553
  if not accumulate:
528
554
  out.clear()
529
555
  out.extend(parts)
@@ -647,7 +673,8 @@ class WaveVStack(Waveform):
647
673
 
648
674
  def __call__(self, x, frag=False, out=None, function_lib=None):
649
675
  assert frag is False, 'WaveVStack does not support frag mode'
650
- out = np.full_like(x, self.offset, dtype=complex)
676
+ out = np.full_like(x, self.offset, dtype=np.complex128)
677
+ out = cast(NDArray[np.complex128], out)
651
678
  if self.shift != 0:
652
679
  x = x - self.shift
653
680
  if function_lib is None:
@@ -732,7 +759,7 @@ class WaveVStack(Waveform):
732
759
  ret.offset = self.offset
733
760
  return ret
734
761
 
735
- def __add__(self, other):
762
+ def __add__(self, other) -> WaveVStack:
736
763
  ret = WaveVStack()
737
764
  ret.wlist.extend(self.wlist)
738
765
  if isinstance(other, WaveVStack):
@@ -750,10 +777,10 @@ class WaveVStack(Waveform):
750
777
  ret.offset += other
751
778
  return ret
752
779
 
753
- def __radd__(self, v):
780
+ def __radd__(self, v) -> WaveVStack:
754
781
  return self + v
755
782
 
756
- def __mul__(self, other):
783
+ def __mul__(self, other) -> WaveVStack:
757
784
  if isinstance(other, Waveform):
758
785
  other = other.simplify() << self.shift
759
786
  ret = WaveVStack([Waveform(*w) * other for w in self.wlist])
@@ -766,10 +793,10 @@ class WaveVStack(Waveform):
766
793
  ret.offset = self.offset * other
767
794
  return ret
768
795
 
769
- def __rmul__(self, v):
796
+ def __rmul__(self, v) -> WaveVStack:
770
797
  return self * v
771
798
 
772
- def __eq__(self, other):
799
+ def __eq__(self, other) -> bool:
773
800
  if self.wlist:
774
801
  return False
775
802
  else:
@@ -961,6 +988,42 @@ def _format_DRAG(shift, *args):
961
988
  return f"DRAG(...)"
962
989
 
963
990
 
991
+ def _format_MOLLIFIER(shift, *args):
992
+ r = _num_latex(args[0])
993
+ d = _num_latex(args[1])
994
+ shift_str = _num_latex(-shift)
995
+ if shift_str == '0':
996
+ shift_str = ''
997
+ elif shift_str[0] != '-':
998
+ shift_str = '+' + shift_str
999
+
1000
+ if d == '0':
1001
+ return f"\\mathrm{{Mollifier}}\\left(t{shift_str}, r={r}\\right)"
1002
+ elif d == '1':
1003
+ return f"\\mathrm{{Mollifier}}'\\left(t{shift_str}, r={r}\\right)"
1004
+ elif d == '2':
1005
+ return f"\\mathrm{{Mollifier}}''\\left(t{shift_str}, r={r}\\right)"
1006
+ else:
1007
+ return f"\\mathrm{{Mollifier}}^{{({d})}}\\left(t{shift_str}, r={r}\\right)"
1008
+
1009
+
1010
+ def _format_D_GAUSSIAN(shift, *args):
1011
+ sigma = _num_latex(args[0] / np.sqrt(2))
1012
+ d = args[1]
1013
+ shift_str = _num_latex(-shift)
1014
+ if shift_str == '0':
1015
+ shift_str = ''
1016
+ elif shift_str[0] != '-':
1017
+ shift_str = '+' + shift_str
1018
+
1019
+ if d == 0:
1020
+ return f"\\mathrm{{Gaussian}}\\left(t{shift_str}, \\sigma={sigma}\\right)"
1021
+ elif d == 1:
1022
+ return f"\\frac{{\\mathrm{{d}}}}{{\\mathrm{{d}}t}}\\mathrm{{Gaussian}}\\left(t{shift_str}, \\sigma={sigma}\\right)"
1023
+ else:
1024
+ return f"\\frac{{\\mathrm{{d}}^{{{d}}}}}{{\\mathrm{{d}}t^{{{d}}}}}\\mathrm{{Gaussian}}\\left(t{shift_str}, \\sigma={sigma}\\right)"
1025
+
1026
+
964
1027
  registerBaseFuncLatex(LINEAR, _format_LINEAR)
965
1028
  registerBaseFuncLatex(GAUSSIAN, _format_GAUSSIAN)
966
1029
  registerBaseFuncLatex(ERF, _format_ERF)
@@ -970,12 +1033,27 @@ registerBaseFuncLatex(EXP, _format_EXP)
970
1033
  registerBaseFuncLatex(COSH, _format_COSH)
971
1034
  registerBaseFuncLatex(SINH, _format_SINH)
972
1035
  registerBaseFuncLatex(DRAG, _format_DRAG)
1036
+ registerBaseFuncLatex(MOLLIFIER, _format_MOLLIFIER)
1037
+ registerBaseFuncLatex(D_GAUSSIAN, _format_D_GAUSSIAN)
973
1038
 
974
1039
 
975
- def D(wav):
1040
+ def D(wav: Waveform, d: int = 1) -> Waveform:
976
1041
  """derivative
1042
+
1043
+ Parameters
1044
+ ----------
1045
+ wav : Waveform
1046
+ The waveform to take the derivative of.
1047
+ d : int, optional
1048
+ The order of the derivative, by default 1.
977
1049
  """
978
- return Waveform(bounds=wav.bounds, seq=tuple(_D(x) for x in wav.seq))
1050
+ assert d >= 0 and isinstance(d, int), "d must be a non-negative integer"
1051
+ if d == 0:
1052
+ return wav
1053
+ elif d == 1:
1054
+ return Waveform(bounds=wav.bounds, seq=tuple(_D(x) for x in wav.seq))
1055
+ else:
1056
+ return D(D(wav, d - 1), 1)
979
1057
 
980
1058
 
981
1059
  def convolve(a, b):
@@ -1014,7 +1092,7 @@ def step(edge, type='erf'):
1014
1092
  seq=(_zero, rise, _one))
1015
1093
 
1016
1094
 
1017
- def square(width, edge=0, type='erf'):
1095
+ def square(width: float, edge: float = 0, type: str = 'erf') -> Waveform:
1018
1096
  if width <= 0:
1019
1097
  return zero()
1020
1098
  if edge == 0:
@@ -1027,7 +1105,9 @@ def square(width, edge=0, type='erf'):
1027
1105
  (step(edge, type=type) >> width / 2))
1028
1106
 
1029
1107
 
1030
- def gaussian(width, plateau=0.0):
1108
+ def gaussian(width: float,
1109
+ plateau: float = 0.0,
1110
+ d: int | None = None) -> Waveform:
1031
1111
  if width <= 0 and plateau <= 0.0:
1032
1112
  return zero()
1033
1113
  # width is two times FWHM
@@ -1035,26 +1115,27 @@ def gaussian(width, plateau=0.0):
1035
1115
  std_sq2 = width / 3.3302184446307908
1036
1116
  # std is set to give total pulse area same as a square
1037
1117
  # std_sq2 = width/np.sqrt(np.pi)
1118
+ if d is None:
1119
+ base = lambda shift: basic_wave(GAUSSIAN, std_sq2, shift=shift)
1120
+ else:
1121
+ base = lambda shift: basic_wave(D_GAUSSIAN, std_sq2, d, shift=shift)
1122
+
1038
1123
  if round(0.5 * plateau, NDIGITS) <= 0.0:
1039
1124
  return Waveform(bounds=(round(-0.75 * width,
1040
1125
  NDIGITS), round(0.75 * width,
1041
1126
  NDIGITS), +inf),
1042
- seq=(_zero, basic_wave(GAUSSIAN, std_sq2), _zero))
1127
+ seq=(_zero, base(0), _zero))
1043
1128
  else:
1044
1129
  return Waveform(bounds=(round(-0.75 * width - 0.5 * plateau,
1045
1130
  NDIGITS), round(-0.5 * plateau, NDIGITS),
1046
1131
  round(0.5 * plateau, NDIGITS),
1047
1132
  round(0.75 * width + 0.5 * plateau,
1048
1133
  NDIGITS), +inf),
1049
- seq=(_zero,
1050
- basic_wave(GAUSSIAN,
1051
- std_sq2,
1052
- shift=-0.5 * plateau), _one,
1053
- basic_wave(GAUSSIAN, std_sq2,
1054
- shift=0.5 * plateau), _zero))
1134
+ seq=(_zero, base(-0.5 * plateau), _one,
1135
+ base(0.5 * plateau), _zero))
1055
1136
 
1056
1137
 
1057
- def cos(w, phi=0):
1138
+ def cos(w: float, phi: float = 0) -> Waveform:
1058
1139
  if w == 0:
1059
1140
  return const(np.cos(phi))
1060
1141
  if w < 0:
@@ -1063,7 +1144,7 @@ def cos(w, phi=0):
1063
1144
  return Waveform(seq=(basic_wave(COS, w, shift=-phi / w), ))
1064
1145
 
1065
1146
 
1066
- def sin(w, phi=0):
1147
+ def sin(w: float, phi: float = 0) -> Waveform:
1067
1148
  if w == 0:
1068
1149
  return const(np.sin(phi))
1069
1150
  if w < 0:
@@ -1072,7 +1153,7 @@ def sin(w, phi=0):
1072
1153
  return Waveform(seq=(basic_wave(COS, w, shift=(pi / 2 - phi) / w), ))
1073
1154
 
1074
1155
 
1075
- def exp(alpha):
1156
+ def exp(alpha: float | complex) -> Waveform:
1076
1157
  if isinstance(alpha, complex):
1077
1158
  if alpha.real == 0:
1078
1159
  return cos(alpha.imag) + 1j * sin(alpha.imag)
@@ -1082,7 +1163,7 @@ def exp(alpha):
1082
1163
  return Waveform(seq=(basic_wave(EXP, alpha), ))
1083
1164
 
1084
1165
 
1085
- def sinc(bw):
1166
+ def sinc(bw: float) -> Waveform:
1086
1167
  if bw <= 0:
1087
1168
  return zero()
1088
1169
  width = 100 / bw
@@ -1091,7 +1172,7 @@ def sinc(bw):
1091
1172
  seq=(_zero, basic_wave(SINC, bw), _zero))
1092
1173
 
1093
1174
 
1094
- def cosPulse(width, plateau=0.0):
1175
+ def cosPulse(width: float, plateau: float = 0.0) -> Waveform:
1095
1176
  # cos = basic_wave(COS, 2*np.pi/width)
1096
1177
  # pulse = mul(add(cos, _one), _half)
1097
1178
  if round(0.5 * plateau, NDIGITS) > 0:
@@ -1105,19 +1186,21 @@ def cosPulse(width, plateau=0.0):
1105
1186
  seq=(_zero, pulse, _zero))
1106
1187
 
1107
1188
 
1108
- def hanning(width, plateau=0.0):
1189
+ def hanning(width: float, plateau: float = 0.0) -> Waveform:
1109
1190
  return cosPulse(width, plateau=plateau)
1110
1191
 
1111
1192
 
1112
- def cosh(w):
1193
+ def cosh(w: float) -> Waveform:
1113
1194
  return Waveform(seq=(basic_wave(COSH, w), ))
1114
1195
 
1115
1196
 
1116
- def sinh(w):
1197
+ def sinh(w: float) -> Waveform:
1117
1198
  return Waveform(seq=(basic_wave(SINH, w), ))
1118
1199
 
1119
1200
 
1120
- def coshPulse(width, eps=1.0, plateau=0.0):
1201
+ def coshPulse(width: float,
1202
+ eps: float = 1.0,
1203
+ plateau: float = 0.0) -> Waveform:
1121
1204
  """Cosine hyperbolic pulse with the following im
1122
1205
 
1123
1206
  pulse edge shape:
@@ -1167,24 +1250,58 @@ def coshPulse(width, eps=1.0, plateau=0.0):
1167
1250
  seq=(_zero, raising, _one, falling, _zero))
1168
1251
 
1169
1252
 
1170
- def general_cosine(duration, *arg):
1253
+ def general_cosine(duration: float, *arg: float) -> Waveform:
1171
1254
  wav = zero()
1172
- arg = np.asarray(arg)
1173
- arg /= arg[::2].sum()
1174
- for i, a in enumerate(arg, start=1):
1255
+ arg_ = np.asarray(arg)
1256
+ arg_ /= arg_[::2].sum()
1257
+ for i, a in enumerate(arg_, start=1):
1175
1258
  wav += a / 2 * (1 - (-1)**i * cos(i * 2 * pi / duration))
1176
1259
  return wav * square(duration)
1177
1260
 
1178
1261
 
1179
- def slepian(duration, *arg):
1262
+ def slepian(duration: float, *arg: float) -> Waveform:
1180
1263
  wav = zero()
1181
- arg = np.asarray(arg)
1182
- arg /= arg[::2].sum()
1183
- for i, a in enumerate(arg, start=1):
1264
+ arg_ = np.asarray(arg)
1265
+ arg_ /= arg_[::2].sum()
1266
+ for i, a in enumerate(arg_, start=1):
1184
1267
  wav += a / 2 * (1 - (-1)**i * cos(i * 2 * pi / duration))
1185
1268
  return wav * square(duration)
1186
1269
 
1187
1270
 
1271
+ def mollifier(width: float, plateau: float = 0.0, d: int = 0) -> Waveform:
1272
+ """
1273
+ Mollifier function is a smooth function that is 1 at the origin and 0 outside a certain radius.
1274
+ It is defined as:
1275
+
1276
+ f(x) = exp(1 / ((x / r) ^ 2 - 1) + 1) in case |x| < r
1277
+ = 0 in case |x| >= r
1278
+ where r = width / 2 is the radius of the mollifier.
1279
+
1280
+ The parameter plateau is the width of the plateau.
1281
+ The parameter d is the order of the derivative.
1282
+ """
1283
+ assert d >= 0 and isinstance(d, int), "d must be a non-negative integer"
1284
+ assert width > 0, "width must be positive"
1285
+
1286
+ if plateau <= 0:
1287
+ return Waveform(bounds=(-0.5 * width, 0.5 * width, inf),
1288
+ seq=(_zero, basic_wave(MOLLIFIER, width / 2,
1289
+ d), _zero))
1290
+ else:
1291
+ return Waveform(bounds=(-0.5 * width - 0.5 * plateau, -0.5 * plateau,
1292
+ 0.5 * plateau, 0.5 * width + 0.5 * plateau,
1293
+ inf),
1294
+ seq=(_zero,
1295
+ basic_wave(MOLLIFIER,
1296
+ width / 2,
1297
+ d,
1298
+ shift=-0.5 * plateau), _one,
1299
+ basic_wave(MOLLIFIER,
1300
+ width / 2,
1301
+ d,
1302
+ shift=0.5 * plateau), _zero))
1303
+
1304
+
1188
1305
  def _poly(*a):
1189
1306
  """
1190
1307
  a[0] + a[1] * t + a[2] * t**2 + ...
@@ -1212,7 +1329,13 @@ def t():
1212
1329
  return Waveform(seq=((((LINEAR, 0), ), (1, )), (1, )))
1213
1330
 
1214
1331
 
1215
- def drag(freq, width, plateau=0, delta=0, block_freq=None, phase=0, t0=0):
1332
+ def drag(freq: float,
1333
+ width: float,
1334
+ plateau: float = 0,
1335
+ delta: float = 0,
1336
+ block_freq: float | None = None,
1337
+ phase: float = 0,
1338
+ t0: float = 0) -> Waveform:
1216
1339
  phase += pi * delta * (width + plateau)
1217
1340
  if plateau <= 0:
1218
1341
  return Waveform(seq=(_zero,
@@ -1241,7 +1364,11 @@ def drag(freq, width, plateau=0, delta=0, block_freq=None, phase=0, t0=0):
1241
1364
  NDIGITS), +inf))
1242
1365
 
1243
1366
 
1244
- def chirp(f0, f1, T, phi0=0, type='linear'):
1367
+ def chirp(f0: float,
1368
+ f1: float,
1369
+ T: float,
1370
+ phi0: float = 0,
1371
+ type: str = 'linear') -> Waveform:
1245
1372
  """
1246
1373
  A chirp is a signal in which the frequency increases (up-chirp)
1247
1374
  or decreases (down-chirp) with time. In some sources, the term
@@ -1280,7 +1407,7 @@ def chirp(f0, f1, T, phi0=0, type='linear'):
1280
1407
  raise ValueError(f'unknown type {type}')
1281
1408
 
1282
1409
 
1283
- def interp(x, y):
1410
+ def interp(x: NDArray[np.float64], y: NDArray[np.float64]) -> Waveform:
1284
1411
  seq, bounds = [_zero], [x[0]]
1285
1412
  for x1, x2, y1, y2 in zip(x[:-1], x[1:], y[:-1], y[1:]):
1286
1413
  if x2 == x1:
@@ -1298,12 +1425,20 @@ def interp(x, y):
1298
1425
  for b in bounds)).simplify()
1299
1426
 
1300
1427
 
1301
- def cut(wav, start=None, stop=None, head=None, tail=None, min=None, max=None):
1428
+ def cut(wav: Waveform,
1429
+ start: float | None = None,
1430
+ stop: float | None = None,
1431
+ head: float | None = None,
1432
+ tail: float | None = None,
1433
+ min: float | None = None,
1434
+ max: float | None = None) -> Waveform:
1302
1435
  offset = 0
1303
1436
  if start is not None and head is not None:
1304
- offset = head - wav(np.array([1.0 * start]))[0]
1437
+ offset = head - cast(NDArray[np.float64], wav(np.array([1.0 * start
1438
+ ])))[0]
1305
1439
  elif stop is not None and tail is not None:
1306
- offset = tail - wav(np.array([1.0 * stop]))[0]
1440
+ offset = tail - cast(NDArray[np.float64], wav(np.array([1.0 * stop
1441
+ ])))[0]
1307
1442
  wav = wav + offset
1308
1443
 
1309
1444
  if start is not None:
@@ -1334,15 +1469,15 @@ def samplingPoints(start, stop, points):
1334
1469
  tuple(points)), _zero))
1335
1470
 
1336
1471
 
1337
- def mixing(I,
1338
- Q=None,
1472
+ def mixing(I: Waveform,
1473
+ Q: Waveform | None = None,
1339
1474
  *,
1340
- phase=0.0,
1341
- freq=0.0,
1342
- ratioIQ=1.0,
1343
- phaseDiff=0.0,
1344
- block_freq=None,
1345
- DRAGScaling=None):
1475
+ phase: float = 0.0,
1476
+ freq: float = 0.0,
1477
+ ratioIQ: float = 1.0,
1478
+ phaseDiff: float = 0.0,
1479
+ block_freq: float | None = None,
1480
+ DRAGScaling: float | None = None) -> tuple[Waveform, Waveform]:
1346
1481
  """SSB or envelope mixing
1347
1482
  """
1348
1483
  if Q is None:
@@ -1356,8 +1491,8 @@ def mixing(I,
1356
1491
  Qout = -I * sin(w, -phase + phaseDiff) + Q * cos(w, -phase + phaseDiff)
1357
1492
  else:
1358
1493
  # envelope mixing
1359
- Iout = I * np.cos(-phase) + Q * np.sin(-phase)
1360
- Qout = -I * np.sin(-phase) + Q * np.cos(-phase)
1494
+ Iout = cast(Waveform, I * np.cos(-phase) + Q * np.sin(-phase))
1495
+ Qout = cast(Waveform, -I * np.sin(-phase) + Q * np.cos(-phase))
1361
1496
 
1362
1497
  # apply DRAG
1363
1498
  if block_freq is not None and block_freq != freq:
@@ -1380,7 +1515,7 @@ def mixing(I,
1380
1515
  __all__ = [
1381
1516
  'D', 'Waveform', 'chirp', 'const', 'cos', 'cosh', 'coshPulse', 'cosPulse',
1382
1517
  'cut', 'drag', 'exp', 'function', 'gaussian', 'general_cosine', 'hanning',
1383
- 'interp', 'mixing', 'one', 'poly', 'registerBaseFunc',
1518
+ 'interp', 'mixing', 'mollifier', 'one', 'poly', 'registerBaseFunc',
1384
1519
  'registerDerivative', 'samplingPoints', 'sign', 'sin', 'sinc', 'sinh',
1385
1520
  'square', 'step', 't', 'zero'
1386
1521
  ]
@@ -4,7 +4,7 @@ from ast import literal_eval
4
4
  from functools import lru_cache
5
5
  from pathlib import Path
6
6
 
7
- from antlr4 import *
7
+ from antlr4 import CommonTokenStream, InputStream
8
8
  from antlr4.error.ErrorListener import ErrorListener
9
9
 
10
10
  from . import multy_drag, waveform
@@ -30,9 +30,9 @@ class WaveformVisitor:
30
30
  self.functions = [
31
31
  'D', 'chirp', 'const', 'cos', 'cosh', 'coshPulse', 'cosPulse',
32
32
  'cut', 'drag', 'drag_sin', 'drag_sinx', 'exp', 'gaussian',
33
- 'general_cosine', 'hanning', 'interp', 'mixing', 'one', 'poly',
34
- 'samplingPoints', 'sign', 'sin', 'sinc', 'sinh', 'square', 'step',
35
- 't', 'zero'
33
+ 'general_cosine', 'hanning', 'interp', 'mixing', 'mollifier',
34
+ 'one', 'poly', 'samplingPoints', 'sign', 'sin', 'sinc', 'sinh',
35
+ 'square', 'step', 't', 'zero'
36
36
  ]
37
37
  self.constants = {
38
38
  'pi': waveform.pi,
@@ -226,14 +226,13 @@ def _generate_antlr_parser():
226
226
 
227
227
  # Generate ANTLR files
228
228
  try:
229
- result = subprocess.run([
230
- "antlr4", "-Dlanguage=Python3",
231
- str(grammar_file)
232
- ],
233
- cwd=str(current_dir),
234
- capture_output=True,
235
- text=True,
236
- check=True)
229
+ result = subprocess.run(
230
+ ["antlr4", "-Dlanguage=Python3",
231
+ str(grammar_file)],
232
+ cwd=str(current_dir),
233
+ capture_output=True,
234
+ text=True,
235
+ check=True)
237
236
  except (subprocess.CalledProcessError, FileNotFoundError) as e:
238
237
  # Fall back to java command if antlr4 command is not available
239
238
  try:
@@ -258,7 +257,7 @@ def parse_waveform_expression(expr: str) -> waveform.Waveform:
258
257
  try:
259
258
  # Generate parser files if they don't exist
260
259
  # _generate_antlr_parser()
261
-
260
+
262
261
  # Import generated ANTLR classes
263
262
  from .WaveformLexer import WaveformLexer
264
263
  from .WaveformParser import WaveformParser
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: waveforms
3
- Version: 2.1.1
3
+ Version: 2.2.1
4
4
  Summary: Edit waveforms used in experiment
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes