FIR及IIR滤波器的FPGA设计实现方案

iir滤波器设计
(一)冲激响应不变法
这种方法是通过将模拟滤波器频率特性h(s)反拉氏变换为h(t),再将h(t)等间隔抽样成h(n)后,对h(n)取z变换求得h(z),即得到了数字滤波器的系统函数。
对比(1)式和(4)式可以发现s域中的极点s映射到z域,则位于z=e^(st)处。
由映射关系可知z平面与s平面呈多值映射的关系。
s平面的虚轴对应的σ=0,则上式中第一项e^(σt)=1,第二项表示旋转的角度,角度以2π/t为周期,所以s平面的虚轴每段2π/t都对应z平面上的单位圆。
s左平面对应σ1,所以s域的右半平面对应z平面上的单位圆外。
在第二步中,我们对h(t)进行了抽样,对应到s域则会产生频谱沿虚轴以2π/t为周期的搬移。
所以实际上我们得到的是h(t)抽样后的s平面与z平面的映射,当ω以2π/t整数倍改变时,会映射到z平面上同一点。下图所示为s平面虚轴映射到z平面的单位圆。可以看出产生了频谱混叠现象。
综上,冲激响应不变法可以将模拟滤波器转换成数字滤波器,但由于混叠现象使得高频部分严重失真,因而只适用于低通滤波器或限带(0<ω<π)的高通或带通场合。
(二)双线性变换法
上面的冲激响应不变法的缺点就是会产生频谱混叠,究其原因是由于对信号进行了抽样,实际得到的是周期延拓后的s平面与z平面的映射,所以产生了多值映射。
在双线性变换法中,我们首先将s平面通过反正切函数压缩到s1平面的(-π/t,π/t)横带内,再使用上面冲激响应不变法中使用的平面映射关系z=e^(s1t),将s1平面映射到z平面。这样一来s平面与z平面就构成了单值映射的关系。
第二步由s1平面映射至z平面时,使用了z=e^(s1t),和冲激响应不变法中s到z平面使用的映射一样,应该相当于用了冲激响应不变法,进行了一次频谱延拓再映射到z平面吧。延拓后s1平面到z平面是多值映射,但s平面到z平面是单值映射。s平面整个虚轴对应于z平面的单位圆一周。
综上,双线性变换法克服了多值映射关系,可以消除频率的混叠。但是由于ω与w成非线性关系,频率有畸变。
fir滤波器设计
fir滤波器的设计比较简单,就是要设计一个数字滤波器去逼近一个理想的低通滤波器。通常这个理想的低通滤波器在频域上是一个矩形窗。
但是在时域上它是一个sa函数。但是这个采样序列是无限的,计算机是无法对它进行计算。
故我们需要对此采样函数进行截断处理。也就是把这个时域采样序列去乘一个窗函数,也就是加一个窗函数。
就把这个无限的时域采样序列截成了有限个序列值。
但是加窗后对此采样序列的频域也产生了影响:此时的频域便不在是一个理想的矩形窗,而是成了一个有过渡带,阻带有波动的低通滤波器。
通常根据所加的窗函数的不同,在频域所得的低通滤波器的阻带衰减也不同。常用的窗函数有矩形窗、三角窗、汉宁窗(升余弦窗)、blackman窗(二阶升余弦窗)等。
所以窗函数法设计fir滤波器的步骤如下:
fir滤波器的fpga实现
由于在quartus中提供了fir滤波器的ip核,所以只需要利用matlab根据要求计算出滤波器的系数,再将系数导入ip核就可以实现fir滤波器。
要求:滤波器采样频率8mhz,过渡带[1mhz,2mhz],通带衰减小于1db,阻带衰减大于40db,滤波器系数量化位数为12比特。
1.利用matlab设计出满足要求的fir滤波器
这里需要用到kaiserord函数得到满足要求的最小阶数,及firpm函数设计最优滤波器。下面的代码参考自《数字调制解调技术的matlab与fpga实现》杜勇。
matlab代码(可以滑动哟)
%e4_5_lpfdesign.m
%设计一个低通滤波器。采样频率fs=8mhz,过渡带fc=[1mhz 2mhz];
%绘出滤波器第数量化前后的幅频响应图;将量化后的滤波器系数写入指定的txt文本文件中
function h_pm=e4_5_lpfdesign;
fs=8*10^6; %采样频率
qm=12; %滤波器系数量化位数
fc=[110^6 210^6]; %过渡带
mag=[1 0]; %窗函数的理想滤波器幅度
%设置通带容限a1及阻带容限a2
%通带衰减ap=-20*log10(1-a1)=0.915db,阻带衰减为as=-20*log10(a2)=40db
a1=0.1;a2=0.01;
dev=[a1 a2];
%采用凯塞窗函数获取满足要求的最小滤波器阶数
[n,wn,beta,ftype]=kaiserord(fc,mag,dev,fs)
%采用firpm函数设计最优滤波器
fpm=[0 fc(1)*2/fs fc(2)*2/fs 1]; %firpm函数的频段向量
magpm=[1 1 0 0]; %firpm函数的幅值向量
h_pm=firpm(n,fpm,magpm); %设计最优滤波器
%量化滤波系数
q_pm=round(h_pm/max(abs(h_pm))*(2^(qm-1)-1));
%将生成的滤波器系数数据写入fpga所需的txt文件中
fid=fopen('e:fpga docfpga数字信号处理数字调制解调技术的matlab与fpga实现——alteraverilog版chapter_4e4_5_firipcoree4_5_lpf.txt','w');
fprintf(fid,'%12.12f
',h_pm);
fclose(fid);
2.调用fir滤波器ip核
设置fir参数时,设置滤波器系数位宽为12比特;流水线级数为1;实现结构设置为multi-cycle(多时钟周期结构),fpga系统时钟频率为32mhz,而数据速率为8mhz,所以每4个时钟周期处理一个数据即可,因此设置“clock to compute”的值为4。在设置滤波器系数的时候,将设计好的txt文件装载进去,生成完ip核后将其例化。
顶层模块
module firipcore (
reset_n,clk,xin,yout);input reset_n; //复位信号,低电平有效
input clk; //fpga系统时钟/数据速率:32mhz
input signed [11:0] xin; //数据输入频率为8mhz
output signed [24:0] yout; //滤波后的输出数据
wire sink_valid,ast_source_ready,ast_source_valid,ast_sink_ready;
wire [1:0] ast_source_error;
wire [1:0] ast_sink_error;
assign ast_source_ready=1'b1;
assign ast_sink_error=2'd0;
//由于系统时钟为数据速率的4倍,因此需要每4个时钟周期设置一次ast_sink_valid有效信号
reg [1:0] count;
reg ast_sink_valid;
always @(posedge clk or negedge reset_n)
if (!reset_n) begin
count <= 2'd0;ast_sink_valid <= 1'b0;endelse begin
count <= count + 2'd1;if (count==0) ast_sink_valid <= 1'b1;else ast_sink_valid <= 1'b0;endassign sink_valid = ast_sink_valid;
//实例化fir滤波器核
fir u0(
.clk(clk),.reset_n(reset_n),.ast_sink_data(xin),.ast_sink_valid(sink_valid),.ast_source_ready(ast_source_ready),.ast_sink_error(ast_sink_error),.ast_source_data(yout),.ast_sink_ready(ast_sink_ready),.ast_source_valid(ast_source_valid),.ast_source_error(ast_source_error));endmodule
3.matlab产生仿真测试数据
由于设计的时截止频率为2mhz的低通滤波器,我们可以产生频率为1mhz和2mhz的合成信号。
产生测试数据
%e4_6_testdata.m
f1=1*10^6; %信号1频率为1mhz
f2=2.1*10^6; %信号2频率为2.1mhz
fs=8*10^6; %采样频率为8mhz
n=12; %量化位数为12比特
len=2000; %数据长度为2000
%%产生两个单载波合成后的信号
t=0:1/fs:(len-1)/fs;
c1=2pif1*t;
c2=2pif2*t;
s1=sin(c1);%产生正弦波
s2=sin(c2);%产生正弦波
s=s1+s2; %对两个单载波信号进行合成
%调用e4_6_lpfdesign函数设计的滤波器对信号进行滤波
hn=e4_5_lpfdesign;
filter_s=filter(hn,1,s);
%求信号的幅频响应
m_s=20*log(abs(fft(s,1024)))/log(10); m_s=m_s-max(m_s);
%滤波后的幅频响应
fm_s=20*log(abs(fft(filter_s,1024)))/log(10); fm_s=fm_s-max(fm_s);
%滤波器本身的幅频响应
m_hn=20*log(abs(fft(hn,1024)))/log(10); m_hn=m_hn-max(m_hn);
%设置幅频响应的横坐标单位为hz
x_f=[0:(fs/length(m_s)):fs/2];
%只显示正频率部分的幅频响应
mf_s=m_s(1:length(x_f));
fmf_s=fm_s(1:length(x_f));
fm_hn=m_hn(1:length(x_f));
%绘制幅频响应曲线
subplot(211)
plot(x_f,mf_s,'-.',x_f,fmf_s,'-',x_f,fm_hn,'--');
xlabel('频率(hz)');ylabel('幅度(db)');title('matlab仿真合成单频信号滤波前后的频谱');
legend('输入信号频谱','输出信号频谱','滤波器响应');
grid;
%绘制滤波前后的时域波形
subplot(212)
%绘制时域波形
%设置显示数据范围,设置横坐标单位ms
t=0:1/fs:80/fs;t=t*10^6;
t_s=s(1:length(t));
t_filter_s=filter_s(1:length(t));
plot(t,t_s,'--',t,t_filter_s,'-');
xlabel('时间(ms)');ylabel('幅度');title('fpga仿真合成单频信号滤波前后的时域波形');
legend('输入信号波形','输出信号波形');
grid;
%对仿真产生的合成单频信号进行量化处理
s=s/max(abs(s)); %归一化处理
q_s=round(s*(2^(n-1)-1));%12比特量化
%将生成的数据以二进制数据格式写入txt文件中
fid=fopen('e:fpga docfpga数字信号处理数字调制解调技术的matlab与fpga实现——alteraverilog版chapter_4e4_5_firipcoree4_5_testdata.txt','w');
for i=1:length(q_s)
b_noise=dec2bin(q_s(i)+(q_s(i)< 0)*2^n,n);for j=1:n if b_noise(j)=='1' tb=1; else tb=0; end fprintf(fid,'%d',tb); endfprintf(fid,'');end
fprintf(fid,';');
fclose(fid);
4.编写测试激励文件
测试激励文件
`timescale 1 ns/ 1 ns
module firipcore_vlg_tst();
reg [11:0] xin;
reg clk,clk_data;
reg reset_n;
wire [24:0] yout;
firipcore i1 (
.xin(xin),.yout(yout),.clk(clk),.reset_n(reset_n));
parameter clk_period=20; //设置时钟信号周期(频率):50mhz
parameter data_clk_period=clk_period*4; //设置数据时钟周期
parameter clk_half_period=clk_period/2;
parameter data_half_period=data_clk_period/2;
parameter data_num=2000; //仿真数据长度
parameter time_sim=data_num*data_clk_period; //仿真时间
initial
begin
//设置输入信号初值xin=12'd10;//设置时钟信号初值clk=1;clk_data=1;//设置复位信号reset_n=0;#110 reset_n=1;//设置仿真时间#time_sim $finish;end
//产生时钟信号
always
#clk_half_period clk=~clk;
always
#data_half_period clk_data=~clk_data;
//从外部tx文件(e4_5_testdata.txt)读入数据作为测试激励
integer pattern;
reg [11:0] stimulus[1:data_num];
initial
begin
//文件必须放置在工程目录simulationmodelsim路径下
$readmemb(e4_5_testdata.txt,stimulus);
pattern=0;
repeat(data_num)
begin pattern=pattern+1; xin=stimulus[pattern]; #data_clk_period;endend
//将仿真数据yout写入外部txt文件中(e4_5_fpgadata.txt)
integer file_out;
initial
begin
//文件放置在工程目录simulationmodelsim路径下
file_out = $fopen(e4_5_fpgadata.txt);
if(!file_out)
begin $display(could not open file!); $finish;endend
wire rst_write;
wire signed [24:0] dout_s;
assign dout_s = yout; //将yout转换成有符号数据
assign rst_write = clk_data & (reset_n); //产生写入时钟信号,复位状态时不写入数据
always @(posedge rst_write )
$fdisplay(file_out,%d,dout_s);
endmodule
仿真结果
iir滤波器的fpga实现
iir滤波器结构包括直接ⅰ型、直接ⅱ型、级联型和并联型。其中级联型结构便于准确实现数字滤波器零极点,且受参数量化影响小,因此使用广泛。
它实际上相当于将级数较多的滤波器分解成多个级数小于等于3的iir滤波器,前一级的输出作为后一级的输入,其中每个滤波器均可看成独立的结构。
同样滤波器的参数需要使用matlab计算出,还需要将计算出的滤波器参数转换成级联的形式。
由于没有现成的iir滤波器ip核,所以需要用verilog来实现,结构如下。可以看出用fpga实现并不复杂,只是移位乘上系数相加的过程。
部分代码如下
iir第一级
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
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; endelse 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
仿真结果

数字触发器原理与亚稳态特性
鸿蒙不是安卓的拷贝,也不是IOS的拷贝
你是否还在怀念火星车的样子呢?
江苏移动开通了全球首个4G O-RAN基站
WiFi 4、WiFi 5和WiFi 6的区别及优势
FIR及IIR滤波器的FPGA设计实现方案
5G应用于轨道交通领域目前最主要问题在于功耗
博通并购高通,高通苹果的官司有望提前解决
Q-FOG循环腐蚀盐雾箱需要满足哪些测试要求
Intel量产32nm工艺技术的回顾
2018全球最强物联网公司榜单,这些公司你都听过吗
深入解析安防行业的未来发展趋势
床头灯定时器电路原理图
配网行波故障预警与定位装置对多分支线的监测
立足优势 持续领先:KIOXIA铠侠新一代UFS嵌入式闪存器件已批量交货
禾多科技为中国消费者创造更加优秀的自动驾驶体验
检测电容好坏的8种方法(操作步骤+案例示范)
诠鼎集团力推CitrusCom, KSI产品应用于智能手机方案
超声波雾化器的原理简介
基于嵌入式arm核心板设计无线地磁车辆检测网关-飞凌嵌入式