我们上一篇博客对CIC滤波器的理论与实现进行了详细的介绍,相信同学们从前一篇博客可以进行相应的学习。但是CIC滤波器本质上就是 低通滤波器。为什么如此常用,只是因为CIC滤波器构成简单不需要乘法器,运行速度快,在通信中的上下变频中非常常用。当然CIC滤波器可是使用低通滤波器来实现,但是资源利用率不高。 本次项目我们将使用多级CIC滤波器进行抽取与插值操作,这样做的目的主要是为了提高阻带衰减,是有用信号的占比更大。但是提高阻带衰减的同时会降低通带衰减,这些特点也就决定了CIC滤波器在数字上下变频中的应用,因为该应用中信号的抽样频率远大于有用信号的频率。学习这一篇博客的时候一定要先学习上一篇博客,否则会导致概念不明白。 根据上一篇文章我们关于CIC滤波器严格的计算,可以发现单级CIC滤波器的第一旁瓣电平衰减固定为 13.46dB,且与滤波器的阶数无关。然而,这个 阻带衰减通常不满足实际中的要求,所以会把多个简单的CIC滤波器进行级联,所以称为 多级CIC滤波器。 其实,CIC滤波器大多应用于 抗混叠抽取/内插滤波器,也是因为上述的原因。因为在抗混叠应用中,有效信号频带往往远小于采样率,因此总可以设计出同时满足通带和阻带要求的CIC滤波器。 常见信号的抽取操作如下图: 理论上多级CIC滤波器可以直接由多个单级CIC滤波器级联得到,但根据 Noble恒等式(“先进行抽取或者插值,再进行线性滤波”与“先进行线性滤波,再进行抽取或者插值”这两者是可以等价的) 。这个公式特别重要也是CIC滤波器在抗混叠滤波器应用如此广泛的另一个原因。所以根据这个原理,当抽取时,我们把抽取操作放到CIC滤波器积分与梳状之间。假设抽取个数与CIC滤波器的阶数相同,那么级联的梳状滤波器正好变成一阶,如下图: 上面我们我们已经介绍了CIC滤波器在抽取中的优点以及特殊结构。接下来我们将介绍CIC滤波器在内插中的优点及特殊结构。 同样,利用 Noble恒等式,我们可以将内插操作放到梳状滤波器与积分滤波器的中间。假设内插的个数与梳状滤波器的阶数相同,那么将内插操作插入到梳状滤波器之后,便可以将梳状滤波器化简为1阶滤波器。从而减少硬件资源量,变化之后的图形如下图: 我们实现的功能是,采样率1MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍抽取。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作。最后对比两个结果。我们严格按照变形之后的图形,即经过Noble恒等式变形之后的图形进行编写MATLAB代码: 相信大家经过MATLAB代码与博客理论之间的学习,可以很容易学会CIC滤波器在信号抽取上面的实现。 我们将上面的MATLAB文件进行运行,结果如下: 我们实现的功能是,采样率0.25MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍内插。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作。我们的内插操作也是按照前面Noble恒等式变形之后的图形进行的程序**。这里需要注意一下,上一篇博客关于单级CIC滤波器的内插操作,我们没有按照变形之后的图像操作,只是把CIC当成了一个简单的低通滤波器来进行信号处理。但是抽取部分吗是严格按照变形之后的图形进行的。**,代码如下: 同样从上面的MATLAB代码,相信大家可以很容易的学会基于CIC滤波器的内插操作。 由于积分运算会导致数据位宽扩展,首先需要确定积分器的输出数据位宽。可以借助如下公式,当输入信号为Bin位时,积分器最大可能输出位数为: 我们实现的功能是,采样率1MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍抽取。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作 cic模块: tb模块: 上面我们为了方便起见使用了DDS IP来产生正弦波信号,详细的IP定制步骤可以查看我们前面的DDS的文章。 进行运行结果如下: 同样这里梳状滤波器、积分滤波器的输入输出位宽满足多级CIC滤波器的抽取时候的条件。本次实验选取的位宽依旧有很大剩余,这是为了计算的简洁性,但是做学术的时候绝对不可以出现这样的情况。** 我们实现的功能是:采样率0.25MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍内插。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作。 这里废话不多说,直接给出相应的代码供大家学习,这里需要注意我们使用的结构是经过Noble恒等式优化之后的结构,整个过程与MATLAB仿真完全一摸一样。 仔细读一下代码再结合前面的理论相信大家可以学会CIC滤波器在内插时候的操作。 tb模块: 正弦波的产生我们同样使用了DDS IP核。 CIC滤波器内插结果如下: [1]、FPGADesigner——ImapBox博主 [2]、长弓的坚持——ImapBox博主 [3]、行州人——ImapBox博主 [4]、FPGA开源工作室——ImapBox博主 在查找一些资料的时候,发现一些博主只给出部分代码,其实这样别人根本看不懂,只有给出整个工程代码才易于知识的传播。创作不易,认为文章有帮助的同学们可以关注、、转发支持。为行业贡献及其微小的一部分。或者对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:多级CIC滤波器理论与设计
项目简述
多级CIC滤波器
不过增加CIC滤波器的级数也有不利的影响:通带衰减也随着增加。换句话说,对于给定的通带衰减要求,多 级CIC滤波器的通带范围会随着级数的增加而不断变窄,通带衰减也会随之增加。滤波器的设计不仅要考虑阻带误差容限,还要考虑通带误差容限,设计多级CIC滤波器时要注意考虑这个问题。这里再次强调CIC滤波器就是低通滤波器,至于为什么不使用其他的低通滤波器,而使用CIC滤波器,主要是因为结构简单。多级CIC滤波器的抽取操作
从上面我们可以看出一般先进行抗混叠滤波再进行抽取。这事抗混叠滤波就可以使用如下CIC多级滤波器进行级联。
上面的图是一级CIC,如果感觉阻带衰减不满足要求,那么可以进行多级CIC滤波器的级联。
在这里插入图片描述
多级CIC抽取的整个级联图倍简化成上面图形,所以CIC滤波器在抽取中才会那么常用。多级CIC滤波器的内插操作
常见的内插操作如下:
从上面我们可以看出一般先进行内插再进行抗混叠滤波。这时抗混叠滤波就可以使用如下CIC多级滤波器进行级联。
上面的图是一级CIC,如果感觉阻带衰减不满足要求,那么可以进行多级CIC滤波器的级联。
多级CIC滤波器的抽取的MATLAB实现
close all clear all clc %set system parameter fs = 2500; %The frequency of the local oscillator signal Fs = 1000000; %sampling frequency N = 24; %Quantitative bits L = 50000000; %Generating an input signal t =0:1/Fs:(1/Fs)*(L-1); %Generating the time series of sampling frequencies sc =sin(2*pi*fs*t); %a sinusoidal input signal that produces a random starting phase b =[1,-1];%integerator a =[1,-1];%comb %comb c1=filter(1,b,sc); c2=filter(1,b,c1); c3=filter(1,b,c2); y = downsample(c3,4); %integerater i1 =filter(a,1,y); i2 =filter(a,1,i1); i3 =filter(a,1,i2); sf = i3; figure(1), subplot(211),stem(t(1:1600),sc(1:1600)); xlabel('时间(t)','fontsize',8); ylabel('幅度(dB)','fontsize',8); title('sc','fontsize',8); subplot(212),stem(t(1:400),sf(1:400)); xlabel('时间/4(t)','fontsize',8); ylabel('幅度(dB)','fontsize',8); title('sf','fontsize',8);
多级CIC滤波器的抽取的MATLAB结果
在这里插入图片描述
从上面的结果可以看出我们成功实现了CIC抽取操作。
多级CIC滤波器的内插的MATLAB实现
close all clear all clc %set system parameter fs = 2500; %The frequency of the local oscillator signal Fs = 250000; %sampling frequency L = 81920; %Generating an input signal t =0:1/Fs:(1/Fs)*(L-1); %Generating the time series of sampling frequencies sc =sin(2*pi*fs*t); %a sinusoidal input signal that produces a random starting phase b =[1,-1];%comb a =[1,-1];%integerator %comb c1=filter(b,1,sc); c2=filter(b,1,c1); c3=filter(b,1,c2); y = upsample(c3,4); %integerater i1 =filter(1,a,y); i2 =filter(1,a,i1); i3 =filter(1,a,i2); sf = i3; figure(1), subplot(211),stem(t(1:320),sc(1:320)); xlabel('时间(t)','fontsize',8); ylabel('幅度(dB)','fontsize',8); title('sc','fontsize',8); subplot(212),stem(t(1:1280),sf(1:1280)); xlabel('时间*4(t)','fontsize',8); ylabel('幅度(dB)','fontsize',8); title('sf','fontsize',8);
多级CIC滤波器的内插的MATLAB结果
从上面的结果可以看出,我们实现的基于CIC滤波器的内插操作成功实现。多级CIC滤波器的抽取的FPGA实现
R为抽取/插值倍数,D为滤波器级数,N为滤波器阶数。
梳状滤波器模块设计与积分模块很相似,只不过是由寄存器和减法器组成的。该模块的输出即为整个CIC抽取滤波器的输出数据,位宽可由如下公式确定:
当然我们程序中使用的位宽稍大。
我们此代码得书写严格按照我们博客上面给得结构,也与MATLAB的流程一摸一样,但是输出可以极大的缩小位宽,为了方便原因,我们不再调整。多级CIC滤波器的抽取的FPGA代码
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : cic.v // Create Time : 2020-04-24 15:08:16 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module cic( //System Interfaces input sclk , input rst_n , //Communication Interfaces input rvalid , input signed [ 9:0] din , output reg tvalid , output reg signed [33:0] dout ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ wire signed [33:0] din_x ; //积分器 wire signed [33:0] int_in1 ; wire signed [33:0] int_in2 ; wire signed [33:0] int_in3 ; reg signed [33:0] int_r1 ; reg signed [33:0] int_r2 ; reg signed [33:0] int_r3 ; wire signed [33:0] int_data ; //抽取 reg [ 2:0] cnt ; reg ext_valid ; //梳状滤波器 wire signed [33:0] comb_din ; reg signed [33:0] comb_r1 ; reg signed [33:0] comb_r2 ; reg signed [33:0] comb_r3 ; wire signed [33:0] comb_in1 ; wire signed [33:0] comb_in2 ; wire signed [33:0] comb_in3 ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign din_x = rvalid == 1'b1 ? {{24{din[9]}},din}: din_x; assign int_in1 = int_r1 + din_x; assign int_in2 = int_r2 + int_in1; assign int_in3 = int_r3 + int_in2; assign comb_din = ext_valid == 1'b1 ? int_in3 : comb_din; assign comb_in1 = comb_din - comb_r1; assign comb_in2 = comb_in1 - comb_r2; assign comb_in3 = comb_in2 - comb_r3; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) int_r1 <= 34'd0; else if(rvalid == 1'b1) int_r1 <= int_in1; else int_r1 <= int_r1; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) int_r2 <= 34'd0; else if(rvalid == 1'b1) int_r2 <= int_in2; else int_r2 <= int_r2; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) int_r3 <= 34'd0; else if(rvalid == 1'b1) int_r3 <= int_in3; else int_r3 <= int_r3; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt <= 3'd0; else if(rvalid == 1'b1 && cnt == 'd3) cnt <= 3'd0; else if(rvalid == 1'b1) cnt <= cnt + 1'b1; else cnt <= cnt; always @(*) if(rvalid == 1'b1 && cnt == 'd3) ext_valid <= 1'b1; else ext_valid <= 1'b0; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) comb_r1 <= 34'd0; else if(ext_valid == 1'b1) comb_r1 <= int_in3; else comb_r1 <= comb_r1; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) comb_r2 <= 34'd0; else if(ext_valid == 1'b1) comb_r2 <= comb_in1; else comb_r2 <= comb_r2; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) comb_r3 <= 34'd0; else if(ext_valid == 1'b1) comb_r3 <= comb_in2; else comb_r3 <= comb_r3; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) dout <= 'd0; else if(ext_valid == 1'b1) dout <= comb_in3; else dout <= dout; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) tvalid <= 1'b0; else tvalid <= ext_valid; endmodule
多级CIC滤波器的抽取的FPGA测试代码
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : tb.v // Create Time : 2020-04-24 16:00:12 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module tb(); reg sclk ; reg rst_n ; wire rvalid ; wire [ 7:0] din ; wire tvalid ; wire [12:0] dout ; initial begin sclk = 1'b0; rst_n <= 1'b0; #(1000); rst_n <= 1'b1; end always #(500) sclk = ~sclk; dds_compiler_0 dds_compiler_0_inst ( .aclk (sclk ), // input wire aclk .m_axis_data_tvalid (rvalid ), // output wire m_axis_data_tvalid .m_axis_data_tdata (din ) // output wire [7 : 0] m_axis_data_tdata ); cic cic_inst( //System Interfaces .sclk (sclk ), .rst_n (rst_n ), //Communication Interfaces .rvalid (rvalid ), .din ({{2{din[7]}},din} ), .tvalid (tvalid ), .dout (dout ) ); endmodule
多级CIC滤波器的抽取的FPGA仿真结果
放大的局部信息:
从上面的运行结果中可以看出,我们成功实现了原始信号的四抽取。如果要实现更高倍数的抽取,只需要对代码中稍作修改即可。多级CIC滤波器的内插的FPGA实现
多级CIC滤波器的内插的FPGA代码
CIC_inter模块:`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : CIC_inter.v // Create Time : 2020-04-24 20:20:56 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module CIC_inter( //System Interfaces input sclk , input rst_n , //Communication Interfaces input rvalid , input [ 9:0] din , output wire tvalid , output wire [33:0] dout ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ wire signed [33:0] din_x ; //积分器 wire signed [33:0] int_in1 ; wire signed [33:0] int_in2 ; wire signed [33:0] int_in3 ; reg signed [33:0] int_r1 ; reg signed [33:0] int_r2 ; reg signed [33:0] int_r3 ; wire signed [33:0] int_data ; wire signed [33:0] int_din ; //抽取 reg [ 2:0] cnt ; reg intr_valid ; //梳状滤波器 reg signed [33:0] comb_r1 ; reg signed [33:0] comb_r2 ; reg signed [33:0] comb_r3 ; wire signed [33:0] comb_in1 ; wire signed [33:0] comb_in2 ; wire signed [33:0] comb_in3 ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign din_x = rvalid == 1'b1 ? {{24{din[9]}},din} : 34'd0; assign int_in1 = int_r1 + int_din; assign int_in2 = int_r2 + int_in1; assign int_in3 = int_r3 + int_in2; assign comb_in1 = din_x - comb_r1; assign comb_in2 = comb_in1 - comb_r2; assign comb_in3 = comb_in2 - comb_r3; assign int_din = rvalid == 1'b1 ? comb_in3 : 34'd0; assign dout = int_in3; assign tvalid = intr_valid; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) comb_r1 <= 34'd0; else if(rvalid == 1'b1) comb_r1 <= din_x; else comb_r1 <= comb_r1; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) comb_r2 <= 34'd0; else if(rvalid == 1'b1) comb_r2 <= comb_in1; else comb_r2 <= comb_r2; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) comb_r3 <= 34'd0; else if(rvalid == 1'b1) comb_r3 <= comb_in2; else comb_r3 <= comb_r3; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt <= 3'd0; else if(cnt == 'd3) cnt <= 3'd0; else if(rvalid == 1'b1) cnt <= 3'd1; else cnt <= cnt + 1'b1; always @(*) if(rvalid == 1'b1) intr_valid <= 1'b1; else if(cnt > 0) intr_valid <= 1'b1; else intr_valid <= 1'b0; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) int_r1 <= 34'd0; else if(intr_valid == 1'b1) int_r1 <= int_in1; else int_r1 <= int_r1; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) int_r2 <= 34'd0; else if(intr_valid == 1'b1) int_r2 <= int_in2; else int_r2 <= int_r2; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) int_r3 <= 34'd0; else if(intr_valid == 1'b1) int_r3 <= int_in3; else int_r3 <= int_r3; endmodule
多级CIC滤波器的内插的FPGA测试代码
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : tb.v // Create Time : 2020-04-24 16:00:12 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module tb(); reg sclk ; reg rst_n ; wire rvalid ; wire [ 7:0] din ; reg clk_250k ; reg clk_1m ; reg [ 8:0] cnt_250k ; reg [ 8:0] cnt_1m ; wire tvalid ; wire [33:0] dout ; reg CIC_inter_valid ; reg [ 2:0] cnt ; initial begin sclk = 1'b0; rst_n <= 1'b0; #(1000); rst_n <= 1'b1; end always #(10) sclk = ~sclk; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt_250k <= 9'd0; else if(cnt_250k == 'd99) cnt_250k <= 9'd0; else cnt_250k <= cnt_250k + 1'b1; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) clk_250k <= 1'b0; else if(cnt_250k == 'd99) clk_250k <= ~clk_250k; else clk_250k <= clk_250k; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt_1m <= 9'd0; else if(cnt_1m == 'd24) cnt_1m <= 9'd0; else cnt_1m <= cnt_1m + 1'b1; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) clk_1m <= 1'b0; else if(cnt_1m == 'd24) clk_1m <= ~clk_1m; else clk_1m <= clk_1m; always @(posedge clk_1m or negedge rst_n) if(rst_n == 1'b0) cnt <= 3'd0; else if(cnt == 'd3 && rvalid == 1'b1) cnt <= 3'd0; else if(rvalid == 1'b1) cnt <= cnt + 1'b1; else cnt <= cnt; always @(posedge clk_1m or negedge rst_n) if(rst_n == 1'b0) CIC_inter_valid <= 1'b0; else if(cnt == 'd3 && rvalid == 1'b1) CIC_inter_valid <= 1'b1; else CIC_inter_valid <= 1'b0; dds_compiler_0 dds_compiler_0_inst ( .aclk (clk_250k ), // input wire aclk .m_axis_data_tvalid (rvalid ), // output wire m_axis_data_tvalid .m_axis_data_tdata (din ) // output wire [7 : 0] m_axis_data_tdata ); CIC_inter CIC_inter_inst( //System Interfaces .sclk (clk_1m ), .rst_n (rst_n ), //Communication Interfaces .rvalid (CIC_inter_valid ), .din ({{2{din[7]}},din} ), .tvalid (tvalid ), .dout (dout ) ); endmodule
多级CIC滤波器的内插的FPGA仿真结果
放大后的细节如下:
由上图可知,我们成功实现了基于CIC滤波器的内插操作。参考文献
总结
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算