ezmsg.sigproc.util.sosfilt_direct#
Call scipy’s SOS kernel directly, skipping the per-call wrapper cost.
scipy.signal.sosfilt spends a fixed ~12-18 us per call on validation, dtype
resolution and shape bookkeeping before reaching its Cython kernel. That cost is
independent of chunk size, so it is invisible offline and dominant online:
- n_ch x N sosfilt direct saved
16 x 30 15.3 us 6.1 us 59.9% 32 x 30 18.4 us 9.0 us 51.0% 64 x 30 23.8 us 14.6 us 38.8%
256 x 30 59.2 us 49.3 us 16.6% 256 x 128 207.0 us 198.4 us 4.1%
This module reproduces sosfilt’s semantics exactly – same dtype promotion,
same layout, same Cython kernel – with the invariant work hoisted into
DirectSosfilt, built once per stream. Output is bit-identical to
scipy.signal.sosfilt, which is the point: it must be a pure latency
optimization, never a numerical one.
It depends on scipy.signal._sosfilt._sosfilt, a private entry point. Two
guards cover that: the import is optional, and available() verifies the
private kernel against the public function once per process before anything
trusts it. If either fails, callers fall back to scipy.signal.sosfilt and
the only consequence is the lost microseconds.
Note the state (zi) is deliberately kept in scipy’s public layout and
converted per call. Keeping it in the kernel’s layout would save a further
~10-15% but would change the meaning of FilterState.zi, which other code
reads; the conversion is cheap enough that the compatibility is worth more.
Module Attributes
Promoted dtypes the Cython kernel handles and for which we have verified equivalence. |
Functions
- available()[source]#
Whether the direct path may be used, verifying the private kernel once.
The check filters a small random signal through both the private kernel and
scipy.signal.sosfiltand requires bit-identical output and state. It runs at most once per process and costs well under a millisecond.- Return type:
Classes
- class DirectSosfilt(sos, dtype)[source]#
Bases:
objectA SOS filter with scipy’s per-call setup hoisted to construction.
Construction reproduces the validation
scipy.signal.sosfiltperforms via_validate_sos, and raises the same errors. That is not defensive tidiness: the Cython kernel assumesa0 == 1and silently filters with whatever it is given, so coefficients public scipy rejects would otherwise be accepted here and produce a different answer. Callers are expected to treat aValueErroras “fall back to public scipy” and let it raise the authoritative error.- Parameters:
sos (NDArray) –
(n_sections, 6)coefficients.dtype (DTypeLike) – The promoted dtype the stream will run in. Must match what
np.result_type(sos, data, zi)yields, orapply()would diverge from scipy;can_apply()is the guard for that.