How to Implement FIR Filter in VHDL

FIR Filter Introduction

Finite Impulse Response (FIR) filters are characterized by a time response depending only on a given number of the last samples of the input signal. For a causal discrete-time FIR filter of order N, each value of the output sequence is a weighted sum of the most recent input values:

 

fir_filter_equation

 

 

 

where:

  • x[n] is the input signal,
  • y[n] is the output signal,
  • N is the filter order; a Nth-order filter has (N+1) terms on the right-hand side
  • bi is the value of the impulse response at the i’th instant for 0<= i <=N of a Nth-order FIR filter. If the filter is a direct form FIR filter then is also a coefficient of the filter (see Figure1).

This computation is also known as discrete convolution.

On Wikipedia FIR web-page, you can find further information on FIR design theory.

fir-direct-form
Figure 1 – FIR Filter direct form implementation

 

FIR Filter Hardware Architecture

Here we want to see how to implement FIR filter architecture in FPGA or ASIC using VHDL.

Figure 2 reports an example of 4 taps FIR direct form that can be simply coded in VHDL. In figure 2, the input x(n) and the coefficient bi are 8-bits signed.

After the filter coefficients multiplication, the multiplier output dynamic will be an 8+8=16 bit.

In fact, when you multiply two numbers of N-bit and M-bit the output dynamic of the multiplication result is (N+M)-bits.

When you perform addition, the number of bit of the result will be incremented by 1. The FIR filter design architecture of figure 2  can be easily extended to a length greater than 4.

4-taps FIR Filter hardware architecture example

FIR Filter Design VHDL Code

Here below is reported the VHDL code for the FIR filter design of figure 2. The VHDL code implements a low pass FIR filter with 4 taps, 8-bit input, 8-bit coefficient.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity fir_filter_4 is
port (
  i_clk        : in  std_logic;
  i_rstb       : in  std_logic;
  -- coefficient
  i_coeff_0    : in  std_logic_vector( 7 downto 0);
  i_coeff_1    : in  std_logic_vector( 7 downto 0);
  i_coeff_2    : in  std_logic_vector( 7 downto 0);
  i_coeff_3    : in  std_logic_vector( 7 downto 0);
  -- data input
  i_data       : in  std_logic_vector( 7 downto 0);
  -- filtered data 
  o_data       : out std_logic_vector( 9 downto 0));
end fir_filter_4;

architecture rtl of fir_filter_4 is

type t_data_pipe      is array (0 to 3) of signed(7  downto 0);
type t_coeff          is array (0 to 3) of signed(7  downto 0);

type t_mult           is array (0 to 3) of signed(15    downto 0);
type t_add_st0        is array (0 to 1) of signed(15+1  downto 0);

signal r_coeff              : t_coeff ;
signal p_data               : t_data_pipe;
signal r_mult               : t_mult;
signal r_add_st0            : t_add_st0;
signal r_add_st1            : signed(15+2  downto 0);

begin

