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 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.

View File

@ -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 sign = self.phase_accumulator.is_negative();
self.phase_accumulator = self
.phase_accumulator
.wrapping_add(self.config.frequency_tuning_word[sign as usize]);
let phase = self.phase_accumulator as i32;
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 _)
}
}