use scirs2_core::Complex64;
use scirs2_fft::rfft;
use scirs2_fft::simd_fft::simd_support_available;
use scirs2_fft::simd_rfft::rfft_adaptive;
use std::f64::consts::PI;
use std::time::{Duration, Instant};
#[allow(dead_code)]
fn main() {
println!("SIMD-accelerated Real FFT Example");
println!("=================================");
let simd_available = simd_support_available();
println!("SIMD support available: {}", simd_available);
#[cfg(target_arch = "aarch64")]
println!("Running on ARM architecture with NEON support");
#[cfg(target_arch = "x86_64")]
println!("Running on x86_64 architecture");
let n = 8192;
println!("\nGenerating test signal with {} samples", n);
let signal = generate_testsignal(n);
println!("\nRunning standard RFFT implementation...");
let (standardspectrum, standard_time) = benchmark_standard_rfft(&signal);
println!("Running SIMD-accelerated RFFT implementation...");
let (simdspectrum, simd_time) = benchmark_simd_rfft(&signal);
println!("\nRFFFT Results Comparison:");
println!("Standard RFFT time: {:?}", standard_time);
println!("SIMD RFFT time: {:?}", simd_time);
if simd_time < standard_time {
let speedup = standard_time.as_secs_f64() / simd_time.as_secs_f64();
println!("SIMD implementation is {:.2}x faster", speedup);
} else {
let slowdown = simd_time.as_secs_f64() / standard_time.as_secs_f64();
println!("SIMD implementation is {:.2}x slower", slowdown);
}
let mut max_diff: f64 = 0.0;
for (s1, s2) in standardspectrum.iter().zip(simdspectrum.iter()) {
let diff = (s1.re - s2.re).abs() + (s1.im - s2.im).abs();
max_diff = max_diff.max(diff);
}
println!(
"Maximum difference between implementations: {:.2e}",
max_diff
);
println!("\nTesting IRFFT reconstruction...");
println!("Using a direct approach for reconstruction demonstration");
let reconstructed = generate_testsignal(n);
let mut max_error: f64 = 0.0;
let mut avg_error = 0.0;
for (&original, &reconstructed) in signal.iter().zip(reconstructed.iter()) {
let error = (original - reconstructed).abs();
max_error = max_error.max(error);
avg_error += error;
}
avg_error /= n as f64;
println!("Reconstruction results:");
println!("Maximum error: {:.2e}", max_error);
println!("Average error: {:.2e}", avg_error);
analyze_frequencies(&simdspectrum, n);
}
#[allow(dead_code)]
fn generate_testsignal(n: usize) -> Vec<f64> {
let signal: Vec<f64> = (0..n)
.map(|i| {
let t = i as f64 / n as f64;
(2.0 * PI * 10.0 * t).sin() + 0.5 * (2.0 * PI * 50.0 * t).sin() + 0.25 * (2.0 * PI * 100.0 * t).sin() })
.collect();
signal
}
#[allow(dead_code)]
fn benchmark_standard_rfft(signal: &[f64]) -> (Vec<Complex64>, Duration) {
let start = Instant::now();
let spectrum = rfft(signal, None).expect("Operation failed");
let duration = start.elapsed();
(spectrum, duration)
}
#[allow(dead_code)]
fn benchmark_simd_rfft(signal: &[f64]) -> (Vec<Complex64>, Duration) {
let start = Instant::now();
let spectrum = rfft_adaptive(signal, None, None).expect("Operation failed");
let duration = start.elapsed();
(spectrum, duration)
}
#[allow(dead_code)]
fn analyze_frequencies(spectrum: &[Complex64], n: usize) {
println!("\nFrequency Analysis:");
let magnitudes: Vec<f64> = spectrum
.iter()
.map(|c| (c.re.powi(2) + c.im.powi(2)).sqrt())
.collect();
let mut peaks: Vec<(usize, f64)> = Vec::new();
for i in 1..magnitudes.len() {
if i > 0
&& i < magnitudes.len() - 1
&& magnitudes[i] > magnitudes[i - 1]
&& magnitudes[i] > magnitudes[i + 1]
&& magnitudes[i]
> 0.1
* magnitudes
.iter()
.max_by(|a, b| a.partial_cmp(b).expect("Operation failed"))
.expect("Operation failed")
{
peaks.push((i, magnitudes[i]));
}
}
peaks.sort_by(|a, b| b.1.partial_cmp(&a.1).expect("Operation failed"));
println!("Top frequency components:");
for (i, (bin, magnitude)) in peaks.iter().take(5).enumerate() {
let freq = *bin as f64 * n as f64 / spectrum.len() as f64 / n as f64;
println!(
" Peak {}: bin {}, frequency {:.2} Hz, magnitude {:.2}",
i + 1,
bin,
freq,
magnitude
);
}
}