EmbDev.net

Forum: FPGA, VHDL & Verilog IIR FILTER PROBLEM


von Chris C. (programmer001)


Rate this post
useful
not useful
Hi!
I have a problem with IIR filter. On the output I have a input sin 
signal but the filter doesn't suppress the signal. It behaviour is that 
as rewrite
input signal to output. I think that the problem is in the subtraction 
operation or types. Fcut=2MHz. Code below:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.NUMERIC_STD.ALL;

entity dsp is
    Port ( clk : in  STD_LOGIC := '0';
           clk_adc : out  STD_LOGIC := '0';
     clk_dac : out  STD_LOGIC := '0';
           adc_data : in  STD_LOGIC_VECTOR(9 downto 0) := (others => 
'0');
           dac_data : out  STD_LOGIC_VECTOR(9 downto 0) := (others => 
'0')
       );
end dsp;

architecture Behavioral of dsp is


constant coeff_a0: integer := 128; --coefficients
constant coeff_a1: integer := 256;
constant coeff_a2: integer := 128;

constant coeff_b0: integer := -293;
constant coeff_b1: integer := 106;


constant offset: STD_LOGIC_VECTOR(9 downto 0) := "1000000000";

signal adc_buffer: signed(9 downto 0) := (others => '0');
signal dac_buffer: STD_LOGIC_VECTOR(9 downto 0) := (others => '0');

signal mult_a0: signed(19 downto 0):= (others => '0'); --mult registers
signal mult_a1: signed(19 downto 0):= (others => '0');
signal mult_a2: signed(19 downto 0):= (others => '0');


signal mult_b0: signed(19 downto 0):= (others => '0');
signal mult_b1: signed(19 downto 0):= (others => '0');

signal tmult_a0: signed(9 downto 0):= (others => '0'); --truncate 
registers
signal tmult_a1: signed(9 downto 0):= (others => '0');
signal tmult_a2: signed(9 downto 0):= (others => '0');


signal tmult_b0: signed(9 downto 0):= (others => '0');
signal tmult_b1: signed(9 downto 0):= (others => '0');

signal add_all: signed(9 downto 0):= (others => '0');

signal pipe_a0: signed(9 downto 0) := (others => '0'); --delay registers
signal pipe_a1: signed(9 downto 0) := (others => '0');
signal pipe_a2: signed(9 downto 0) := (others => '0');


signal pipe_b0: signed(9 downto 0) := (others => '0');
signal pipe_b1: signed(9 downto 0) := (others => '0');


begin

P0: process(clk)
begin

  if falling_edge(clk) then

  adc_buffer <= signed(adc_data); -- adc give data in U2 code

  pipe_a0 <= adc_buffer;
  pipe_a1 <= pipe_a0;
  pipe_a2 <= pipe_a1;

  pipe_b0 <= signed(add_all);
  pipe_b1 <= pipe_b0;

  dac_data <= dac_buffer(9 downto 0); -- write to dac

  end if;

end process;

  mult_a0 <= pipe_a0*to_signed(coeff_a0,10); -- multiplication
  mult_a1 <= pipe_a1*to_signed(coeff_a1,10);
  mult_a2 <= pipe_a2*to_signed(coeff_a2,10);

  mult_b0 <= pipe_b0*to_signed(coeff_b0,10);
  mult_b1 <= pipe_b1*to_signed(coeff_b1,10);

  tmult_a0 <= mult_a0(19 downto 10); -- truncate to 10 bits
  tmult_a1 <= mult_a1(19 downto 10);
  tmult_a2 <= mult_a2(19 downto 10);

  tmult_b0 <= mult_b0(19 downto 10);
  tmult_b1 <= mult_b1(19 downto 10);

  --sum (add and substract)
  add_all <= tmult_a0 + tmult_a1 + tmult_a2 - tmult_b0 - tmult_b1;


  dac_buffer <= STD_LOGIC_VECTOR(add_all) + offset; -- to offset binary 
