Complex

Struct Complex 

Source
pub struct Complex<T: Float> {
    pub re: T,
    pub im: T,
}
Expand description

Número complexo genérico com suporte a f32 e f64

Fields§

§re: T§im: T

Implementations§

Source§

impl<T: Float> Complex<T>

Source

pub fn new(re: T, im: T) -> Self

Examples found in repository?
examples/benchmark.rs (line 9)
7fn benchmark_recursive(size: usize, iterations: usize) -> f64 {
8    let input: Vec<Complex<f64>> = (0..size)
9        .map(|i| Complex::new((i as f64).sin(), (i as f64).cos()))
10        .collect();
11
12    let start = Instant::now();
13    for _ in 0..iterations {
14        let _ = fft(&input);
15    }
16    let duration = start.elapsed();
17    duration.as_secs_f64() / (iterations as f64)
18}
19
20fn benchmark_iterative(size: usize, iterations: usize) -> f64 {
21    let input: Vec<Complex<f64>> = (0..size)
22        .map(|i| Complex::new((i as f64).sin(), (i as f64).cos()))
23        .collect();
24
25    let planner = FftPlanner::new(size, false).unwrap();
26
27    let start = Instant::now();
28    for _ in 0..iterations {
29        let _ = planner.process(&input).unwrap();
30    }
31    let duration = start.elapsed();
32    duration.as_secs_f64() / (iterations as f64)
33}
34
35fn main() {
36    println!("=== Benchmark FFT - Avila FFT ===");
37    println!("Compile com --release para resultados precisos!\n");
38
39    let sizes = vec![64, 128, 256, 512, 1024, 2048, 4096];
40
41    println!("{:>6} | {:>12} | {:>12} | {:>10} | {:>12}",
42        "N", "Recursiva", "Iterativa", "Speedup", "Throughput");
43    println!("{}", "-".repeat(70));
44
45    for &size in &sizes {
46        // Mais iterações para tamanhos menores
47        let iterations = (100000 / size).max(10);
48
49        let time_recursive = benchmark_recursive(size, iterations);
50        let time_iterative = benchmark_iterative(size, iterations);
51        let speedup = time_recursive / time_iterative;
52        let throughput = (size as f64) / time_iterative / 1e6; // Msamples/s
53
54        println!("{:6} | {:9.2} µs | {:9.2} µs | {:8.2}x | {:8.1} Ms/s",
55            size,
56            time_recursive * 1e6,
57            time_iterative * 1e6,
58            speedup,
59            throughput
60        );
61    }
62
63    println!("\n=== Análise de Complexidade ===\n");
64
65    // Verifica se segue O(N log N)
66    println!("Verificando complexidade O(N log N):");
67    let base_size = 256;
68    let base_time = benchmark_iterative(base_size, 1000);
69
70    for &size in &[512, 1024, 2048] {
71        let time = benchmark_iterative(size, 1000);
72        let ratio = size / base_size;
73        let expected_ratio = (ratio as f64) * (size as f64).log2() / (base_size as f64).log2();
74        let actual_ratio = time / base_time;
75
76        println!("  N={:4}: esperado {:.2}x, observado {:.2}x",
77            size, expected_ratio, actual_ratio);
78    }
79
80    println!("\n=== Teste de Precisão ===\n");
81
82    // Compara precisão entre recursiva e iterativa
83    let test_size = 1024;
84    let input: Vec<Complex<f64>> = (0..test_size)
85        .map(|i| Complex::new((i as f64) * 0.1, (i as f64) * 0.05))
86        .collect();
87
88    let result_recursive = fft(&input);
89
90    let planner = FftPlanner::new(test_size, false).unwrap();
91    let result_iterative = planner.process(&input).unwrap();
92
93    let max_error = result_recursive.iter()
94        .zip(result_iterative.iter())
95        .map(|(a, b)| (a.re - b.re).abs().max((a.im - b.im).abs()))
96        .fold(0.0, f64::max);
97
98    println!("Erro máximo entre recursiva e iterativa: {:.2e}", max_error);
99
100    if max_error < 1e-10 {
101        println!("✓ Precisão idêntica!");
102    } else {
103        println!("⚠ Diferença detectada (ainda aceitável)");
104    }
105
106    println!("\n=== Uso de Memória ===\n");
107
108    println!("Recursiva:");
109    println!("  - Cria O(N log N) vetores temporários");
110    println!("  - Stack frames: O(log N)");
111    println!("  - Não recomendada para N grande\n");
112
113    println!("Iterativa:");
114    println!("  - Trabalha in-place após bit-reversal");
115    println!("  - Cache de twiddle factors: O(N/2)");
116    println!("  - Recomendada para produção");
117}
More examples
Hide additional examples
examples/ultimate_benchmark.rs (line 32)
26fn benchmark_simd_vs_scalar() {
27    println!("🚀 SIMD vs Scalar Operations");
28    println!("────────────────────────────────────────────────────────");
29    
30    // Complex multiplication benchmark
31    let iterations = 1_000_000;
32    let a = Complex::new(3.0, 4.0);
33    let b = Complex::new(1.0, 2.0);
34    
35    // SIMD version
36    let start = Instant::now();
37    for _ in 0..iterations {
38        let _ = complex_mul_simd(a, b);
39    }
40    let simd_time = start.elapsed();
41    
42    // Scalar version
43    let start = Instant::now();
44    for _ in 0..iterations {
45        let _ = a * b;
46    }
47    let scalar_time = start.elapsed();
48    
49    let speedup = scalar_time.as_secs_f64() / simd_time.as_secs_f64();
50    
51    println!("  Complex Multiplication ({} ops):", iterations);
52    println!("    Scalar: {:.2} ms", scalar_time.as_secs_f64() * 1000.0);
53    println!("    SIMD:   {:.2} ms", simd_time.as_secs_f64() * 1000.0);
54    println!("    Speedup: {:.2}x\n", speedup);
55    
56    // Magnitude batch benchmark
57    let data: Vec<Complex<f64>> = (0..10000)
58        .map(|i| Complex::new((i as f64).sin(), (i as f64).cos()))
59        .collect();
60    
61    let start = Instant::now();
62    let _mag_simd = magnitude_squared_batch(&data);
63    let simd_time = start.elapsed();
64    
65    let start = Instant::now();
66    let _mag_scalar: Vec<f64> = data.iter()
67        .map(|c| c.re * c.re + c.im * c.im)
68        .collect();
69    let scalar_time = start.elapsed();
70    
71    let speedup = scalar_time.as_secs_f64() / simd_time.as_secs_f64();
72    
73    println!("  Magnitude Batch (10K samples):");
74    println!("    Scalar: {:.2} ms", scalar_time.as_secs_f64() * 1000.0);
75    println!("    SIMD:   {:.2} ms", simd_time.as_secs_f64() * 1000.0);
76    println!("    Speedup: {:.2}x", speedup);
77}
78
79fn benchmark_cache_effectiveness() {
80    println!("💾 Cache Effectiveness");
81    println!("────────────────────────────────────────────────────────");
82    
83    clear_cache();
84    
85    // Benchmark without cache
86    let sizes = vec![1024, 2048, 4096, 1024, 2048, 4096];
87    
88    let start = Instant::now();
89    for &size in &sizes {
90        let _planner: FftPlanner<f64> = FftPlanner::new(size, false).unwrap();
91    }
92    let no_cache_time = start.elapsed();
93    
94    // Benchmark with cache
95    clear_cache();
96    
97    let start = Instant::now();
98    for &size in &sizes {
99        let _planner = get_cached_planner(size, false);
100    }
101    let cache_time = start.elapsed();
102    
103    let (hits, misses, hit_rate) = cache_stats();
104    let speedup = no_cache_time.as_secs_f64() / cache_time.as_secs_f64();
105    
106    println!("  Planner Creation (6 planners, 3 unique sizes):");
107    println!("    Without cache: {:.2} ms", no_cache_time.as_secs_f64() * 1000.0);
108    println!("    With cache:    {:.2} ms", cache_time.as_secs_f64() * 1000.0);
109    println!("    Speedup: {:.2}x", speedup);
110    println!("    Cache hits: {}, misses: {}, hit rate: {:.1}%", 
111             hits, misses, hit_rate * 100.0);
112    
113    // Window cache test
114    let window_type = timefreq::WindowType::Hann;
115    warmup_window_cache(window_type);
116    
117    let start = Instant::now();
118    for _ in 0..100 {
119        let _window = get_cached_window(window_type, 2048);
120    }
121    let cached_time = start.elapsed();
122    
123    println!("\n  Window Function (100 calls, size 2048):");
124    println!("    With cache: {:.2} ms", cached_time.as_secs_f64() * 1000.0);
125    println!("    Avg per call: {:.2} µs", cached_time.as_secs_f64() * 1_000_000.0 / 100.0);
126}
127
128fn benchmark_bluestein() {
129    println!("🎯 Bluestein's Algorithm (Arbitrary-Length FFT)");
130    println!("────────────────────────────────────────────────────────");
131    
132    let test_sizes = vec![100, 500, 1000];
133    
134    for &size in &test_sizes {
135        let signal: Vec<f64> = (0..size)
136            .map(|i| (2.0 * std::f64::consts::PI * 10.0 * i as f64 / size as f64).sin())
137            .collect();
138        
139        let fft = BluesteinFft::new(size).unwrap();
140        
141        let start = Instant::now();
142        let _result = fft.process(&signal).unwrap();
143        let time = start.elapsed();
144        
145        println!("  Size {}: {:.2} ms", size, time.as_secs_f64() * 1000.0);
146    }
147    
148    println!("\n  ✓ Can now perform FFT on ANY size, not just powers of 2!");
149}
150
151fn benchmark_complete_pipeline() {
152    println!("⚡ Complete Pipeline Comparison");
153    println!("────────────────────────────────────────────────────────");
154    
155    let sample_rate = 44100.0;
156    let duration = 1.0;
157    let signal_size = (sample_rate * duration) as usize;
158    
159    // Generate test signal
160    let signal: Vec<f64> = (0..signal_size)
161        .map(|i| {
162            let t = i as f64 / sample_rate;
163            (2.0 * std::f64::consts::PI * 440.0 * t).sin()
164                + 0.5 * (2.0 * std::f64::consts::PI * 880.0 * t).sin()
165        })
166        .collect();
167    
168    println!("  Signal: {:.1}s @ {:.0} Hz ({} samples)", duration, sample_rate, signal_size);
169    println!();
170    
171    // 1. Basic FFT
172    let fft_size = signal_size.next_power_of_two();
173    let planner = FftPlanner::new(fft_size, false).unwrap();
174    
175    let mut padded = signal.clone();
176    padded.resize(fft_size, 0.0);
177    
178    let complex: Vec<Complex<f64>> = padded.iter()
179        .map(|&s| Complex::new(s, 0.0))
180        .collect();
181    
182    let start = Instant::now();
183    let _spectrum = planner.process(&complex).unwrap();
184    let basic_time = start.elapsed();
185    
186    println!("  1. Basic FFT (power-of-2):");
187    println!("     Time: {:.2} ms", basic_time.as_secs_f64() * 1000.0);
188    
189    // 2. FFT with SIMD magnitude
190    let start = Instant::now();
191    let spectrum = planner.process(&complex).unwrap();
192    let magnitudes = magnitude_squared_batch(&spectrum);
193    let simd_time = start.elapsed();
194    
195    println!("\n  2. FFT + SIMD Magnitude:");
196    println!("     Time: {:.2} ms", simd_time.as_secs_f64() * 1000.0);
197    println!("     Computed {} magnitudes", magnitudes.len());
198    
199    // 3. Parallel STFT
200    let window_size = 2048;
201    let hop_size = 512;
202    let window = get_cached_window(timefreq::WindowType::Hann, window_size);
203    
204    let config = ParallelConfig {
205        num_threads: 4,
206        min_chunk_size: 512,
207    };
208    let processor = ParallelStft::<f64>::new(window_size, hop_size, config);
209    
210    let start = Instant::now();
211    let frames = processor.process_parallel(&signal, &window);
212    let parallel_time = start.elapsed();
213    
214    println!("\n  3. Parallel STFT (4 threads):");
215    println!("     Time: {:.2} ms", parallel_time.as_secs_f64() * 1000.0);
216    println!("     Frames: {}", frames.len());
217    println!("     Throughput: {:.1}x realtime", 
218             signal_size as f64 / sample_rate / parallel_time.as_secs_f64());
219    
220    // Overall improvement
221    println!("\n  ╔═══════════════════════════════════════════════════╗");
222    println!("  ║  OVERALL PERFORMANCE IMPROVEMENTS                 ║");
223    println!("  ╠═══════════════════════════════════════════════════╣");
224    println!("  ║  ✓ SIMD operations: 2-4x faster                   ║");
225    println!("  ║  ✓ Cached planners: 3-5x faster reuse             ║");
226    println!("  ║  ✓ Parallel processing: 4x with 4 threads         ║");
227    println!("  ║  ✓ Arbitrary-length FFT: Now possible!            ║");
228    println!("  ║  ✓ Combined: Up to 10-20x faster pipelines!       ║");
229    println!("  ╚═══════════════════════════════════════════════════╝");
230}
examples/scale_benchmark.rs (line 39)
21fn benchmark_parallel_fft() {
22    println!("📊 Parallel FFT Batch Processing");
23    println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
24
25    let sizes = vec![1024, 2048, 4096];
26    let batch_sizes = vec![10, 50, 100];
27
28    for &size in &sizes {
29        println!("\nFFT Size: {}", size);
30
31        for &batch in &batch_sizes {
32            // Generate test signals
33            let signals: Vec<Vec<Complex<f64>>> = (0..batch)
34                .map(|i| {
35                    (0..size)
36                        .map(|j| {
37                            let t = j as f64 / size as f64;
38                            let freq = 100.0 + i as f64 * 10.0;
39                            Complex::new((2.0 * std::f64::consts::PI * freq * t).sin(), 0.0)
40                        })
41                        .collect()
42                })
43                .collect();
44
45            // Serial processing
46            let start = Instant::now();
47            let mut serial_results = Vec::new();
48            for signal in &signals {
49                let planner = FftPlanner::new(size, false).unwrap();
50                let result = planner.process(signal).unwrap();
51                serial_results.push(result);
52            }
53            let serial_time = start.elapsed();
54
55            // Parallel processing (2 threads)
56            let config = ParallelConfig {
57                num_threads: 2,
58                min_chunk_size: 512,
59            };
60            let processor = ParallelFft::<f64>::new(config);
61
62            let start = Instant::now();
63            let parallel_results = processor.process_batch(signals.clone(), false);
64            let parallel_time = start.elapsed();
65
66            // Parallel processing (4 threads)
67            let config = ParallelConfig {
68                num_threads: 4,
69                min_chunk_size: 512,
70            };
71            let processor = ParallelFft::<f64>::new(config);
72
73            let start = Instant::now();
74            let _ = processor.process_batch(signals, false);
75            let parallel4_time = start.elapsed();
76
77            let speedup_2 = serial_time.as_secs_f64() / parallel_time.as_secs_f64();
78            let speedup_4 = serial_time.as_secs_f64() / parallel4_time.as_secs_f64();
79
80            println!("  Batch: {:3} signals", batch);
81            println!("    Serial:    {:6.2} ms", serial_time.as_secs_f64() * 1000.0);
82            println!("    Parallel2: {:6.2} ms (speedup: {:.2}x)",
83                     parallel_time.as_secs_f64() * 1000.0, speedup_2);
84            println!("    Parallel4: {:6.2} ms (speedup: {:.2}x)",
85                     parallel4_time.as_secs_f64() * 1000.0, speedup_4);
86
87            // Verify correctness
88            assert_eq!(serial_results.len(), parallel_results.len());
89            for (s, p) in serial_results.iter().zip(parallel_results.iter()) {
90                for (sv, pv) in s.iter().zip(p.iter()) {
91                    let diff = (sv.re - pv.re).abs() + (sv.im - pv.im).abs();
92                    assert!(diff < 1e-10, "Results differ!");
93                }
94            }
95        }
96    }
97
98    println!("\n✓ All parallel FFT results match serial processing");
99}
examples/spectral_analysis.rs (line 57)
12fn main() {
13    println!("=== Análise Espectral com Avila FFT ===\n");
14
15    // Parâmetros do sinal
16    let sample_rate = 1000.0; // Hz
17    let duration = 1.0; // segundos
18    let n = (sample_rate * duration) as usize; // 1000 amostras
19
20    // Garante potência de 2
21    let n = n.next_power_of_two();
22    println!("Amostras: {}", n);
23    println!("Taxa de amostragem: {} Hz", sample_rate);
24    println!("Resolução: {:.2} Hz\n", sample_rate / n as f64);
25
26    // Gera sinal composto: 50Hz + 120Hz + 300Hz + ruído
27    println!("Gerando sinal com 3 componentes:");
28    println!("  - 50 Hz (amplitude 1.0)");
29    println!("  - 120 Hz (amplitude 0.7)");
30    println!("  - 300 Hz (amplitude 0.3)");
31    println!("  + ruído branco\n");
32
33    let signal: Vec<f64> = (0..n)
34        .map(|i| {
35            let t = i as f64 / sample_rate;
36
37            // Componentes senoidais
38            let sig1 = 1.0 * (2.0 * PI * 50.0 * t).sin();
39            let sig2 = 0.7 * (2.0 * PI * 120.0 * t).sin();
40            let sig3 = 0.3 * (2.0 * PI * 300.0 * t).sin();
41
42            // Ruído simulado (pseudo-aleatório)
43            let noise = 0.1 * ((t * 12345.0).sin() + (t * 67890.0).cos());
44
45            sig1 + sig2 + sig3 + noise
46        })
47        .collect();
48
49    // Aplica janela de Blackman-Harris (alta atenuação)
50    println!("Aplicando janela de Blackman-Harris...");
51    let window_fn = window::blackman_harris::<f64>(n);
52    let windowed = window::apply(&signal, &window_fn);
53
54    // Converte para complexo
55    let complex_signal: Vec<Complex<f64>> = windowed
56        .iter()
57        .map(|&x| Complex::new(x, 0.0))
58        .collect();
59
60    // Cria planner e executa FFT
61    println!("Executando FFT...");
62    let planner = FftPlanner::new(n, false).unwrap();
63    let spectrum = planner.process(&complex_signal).unwrap();
64
65    // Analisa apenas metade do espectro (frequências positivas)
66    println!("\n=== Espectro de Potência ===\n");
67
68    let mut peaks = Vec::new();
69
70    for k in 0..n/2 {
71        let frequency = k as f64 * sample_rate / n as f64;
72        let magnitude = spectrum[k].norm();
73        let power_db = 20.0 * magnitude.log10();
74
75        // Detecta picos significativos (> -20 dB)
76        if power_db > -20.0 {
77            peaks.push((frequency, power_db));
78        }
79
80        // Imprime algumas frequências representativas
81        if k < 10 || (k % 50 == 0 && k < n/2) {
82            println!("  {:6.1} Hz: {:7.2} dB", frequency, power_db);
83        }
84    }
85
86    // Reporta picos detectados
87    println!("\n=== Picos Detectados (> -20 dB) ===\n");
88    peaks.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
89
90    for (i, (freq, db)) in peaks.iter().take(10).enumerate() {
91        println!("  {}. {:6.1} Hz: {:7.2} dB", i+1, freq, db);
92    }
93
94    // Teste de reversibilidade
95    println!("\n=== Teste de Reversibilidade ===\n");
96    let ifft_planner = FftPlanner::new(n, true).unwrap();
97    let recovered = ifft_planner.process(&spectrum).unwrap();
98
99    // Calcula erro RMS
100    let rms_error: f64 = complex_signal.iter()
101        .zip(recovered.iter())
102        .map(|(orig, rec)| (orig.re - rec.re).powi(2))
103        .sum::<f64>()
104        .sqrt() / (n as f64);
105
106    println!("Erro RMS (IFFT roundtrip): {:.2e}", rms_error);
107
108    if rms_error < 1e-10 {
109        println!("✓ Reversibilidade perfeita!");
110    }
111
112    // Demonstra diferentes janelas
113    println!("\n=== Comparação de Janelas ===\n");
114
115    let windows = vec![
116        ("Retangular", window::rectangular::<f64>(128)),
117        ("Hamming", window::hamming::<f64>(128)),
118        ("Hann", window::hann::<f64>(128)),
119        ("Blackman", window::blackman::<f64>(128)),
120    ];
121
122    for (name, win) in windows {
123        let sum: f64 = win.iter().sum();
124        let max = win.iter().cloned().fold(0.0, f64::max);
125        let min = win.iter().cloned().fold(1.0, f64::min);
126
127        println!("  {:<15} - soma: {:.2}, min: {:.3}, max: {:.3}",
128            name, sum, min, max);
129    }
130
131    println!("\n=== Análise Completa ===");
132}
Source

