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;