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>
This commit is contained in:
bors[bot] 2021-08-10 19:46:44 +00:00 committed by GitHub
commit 323ed54989
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 24 deletions

View File

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

View File

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