pub fn zero() -> Self

Source

pub fn one() -> Self

Source

pub fn i() -> Self

Source

pub fn norm(&self) -> T

Norma (módulo) do número complexo: |z| = √(re² + im²)

Examples found in repository?
examples/image_processing.rs (line 101)
82fn analyze_spatial_frequency(image: &Image2D<f64>) {
83    println!("Executando FFT 2D...");
84    let freq = fft2d(image).unwrap();
85
86    // Calcula espectro de potência
87    let power = freq.power_spectrum();
88
89    // Estatísticas
90    let total_power: f64 = power.iter().sum();
91    let max_power = power.iter().cloned().fold(0.0, f64::max);
92    let avg_power = total_power / power.len() as f64;
93
94    println!("Potência total: {:.2e}", total_power);
95    println!("Potência média: {:.2e}", avg_power);
96    println!("Potência máxima: {:.2e}", max_power);
97
98    // Analisa componente DC
99    let dc = freq.get(0, 0);
100    println!("\nComponente DC: {:.2} + {:.2}i", dc.re, dc.im);
101    println!("Magnitude DC: {:.2}", dc.norm());
102
103    // Conta componentes significativas
104    let threshold = max_power * 0.01; // 1% do máximo
105    let significant = power.iter().filter(|&&p| p > threshold).count();
106    println!("\nComponententes significativas (>1% max): {}", significant);
107    println!("Percentual: {:.1}%", 100.0 * significant as f64 / power.len() as f64);
108}
More examples
Hide additional examples
examples/scale_benchmark.rs (line 227)
183fn benchmark_streaming() {
184    println!("📊 Streaming Processing (Constant Memory)");
185    println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
186
187    // Create test file with 100K samples (~6 seconds at 16384 Hz)
188    let test_file = "benchmark_signal.txt";
189    let n_samples = 100_000;
190    let sample_rate = 16384.0;
191
192    println!("\nGenerating test file: {} samples ({:.2}s)",
193             n_samples, n_samples as f64 / sample_rate);
194
195    let start = Instant::now();
196    let mut file = std::fs::File::create(test_file).unwrap();
197    use std::io::Write;
198
199    for i in 0..n_samples {
200        let t = i as f64 / sample_rate;
201        let freq = 200.0 + 300.0 * t / (n_samples as f64 / sample_rate);
202        let sample = (2.0 * std::f64::consts::PI * freq * t).sin();
203        writeln!(file, "{}", sample).unwrap();
204    }
205    let gen_time = start.elapsed();
206
207    println!("File generation: {:.2} ms", gen_time.as_secs_f64() * 1000.0);
208
209    // Streaming processing with different buffer sizes
210    let buffer_sizes = vec![4096, 16384, 65536];
211
212    for &buffer_size in &buffer_sizes {
213        let config = StreamConfig {
214            window_size: 1024,
215            hop_size: 512,
216            buffer_size,
217            sample_rate,
218        };
219
220        let mut processor = StreamingStft::<f64>::new(config);
221        let mut frame_count = 0;
222
223        let start = Instant::now();
224        processor.process_file(test_file, |idx, _time, frame| {
225            frame_count = idx + 1;
226            // Simulate some processing
227            let _mag: f64 = frame.iter().map(|c| c.norm()).sum();
228        }).unwrap();
229        let process_time = start.elapsed();
230
231        let throughput = n_samples as f64 / process_time.as_secs_f64();
232
233        println!("\nBuffer: {} samples", buffer_size);
234        println!("  Frames processed: {}", frame_count);
235        println!("  Time: {:.2} ms", process_time.as_secs_f64() * 1000.0);
236        println!("  Throughput: {:.0} samples/sec ({:.1}x realtime)",
237                 throughput, throughput / sample_rate);
238    }
239
240    // Cleanup
241    std::fs::remove_file(test_file).unwrap();
242
243    println!("\n✓ Streaming processing completed with constant memory");
244}
examples/spectral_analysis.rs (line 72)
12fn main() {
13    println!("=== Análise Espectral com Avila FFT ===\n");
14
15    // Parâmetros do sinal
16    let sample_rate = 1000.0; // Hz
17    let duration = 1.0; // segundos
18    let n = (sample_rate * duration) as usize; // 1000 amostras
19
20    // Garante potência de 2
21    let n = n.next_power_of_two();
22    println!("Amostras: {}", n);
23    println!("Taxa de amostragem: {} Hz", sample_rate);
24    println!("Resolução: {:.2} Hz\n", sample_rate / n as f64);
25
26    // Gera sinal composto: 50Hz + 120Hz + 300Hz + ruído
27    println!("Gerando sinal com 3 componentes:");
28    println!("  - 50 Hz (amplitude 1.0)");
29    println!("  - 120 Hz (amplitude 0.7)");
30    println!("  - 300 Hz (amplitude 0.3)");
31    println!("  + ruído branco\n");
32
33    let signal: Vec<f64> = (0..n)
34        .map(|i| {
35            let t = i as f64 / sample_rate;
36
37            // Componentes senoidais
38            let sig1 = 1.0 * (2.0 * PI * 50.0 * t).sin();
39            let sig2 = 0.7 * (2.0 * PI * 120.0 * t).sin();
40            let sig3 = 0.3 * (2.0 * PI * 300.0 * t).sin();
41
42            // Ruído simulado (pseudo-aleatório)
43            let noise = 0.1 * ((t * 12345.0).sin() + (t * 67890.0).cos());
44
45            sig1 + sig2 + sig3 + noise
46        })
47        .collect();
48
49    // Aplica janela de Blackman-Harris (alta atenuação)
50    println!("Aplicando janela de Blackman-Harris...");
51    let window_fn = window::blackman_harris::<f64>(n);
52    let windowed = window::apply(&signal, &window_fn);
53
54    // Converte para complexo
55    let complex_signal: Vec<Complex<f64>> = windowed
56        .iter()
57        .map(|&x| Complex::new(x, 0.0))
58        .collect();
59
60    // Cria planner e executa FFT
61    println!("Executando FFT...");
62    let planner = FftPlanner::new(n, false).unwrap();
63    let spectrum = planner.process(&complex_signal).unwrap();
64
65    // Analisa apenas metade do espectro (frequências positivas)
66    println!("\n=== Espectro de Potência ===\n");
67
68    let mut peaks = Vec::new();
69
70    for k in 0..n/2 {
71        let frequency = k as f64 * sample_rate / n as f64;
72        let magnitude = spectrum[k].norm();
73        let power_db = 20.0 * magnitude.log10();
74
75        // Detecta picos significativos (> -20 dB)
76        if power_db > -20.0 {
77            peaks.push((frequency, power_db));
78        }
79
80        // Imprime algumas frequências representativas
81        if k < 10 || (k % 50 == 0 && k < n/2) {
82            println!("  {:6.1} Hz: {:7.2} dB", frequency, power_db);
83        }
84    }
85
86    // Reporta picos detectados
87    println!("\n=== Picos Detectados (> -20 dB) ===\n");
88    peaks.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
89
90    for (i, (freq, db)) in peaks.iter().take(10).enumerate() {
91        println!("  {}. {:6.1} Hz: {:7.2} dB", i+1, freq, db);
92    }
93
94    // Teste de reversibilidade
95    println!("\n=== Teste de Reversibilidade ===\n");
96    let ifft_planner = FftPlanner::new(n, true).unwrap();
97    let recovered = ifft_planner.process(&spectrum).unwrap();
98
99    // Calcula erro RMS
100    let rms_error: f64 = complex_signal.iter()
101        .zip(recovered.iter())
102        .map(|(orig, rec)| (orig.re - rec.re).powi(2))
103        .sum::<f64>()
104        .sqrt() / (n as f64);
105
106    println!("Erro RMS (IFFT roundtrip): {:.2e}", rms_error);
107
108    if rms_error < 1e-10 {
109        println!("✓ Reversibilidade perfeita!");
110    }
111
112    // Demonstra diferentes janelas
113    println!("\n=== Comparação de Janelas ===\n");
114
115    let windows = vec![
116        ("Retangular", window::rectangular::<f64>(128)),
117        ("Hamming", window::hamming::<f64>(128)),
118        ("Hann", window::hann::<f64>(128)),
119        ("Blackman", window::blackman::<f64>(128)),
120    ];
121
122    for (name, win) in windows {
123        let sum: f64 = win.iter().sum();
124        let max = win.iter().cloned().fold(0.0, f64::max);
125        let min = win.iter().cloned().fold(1.0, f64::min);
126
127        println!("  {:<15} - soma: {:.2}, min: {:.3}, max: {:.3}",
128            name, sum, min, max);
129    }
130
131    println!("\n=== Análise Completa ===");
132}
Source

