I'm quite new to VHDL and I'm struggling with a first order low pass
filter I want to implement. In a naive attempt, I wanted to implement
the following equation in VHDL:
In my VHDL code I did the following:
1 | process (Clk)
|
2 | begin
|
3 | if rising_edge(Clk) then
|
4 | if Rst = '0' then
|
5 | AccuP <= (others => '0');
|
6 | else
|
7 | AccuP <= AccuN;
|
8 | end if;
|
9 | end if;
|
10 | end process;
|
11 |
|
12 |
|
13 | process(AccuP, DataIn, FiltAlpha, FiltBeta)
|
14 | begin
|
15 | AccuN <= resize(shift_right(unsigned(FiltBeta)*unsigned(AccuP) + unsigned(FiltAlpha)*unsigned(DataIn), 16), AccuN'length);
|
16 | end process;
|
where
FiltAlpha = a * 2^16 = 14559
FiltBeta = 2^16-FiltAlpha = 50977
Since the filter coefficient a lies between 0 and 1, I had to upscale
it, i.e. I multiplied my filter coefficient with 2^16, carried out the
fixed point multiplication and shifted the result to the right 16 times.
This is somehow "working", meaning that if I plot a step response I get
the expected exponential output signal, although I'm not sure about the
delay visible between sample 500 and 1000. The input step jumps from 0
to 4095 at 0.
The problem I face now is, that the final value of the result does not
converge to 4095 as I'd expect, in fact it stops at 4091. This is caused
by the right shift operation in the code above, where due to rounding I
lose the fractional bits.
I couldn't really find a way to avoid this problem. So my questions
basically are:
- How to get rid of this, i.e. how do I implement a filter which will
reach the full output signal? What would be the "correct" way of
implementing such a filter?
- Could I just accept it or is their some additional problems with my
implementation I overlook at the moment?