aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorQuentin Smith <[email protected]>2022-08-21 02:43:13 -0400
committerQuentin Smith <[email protected]>2022-08-21 02:43:13 -0400
commit64154fec8cd7497992ef0d93f319b98215b8a84e (patch)
tree69b8f16ce1d0a1206c2ea57d8958b71bce8d5e46 /examples
parented97e61dbecc636c3cc9f67778d4b7eb48cff893 (diff)
Demonstrate FFT in example
Diffstat (limited to 'examples')
-rw-r--r--examples/nrf/Cargo.toml1
-rw-r--r--examples/nrf/src/bin/pdm_continuous.rs24
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"
32usbd-hid = "0.5.2" 32usbd-hid = "0.5.2"
33serde = { version = "1.0.136", default-features = false } 33serde = { version = "1.0.136", default-features = false }
34num-integer = { version = "0.1.45", default-features = false } 34num-integer = { version = "0.1.45", default-features = false }
35microfft = "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
5use defmt::info; 5use defmt::info;
6use core::cmp::Ordering;
6use embassy_executor::Spawner; 7use embassy_executor::Spawner;
7use embassy_nrf::interrupt; 8use embassy_nrf::interrupt;
8use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio}; 9use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio};
9use fixed::types::I7F1; 10use fixed::types::I7F1;
10use num_integer::Roots; 11use num_integer::Roots;
12use microfft::real::rfft_1024;
11use {defmt_rtt as _, panic_probe as _}; 13use {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
60fn 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