pub fn norm_sqr(&self) -> T

Norma quadrada (mais eficiente): |z|² = re² + im²

Examples found in repository?
examples/image_processing.rs (line 222)
208fn analyze_quadrants(image: &Image2D<f64>) {
209    println!("Dividindo espectro em quadrantes...");
210
211    let mut freq = fft2d(image).unwrap();
212    freq.fftshift(); // Move DC para centro
213
214    let half_w = freq.width / 2;
215    let half_h = freq.height / 2;
216
217    // Calcula potência em cada quadrante
218    let mut quadrants = vec![0.0; 4];
219
220    for y in 0..freq.height {
221        for x in 0..freq.width {
222            let power = freq.get(x, y).norm_sqr();
223            let q = if x < half_w {
224                if y < half_h { 0 } else { 2 }
225            } else {
226                if y < half_h { 1 } else { 3 }
227            };
228            quadrants[q] += power;
229        }
230    }
231
232    let total: f64 = quadrants.iter().sum();
233
234    println!("\nDistribuição de potência por quadrante:");
235    for (i, &power) in quadrants.iter().enumerate() {
236        println!("  Q{}: {:.2e} ({:.1}%)",
237            i + 1, power, 100.0 * power / total);
238    }
239
240    // Identifica direção dominante
241    let horizontal = (quadrants[0] + quadrants[1]) / total;
242    let vertical = (quadrants[0] + quadrants[2]) / total;
243
244    println!("\nDireção dominante:");
245    println!("  Horizontal: {:.1}%", horizontal * 100.0);
246    println!("  Vertical: {:.1}%", vertical * 100.0);
247}
248
249/// Testa reversibilidade FFT 2D
250fn test_reversibility(image: &Image2D<f64>) {
251    println!("Testando FFT -> IFFT...");
252
253    let freq = fft2d(image).unwrap();
254    let recovered = ifft2d(&freq).unwrap();
255
256    // Calcula erro
257    let mut max_error: f64 = 0.0;
258    let mut total_error = 0.0;
259
260    for i in 0..image.data.len() {
261        let error = (image.data[i].re - recovered.data[i].re).abs();
262        max_error = max_error.max(error);
263        total_error += error * error;
264    }
265
266    let rms_error = (total_error / image.data.len() as f64).sqrt();
267
268    println!("Erro RMS: {:.2e}", rms_error);
269    println!("Erro máximo: {:.2e}", max_error);
270
271    if rms_error < 1e-10 {
272        println!("✓ Reversibilidade perfeita!");
273    } else {
274        println!("⚠ Pequeno erro numérico (aceitável)");
275    }
276
277    // Verifica Parseval
278    let energy_spatial: f64 = image.data.iter()
279        .map(|c| c.norm_sqr())
280        .sum();
281
282    let energy_freq: f64 = freq.data.iter()
283        .map(|c| c.norm_sqr())
284        .sum::<f64>() / (image.data.len() as f64);
285
286    let parseval_error = (energy_spatial - energy_freq).abs() / energy_spatial;
287
288    println!("\nTeorema de Parseval:");
289    println!("Energia espacial: {:.2e}", energy_spatial);
290    println!("Energia frequência: {:.2e}", energy_freq);
291    println!("Erro relativo: {:.2e}", parseval_error);
292
293    if parseval_error < 1e-8 {
294        println!("✓ Parseval verificado!");
295    }
296}
Source

