waveforms 3.5.0__tar.gz → 3.5.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.
- {waveforms-3.5.0/waveforms.egg-info → waveforms-3.5.1}/PKG-INFO +34 -2
- {waveforms-3.5.0 → waveforms-3.5.1}/README.md +33 -1
- waveforms-3.5.1/tests/test_native_sos.py +176 -0
- waveforms-3.5.1/tests/test_output_limits.py +252 -0
- waveforms-3.5.1/waveforms/WaveformLexer.py +134 -0
- waveforms-3.5.1/waveforms/WaveformListener.py +228 -0
- waveforms-3.5.1/waveforms/WaveformParser.py +1241 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/_cwaveform.c +181 -18
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/_cwaveform.h +18 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/_cwaveform.md +38 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/_waveform.pyi +8 -1
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/_waveform.pyx +107 -2
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/version.py +1 -1
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/waveform.py +172 -55
- {waveforms-3.5.0 → waveforms-3.5.1/waveforms.egg-info}/PKG-INFO +34 -2
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms.egg-info/SOURCES.txt +5 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/LICENSE +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/MANIFEST.in +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/pyproject.toml +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/setup.cfg +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/setup.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/tests/test_core.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/tests/test_nonlinear.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/tests/test_waveform.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/tests/test_wavevstack.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/Waveform.g4 +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/__init__.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/__main__.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/distortion.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/nonlinear.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/utils.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms/waveform_parser.py +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms.egg-info/dependency_links.txt +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms.egg-info/entry_points.txt +0 -0
- {waveforms-3.5.0 → waveforms-3.5.1}/waveforms.egg-info/requires.txt +0 -0
- {waveforms-3.5.0 → waveforms-3.5.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: 3.5.
|
|
3
|
+
Version: 3.5.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>
|
|
@@ -180,12 +180,44 @@ flux_samples = trajectory.sample(dtype=np.int16)
|
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
The sampling order is waveform accumulation, nonlinear mapping, optional SOS
|
|
183
|
-
filtering/predistortion,
|
|
183
|
+
filtering/predistortion, output amplitude limits (`min`/`max`), and finally
|
|
184
|
+
integer quantization or floating-point output. This is important for
|
|
184
185
|
`WaveVStack`: the map is applied to the accumulated trajectory rather than to
|
|
185
186
|
each pulse event independently. `method="linear"` selects the smaller and
|
|
186
187
|
fastest two-point interpolation path. Maps serialize independently through
|
|
187
188
|
`to_bytes()`/`from_bytes()` using the language-neutral `NLM1` format.
|
|
188
189
|
|
|
190
|
+
Every waveform and stack has output limits, defaulting to `min=-np.inf` and
|
|
191
|
+
`max=np.inf`. A stack ignores its child waveforms' limits and uses only its own:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
stack.min = -0.2
|
|
195
|
+
stack.max = 0.3
|
|
196
|
+
samples = stack.sample() # limit after the complete calibration/filter chain
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Limits apply to whole and chunked sampling, including `out=` buffers and
|
|
200
|
+
integer output. Complex signals limit I and Q independently; `sample_iq()`
|
|
201
|
+
uses the same final limits. The filter state continues from the unclipped
|
|
202
|
+
filtered signal across chunks. DAC `full_scale` controls integer conversion
|
|
203
|
+
and saturation separately from these amplitude limits.
|
|
204
|
+
|
|
205
|
+
Real-coefficient SOS filters (`filters=(sos, initial)`) run in the C core for
|
|
206
|
+
float64 and complex128 signals. This stage subtracts the baseline `initial`,
|
|
207
|
+
applies the cascade, restores the baseline, and applies the final limits.
|
|
208
|
+
Real int16/int32 output is quantized in the same stage, without allocating a
|
|
209
|
+
full filtered floating-point buffer. Float output can reuse the sampled
|
|
210
|
+
buffer. A small fixed scratch buffer keeps filtering and conversion local;
|
|
211
|
+
waveform evaluation and nonlinear mapping still precede this stage. Complex
|
|
212
|
+
coefficients and extended precision retain the SciPy implementation.
|
|
213
|
+
`sample_iq()` still converts the filtered complex result into separate I/Q
|
|
214
|
+
output arrays. See [the SOS benchmark](benchmarks/sos_filter.md).
|
|
215
|
+
|
|
216
|
+
Calling `waveform(t)` directly evaluates with amplitude limits but without
|
|
217
|
+
nonlinear calibration or filtering. Sampling evaluates the underlying signal
|
|
218
|
+
without limits before applying its processing chain. Limits are sampling
|
|
219
|
+
metadata preserved by pickle, not part of the raw WNF4/WNS4 binary blocks.
|
|
220
|
+
|
|
189
221
|
## Reporting Issues
|
|
190
222
|
Please report all issues [on github](https://github.com/feihoo87/waveforms/issues).
|
|
191
223
|
|
|
@@ -136,12 +136,44 @@ flux_samples = trajectory.sample(dtype=np.int16)
|
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
The sampling order is waveform accumulation, nonlinear mapping, optional SOS
|
|
139
|
-
filtering/predistortion,
|
|
139
|
+
filtering/predistortion, output amplitude limits (`min`/`max`), and finally
|
|
140
|
+
integer quantization or floating-point output. This is important for
|
|
140
141
|
`WaveVStack`: the map is applied to the accumulated trajectory rather than to
|
|
141
142
|
each pulse event independently. `method="linear"` selects the smaller and
|
|
142
143
|
fastest two-point interpolation path. Maps serialize independently through
|
|
143
144
|
`to_bytes()`/`from_bytes()` using the language-neutral `NLM1` format.
|
|
144
145
|
|
|
146
|
+
Every waveform and stack has output limits, defaulting to `min=-np.inf` and
|
|
147
|
+
`max=np.inf`. A stack ignores its child waveforms' limits and uses only its own:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
stack.min = -0.2
|
|
151
|
+
stack.max = 0.3
|
|
152
|
+
samples = stack.sample() # limit after the complete calibration/filter chain
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Limits apply to whole and chunked sampling, including `out=` buffers and
|
|
156
|
+
integer output. Complex signals limit I and Q independently; `sample_iq()`
|
|
157
|
+
uses the same final limits. The filter state continues from the unclipped
|
|
158
|
+
filtered signal across chunks. DAC `full_scale` controls integer conversion
|
|
159
|
+
and saturation separately from these amplitude limits.
|
|
160
|
+
|
|
161
|
+
Real-coefficient SOS filters (`filters=(sos, initial)`) run in the C core for
|
|
162
|
+
float64 and complex128 signals. This stage subtracts the baseline `initial`,
|
|
163
|
+
applies the cascade, restores the baseline, and applies the final limits.
|
|
164
|
+
Real int16/int32 output is quantized in the same stage, without allocating a
|
|
165
|
+
full filtered floating-point buffer. Float output can reuse the sampled
|
|
166
|
+
buffer. A small fixed scratch buffer keeps filtering and conversion local;
|
|
167
|
+
waveform evaluation and nonlinear mapping still precede this stage. Complex
|
|
168
|
+
coefficients and extended precision retain the SciPy implementation.
|
|
169
|
+
`sample_iq()` still converts the filtered complex result into separate I/Q
|
|
170
|
+
output arrays. See [the SOS benchmark](benchmarks/sos_filter.md).
|
|
171
|
+
|
|
172
|
+
Calling `waveform(t)` directly evaluates with amplitude limits but without
|
|
173
|
+
nonlinear calibration or filtering. Sampling evaluates the underlying signal
|
|
174
|
+
without limits before applying its processing chain. Limits are sampling
|
|
175
|
+
metadata preserved by pickle, not part of the raw WNF4/WNS4 binary blocks.
|
|
176
|
+
|
|
145
177
|
## Reporting Issues
|
|
146
178
|
Please report all issues [on github](https://github.com/feihoo87/waveforms/issues).
|
|
147
179
|
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Native SOS processing agrees with SciPy and keeps output limits out of state."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
5
|
+
from scipy.signal import butter, sosfilt
|
|
6
|
+
|
|
7
|
+
import waveforms as wf
|
|
8
|
+
from waveforms._waveform import quantize_samples, sosfilt_samples
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _clip(values, lower, upper):
|
|
12
|
+
if np.iscomplexobj(values):
|
|
13
|
+
return (np.clip(values.real, lower, upper)
|
|
14
|
+
+ 1j * np.clip(values.imag, lower, upper))
|
|
15
|
+
return np.clip(values, lower, upper)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.parametrize("sections", [1, 2, 4, 8, 16])
|
|
19
|
+
@pytest.mark.parametrize("complex_signal", [False, True])
|
|
20
|
+
def test_scipy_equivalence_and_streaming(sections, complex_signal):
|
|
21
|
+
rng = np.random.default_rng(832)
|
|
22
|
+
sos = butter(2 * sections, .2, output="sos")
|
|
23
|
+
values = rng.normal(size=1031)
|
|
24
|
+
zi = rng.normal(size=(sections, 2)) * .001
|
|
25
|
+
initial = .07
|
|
26
|
+
if complex_signal:
|
|
27
|
+
values = values + 1j * rng.normal(size=len(values))
|
|
28
|
+
zi = zi + 1j * rng.normal(size=zi.shape) * .001
|
|
29
|
+
initial += .04j
|
|
30
|
+
original = values.copy()
|
|
31
|
+
initial_state = zi.copy()
|
|
32
|
+
filtered, expected_state = sosfilt(sos, values - initial, zi=zi)
|
|
33
|
+
expected = _clip(filtered + initial, -.17, .23)
|
|
34
|
+
result, state = sosfilt_samples(values, sos, initial, zi,
|
|
35
|
+
lower=-.17, upper=.23)
|
|
36
|
+
np.testing.assert_allclose(result, expected, rtol=3e-13, atol=3e-14)
|
|
37
|
+
np.testing.assert_allclose(state, expected_state, rtol=3e-13, atol=3e-14)
|
|
38
|
+
np.testing.assert_array_equal(zi, initial_state)
|
|
39
|
+
np.testing.assert_array_equal(values, original)
|
|
40
|
+
|
|
41
|
+
# Boundaries straddle the internal block size and include a one-sample chunk.
|
|
42
|
+
output = np.empty_like(values)
|
|
43
|
+
state = zi
|
|
44
|
+
start = 0
|
|
45
|
+
for stop in (1, 254, 511, 512, 1024, len(values)):
|
|
46
|
+
part, state = sosfilt_samples(values[start:stop], sos, initial, state,
|
|
47
|
+
lower=-.17, upper=.23,
|
|
48
|
+
out=output[start:stop])
|
|
49
|
+
assert np.shares_memory(part, output)
|
|
50
|
+
start = stop
|
|
51
|
+
np.testing.assert_array_equal(output, result)
|
|
52
|
+
np.testing.assert_allclose(state, expected_state, rtol=3e-13, atol=3e-14)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.mark.parametrize("bits", [16, 32])
|
|
56
|
+
@pytest.mark.parametrize("sections", [1, 4, 8])
|
|
57
|
+
def test_direct_quantization_matches_scipy(bits, sections):
|
|
58
|
+
rng = np.random.default_rng(337)
|
|
59
|
+
values = rng.uniform(-2, 2, 5003)
|
|
60
|
+
sos = butter(sections * 2, .25, output="sos")
|
|
61
|
+
expected = quantize_samples(
|
|
62
|
+
np.clip(sosfilt(sos, values - .1) + .1, -.25, .35), bits, .7)
|
|
63
|
+
output = np.empty_like(expected)
|
|
64
|
+
result, _ = sosfilt_samples(values, sos, .1, bits=bits, full_scale=.7,
|
|
65
|
+
lower=-.25, upper=.35, out=output)
|
|
66
|
+
assert result is output
|
|
67
|
+
np.testing.assert_array_equal(result, expected)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@pytest.mark.parametrize("complex_signal", [False, True])
|
|
71
|
+
@pytest.mark.parametrize("overlap", [False, True])
|
|
72
|
+
def test_aliasing_and_readonly_inputs(complex_signal, overlap):
|
|
73
|
+
rng = np.random.default_rng(4)
|
|
74
|
+
storage = rng.normal(size=601)
|
|
75
|
+
if complex_signal:
|
|
76
|
+
storage = storage + 1j * rng.normal(size=len(storage))
|
|
77
|
+
values = storage[:-1]
|
|
78
|
+
output = storage[1:] if overlap else values
|
|
79
|
+
sos = butter(6, .3, output="sos")
|
|
80
|
+
sos.flags.writeable = False
|
|
81
|
+
# SciPy 1.13 requires a writable coefficient buffer.
|
|
82
|
+
expected = sosfilt(sos.copy(), values.copy())
|
|
83
|
+
result, _ = sosfilt_samples(values, sos, out=output)
|
|
84
|
+
assert result is output
|
|
85
|
+
np.testing.assert_allclose(result, expected, rtol=3e-13, atol=3e-14)
|
|
86
|
+
values.flags.writeable = False
|
|
87
|
+
expected = sosfilt(sos.copy(), values.copy())
|
|
88
|
+
result, _ = sosfilt_samples(values, sos)
|
|
89
|
+
np.testing.assert_allclose(result, expected, rtol=3e-13, atol=3e-14)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_coefficients_may_overlap_output():
|
|
93
|
+
sos = butter(8, .3, output="sos")
|
|
94
|
+
values = np.linspace(-1, 1, sos.size)
|
|
95
|
+
expected = sosfilt(sos.copy(), values)
|
|
96
|
+
result, _ = sosfilt_samples(values, sos, out=sos.reshape(-1))
|
|
97
|
+
np.testing.assert_allclose(result, expected, rtol=3e-13, atol=3e-14)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@pytest.mark.parametrize("dtype", [np.float64, np.complex128])
|
|
101
|
+
def test_empty_input_preserves_state(dtype):
|
|
102
|
+
sos = butter(4, .3, output="sos")
|
|
103
|
+
zi = np.ones((2, 2), dtype=dtype)
|
|
104
|
+
result, state = sosfilt_samples(np.empty(0, dtype=dtype), sos, zi=zi)
|
|
105
|
+
assert result.shape == (0,)
|
|
106
|
+
assert result.dtype == dtype
|
|
107
|
+
np.testing.assert_array_equal(state, zi)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@pytest.mark.parametrize("sos", [np.ones((2, 5)), np.ones((1, 2, 6)),
|
|
111
|
+
[[1, 0, 0, 2, 0, 0]]])
|
|
112
|
+
def test_invalid_coefficients(sos):
|
|
113
|
+
with pytest.raises(ValueError, match="sos"):
|
|
114
|
+
sosfilt_samples(np.ones(3), sos)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_invalid_state_and_output():
|
|
118
|
+
sos = butter(4, .3, output="sos")
|
|
119
|
+
values = np.ones(10)
|
|
120
|
+
with pytest.raises(ValueError, match="zi"):
|
|
121
|
+
sosfilt_samples(values, sos, zi=np.zeros((1, 2)))
|
|
122
|
+
with pytest.raises(ValueError, match="shape"):
|
|
123
|
+
sosfilt_samples(values, sos, out=np.empty(9))
|
|
124
|
+
with pytest.raises(TypeError, match="dtype"):
|
|
125
|
+
sosfilt_samples(values, sos, bits=16, out=np.empty(10))
|
|
126
|
+
with pytest.raises(ValueError, match="contiguous"):
|
|
127
|
+
sosfilt_samples(values, sos, bits=16, out=np.empty(20, dtype=np.int16)[::2])
|
|
128
|
+
with pytest.raises(TypeError, match="real signal"):
|
|
129
|
+
sosfilt_samples(values + 1j, sos, bits=16)
|
|
130
|
+
with pytest.raises(ValueError, match="full_scale"):
|
|
131
|
+
sosfilt_samples(values, sos, bits=16, full_scale=0)
|
|
132
|
+
with pytest.raises(ValueError, match="min and max"):
|
|
133
|
+
sosfilt_samples(values, sos, lower=np.nan)
|
|
134
|
+
with pytest.raises(ValueError, match="non-finite"):
|
|
135
|
+
sosfilt_samples(np.array([np.nan]), sos, bits=16)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _wave():
|
|
139
|
+
wave = .4 + .5 * wf.cos(6 * np.pi)
|
|
140
|
+
wave.start, wave.stop, wave.sample_rate = 0., 1., 1024
|
|
141
|
+
wave.min, wave.max = -.15, .27
|
|
142
|
+
return wave
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@pytest.mark.parametrize("coefficient_dtype", [np.complex128, np.longdouble])
|
|
146
|
+
def test_scipy_fallback(coefficient_dtype):
|
|
147
|
+
wave = _wave()
|
|
148
|
+
sos = butter(4, .3, output="sos").astype(coefficient_dtype)
|
|
149
|
+
if coefficient_dtype == np.complex128:
|
|
150
|
+
sos[0, 0] += .1j
|
|
151
|
+
wave.filters = sos, .03
|
|
152
|
+
raw = .4 + .5 * np.cos(6 * np.pi * np.arange(1024) / 1024)
|
|
153
|
+
expected = _clip(sosfilt(sos, raw - .03) + .03, wave.min, wave.max)
|
|
154
|
+
np.testing.assert_allclose(wave.sample(), expected, rtol=3e-13, atol=3e-14)
|
|
155
|
+
np.testing.assert_allclose(np.concatenate(list(wave.sample(chunk_size=73))),
|
|
156
|
+
expected, rtol=3e-13, atol=3e-14)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_pipeline_output_casting_and_single_section_vector():
|
|
160
|
+
wave = _wave()
|
|
161
|
+
wave.filters = butter(2, .3, output="sos")[0], .03
|
|
162
|
+
expected = wave.sample()
|
|
163
|
+
for dtype in (None, np.float32, np.float64):
|
|
164
|
+
for stride in (1, 2):
|
|
165
|
+
output = np.empty(1024 * stride)[::stride]
|
|
166
|
+
result = wave.sample(dtype=dtype, out=output)
|
|
167
|
+
assert result is output
|
|
168
|
+
np.testing.assert_array_equal(result, expected.astype(dtype or np.float64))
|
|
169
|
+
expected_i16 = quantize_samples(expected, 16)
|
|
170
|
+
np.testing.assert_array_equal(wave.sample(dtype=np.int16), expected_i16)
|
|
171
|
+
np.testing.assert_allclose(np.concatenate(list(wave.sample(chunk_size=31))),
|
|
172
|
+
expected, rtol=3e-13, atol=3e-14)
|
|
173
|
+
with pytest.raises(TypeError, match="dtype"):
|
|
174
|
+
wave.sample(dtype=np.int16, out=np.empty(1024))
|
|
175
|
+
with pytest.raises(ValueError, match="contiguous"):
|
|
176
|
+
wave.sample(out=np.empty(2048, dtype=np.int16)[::2])
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Output limits belong after calibration/filtering, before DAC conversion."""
|
|
2
|
+
|
|
3
|
+
import pickle
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pytest
|
|
7
|
+
from scipy.signal import sosfilt
|
|
8
|
+
|
|
9
|
+
import waveforms as wf
|
|
10
|
+
from waveforms._waveform import quantize_samples
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _configure(wave, rate=128):
|
|
14
|
+
wave.start = 0.0
|
|
15
|
+
wave.stop = 1.0
|
|
16
|
+
wave.sample_rate = rate
|
|
17
|
+
return wave
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _signal(kind):
|
|
21
|
+
real = 0.45 + 0.35 * wf.cos(6 * np.pi)
|
|
22
|
+
imag = -0.3 + 0.2 * wf.sin(4 * np.pi)
|
|
23
|
+
if kind == "real":
|
|
24
|
+
return real
|
|
25
|
+
if kind == "complex":
|
|
26
|
+
# Component limits must not truncate a later calibration/filter input.
|
|
27
|
+
real.min, real.max = -0.01, 0.01
|
|
28
|
+
imag.min, imag.max = -0.01, 0.01
|
|
29
|
+
return wf.ComplexWaveform(real, imag)
|
|
30
|
+
real_children = [0.6 * real, 0.4 * real]
|
|
31
|
+
imag_children = [0.3 * imag, 0.7 * imag]
|
|
32
|
+
for child in real_children + imag_children:
|
|
33
|
+
child.min, child.max = -0.01, 0.01
|
|
34
|
+
real_stack = wf.WaveVStack(real_children)
|
|
35
|
+
if kind == "stack":
|
|
36
|
+
return real_stack
|
|
37
|
+
imag_stack = wf.WaveVStack(imag_children)
|
|
38
|
+
real_stack.min, real_stack.max = -0.02, 0.02
|
|
39
|
+
imag_stack.min, imag_stack.max = -0.02, 0.02
|
|
40
|
+
return wf.ComplexWaveVStack(real_stack, imag_stack)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _clip(values, lower, upper):
|
|
44
|
+
if np.iscomplexobj(values):
|
|
45
|
+
return (np.clip(values.real, lower, upper)
|
|
46
|
+
+ 1j * np.clip(values.imag, lower, upper))
|
|
47
|
+
return np.clip(values, lower, upper)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@pytest.mark.parametrize("kind", ["real", "stack", "complex", "complex_stack"])
|
|
51
|
+
@pytest.mark.parametrize("rate", [128, 127.5])
|
|
52
|
+
@pytest.mark.parametrize("gain", [0.25, 2.0])
|
|
53
|
+
def test_output_limits_follow_mapping_and_filter_with_chunk_state(kind, rate, gain):
|
|
54
|
+
wave = _configure(_signal(kind), rate)
|
|
55
|
+
wave.min, wave.max = -0.22, 0.27
|
|
56
|
+
# Stateful filter exercises overshoot and continuing with the unclipped zf.
|
|
57
|
+
sos = np.array([[gain * 0.5, 0., 0., 1., -0.5, 0.]])
|
|
58
|
+
initial = 0.03
|
|
59
|
+
wave.filters = (sos, initial)
|
|
60
|
+
mapping = wf.NonlinearMap.from_samples(
|
|
61
|
+
[-3., 3.], [-6., 6.], method="linear", table_size=2)
|
|
62
|
+
wave.nonlinear = (mapping, mapping) if "complex" in kind else mapping
|
|
63
|
+
|
|
64
|
+
positions = np.arange(0., 1., 1 / rate)
|
|
65
|
+
raw = 0.45 + 0.35 * np.cos(6 * np.pi * positions)
|
|
66
|
+
if "complex" in kind:
|
|
67
|
+
raw = raw + 1j * (-0.3 + 0.2 * np.sin(4 * np.pi * positions))
|
|
68
|
+
filtered = sosfilt(sos, 2 * raw - initial) + initial
|
|
69
|
+
expected = _clip(filtered, wave.min, wave.max)
|
|
70
|
+
|
|
71
|
+
np.testing.assert_allclose(wave.sample(), expected, rtol=2e-13, atol=2e-14)
|
|
72
|
+
chunks = list(wave.sample(chunk_size=13))
|
|
73
|
+
np.testing.assert_allclose(np.concatenate(chunks), expected,
|
|
74
|
+
rtol=2e-13, atol=2e-14)
|
|
75
|
+
target = np.empty_like(expected)
|
|
76
|
+
assert wave.sample(out=target) is target
|
|
77
|
+
np.testing.assert_allclose(target, expected, rtol=2e-13, atol=2e-14)
|
|
78
|
+
restored = pickle.loads(pickle.dumps(wave))
|
|
79
|
+
np.testing.assert_array_equal(restored.sample(), wave.sample())
|
|
80
|
+
|
|
81
|
+
if "complex" in kind:
|
|
82
|
+
for dtype, bits in ((np.int16, 16), (np.int32, 32)):
|
|
83
|
+
targets = tuple(np.empty(len(expected), dtype=dtype) for _ in range(2))
|
|
84
|
+
actual = wave.sample_iq(dtype=dtype, full_scale=0.7, out=targets)
|
|
85
|
+
for result, output, component in zip(actual, targets,
|
|
86
|
+
(expected.real, expected.imag)):
|
|
87
|
+
assert result is output
|
|
88
|
+
np.testing.assert_array_equal(
|
|
89
|
+
result, quantize_samples(component, bits, 0.7))
|
|
90
|
+
iq_chunks = list(wave.sample_iq(
|
|
91
|
+
dtype=dtype, full_scale=0.7, chunk_size=13, out=targets))
|
|
92
|
+
for index, component in enumerate((expected.real, expected.imag)):
|
|
93
|
+
np.testing.assert_array_equal(
|
|
94
|
+
np.concatenate([chunk[index] for chunk in iq_chunks]),
|
|
95
|
+
quantize_samples(component, bits, 0.7))
|
|
96
|
+
else:
|
|
97
|
+
for dtype, bits in ((np.int16, 16), (np.int32, 32)):
|
|
98
|
+
expected_integer = quantize_samples(expected, bits, 0.7)
|
|
99
|
+
target = np.empty(len(expected), dtype=dtype)
|
|
100
|
+
assert wave.sample(out=target, full_scale=0.7) is target
|
|
101
|
+
np.testing.assert_array_equal(target, expected_integer)
|
|
102
|
+
chunks = wave.sample(out=target, chunk_size=13, full_scale=0.7)
|
|
103
|
+
np.testing.assert_array_equal(np.concatenate(list(chunks)), expected_integer)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@pytest.mark.parametrize("gain,expected", [(2., .2), (.25, .1)])
|
|
107
|
+
def test_filter_gain_never_sees_prematurely_limited_input(gain, expected):
|
|
108
|
+
wave = _configure(wf.const(.4))
|
|
109
|
+
wave.min, wave.max = -.2, .2
|
|
110
|
+
wave.filters = (np.array([[gain, 0., 0., 1., 0., 0.]]), 0.)
|
|
111
|
+
np.testing.assert_allclose(wave.sample(), expected)
|
|
112
|
+
np.testing.assert_allclose(np.concatenate(list(wave.sample(chunk_size=7))), expected)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@pytest.mark.parametrize("kind", ["real", "stack", "complex", "complex_stack"])
|
|
116
|
+
def test_limits_cannot_hide_nonlinear_domain_errors(kind):
|
|
117
|
+
wave = _configure(_signal(kind))
|
|
118
|
+
wave.min, wave.max = -.1, .1
|
|
119
|
+
mapping = wf.NonlinearMap.from_samples([-.2, .2], [-.2, .2], method="linear")
|
|
120
|
+
wave.nonlinear = (mapping, mapping) if "complex" in kind else mapping
|
|
121
|
+
with pytest.raises(ValueError, match="outside its domain"):
|
|
122
|
+
wave.sample()
|
|
123
|
+
with pytest.raises(ValueError, match="outside its domain"):
|
|
124
|
+
list(wave.sample(chunk_size=7))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@pytest.mark.parametrize("rate", [2_400_000_000, 7_000_000_000])
|
|
128
|
+
@pytest.mark.parametrize("spacing", [2e-9, 40e-9])
|
|
129
|
+
@pytest.mark.parametrize("many_scales", [False, True])
|
|
130
|
+
@pytest.mark.parametrize("limits", [(-.18, .26), (.08, .26), (-.3, -.1)])
|
|
131
|
+
def test_stack_native_limits_after_overlap_and_before_quantization(
|
|
132
|
+
rate, spacing, many_scales, limits):
|
|
133
|
+
pulse = wf.gaussian(20e-9)
|
|
134
|
+
pulse.min, pulse.max = -.001, .001
|
|
135
|
+
scales = np.linspace(-.9, .9, 80) if many_scales else np.resize([-.6, .4, .8], 80)
|
|
136
|
+
stack = wf.WaveVStack.from_events(
|
|
137
|
+
[pulse], np.zeros(80, dtype=np.uint32),
|
|
138
|
+
np.arange(80, dtype=np.int64) * wf.time_to_tick(spacing), scales)
|
|
139
|
+
stack.offset = .03
|
|
140
|
+
stack.start, stack.stop = -30e-9, 80 * spacing + 30e-9
|
|
141
|
+
stack.sample_rate = rate
|
|
142
|
+
raw = stack.sample()
|
|
143
|
+
plan = stack._sample_plan_cache[1]
|
|
144
|
+
stack.min, stack.max = limits
|
|
145
|
+
expected = np.clip(raw, *limits)
|
|
146
|
+
np.testing.assert_array_equal(stack.sample(), expected)
|
|
147
|
+
# Limits are execution parameters: changing them must not rebuild the plan.
|
|
148
|
+
assert stack._sample_plan_cache[1] is plan
|
|
149
|
+
np.testing.assert_allclose(np.concatenate(list(stack.sample(chunk_size=137))),
|
|
150
|
+
expected, rtol=2e-13, atol=2e-14)
|
|
151
|
+
for dtype, bits in ((np.int16, 16), (np.int32, 32)):
|
|
152
|
+
expected_integer = quantize_samples(expected, bits, .7)
|
|
153
|
+
out = np.empty(len(raw), dtype=dtype)
|
|
154
|
+
assert stack.sample(dtype=dtype, out=out, full_scale=.7) is out
|
|
155
|
+
np.testing.assert_array_equal(out, expected_integer)
|
|
156
|
+
stack.min, stack.max = -np.inf, np.inf
|
|
157
|
+
np.testing.assert_array_equal(stack.sample(), raw)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@pytest.mark.parametrize("kind", ["stack", "complex_stack"])
|
|
161
|
+
def test_stack_owns_limits_and_preserves_them_in_pickle_and_shift(kind):
|
|
162
|
+
stack = _configure(_signal(kind))
|
|
163
|
+
assert stack.min == -np.inf and stack.max == np.inf
|
|
164
|
+
raw = stack.sample()
|
|
165
|
+
stack.min, stack.max = -.17, .23
|
|
166
|
+
expected = _clip(raw, stack.min, stack.max)
|
|
167
|
+
np.testing.assert_array_equal(stack.sample(), expected)
|
|
168
|
+
shifted = stack >> 0.0
|
|
169
|
+
assert (shifted.min, shifted.max) == (-.17, .23)
|
|
170
|
+
np.testing.assert_array_equal(shifted.sample(), expected)
|
|
171
|
+
restored = pickle.loads(pickle.dumps(stack))
|
|
172
|
+
assert (restored.min, restored.max) == (-.17, .23)
|
|
173
|
+
np.testing.assert_array_equal(restored.sample(), expected)
|
|
174
|
+
# Legacy states omit limits, and the oldest also omit the nonlinear map.
|
|
175
|
+
state = stack.__getstate__()[:-2]
|
|
176
|
+
for legacy in (state, state[:-2] + state[-1:]):
|
|
177
|
+
restored = type(stack).__new__(type(stack))
|
|
178
|
+
restored.__setstate__(legacy)
|
|
179
|
+
assert restored.min == -np.inf and restored.max == np.inf
|
|
180
|
+
np.testing.assert_array_equal(restored.sample(), raw)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@pytest.mark.parametrize("kind", ["stack", "complex_stack"])
|
|
184
|
+
def test_stack_direct_evaluation_limits_only_its_own_contribution(kind):
|
|
185
|
+
stack = _signal(kind)
|
|
186
|
+
positions = np.array([.013, .129, .44])
|
|
187
|
+
raw = stack(positions)
|
|
188
|
+
stack.min, stack.max = -.17, .23
|
|
189
|
+
expected = _clip(raw, stack.min, stack.max)
|
|
190
|
+
output = np.full_like(raw, 3)
|
|
191
|
+
assert stack(positions, out=output, accumulate=True) is output
|
|
192
|
+
np.testing.assert_allclose(output, 3 + expected)
|
|
193
|
+
np.testing.assert_allclose(stack(float(positions[0])), expected[0])
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def test_empty_stack_limits_apply_to_idle_and_float_output_buffers():
|
|
197
|
+
stack = _configure(wf.WaveVStack())
|
|
198
|
+
stack.min, stack.max = .13, .27
|
|
199
|
+
for dtype in (np.float32, np.float64, np.int16, np.int32):
|
|
200
|
+
target = np.empty(128, dtype=dtype)
|
|
201
|
+
result = stack.sample(dtype=dtype, out=target)
|
|
202
|
+
assert result is target
|
|
203
|
+
if np.issubdtype(dtype, np.integer):
|
|
204
|
+
expected = quantize_samples(np.full(128, .13), np.iinfo(dtype).bits)
|
|
205
|
+
else:
|
|
206
|
+
expected = np.full(128, .13, dtype=dtype)
|
|
207
|
+
np.testing.assert_array_equal(result, expected)
|
|
208
|
+
stack.stop = stack.start
|
|
209
|
+
assert stack.sample(dtype=np.int16).size == 0
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@pytest.mark.parametrize("kind", ["real", "stack", "complex", "complex_stack"])
|
|
213
|
+
@pytest.mark.parametrize("bounds", [
|
|
214
|
+
(1., -1.), (np.nan, 1.), (-1., np.nan), (np.inf, np.inf), (-np.inf, -np.inf),
|
|
215
|
+
])
|
|
216
|
+
def test_invalid_output_limits_are_rejected(kind, bounds):
|
|
217
|
+
wave = _configure(_signal(kind))
|
|
218
|
+
wave.min, wave.max = bounds
|
|
219
|
+
with pytest.raises(ValueError, match="min and max"):
|
|
220
|
+
wave.sample()
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@pytest.mark.parametrize("rate", [2_400_000_000, 7_000_000_000])
|
|
224
|
+
@pytest.mark.parametrize("bits", [16, 32])
|
|
225
|
+
def test_integer_limit_rounding_at_half_codes_and_beyond_full_scale(rate, bits):
|
|
226
|
+
wave = wf.WaveVStack([wf.square(20e-9), -wf.square(20e-9) >> 40e-9])
|
|
227
|
+
wave.start, wave.stop, wave.sample_rate = -30e-9, 70e-9, rate
|
|
228
|
+
raw = wave.sample()
|
|
229
|
+
full_scale = .7
|
|
230
|
+
code = full_scale / (2 ** (bits - 1))
|
|
231
|
+
dtype = np.int16 if bits == 16 else np.int32
|
|
232
|
+
for lower, upper in ((-.5 * code, 2.5 * code), (.8, 1.1), (-1.1, -.8),
|
|
233
|
+
(-np.inf, .2), (-.2, np.inf), (.1, .1)):
|
|
234
|
+
wave.min, wave.max = lower, upper
|
|
235
|
+
np.testing.assert_array_equal(
|
|
236
|
+
wave.sample(dtype=dtype, full_scale=full_scale),
|
|
237
|
+
quantize_samples(np.clip(raw, lower, upper), bits, full_scale))
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def test_many_scale_native_limits_span_scratch_blocks_and_partial_placements():
|
|
241
|
+
wave = wf.WaveVStack.from_events(
|
|
242
|
+
[wf.gaussian(300e-9)], np.zeros(80, dtype=np.uint32),
|
|
243
|
+
np.arange(80, dtype=np.int64) * wf.time_to_tick(600e-9),
|
|
244
|
+
np.linspace(-.9, .9, 80))
|
|
245
|
+
wave.start, wave.stop = 47e-9, 79 * 600e-9 + 73e-9
|
|
246
|
+
wave.sample_rate = 2_400_000_000
|
|
247
|
+
raw = wave.sample()
|
|
248
|
+
wave.min, wave.max = -.17, .23
|
|
249
|
+
for dtype, bits in ((np.int16, 16), (np.int32, 32)):
|
|
250
|
+
np.testing.assert_array_equal(
|
|
251
|
+
wave.sample(dtype=dtype, full_scale=.7),
|
|
252
|
+
quantize_samples(np.clip(raw, -.17, .23), bits, .7))
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Generated from Waveform.g4 by ANTLR 4.13.2
|
|
2
|
+
from antlr4 import *
|
|
3
|
+
from io import StringIO
|
|
4
|
+
import sys
|
|
5
|
+
if sys.version_info[1] > 5:
|
|
6
|
+
from typing import TextIO
|
|
7
|
+
else:
|
|
8
|
+
from typing.io import TextIO
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def serializedATN():
|
|
12
|
+
return [
|
|
13
|
+
4,0,22,169,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
|
|
14
|
+
2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,
|
|
15
|
+
13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,
|
|
16
|
+
19,2,20,7,20,2,21,7,21,2,22,7,22,1,0,1,0,1,1,1,1,1,2,1,2,1,3,1,3,
|
|
17
|
+
1,4,1,4,1,5,1,5,1,6,1,6,1,7,1,7,1,8,1,8,1,9,1,9,1,10,1,10,1,11,1,
|
|
18
|
+
11,1,11,3,11,73,8,11,1,12,4,12,76,8,12,11,12,12,12,77,1,12,1,12,
|
|
19
|
+
5,12,82,8,12,10,12,12,12,85,9,12,3,12,87,8,12,1,12,1,12,4,12,91,
|
|
20
|
+
8,12,11,12,12,12,92,3,12,95,8,12,1,12,1,12,3,12,99,8,12,1,12,4,12,
|
|
21
|
+
102,8,12,11,12,12,12,103,3,12,106,8,12,1,13,4,13,109,8,13,11,13,
|
|
22
|
+
12,13,110,1,14,1,14,3,14,115,8,14,1,14,1,14,1,15,1,15,5,15,121,8,
|
|
23
|
+
15,10,15,12,15,124,9,15,1,15,1,15,1,15,5,15,129,8,15,10,15,12,15,
|
|
24
|
+
132,9,15,1,15,3,15,135,8,15,1,16,1,16,1,16,1,16,1,16,1,16,3,16,143,
|
|
25
|
+
8,16,1,17,1,17,5,17,147,8,17,10,17,12,17,150,9,17,1,18,1,18,1,18,
|
|
26
|
+
1,19,1,19,1,19,1,20,1,20,1,20,1,21,4,21,162,8,21,11,21,12,21,163,
|
|
27
|
+
1,21,1,21,1,22,1,22,0,0,23,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,
|
|
28
|
+
9,19,10,21,11,23,12,25,13,27,14,29,15,31,16,33,17,35,18,37,19,39,
|
|
29
|
+
20,41,21,43,22,45,0,1,0,8,2,0,69,69,101,101,2,0,43,43,45,45,3,0,
|
|
30
|
+
10,10,13,13,34,34,3,0,10,10,13,13,39,39,3,0,65,90,95,95,97,122,4,
|
|
31
|
+
0,48,57,65,90,95,95,97,122,3,0,9,10,13,13,32,32,1,0,48,57,186,0,
|
|
32
|
+
1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,
|
|
33
|
+
0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,
|
|
34
|
+
0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,
|
|
35
|
+
0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,
|
|
36
|
+
0,0,0,0,43,1,0,0,0,1,47,1,0,0,0,3,49,1,0,0,0,5,51,1,0,0,0,7,53,1,
|
|
37
|
+
0,0,0,9,55,1,0,0,0,11,57,1,0,0,0,13,59,1,0,0,0,15,61,1,0,0,0,17,
|
|
38
|
+
63,1,0,0,0,19,65,1,0,0,0,21,67,1,0,0,0,23,72,1,0,0,0,25,94,1,0,0,
|
|
39
|
+
0,27,108,1,0,0,0,29,114,1,0,0,0,31,134,1,0,0,0,33,142,1,0,0,0,35,
|
|
40
|
+
144,1,0,0,0,37,151,1,0,0,0,39,154,1,0,0,0,41,157,1,0,0,0,43,161,
|
|
41
|
+
1,0,0,0,45,167,1,0,0,0,47,48,5,61,0,0,48,2,1,0,0,0,49,50,5,94,0,
|
|
42
|
+
0,50,4,1,0,0,0,51,52,5,42,0,0,52,6,1,0,0,0,53,54,5,47,0,0,54,8,1,
|
|
43
|
+
0,0,0,55,56,5,43,0,0,56,10,1,0,0,0,57,58,5,45,0,0,58,12,1,0,0,0,
|
|
44
|
+
59,60,5,40,0,0,60,14,1,0,0,0,61,62,5,41,0,0,62,16,1,0,0,0,63,64,
|
|
45
|
+
5,44,0,0,64,18,1,0,0,0,65,66,5,91,0,0,66,20,1,0,0,0,67,68,5,93,0,
|
|
46
|
+
0,68,22,1,0,0,0,69,73,3,25,12,0,70,73,3,27,13,0,71,73,3,29,14,0,
|
|
47
|
+
72,69,1,0,0,0,72,70,1,0,0,0,72,71,1,0,0,0,73,24,1,0,0,0,74,76,3,
|
|
48
|
+
45,22,0,75,74,1,0,0,0,76,77,1,0,0,0,77,75,1,0,0,0,77,78,1,0,0,0,
|
|
49
|
+
78,86,1,0,0,0,79,83,5,46,0,0,80,82,3,45,22,0,81,80,1,0,0,0,82,85,
|
|
50
|
+
1,0,0,0,83,81,1,0,0,0,83,84,1,0,0,0,84,87,1,0,0,0,85,83,1,0,0,0,
|
|
51
|
+
86,79,1,0,0,0,86,87,1,0,0,0,87,95,1,0,0,0,88,90,5,46,0,0,89,91,3,
|
|
52
|
+
45,22,0,90,89,1,0,0,0,91,92,1,0,0,0,92,90,1,0,0,0,92,93,1,0,0,0,
|
|
53
|
+
93,95,1,0,0,0,94,75,1,0,0,0,94,88,1,0,0,0,95,105,1,0,0,0,96,98,7,
|
|
54
|
+
0,0,0,97,99,7,1,0,0,98,97,1,0,0,0,98,99,1,0,0,0,99,101,1,0,0,0,100,
|
|
55
|
+
102,3,45,22,0,101,100,1,0,0,0,102,103,1,0,0,0,103,101,1,0,0,0,103,
|
|
56
|
+
104,1,0,0,0,104,106,1,0,0,0,105,96,1,0,0,0,105,106,1,0,0,0,106,26,
|
|
57
|
+
1,0,0,0,107,109,3,45,22,0,108,107,1,0,0,0,109,110,1,0,0,0,110,108,
|
|
58
|
+
1,0,0,0,110,111,1,0,0,0,111,28,1,0,0,0,112,115,3,25,12,0,113,115,
|
|
59
|
+
3,27,13,0,114,112,1,0,0,0,114,113,1,0,0,0,115,116,1,0,0,0,116,117,
|
|
60
|
+
5,106,0,0,117,30,1,0,0,0,118,122,5,34,0,0,119,121,8,2,0,0,120,119,
|
|
61
|
+
1,0,0,0,121,124,1,0,0,0,122,120,1,0,0,0,122,123,1,0,0,0,123,125,
|
|
62
|
+
1,0,0,0,124,122,1,0,0,0,125,135,5,34,0,0,126,130,5,39,0,0,127,129,
|
|
63
|
+
8,3,0,0,128,127,1,0,0,0,129,132,1,0,0,0,130,128,1,0,0,0,130,131,
|
|
64
|
+
1,0,0,0,131,133,1,0,0,0,132,130,1,0,0,0,133,135,5,39,0,0,134,118,
|
|
65
|
+
1,0,0,0,134,126,1,0,0,0,135,32,1,0,0,0,136,137,5,112,0,0,137,143,
|
|
66
|
+
5,105,0,0,138,143,5,101,0,0,139,140,5,105,0,0,140,141,5,110,0,0,
|
|
67
|
+
141,143,5,102,0,0,142,136,1,0,0,0,142,138,1,0,0,0,142,139,1,0,0,
|
|
68
|
+
0,143,34,1,0,0,0,144,148,7,4,0,0,145,147,7,5,0,0,146,145,1,0,0,0,
|
|
69
|
+
147,150,1,0,0,0,148,146,1,0,0,0,148,149,1,0,0,0,149,36,1,0,0,0,150,
|
|
70
|
+
148,1,0,0,0,151,152,5,42,0,0,152,153,5,42,0,0,153,38,1,0,0,0,154,
|
|
71
|
+
155,5,60,0,0,155,156,5,60,0,0,156,40,1,0,0,0,157,158,5,62,0,0,158,
|
|
72
|
+
159,5,62,0,0,159,42,1,0,0,0,160,162,7,6,0,0,161,160,1,0,0,0,162,
|
|
73
|
+
163,1,0,0,0,163,161,1,0,0,0,163,164,1,0,0,0,164,165,1,0,0,0,165,
|
|
74
|
+
166,6,21,0,0,166,44,1,0,0,0,167,168,7,7,0,0,168,46,1,0,0,0,18,0,
|
|
75
|
+
72,77,83,86,92,94,98,103,105,110,114,122,130,134,142,148,163,1,6,
|
|
76
|
+
0,0
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
class WaveformLexer(Lexer):
|
|
80
|
+
|
|
81
|
+
atn = ATNDeserializer().deserialize(serializedATN())
|
|
82
|
+
|
|
83
|
+
decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ]
|
|
84
|
+
|
|
85
|
+
T__0 = 1
|
|
86
|
+
T__1 = 2
|
|
87
|
+
T__2 = 3
|
|
88
|
+
T__3 = 4
|
|
89
|
+
T__4 = 5
|
|
90
|
+
T__5 = 6
|
|
91
|
+
T__6 = 7
|
|
92
|
+
T__7 = 8
|
|
93
|
+
T__8 = 9
|
|
94
|
+
T__9 = 10
|
|
95
|
+
T__10 = 11
|
|
96
|
+
NUMBER = 12
|
|
97
|
+
REAL = 13
|
|
98
|
+
INT = 14
|
|
99
|
+
IMAG = 15
|
|
100
|
+
STRING = 16
|
|
101
|
+
CONSTANT = 17
|
|
102
|
+
ID = 18
|
|
103
|
+
POW = 19
|
|
104
|
+
LSHIFT = 20
|
|
105
|
+
RSHIFT = 21
|
|
106
|
+
WS = 22
|
|
107
|
+
|
|
108
|
+
channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
|
|
109
|
+
|
|
110
|
+
modeNames = [ "DEFAULT_MODE" ]
|
|
111
|
+
|
|
112
|
+
literalNames = [ "<INVALID>",
|
|
113
|
+
"'='", "'^'", "'*'", "'/'", "'+'", "'-'", "'('", "')'", "','",
|
|
114
|
+
"'['", "']'", "'**'", "'<<'", "'>>'" ]
|
|
115
|
+
|
|
116
|
+
symbolicNames = [ "<INVALID>",
|
|
117
|
+
"NUMBER", "REAL", "INT", "IMAG", "STRING", "CONSTANT", "ID",
|
|
118
|
+
"POW", "LSHIFT", "RSHIFT", "WS" ]
|
|
119
|
+
|
|
120
|
+
ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6",
|
|
121
|
+
"T__7", "T__8", "T__9", "T__10", "NUMBER", "REAL", "INT",
|
|
122
|
+
"IMAG", "STRING", "CONSTANT", "ID", "POW", "LSHIFT", "RSHIFT",
|
|
123
|
+
"WS", "DIGIT" ]
|
|
124
|
+
|
|
125
|
+
grammarFileName = "Waveform.g4"
|
|
126
|
+
|
|
127
|
+
def __init__(self, input=None, output:TextIO = sys.stdout):
|
|
128
|
+
super().__init__(input, output)
|
|
129
|
+
self.checkVersion("4.13.2")
|
|
130
|
+
self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
|
|
131
|
+
self._actions = None
|
|
132
|
+
self._predicates = None
|
|
133
|
+
|
|
134
|
+
|