waveforms 3.3.2__tar.gz → 3.4.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.3.2/waveforms.egg-info → waveforms-3.4.0}/PKG-INFO +1 -1
- {waveforms-3.3.2 → waveforms-3.4.0}/tests/test_waveform.py +14 -5
- {waveforms-3.3.2 → waveforms-3.4.0}/tests/test_wavevstack.py +47 -1
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/__init__.py +9 -2
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/_cwaveform.c +270 -138
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/_cwaveform.h +2 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/_waveform.pyx +12 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/version.py +1 -1
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/waveform.py +86 -35
- {waveforms-3.3.2 → waveforms-3.4.0/waveforms.egg-info}/PKG-INFO +1 -1
- {waveforms-3.3.2 → waveforms-3.4.0}/LICENSE +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/MANIFEST.in +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/README.md +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/pyproject.toml +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/setup.cfg +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/setup.py +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/tests/test_core.py +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/Waveform.g4 +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/__main__.py +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/_cwaveform.md +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/_waveform.pyi +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/distortion.py +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/utils.py +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms/waveform_parser.py +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms.egg-info/SOURCES.txt +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms.egg-info/dependency_links.txt +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms.egg-info/entry_points.txt +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms.egg-info/requires.txt +0 -0
- {waveforms-3.3.2 → waveforms-3.4.0}/waveforms.egg-info/top_level.txt +0 -0
|
@@ -22,8 +22,9 @@ PUBLIC_NAMES = {
|
|
|
22
22
|
"exp", "function",
|
|
23
23
|
"gaussian", "general_cosine", "get_time_resolution", "hanning", "interp", "mixing",
|
|
24
24
|
"mollifier", "one", "poly", "registerBaseFunc", "registerDerivative",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
25
|
+
"quantize_time", "sample_clock", "sample_grid", "samplingPoints",
|
|
26
|
+
"set_time_resolution", "sign", "sin", "sinc", "sinh", "square",
|
|
27
|
+
"step", "t", "tick_to_time", "time_to_tick", "wave_eval", "zero",
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
|
|
@@ -34,6 +35,9 @@ def test_public_api_and_basic_sampling():
|
|
|
34
35
|
assert np.allclose(wf.sin(0.7)(x), np.sin(0.7 * x))
|
|
35
36
|
assert np.allclose(wf.poly([1, -0.5, 0.25])(x),
|
|
36
37
|
1 - 0.5 * x + 0.25 * x**2)
|
|
38
|
+
assert wf.zero().is_zero()
|
|
39
|
+
assert (0 * wf.gaussian(1)).is_zero()
|
|
40
|
+
assert not wf.one().is_zero()
|
|
37
41
|
|
|
38
42
|
|
|
39
43
|
def test_binary_roundtrip_is_zero_copy_for_bytes_input():
|
|
@@ -461,7 +465,7 @@ def test_device_sample_clocks_and_rational_fallback():
|
|
|
461
465
|
assert np.all(np.diff(grid) > 0)
|
|
462
466
|
|
|
463
467
|
|
|
464
|
-
def
|
|
468
|
+
def test_fixed_width_quantization_and_rational_sampling():
|
|
465
469
|
values = np.array([-2, -1, -0.5, 0, 0.5, 1, 2.0])
|
|
466
470
|
assert np.array_equal(
|
|
467
471
|
quantize_samples(values, 16),
|
|
@@ -498,8 +502,13 @@ def test_fixed_width_quantization_supported_sampling_and_fallback():
|
|
|
498
502
|
assert np.array_equal(chunks, whole)
|
|
499
503
|
|
|
500
504
|
odd_rate = 7_000_000_000
|
|
501
|
-
|
|
502
|
-
|
|
505
|
+
rational_samples = wav.sample(odd_rate)
|
|
506
|
+
numerator, denominator = sample_clock(odd_rate)
|
|
507
|
+
rational_grid = sample_grid(
|
|
508
|
+
time_to_tick(wav.start), len(rational_samples),
|
|
509
|
+
numerator, denominator,
|
|
510
|
+
)
|
|
511
|
+
assert np.allclose(rational_samples, wav(rational_grid), rtol=0, atol=1e-15)
|
|
503
512
|
|
|
504
513
|
|
|
505
514
|
def test_simd_node_evaluation_matches_scalar_boundaries():
|
|
@@ -3,7 +3,10 @@ import pickle
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from scipy.signal import butter, lfilter, lfiltic, tf2sos
|
|
5
5
|
|
|
6
|
-
from waveforms import
|
|
6
|
+
from waveforms import (
|
|
7
|
+
Waveform, WaveVStack, cos, gaussian, pi, poly, sin, step,
|
|
8
|
+
time_to_tick, zero,
|
|
9
|
+
)
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
def _waves():
|
|
@@ -59,3 +62,46 @@ def test_wavevstack_binary_template_sharing_and_pickle():
|
|
|
59
62
|
restored = WaveVStack.from_bytes(stack.to_bytes())
|
|
60
63
|
assert restored == stack
|
|
61
64
|
assert pickle.loads(pickle.dumps(stack)) == stack
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_wavevstack_content_deduplication_and_constant_time_support():
|
|
68
|
+
base = gaussian(20e-9) * cos(2 * pi * 5e9)
|
|
69
|
+
waves = [
|
|
70
|
+
Waveform.from_bytes(base.to_bytes()) >> (index * 80e-9)
|
|
71
|
+
for index in range(100)
|
|
72
|
+
]
|
|
73
|
+
stack = WaveVStack([zero(), *waves])
|
|
74
|
+
|
|
75
|
+
assert len(stack) == stack.event_count == 100
|
|
76
|
+
assert stack.template_count == 1
|
|
77
|
+
assert np.isclose(stack.begin, base.begin)
|
|
78
|
+
assert np.isclose(stack.end, base.end + 99 * 80e-9)
|
|
79
|
+
|
|
80
|
+
restored = WaveVStack.from_bytes(stack.to_bytes())
|
|
81
|
+
shifted = restored >> 2e-9
|
|
82
|
+
assert restored.template_count == 1
|
|
83
|
+
assert restored.event_count == 100
|
|
84
|
+
assert np.isclose(shifted.begin, stack.begin + 2e-9)
|
|
85
|
+
assert np.isclose(shifted.end, stack.end + 2e-9)
|
|
86
|
+
|
|
87
|
+
empty = WaveVStack()
|
|
88
|
+
assert empty.begin == -np.inf
|
|
89
|
+
assert empty.end == np.inf
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_wavevstack_compiler_event_columns():
|
|
93
|
+
template = gaussian(20e-9) * cos(2 * pi * 5e9)
|
|
94
|
+
delays = np.arange(100, dtype=np.int64) * time_to_tick(80e-9)
|
|
95
|
+
stack = WaveVStack.from_events(
|
|
96
|
+
(template,), np.zeros(100, dtype=np.uint32), delays,
|
|
97
|
+
np.full(100, 0.25),
|
|
98
|
+
)
|
|
99
|
+
expected = WaveVStack([
|
|
100
|
+
0.25 * template >> (index * 80e-9) for index in range(100)
|
|
101
|
+
])
|
|
102
|
+
|
|
103
|
+
assert stack.template_count == 1
|
|
104
|
+
assert stack.event_count == 100
|
|
105
|
+
assert stack.to_bytes() == expected.to_bytes()
|
|
106
|
+
positions = np.linspace(-20e-9, 8e-6, 1000)
|
|
107
|
+
assert np.allclose(stack(positions), expected(positions))
|
|
@@ -30,9 +30,12 @@ from .waveform import (
|
|
|
30
30
|
mollifier,
|
|
31
31
|
one,
|
|
32
32
|
poly,
|
|
33
|
+
quantize_time,
|
|
33
34
|
registerBaseFunc,
|
|
34
35
|
registerDerivative,
|
|
35
36
|
samplingPoints,
|
|
37
|
+
sample_clock,
|
|
38
|
+
sample_grid,
|
|
36
39
|
set_time_resolution,
|
|
37
40
|
sign,
|
|
38
41
|
sin,
|
|
@@ -41,6 +44,8 @@ from .waveform import (
|
|
|
41
44
|
square,
|
|
42
45
|
step,
|
|
43
46
|
t,
|
|
47
|
+
tick_to_time,
|
|
48
|
+
time_to_tick,
|
|
44
49
|
wave_eval,
|
|
45
50
|
zero,
|
|
46
51
|
)
|
|
@@ -53,7 +58,9 @@ __all__ = [
|
|
|
53
58
|
"e", "exp", "function",
|
|
54
59
|
"gaussian", "general_cosine", "get_time_resolution", "hanning",
|
|
55
60
|
"interp", "mixing", "mollifier", "one", "pi", "poly",
|
|
56
|
-
"
|
|
61
|
+
"quantize_time", "registerBaseFunc", "registerDerivative",
|
|
62
|
+
"sample_clock", "sample_grid", "samplingPoints",
|
|
57
63
|
"set_time_resolution", "sign", "sin", "sinc", "sinh", "square",
|
|
58
|
-
"step", "t", "
|
|
64
|
+
"step", "t", "tick_to_time", "time_to_tick", "wave_eval", "zero",
|
|
65
|
+
"__version__",
|
|
59
66
|
]
|
|
@@ -87,6 +87,18 @@ typedef struct wf_node {
|
|
|
87
87
|
int64_t upper;
|
|
88
88
|
} wf_node;
|
|
89
89
|
|
|
90
|
+
typedef struct wf_drag_sin_kernel {
|
|
91
|
+
size_t order;
|
|
92
|
+
size_t power;
|
|
93
|
+
size_t basis_count;
|
|
94
|
+
double angular;
|
|
95
|
+
double normalization;
|
|
96
|
+
double *transform;
|
|
97
|
+
double *derivatives;
|
|
98
|
+
double *left_polynomial;
|
|
99
|
+
double *right_polynomial;
|
|
100
|
+
} wf_drag_sin_kernel;
|
|
101
|
+
|
|
90
102
|
struct cwaveform_wave {
|
|
91
103
|
uint32_t references;
|
|
92
104
|
uint32_t node_count;
|
|
@@ -97,6 +109,7 @@ struct cwaveform_wave {
|
|
|
97
109
|
wf_node *nodes;
|
|
98
110
|
double *parameters;
|
|
99
111
|
size_t parameter_count;
|
|
112
|
+
wf_drag_sin_kernel **drag_sin_kernels;
|
|
100
113
|
};
|
|
101
114
|
|
|
102
115
|
struct cwaveform_stack {
|
|
@@ -107,6 +120,8 @@ struct cwaveform_stack {
|
|
|
107
120
|
uint32_t *template_ids;
|
|
108
121
|
int64_t *delays;
|
|
109
122
|
double *scales;
|
|
123
|
+
int64_t lower_tick;
|
|
124
|
+
int64_t upper_tick;
|
|
110
125
|
uint64_t hash;
|
|
111
126
|
size_t data_size;
|
|
112
127
|
uint8_t *data;
|
|
@@ -147,6 +162,8 @@ struct cwaveform_sample_plan {
|
|
|
147
162
|
|
|
148
163
|
static double wf_node_parameter(const cwaveform_wave *wave,
|
|
149
164
|
const wf_node *node, size_t index);
|
|
165
|
+
static int wf_wave_prepare_drag_sin_kernels(cwaveform_wave *wave);
|
|
166
|
+
static void wf_wave_clear_drag_sin_kernels(cwaveform_wave *wave);
|
|
150
167
|
|
|
151
168
|
static double wf_hypot(double x, double y) {
|
|
152
169
|
double high = fabs(x);
|
|
@@ -474,6 +491,10 @@ static cwaveform_wave *wf_wave_from_parts(const wf_node *nodes,
|
|
|
474
491
|
+ (size_t)index * sizeof(double), parameters[index]);
|
|
475
492
|
}
|
|
476
493
|
wave->hash = wf_hash_bytes(wave->data, size);
|
|
494
|
+
if (wf_wave_prepare_drag_sin_kernels(wave) != 0) {
|
|
495
|
+
cwaveform_wave_release(wave);
|
|
496
|
+
return NULL;
|
|
497
|
+
}
|
|
477
498
|
return wave;
|
|
478
499
|
}
|
|
479
500
|
|
|
@@ -1716,6 +1737,10 @@ cwaveform_wave *cwaveform_wave_from_bytes(const uint8_t *data, size_t size) {
|
|
|
1716
1737
|
wave->parameter_count = parameter_count;
|
|
1717
1738
|
wave->data_size = size;
|
|
1718
1739
|
wave->hash = wf_hash_bytes(data, size);
|
|
1740
|
+
if (wf_wave_prepare_drag_sin_kernels(wave) != 0) {
|
|
1741
|
+
cwaveform_wave_release(wave);
|
|
1742
|
+
return NULL;
|
|
1743
|
+
}
|
|
1719
1744
|
return wave;
|
|
1720
1745
|
}
|
|
1721
1746
|
|
|
@@ -1957,6 +1982,7 @@ void cwaveform_wave_release(cwaveform_wave *wave) {
|
|
|
1957
1982
|
free(wave->data);
|
|
1958
1983
|
free(wave->nodes);
|
|
1959
1984
|
free(wave->parameters);
|
|
1985
|
+
wf_wave_clear_drag_sin_kernels(wave);
|
|
1960
1986
|
free(wave);
|
|
1961
1987
|
}
|
|
1962
1988
|
|
|
@@ -2172,198 +2198,272 @@ static double wf_polynomial_derivative_value(const double *coefficients,
|
|
|
2172
2198
|
return value;
|
|
2173
2199
|
}
|
|
2174
2200
|
|
|
2175
|
-
static
|
|
2176
|
-
|
|
2177
|
-
|
|
2201
|
+
static void wf_drag_sin_kernel_free(wf_drag_sin_kernel *kernel) {
|
|
2202
|
+
if (kernel == NULL) return;
|
|
2203
|
+
free(kernel->transform);
|
|
2204
|
+
free(kernel->derivatives);
|
|
2205
|
+
free(kernel->left_polynomial);
|
|
2206
|
+
free(kernel->right_polynomial);
|
|
2207
|
+
free(kernel);
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
static wf_drag_sin_kernel *wf_drag_sin_kernel_create(
|
|
2211
|
+
const cwaveform_wave *wave, const wf_node *node, int sinx) {
|
|
2178
2212
|
size_t total = (size_t)node->parameter_count + 1;
|
|
2179
2213
|
size_t block_count = total - 7;
|
|
2180
2214
|
size_t order = block_count + 1;
|
|
2181
2215
|
size_t power = ((block_count + 2) >> 1) << 1;
|
|
2182
2216
|
size_t basis_count;
|
|
2183
|
-
double t0 = wf_node_parameter(wave, node, 0);
|
|
2184
|
-
double frequency = wf_node_parameter(wave, node, 1);
|
|
2185
2217
|
double width = wf_node_parameter(wave, node, 2);
|
|
2186
2218
|
double delta = wf_node_parameter(wave, node, 3);
|
|
2187
|
-
double phase = wf_node_parameter(wave, node, 4);
|
|
2188
|
-
double plateau = wf_node_parameter(wave, node, 5);
|
|
2189
2219
|
double tab = wf_node_parameter(wave, node, 6);
|
|
2190
|
-
|
|
2191
|
-
double
|
|
2192
|
-
double
|
|
2193
|
-
double *basis;
|
|
2194
|
-
double *values;
|
|
2195
|
-
double components[2] = {0.0, 0.0};
|
|
2196
|
-
double normalization = 1.0;
|
|
2220
|
+
wf_drag_sin_kernel *kernel;
|
|
2221
|
+
double basis[67];
|
|
2222
|
+
double values[65];
|
|
2197
2223
|
size_t index;
|
|
2198
|
-
if (!(width > 0.0) || block_count > 64) return
|
|
2224
|
+
if (!(width > 0.0) || block_count > 64) return NULL;
|
|
2199
2225
|
if (power < 2) power = 2;
|
|
2200
2226
|
basis_count = power + 1;
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2227
|
+
kernel = (wf_drag_sin_kernel *)calloc(1, sizeof(*kernel));
|
|
2228
|
+
if (kernel == NULL) return NULL;
|
|
2229
|
+
kernel->order = order;
|
|
2230
|
+
kernel->power = power;
|
|
2231
|
+
kernel->basis_count = basis_count;
|
|
2232
|
+
kernel->angular = 3.14159265358979323846 / width;
|
|
2233
|
+
kernel->normalization = 1.0;
|
|
2234
|
+
kernel->transform = (double *)calloc(order * 4, sizeof(double));
|
|
2235
|
+
kernel->derivatives = (double *)calloc(
|
|
2236
|
+
order * basis_count, sizeof(double));
|
|
2237
|
+
if (sinx) {
|
|
2238
|
+
kernel->left_polynomial = (double *)calloc(
|
|
2239
|
+
2 * order, sizeof(double));
|
|
2240
|
+
kernel->right_polynomial = (double *)calloc(
|
|
2241
|
+
2 * order, sizeof(double));
|
|
2242
|
+
}
|
|
2243
|
+
if (kernel->transform == NULL || kernel->derivatives == NULL
|
|
2244
|
+
|| (sinx && (kernel->left_polynomial == NULL
|
|
2245
|
+
|| kernel->right_polynomial == NULL))) {
|
|
2246
|
+
wf_drag_sin_kernel_free(kernel);
|
|
2247
|
+
return NULL;
|
|
2248
|
+
}
|
|
2249
|
+
kernel->transform[0] = 1.0;
|
|
2250
|
+
kernel->transform[3] = 1.0;
|
|
2213
2251
|
for (index = 0; index < block_count; ++index) {
|
|
2214
2252
|
double block_frequency = wf_node_parameter(wave, node, 7 + index);
|
|
2215
2253
|
double coefficient = 1.0 / (2.0 * 3.14159265358979323846
|
|
2216
2254
|
* (block_frequency - delta));
|
|
2217
2255
|
size_t row = index + 1;
|
|
2218
2256
|
while (row-- != 0) {
|
|
2219
|
-
double *target = transform + (row + 1) * 4;
|
|
2220
|
-
const double *source = transform + row * 4;
|
|
2257
|
+
double *target = kernel->transform + (row + 1) * 4;
|
|
2258
|
+
const double *source = kernel->transform + row * 4;
|
|
2221
2259
|
target[0] += -coefficient * source[1];
|
|
2222
2260
|
target[1] += coefficient * source[0];
|
|
2223
2261
|
target[2] += -coefficient * source[3];
|
|
2224
2262
|
target[3] += coefficient * source[2];
|
|
2225
2263
|
}
|
|
2226
2264
|
}
|
|
2227
|
-
derivatives[power] = 1.0;
|
|
2265
|
+
kernel->derivatives[power] = 1.0;
|
|
2228
2266
|
for (index = 1; index < order; ++index) {
|
|
2229
2267
|
size_t exponent;
|
|
2230
2268
|
if (index & 1) {
|
|
2231
2269
|
for (exponent = 0; exponent < power; ++exponent)
|
|
2232
|
-
derivatives[index * basis_count + exponent] =
|
|
2233
|
-
derivatives[
|
|
2234
|
-
|
|
2270
|
+
kernel->derivatives[index * basis_count + exponent] =
|
|
2271
|
+
kernel->derivatives[
|
|
2272
|
+
(index - 1) * basis_count + exponent + 1]
|
|
2273
|
+
* (double)(exponent + 1) * kernel->angular;
|
|
2235
2274
|
} else {
|
|
2236
2275
|
for (exponent = 0; exponent + 2 <= power; ++exponent)
|
|
2237
|
-
derivatives[index * basis_count + exponent] =
|
|
2238
|
-
derivatives[
|
|
2276
|
+
kernel->derivatives[index * basis_count + exponent] =
|
|
2277
|
+
kernel->derivatives[
|
|
2278
|
+
(index - 2) * basis_count + exponent + 2]
|
|
2239
2279
|
* (double)(exponent + 1) * (double)(exponent + 2);
|
|
2240
2280
|
for (exponent = 0; exponent <= power; ++exponent)
|
|
2241
|
-
derivatives[index * basis_count + exponent] -=
|
|
2242
|
-
derivatives[
|
|
2281
|
+
kernel->derivatives[index * basis_count + exponent] -=
|
|
2282
|
+
kernel->derivatives[
|
|
2283
|
+
(index - 2) * basis_count + exponent]
|
|
2243
2284
|
* (double)(exponent * exponent);
|
|
2244
2285
|
for (exponent = 0; exponent <= power; ++exponent)
|
|
2245
|
-
derivatives[index * basis_count + exponent]
|
|
2246
|
-
*= angular * angular;
|
|
2286
|
+
kernel->derivatives[index * basis_count + exponent]
|
|
2287
|
+
*= kernel->angular * kernel->angular;
|
|
2247
2288
|
}
|
|
2248
2289
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
for (exponent = 0; exponent <= power; ++exponent)
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
double boundary_sine = sin(boundary_angle);
|
|
2278
|
-
double boundary_cosine = cos(boundary_angle);
|
|
2279
|
-
double *boundary_basis = basis;
|
|
2280
|
-
double *edge_values = (double *)calloc(order, sizeof(double));
|
|
2281
|
-
double *polynomial = (double *)calloc(2 * order, sizeof(double));
|
|
2282
|
-
double edge_x = (left ? -tab : tab) * width / 2.0;
|
|
2283
|
-
double x = left ? local - midpoint : local - plateau_stop;
|
|
2284
|
-
if (edge_values == NULL || polynomial == NULL) {
|
|
2285
|
-
free(edge_values); free(polynomial);
|
|
2286
|
-
free(transform); free(derivatives); free(basis); free(values);
|
|
2287
|
-
return NAN;
|
|
2288
|
-
}
|
|
2289
|
-
for (exponent = 0; exponent <= power; ++exponent) {
|
|
2290
|
-
boundary_basis[exponent] = pow(boundary_sine,
|
|
2291
|
-
(double)exponent);
|
|
2292
|
-
if (exponent & 1) boundary_basis[exponent]
|
|
2293
|
-
*= boundary_cosine;
|
|
2294
|
-
}
|
|
2295
|
-
for (index = 0; index < order; ++index)
|
|
2296
|
-
for (exponent = 0; exponent <= power; ++exponent)
|
|
2297
|
-
edge_values[index] +=
|
|
2298
|
-
derivatives[index * basis_count + exponent]
|
|
2299
|
-
* boundary_basis[exponent];
|
|
2300
|
-
if (wf_edge_polynomial(edge_values, order, edge_x,
|
|
2301
|
-
polynomial) != 0) {
|
|
2302
|
-
free(edge_values); free(polynomial);
|
|
2303
|
-
free(transform); free(derivatives); free(basis); free(values);
|
|
2304
|
-
return NAN;
|
|
2305
|
-
}
|
|
2306
|
-
for (index = 0; index < order; ++index)
|
|
2307
|
-
values[index] = wf_polynomial_derivative_value(
|
|
2308
|
-
polynomial, 2 * order, index, x);
|
|
2309
|
-
free(edge_values);
|
|
2310
|
-
free(polynomial);
|
|
2290
|
+
|
|
2291
|
+
if (sinx) {
|
|
2292
|
+
int side;
|
|
2293
|
+
for (side = 0; side < 2; ++side) {
|
|
2294
|
+
double boundary_angle = kernel->angular
|
|
2295
|
+
* ((side == 0 ? (1.0 - tab) : (1.0 + tab))
|
|
2296
|
+
* width / 2.0);
|
|
2297
|
+
double boundary_sine = sin(boundary_angle);
|
|
2298
|
+
double boundary_cosine = cos(boundary_angle);
|
|
2299
|
+
double edge_x = (side == 0 ? -tab : tab) * width / 2.0;
|
|
2300
|
+
double *polynomial = side == 0
|
|
2301
|
+
? kernel->left_polynomial : kernel->right_polynomial;
|
|
2302
|
+
double sine_power = 1.0;
|
|
2303
|
+
size_t exponent;
|
|
2304
|
+
memset(values, 0, order * sizeof(double));
|
|
2305
|
+
for (exponent = 0; exponent <= power; ++exponent) {
|
|
2306
|
+
basis[exponent] = sine_power;
|
|
2307
|
+
if (exponent & 1) basis[exponent] *= boundary_cosine;
|
|
2308
|
+
sine_power *= boundary_sine;
|
|
2309
|
+
}
|
|
2310
|
+
for (index = 0; index < order; ++index)
|
|
2311
|
+
for (exponent = 0; exponent <= power; ++exponent)
|
|
2312
|
+
values[index] += kernel->derivatives[
|
|
2313
|
+
index * basis_count + exponent] * basis[exponent];
|
|
2314
|
+
if (wf_edge_polynomial(
|
|
2315
|
+
values, order, edge_x, polynomial) != 0) {
|
|
2316
|
+
wf_drag_sin_kernel_free(kernel);
|
|
2317
|
+
return NULL;
|
|
2311
2318
|
}
|
|
2312
2319
|
}
|
|
2313
|
-
}
|
|
2314
|
-
|
|
2315
|
-
double peak_components[2] = {0.0, 0.0};
|
|
2320
|
+
} else {
|
|
2321
|
+
double components[2] = {0.0, 0.0};
|
|
2316
2322
|
size_t exponent;
|
|
2317
2323
|
memset(basis, 0, basis_count * sizeof(double));
|
|
2324
|
+
memset(values, 0, order * sizeof(double));
|
|
2318
2325
|
for (exponent = 0; exponent <= power; exponent += 2)
|
|
2319
2326
|
basis[exponent] = 1.0;
|
|
2320
|
-
memset(values, 0, order * sizeof(double));
|
|
2321
2327
|
for (index = 0; index < order; ++index)
|
|
2322
2328
|
for (exponent = 0; exponent <= power; ++exponent)
|
|
2323
|
-
values[index] += derivatives[
|
|
2324
|
-
* basis[exponent];
|
|
2329
|
+
values[index] += kernel->derivatives[
|
|
2330
|
+
index * basis_count + exponent] * basis[exponent];
|
|
2325
2331
|
for (index = 0; index < order; ++index) {
|
|
2326
|
-
|
|
2327
|
-
|
|
2332
|
+
components[0] += kernel->transform[index * 4] * values[index];
|
|
2333
|
+
components[1] += kernel->transform[index * 4 + 2]
|
|
2334
|
+
* values[index];
|
|
2328
2335
|
}
|
|
2329
|
-
normalization = wf_hypot(
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2336
|
+
kernel->normalization = wf_hypot(components[0], components[1]);
|
|
2337
|
+
}
|
|
2338
|
+
return kernel;
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
static int wf_wave_prepare_drag_sin_kernels(cwaveform_wave *wave) {
|
|
2342
|
+
uint32_t index;
|
|
2343
|
+
int needed = 0;
|
|
2344
|
+
for (index = 0; index < wave->node_count; ++index) {
|
|
2345
|
+
uint8_t op = wave->nodes[index].op;
|
|
2346
|
+
if (op == WF_OP_DRAG_SIN || op == WF_OP_DRAG_SINX) {
|
|
2347
|
+
needed = 1;
|
|
2348
|
+
break;
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
if (!needed) return 0;
|
|
2352
|
+
wave->drag_sin_kernels = (wf_drag_sin_kernel **)calloc(
|
|
2353
|
+
wave->node_count, sizeof(*wave->drag_sin_kernels));
|
|
2354
|
+
if (wave->drag_sin_kernels == NULL) return -1;
|
|
2355
|
+
for (index = 0; index < wave->node_count; ++index) {
|
|
2356
|
+
const wf_node *node = wave->nodes + index;
|
|
2357
|
+
if (node->op != WF_OP_DRAG_SIN && node->op != WF_OP_DRAG_SINX)
|
|
2358
|
+
continue;
|
|
2359
|
+
wave->drag_sin_kernels[index] = wf_drag_sin_kernel_create(
|
|
2360
|
+
wave, node, node->op == WF_OP_DRAG_SINX);
|
|
2361
|
+
if (wave->drag_sin_kernels[index] == NULL) {
|
|
2362
|
+
wf_wave_clear_drag_sin_kernels(wave);
|
|
2363
|
+
return -1;
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
return 0;
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
static void wf_wave_clear_drag_sin_kernels(cwaveform_wave *wave) {
|
|
2370
|
+
uint32_t index;
|
|
2371
|
+
if (wave->drag_sin_kernels == NULL) return;
|
|
2372
|
+
for (index = 0; index < wave->node_count; ++index)
|
|
2373
|
+
wf_drag_sin_kernel_free(wave->drag_sin_kernels[index]);
|
|
2374
|
+
free(wave->drag_sin_kernels);
|
|
2375
|
+
wave->drag_sin_kernels = NULL;
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
static double wf_drag_sin_value(const cwaveform_wave *wave,
|
|
2379
|
+
uint32_t node_index,
|
|
2380
|
+
const wf_node *node, double local,
|
|
2381
|
+
int sinx) {
|
|
2382
|
+
const wf_drag_sin_kernel *kernel = wave->drag_sin_kernels == NULL
|
|
2383
|
+
? NULL : wave->drag_sin_kernels[node_index];
|
|
2384
|
+
double t0 = wf_node_parameter(wave, node, 0);
|
|
2385
|
+
double frequency = wf_node_parameter(wave, node, 1);
|
|
2386
|
+
double width = wf_node_parameter(wave, node, 2);
|
|
2387
|
+
double delta = wf_node_parameter(wave, node, 3);
|
|
2388
|
+
double phase = wf_node_parameter(wave, node, 4);
|
|
2389
|
+
double plateau = wf_node_parameter(wave, node, 5);
|
|
2390
|
+
double tab = wf_node_parameter(wave, node, 6);
|
|
2391
|
+
double basis[67];
|
|
2392
|
+
double values[65];
|
|
2393
|
+
double components[2] = {0.0, 0.0};
|
|
2394
|
+
double midpoint;
|
|
2395
|
+
double plateau_stop;
|
|
2396
|
+
size_t index;
|
|
2397
|
+
if (kernel == NULL) return NAN;
|
|
2398
|
+
midpoint = t0 + width / 2.0;
|
|
2399
|
+
plateau_stop = midpoint + plateau;
|
|
2400
|
+
memset(values, 0, kernel->order * sizeof(double));
|
|
2401
|
+
if (sinx) {
|
|
2402
|
+
int left = local >= midpoint - tab * width / 2.0
|
|
2403
|
+
&& local <= midpoint;
|
|
2404
|
+
int right = local >= plateau_stop
|
|
2405
|
+
&& local <= plateau_stop + tab * width / 2.0;
|
|
2406
|
+
if (left || right) {
|
|
2407
|
+
double x = left ? local - midpoint : local - plateau_stop;
|
|
2408
|
+
const double *polynomial = left
|
|
2409
|
+
? kernel->left_polynomial : kernel->right_polynomial;
|
|
2410
|
+
for (index = 0; index < kernel->order; ++index)
|
|
2411
|
+
values[index] = wf_polynomial_derivative_value(
|
|
2412
|
+
polynomial, 2 * kernel->order, index, x);
|
|
2413
|
+
} else {
|
|
2414
|
+
double adjusted = local >= plateau_stop
|
|
2415
|
+
? local - plateau : local;
|
|
2416
|
+
double angle = kernel->angular * (adjusted - t0);
|
|
2417
|
+
double sine = sin(angle);
|
|
2418
|
+
double cosine = cos(angle);
|
|
2419
|
+
double sine_power = 1.0;
|
|
2337
2420
|
int in_plateau = local > midpoint && local < plateau_stop;
|
|
2338
|
-
|
|
2339
|
-
for (
|
|
2340
|
-
basis[
|
|
2341
|
-
if (
|
|
2342
|
-
if (in_plateau) basis[
|
|
2421
|
+
size_t exponent;
|
|
2422
|
+
for (exponent = 0; exponent <= kernel->power; ++exponent) {
|
|
2423
|
+
basis[exponent] = sine_power;
|
|
2424
|
+
if (exponent & 1) basis[exponent] *= cosine;
|
|
2425
|
+
if (in_plateau) basis[exponent] = 0.0;
|
|
2426
|
+
sine_power *= sine;
|
|
2343
2427
|
}
|
|
2344
|
-
for (index = 0; index < order; ++index)
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2428
|
+
for (index = 0; index < kernel->order; ++index)
|
|
2429
|
+
for (exponent = 0; exponent <= kernel->power; ++exponent)
|
|
2430
|
+
values[index] += kernel->derivatives[
|
|
2431
|
+
index * kernel->basis_count + exponent]
|
|
2348
2432
|
* basis[exponent];
|
|
2349
|
-
}
|
|
2350
2433
|
if (in_plateau) values[0] = 1.0;
|
|
2351
2434
|
}
|
|
2435
|
+
} else {
|
|
2436
|
+
double adjusted = local >= plateau_stop ? local - plateau : local;
|
|
2437
|
+
double angle = kernel->angular * (adjusted - t0);
|
|
2438
|
+
double sine = sin(angle);
|
|
2439
|
+
double cosine = cos(angle);
|
|
2440
|
+
double sine_power = 1.0;
|
|
2441
|
+
int in_plateau = local > midpoint && local < plateau_stop;
|
|
2442
|
+
size_t exponent;
|
|
2443
|
+
for (exponent = 0; exponent <= kernel->power; ++exponent) {
|
|
2444
|
+
basis[exponent] = sine_power;
|
|
2445
|
+
if (exponent & 1) basis[exponent] *= cosine;
|
|
2446
|
+
if (in_plateau) basis[exponent] = 0.0;
|
|
2447
|
+
sine_power *= sine;
|
|
2448
|
+
}
|
|
2449
|
+
for (index = 0; index < kernel->order; ++index)
|
|
2450
|
+
for (exponent = 0; exponent <= kernel->power; ++exponent)
|
|
2451
|
+
values[index] += kernel->derivatives[
|
|
2452
|
+
index * kernel->basis_count + exponent]
|
|
2453
|
+
* basis[exponent];
|
|
2454
|
+
if (in_plateau) values[0] = 1.0;
|
|
2352
2455
|
}
|
|
2353
|
-
for (index = 0; index < order; ++index) {
|
|
2354
|
-
components[0] += transform[index * 4
|
|
2355
|
-
components[1] += transform[index * 4 + 2] * values[index];
|
|
2456
|
+
for (index = 0; index < kernel->order; ++index) {
|
|
2457
|
+
components[0] += kernel->transform[index * 4] * values[index];
|
|
2458
|
+
components[1] += kernel->transform[index * 4 + 2] * values[index];
|
|
2356
2459
|
}
|
|
2357
|
-
components[0] /= normalization;
|
|
2358
|
-
components[1] /= normalization;
|
|
2460
|
+
components[0] /= kernel->normalization;
|
|
2461
|
+
components[1] /= kernel->normalization;
|
|
2359
2462
|
{
|
|
2360
2463
|
double carrier = 2.0 * 3.14159265358979323846
|
|
2361
2464
|
* (frequency + delta) * local
|
|
2362
2465
|
- (2.0 * 3.14159265358979323846 * delta * t0 + phase);
|
|
2363
|
-
|
|
2364
|
-
+ components[1] * sin(carrier);
|
|
2365
|
-
free(transform); free(derivatives); free(basis); free(values);
|
|
2366
|
-
return result;
|
|
2466
|
+
return components[0] * cos(carrier) + components[1] * sin(carrier);
|
|
2367
2467
|
}
|
|
2368
2468
|
}
|
|
2369
2469
|
|
|
@@ -2521,11 +2621,13 @@ static double wf_evaluate_one(const cwaveform_wave *wave, double position,
|
|
|
2521
2621
|
}
|
|
2522
2622
|
case WF_OP_DRAG_SIN:
|
|
2523
2623
|
local = position - (double)node->shift / ticks;
|
|
2524
|
-
values[index] = wf_drag_sin_value(
|
|
2624
|
+
values[index] = wf_drag_sin_value(
|
|
2625
|
+
wave, index, node, local, 0);
|
|
2525
2626
|
break;
|
|
2526
2627
|
case WF_OP_DRAG_SINX:
|
|
2527
2628
|
local = position - (double)node->shift / ticks;
|
|
2528
|
-
values[index] = wf_drag_sin_value(
|
|
2629
|
+
values[index] = wf_drag_sin_value(
|
|
2630
|
+
wave, index, node, local, 1);
|
|
2529
2631
|
break;
|
|
2530
2632
|
case WF_OP_ADD:
|
|
2531
2633
|
values[index] = values[node->left] + values[node->right];
|
|
@@ -3405,6 +3507,8 @@ cwaveform_stack *cwaveform_stack_create(
|
|
|
3405
3507
|
stack = (cwaveform_stack *)calloc(1, sizeof(*stack));
|
|
3406
3508
|
if (stack == NULL) return NULL;
|
|
3407
3509
|
stack->references = 1;
|
|
3510
|
+
stack->lower_tick = INT64_MIN;
|
|
3511
|
+
stack->upper_tick = INT64_MAX;
|
|
3408
3512
|
stack->template_count = template_count;
|
|
3409
3513
|
stack->event_count = event_count;
|
|
3410
3514
|
stack->templates = (cwaveform_wave **)calloc(template_count,
|
|
@@ -3435,6 +3539,26 @@ cwaveform_stack *cwaveform_stack_create(
|
|
|
3435
3539
|
stack->delays[index] = delay_ticks[index];
|
|
3436
3540
|
stack->scales[index] = scales[index];
|
|
3437
3541
|
}
|
|
3542
|
+
if (event_count != 0) {
|
|
3543
|
+
int have_support = 0;
|
|
3544
|
+
int64_t lower_tick = INT64_MAX;
|
|
3545
|
+
int64_t upper_tick = INT64_MIN;
|
|
3546
|
+
for (index = 0; index < event_count; ++index) {
|
|
3547
|
+
cwaveform_wave *wave = stack->templates[stack->template_ids[index]];
|
|
3548
|
+
int64_t lower = wf_add_tick(
|
|
3549
|
+
wave->nodes[wave->root].lower, stack->delays[index]);
|
|
3550
|
+
int64_t upper = wf_add_tick(
|
|
3551
|
+
wave->nodes[wave->root].upper, stack->delays[index]);
|
|
3552
|
+
if (lower >= upper) continue;
|
|
3553
|
+
if (!have_support || lower < lower_tick) lower_tick = lower;
|
|
3554
|
+
if (!have_support || upper > upper_tick) upper_tick = upper;
|
|
3555
|
+
have_support = 1;
|
|
3556
|
+
}
|
|
3557
|
+
if (have_support) {
|
|
3558
|
+
stack->lower_tick = lower_tick;
|
|
3559
|
+
stack->upper_tick = upper_tick;
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3438
3562
|
if (wf_stack_encode(stack) != 0) {
|
|
3439
3563
|
cwaveform_stack_release(stack);
|
|
3440
3564
|
return NULL;
|
|
@@ -3727,6 +3851,14 @@ size_t cwaveform_stack_template_count(const cwaveform_stack *stack) {
|
|
|
3727
3851
|
return stack == NULL ? 0 : stack->template_count;
|
|
3728
3852
|
}
|
|
3729
3853
|
|
|
3854
|
+
int64_t cwaveform_stack_lower_tick(const cwaveform_stack *stack) {
|
|
3855
|
+
return stack == NULL ? INT64_MIN : stack->lower_tick;
|
|
3856
|
+
}
|
|
3857
|
+
|
|
3858
|
+
int64_t cwaveform_stack_upper_tick(const cwaveform_stack *stack) {
|
|
3859
|
+
return stack == NULL ? INT64_MAX : stack->upper_tick;
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3730
3862
|
static size_t wf_lower_bound(const double *values, size_t count, double target) {
|
|
3731
3863
|
size_t first = 0;
|
|
3732
3864
|
while (count != 0) {
|
|
@@ -145,6 +145,8 @@ CWAVEFORM_API const uint8_t *cwaveform_stack_bytes(const cwaveform_stack *stack,
|
|
|
145
145
|
CWAVEFORM_API uint64_t cwaveform_stack_hash(const cwaveform_stack *stack);
|
|
146
146
|
CWAVEFORM_API size_t cwaveform_stack_event_count(const cwaveform_stack *stack);
|
|
147
147
|
CWAVEFORM_API size_t cwaveform_stack_template_count(const cwaveform_stack *stack);
|
|
148
|
+
CWAVEFORM_API int64_t cwaveform_stack_lower_tick(const cwaveform_stack *stack);
|
|
149
|
+
CWAVEFORM_API int64_t cwaveform_stack_upper_tick(const cwaveform_stack *stack);
|
|
148
150
|
CWAVEFORM_API int cwaveform_stack_evaluate(
|
|
149
151
|
const cwaveform_stack *stack, const double *positions, size_t count,
|
|
150
152
|
int64_t global_shift, double offset, double *output);
|
|
@@ -521,6 +521,8 @@ cdef extern from "_cwaveform.h":
|
|
|
521
521
|
uint64_t cwaveform_stack_hash(const cwaveform_stack *) noexcept nogil
|
|
522
522
|
size_t cwaveform_stack_event_count(const cwaveform_stack *) noexcept nogil
|
|
523
523
|
size_t cwaveform_stack_template_count(const cwaveform_stack *) noexcept nogil
|
|
524
|
+
int64_t cwaveform_stack_lower_tick(const cwaveform_stack *) noexcept nogil
|
|
525
|
+
int64_t cwaveform_stack_upper_tick(const cwaveform_stack *) noexcept nogil
|
|
524
526
|
int cwaveform_stack_evaluate(
|
|
525
527
|
const cwaveform_stack *, const double *, size_t, int64_t, double,
|
|
526
528
|
double *) noexcept nogil
|
|
@@ -1040,6 +1042,16 @@ cdef class CWaveformStackCore:
|
|
|
1040
1042
|
self._ensure_pointer()
|
|
1041
1043
|
return cwaveform_stack_template_count(self._pointer)
|
|
1042
1044
|
|
|
1045
|
+
@property
|
|
1046
|
+
def lower_tick(self):
|
|
1047
|
+
self._ensure_pointer()
|
|
1048
|
+
return cwaveform_stack_lower_tick(self._pointer)
|
|
1049
|
+
|
|
1050
|
+
@property
|
|
1051
|
+
def upper_tick(self):
|
|
1052
|
+
self._ensure_pointer()
|
|
1053
|
+
return cwaveform_stack_upper_tick(self._pointer)
|
|
1054
|
+
|
|
1043
1055
|
@property
|
|
1044
1056
|
def hash64(self):
|
|
1045
1057
|
self._ensure_pointer()
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Define version number here and read it from setup.py automatically"""
|
|
2
|
-
__version__ = "3.
|
|
2
|
+
__version__ = "3.4.0"
|
|
@@ -39,18 +39,6 @@ _ONE_EXPR = ((((), ()),), (1.0,))
|
|
|
39
39
|
_COMPLEX_WAVE_MAGIC = b"CWF1"
|
|
40
40
|
_COMPLEX_STACK_MAGIC = b"CWS1"
|
|
41
41
|
_COMPLEX_HEADER = struct.Struct("<4sII")
|
|
42
|
-
_SUPPORTED_SAMPLE_RATES = frozenset({
|
|
43
|
-
500_000_000,
|
|
44
|
-
1_000_000_000,
|
|
45
|
-
1_200_000_000,
|
|
46
|
-
2_000_000_000,
|
|
47
|
-
2_400_000_000,
|
|
48
|
-
2_500_000_000,
|
|
49
|
-
4_000_000_000,
|
|
50
|
-
6_000_000_000,
|
|
51
|
-
8_000_000_000,
|
|
52
|
-
10_000_000_000,
|
|
53
|
-
})
|
|
54
42
|
_INF_TICK = np.iinfo(np.int64).max
|
|
55
43
|
_C_CLOCK_ACTIVE = get_time_resolution() == 1 / _CORE_TICKS_PER_SECOND
|
|
56
44
|
_C_CLOCK_LOCKED = False
|
|
@@ -206,12 +194,12 @@ def _is_tick_aligned(value, tick):
|
|
|
206
194
|
|
|
207
195
|
|
|
208
196
|
def _sampling_plan(start, stop, sample_rate):
|
|
209
|
-
"""Return an integer/rational tick plan for
|
|
197
|
+
"""Return an integer/rational tick plan for an integral-Hz device rate."""
|
|
210
198
|
rate = float(sample_rate)
|
|
211
199
|
if not np.isfinite(rate) or rate <= 0:
|
|
212
200
|
raise ValueError("sample_rate must be a finite positive number")
|
|
213
201
|
integer_rate = int(rate)
|
|
214
|
-
if rate != integer_rate
|
|
202
|
+
if rate != integer_rate:
|
|
215
203
|
return None
|
|
216
204
|
start_tick = time_to_tick(start)
|
|
217
205
|
stop_tick = time_to_tick(stop)
|
|
@@ -357,6 +345,10 @@ class Waveform(metaclass=_WaveformMeta):
|
|
|
357
345
|
sample_rate: float | None
|
|
358
346
|
filters: tuple[np.ndarray, float] | None
|
|
359
347
|
|
|
348
|
+
def is_zero(self):
|
|
349
|
+
"""Return whether this object has no non-zero waveform support."""
|
|
350
|
+
return self.begin >= self.end
|
|
351
|
+
|
|
360
352
|
@classmethod
|
|
361
353
|
def from_bytes(cls, data):
|
|
362
354
|
"""Restore any waveform kind from its canonical binary block."""
|
|
@@ -809,6 +801,17 @@ class WaveVStack(Waveform, metaclass=_WaveVStackMeta):
|
|
|
809
801
|
return RealWaveVStack.from_bytes(data)
|
|
810
802
|
return RealWaveVStack.from_bytes(data)
|
|
811
803
|
|
|
804
|
+
@classmethod
|
|
805
|
+
def from_events(cls, templates, template_ids, delay_ticks, scales):
|
|
806
|
+
"""Build a real stack from compiler-native event columns.
|
|
807
|
+
|
|
808
|
+
``delay_ticks`` uses the process-wide integer clock. This entry point
|
|
809
|
+
avoids constructing one temporary Python waveform per event.
|
|
810
|
+
"""
|
|
811
|
+
return RealWaveVStack.from_events(
|
|
812
|
+
templates, template_ids, delay_ticks, scales
|
|
813
|
+
)
|
|
814
|
+
|
|
812
815
|
|
|
813
816
|
class _RealWaveVStackBase(WaveVStack):
|
|
814
817
|
"""Common real-stack type; concrete storage is provided by the C core."""
|
|
@@ -1160,6 +1163,9 @@ class RealWaveform(_RealWaveformBase):
|
|
|
1160
1163
|
return (self._scale == 0.0
|
|
1161
1164
|
or self._core.lower_tick >= self._core.upper_tick)
|
|
1162
1165
|
|
|
1166
|
+
def is_zero(self):
|
|
1167
|
+
return self._is_zero()
|
|
1168
|
+
|
|
1163
1169
|
@property
|
|
1164
1170
|
def bounds(self):
|
|
1165
1171
|
lower = self.begin
|
|
@@ -1468,19 +1474,28 @@ class RealWaveVStack(_RealWaveVStackBase):
|
|
|
1468
1474
|
ids = []
|
|
1469
1475
|
delays = []
|
|
1470
1476
|
scales = []
|
|
1477
|
+
event_waves = []
|
|
1471
1478
|
for wave in waves:
|
|
1472
1479
|
if not isinstance(wave, RealWaveform):
|
|
1473
1480
|
raise TypeError("RealWaveVStack accepts RealWaveform objects")
|
|
1474
|
-
|
|
1475
|
-
|
|
1481
|
+
if wave._is_zero():
|
|
1482
|
+
continue
|
|
1483
|
+
key = wave._core.hash64
|
|
1484
|
+
template_id = None
|
|
1485
|
+
for candidate in template_map.get(key, ()):
|
|
1486
|
+
if templates[candidate] == wave._core:
|
|
1487
|
+
template_id = candidate
|
|
1488
|
+
break
|
|
1476
1489
|
if template_id is None:
|
|
1477
1490
|
template_id = len(templates)
|
|
1478
|
-
template_map[
|
|
1491
|
+
template_map.setdefault(key, []).append(template_id)
|
|
1479
1492
|
templates.append(wave._core)
|
|
1480
1493
|
ids.append(template_id)
|
|
1481
1494
|
delays.append(wave._delay_tick)
|
|
1482
1495
|
scales.append(wave._scale)
|
|
1496
|
+
event_waves.append(wave)
|
|
1483
1497
|
_core = _CWaveformStackCore.from_events(templates, ids, delays, scales)
|
|
1498
|
+
waves = tuple(event_waves)
|
|
1484
1499
|
self._core = _core
|
|
1485
1500
|
self.start = None
|
|
1486
1501
|
self.stop = None
|
|
@@ -1494,6 +1509,19 @@ class RealWaveVStack(_RealWaveVStackBase):
|
|
|
1494
1509
|
self._waves_cache = tuple(waves) if waves else None
|
|
1495
1510
|
self._eval_core_cache = None
|
|
1496
1511
|
|
|
1512
|
+
@classmethod
|
|
1513
|
+
def from_events(cls, templates, template_ids, delay_ticks, scales):
|
|
1514
|
+
_ensure_c_clock_locked()
|
|
1515
|
+
templates = tuple(templates)
|
|
1516
|
+
if not all(isinstance(template, RealWaveform)
|
|
1517
|
+
for template in templates):
|
|
1518
|
+
raise TypeError("templates must contain RealWaveform objects")
|
|
1519
|
+
cores = [template._materialized_core() for template in templates]
|
|
1520
|
+
core = _CWaveformStackCore.from_events(
|
|
1521
|
+
cores, template_ids, delay_ticks, scales
|
|
1522
|
+
)
|
|
1523
|
+
return cls(_core=core)
|
|
1524
|
+
|
|
1497
1525
|
@property
|
|
1498
1526
|
def shift(self):
|
|
1499
1527
|
return _c_tick_to_time(self._shift_tick)
|
|
@@ -1510,20 +1538,29 @@ class RealWaveVStack(_RealWaveVStackBase):
|
|
|
1510
1538
|
|
|
1511
1539
|
@property
|
|
1512
1540
|
def begin(self):
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
value = -inf
|
|
1541
|
+
tick = self._core.lower_tick
|
|
1542
|
+
value = (-inf if tick == np.iinfo(np.int64).min
|
|
1543
|
+
else _c_tick_to_time(tick + self._shift_tick))
|
|
1517
1544
|
return value if self.start is None else max(self.start, value)
|
|
1518
1545
|
|
|
1519
1546
|
@property
|
|
1520
1547
|
def end(self):
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
value = inf
|
|
1548
|
+
tick = self._core.upper_tick
|
|
1549
|
+
value = (inf if tick == np.iinfo(np.int64).max
|
|
1550
|
+
else _c_tick_to_time(tick + self._shift_tick))
|
|
1525
1551
|
return value if self.stop is None else min(self.stop, value)
|
|
1526
1552
|
|
|
1553
|
+
@property
|
|
1554
|
+
def event_count(self):
|
|
1555
|
+
return self._core.event_count
|
|
1556
|
+
|
|
1557
|
+
@property
|
|
1558
|
+
def template_count(self):
|
|
1559
|
+
return self._core.template_count
|
|
1560
|
+
|
|
1561
|
+
def __len__(self):
|
|
1562
|
+
return self._core.event_count
|
|
1563
|
+
|
|
1527
1564
|
def __call__(self, x, out=None, accumulate=False, **kwargs):
|
|
1528
1565
|
scalar = isinstance(x, (int, float, np.number))
|
|
1529
1566
|
raw_positions = np.asarray([x] if scalar else x)
|
|
@@ -1962,9 +1999,8 @@ def sinh(w):
|
|
|
1962
1999
|
return RealWaveform._from_core(_scalar(SINH, w))
|
|
1963
2000
|
|
|
1964
2001
|
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
return zero()
|
|
2002
|
+
@lru_cache(maxsize=1024)
|
|
2003
|
+
def _cosh_pulse_core(width, eps, plateau):
|
|
1968
2004
|
w = eps / width
|
|
1969
2005
|
amplitude = np.cosh(eps / 2)
|
|
1970
2006
|
scale = -1 / (amplitude - 1)
|
|
@@ -1975,12 +2011,25 @@ def coshPulse(width, eps=1.0, plateau=0.0):
|
|
|
1975
2011
|
offset=amplitude / (amplitude - 1),
|
|
1976
2012
|
)
|
|
1977
2013
|
|
|
1978
|
-
if plateau == 0
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2014
|
+
if (plateau == 0
|
|
2015
|
+
or quantize_time(-plateau / 2) == quantize_time(plateau / 2)):
|
|
2016
|
+
waveform = _piecewise(
|
|
2017
|
+
(-width / 2, width / 2, inf), 0, edge(0), 0
|
|
2018
|
+
)
|
|
2019
|
+
else:
|
|
2020
|
+
waveform = _piecewise(
|
|
2021
|
+
(-width / 2 - plateau / 2, -plateau / 2, plateau / 2,
|
|
2022
|
+
width / 2 + plateau / 2, inf),
|
|
2023
|
+
0, edge(-plateau / 2), 1, edge(plateau / 2), 0,
|
|
2024
|
+
)
|
|
2025
|
+
return waveform._materialized_core()
|
|
2026
|
+
|
|
2027
|
+
|
|
2028
|
+
def coshPulse(width, eps=1.0, plateau=0.0):
|
|
2029
|
+
if width <= 0 and plateau <= 0:
|
|
2030
|
+
return zero()
|
|
2031
|
+
return RealWaveform._from_core(
|
|
2032
|
+
_cosh_pulse_core(float(width), float(eps), float(plateau))
|
|
1984
2033
|
)
|
|
1985
2034
|
|
|
1986
2035
|
|
|
@@ -2236,6 +2285,8 @@ __all__ = [
|
|
|
2236
2285
|
"gaussian", "general_cosine", "get_time_resolution", "hanning",
|
|
2237
2286
|
"interp", "mixing", "mollifier", "one", "play", "poly",
|
|
2238
2287
|
"registerBaseFunc", "registerDerivative", "samplingPoints",
|
|
2239
|
-
"
|
|
2288
|
+
"sample_clock", "sample_grid", "quantize_time", "time_to_tick",
|
|
2289
|
+
"tick_to_time", "set_time_resolution", "sign", "sin", "sinc",
|
|
2290
|
+
"sinh", "slepian",
|
|
2240
2291
|
"square", "step", "t", "wave_eval", "zero", "e", "inf", "pi",
|
|
2241
2292
|
]
|
|
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
|