convertion

  clk_adc <= clk;
  clk_dac <= clk;


end Behavioral;

von Pongo (Guest)


Rate this post
useful
not useful
Chris C. wrote:
> if falling_edge(clk) then
THIS IS NONSENSE. THERE IS NO FALLING CLOCK SENSITIVE FF IN AN FPGA.

> clk_adc <= clk;
> clk_dac <= clk;

THIS IS BAD! CLOCKS CANNOT BE ROUTET OUT.

also TRUNCATION IS TO EARLY.

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


Rate this post
useful
not useful
Chris C. wrote:
> use IEEE.STD_LOGIC_unsigned.ALL;
> use IEEE.NUMERIC_STD.ALL;
Use the first one or use the second one. But never ever use both of them 
together.
Best is to use the numeric_std and its conversions and casts.
See how simple that is:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std
Try Google translator, it's German...

von Duke Scarring (Guest)


Attached files:

Rate this post
useful
not useful
Beside all the other mentioned problems:
What is your main clock frequency?

I've added a testbench to the see the filter effect.
For me it looks like your cutoff frequency is to high.

Duke

von Chris C. (programmer001)


Rate this post
useful
not useful
My clock frequency -> 100MHz

In code below coefficient are for 4MHz cut-off frequency but I dont know 
if they are correct. In new code is is easy to change coefficients.
I need coefficients only to test my filter. I would be gratefull if 
somebody generate coefficient (10 bit) to low-pass with cut-off beetwenn 
1-10MHz.
I dont know what to do with overflow bits. If I have 23-bit ad_all 
signal the output amplitude is 4 times lower than when I have 19-bit 
ad_all signal.
It probably means that the overflow bits doesn't occur. In my opinion 
the sum of 5 signed 19-bit signals should be stored in 23-bit signal.
Secondly is that if I operate on signed values I should be carefull with 
math operations signs (+/-). If I add negative values as a constant 
signed, in operation of sum of the signals I must use only "+" sign.
I ignored all overflow bits.
It is possible that I have only wrong coefficient. On hardware filter 
works but not correct.

My new, some improved code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity dsp is
    Port ( clk : in  STD_LOGIC := '0';
     clk_adc : out  STD_LOGIC := '0';
     clk_dac : out  STD_LOGIC := '0';
           adc_data : in  STD_LOGIC_VECTOR(9 downto 0) := (others => 
'0');
           dac_data : out  STD_LOGIC_VECTOR(9 downto 0) := (others => 
'0')
       );
end dsp;

architecture Behavioral of dsp is

constant coeff_a0: integer := 133; --coefficients
constant coeff_a1: integer := 262;
constant coeff_a2: integer := 133;

constant coeff_b0: integer := -164;
constant coeff_b1: integer := 70;

constant offset: signed(9 downto 0) :=  "0111111111"; -- +511 in U2

signal adc_buffer: signed(9 downto 0) := (others => '0');
signal dac_buffer: signed(9 downto 0) := (others => '0');

signal mult_a0: signed(19 downto 0):= (others => '0'); --mult registers
signal mult_a1: signed(19 downto 0):= (others => '0');
signal mult_a2: signed(19 downto 0):= (others => '0');


signal mult_b0: signed(19 downto 0):= (others => '0');
signal mult_b1: signed(19 downto 0):= (others => '0');

signal add_all: signed(19 downto 0):= (others => '0');

signal pipe_a0: signed(9 downto 0) := (others => '0'); --delay registers
signal pipe_a1: signed(9 downto 0) := (others => '0');
signal pipe_a2: signed(9 downto 0) := (others => '0');


signal pipe_b0: signed(9 downto 0) := (others => '0');
signal pipe_b1: signed(9 downto 0) := (others => '0');

begin

