Verilog 级联IIR滤波器设计

IIR滤波器

      • Matlab设计
      • Verilog设计
      • 测试结果
      • 理论原理

Matlab设计

设计一个4阶IIR低通滤波器,采样频率为8MHz,截至频率为2MHz,阻带衰减为40dB,滤波器量化位数12bits。

  • 方法一:采用FilterDesigner进行设计比较方便
    Verilog 级联IIR滤波器设计_第1张图片
    方法二:采用内置函数设计
// An highlighted block
fs = 8*10^6; %采样频率
fd = 2*10^6; %截至频率
Rp = 40; % 阻带衰减
qm = 12 %量化位数
N = 4; %阶数

[b,a] = cheby2(N,Rp,fd*2/fs);
[H,w] = freqz(b,a);

%直接型量化结果对比

QA_dir = zeros(length(b));
QB_dir = zeros(length(b));
for i=1
    [QB_dir,QA_dir]=Qcoe(b,a,qm);
end
[H_Q,w_Q] = freqz(QB_dir,QA_dir);
subplot(211);
plot(w/pi,20*log10(abs(H))/abs(H(1)),'r--',w/pi,20*log10(abs(H_Q))/abs(H_Q(1)),'b-.');
xlabel('Nomalized frequency'); ylabel('Magnitude');
legend('量化前幅频响应','量化后幅频响应')
grid;

%将系数转化为级联型系数
%B每行代表级联的分母,A分子同
[b0,B,A]=E4_6_dir2cas(b,a);

%将滤波器增益b0分配至第一级滤波器
%B(1,:) = B(1,:)*b0;
%获取转换后的滤波器长度
S=size(B);
QB=zeros(S(1),S(2));
QA=QB;

%12bits量化
for i=1:S(1)
    [QB(i,:),QA(i,:)]=Qcoe(B(i,:),A(i,:),qm);
end
QA,QB

%输入波形生成
f1 = 1*10^6;
f2 = 3*10^6;
t = 0:1/fs:120/fs;
s = sin(2*pi*f1*t) + sin(2*pi*f2*t);

s_filter = filter(b,a,s);
s_filter_qm = filter(QB_dir,QA_dir,s);

subplot(212);
plot(t,s,'-',t,s_filter,'g-',t,s_filter_qm,'r--');
xlabel('t'); ylabel('Magnitude');
legend('滤波前','滤波后','量化后滤波')
grid;

%产生仿真所用文件
Q_s = (s/abs(max(s)))*(2^(qm-1) -1 );
fid = fopen('E:\Work\IC\Modem\code\Chapter_4\IIR\test_data.txt','w');
for i=1:length(Q_s)
    B_noise = dec2bin( Q_s(i)  + (Q_s(i) < 0)*2^qm,qm);
    for j=1:qm 
        if B_noise(j) == '1'
            tb = 1;
        else 
            tb = 0;
        end
        fprintf(fid,'%d',tb);
    end
    fprintf(fid,'\r\n');
end
fclose(fid);          

其中两个函数参考杜勇老师的书设计

  • 第一个E4_6_dir2cas作用是将直接型的系数转化为并联型
function [b0,B,A]=E4_6_dir2cas(b,a);
%变直接型IIR滤波器结构为级联形式
%b0=增益系数
%B=包含因子系数bk的K3列矩阵
%A=包含因子系数ak的K3列矩阵
%a=直接型分母多项式系数
%b=直接型分子多项式系数
%计算增益系数
bb=b;aa=a;

b0=b(1);b=b/b0;
a0=a(1);a=a/a0;
b0=b0/a0;
%将分子、分母多项式系数的长度补齐进行计算
M=length(b);N=length(a);
if N>M
    b=[b zeros(1,N-M)];
elseif M>N
    a=[a zeros(1,M-N)]; N=M;
else
    N=M;
end
%级联型系数矩阵初始化
K=floor(N/2);B=zeros(K,3);A=zeros(K,3);
if K*2==N
    b=[b 0];
    a=[a 0];
