pll: add note on dithering

This commit is contained in:
Robert Jördens 2020-12-05 13:05:59 +01:00
parent 974fa6e220
commit 4cfe6ba416

View File

@ -10,9 +10,8 @@ use serde::{Deserialize, Serialize};
/// stable for any gain (1 <= shift <= 30). It has a single parameter that determines the loop
/// bandwidth in octave steps. The gain can be changed freely between updates.
///
/// The frequency settling time constant for an (any) frequency jump is `1 << shift` update cycles.
/// The phase settling time in response to a frequency jump is about twice that. The loop bandwidth
/// is about `1/(2*pi*(1 << shift))` in units of the sample rate.
/// The frequency and phase settling time constants for an (any) frequency jump are `1 << shift`
/// update cycles. The loop bandwidth is about `1/(2*pi*(1 << shift))` in units of the sample rate.
///
/// All math is naturally wrapping 32 bit integer. Phase and frequency are understood modulo that
/// overflow in the first Nyquist zone. Expressing the IIR equations in other ways (e.g. single
@ -20,7 +19,8 @@ use serde::{Deserialize, Serialize};
///
/// There are no floating point rounding errors here. But there is integer quantization/truncation
/// error of the `shift` lowest bits leading to a phase offset for very low gains. Truncation
/// bias is applied. Rounding is "half up".
/// bias is applied. Rounding is "half up". The phase truncation error can be removed very
/// efficiently by dithering.
///
/// This PLL does not unwrap phase slips during lock acquisition. This can and should be
/// implemented elsewhere by (down) scaling and then unwrapping the input phase and (up) scaling
@ -89,6 +89,7 @@ mod tests {
assert_eq!(f.wrapping_sub(f0).abs() <= 1, true);
}
if i > n / 2 {
// The remaining error is removed by dithering.
assert_eq!(y.wrapping_sub(x).abs() < 1 << 18, true);
}
}