Average DFT input at lower stimulation frequencies to lower noise.

This commit is contained in:
2026-03-12 17:54:20 +01:00
parent 2c9706dd2a
commit bf32f0abdb
3 changed files with 89 additions and 1 deletions

View File

@@ -125,6 +125,7 @@ pub struct DspConfig {
muxselp: Option<MUXSELP>, muxselp: Option<MUXSELP>,
ctiacon: Option<CTIACON>, ctiacon: Option<CTIACON>,
rtiacon: Option<RTIACON>, rtiacon: Option<RTIACON>,
pub avrgnum: Option<AVRGNUM>,
sinc3osr: Option<SINC3OSR>, sinc3osr: Option<SINC3OSR>,
sinc2osr: Option<SINC2OSR>, sinc2osr: Option<SINC2OSR>,
adcsamplerate: Option<ADCSAMPLERATE>, adcsamplerate: Option<ADCSAMPLERATE>,
@@ -162,6 +163,11 @@ impl DspConfig {
self self
} }
pub fn avrgnum(&mut self, avrgnum: Option<AVRGNUM>) -> &mut Self {
self.avrgnum = avrgnum;
self
}
pub fn sinc3osr(&mut self, sinc3osr: SINC3OSR) -> &mut Self { pub fn sinc3osr(&mut self, sinc3osr: SINC3OSR) -> &mut Self {
self.sinc3osr = Some(sinc3osr); self.sinc3osr = Some(sinc3osr);
self self
@@ -561,6 +567,11 @@ impl AD5940 {
} }
} }
// When averaging, the wait time needs to be multiplied by the number of averages to fill the DFT buffer with the correct number of samples
if let Some(avrgnum) = config.avrgnum {
wait_time *= 2u32.pow(avrgnum as u32 + 1); // For low frequencies, we need to average more samples to get a stable measurement
}
// Calculate wait time based on DFTNUM // Calculate wait time based on DFTNUM
if let Some(dftnum) = config.dftnum { if let Some(dftnum) = config.dftnum {
let samples_per_dft = 1 << (dftnum as u32 + 2); let samples_per_dft = 1 << (dftnum as u32 + 2);
@@ -728,6 +739,13 @@ impl AD5940 {
// ADCFILTERCON // ADCFILTERCON
let mut current = self.read_reg(Register::ADCFILTERCON).await?; let mut current = self.read_reg(Register::ADCFILTERCON).await?;
if let Some(avrnum) = config.avrgnum {
current = AVRGEN::apply(current, AVRGEN::AverageEnabled as u32);
current = AVRGNUM::apply(current, avrnum as u32);
} else {
current = AVRGEN::apply(current, AVRGEN::AverageDisabled as u32);
}
if let Some(sinc3osr) = config.sinc3osr{ if let Some(sinc3osr) = config.sinc3osr{
current = SINC3OSR::apply(current, sinc3osr as u32); current = SINC3OSR::apply(current, sinc3osr as u32);
} }

View File

@@ -395,6 +395,23 @@ impl RegisterField for RTIACON {
const MASK: u32 = 0b1111; const MASK: u32 = 0b1111;
} }
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum AVRGNUM {
ADC2 = 0b00,
ADC4 = 0b01,
ADC8 = 0b10,
ADC16 = 0b11,
}
impl RegisterField for AVRGNUM {
fn reset() -> Self {
AVRGNUM::ADC2
}
const BIT_OFFSET: u32 = 14;
const MASK: u32 = 0b11;
}
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum SINC3OSR { pub enum SINC3OSR {
@@ -436,6 +453,21 @@ impl RegisterField for SINC2OSR {
const MASK: u32 = 0b1111; const MASK: u32 = 0b1111;
} }
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum AVRGEN {
AverageDisabled = 0b0,
AverageEnabled = 0b1,
}
impl RegisterField for AVRGEN {
fn reset() -> Self {
AVRGEN::AverageDisabled
}
const BIT_OFFSET: u32 = 7;
const MASK: u32 = 0b1;
}
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ADCSAMPLERATE { pub enum ADCSAMPLERATE {

View File

@@ -480,6 +480,11 @@ impl ImpedanceSetup {
// Create vector to store the periods per DFT for each frequency // Create vector to store the periods per DFT for each frequency
let mut periods_per_dft_vec = heapless::Vec::<f32, N>::new(); let mut periods_per_dft_vec = heapless::Vec::<f32, N>::new();
// Find out if we have low frequencies (<300Hz) and/or high frequencies (>=300Hz) in our measurement points for the averaging configuration
let averaging_cutoff = 300;
let mut set_avg_low_freq = number_of_points.values().iter().any(|&f| f < averaging_cutoff);
let mut set_avg_high_freq = number_of_points.values().iter().any(|&f| f >= averaging_cutoff);
// Reset FIFO // Reset FIFO
self.ad5940.clear_and_enable_fifo().await.unwrap(); self.ad5940.clear_and_enable_fifo().await.unwrap();
@@ -510,6 +515,20 @@ impl ImpedanceSetup {
if let Some(dsp_config) = &mut self.dsp_config { if let Some(dsp_config) = &mut self.dsp_config {
dsp_config dsp_config
.dftnum(selected_dft_num); .dftnum(selected_dft_num);
// Decide averaging based on frequency, apply once to avoid unnecessary writes to the registers in the loop
if frequency < averaging_cutoff && set_avg_low_freq {
dsp_config
.avrgnum(Some(AVRGNUM::ADC4));
set_avg_low_freq = false;
self.ad5940.apply_dsp_config(dsp_config).await.unwrap();
}
if frequency >= averaging_cutoff && set_avg_high_freq {
dsp_config
.avrgnum(None);
set_avg_high_freq = false;
self.ad5940.apply_dsp_config(dsp_config).await.unwrap();
}
// Update DFTNUM // Update DFTNUM
let mut current = self.ad5940.read_reg(Register::DFTCON).await.unwrap(); let mut current = self.ad5940.read_reg(Register::DFTCON).await.unwrap();
@@ -600,6 +619,11 @@ impl ImpedanceSetup {
}, },
} }
// Find out if we have low frequencies (<300Hz) and/or high frequencies (>=300Hz) in our measurement points for the averaging configuration
let averaging_cutoff = 300;
let mut set_avg_low_freq = number_of_points.values().iter().any(|&f| f < averaging_cutoff);
let mut set_avg_high_freq = number_of_points.values().iter().any(|&f| f >= averaging_cutoff);
// Reset FIFO // Reset FIFO
self.ad5940.clear_and_enable_fifo().await.unwrap(); self.ad5940.clear_and_enable_fifo().await.unwrap();
@@ -630,7 +654,21 @@ impl ImpedanceSetup {
if let Some(dsp_config) = &mut self.dsp_config { if let Some(dsp_config) = &mut self.dsp_config {
dsp_config dsp_config
.dftnum(selected_dft_num); .dftnum(selected_dft_num);
// Decide averaging based on frequency, apply once to avoid unnecessary writes to the registers in the loop
if frequency < averaging_cutoff && set_avg_low_freq {
dsp_config
.avrgnum(Some(AVRGNUM::ADC4));
set_avg_low_freq = false;
self.ad5940.apply_dsp_config(dsp_config).await.unwrap(); // Apply immediately to avoid unnecessary waits in the loop when averaging is enabled for low frequencies
}
if frequency >= averaging_cutoff && set_avg_high_freq {
dsp_config
.avrgnum(None);
set_avg_high_freq = false;
self.ad5940.apply_dsp_config(dsp_config).await.unwrap(); // Apply immediately to avoid unnecessary waits in the loop when averaging is disabled for high frequencies
}
// Update DFTNUM // Update DFTNUM
let mut current = self.ad5940.read_reg(Register::DFTCON).await.unwrap(); let mut current = self.ad5940.read_reg(Register::DFTCON).await.unwrap();
current = DFTNUM::apply(current, selected_dft_num as u32); current = DFTNUM::apply(current, selected_dft_num as u32);