[time-nuts] PLL Math Question
hmurray at megapathdsl.net
Wed Mar 12 23:08:15 EDT 2014
bob at evoria.net said:
> In the moving averages I'm doing, I'm saving the last bit to be shifted out
> and if it's a 1 (i.e. 0.5) I increase the result by 1.
That's just rounding up at an important place. It's probably a good idea,
but doesn't cover the area I was trying to point out. Let me try again...
Suppose you are doing:
x_avg = x_avg + (x - x_avg) * a_avg;
For exponential smoothing, a_avg will be a fraction. Let's pick a_avg to be
1/8. That's a right shift by 3 bits. I don't think there is anything magic
about shifting, but that makes a particular case easy to spot and discuss.
Suppose x_avg is 0 and x has been 0 for a while. Everything is stable. Now change x to 2. (x - x_avg) is 2, the shift kicks it off the edge, so x_avg doesn't change. (It went 2 bits off, so your round up doesn't catch it.) The response to small steps is to ignore them.
If you have noisy data, things probably work out OK. If you need to process low level (very) low frequency changes (which seems desirable for a GPSDO) you probably want some fractional bits. For me, the easy way to do that is to use
y = x * k
Let's use k = 16, a 4 bit left shift.
For the same step of x=2, y= 32, (y - y_avg) is 32, shifted right by 3 that's 4, so y_avg is 4.
I'm sure this is all business-as-usual for the people who write control loops in small CPUs using fixed point arithmethic. Of course, you have to worry about shifting too far left (overflow) and things like that.
If you have enough cycles, you can use floating point. :)
These are my opinions. I hate spam.
More information about the time-nuts