本帖最后由 cyy13623649348 于 2019-8-25 13:15 编辑
1. FIR滤波器原理 FIR滤波器是线性时不变系统,分析FIR、IIR系统的方法都是以线性时不变系统为基础的。 滤波器的出可以表示为输入序列和单位取样响应的卷积。 系统函数为 FIR滤波器单位取样响应满足对称条件时具有线性相位特性。 FIR滤波器的结构有直接型、级联型、频率取样型和快速卷积型。FPGA实现时最常用的是最简单的直接型结构。FPGA实现直接型结构的FIR滤波器可以采用串行结构、并行结构、分布式结构和IP核等。 FIR滤波器直接型结构 图 1 FIR直接型结构 2.FIR滤波器设计
之前设计了一个数字混频程序,载频为1MHz,信号频率为625kHz。相乘后的信号包含和频1.625MH,差频375kHz两个频率分量。本次设计一个31阶(长度为32)的低通滤波器,截止频率为375KHz,采样频率10M。将混频后的信号通过滤波器,就可以得到375kHz的信号。
数字信号处理学习——混频器
http://www.corecourse.cn/forum.php?mod=viewthread&tid=27994
(出处: 芯路恒电子技术论坛)
(1)通过MATLAB设计出滤波器系数;- N=32; %滤波器长度
- fs=10000000;%采样频率10M
- fc=375000; %低通滤波器的截止频率375kHz
- B=12; %量化位数
- %生成各种窗函数
- % w_rect=rectwin(N)';
- % w_hann=hann(N)';
- % w_hamm=hamming(N)';
- w_kais=blackman(N)';
- % w_kais=kaiser(N,7.856)';
- %采用fir1函数设计FIR滤波器
- % b_rect=fir1(N-1,fc*2/fs,w_rect);
- % b_hann=fir1(N-1,fc*2/fs,w_hann);
- % b_hamm=fir1(N-1,fc*2/fs,w_hamm);
- % b_blac=fir1(N-1,fc*2/fs,w_blac);
- b_kais=fir1(N-1,fc*2/fs,w_kais);
- %量化滤波器系数
- Q1=max(abs(b_kais))
- Q2=b_kais/Q1
- Q3=Q2*(2^(B-1)-1)
- Q_kais=round(b_kais/max(abs(b_kais))*(2^(B-1)-1))
- hn=Q_kais;
- %转化成16进制数补码
- Q_h=dec2hex(Q_kais+2^B*(Q_kais<0))
- %求滤波器的幅频响应
- % m_rect=20*log(abs(fft(b_rect,512)))/log(10);
- % m_hann=20*log(abs(fft(b_hann,512)))/log(10);
- % m_hamm=20*log(abs(fft(b_hamm,512)))/log(10);
- % m_blac=20*log(abs(fft(b_blac,512)))/log(10);
- m_kais=20*log(abs(fft(b_kais,1024)))/log(10); m_kais=m_kais-max(m_kais);
- Q_kais=20*log(abs(fft(Q_kais,1024)))/log(10); Q_kais=Q_kais-max(Q_kais);
- %设置幅频响应的横坐标单位为Hz
- x_f=[0:(fs/length(m_kais)):fs/2];
- %只显示正频率部分的幅频响应
- % m1=m_rect(1:length(x_f));
- % m2=m_hann(1:length(x_f));
- % m3=m_hamm(1:length(x_f));
- % m4=m_blac(1:length(x_f));
- m5=m_kais(1:length(x_f));
- m6=Q_kais(1:length(x_f));
- %绘制幅频响应曲线
- % plot(x_f,m1,'-',x_f,m2,'*',x_f,m3,'+',x_f,m4,'--',x_f,m5,'-.');
- plot(x_f,m5,'-',x_f,m6,'--');
- xlabel('频率(Hz)');ylabel('幅度(dB)');
- legend('未量化','12bit量化');
- grid;</font>
复制代码
(2)使用Varilog设计串行FIR程序;
根据FIR直接型结构,滤波器是一个乘累加运算,乘累加的次数由滤波器的阶数决定,前面提到FIR滤波器具有线性相位特性,其系数具有对称性,因此可以减少运算次数。
图 2 FIR串行结构
由于设定的采样时钟为10MHz,而两次采样间隔内要完成16次加法运算,因此系统时钟必须高于采样时钟16倍以上。这里使用PLL产生一个160M系统时钟。 根据图2,串行结构只需要一个乘法器和一个加法器即可,这里通过IP核来实现 - /*实例化有符号数加法器IP核,对输入数据进行1位符号位扩展,输出结果为13比特数据*/
- reg signed [12:0] add_a;
- reg signed [12:0] add_b;
- wire signed [12:0] add_s; //输入为12比特量化数据,两个对称系数相加需要13比特存储
- adder adder (
- .dataa (add_a),
- .datab (add_b),
- .result(add_s)
- );
-
- /*例化有符号数乘法器*/
- reg signed [11:0]coe; //滤波器12bit量化数据
- wire signed [24:0]Mout;
- mult mult (
- .clock (clk),
- .dataa (coe),
- .datab (add_s),
- .result (Mout)
- );
复制代码 在两次采样间隔中完成16个滤波器系数与数据的乘法运算。一个加法器顺序完成16次加法运算- always@(posedge clk or negedge rst_n)
- if(!rst_n) begin
- add_a <= 13'd0;
- add_b <= 13'd0;
- coe <= 12'd0;
- end
- else begin
- case(simple_cnt)
- 0:begin
- add_a <= {in_reg[0][11],in_reg[0]};
- add_b <= {in_reg[31][11],in_reg[31]};
- coe <= 12'h000;//c0
- end
- 1:begin
- add_a <= {in_reg[1][11],in_reg[1]};
- add_b <= {in_reg[30][11],in_reg[30]};
- coe <= 12'hfff; //c1
- end
- 2:begin
- add_a <= {in_reg[2][11],in_reg[2]};
- add_b <= {in_reg[29][11],in_reg[29]};
- coe <= 12'h000; //c2
- end
- 3:begin
- add_a <= {in_reg[3][11],in_reg[3]};
- add_b <= {in_reg[28][11],in_reg[28]};
- coe <= 12'h005; //c3
- end
- 4:begin
- add_a <= {in_reg[4][11],in_reg[4]};
- add_b <= {in_reg[27][11],in_reg[27]};
- coe <= 12'h017; //c4
- end
- 5:begin
- add_a <= {in_reg[5][11],in_reg[5]};
- add_b <= {in_reg[26][11],in_reg[26]};
- coe <= 12'h03e; //c5
- end
- 6:begin
- add_a <= {in_reg[6][11],in_reg[6]};
- add_b <= {in_reg[25][11],in_reg[25]};
- coe <= 12'h086; //c6
- end
- 7:begin
- add_a <= {in_reg[7][11],in_reg[7]};
- add_b <= {in_reg[24][11],in_reg[24]};
- coe <= 12'h0fa; //c7
- end
- 8:begin
- add_a <= {in_reg[8][11],in_reg[8]};
- add_b <= {in_reg[23][11],in_reg[23]};
- coe <= 12'h1a2; //c8
- end
- 9:begin
- add_a <= {in_reg[9][11],in_reg[9]};
- add_b <= {in_reg[22][11],in_reg[22]};
- coe <= 12'h27f; //c9
- end
- 10:begin
- add_a <= {in_reg[10][11],in_reg[10]};
- add_b <= {in_reg[21][11],in_reg[21]};
- coe <= 12'h389; //c10
- end
- 11:begin
- add_a <= {in_reg[11][11],in_reg[11]};
- add_b <= {in_reg[20][11],in_reg[20]};
- coe <= 12'h4ad; //c11
- end
- 12:begin
- add_a <= {in_reg[12][11],in_reg[12]};
- add_b <= {in_reg[19][11],in_reg[19]};
- coe <= 12'h5d1; //c12
- end
- 13:begin
- add_a <= {in_reg[13][11],in_reg[13]};
- add_b <= {in_reg[18][11],in_reg[18]};
- coe <= 12'h6d4; //c13
- end
- 14:begin
- add_a <= {in_reg[14][11],in_reg[14]};
- add_b <= {in_reg[17][11],in_reg[17]};
- coe <= 12'h797; //c14
- end
- 15:begin
- add_a <= {in_reg[15][11],in_reg[15]};
- add_b <= {in_reg[16][11],in_reg[16]};
- coe <= 12'h7ff; //c15
- end
- endcase
- end
复制代码 最后对滤波器系数与输入数据的乘法结果进行累加,并输出滤波后的数据。考虑到乘法器及累加器的延时,需要计数器为2时对累加器清零,同时输出滤波器结果数据。- reg signed [28:0] sum;
- reg signed [28:0] yout;
- always @(posedge clk or negedge rst_n)
- if(!rst_n) begin
- sum = 29'd0;
- yout <= 29'd0;
- end
- else begin
- if(simple_cnt==2) begin
- yout <= sum;
- sum = 29'd0;
- sum =sum + Mout;
- end
- else
- sum = sum + Mout;
- end
-
- assign Signal_out = yout;
复制代码
(3)仿真验证
将数字混频后的输出接到滤波器的输入
- module Fir_test(
- rst_n,
- clk,
- Signal_out
- );
-
- input rst_n;
- input clk;
- output [28:0]Signal_out;
-
- wire [23:0]Mixer_out;
- wire clk_PLL;
-
- PLL PLL(
- .inclk0(clk),
- .c0(clk_PLL)
- );
- Mixer Mixer(
- .rst_n(rst_n),
- .clk(clk),
- .dout(Mixer_out)
- );
- Fir_filter Fir_filter(
- .rst_n(rst_n),
- .clk(clk_PLL),
- .Signal_in(Mixer_out[23:12]),
- .Signal_out(Signal_out)
- );
-
- endmodule
复制代码 仿真得到下面结果,前三个波形为混频器输入和输出,最后的波形为滤波器输出,可以看到滤波器输出的结果为375KHz。
图 3 FIR测试结果
工程链接:https://pan.baidu.com/s/1i0P6pzjkdHnT71_7zhIYjQ 提取码:8grs
不是很明白的话可以参考杜勇老师《数字滤波器的MATLAB与FPGA实现》。 |