Browse Source

Merge #434

434: Adding optimized signal generator r=jordens a=ryan-summers

This PR fixes #415 by implementing the proposed changes to reduce processing overhead.

Unfortunately, even with these changes, it appears to not be possible to stream at full data rate even when using square waves - there are still losses of ~0.5% of frames.

These changes were run with a signal frequency/amplitude/symmetry sweep from 500Hz-1KHz, Symmetry 0-1, and amplitude 1V -> 2V and output waveform on a scope looked well-formed.

Co-authored-by: Ryan Summers <ryan.summers@vertigo-designs.com>
master
bors[bot] 2 months ago
committed by GitHub
parent
commit
323ed54989
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/bin/lockin.rs
  2. 40
      src/hardware/signal_generator.rs

2
src/bin/lockin.rs

@ -279,7 +279,7 @@ const APP: () = {
let signal_config = {
let frequency_tuning_word =
(1u64 << (32 - BATCH_SIZE_SIZE_LOG2)) as u32;
(1u64 << (32 - BATCH_SIZE_SIZE_LOG2)) as i32;
signal_generator::Config {
// Same frequency as batch size.

40
src/hardware/signal_generator.rs

@ -93,12 +93,12 @@ impl BasicConfig {
ftw / self.symmetry
} else {
NYQUIST
} as u32,
} as i32,
if symmetry_complement * NYQUIST > ftw {
ftw / symmetry_complement
} else {
NYQUIST
} as u32,
} as i32,
];
Ok(Config {
@ -120,7 +120,7 @@ pub struct Config {
pub amplitude: i16,
/// The frequency tuning word of the signal. Phase is incremented by this amount
pub frequency_tuning_word: [u32; 2],
pub frequency_tuning_word: [i32; 2],
}
impl Default for Config {
@ -135,7 +135,7 @@ impl Default for Config {
#[derive(Debug)]
pub struct SignalGenerator {
phase_accumulator: u32,
phase_accumulator: i32,
config: Config,
}
@ -174,32 +174,26 @@ impl core::iter::Iterator for SignalGenerator {
/// Get the next value in the generator sequence.
fn next(&mut self) -> Option<i16> {
self.phase_accumulator = self.phase_accumulator.wrapping_add(
if (self.phase_accumulator as i32).is_negative() {
self.config.frequency_tuning_word[0]
} else {
self.config.frequency_tuning_word[1]
},
);
let phase = self.phase_accumulator as i32;
let sign = self.phase_accumulator.is_negative();
self.phase_accumulator = self
.phase_accumulator
.wrapping_add(self.config.frequency_tuning_word[sign as usize]);
let amplitude: i16 = match self.config.signal {
Signal::Cosine => (dsp::cossin(phase).0 >> 16) as i16,
let scale = match self.config.signal {
Signal::Cosine => (dsp::cossin(self.phase_accumulator).0 >> 16),
Signal::Square => {
if phase.is_negative() {
i16::MAX
if sign {
-1 << 15
} else {
-i16::MAX
1 << 15
}
}
Signal::Triangle => i16::MAX - (phase.abs() >> 15) as i16,
Signal::Triangle => {
(self.phase_accumulator >> 15).abs() - (1 << 15)
}
};
// Calculate the final output result as an i16.
let result = amplitude as i32 * self.config.amplitude as i32;
// Note: We downshift by 15-bits to preserve only one of the sign bits.
Some(((result + (1 << 14)) >> 15) as i16)
Some(((self.config.amplitude as i32 * scale) >> 15) as _)
}
}
Loading…
Cancel
Save