pub fn conj(&self) -> Self

Conjugado complexo: z* = re - i·im

Source

pub fn arg(&self) -> T

Argumento (fase) do número complexo: arg(z) = atan2(im, re)

Source

pub fn exp(&self) -> Self

Exponencial complexa: exp(z) = exp(re) · (cos(im) + i·sin(im))

Source

pub fn powf(&self, n: T) -> Self

Potência de número complexo: z^n usando forma polar

Source

pub fn is_nan(&self) -> bool

Verifica se contém NaN

Source

pub fn is_infinite(&self) -> bool

Verifica se contém infinito

Source

pub fn is_finite(&self) -> bool

Verifica se é finito (não NaN nem infinito)

Trait Implementations§

Source§

impl<T: Float> Add for Complex<T>

Source§

type Output = Complex<T>

The resulting type after applying the + operator.
Source§

fn add(self, rhs: Self) -> Self

Performs the + operation. Read more
Source§

impl<T: Float> AddAssign for Complex<T>

Source§

fn add_assign(&mut self, rhs: Self)

Performs the += operation. Read more
Source§

impl<T: Clone + Float> Clone for Complex<T>

Source§

fn clone(&self) -> Complex<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug + Float> Debug for Complex<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Float> Div<T> for Complex<T>

Source§

