Skip to main content

secs_dsp/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(unsafe_op_in_unsafe_fn)]
3//! f64 DSP primitives and optimizers with SciPy/NumPy semantics.
4//!
5//! Shared by `secs-engine`, `secs-mdat` (response caches), `secs-camilla`
6//! (FIR resampling) and `secs-audio` (sweep deconvolution). Functions match
7//! the NumPy/SciPy calls SECS 2 makes, including the details a port must keep
8//! (docs/ARCHITECTURE.md, "Numerics"):
9//!
10//! - FFT through cached `realfft` plans; pairwise summation where NumPy sums.
11//! - RBJ biquads, analog LR/BW prototypes, all-pass, minimum phase (cepstrum),
12//!   fractional-octave smoothing, group delay, `butter`/`sosfilt`/`firwin`,
13//!   `find_peaks` with the plateau-midpoint rule.
14//! - `least_squares` (bounded TRF, exact trust-region solver, two-point
15//!   Jacobians; `max_nfev` counts residual calls only), ported
16//!   from SciPy 1.18.1 by way of Impulcifer's `optimize.rs` (MIT).
17//! - Differential evolution uses legacy RandomState (MT19937) with SciPy's
18//!   immediate best1bin draw order and Latin-hypercube initialization.
19//! - Rounding is half-to-even (`f64::round_ties_even`) wherever NumPy rounds.
20//!
21//! There is no handwritten `std::arch`; faer SIMD dispatch is provided by pulp.
22//!
23//! New primitive APIs return `Result` for data-dependent upstream failures.
24//! Allocation failure or unrepresentable array/order sizes are programmer errors.
25//! FFT APIs retain their documented panic contract. TRF parity is partial;
26//! see `tests/golden.rs` and the feature registry before using it in an engine.
27
28pub mod convolution;
29pub mod fft;
30pub use fft::Complex64;
31pub mod fir;
32pub mod grid;
33pub mod iir;
34pub mod lowrate;
35pub mod minphase;
36pub mod multirate;
37mod numeric;
38pub use numeric::divide as complex_div;
39pub use numeric::interp;
40pub use numeric::sum as pairwise_sum;
41pub mod optimize;
42pub mod peaks;
43pub mod random;
44pub mod resample;
45pub mod response;
46pub mod smooth;
47
48/// Data-dependent errors corresponding to upstream invalid inputs.
49#[derive(Debug, thiserror::Error)]
50pub enum DspError {
51    #[error("{0}")]
52    InvalidArgument(String),
53}
54
55pub(crate) fn invalid(message: &str) -> DspError {
56    DspError::InvalidArgument(message.to_owned())
57}