diff --git a/Cargo.toml b/Cargo.toml index 5ea09a2c79e2d1cbee23eed9d6e5491247177c72..71b9c28e770c26f24645ebd81797c65b256f963a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,9 @@ [package] -name = "goertzel" +edition = "2021" +name = "goertzel-nostd" version = "0.2.0" -authors = ["Matt McPherrin <matt@mcpherrin.ca>"] +authors = ["Stephen D"] repository = "https://github.com/mcpherrinm/goertzel.git" keywords = ["dsp", "goertzel", "fft", "fourier"] license = "MIT" -description = "An implementation of Goertzel's Algoritm" +description = "An nostd implementation of Goertzel's Algoritm" diff --git a/README.md b/README.md index e1ae2d5d692b60c3896f59bab32b831863a23848..4603bd788f0d207e0215dc9024eb4a956c909c9e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -Goertzel +Goertzel-nostd -------- The Goertzel Algoritm is a single-bin discrete fourier transform, useful for tone detection with a small number of tones. This has not yet been extensively tested, but appears to basically work. + +This is a fork of [goertzel](https://github.com/mcpherrinm/goertzel). diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000000000000000000000000000000000000..a4f58761a21a7247aab2f84bbaea0f501ade6c81 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +tab_spaces = 4 +hard_tabs = true +edition = "2021" diff --git a/src/lib.rs b/src/lib.rs index ee7a171e8dfbe47010f2f878794ed4b878ae9cb4..64eb6f6dd57bf789ade85168f932087ed0d911f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,95 +6,99 @@ use std::f32::consts::PI; /// Set up parameters (and some precomputed values for those). #[derive(Clone, Copy)] pub struct Parameters { - // Parameters we're working with - window_size: usize, - // Precomputed value: - sine: f32, - cosine: f32, - term_coefficient: f32, + // Parameters we're working with + window_size: usize, + // Precomputed value: + sine: f32, + cosine: f32, + term_coefficient: f32, } pub struct Partial { - params: Parameters, - count: usize, - prev: f32, - prevprev: f32, + params: Parameters, + count: usize, + prev: f32, + prevprev: f32, } 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(); - Parameters { - window_size: window_size, - sine: omega.sin(), - cosine: cosine, - term_coefficient: 2. * cosine, - } - } + 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(); + Parameters { + window_size: window_size, + sine: omega.sin(), + cosine: cosine, + term_coefficient: 2. * cosine, + } + } - pub fn start(self) -> Partial { - Partial{ params: self, count: 0, prev: 0., prevprev: 0. } - } + pub fn start(self) -> Partial { + Partial { + params: self, + count: 0, + prev: 0., + prevprev: 0., + } + } - pub fn mag(self, samples: &[i16]) -> f32 { - self.start().add(samples).finish_mag() - } + pub fn mag(self, samples: &[i16]) -> f32 { + self.start().add(samples).finish_mag() + } } impl Partial { - pub fn add(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; - self.prev = this; - } - self.count += samples.len(); - self - } - pub fn finish(self) -> (f32, f32) { - assert_eq!(self.count, self.params.window_size); - let real = self.prev - self.prevprev * self.params.cosine; - let imag = self.prevprev * self.params.sine; - (real, imag) - } + pub fn add(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; + self.prev = this; + } + self.count += samples.len(); + self + } + pub fn finish(self) -> (f32, f32) { + assert_eq!(self.count, self.params.window_size); + let real = self.prev - self.prevprev * self.params.cosine; + let imag = self.prevprev * self.params.sine; + (real, imag) + } - pub fn finish_mag(self) -> f32 { - let (real, imag) = self.finish(); - (real*real + imag*imag).sqrt() - } + pub fn finish_mag(self) -> f32 { + let (real, imag) = self.finish(); + (real * real + imag * imag).sqrt() + } } #[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.); + 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.); } #[test] fn sine() { - let mut buf = [0; 8000]; - 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; - } + let mut buf = [0; 8000]; + 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; + } - let p = Parameters::new(freq, 8000, 8000); - let mag = p.start().add(&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[..]); - println!("{:4}: {:12.3}", testfreq, testmag); - if (freq-testfreq).abs() > 100. { - println!("{} > 10*{}", mag, testmag); - assert!(mag > 10.*testmag); - } - } - } + let p = Parameters::new(freq, 8000, 8000); + let mag = p.start().add(&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[..]); + println!("{:4}: {:12.3}", testfreq, testmag); + if (freq - testfreq).abs() > 100. { + println!("{} > 10*{}", mag, testmag); + assert!(mag > 10. * testmag); + } + } + } } -