EmbDev.net

Forum: FPGA, VHDL & Verilog First order IIR low pass - quantization prevents full output range


von VHDL Newbie (Guest)


Attached files:

Rate this post
useful
not useful
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?

: Moved by Moderator
von VHDL Newbie (Guest)


Attached files:

Rate this post
useful
not useful
Edit: Messed up the picture, attached is a better one. If some admin 
could replace it it would be great.

von Duke Scarring (Guest)


Rate this post
useful
not useful
VHDL Newbie schrieb:
> This is caused
> by the right shift operation in the code above, where due to rounding I
> lose the fractional bits.
What if you add 1/2 before cutting the bits?

Duke

von Lothar M. (Company: Titel) (lkmiller) (Moderator)


Rate this post
useful
not useful
VHDL Newbie schrieb:
1
 process(AccuP, DataIn, FiltAlpha, FiltBeta)
2
 begin
3
     AccuN <= resize(shift_right(unsigned(FiltBeta)*unsigned(AccuP) +  unsigned(FiltAlpha)*unsigned(DataIn), 16), AccuN'length);
4
 end process;
Why a process?
Do such things concurrent will reduce the risc of incomplete sensitivity 
lists:
1
-- process(AccuP, DataIn, FiltAlpha, FiltBeta)
2
-- begin
3
     AccuN <= resize(shift_right(unsigned(FiltBeta)*unsigned(AccuP) +  unsigned(FiltAlpha)*unsigned(DataIn), 16), AccuN'length);
4
-- end process;

And why not using unsigned vectors for the accus to get rid of that 
conversions back and forth?

VHDL Newbie schrieb:
> - How to get rid of this, i.e. how do I implement a filter which will
> reach the full output signal?
You must implement an "internal" accumulator with more bits than you 
have to output to sum up the lower bits also. So simply use internally a 
20 bit accu for summation and pass the high bits to the upper level.

Duke Scarring schrieb:
> What if you add 1/2 before cutting the bits?
Thats somehow the same way: add one bit to the vectors length...  ;-)

VHDL Newbie schrieb:
> In a naive attempt, I wanted to implement the following equation in
> VHDL
By selecting "nice binary" values it is fairly easy to avoid rounding 
error:
http://www.lothar-miller.de/s9y/categories/58-Filter
Try google translator, its German.

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.