arnaucube
arnaucube/fft-rsPublic Self-hosted repository
fft-rs/src/lib.rs
src/lib.rsRaw
  1use num::complex::{Complex, Complex64};
  2use std::f64::consts::PI;
  3
  4// dft computes the Discrete Fourier Transform
  5pub fn dft(x: &Vec<f64>) -> Vec<Complex64> {
  6    let mut x_compl: Vec<Complex64> = vec![Complex::new(0_f64, 0_f64); x.len()];
  7    for i in 0..x.len() {
  8        x_compl[i] = Complex::new(x[i], 0_f64);
  9    }
 10
 11    let mut w = Complex::new(0_f64, -2_f64 * PI / x.len() as f64);
 12
 13    // f_k = SUM{n=0, N-1} f_n * e^(-j2pi*k*n)/N
 14    // https://en.wikipedia.org/wiki/Discrete_Fourier_transform
 15    let mut f: Vec<Vec<Complex64>> = Vec::new();
 16    for i in 0..x.len() {
 17        let mut f_k: Vec<Complex64> = Vec::new();
 18        for j in 0..x.len() {
 19            let i_compl = Complex::new(0_f64, i as f64);
 20            let j_compl = Complex::new(0_f64, j as f64);
 21            let fe = (w * i_compl * j_compl).exp();
 22            f_k.push(fe);
 23        }
 24        f.push(f_k.clone());
 25    }
 26    let r = mul_mv(f, x_compl);
 27    r
 28}
 29
 30// idft computes the Inverse Discrete Fourier Transform
 31pub fn idft(x: &Vec<Complex64>) -> Vec<f64> {
 32    let mut w = Complex::new(0_f64, 2_f64 * PI / x.len() as f64);
 33
 34    // f_k = (SUM{n=0, N-1} f_n * e^(j2pi*k*n)/N)/N
 35    let mut dft_matrix: Vec<Vec<Complex64>> = Vec::new();
 36    for i in 0..x.len() {
 37        let mut f_k: Vec<Complex64> = Vec::new();
 38        for j in 0..x.len() {
 39            let i_compl = Complex::new(0_f64, i as f64);
 40            let j_compl = Complex::new(0_f64, j as f64);
 41            let fe = (w * i_compl * j_compl).exp();
 42            f_k.push(fe);
 43        }
 44        dft_matrix.push(f_k.clone());
 45    }
 46    let mut r = mul_mv(dft_matrix, x.clone());
 47    let n = x.len() as f64;
 48    let mut rr: Vec<f64> = Vec::new();
 49    for i in 0..r.len() {
 50        r[i] = r[i] / Complex::new(n, 0_f64);
 51        rr.push(r[i].re);
 52    }
 53    rr
 54}
 55
 56// mul_mv multiplies a Matrix by a Vector
 57fn mul_mv(a: Vec<Vec<Complex64>>, b: Vec<Complex64>) -> Vec<Complex64> {
 58    if a[0].len() != a.len() {
 59        panic!("err b[0].len():{:?} != b.len():{:?}", a[0].len(), a.len());
 60    }
 61    if a.len() != b.len() {
 62        panic!("err a.len():{:?} != b.len():{:?}", a.len(), b.len());
 63    }
 64
 65    let rows = a.len();
 66    let cols = a.len();
 67
 68    let mut c: Vec<Complex64> = vec![Complex::new(0_f64, 0_f64); cols];
 69    for i in 0..rows {
 70        for j in 0..cols {
 71            c[i] += a[i][j] * b[j];
 72        }
 73    }
 74    c
 75}
 76
 77#[cfg(test)]
 78mod tests {
 79    use super::*;
 80
 81    #[test]
 82    fn test_dft_simple_values() {
 83        let values: Vec<f64> = vec![0.2, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8];
 84        let r = dft(&values);
 85        assert_eq!(r.len(), 8);
 86
 87        assert_eq!(format!("{:.2}", r[0]), "3.70+0.00i");
 88        assert_eq!(format!("{:.2}", r[1]), "-0.30-0.97i");
 89        assert_eq!(format!("{:.2}", r[2]), "-0.30-0.40i");
 90        assert_eq!(format!("{:.2}", r[3]), "-0.30-0.17i");
 91        assert_eq!(format!("{:.2}", r[4]), "-0.30+0.00i");
 92
 93        // expect result similar to initial values
 94        let o = idft(&r);
 95        assert_eq!(format!("{:.1}", o[0]), "0.2");
 96        assert_eq!(format!("{:.1}", o[1]), "0.2");
 97        assert_eq!(format!("{:.1}", o[2]), "0.3");
 98        assert_eq!(format!("{:.1}", o[3]), "0.4");
 99        assert_eq!(format!("{:.1}", o[4]), "0.5");
100        assert_eq!(format!("{:.1}", o[5]), "0.6");
101        assert_eq!(format!("{:.1}", o[6]), "0.7");
102        assert_eq!(format!("{:.1}", o[7]), "0.8");
103    }
104}