diff --git a/Cargo.toml b/Cargo.toml index 71b9c28e770c26f24645ebd81797c65b256f963a..0363e1545e1c267d7ed52ea95b3d5c15fbaa40d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,6 @@ repository = "https://github.com/mcpherrinm/goertzel.git" keywords = ["dsp", "goertzel", "fft", "fourier"] license = "MIT" description = "An nostd implementation of Goertzel's Algoritm" + +[dependencies] +libm = "0.2.1" diff --git a/src/lib.rs b/src/lib.rs index 64eb6f6dd57bf789ade85168f932087ed0d911f5..8277a57dc664aeb9a173988965652043837d2699 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,10 @@ // This (implicitly/naively) uses a rectangular window. Some way to set up a window function // will be needed probably -- if mutating your samples before calling this isn't sufficient. -use std::f32; -use std::f32::consts::PI; + +// allow std in tests +#![cfg_attr(not(test), no_std)] + +use core::f32::consts::PI; /// Set up parameters (and some precomputed values for those). #[derive(Clone, Copy)] @@ -25,11 +28,11 @@ impl Parameters { pub fn new(target_freq: f32, sample_rate: u32, window_size: usize) -> Self { let k = target_freq * (window_size as f32) / (sample_rate as f32); let omega = (PI * 2. * k) / (window_size as f32); - let cosine = omega.cos(); + let cosine = libm::cosf(omega); Parameters { - window_size: window_size, - sine: omega.sin(), - cosine: cosine, + window_size, + sine: libm::sinf(omega), + cosine, term_coefficient: 2. * cosine, } } @@ -44,12 +47,12 @@ impl Parameters { } pub fn mag(self, samples: &[i16]) -> f32 { - self.start().add(samples).finish_mag() + self.start().add_samples(samples).finish_mag() } } impl Partial { - pub fn add(mut self, samples: &[i16]) -> Self { + pub fn add_samples(mut self, samples: &[i16]) -> Self { for &sample in samples { let this = self.params.term_coefficient * self.prev - self.prevprev + (sample as f32); self.prevprev = self.prev; @@ -67,15 +70,21 @@ impl Partial { pub fn finish_mag(self) -> f32 { let (real, imag) = self.finish(); - (real * real + imag * imag).sqrt() + libm::sqrtf(real * real + imag * imag) } } #[test] fn zero_data() { let p = Parameters::new(1800., 8000, 256); - assert!(p.start().add(&[0; 256]).finish_mag() == 0.); - assert!(p.start().add(&[0; 128]).add(&[0; 128]).finish_mag() == 0.); + assert!(p.start().add_samples(&[0; 256]).finish_mag() == 0.); + assert!( + p.start() + .add_samples(&[0; 128]) + .add_samples(&[0; 128]) + .finish_mag() + == 0. + ); } #[test] @@ -84,13 +93,13 @@ fn sine() { for &freq in [697., 1200., 1800., 1633.].iter() { // Generate a 1 second sine wave at freq hz let step = 1. / 8000.; - for sample in (0..8000) { - let time = sample as f32 * step; - buf[sample] = ((time * freq * PI * 2.).sin() * std::i16::MAX as f32) as i16; + for (i, v) in buf.iter_mut().enumerate() { + let time = i as f32 * step; + *v = ((time * freq * PI * 2.).sin() * std::i16::MAX as f32) as i16; } let p = Parameters::new(freq, 8000, 8000); - let mag = p.start().add(&buf[..]).finish_mag(); + let mag = p.start().add_samples(&buf[..]).finish_mag(); for testfreq in (0..30).map(|x| (x * 100) as f32) { let p = Parameters::new(testfreq, 8000, 8000); let testmag = p.mag(&buf[..]);