Adding signal generator control to dual-iir

This commit is contained in:
Ryan Summers 2021-06-28 13:16:54 +02:00
parent a2f67ada3c
commit 9cca1497b7
2 changed files with 63 additions and 20 deletions

View File

@ -16,6 +16,7 @@ use stabilizer::{
hal, hal,
system_timer::SystemTimer, system_timer::SystemTimer,
DigitalInput0, DigitalInput1, AFE0, AFE1, DigitalInput0, DigitalInput1, AFE0, AFE1,
signal_generator::SignalGenerator,
}, },
net::{ net::{
data_stream::{BlockGenerator, StreamTarget}, data_stream::{BlockGenerator, StreamTarget},
@ -39,6 +40,13 @@ pub struct Settings {
force_hold: bool, force_hold: bool,
telemetry_period: u16, telemetry_period: u16,
stream_target: StreamTarget, stream_target: StreamTarget,
signal_generator: signal_generator::Config;
output_mode: [OutputMode; 2],
}
pub struct OutputMode {
IirFilter,
SignalGenerator,
} }
impl Default for Settings { impl Default for Settings {
@ -59,6 +67,8 @@ impl Default for Settings {
// The default telemetry period in seconds. // The default telemetry period in seconds.
telemetry_period: 10, telemetry_period: 10,
signal_generator: signal_generator::Config::default(),
stream_target: StreamTarget::default(), stream_target: StreamTarget::default(),
} }
} }
@ -172,24 +182,42 @@ const APP: () = {
fence(Ordering::SeqCst); fence(Ordering::SeqCst);
for channel in 0..adc_samples.len() { for channel in 0..adc_samples.len() {
adc_samples[channel] match settings.output_mode[channel] {
.iter() OutputMode::IirFilter => {
.zip(dac_samples[channel].iter_mut()) adc_samples[channel]
.map(|(ai, di)| {
let x = f32::from(*ai as i16);
let y = settings.iir_ch[channel]
.iter() .iter()
.zip(iir_state[channel].iter_mut()) .zip(dac_samples[channel].iter_mut())
.fold(x, |yi, (ch, state)| { .map(|(ai, di)| {
ch.update(state, yi, hold) let x = f32::from(*ai as i16);
}); let y = settings.iir_ch[channel]
// Note(unsafe): The filter limits must ensure that the value is in range. .iter()
// The truncation introduces 1/2 LSB distortion. .zip(iir_state[channel].iter_mut())
let y: i16 = unsafe { y.to_int_unchecked() }; .fold(x, |yi, (ch, state)| {
// Convert to DAC code ch.update(state, yi, hold)
*di = DacCode::from(y).0; });
}) // Note(unsafe): The filter limits must ensure that the value is in range.
.last(); // The truncation introduces 1/2 LSB distortion.
let y: i16 = unsafe { y.to_int_unchecked() };
// Convert to DAC code
*di = DacCode::from(y).0;
})
.last();
}
OutputMode::SignalGenerator => {
// Do not generate the samples twice, or we may mess up phasing of the
// signal generator. Instead, copy the previously-generated signal.
// TODO: Is there a nicer way we can handle this edge case?
if (channel == 1) && settings.output_mode[0] == OutputMode::SignalGenerator {
adc_samples[1].copy_from_slice(adc_samples[0]);
} else {
signal_generator.generate(&mut adc_samples[channel]);
}
}
}
}
if !settings.output_mode.iter().any(|&mode| mode == OutputMode::SignalGenerator) {
signal_generator.skip(adc_samples[0].len());
} }
// Stream the data. // Stream the data.
@ -230,6 +258,9 @@ const APP: () = {
c.resources.afes.0.set_gain(settings.afe[0]); c.resources.afes.0.set_gain(settings.afe[0]);
c.resources.afes.1.set_gain(settings.afe[1]); c.resources.afes.1.set_gain(settings.afe[1]);
// Update the signal generator
c.resources.signal_generator.update_waveform(settings.signal_generator);
let target = settings.stream_target.into(); let target = settings.stream_target.into();
c.resources.network.direct_stream(target); c.resources.network.direct_stream(target);
} }

View File

@ -66,13 +66,13 @@ struct InternalConf {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Generator { pub struct SignalGenerator {
index: u32, index: u32,
config: InternalConf, config: InternalConf,
pending_config: Option<InternalConf>, pending_config: Option<InternalConf>,
} }
impl Default for Generator { impl Default for SignalGenerator {
fn default() -> Self { fn default() -> Self {
Self { Self {
config: Config::default().into(), config: Config::default().into(),
@ -82,7 +82,7 @@ impl Default for Generator {
} }
} }
impl Generator { impl SignalGenerator {
/// Construct a new signal generator with some specific config. /// Construct a new signal generator with some specific config.
/// ///
/// # Args /// # Args
@ -108,6 +108,18 @@ impl Generator {
} }
} }
/// Skip `count` elements of the generator
pub fn skip(&mut self, count: usize) {
let index = self.index.wrapping_add(count);
// If we skip past the period of the signal, apply any pending config.
if index > self.config.period && let Some(config) = self.pendig_config.take() {
self.config = config;
}
self.index = index % self.config.period;
}
/// Get the next value in the generator sequence. /// Get the next value in the generator sequence.
pub fn next(&mut self) -> i16 { pub fn next(&mut self) -> i16 {
// When phase wraps, apply any new settings. // When phase wraps, apply any new settings.