Skip to main content

secs_engine/
grid.rs

1//! The design grid every full-resolution spectrum lives on.
2//!
3//! Upstream: `correction_engine.py` `SR`, `N_FFT`, `freqs()`.
4
5use std::sync::OnceLock;
6
7/// Design sample rate in Hz. Every measurement must use it (upstream checks
8/// only the main position; SECS 2R checks all, D2).
9pub const SR: u32 = 48_000;
10/// [`SR`] as a float, for arithmetic.
11pub const SR_F: f64 = 48_000.0;
12/// Design FFT length, 2^17 (0.366 Hz bins), enough to resolve low room modes.
13pub const N_FFT: usize = 1 << 17;
14/// Bins of a full design spectrum, `N_FFT / 2 + 1`.
15pub const BINS: usize = N_FFT / 2 + 1;
16
17/// `secs_dsp::grid::freqs(N_FFT, SR)`, computed once per process.
18pub fn design_freqs() -> &'static [f64] {
19    static F: OnceLock<Vec<f64>> = OnceLock::new();
20    F.get_or_init(|| {
21        let step = 1.0 / (N_FFT as f64 * (1.0 / SR_F));
22        (0..BINS).map(|k| k as f64 * step).collect()
23    })
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29
30    #[test]
31    fn design_grid_matches_the_dsp_primitive() {
32        let expected = secs_dsp::grid::freqs(N_FFT, SR_F).unwrap();
33        assert_eq!(design_freqs().len(), BINS);
34        assert!(
35            design_freqs()
36                .iter()
37                .zip(&expected)
38                .all(|(a, b)| a.to_bits() == b.to_bits())
39        );
40    }
41}