end
%根据多项式系数利用函数roots求出所有的根
%利用cplxpair进行按实部从小到大的成对排序
broots=cplxpair(roots(b));
aroots=cplxpair(roots(a));
%取出复共轭对的根变换成多项式系数即为所求
for i=1:2:2*K
    Brow=broots(i:1:i+1,:);
    Brow=real(poly(Brow));
    B(fix(i+1)/2,:)=Brow;
    Arow=aroots(i:1:i+1,:);
    Arow=real(poly(Arow));
    A(fix(i+1)/2,:)=Arow;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%滤波器级数为8的时候
%测试转换后前后的滤波器幅频响应
% delta=[1,zeros(1,31)];
% F1=filter(bb,aa,delta);
% figure(1);plot(abs(fft(F1)));
% F21=filter(B(1,:),A(1,:),delta);
% F22=filter(B(2,:),A(2,:),F21);
% F23=filter(B(3,:),A(3,:),F22);
% F2=filter(b0*B(4,:),A(4,:),F23)
%测试量化前后的滤波器幅频响应
% [Qb1,Qa1]=E5_52_Qcoe(B(1,:),A(1,:),12)
% [Qb2,Qa2]=E5_52_Qcoe(B(2,:),A(2,:),12)
% [Qb3,Qa3]=E5_52_Qcoe(B(3,:),A(3,:),12)
% [Qb4,Qa4]=E5_52_Qcoe(b0*B(4,:),A(4,:),12)
% QF21=filter(B(1,:),A(1,:),delta);
% QF22=filter(B(2,:),A(2,:),QF21);
% QF23=filter(B(3,:),A(3,:),QF22);
% QF2=filter(B(4,:),A(4,:),QF23);
% figure(2);plot(abs(fft(QF2)));
%%%%%%%%%%%%%%%%%%%%%%比较F1F2的值即可
  • 第二个函数是量化函数,并保持a(1)系数量化后为2的整数次幂,为了逻辑严谨性和简化,对源代码做了修改。
function [Qb,Qa]  = Qcoe(b,a,qm);

max_data = max(max(a),max(b));
Qm = ceil(log2(max_data/a(1))); %
base = a(1)*2^Qm;
Qb = round(b/base*(2^(qm-1)-1));
Qa = round(a/base*(2^(qm-1)-1));
  • 最后结果
    Verilog 级联IIR滤波器设计_第2张图片
    级联系数为
    Verilog 级联IIR滤波器设计_第3张图片

Verilog设计

  • 参考数字调制解调技术的MATLAB与FPGA实现 Altera Verilog版_杜勇一书
    Verilog 级联IIR滤波器设计_第4张图片
  • 顶层模块,两级级联构成
module IIRCas (
	rst,clk,Xin,
	Yout);
	
	input		rst;   //复位信号,高电平有效
	input		clk;   //FPGA系统时钟,频率为8MHz
	input	 signed [11:0]	Xin;  //数据输入频率为8MHZ
	output signed [11:0]	Yout; //滤波后的输出数据
	
	//实例化第一级滤波器运算模块
	wire signed [11:0] Y1;
	FirstTap U1 (
		.rst (rst),
		.clk (clk),
		.Xin (Xin),
		.Yout (Y1));

	//实例化第二级滤波器运算模块
	SecondTap U2 (
		.rst (rst),
		.clk (clk),
		.Xin (Y1),
		.Yout (Yout));

		
endmodule
  • 第一级滤波器,其中系数乘法用加法代替,有利于减少乘法器资源。
