Global training solutions for engineers creating the world's electronics

Finite Impulse Response (FIR) Filter

The VHDL code presented in this model will show you how to describe a typical reference model in VHDL. We'll use a 32-tap FIR filter as an example. For a discussion of the advantages of reference models, please refer to our Tips page. Lets's look at some of the highlights of this model.

Most obviously, the model is a single clocked process. The core of the FIR algorithm is embedded in the function sum_of_products which implements the chain of multiply-accumulations. The current data input is the signal a, which is added to the data_table, the set of data inputs sampled over the last N clock cycles (in this example N is 32), courtesy of the shift_fifo function. The coefficients for the filter arrive on the two-dimensional b input; they are stored in the coefficient_table_var array. For the sum_of_products function, the data_table data set has to be re-ordered which is where the reverse_order function comes in.

This FIR model allows bit-level performance modelling. Note that the output wordlength is 21 bits. The input data and coefficients are both 8 bit wordlength:

 

  • An 8-bit by 8-bit multiply produces a 16 bit result
  • There are 32 taps, log2N = 5
  • 16 + 5 gives 21 bits for the output

As the model is clocked and operates on bit-level data, this FIR filter description can be used (and indeed was used) as a reference model for the design of a synthesisable FIR filter.

You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details).

-- FIR Filter Model
--
-- +-----------------------------+
-- |    Copyright 1996 DOULOS    |
-- |        Library:  DSP        |
-- |    designer : Tim Pagden    |
-- |     opened: 30 Sep 1995     |
-- +-----------------------------+

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

library maths;
  use maths.maths_class.all;
library matrix;
  use matrix.matrix_class.all;

entity FIR_32tap_8_8 is
port (
  a : in  std_logic_vector(7 downto 0);
  b : in  logic_8_vector(31 downto 0);
  clock : in  std_logic;
  reset : in  std_logic;
  y : out std_logic_vector(20 downto 0)
);
end FIR_32tap_8_8;

architecture behavioural of FIR_32tap_8_8 is

  constant number_of_taps: integer := 32;

  signal data_table: single_vector(number_of_taps-1 downto 0);
  signal coefficient_table: single_vector(number_of_taps-1 downto 0);

begin

  -- y <= sum_over (0, k-1, a((k-1)-i), b(i))
  -- coefficient_table <= b;

  fir_algorithm: process (clock)
    variable data_out : single;
    variable fir_result : single;
    variable data_table_var: single_vector(number_of_taps-1 downto 0);
    -- the coeff table assignment really ought to be handled at the entity interface
    variable coefficient_table_var: single_vector(number_of_taps-1 downto 0);
    variable tmp : single_vector(number_of_taps-1 downto 0);
    variable tmp2 : single;
    variable tmp3 : single_vector(number_of_taps-1 downto 0);
    variable tmp4 : integer;
    variable num_taps_minus_1 : integer;
    variable y_result : signed(20 downto 0);
  begin
    if rising_edge(clock) then
      -- data_table_var := data_table(number_of_taps-1) & data_table(number_of_taps-2 downto 0);
      -- putting the coeff table in a loop like this allows dynamic coeff updating
      for i in 0 to number_of_taps-1 loop
        coefficient_table_var(i) := single(to_integer(unsigned(b(i))))/127.0;
      end loop;
      -- tmp := reverse_order(data_table_var);

      -- tmp2 := 0.15;  + to_integer(a);
      data_table_var := data_table;
      tmp2 := single(to_integer(signed(a)));
      data_table_var := shift_fifo (data_table_var, tmp2); -- fifo =>  data_in =>
      data_table <= data_table_var;

      -- tmp3 := reverse_order(data_table_var);
      -- tmp4 := 0;
      num_taps_minus_1 := number_of_taps-1;
      fir_result := sum_of_products (
        lower_limit => 0,
        upper_limit => number_of_taps-1,
        a_in => reverse_order(data_table_var),
        b_in => coefficient_table_var
      );
      y_result := to_signed(integer(fir_result), y_result'length);
      y <= std_logic_vector(y_result);
    end if;
  end process;

end behavioural;

To download the VHDL source code for this model, click here.

 

Back to VHDL models.

Great training!! Excellent Instructor, Excellent facility ...Met all my expectations.
Henry Hastings
Lockheed Martin

View more references