use crate::cf32;
use crate::vecops::VecOps;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Scale {
None,
SN,
N,
X(f32),
}
impl Scale {
pub fn scale(self, data: &mut [cf32]) {
match self {
Scale::None => (),
Scale::SN => {
let s = (data.len() as f32).sqrt().recip();
data.vec_scale(s);
}
Scale::N => {
let s = (data.len() as f32).recip();
data.vec_scale(s);
}
Scale::X(s) => {
data.vec_scale(s);
}
}
}
}
#[allow(clippy::len_without_is_empty)]
pub trait Fft {
fn fwd(&mut self, input: &[cf32], output: &mut [cf32], s: Scale);
fn bwd(&mut self, input: &[cf32], output: &mut [cf32], s: Scale);
fn ifwd(&mut self, input: &mut [cf32], s: Scale);
fn ibwd(&mut self, input: &mut [cf32], s: Scale);
fn len(&self) -> usize;
}
#[cfg(feature = "fft_chfft")]
pub use self::ch::Cfft;
#[cfg(feature = "fft_chfft")]
mod ch {
extern crate chfft;
use super::{Fft, Scale};
use chfft::CFft1D;
use crate::cf32;
use crate::vecops::VecOps;
pub struct Cfft {
fft: CFft1D<f32>,
tmp: Vec<cf32>,
len: usize,
}
impl Cfft {
pub fn with_len(len: usize) -> Cfft {
Cfft {
fft: CFft1D::<f32>::with_len(len),
tmp: vec![cf32::default(); len],
len,
}
}
}
impl Fft for Cfft {
fn fwd(&mut self, input: &[cf32], output: &mut [cf32], s: Scale) {
assert_eq!(
self.len,
input.len(),
"Input and FFT must be the same length"
);
self.tmp.vec_clone(&input);
self.fft.forward0i(&mut self.tmp);
output.vec_clone(&self.tmp);
s.scale(output);
}
fn bwd(&mut self, input: &[cf32], output: &mut [cf32], s: Scale) {
assert_eq!(
self.len,
input.len(),
"Input and FFT must be the same length"
);
self.tmp.vec_clone(&input);
self.fft.backward0i(&mut self.tmp);
output.vec_clone(&self.tmp);
s.scale(output);
}
fn ifwd(&mut self, input: &mut [cf32], s: Scale) {
assert_eq!(
self.len,
input.len(),
"Input and FFT must be the same length"
);
self.fft.forward0i(input);
s.scale(input);
}
fn ibwd(&mut self, input: &mut [cf32], s: Scale) {
assert_eq!(
self.len,
input.len(),
"Input and FFT must be the same length"
);
self.fft.backward0i(input);
s.scale(input);
}
fn len(&self) -> usize {
self.len
}
}
}
#[cfg(test)]
mod test {
use super::Scale;
use crate::cf32;
#[test]
fn scale() {
let input = vec![cf32::new(4.0, 0.0); 4];
let no = Scale::None;
let mut nos = input.clone();
no.scale(&mut nos);
assert_evm!(nos, &input, 80.0);
let sn = Scale::SN;
let snc = vec![cf32::new(2.0, 0.0); 4];
let mut sns = input.clone();
sn.scale(&mut sns);
assert_evm!(sns, snc, 80.0);
let n = Scale::N;
let nc = vec![cf32::new(1.0, 0.0); 4];
let mut ns = input.clone();
n.scale(&mut ns);
assert_evm!(ns, nc, 80.0);
let x = Scale::X(2.0);
let xc = vec![cf32::new(8.0, 0.0); 4];
let mut xs = input.clone();
x.scale(&mut xs);
assert_evm!(xs, xc, 80.0);
}
}