Against SciPy
Measured on 2026-11-06 with dspk 0.0.6, on NVIDIA GeForce RTX 2070 with Max-Q Design · Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz (12 threads) · Linux 7.2.15-300.fc45.x86_64.
One 384 × 60000 float32 block (2 s of Neuropixels at 30 kHz). Each time is the median of 5 calls after a warm-up, end to end from a NumPy array (upload, kernels, download) for dspk; scipy / numpy in float64 on the CPU. Error: max |dspk − scipy| / max |scipy|.
Time (ms)
Section titled “Time (ms)”| Operation | CUDA | wgpu | CPU runtime | SciPy / NumPy |
|---|---|---|---|---|
| zero-phase band-pass | 233 | 281 | 336 | 525 |
| causal band-pass | 202 | 257 | 258 | 259 |
| notch 60 Hz | 234 | 314 | 263 | 2461 |
| FIR 101 taps | 209 | 230 | 258 | 605 |
| median width 5 | 203 | 217 | 210 | 1042 |
| resample 1/3 | 156 | 194 | 163 | 556 |
| common median reference | 220 | 249 | 425 | 316 |
Most of each dspk time is the 92 MB transfer to the device and back. Chaining stages in a pipeline pays for that transfer once.
Agreement (largest difference, relative to SciPy’s peak)
Section titled “Agreement (largest difference, relative to SciPy’s peak)”| Operation | CUDA | wgpu | CPU runtime | Tolerance | Passed |
|---|---|---|---|---|---|
| zero-phase band-pass | 2.4e-06 | 2.4e-06 | 2.4e-06 | 1e-05 | yes |
| causal band-pass | 1.1e-06 | 1.1e-06 | 1.1e-06 | 1e-05 | yes |
| notch 60 Hz | 4.1e-06 | 4.3e-06 | 3.6e-06 | 1e-05 | yes |
| FIR 101 taps | 6.5e-07 | 6.5e-07 | 6.5e-07 | 1e-05 | yes |
| median width 5 | 0.0e+00 | 0.0e+00 | 0.0e+00 | 1e-06 | yes |
| resample 1/3 | 7.2e-07 | 7.2e-07 | 7.2e-07 | 1e-05 | yes |
| common median reference | 0.0e+00 | 0.0e+00 | 0.0e+00 | 1e-06 | yes |
dspk works in float32 on the device, and SciPy in float64, so filters agree to float32 level. Median and common median reference are exact.


Run it yourself
Section titled “Run it yourself”uv run python benchmarks/signal-operations/scipy_timing.py --repeats 5Build with maturin develop --release first, and run each benchmark in a fresh process.