200 likes | 225 Views
Learn about Finite Impulse Response filters, convolution in time and frequency domains, direct and transform FIR filter forms, bit growth, serial FIR filters, optimal hardware designs, and FPGA implementation using Xilinx ISE/WebPack.
E N D
ECE 448: Lab 4 FIR Filters
Agenda for today Part 1: Introduction to Experiment 4: FIR Filter Part 2: Hands-on Session: FPGA Design Flow Based on Xilinx ISE/WebPack and ModelSim
Filters |·| • Keep the green, block the red. • Blue is a Low Pass Filter (LPF) • Multiplication in frequency domain • Convolution in time domain -ω -ωs -ωp ωp ωs ω
Convolution Equations • Continuous time • Discrete time
Convolution Problems • The function g[n] is called the “filter taps” • Infinite number of taps is impossible to implement. • Not enough space to store taps! • Not enough time to compute output! • For this reason, we take a finite number of taps (normally centered at n=0)
Direct Form FIR Filter • FIR = Finite Impulse Response • Simple to implement in VHDL • Very long critical path (1 mults + M-1 adds) x(n) Z-1 Z-1 Z-1 h0 h1 h2 hM-1 y(n)
Direct Form Transform FIR Filter • Greatly reduced critical path • 1 Multiply and 1 Add • Constant regardless of filter length • Taps are reversed • Still a problem? x(n) hM-1 hM-2 hM-3 h0 Z-1 Z-1 Z-1 y(n)
Bit growth • bit_length(a*b) = bit_length(a) + bit_length(b) • bit_length(a+b) = max(bit_length(a),bit_length(b))+1 • If filter has “unity gain”, adders do not cause growth x(n) 2p p 2p p 2p 2p hM-1 hM-2 hM-3 h0 Z-1 Z-1 Z-1 Q y(n)
Serial FIR Filter • Reuse Multiplier and Accumulator (MACC) • M cycles to compute • Hardware reduced by factor of M Cycle through h(M-1) through h(0) hold x(n) for M samples y(n) valid after M samples Z-1
Optimal Hardware • All hardware can be made out of LUT/FF Combination • Possibly the best solution, maybe not • Might be better, optimal hardware • Three (3) ways to use optimal hardware • Inference • Usually best • Faster Simulation • No extra libraries • Not FPGA specific • Instantiation • CoreGen
Inference library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity mult18x18 is generic ( word_size : natural := 18; signed_mult : boolean := true); port ( clk : in std_logic; a : in std_logic_vector(1*word_size-1 downto 0); b : in std_logic_vector(1*word_size-1 downto 0); c : out std_logic_vector(2*word_size-1 downto 0)); end entity mult18x18; architecture infer of mult18x18 is begin process(clk) begin if rising_edge(clk) then if signed_mult then c <= std_logic_vector(signed(a) * signed(b)); else c <= std_logic_vector(unsigned(a) * unsigned(b)); end if; end if; end process; end architecture infer;
Instantiation -- Component Declaration for MULT18X18 should be placed -- after architecture statement but before begin keyword component MULT18X18 port ( P : out STD_LOGIC_VECTOR (35 downto 0); A : in STD_LOGIC_VECTOR (17 downto 0); B : in STD_LOGIC_VECTOR (17 downto 0)); end component; -- Component Attribute specification for MULT18X18 -- should be placed after architecture declaration but -- before the begin keyword -- Attributes should be placed here -- Component Instantiation for MULT18X18 should be placed -- in architecture after the begin keyword MULT18X18_INSTANCE_NAME : MULT18X18 port map (P => user_P, A => user_A, B => user_B);
CoreGen • For more complicated hardware (like FIFOs) • Use Xilinx tools to generate the instantiation with particular settings • Will not use until future lab
Extra Information • Entity declaration entity fir_filter is port( clk : in std_logic; reset : in std_logic; -- Input signals samp_i : in std_logic; data_i : in std_logic_vector(15 downto 0); -- Output signals samp_o : out std_logic; data_o : out std_logic_vector(15 downto 0)); end entity fir_filter;
Extra Information (2) • samp_i is a one-cycle clock enable • samp_o is a one_cycle “calculation finished” signal • data_in is 16 bits (or 18 bits if you feel ambitious) • data_out is 16 bits (quantized)
Extra Information (3) • Nested types • Used for multidimensional arrays • Also used for ROM/RAM interfaces • Usually enough to infer such memory units type word_vector is array (natural range <>) of signed(15 downto 0); constant taps : word_vector(0 to 31) := ( x"0001", x"0002", x"0003", x"0004", x"0005", x"0006", x"0007", x"0008", x"0009", x"000A", x"000B", x"000C", x"000D", x"000E", x"000F", x"0010", x"0011", x"0012", x"0013", x"0014", x"0015", x"0016", x"0017", x"0018", x"0019", x"001A", x"001B", x"001C", x"001D", x"001E", x"001F", x"0020");
Extra Information (4) • Test filter with Impulse • …,zero, zero, zero, one, zero, zero, zero… • Test Circuit with ‘ramp’ taps • taps <= (x”0001”,x”0002”,x”0003”,… • Testing with ‘ramp’ helps test filter function • Replace ‘ramp’ with ‘sinc’ taps • Sinc taps are used because rectangle in freq domain is sin(x)/x=sinc(x) in time domain • Make sure ‘sinc’ comes out of filter
Part 2 Hands-on Session FPGA Design Flow Based on Xilinx ISE/WebPack & ModelSim