improve PLL fractional divider algorithm

This commit is contained in:
Jan Käberich 2025-08-17 19:37:10 +02:00
parent 66d5bdd91b
commit 8b44421ea3
7 changed files with 82 additions and 19 deletions

View file

@ -2,6 +2,7 @@
#include "stm.hpp"
#include <cmath>
#include <algorithm>
Algorithm::RationalApproximation Algorithm::BestRationalApproximation(float ratio, uint32_t max_denom) {
RationalApproximation result;
@ -42,3 +43,47 @@ Algorithm::RationalApproximation Algorithm::BestRationalApproximation(float rati
}
return result;
}
uint32_t gcd(uint32_t u, uint32_t v) {
if(u==0) {
return v;
} else if(v==0) {
return u;
}
uint8_t i = __builtin_ctz(u);
u >>= i;
uint8_t j = __builtin_ctz(v);
v >>= j;
uint8_t k = i < j ? i : j;
while(true) {
if(u > v) {
std::swap(u, v);
}
v -= u;
if(v==0) {
return u << k;
}
v >>= __builtin_ctz(v);
}
}
Algorithm::RationalApproximation Algorithm::BestRationalApproximation(
RationalApproximation ratio, uint32_t max_denom) {
if(ratio.denom <= max_denom) {
// nothing to do, we can just return the ratio as it is
return ratio;
}
// Try to simplify the ratio.
// Find greatest common divider
uint32_t div = gcd(ratio.num, ratio.denom);
ratio.num /= div;
ratio.denom /= div;
if(ratio.denom <= max_denom) {
// small enough now, can use as is
return ratio;
}
// no good, we need to approximate
return Algorithm::BestRationalApproximation((float) ratio.num / ratio.denom, max_denom);
}