scirs2_fft/sparse_fft/
config.rs

1//! Configuration types and utilities for Sparse FFT algorithms
2//!
3//! This module contains the configuration structures, enums, and utility functions
4//! used to configure and control sparse FFT computations.
5
6use scirs2_core::numeric::Complex64;
7use std::fmt::Debug;
8
9/// Helper function to extract complex values from various types (for doctests)
10#[allow(dead_code)]
11pub fn try_as_complex<T: 'static + Copy>(val: T) -> Option<Complex64> {
12    use std::any::Any;
13
14    // Try to use runtime type checking with Any for complex types
15    if let Some(complex) = (&val as &dyn Any).downcast_ref::<Complex64>() {
16        return Some(*complex);
17    }
18
19    // Try to handle f32 complex numbers
20    if let Some(complex32) = (&val as &dyn Any).downcast_ref::<scirs2_core::numeric::Complex<f32>>()
21    {
22        return Some(Complex64::new(complex32.re as f64, complex32.im as f64));
23    }
24
25    None
26}
27
28/// Sparsity estimation method
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum SparsityEstimationMethod {
31    /// Manual estimation (user provides the sparsity)
32    Manual,
33    /// Automatic estimation based on thresholding
34    Threshold,
35    /// Adaptive estimation based on signal properties
36    Adaptive,
37    /// Frequency domain pruning for high accuracy estimation
38    FrequencyPruning,
39    /// Spectral flatness measure for noise vs signal discrimination
40    SpectralFlatness,
41}
42
43/// Sparse FFT algorithm variant
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum SparseFFTAlgorithm {
46    /// Sublinear Sparse FFT
47    Sublinear,
48    /// Compressed Sensing-based Sparse FFT
49    CompressedSensing,
50    /// Iterative Method for Sparse FFT
51    Iterative,
52    /// Deterministic Sparse FFT
53    Deterministic,
54    /// Frequency-domain pruning approach
55    FrequencyPruning,
56    /// Advanced pruning using spectral flatness measure
57    SpectralFlatness,
58}
59
60/// Window function to apply before FFT
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum WindowFunction {
63    /// No windowing (rectangular window)
64    None,
65    /// Hann window (reduces spectral leakage)
66    Hann,
67    /// Hamming window (good for speech)
68    Hamming,
69    /// Blackman window (excellent sidelobe suppression)
70    Blackman,
71    /// Flat top window (best amplitude accuracy)
72    FlatTop,
73    /// Kaiser window with adjustable parameter
74    Kaiser,
75}
76
77/// Sparse FFT configuration
78#[derive(Debug, Clone)]
79pub struct SparseFFTConfig {
80    /// The sparsity estimation method
81    pub estimation_method: SparsityEstimationMethod,
82    /// Expected sparsity (k) - number of significant frequency components
83    pub sparsity: usize,
84    /// Algorithm variant to use
85    pub algorithm: SparseFFTAlgorithm,
86    /// Threshold for frequency coefficient significance (when using threshold method)
87    pub threshold: f64,
88    /// Number of iterations for iterative methods
89    pub iterations: usize,
90    /// Random seed for probabilistic algorithms
91    pub seed: Option<u64>,
92    /// Maximum signal size to process (to prevent test timeouts)
93    pub max_signal_size: usize,
94    /// Adaptivity parameter (controls how aggressive adaptivity is)
95    pub adaptivity_factor: f64,
96    /// Pruning parameter (controls sensitivity of frequency pruning)
97    pub pruning_sensitivity: f64,
98    /// Spectral flatness threshold (0-1, lower values = more selective)
99    pub flatness_threshold: f64,
100    /// Analysis window size for spectral flatness calculations
101    pub window_size: usize,
102    /// Window function to apply before FFT
103    pub window_function: WindowFunction,
104    /// Kaiser window beta parameter (when using Kaiser window)
105    pub kaiser_beta: f64,
106}
107
108impl Default for SparseFFTConfig {
109    fn default() -> Self {
110        Self {
111            estimation_method: SparsityEstimationMethod::Threshold,
112            sparsity: 10,
113            algorithm: SparseFFTAlgorithm::Sublinear,
114            threshold: 0.01,
115            iterations: 3,
116            seed: None,
117            max_signal_size: 1024, // Default max size to avoid test timeouts
118            adaptivity_factor: 0.25,
119            pruning_sensitivity: 0.05,
120            flatness_threshold: 0.3,
121            window_size: 16,
122            window_function: WindowFunction::None,
123            kaiser_beta: 14.0, // Default beta for Kaiser window
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn test_default_config() {
134        let config = SparseFFTConfig::default();
135        assert_eq!(config.sparsity, 10);
136        assert_eq!(config.threshold, 0.01);
137        assert_eq!(config.max_signal_size, 1024);
138    }
139
140    #[test]
141    fn test_try_as_complex() {
142        let val = Complex64::new(1.0, 2.0);
143        assert_eq!(try_as_complex(val), Some(val));
144
145        let val32 = scirs2_core::numeric::Complex::new(1.0f32, 2.0f32);
146        assert_eq!(try_as_complex(val32), Some(Complex64::new(1.0, 2.0)));
147    }
148}