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