[time-nuts] PLL Math Question
dennis.c.ferguson at gmail.com
Thu Mar 13 14:58:48 EDT 2014
On 12 Mar, 2014, at 23:08 , Hal Murray <hmurray at megapathdsl.net> wrote:
> 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.
Note that you can't do fixed-point computations exactly the same way
you would do it in floating point, you often need to rearrange the equations
a bit. You can usually find a rearrangement which provides equivalent
results, however. Let's define an extra variable, x_sum, where
x_avg = x_sum * a_avg;
The equation above can then be rewritten in terms of x_sum, i.e.
x_sum = x_sum * (1 - a_avg) + x;
With an a_avg of 1/8 you'll instead be multiplying x_sum by 7, shifting
it right 3 bits (you might want to round before the shift) and adding x.
The new value of x_avg can be computed from the new value of x_sum with a
shift (you might want to round that too), or you could pretend that x_sum
is a fixed-point number with the decimal point 3 bits from the right.
In either case x_sum carries enough bits that you don't lose precision.
More information about the time-nuts