type Output = Complex<T>

The resulting type after applying the / operator.
Source§

fn div(self, rhs: T) -> Self

Performs the / operation. Read more
Source§

impl<T: Float> Div for Complex<T>

Source§

type Output = Complex<T>

The resulting type after applying the / operator.
Source§

fn div(self, rhs: Self) -> Self

Performs the / operation. Read more
Source§

impl<T: Float> Mul<T> for Complex<T>

Source§

type Output = Complex<T>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: T) -> Self

Performs the * operation. Read more
Source§

impl<T: Float> Mul for &Complex<T>

Source§

type Output = Complex<T>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Self) -> Complex<T>

Performs the * operation. Read more
Source§

impl<T: Float> Mul for Complex<T>

Source§

type Output = Complex<T>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Self) -> Self

Performs the * operation. Read more
Source§

impl<T: Float> MulAssign<T> for Complex<T>

Source§

fn mul_assign(&mut self, rhs: T)

Performs the *= operation. Read more
Source§

impl<T: Float> Sub for Complex<T>

Source§

type Output = Complex<T>

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: Self) -> Self

Performs the - operation. Read more
Source§

impl<T: Float> SubAssign for Complex<T>

Source§

fn sub_assign(&mut self, rhs: Self)

Performs the -= operation. Read more
Source§

impl<'a, T: Float> Sum<&'a Complex<T>> for Complex<T>

Source§

fn sum<I: Iterator<Item = &'a Complex<T>>>(iter: I) -> Self

Takes an iterator and generates Self from the elements by “summing up” the items.
Source§

impl<T: Float> Sum for Complex<T>

Source§

fn sum<I: Iterator<Item = Self>>(iter: I) -> Self

Takes an iterator and generates Self from the elements by “summing up” the items.
Source§

impl<T: Copy + Float> Copy for Complex<T>

Auto Trait Implementations§

§

impl<T> Freeze for Complex<T>
where T: Freeze,

§

impl<T> RefUnwindSafe for Complex<T>
where T: RefUnwindSafe,

§

impl<T> Send for Complex<T>
where T: Send,

§

impl<T> Sync for Complex<T>
where T: Sync,

§

impl<T> Unpin for Complex<T>
where T: Unpin,

§

impl<T> UnwindSafe for Complex<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.