p_input : process (i_rstb,i_clk)
begin
  if(i_rstb='0') then
    p_data       <= (others=>(others=>'0'));
    r_coeff      <= (others=>(others=>'0'));
  elsif(rising_edge(i_clk)) then
    p_data      <= signed(i_data)&p_data(0 to p_data'length-2);
    r_coeff(0)  <= signed(i_coeff_0);
    r_coeff(1)  <= signed(i_coeff_1);
    r_coeff(2)  <= signed(i_coeff_2);
    r_coeff(3)  <= signed(i_coeff_3);
  end if;
end process p_input;

p_mult : process (i_rstb,i_clk)
begin
  if(i_rstb='0') then
    r_mult       <= (others=>(others=>'0'));
  elsif(rising_edge(i_clk)) then
    for k in 0 to 3 loop
      r_mult(k)       <= p_data(k) * r_coeff(k);
    end loop;
  end if;
end process p_mult;

p_add_st0 : process (i_rstb,i_clk)
begin
  if(i_rstb='0') then
    r_add_st0     <= (others=>(others=>'0'));
  elsif(rising_edge(i_clk)) then
    for k in 0 to 1 loop
      r_add_st0(k)     <= resize(r_mult(2*k),17)  + resize(r_mult(2*k+1),17);
    end loop;
  end if;
end process p_add_st0;

p_add_st1 : process (i_rstb,i_clk)
begin
  if(i_rstb='0') then
    r_add_st1     <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    r_add_st1     <= resize(r_add_st0(0),18)  + resize(r_add_st0(1),18);
  end if;
end process p_add_st1;

p_output : process (i_rstb,i_clk)
begin
  if(i_rstb='0') then
    o_data     <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    o_data     <= std_logic_vector(r_add_st1(17 downto 8));
  end if;
end process p_output;


end rtl;

 

The FIR filter is implemented fully pipelined, in fact, there is a registration stage at the output of each multiplication or addition.

The output dynamic of the FIR filter is 10-bit, i.e. is not fully dynamic output.

The VHDL code of the FIR filter can be implemented either in ASIC or in FPGA. The implementation should be guarantee full speed for the FIR filter.

Figure 3 shows RTL viewer of Altera Quartus II for the FIR filter VHLD example code above

Figure 3 - FIR Filter Quartus II RTL viewer
Figure 3 – FIR Filter Quartus II RTL viewer

 

If you appreciated this post, please help us to share it with your friend.

 

[social_sharing style=”style-7″ fb_like_url=”https://surf-vhdl.com/how-to-implement-fir-filter-in-vhdl” fb_color=”light” fb_lang=”en_US” fb_text=”like” fb_button_text=”Share” tw_lang=”en” tw_url=”https://surf-vhdl.com/how-to-implement-fir-filter-in-vhdl” tw_button_text=”Share” g_url=”https://surf-vhdl.com/how-to-implement-fir-filter-in-vhdl/” g_lang=”en-US” g_button_text=”Share” linkedin_url=”https://surf-vhdl.com/how-to-implement-fir-filter-in-vhdl” linkedin_lang=”en_US” alignment=”center”]

 

If you need to contact us, please write to: surf.vhdl@gmail.com

We appreciate any of your comment, please post below:

71 thoughts to “How to Implement FIR Filter in VHDL”

  1. Thanks Francesco! Compact and very useful codes!
    Question: If the number of taps were generics, how can i generate the seperate process statements for the adder tree? can you give an example?
    Thanks!

      1. Thanks for the reply!

        I think it should be possible to realize a parametrized (Generic) adder tree using GENERATE statement.

        All the best!

  2. Can you have verilog code for FIR filter design, with hardware implementation.

    Help me, Im not understood how filter working in real time, shall u give me some notes

    1. you have to start with math parallelization of the filter,
      then you can use the FIR template to implement the code

    1. just put your email in the box in the post. If you have problem in receiving the email, check your spam folder, sometimes the email is marked as spam

  3. hi dear,
    I need some help on one project, I want to design FIR filter in FPGA using VHDL and connect it with any medium using high-speed serial interface to observer performance of FIR filter. can anyone help me in this regards?

    BR:
    Sarwan

  4. Could you please elaborate on those 3 Lines of the Code
    p_data <= signed(i_data)&p_data(0 to p_data'length-2);

    for k in 0 to 1 loop
    r_add_st0(k) <= resize(r_mult(2*k),17) + resize(r_mult(2*k+1),17);
    end loop;

    r_add_st1 <= resize(r_add_st0(0),18) + resize(r_add_st0(1),18);

    Thank you

    1. the function “resize” is used to extend the number of bit of its argument.
      For instance
      resize(r_mult(2*k),17)

      extend to 17-bit the 16-bit multiplier output register extending the sign bit

  5. Kindly can any one explain to me why in this line it’s Legnth – 2 (Which i though since the new entered data is a new 8 bits ,so it should be Legnth – 1)

    p_data <= signed(i_data)&p_data(0 to p_data'length-2);

    1. The “p_data” represents the filter data pipe.
      In the example above the data pipe length is 4 registers of 8 bits.
      The code can be rewritten as:

      p_data <= signed(i_data)&p_data(0 to 2); since p_data'length = 4

  6. Hello,
    I really liked this post. The post is one of the most helpful FIR filter tutorial on the internet.
    I have one question about this code.

    o_data <= std_logic_vector(r_add_st1(17 downto 8));

    I believe this line of code divides the result by 128 (shifting). Why is that neccesary? I guess it is related to coefficients scaling, but I want to know why it is neccesary and how you come up with 128. Can you eloborate?

    Thanks!

  7. Hello,
    This is the most helpful post about FIR filter on the internet! Thanks for sharing. I have one question about the VHDL code.
    o_data <= std_logic_vector(r_add_st1(17 downto 8));
    I believe this line of code divides r_add_st1 by 256. Why is that neccesary? I assume this has something to do with coefficients scaling/quantization. How do you come up with 256? Can you eloborate?
    Thanks!

  8. Sir/Madam
    how can i implement the same 4 tap fir low pass filter in structural model! whether it is possible to call adders and multipliers programs for implementing 4 tap FIR Filter?

  9. Hai sir,
    How to compare the lowpass filter output from modelsim to lowpass filter from Matlab.
    I generated filter coefficients fdatool from Matlab.

      1. i use float core to convert my standard IEEE 32 bit float input to fixed point and use this code bud I dont know how to change the sampling frequency

  10. sir/mam,
    i want code for chebysev filter(IIR). Can you please provide me the code,its an urgent need for my final year project.

  11. In the test bench, you are using several coefficients -10, 110, 127, -20.
    And the input is delta or a step of magnitude 127.
    What is the equivalent float value above numbers if I want to do hand calculation using the formula of filter?

    That is y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] + b3*x[n-3]

    Can you brief of how to convert filter coefficients to integers (fixed point) used in FPGAs

    Thanks

  12. how we can add latch enable input in this code
    for example we have 100 clock sample rate so every 100 clock , for one clock we have latch enable = 1
    so i_data in every 100 clock latch and filter
    please help meee

Leave a Reply

Your email address will not be published. Required fields are marked *