diff options
| author | Quentin Smith <[email protected]> | 2022-08-21 02:43:13 -0400 |
|---|---|---|
| committer | Quentin Smith <[email protected]> | 2022-08-21 02:43:13 -0400 |
| commit | 64154fec8cd7497992ef0d93f319b98215b8a84e (patch) | |
| tree | 69b8f16ce1d0a1206c2ea57d8958b71bce8d5e46 /examples | |
| parent | ed97e61dbecc636c3cc9f67778d4b7eb48cff893 (diff) | |
Demonstrate FFT in example
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/nrf/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/nrf/src/bin/pdm_continuous.rs | 24 |
2 files changed, 24 insertions, 1 deletions
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index d0567ba8e..876dcf734 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml | |||
| @@ -32,3 +32,4 @@ embedded-storage = "0.3.0" | |||
| 32 | usbd-hid = "0.5.2" | 32 | usbd-hid = "0.5.2" |
| 33 | serde = { version = "1.0.136", default-features = false } | 33 | serde = { version = "1.0.136", default-features = false } |
| 34 | num-integer = { version = "0.1.45", default-features = false } | 34 | num-integer = { version = "0.1.45", default-features = false } |
| 35 | microfft = "0.5.0" | ||
diff --git a/examples/nrf/src/bin/pdm_continuous.rs b/examples/nrf/src/bin/pdm_continuous.rs index 33ba1e274..e78bc40dc 100644 --- a/examples/nrf/src/bin/pdm_continuous.rs +++ b/examples/nrf/src/bin/pdm_continuous.rs | |||
| @@ -3,11 +3,13 @@ | |||
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | 4 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use core::cmp::Ordering; | ||
| 6 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::interrupt; | 8 | use embassy_nrf::interrupt; |
| 8 | use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio}; | 9 | use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio}; |
| 9 | use fixed::types::I7F1; | 10 | use fixed::types::I7F1; |
| 10 | use num_integer::Roots; | 11 | use num_integer::Roots; |
| 12 | use microfft::real::rfft_1024; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 14 | ||
| 13 | // Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer | 15 | // Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer |
| @@ -36,8 +38,10 @@ async fn main(_p: Spawner) { | |||
| 36 | // and set the sample buffer size accordingly. Exceeding this | 38 | // and set the sample buffer size accordingly. Exceeding this |
| 37 | // time can lead to the peripheral re-writing the other buffer. | 39 | // time can lead to the peripheral re-writing the other buffer. |
| 38 | let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16; | 40 | let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16; |
| 41 | let (peak_freq_index, peak_mag) = fft_peak_freq(&buf); | ||
| 42 | let peak_freq = peak_freq_index * 16000 / buf.len(); | ||
| 39 | info!( | 43 | info!( |
| 40 | "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}", | 44 | "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}, peak {} @ {} Hz", |
| 41 | buf.len(), | 45 | buf.len(), |
| 42 | buf.iter().min().unwrap(), | 46 | buf.iter().min().unwrap(), |
| 43 | buf.iter().max().unwrap(), | 47 | buf.iter().max().unwrap(), |
| @@ -45,9 +49,27 @@ async fn main(_p: Spawner) { | |||
| 45 | ( | 49 | ( |
| 46 | buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b)) | 50 | buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b)) |
| 47 | / buf.len() as i32).sqrt() as i16, | 51 | / buf.len() as i32).sqrt() as i16, |
| 52 | peak_mag, peak_freq, | ||
| 48 | ); | 53 | ); |
| 49 | SamplerState::Sampled | 54 | SamplerState::Sampled |
| 50 | }, | 55 | }, |
| 51 | ) | 56 | ) |
| 52 | .await; | 57 | .await; |
| 53 | } | 58 | } |
| 59 | |||
| 60 | fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) { | ||
| 61 | let mut f = [0f32; 1024]; | ||
| 62 | for i in 0..input.len() { | ||
| 63 | f[i] = (input[i] as f32) / 32768.0; | ||
| 64 | } | ||
| 65 | // N.B. rfft_1024 does the FFT in-place so result is actually also a reference to f. | ||
| 66 | let result = rfft_1024(&mut f); | ||
| 67 | result[0].im = 0.0; | ||
| 68 | |||
| 69 | result | ||
| 70 | .iter() | ||
| 71 | .map(|c| ((c.norm_sqr()*32768.0) as u32).sqrt()) | ||
| 72 | .enumerate() | ||
| 73 | .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal)) | ||
| 74 | .unwrap() | ||
| 75 | } \ No newline at end of file | ||