P0: process(clk)
begin

  if falling_edge(clk) then

  adc_buffer <= signed(adc_data); -- adc give data in U2 code

  pipe_a0 <= adc_buffer;
  pipe_a1 <= pipe_a0;
  pipe_a2 <= pipe_a1;

  pipe_b0 <= add_all(19 downto 10); --truncated sum
  pipe_b1 <= pipe_b0;

  dac_data <= STD_LOGIC_VECTOR(dac_buffer(9 downto 0)); -- write to dac 
(ignore MSB - offset bin conversion)



  mult_a0 <= pipe_a0*to_signed(coeff_a0,10);  -- signed * signed return 
20 bit signed
  mult_a1 <= pipe_a1*to_signed(coeff_a1,10);
  mult_a2 <= pipe_a2*to_signed(coeff_a2,10);

  mult_b0 <= pipe_b0*to_signed(coeff_b0,10);
  mult_b1 <= pipe_b1*to_signed(coeff_b1,10);

  --sum of signed results
  add_all <= mult_a0 + mult_a1 + mult_a2 + mult_b0 + mult_b1; --signed + 
signed + ...

  dac_buffer <= add_all(19 downto 10) + offset; -- to offset binary 
convertion (add 511) signed + signed
    end if;

end process;                               -- dac buffer is 11 bit long

  clk_adc <= clk;
  clk_dac <= clk;


end Behavioral;

: Edited by User
von Andreas (Guest)


Rate this post
useful
not useful
Chris C. wrote:
> In code below coefficient are for 4MHz cut-off frequency but I dont know
> if they are correct.

Did you have a matlab? There is a toolbox available for calculating 
filter coeffiecients in fixed data formats. Also do this toolbox a 
stability analyis of your IIR filter.

Best Regards,

von Duke Scarring (Guest)



Rate this post
useful
not useful
Chris C. wrote:
> It is possible that I have only wrong coefficient. On hardware filter
> works but not correct.
Your coefficents are correct but your code doesn't work.

If I use your coefficients with the implementation biquad, form 1 as 
described on this website [1], I got the expected results.

Can you describe graphically the structure of your IIR filter?

Duke

[1] http://www.iowahills.com/4IIRFilterPage.html

von Chris C. (programmer001)


Attached files:

Rate this post
useful
not useful
Duke,
I would implement the same IIR structure as in picture.

von Duke Scarring (Guest)


Attached files:

Rate this post
useful
not useful
The names in code doesn't match with the schematic, but anyway:

1.  move the multiplications out of your register stage (if *_edge ... 
end if)
2.  mind the polarity signs on the big 'adder'
3.  don't move the adder out of the register stage

Another hint (again): Use falling_edge only if you have a good reason.

Duke

von Thomas R. (Company: abaxor engineering) (abaxor)


Rate this post
useful
not useful
Duke Scarring wrote:
> 1.  move the multiplications out of your register stage (if *_edge ...
> end if)
> 2.  .... the big 'adder'

This will led to a lot of logic levels in this case
- 4 adders
- plus 1 multiplier

I would expect timing problems with the code posted by Chris.

Generally it is difficult to run an IIR-Filter with sampling frequency = 
clock frequency. Since the feed back loop has only one clock budget but 
you need at least two operations, add and multiply. Within a second 
order stage (as shown in the iir.jpg picture) there has to be performed 
three sequential operations, 2 additions and 1 multiplication. Either 
you get many logic levels (in terms of DSP blocks) or to many pipeline 
stages.

What is the reason for your IIR-Filter?

Tom

von Chris C. (programmer001)


Rate this post
useful
not useful
Tom,
I make this filter as a project on high school.
It is very possible that you're right. I spend many hours with trying to 
resolve problem with this filter. I obtain results which magnitude 
characteristic was above 10dB upper than expected which I compue in FDA 
Tool in MATLAB. Interestng is that I implemented FIR filter with the 
same way and it works very good. I saw the VHDL code where IIR filter 
was divided to machine state (as you described the number of operations 
in one clock cycle). Maybe it is a solution of my problem but I need 
100MSPS. I think that the problem is in the second part of my filter, it 
works but 10dB above.

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.