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: TImplementations§
Source§impl<T: Float> Complex<T>
impl<T: Float> Complex<T>
Sourcepub fn new(re: T, im: T) -> Self
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
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}pub fn zero() -> Self
pub fn one() -> Self
pub fn i() -> Self
Sourcepub fn norm(&self) -> T
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
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}Sourcepub fn norm_sqr(&self) -> T
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}Sourcepub fn is_infinite(&self) -> bool
pub fn is_infinite(&self) -> bool
Verifica se contém infinito
Trait Implementations§
Source§impl<T: Float> AddAssign for Complex<T>
impl<T: Float> AddAssign for Complex<T>
Source§fn add_assign(&mut self, rhs: Self)
fn add_assign(&mut self, rhs: Self)
Performs the
+= operation. Read moreSource§impl<T: Float> MulAssign<T> for Complex<T>
impl<T: Float> MulAssign<T> for Complex<T>
Source§fn mul_assign(&mut self, rhs: T)
fn mul_assign(&mut self, rhs: T)
Performs the
*= operation. Read moreSource§impl<T: Float> SubAssign for Complex<T>
impl<T: Float> SubAssign for Complex<T>
Source§fn sub_assign(&mut self, rhs: Self)
fn sub_assign(&mut self, rhs: Self)
Performs the
-= operation. Read moreimpl<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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more