module FirstTap (
	rst,clk,Xin,
	Yout);
	
	input		rst;   //复位信号,高电平有效
	input		clk;   //FPGA系统时钟,频率为2kHz
	input	 signed [11:0]	Xin;  //数据输入频率为2kHZ
	output signed [11:0]	Yout; //滤波后的输出数据
	
	//零点系数的实现代码/
	//将输入数据存入移位寄存器中
	reg signed[11:0] Xin1,Xin2;
	always @(posedge clk or posedge rst)
		if (rst)
			//初始化寄存器值为0
			begin
				Xin1 <= 12'd0;
				Xin2 <= 12'd0;
		   end	
		else
		   begin
				Xin1 <= Xin;
				Xin2 <= Xin1;
			end
			
   //采用移位运算及加法运算实现乘法运算
	wire signed [23:0] XMult0,XMult1,XMult2;
	assign XMult0 = {{6{Xin[11]}},Xin,6'd0}+{{7{Xin[11]}},Xin,5'd0}-{{11{Xin[11]}},Xin,1'd0};        //*94
	assign XMult1 = {{5{Xin1[11]}},Xin1,7'd0}+{{9{Xin1[11]}},Xin1,3'd0}+{{10{Xin1[11]}},Xin1,2'd0};  //*140 (2^7+ 2^3 + 2^2)
	assign XMult2 = {{6{Xin2[11]}},Xin2,6'd0}+{{7{Xin2[11]}},Xin2,5'd0}-{{11{Xin2[11]}},Xin2,1'd0};  //*94
 
	//对滤波器系数与输入数据乘法结果进行累加
	wire signed [23:0] Xout;
	assign Xout = XMult0 + XMult1 + XMult2;
	
	
	//极点系数的实现代码///
	wire signed[11:0] Yin;
	reg signed[11:0] Yin1,Yin2;
	always @(posedge clk or posedge rst)
		if (rst)
			//初始化寄存器值为0
			begin
				Yin1 <= 12'd0;
				Yin2 <= 12'd0;
			end
		else
		   begin
				Yin1 <= Yin;
				Yin2 <= Yin1;
			end
			
	//采用移位运算及加法运算实现乘法运算
	wire signed [23:0] YMult1,YMult2;
	wire signed [23:0] Ysum,Ydiv;
	assign YMult1 = {{2{Yin1[11]}},Yin1,10'd0}+{{5{Yin1[11]}},Yin1,7'd0}+{{6{Yin1[11]}},Yin1,6'd0}-
	                {{11{Yin1[11]}},Yin1,1'd0}-{{12{Yin1[11]}},Yin1};  //*1213=1024+128+64-2-1
	assign YMult2 = {{4{Yin2[11]}},Yin2,8'd0}+{{9{Yin2[11]}},Yin2,3'd0}+{{10{Yin2[11]}},Yin2,2'd0}; //*268=256+8+4
	                

	//第一级IIR滤波器实现代码///
	assign Ysum = Xout+YMult1-YMult2;	
	assign Ydiv = {{11{Ysum[23]}},Ysum[23:11]};//2048
	//根据仿真结果可知,第一级滤波器的输出范围可用9位表示
  assign Yin = (rst ? 12'd0 : Ydiv[11:0]);
	//增加一级寄存器,提高运行速度
	reg signed [11:0] Yout_reg ;
	always @(posedge clk)
		Yout_reg <= Yin;
	assign Yout = Yout_reg;
	
endmodule
  • 第二级滤波器
module SecondTap (
	rst,clk,Xin,
	Yout);
	
	input		rst;   //复位信号,高电平有效
	input		clk;   //FPGA系统时钟,频率为2kHz
	input	 signed [11:0]	Xin;  //数据输入频率为2kHZ
	output signed [11:0]	Yout; //滤波后的输出数据
	
	//零点系数的实现代码/
	//将输入数据存入移位寄存器中
	reg signed[11:0] Xin1,Xin2;
	always @(posedge clk or posedge rst)
		if (rst)
			//初始化寄存器值为0
			begin
				Xin1 <= 12'd0;
				Xin2 <= 12'd0;
		   end	
		else
		   begin
				Xin1 <= Xin;
				Xin2 <= Xin1;
			end
			
   //采用移位运算及加法运算实现乘法运算
	wire signed [23:0] XMult0,XMult1,XMult2;
	assign XMult0 = {{1{Xin[11]}},Xin,11'd0};    //*2048
	assign XMult1 = {{4{Xin1[11]}},Xin1,8'd0}+{{6{Xin1[11]}},Xin1,6'd0}+{{10{Xin1[11]}},Xin1,2'd0};  //*324=256+64+4
	assign XMult2 = {{1{Xin2[11]}},Xin2,11'd0};  //*2048
 
	//对滤波器系数与输入数据乘法结果进行累加
	wire signed [23:0] Xout;
	assign Xout = XMult0 + XMult1 + XMult2;
	
	
	//极点系数的实现代码///
	wire signed[11:0] Yin;
	reg signed[11:0] Yin1,Yin2;
	always @(posedge clk or posedge rst)
		if (rst)
			//初始化寄存器值为0
			begin
				Yin1 <= 12'd0;
				Yin2 <= 12'd0;
			end
		else
		   begin
				Yin1 <= Yin;
				Yin2 <= Yin1;
			end
			
	//采用移位运算及加法运算实现乘法运算
	wire signed [23:0] YMult1,YMult2;
	wire signed [23:0] Ysum,Ydiv;
	assign YMult1 = {{1{Yin1[11]}},Yin1,11'd0}-{{5{Yin1[11]}},Yin1,7'd0}-{{9{Yin1[11]}},Yin1,3'd0}-
	                {{10{Yin1[11]}},Yin1,2'd0}-{{12{Yin1[11]}},Yin1};  //*1907=2048-128-8-4-1
	assign YMult2 = {{2{Yin2[11]}},Yin2,10'd0}+{{5{Yin2[11]}},Yin2,7'd0}+{{8{Yin2[11]}},Yin2,4'd0}+ 
	                {{11{Yin2[11]}},Yin2,1'd0}+{{12{Yin2[11]}},Yin2};  //*1171=1024+128+16+2+1

	//第一级IIR滤波器实现代码///
	assign Ysum = Xout+YMult1-YMult2;	
	assign Ydiv = {{11{Ysum[23]}},Ysum[23:11]};//2048
	//根据仿真结果可知,第一级滤波器的输出范围可用9位表示
   assign Yin = (rst ? 12'd0 : Ydiv[11:0]);
	//增加一级寄存器,提高运行速度
	reg signed [11:0] Yout_reg ;
	always @(posedge clk)
		Yout_reg <= Yin;
	assign Yout = Yout_reg;
	
endmodule

测试结果

  • test.v 读取matlab产生的仿真波形文件
// An highlighted block
module test();
reg clk;
reg rst;
reg [11: 0] Xin;
wire [11:0] Yout;

IIRCas  u1
    ( .clk(clk),
      .rst(rst),
      .Xin(Xin),
      .Yout(Yout)
    );

//rst
initial begin
  rst = 1'
  #10 rst = 1'b1;
  #20 rst = 1'b0;
  #400000 $finish;
end

//clk
initial begin
  clk = 1'b1;
  forever #10 clk = ~clk;
end

reg [11: 0] mem [0:1999];
integer i;

initial begin
  $readmemb("/home/IC/Mylearn/IIR/test_data.txt", mem);
  i = 0;
  repeat(1999) begin
    i = i + 1;
    Xin = mem[i];
    #20;
  end
end

 initial begin
  $fsdbDumpfile("iir.fsdb");
  $fsdbDumpvars;
 end
 endmodule
  • 仿真结果,上面为滤波前,下面为滤波后
    Verilog 级联IIR滤波器设计_第5张图片

理论原理

参考如何快速设计一个IIR滤波器,对模型滤波器到数字滤波器的双线性变换解释比较清楚

  • 系统传递函数
    在这里插入图片描述
  • 系统差分方程
    在这里插入图片描述
  • IIR与FIR优缺点

    Verilog 级联IIR滤波器设计_第6张图片
  • IIR结构: 直接Ⅰ型
    Verilog 级联IIR滤波器设计_第7张图片
  • IIR: 直接Ⅱ型
    Verilog 级联IIR滤波器设计_第8张图片

Verilog 级联IIR滤波器设计_第9张图片

  • 级联结构
    Verilog 级联IIR滤波器设计_第10张图片
    Verilog 级联IIR滤波器设计_第11张图片
  • 并联 Verilog 级联IIR滤波器设计_第12张图片

你可能感兴趣的:(IC,matlab,verilog,数字信号处理)