和“无崖子”一起练“内功” 本次介绍基于FPGA的无限冲激响应滤波器IIR,理论不多介绍,说白了IIR滤波器是带反馈的FIR滤波器。 设计步骤如下: 一,利用matlab计算出滤波器系数。 1,利用有函数比如cheby1,cheby2,butter,ellip计算出滤波器系数 这里以cheby2为例: N=7;%滤波器阶数 rp=60;%抑制dB Wp=0.3;%归一化频率 [b,a]=cheby2(N,rp,Wp); 2,对b,a 进行16bit量化取整, -a=2048 -8444 15752 -16938 11259 -4602 1067 -108 --b=7 -5 12 2 2 12 -5 7 3,取补码 --a=0800 DF04 3D88 BDD6 2BFB EE06 042B FF94 --b= 0007 FFFB 000C 0002 0002 000C FFFB 0007 二,FPGA实现 根据计算出的滤波器系数,对应直接型IIR滤波器原理框图如下: 上图中可以看出IIR滤波器,相当于Xn经过FIR滤波器和Yn经过FIR滤波器后相减除常系数,作为输出并反馈给Yn输入。 1,Xn经过FIR滤波器 -- Xn乘加和,与FIR相同 Library IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_arith.all; USE IEEE.std_logic_signed.all; Entity IIR_Xn is port ( Rst:in std_logic;--复位 Clk:in std_logic;--时钟 Xn_in:in std_logic_vector(11 downto 0);--信号输入 Xn_out:out std_logic_vector(30 downto 0)--滤波后信号输出
); end IIR_Xn; architecture behave of IIR_Xn is
----------------------------------- --component声明
-----------------------------------
component multx0--LPM IP核乘法器(配置18个常数乘法器,会节省不少逻辑资源,但是灵活性较低) PORT ( dataa : IN STD_LOGIC_VECTOR (15 DOWNTO 0); datab : IN STD_LOGIC_VECTOR (12 DOWNTO 0); result : OUT STD_LOGIC_VECTOR (28 DOWNTO 0) ); end component;
----------------------------------- --signal声明 type Xn_in_reg is array(7 downto 0)of STD_LOGIC_VECTOR (11 DOWNTO 0);--8个12bit的寄存器,输入信号先存入该寄存器阵列中相当于Z-1延迟。 type Xn_in_add_reg is array(3 downto 0)of STD_LOGIC_VECTOR (12 DOWNTO 0);--4个13bit的寄存器,对称相加后结果,先存入该寄存器阵列中。 type Xn_muADD_reg is array(3 downto 0)of STD_LOGIC_VECTOR (28 DOWNTO 0);--输入信号乘加系数后存入其中。
--定义三指针分别指向上面三个存储阵列 signal Xn_in_reg_point:Xn_in_reg; signal Xn_in_add_reg_point:Xn_in_add_reg; signal Xn_muADD_reg_point:Xn_muADD_reg;
--将滤波器系数声明成常量
constant b0:std_LOGIC_VECTOR(15 downto 0):=x'0007'; constant b1:std_LOGIC_VECTOR(15 downto 0):=x'FFFB'; constant b2:std_LOGIC_VECTOR(15 downto 0):=x'000C'; constant b3:std_LOGIC_VECTOR(15 downto 0):=x'0002';
begin --数据装入移位寄存器,延迟 sig_in_shift:process(Clk,Rst) begin if Rst='0'then for i in 0 to 7 loop Xn_in_reg_point(i)<=(others=>'0'); end loop; elsif rising_edge(Clk)then for i in 0 to 6 loop--sig_in_reg_point(i+1)中是i+1,所以循环中最大为6,最后一位为传给Xn_in_reg_point(7). Xn_in_reg_point(i+1)<=Xn_in_reg_point(i); end loop; Xn_in_reg_point(0)<=Xn_in; end if; end process;
--对称系数xn相加 Xn_in_add_reg_point(0)<=(Xn_in_reg_point(0)(11)&Xn_in_reg_point(0))+(Xn_in_reg_point(7)(11)&Xn_in_reg_point(7)); Xn_in_add_reg_point(1)<=(Xn_in_reg_point(1)(11)&Xn_in_reg_point(1))+(Xn_in_reg_point(6)(11)&Xn_in_reg_point(6)); Xn_in_add_reg_point(2)<=(Xn_in_reg_point(2)(11)&Xn_in_reg_point(2))+(Xn_in_reg_point(5)(11)&Xn_in_reg_point(5)); Xn_in_add_reg_point(3)<=(Xn_in_reg_point(3)(11)&Xn_in_reg_point(3))+(Xn_in_reg_point(4)(11)&Xn_in_reg_point(4)); --分子系数相乘 Umultx0:multx0--乘法器 port map( dataa=>b0, datab=>Xn_in_add_reg_point(0), result=>Xn_muADD_reg_point(0) ); Umultx1:multx0--乘法器 port map( dataa=>b1, datab=>Xn_in_add_reg_point(1), result=>Xn_muADD_reg_point(1) ); Umultx2:multx0--乘法器 port map( dataa=>b2, datab=>Xn_in_add_reg_point(2), result=>Xn_muADD_reg_point(2) ); Umultx3:multx0--乘法器 port map( dataa=>b3, datab=>Xn_in_add_reg_point(3), result=>Xn_muADD_reg_point(3) ); --计算传输函数中分子系数乘后累加 SUM_pro:process(Clk,Rst,Xn_muADD_reg_point) variable SUM1:std_LOGIC_VECTOR(30 downto 0); begin if Rst='0'then SUM1:=(others=>'0'); Xn_out<=(others=>'0'); elsif falling_edge(clk)then Xn_out<=SUM1; SUM1:=(others=>'0'); for i in 0 to 7 loop SUM1:=SUM1+(Xn_muADD_reg_point(i)(28)&Xn_muADD_reg_point(i)(28)&Xn_muADD_reg_point(i)); end loop; end if; end process; end behave; 2,Yn经过FIR 滤波器 Library IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_arith.all; USE IEEE.std_logic_signed.all; Entity IIR_Yn is port ( Rst:in std_logic;--复位 Clk:in std_logic;--时钟 Yn_in:in std_logic_vector(15 downto 0);--信号输入 Yn_out:out std_logic_vector(34 downto 0)--乘加后信号输出
); end IIR_Yn; architecture behave of IIR_Yn is
----------------------------------- --component声明
----------------------------------- component mult0--LPM IP核乘法器(配置18个常数乘法器,会节省不少逻辑资源,但是灵活性较低) PORT ( dataa : IN STD_LOGIC_VECTOR (15 DOWNTO 0); datab : IN STD_LOGIC_VECTOR (15 DOWNTO 0); result : OUT STD_LOGIC_VECTOR (31 DOWNTO 0) ); end component;
----------------------------------- --signal声明
type Yn_reg is array(6 downto 0)of STD_LOGIC_VECTOR (15 DOWNTO 0);--Y0除2048后存入其中(反馈信号)。 type Yn_mul_reg is array(6 downto 0)of STD_LOGIC_VECTOR (31 DOWNTO 0);--7个31bit的寄存器,对称信号相加后与滤波系数相乘结果存入其中。 --定义三指针分别指向上面三个存储阵列 signal Yn_reg_point:Yn_reg; signal Yn_mul_reg_point:Yn_mul_reg; --将滤波器系数声明成常量 constant a0:std_LOGIC_VECTOR(15 downto 0):=x'0800'; constant a1:std_LOGIC_VECTOR(15 downto 0):=x'DF04'; constant a2:std_LOGIC_VECTOR(15 downto 0):=x'3D88'; constant a3:std_LOGIC_VECTOR(15 downto 0):=x'BDD6'; constant a4:std_LOGIC_VECTOR(15 downto 0):=x'2BFB'; constant a5:std_LOGIC_VECTOR(15 downto 0):=x'EE06'; constant a6:std_LOGIC_VECTOR(15 downto 0):=x'042B'; constant a7:std_LOGIC_VECTOR(15 downto 0):=x'FF94';
begin
--数据Yn数据装入移位寄存器 Yn_shift:process(Clk,Rst,Yn_reg_point,Yn_mul_reg_point)
begin if Rst='0'then for i in 0 to 6 loop Yn_reg_point(i)<=(others=>'0'); end loop;
elsif falling_edge(Clk)then for i in 0 to 5 loop--sig_in_reg_point(i+1)中是i+1,所以循环中最大为5,最后一位为传给Yn_reg_point((6). Yn_reg_point(i+1)<=Yn_reg_point(i); end loop; Yn_reg_point(0)<=Yn_in; end if; end process;
--计算传输函数分母输入数据乘加,并行计算方式 --例化7个乘法器 Umult1:mult0--乘法器 port map( dataa=>a1, datab=>Yn_reg_point(0), result=>Yn_mul_reg_point(0) ); Umult2:mult0--乘法器 port map( dataa=>a2, datab=>Yn_reg_point(1), result=>Yn_mul_reg_point(1) ); Umult3:mult0--乘法器 port map( dataa=>a3, datab=>Yn_reg_point(2), result=>Yn_mul_reg_point(2) ); Umult4:mult0--乘法器 port map( dataa=>a4, datab=>Yn_reg_point(3), result=>Yn_mul_reg_point(3) ); Umult5:mult0--乘法器 port map( dataa=>a5, datab=>Yn_reg_point(4), result=>Yn_mul_reg_point(4) ); Umult6:mult0--乘法器 port map( dataa=>a6, datab=>Yn_reg_point(5), result=>Yn_mul_reg_point(5) ); Umult7:mult0--乘法器 port map( dataa=>a7, datab=>Yn_reg_point(6), result=>Yn_mul_reg_point(6) ); --乘系数后累加 Yn_out<=(Yn_mul_reg_point(0)(31)&Yn_mul_reg_point(0)(31)&Yn_mul_reg_point(0)(31)&Yn_mul_reg_point(0))+ (Yn_mul_reg_point(1)(31)&Yn_mul_reg_point(1)(31)&Yn_mul_reg_point(1)(31)&Yn_mul_reg_point(1))+ (Yn_mul_reg_point(2)(31)&Yn_mul_reg_point(2)(31)&Yn_mul_reg_point(2)(31)&Yn_mul_reg_point(2))+ (Yn_mul_reg_point(3)(31)&Yn_mul_reg_point(3)(31)&Yn_mul_reg_point(3)(31)&Yn_mul_reg_point(3))+ (Yn_mul_reg_point(4)(31)&Yn_mul_reg_point(4)(31)&Yn_mul_reg_point(4)(31)&Yn_mul_reg_point(4))+ (Yn_mul_reg_point(5)(31)&Yn_mul_reg_point(5)(31)&Yn_mul_reg_point(5)(31)&Yn_mul_reg_point(5))+ (Yn_mul_reg_point(6)(31)&Yn_mul_reg_point(6)(31)&Yn_mul_reg_point(6)(31)&Yn_mul_reg_point(6)); end behave; 3,Xn-Yn除常系a0 Library IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_arith.all; USE IEEE.std_logic_signed.all; Entity IIR_Xn_Yn_sub_Div is port (
Xn_in:in std_logic_vector(30 downto 0);--信号输入 Yn_in:in std_logic_vector(34 downto 0);--信号输入 Xn_Yn_div:out std_logic_vector(34 downto 0)--信号输出
); end IIR_Xn_Yn_sub_Div; architecture behave of IIR_Xn_Yn_sub_Div is signal Xn_Yn_sub:std_logic_vector(34 downto 0); begin
--test_Xn_Yn_sub<=Xn_Yn_sub; Xn_Yn_sub<=Xn_in(30)&Xn_in(30)&Xn_in(30)&Xn_in(30)&Xn_in-Yn_in;--Xn-Yn Xn_Yn_div<=to_stdlogicvector(to_bitvector(Xn_Yn_sub) sra 11);--除2048 end behave; 4,top层 --直接I型,低通 --N=7;%滤波器阶数 --rs=60;%衰减dB --Wp=0.3;归一化通道 --IIR切比雪夫II,7阶 --分母系数2048 -8444 15752 -16938 11259 -4602 1067 -108 --分母系数补码0800 DF04 3D88 BDD6 2BFB EE06 042B FF94 --系数bit位数=16bit --分子系数7 -5 12 2 2 12 -5 7 --分子系数补码 0007 FFFB 000C 0002 0002 000C FFFB 0007 --传递函数2048*y(n)-8444*y(n-1)+15725*y(n-2)-16938*y(n-3)+11259*y(n-4)-4602*y(n-5)+1067*y(n-6)-108*y(n-7) -- =7*x(n)+x(n-7))-5*(x(n-1)+x(n-6))+12*(x(n-2)+x(n-5))+2*(x(n-3)+x(n-4));
Library IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_arith.all; USE IEEE.std_logic_signed.all; Entity IIR_comp_top is port ( Rst:in std_logic;--复位 Clk:in std_logic;--时钟 sig_in:in std_logic_vector(11 downto 0);--信号输入 sig_out:out std_logic_vector(15 downto 0)--滤波后信号输出 ); end IIR_comp_top; architecture behave of IIR_comp_top is
----------------------------------- --component声明
----------------------------------- component IIR_Xn--例化 IIR_Xn port ( Rst:in std_logic;--复位 Clk:in std_logic;--时钟 Xn_in:in std_logic_vector(11 downto 0);--信号输入 Xn_out:out std_logic_vector(30 downto 0)--滤波后信号输出 ); end component;
component IIR_Yn--例化 IIR_Yn port ( Rst:in std_logic;--复位 Clk:in std_logic;--时钟 Yn_in:in std_logic_vector(15 downto 0);--信号输入 Yn_out:out std_logic_vector(34 downto 0)--滤波后信号输出 ); end component;
component IIR_Xn_Yn_sub_Div----例化Xn-Yn除2048 port (
Xn_in:in std_logic_vector(30 downto 0);--信号输入 Yn_in:in std_logic_vector(34 downto 0);--信号输入 Xn_Yn_div:out std_logic_vector(34 downto 0)--信号输入
); end component;
----------------------------------- --signal声明
signal Xn_out:std_LOGIC_VECTOR(30 downto 0); signal Yn_out:std_LOGIC_VECTOR(34 downto 0); signal Xn_Yn_div:std_LOGIC_VECTOR(34 downto 0);
begin sig_out<=Xn_Yn_div(15 downto 0);
Xn_sum:IIR_Xn--Xn端口映射 port map( Rst=>Rst,--复位 Clk=>Clk,--时钟 Xn_in=>sig_in,--信号输入 Xn_out=>Xn_out--滤波后信号输出 );
Yn_sum:IIR_Yn--Yn端口映射 port map( Rst=>Rst,--复位 Clk=>Clk,--时钟 Yn_in=>Xn_Yn_div(15 downto 0),--信号输入 Yn_out=>Yn_out--滤波后信号输出 );
Xn_Yn_sub:IIR_Xn_Yn_sub_Div--IIR_Xn_Yn_sub_Div端口映射
port map( Xn_in=>Xn_out,--信号输入 Yn_in=>Yn_out,--信号输入 Xn_Yn_div=>Xn_Yn_div--信号输出 ); top层原理图 输出结果见上一篇《数字滤波器(三)》 参考:杜勇老师《数字滤波器的matlab与FPGA实现》
|