Wednesday 16 April 2014

Developing & Delivering KnowHow

Home > Knowhow > Vhdl Designers Guide > Models > Finite Impulse Response FIR Filter

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);


  -- 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);
    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.

Your e-mail comments are welcome - send email

Copyright 1995-2008 Doulos

Privacy Policy Site Map Contact Us