设计一个4阶IIR低通滤波器,采样频率为8MHz,截至频率为2MHz,阻带衰减为40dB,滤波器量化位数12bits。
// 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);
其中两个函数参考杜勇老师的书设计
function [b0,B,A]=E4_6_dir2cas(b,a);
%变直接型IIR滤波器结构为级联形式
%b0=增益系数
%B=包含因子系数bk的K行3列矩阵
%A=包含因子系数ak的K行3列矩阵
%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)));
%%%%%%%%%%%%%%%%%%%%%%比较F1、F2的值即可
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));
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
// 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
参考如何快速设计一个IIR滤波器,对模型滤波器到数字滤波器的双线性变换解释比较清楚