Implement an IIR into my FPGA project


Brightstars

Recommended Posts

I try to implement an IIR into my FPGA project(Have a futher understanding of FPGA=>http://www.apogeeweb.net/article/67.html). I've got the coefficients from my matlab program and implement the gain directly into the coefficients, though I don't need an additional gain multiplier. First I generate the product of the A1,A2,B1 and B2 coefficients, then sum them up, summarize the Input signal with the summation of A1 and A2, then multiply it with b0 and finally create the sum of the B0 product and the B1B2 summation. But my filter doesn't behave like it should in the simulation, is this approach faulty by design or is there some error I don't see in the code?

8jePA.png.c2fca32ea406653309e3a1a485918e25.png

 

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;    
use ieee.NUMERIC_STD.ALL; 
use ieee.std_logic_signed.all;


entity IIR is
generic (
    OUTPUT_WIDTH : integer := 32;
    INPUT_WIDTH : integer := 32;
    B0 : integer := 14419;         -- = ((2^31)/1,995) * 0,000013396 
    B1 : integer := -14105;          -- = ((2^31)/1,995) * -0,000013103
    B2 : integer := 14419;         -- = ((2^31)/1,995) * 0,000013396 
    A1 : integer := -2147268361;        -- = ((2^31)/1,995) * -1,9948 
    A2 : integer := 1070803162          -- = ((2^31)/1,995) * 0,99477 
    );

port (
    iCLK            : in std_logic;
    iRESET_N        : in std_logic;
    inewValue       : in std_logic;                                 -- indicates a new input value
    iIIR_RX         : in std_logic_vector (INPUT_WIDTH-1 downto 0); -- singed is expected
    oDone           : out std_logic;                                -- Done Flag for next Filter
    oIIR_TX         : out std_logic_vector (OUTPUT_WIDTH-1 downto 0)-- Output
    );
end entity IIR;

architecture BEH_FixCoefficientIIR of IIR is

type STATE_TYPE is (idle, mul, s1, s2, s3, s4, convert, finished);
signal state : STATE_TYPE;
constant cA1 : signed(INPUT_WIDTH-1 downto 0)  := to_signed(A1,INPUT_WIDTH);-- A1
constant cA2 : signed(INPUT_WIDTH-1 downto 0)  := to_signed(A2,INPUT_WIDTH);-- A2
constant cB0 : signed(INPUT_WIDTH-1 downto 0)  := to_signed(B0,INPUT_WIDTH);-- B1
constant cB1 : signed(INPUT_WIDTH-1 downto 0)  := to_signed(B1,INPUT_WIDTH);-- B1
constant cB2 : signed(INPUT_WIDTH-1 downto 0)  := to_signed(B2,INPUT_WIDTH);-- B1

signal nSUMX    : signed(INPUT_WIDTH+1 downto 0);
signal nSUMA1A2    : signed(INPUT_WIDTH+1 downto 0);
signal nSUMB1B2    : signed(INPUT_WIDTH+1 downto 0);
signal nSUMXB0    : signed(INPUT_WIDTH+1 downto 0);
signal nB0      : signed((INPUT_WIDTH*2)+1 downto 0);
signal nB1      : signed((INPUT_WIDTH*2)+1 downto 0);
signal nB2      : signed((INPUT_WIDTH*2)+1 downto 0);
signal nA1      : signed((INPUT_WIDTH*2)+1 downto 0);
signal nA2      : signed((INPUT_WIDTH*2)+1 downto 0);
signal nZ1      : signed(INPUT_WIDTH+1 downto 0);
signal nZ2      : signed(INPUT_WIDTH+1 downto 0);
signal nY       : std_logic_vector(INPUT_WIDTH-1 downto 0);
signal nX       : signed(INPUT_WIDTH-1 downto 0);

begin
IIR_STAGES: process (iCLK, iRESET_N)
begin

if(rising_edge(iCLK)) then
    if(iRESET_N = '0') then                 -- Reset Signals and Output
        nSUMX       <= (others => '0');
        nSUMA1A2    <= (others => '0');
        nSUMB1B2    <= (others => '0');
        nSUMXB0     <= (others => '0');
        nZ1         <= (others => '0');
        nZ2         <= (others => '0');
        nB0         <= (others => '0');
        nB1         <= (others => '0');
        nB2         <= (others => '0');
        nA1         <= (others => '0');
        nA2         <= (others => '0');
        nX          <= (others => '0');
        nY          <= (others => '0');
        oDone       <= '0';
        oIIR_TX     <= (others => '0');
        state       <= idle;
    else
        case state is 
            when idle =>
                oDone       <= '0';
                if(iNewValue = '1') then                
                    state   <= mul;
                    nX      <= signed(iIIR_RX);
                end if;
            when mul =>                     -- Multiply signals for sums
                nA1         <= nZ1 * cA1;
                nA2         <= nZ2 * cA2;
                nB1         <= nZ1 * cB1;
                nB2         <= nZ2 * cB2;
                state       <= s1;
            when s1 =>                      -- Create sums 
                nSUMA1A2    <= nA1(nA1'left downto INPUT_WIDTH) - nA2(nA2'left downto INPUT_WIDTH);
                nSUMB1B2    <= nB1(nB1'left downto INPUT_WIDTH) +  nB2(nB2'left downto INPUT_WIDTH);
                state       <= s2;
            when s2 =>                      -- Create Input sum
                nSUMX       <= nX -  nSUMA1A2;
                state       <= s3;
            when s3 =>                      -- Save new values into register and multiply with coefficient B0 for Output-Sum
                nZ1         <= nSUMX;
                nZ2         <= nZ1;
                nB0         <= nSUMX * cB0;
                state   <= s4;
            when s4 =>                      -- Add XB0 and B1B2 summation
                nSUMXB0     <= nB0(nB0'left downto INPUT_WIDTH) + nSUMB1B2;
                state       <= convert;

            when convert =>                 -- convert signed to std logic vector
                nY          <= std_logic_vector(nSUMXB0(nSUMXB0'left downto nSUMXB0'left-INPUT_WIDTH+1));
                state       <= finished;
            when finished =>                -- grab highest bits for output and set Done flag
                oIIR_TX <= nY(nY'left downto (nY'left - OUTPUT_WIDTH+1));
                oDone       <= '1';
                state <= idle;
            when others =>
                state <= idle;
        end case;
    end if;

end if;

end process IIR_STAGES;

end architecture BEH_FixCoefficientIIR;

k1qxh.thumb.png.e85a1bf7ac52a9cc47942dc831863ad9.png

New Async implementation

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;    
use ieee.NUMERIC_STD.ALL;      
use ieee.std_logic_signed.all;


entity IIR is
generic (
    OUTPUT_WIDTH : integer := 48;
    INPUT_WIDTH : integer := 48;
    B0 : integer := 14419;         -- = ((2^31)/1,995) * 0,000013396 
    B1 : integer := -14105;          -- = ((2^31)/1,995) * -0,000013103
    B2 : integer := 14419;         -- = ((2^31)/1,995) * 0,000013396 
    A1 : integer := -2147268361;        -- = ((2^31)/1,995) * -1,9948 
    A2 : integer := 1070803162          -- = ((2^31)/1,995) * 0,99477 
    );

port (
    iCLK            : in std_logic;
    iRESET_N        : in std_logic;
    inewValue       : in std_logic;                                 -- indicates a new input value
    iIIR_RX         : in std_logic_vector (INPUT_WIDTH-1 downto 0); -- singed is expected
    oDone           : out std_logic;                                -- Done Flag for next Filter
    oIIR_TX         : out std_logic_vector (OUTPUT_WIDTH-1 downto 0)-- Output
    );
end entity IIR;

architecture BEH_FixCoefficientIIR of IIR is



constant cA1 : signed(31 downto 0)  := to_signed(A1,32);-- A1
constant cA2 : signed(31 downto 0)  := to_signed(A2,32);-- A2
constant cB0 : signed(31 downto 0)  := to_signed(B0,32);-- B1
constant cB1 : signed(31 downto 0)  := to_signed(B1,32);-- B1
constant cB2 : signed(31 downto 0)  := to_signed(B2,32);-- B1

signal nSUMX    : signed(48 downto 0) := (others => '0');
signal nSUMA1A2    : signed(48 downto 0) := (others => '0');
signal nSUMB1B2    : signed(48 downto 0) := (others => '0');
signal nSUMXB0    : signed(48 downto 0) := (others => '0');
signal nB0      : signed(80 downto 0) := (others => '0');
signal nB1      : signed(80 downto 0) := (others => '0');
signal nB2      : signed(80 downto 0) := (others => '0');
signal nA1      : signed(80 downto 0) := (others => '0');
signal nA2      : signed(80 downto 0) := (others => '0');
signal nZ1      : signed(48 downto 0) := (others => '0');
signal nZ2      : signed(48 downto 0) := (others => '0');
signal nY       : std_logic_vector(47 downto 0) := (others => '0');
signal nX       : signed(47 downto 0) := (others => '0');

begin
nB0 <= nSUMX * cB0;
nB1 <= nZ1 * cB1;
nB2 <= nZ2 * cB2;
nA1 <= nZ1 * cA1;
nA2 <= nZ2 * cA2;
nSUMA1A2 <= nA1(80 downto 32) + nA2(80 downto 32);
nSUMB1B2 <= nB1(80 downto 32) + nB2(80 downto 32);
nSUMXB0 <= nB0(80 downto 32) + nSUMB1B2;
nSUMX <= nX + nSUMA1A2(48 downto 0);
IIR_STAGES: process (iCLK, iRESET_N)
begin

if(rising_edge(iCLK)) then
    if(iNewValue = '1') then 
        nX <= signed(iIIR_RX);
        nZ1 <= nSUMX;
        nZ2 <= nZ1;
        oIIR_TX <= std_logic_vector(nSUMXB0(48 downto 1));
    end if;
end if;
end process IIR_STAGES;

end architecture BEH_FixCoefficientIIR;

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.