rpll: extend tests

This commit is contained in:
Robert Jördens 2021-01-31 17:10:03 +01:00
parent ab20d67a07
commit 82c8fa1a07
2 changed files with 72 additions and 27 deletions

View File

@ -57,24 +57,22 @@ impl RPLL {
// Store timestamp for next time. // Store timestamp for next time.
self.x = x; self.x = x;
// Phase using the current frequency estimate // Phase using the current frequency estimate
let p_sig_64 = (self.ff as u64).wrapping_mul(dx as u64); let p_sig_64 = self.ff as u64 * dx as u64;
// Add half-up rounding bias and apply gain/attenuation // Add half-up rounding bias and apply gain/attenuation
let p_sig = (p_sig_64.wrapping_add(1u64 << (shift_frequency - 1)) let p_sig = ((p_sig_64 + (1u32 << (shift_frequency - 1)) as u64)
>> shift_frequency) as i32; >> shift_frequency) as u32;
// Reference phase (1 << dt2 full turns) with gain/attenuation applied // Reference phase (1 << dt2 full turns) with gain/attenuation applied
let p_ref = 1i32 << (32 + self.dt2 - shift_frequency); let p_ref = 1u32 << (32 + self.dt2 - shift_frequency);
// Update frequency lock // Update frequency lock
self.ff = self.ff.wrapping_add(p_ref.wrapping_sub(p_sig) as u32); self.ff = self.ff.wrapping_add(p_ref.wrapping_sub(p_sig) as u32);
// Time in counter cycles between timestamp and "now" // Time in counter cycles between timestamp and "now"
let dt = x.wrapping_neg() & ((1 << self.dt2) - 1); let dt = (x.wrapping_neg() & ((1 << self.dt2) - 1)) as u32;
// Reference phase estimate "now" // Reference phase estimate "now"
let y_ref = ((self.f >> self.dt2) as i32).wrapping_mul(dt); let y_ref = (self.f >> self.dt2).wrapping_mul(dt) as i32;
// Phase error // Phase error with gain
let dy = y_ref.wrapping_sub(self.y); let dy = y_ref.wrapping_sub(self.y) >> (shift_phase - self.dt2);
// Current frequency estimate from frequency lock and phase error // Current frequency estimate from frequency lock and phase error
self.f = self self.f = self.ff.wrapping_add(dy as u32);
.ff
.wrapping_add((dy >> (shift_phase - self.dt2)) as u32);
} }
(self.y, self.f) (self.y, self.f)
} }
@ -128,8 +126,8 @@ mod test {
for _ in 0..n { for _ in 0..n {
let timestamp = if self.time - self.next_noisy >= 0 { let timestamp = if self.time - self.next_noisy >= 0 {
assert!(self.time - self.next_noisy < 1 << self.dt2); assert!(self.time - self.next_noisy < 1 << self.dt2);
let timestamp = self.next_noisy;
self.next = self.next.wrapping_add(self.period); self.next = self.next.wrapping_add(self.period);
let timestamp = self.next_noisy;
let p_noise = self.rng.gen_range(-self.noise..=self.noise); let p_noise = self.rng.gen_range(-self.noise..=self.noise);
self.next_noisy = self.next.wrapping_add(p_noise); self.next_noisy = self.next.wrapping_add(p_noise);
Some(timestamp) Some(timestamp)
@ -141,15 +139,21 @@ mod test {
self.shift_frequency, self.shift_frequency,
self.shift_phase, self.shift_phase,
); );
let y_ref = (self.time.wrapping_sub(self.next) as i64 let y_ref = (self.time.wrapping_sub(self.next) as i64
* (1i64 << 32) * (1i64 << 32)
/ self.period as i64) as i32; / self.period as i64) as i32;
// phase error // phase error
y.push(yi.wrapping_sub(y_ref) as f32 / 2f32.powi(32)); y.push(yi.wrapping_sub(y_ref) as f32 / 2f32.powi(32));
let p_ref = 1 << 32 + self.dt2; let p_ref = 1 << 32 + self.dt2;
let p_sig = fi as i64 * self.period as i64; let p_sig = fi as u64 * self.period as u64;
// relative frequency error // relative frequency error
f.push(p_sig.wrapping_sub(p_ref) as f32 / 2f32.powi(32)); f.push(
p_sig.wrapping_sub(p_ref) as i64 as f32
/ 2f32.powi(32 + self.dt2 as i32),
);
// advance time // advance time
self.time = self.time.wrapping_add(1 << self.dt2); self.time = self.time.wrapping_add(1 << self.dt2);
} }
@ -157,6 +161,10 @@ mod test {
} }
fn measure(&mut self, n: usize) -> (f32, f32, f32, f32) { fn measure(&mut self, n: usize) -> (f32, f32, f32, f32) {
assert!(self.period >= 1 << self.dt2);
assert!(self.dt2 <= self.shift_frequency);
assert!(self.period < 1 << self.shift_frequency);
assert!(self.period < 1 << self.shift_frequency + 1);
let t_settle = (1 << self.shift_frequency - self.dt2 + 4) let t_settle = (1 << self.shift_frequency - self.dt2 + 4)
+ (1 << self.shift_phase - self.dt2 + 4); + (1 << self.shift_phase - self.dt2 + 4);
self.run(t_settle); self.run(t_settle);
@ -164,6 +172,7 @@ mod test {
let (y, f) = self.run(n); let (y, f) = self.run(n);
let y = Array::from(y); let y = Array::from(y);
let f = Array::from(f); let f = Array::from(f);
// println!("{:?} {:?}", f, y);
let fm = f.mean().unwrap(); let fm = f.mean().unwrap();
let fs = f.std_axis(Axis(0), 0.).into_scalar(); let fs = f.std_axis(Axis(0), 0.).into_scalar();
@ -180,8 +189,8 @@ mod test {
let mut h = Harness::default(); let mut h = Harness::default();
let (fm, fs, ym, ys) = h.measure(1 << 16); let (fm, fs, ym, ys) = h.measure(1 << 16);
assert!(fm.abs() < 1e-9); assert!(fm.abs() < 1e-11);
assert!(fs.abs() < 8e-6); assert!(fs.abs() < 4e-8);
assert!(ym.abs() < 2e-8); assert!(ym.abs() < 2e-8);
assert!(ys.abs() < 2e-8); assert!(ys.abs() < 2e-8);
} }
@ -194,8 +203,8 @@ mod test {
h.shift_phase = 22; h.shift_phase = 22;
let (fm, fs, ym, ys) = h.measure(1 << 16); let (fm, fs, ym, ys) = h.measure(1 << 16);
assert!(fm.abs() < 1e-6); assert!(fm.abs() < 3e-9);
assert!(fs.abs() < 6e-4); assert!(fs.abs() < 3e-6);
assert!(ym.abs() < 4e-4); assert!(ym.abs() < 4e-4);
assert!(ys.abs() < 2e-4); assert!(ys.abs() < 2e-4);
} }
@ -204,31 +213,67 @@ mod test {
fn narrow_fast() { fn narrow_fast() {
let mut h = Harness::default(); let mut h = Harness::default();
h.period = 990; h.period = 990;
h.next = 351;
h.next_noisy = h.next;
h.noise = 5; h.noise = 5;
h.shift_frequency = 23; h.shift_frequency = 23;
h.shift_phase = 22; h.shift_phase = 22;
let (fm, fs, ym, ys) = h.measure(1 << 16); let (fm, fs, ym, ys) = h.measure(1 << 16);
assert!(fm.abs() < 7e-6); assert!(fm.abs() < 2e-9);
assert!(fs.abs() < 6e-4); assert!(fs.abs() < 2e-6);
assert!(ym.abs() < 1e-3); assert!(ym.abs() < 1e-3);
assert!(ys.abs() < 1e-4); assert!(ys.abs() < 1e-4);
} }
/*
#[test] #[test]
fn narrow_slow() { fn narrow_slow() {
let mut h = Harness::default(); let mut h = Harness::default();
h.period = 1818181; h.period = 1818181;
h.noise = 1800; h.next = 35281;
h.next_noisy = h.next;
h.noise = 1000;
h.shift_frequency = 23; h.shift_frequency = 23;
h.shift_phase = 22; h.shift_phase = 22;
let (fm, fs, ym, ys) = h.measure(1 << 16); let (fm, fs, ym, ys) = h.measure(1 << 16);
assert!(fm.abs() < 1e-8); assert!(fm.abs() < 2e-5);
assert!(fs.abs() < 6e-4); assert!(fs.abs() < 6e-4);
assert!(ym.abs() < 2e-4); assert!(ym.abs() < 2e-4);
assert!(ys.abs() < 2e-4); assert!(ys.abs() < 2e-4);
} }
*/
#[test]
fn wide_fast() {
let mut h = Harness::default();
h.period = 990;
h.next = 351;
h.next_noisy = h.next;
h.noise = 5;
h.shift_frequency = 10;
h.shift_phase = 9;
let (fm, fs, ym, ys) = h.measure(1 << 16);
assert!(fm.abs() < 1e-3);
assert!(fs.abs() < 1e-1);
assert!(ym.abs() < 1e-4);
assert!(ys.abs() < 3e-2);
}
#[test]
fn wide_slow() {
let mut h = Harness::default();
h.period = 1818181;
h.next = 35281;
h.next_noisy = h.next;
h.noise = 1000;
h.shift_frequency = 21;
h.shift_phase = 20;
let (fm, fs, ym, ys) = h.measure(1 << 16);
assert!(fm.abs() < 2e-4);
assert!(fs.abs() < 6e-3);
assert!(ym.abs() < 2e-4);
assert!(ys.abs() < 2e-3);
}
} }

View File

@ -119,7 +119,7 @@ const APP: () = {
let (pll_phase, pll_frequency) = c.resources.pll.update( let (pll_phase, pll_frequency) = c.resources.pll.update(
c.resources.timestamper.latest_timestamp().map(|t| t as i32), c.resources.timestamper.latest_timestamp().map(|t| t as i32),
22, // relative PLL frequency bandwidth: 2**-22, TODO: expose 23, // relative PLL frequency bandwidth: 2**-23, TODO: expose
22, // relative PLL phase bandwidth: 2**-22, TODO: expose 22, // relative PLL phase bandwidth: 2**-22, TODO: expose
); );
@ -128,8 +128,8 @@ const APP: () = {
// Demodulation LO phase offset // Demodulation LO phase offset
let phase_offset: i32 = 0; let phase_offset: i32 = 0;
let sample_frequency = ((pll_frequency >> SAMPLE_BUFFER_SIZE_LOG2) let sample_frequency = ((pll_frequency >> SAMPLE_BUFFER_SIZE_LOG2)
as i32) as i32) // TODO: maybe rounding bias
.wrapping_mul(harmonic); // TODO: maybe rounding bias .wrapping_mul(harmonic);
let sample_phase = let sample_phase =
phase_offset.wrapping_add(pll_phase.wrapping_mul(harmonic)); phase_offset.wrapping_add(pll_phase.wrapping_mul(harmonic));