Implementar la estructura IIR SOS en FPGA

0

Intento implementar un IIR en mi proyecto FPGA. Obtuve los coeficientes de mi programa matlab e implementé la ganancia directamente en los coeficientes, aunque no necesito un multiplicador de ganancia adicional. Primero genero el producto de los coeficientes A1, A2, B1 y B2, luego los sumo, resumen la señal de entrada con la suma de A1 y A2, luego lo multiplico por b0 y finalmente creo la suma del producto B0 y B1B2 suma. Pero mi filtro no se comporta como debería en la simulación, ¿este enfoque es defectuoso por diseño o hay algún error que no veo en el código?

LIBRARYieee;USEieee.std_logic_1164.ALL;useieee.NUMERIC_STD.ALL;useieee.std_logic_signed.all;entityIIRisgeneric(OUTPUT_WIDTH:integer:=32;INPUT_WIDTH:integer:=32;B0:integer:=14419;--=((2^31)/1,995)*0,000013396B1:integer:=-14105;--=((2^31)/1,995)*-0,000013103B2:integer:=14419;--=((2^31)/1,995)*0,000013396A1:integer:=-2147268361;--=((2^31)/1,995)*-1,9948A2:integer:=1070803162--=((2^31)/1,995)*0,99477);port(iCLK:instd_logic;iRESET_N:instd_logic;inewValue:instd_logic;--indicatesanewinputvalueiIIR_RX:instd_logic_vector(INPUT_WIDTH-1downto0);--singedisexpectedoDone:outstd_logic;--DoneFlagfornextFilteroIIR_TX:outstd_logic_vector(OUTPUT_WIDTH-1downto0)--Output);endentityIIR;architectureBEH_FixCoefficientIIRofIIRistypeSTATE_TYPEis(idle,mul,s1,s2,s3,s4,convert,finished);signalstate:STATE_TYPE;constantcA1:signed(INPUT_WIDTH-1downto0):=to_signed(A1,INPUT_WIDTH);--A1constantcA2:signed(INPUT_WIDTH-1downto0):=to_signed(A2,INPUT_WIDTH);--A2constantcB0:signed(INPUT_WIDTH-1downto0):=to_signed(B0,INPUT_WIDTH);--B1constantcB1:signed(INPUT_WIDTH-1downto0):=to_signed(B1,INPUT_WIDTH);--B1constantcB2:signed(INPUT_WIDTH-1downto0):=to_signed(B2,INPUT_WIDTH);--B1signalnSUMX:signed(INPUT_WIDTH+1downto0);signalnSUMA1A2:signed(INPUT_WIDTH+1downto0);signalnSUMB1B2:signed(INPUT_WIDTH+1downto0);signalnSUMXB0:signed(INPUT_WIDTH+1downto0);signalnB0:signed((INPUT_WIDTH*2)+1downto0);signalnB1:signed((INPUT_WIDTH*2)+1downto0);signalnB2:signed((INPUT_WIDTH*2)+1downto0);signalnA1:signed((INPUT_WIDTH*2)+1downto0);signalnA2:signed((INPUT_WIDTH*2)+1downto0);signalnZ1:signed(INPUT_WIDTH+1downto0);signalnZ2:signed(INPUT_WIDTH+1downto0);signalnY:std_logic_vector(INPUT_WIDTH-1downto0);signalnX:signed(INPUT_WIDTH-1downto0);beginIIR_STAGES:process(iCLK,iRESET_N)beginif(rising_edge(iCLK))thenif(iRESET_N='0')then--ResetSignalsandOutputnSUMX<=(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;elsecasestateiswhenidle=>oDone<='0';if(iNewValue='1')thenstate<=mul;nX<=signed(iIIR_RX);endif;whenmul=>--MultiplysignalsforsumsnA1<=nZ1*cA1;nA2<=nZ2*cA2;nB1<=nZ1*cB1;nB2<=nZ2*cB2;state<=s1;whens1=>--CreatesumsnSUMA1A2<=nA1(nA1'leftdowntoINPUT_WIDTH)-nA2(nA2'leftdowntoINPUT_WIDTH);nSUMB1B2<=nB1(nB1'leftdowntoINPUT_WIDTH)+nB2(nB2'leftdowntoINPUT_WIDTH);state<=s2;whens2=>--CreateInputsumnSUMX<=nX-nSUMA1A2;state<=s3;whens3=>--SavenewvaluesintoregisterandmultiplywithcoefficientB0forOutput-SumnZ1<=nSUMX;nZ2<=nZ1;nB0<=nSUMX*cB0;state<=s4;whens4=>--AddXB0andB1B2summationnSUMXB0<=nB0(nB0'leftdowntoINPUT_WIDTH)+nSUMB1B2;state<=convert;whenconvert=>--convertsignedtostdlogicvectornY<=std_logic_vector(nSUMXB0(nSUMXB0'leftdowntonSUMXB0'left-INPUT_WIDTH+1));state<=finished;whenfinished=>--grabhighestbitsforoutputandsetDoneflagoIIR_TX<=nY(nY'leftdownto(nY'left-OUTPUT_WIDTH+1));oDone<='1';state<=idle;whenothers=>state<=idle;endcase;endif;endif;endprocessIIR_STAGES;endarchitectureBEH_FixCoefficientIIR;

Nueva implementación asíncrona

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;
    
pregunta DK999

1 respuesta

0

Así que finalmente he escrito un IIR de trabajo con variables QFormat y bits de guarda. Parece funcionar bastante bien, incluso en una cascada. El único inconveniente es que algunos coeficientes que están realmente cerca del círculo unitario no funcionan, pero todos los polos por debajo de 0.95 parecen estar bien.

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 := 64;
    INPUT_WIDTH : integer := 64;
    QFORMAT     : integer := 11;
    GUARDBITS   : integer := 4;
    B0 : integer := 409494;  
    B1 : integer := 818988;  
    B2 : integer := 409494;  
    A1 : integer := -3954428; 
    A2 : integer := 1398100  
    );
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 behavioral of IIR is

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

signal nSUMX    : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);             -- Sum of shifted Input and recursive sum
signal nSUMA1A2    : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);        -- Sum of recursive multiplication
signal nSUMB1B2    : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);          -- Sum of forward multiplication
signal nSUMXB0    : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);           -- Sum before Output
signal nB0      : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);           -- Multiplication of B0
signal nB1      : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);           -- Multiplication of B1
signal nB2      : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);           -- Multiplication of B2
signal nA1      : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);           -- Multiplication of A1
signal nA2      : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT+3 downto 0);           -- Multiplication of A2
signal nZ1      : signed(INPUT_WIDTH-1+GUARDBITS downto 0);
signal nZ2      : signed(INPUT_WIDTH-1+GUARDBITS downto 0);
signal nX       : signed(INPUT_WIDTH+QFORMAT-1 downto 0);
signal nAll0    : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT downto 0) := (others=>'0');           -- Sum before Output
signal nAll1    : signed(INPUT_WIDTH-1+GUARDBITS+QFORMAT downto 0) := (others=>'1');           -- Sum before Output
signal nMAX     : std_logic := '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');
        oDone       <= '0';
        oIIR_TX     <= (others => '0');
    else
        case state is 
            when idle =>
                oDone       <= '0';
                if(iNewValue = '1') then                                                -- If new signal arrives
                    state   <= mul;                                                     -- Change state to multiply
                    nX(INPUT_WIDTH-1 downto 0) <= signed(iIIR_RX);                      -- Get Input signal
                    if(iIIR_RX(iIIR_RX'left) = '1') then
                        nX(nX'left downto INPUT_WIDTH) <= (others => '1');
                    end if;

                end if;
            when mul =>                                                                 -- Multiply signals for sums
                nA1         <= nZ1 * cA1;                                               -- Multiplay old Data from nZ1 with cA1
                nA2         <= nZ2 * cA2;                                               -- Multiplay old Data from nZ2 with cA2
                nB1         <= nZ1 * cB1;                                               -- Multiplay old Data from nZ1 with cB1
                nB2         <= nZ2 * cB2;                                               -- Multiplay old Data from nZ2 with cB2
                nX          <= shift_left(signed(nX),QFORMAT);                          -- Right shift Input signal to meet coefficient multiplication determined by the Q-Format 2^n
                state       <= s1;
            when s1 =>                      -- Create sums 
                nSUMA1A2    <= nA1(nA1'left downto 0) + nA2(nA2'left downto 0);    
                nSUMB1B2    <= nB1(nB1'left downto 0) +  nB2(nB2'left downto 0);
                state       <= s2;
            when s2 =>                      -- Create Input sum
                nSUMX       <= nX -  nSUMA1A2(nSUMA1A2'left downto 0);                -- substract SUMA1A2 from Input signal because recursive signals always get substracted
                state       <= s3;
            when s3 =>                      -- Save new values into register and multiply with coefficient B0 for Output-Sum
                nZ1         <= nSUMX(nSUMX'left-3 downto QFORMAT);                        -- Store right value by dividing 2^Q-FORMAT
                nZ2         <= nZ1;                                                     -- Store old value
                nB0         <= nSUMX(nSUMX'left-3 downto QFORMAT) * cB0;                  -- Multiply B0 by Input signal
                state   <= s4;
            when s4 =>                      -- Add XB0 and B1B2 summation
                nSUMXB0     <= nB0(nB0'left-2 downto 0) + nSUMB1B2;                     -- Add SUMB1B2 to forward multiplication nB0 
                state       <= convert;

            when convert =>                 -- convert signed to std logic vector, check for overflow
                if((nSUMXB0(nSUMXB0'left downto nSUMXB0'left-(GUARDBITS+1)) = nAll0(nAll0'left downto nAll0'left-(GUARDBITS+1))) OR (nSUMXB0(nSUMXB0'left downto nSUMXB0'left-(GUARDBITS+1)) = nAll1(nAll1'left downto nAll1'left-(GUARDBITS+1)))) then
                    oIIR_TX     <= std_logic_vector(nSUMXB0(nSUMXB0'left-GUARDBITS-3 downto QFORMAT));
                    nMAX        <= '0';
                else
                    if(nSUMXB0(nSUMXB0'left) = '1') then
                        oIIR_TX  <= (others=>'0');
                        oIIR_TX(oIIR_TX'left) <= '1';
                        nMAX        <= '1';
                    else
                        oIIR_TX  <= (others=>'1');
                        oIIR_TX(oIIR_TX'left) <= '0';
                        nMAX        <= '1';
                    end if;
                end if;
                oDone       <= '1';
                state       <= idle;
                nX <= (others => '0');
            when others =>
                state <= idle;
        end case;
    end if;

end if;
end process IIR_STAGES;
end architecture behavioral;
    
respondido por el DK999

Lea otras preguntas en las etiquetas