use std::f32::consts::PI;
use gpu_fft::fft;
mod common;
use common::{assert_approx, assert_slice_approx};
#[test]
fn test_fft_impulse() {
let n = 8;
let mut input = vec![0.0f32; n];
input[0] = 1.0;
let (real, imag) = fft(&input);
assert_slice_approx(&real, &[1.0; 8], "real");
assert_slice_approx(&imag, &[0.0; 8], "imag");
}
#[test]
fn test_fft_dc_signal() {
let n = 8;
let input = vec![1.0f32; n];
let (real, imag) = fft(&input);
assert_approx(real[0], n as f32, "real[0]");
assert_approx(imag[0], 0.0, "imag[0]");
for i in 1..n {
assert_approx(real[i], 0.0, &format!("real[{}]", i));
assert_approx(imag[i], 0.0, &format!("imag[{}]", i));
}
}
#[test]
fn test_fft_single_frequency_sine() {
let n = 8usize;
let half_n = n as f32 / 2.0;
let input: Vec<f32> = (0..n)
.map(|i| (2.0 * PI * i as f32 / n as f32).sin())
.collect();
let (real, imag) = fft(&input);
assert_approx(real[0], 0.0, "real[0] (DC)");
assert_approx(imag[0], 0.0, "imag[0] (DC)");
assert_approx(real[1], 0.0, "real[1]");
assert_approx(imag[1], -half_n, "imag[1]");
for k in 2..n - 1 {
assert_approx(real[k], 0.0, &format!("real[{}]", k));
assert_approx(imag[k], 0.0, &format!("imag[{}]", k));
}
assert_approx(real[n - 1], 0.0, &format!("real[{}]", n - 1));
assert_approx(imag[n - 1], half_n, &format!("imag[{}]", n - 1));
}
#[test]
fn test_fft_zero_input() {
let n = 8;
let (real, imag) = fft(&vec![0.0f32; n]);
assert_slice_approx(&real, &[0.0; 8], "real");
assert_slice_approx(&imag, &[0.0; 8], "imag");
}
#[test]
fn test_fft_linearity() {
let scale = 3.0f32;
let input = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let scaled_input: Vec<f32> = input.iter().map(|&x| x * scale).collect();
let (real_base, imag_base) = fft(&input);
let (real_scaled, imag_scaled) = fft(&scaled_input);
let n = real_base.len();
for i in 0..n {
assert_approx(
real_scaled[i],
real_base[i] * scale,
&format!("real[{}]", i),
);
assert_approx(
imag_scaled[i],
imag_base[i] * scale,
&format!("imag[{}]", i),
);
}
}
#[test]
fn test_fft_impulse_large_even() {
let n = 4096usize;
let mut input = vec![0.0f32; n];
input[0] = 1.0;
let (real, imag) = fft(&input);
assert_eq!(real.len(), n);
for k in 0..n {
assert_approx(real[k], 1.0, &format!("real[{k}]"));
assert_approx(imag[k], 0.0, &format!("imag[{k}]"));
}
}
#[test]
fn test_fft_impulse_large_odd() {
let n = 8192usize;
let mut input = vec![0.0f32; n];
input[0] = 1.0;
let (real, imag) = fft(&input);
assert_eq!(real.len(), n);
for k in 0..n {
assert_approx(real[k], 1.0, &format!("real[{k}]"));
assert_approx(imag[k], 0.0, &format!("imag[{k}]"));
}
}
#[test]
fn test_fft_dc_large() {
let n = 4096usize;
let input = vec![1.0f32; n];
let (real, imag) = fft(&input);
assert_approx(real[0], n as f32, "real[0]");
assert_approx(imag[0], 0.0, "imag[0]");
for k in 1..n {
assert_approx(real[k], 0.0, &format!("real[{k}]"));
assert_approx(imag[k], 0.0, &format!("imag[{k}]"));
}
}