「学习笔记」带干货的数字滤波器设计(三)
和“无崖子”一起练“内功”
本次介绍基于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实现》