Demonstrate FFT in example
This commit is contained in:
parent
ed97e61dbe
commit
64154fec8c
@ -32,3 +32,4 @@ embedded-storage = "0.3.0"
|
|||||||
usbd-hid = "0.5.2"
|
usbd-hid = "0.5.2"
|
||||||
serde = { version = "1.0.136", default-features = false }
|
serde = { version = "1.0.136", default-features = false }
|
||||||
num-integer = { version = "0.1.45", default-features = false }
|
num-integer = { version = "0.1.45", default-features = false }
|
||||||
|
microfft = "0.5.0"
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
|
use core::cmp::Ordering;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
use embassy_nrf::interrupt;
|
||||||
use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio};
|
use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio};
|
||||||
use fixed::types::I7F1;
|
use fixed::types::I7F1;
|
||||||
use num_integer::Roots;
|
use num_integer::Roots;
|
||||||
|
use microfft::real::rfft_1024;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
|
// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
|
||||||
@ -36,8 +38,10 @@ async fn main(_p: Spawner) {
|
|||||||
// and set the sample buffer size accordingly. Exceeding this
|
// and set the sample buffer size accordingly. Exceeding this
|
||||||
// time can lead to the peripheral re-writing the other buffer.
|
// time can lead to the peripheral re-writing the other buffer.
|
||||||
let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
|
let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
|
||||||
|
let (peak_freq_index, peak_mag) = fft_peak_freq(&buf);
|
||||||
|
let peak_freq = peak_freq_index * 16000 / buf.len();
|
||||||
info!(
|
info!(
|
||||||
"{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}",
|
"{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}, peak {} @ {} Hz",
|
||||||
buf.len(),
|
buf.len(),
|
||||||
buf.iter().min().unwrap(),
|
buf.iter().min().unwrap(),
|
||||||
buf.iter().max().unwrap(),
|
buf.iter().max().unwrap(),
|
||||||
@ -45,9 +49,27 @@ async fn main(_p: Spawner) {
|
|||||||
(
|
(
|
||||||
buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b))
|
buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b))
|
||||||
/ buf.len() as i32).sqrt() as i16,
|
/ buf.len() as i32).sqrt() as i16,
|
||||||
|
peak_mag, peak_freq,
|
||||||
);
|
);
|
||||||
SamplerState::Sampled
|
SamplerState::Sampled
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) {
|
||||||
|
let mut f = [0f32; 1024];
|
||||||
|
for i in 0..input.len() {
|
||||||
|
f[i] = (input[i] as f32) / 32768.0;
|
||||||
|
}
|
||||||
|
// N.B. rfft_1024 does the FFT in-place so result is actually also a reference to f.
|
||||||
|
let result = rfft_1024(&mut f);
|
||||||
|
result[0].im = 0.0;
|
||||||
|
|
||||||
|
result
|
||||||
|
.iter()
|
||||||
|
.map(|c| ((c.norm_sqr()*32768.0) as u32).sqrt())
|
||||||
|
.enumerate()
|
||||||
|
.max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
|
||||||
|
.unwrap()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user