基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解

多级CIC滤波器理论与设计

  • 项目简述
  • 多级CIC滤波器
    • 多级CIC滤波器的抽取操作
    • 多级CIC滤波器的内插操作
  • 多级CIC滤波器的抽取的MATLAB实现
    • 多级CIC滤波器的抽取的MATLAB结果
  • 多级CIC滤波器的内插的MATLAB实现
    • 多级CIC滤波器的内插的MATLAB结果
  • 多级CIC滤波器的抽取的FPGA实现
    • 多级CIC滤波器的抽取的FPGA代码
    • 多级CIC滤波器的抽取的FPGA测试代码
    • 多级CIC滤波器的抽取的FPGA仿真结果
  • 多级CIC滤波器的内插的FPGA实现
    • 多级CIC滤波器的内插的FPGA代码
    • 多级CIC滤波器的内插的FPGA测试代码
    • 多级CIC滤波器的内插的FPGA仿真结果
  • 参考文献
  • 总结

项目简述

我们上一篇博客对CIC滤波器的理论与实现进行了详细的介绍,相信同学们从前一篇博客可以进行相应的学习。但是CIC滤波器本质上就是 低通滤波器。为什么如此常用,只是因为CIC滤波器构成简单不需要乘法器,运行速度快,在通信中的上下变频中非常常用。当然CIC滤波器可是使用低通滤波器来实现,但是资源利用率不高。

本次项目我们将使用多级CIC滤波器进行抽取与插值操作,这样做的目的主要是为了提高阻带衰减,是有用信号的占比更大。但是提高阻带衰减的同时会降低通带衰减,这些特点也就决定了CIC滤波器在数字上下变频中的应用,因为该应用中信号的抽样频率远大于有用信号的频率。学习这一篇博客的时候一定要先学习上一篇博客,否则会导致概念不明白。

多级CIC滤波器

根据上一篇文章我们关于CIC滤波器严格的计算,可以发现单级CIC滤波器的第一旁瓣电平衰减固定为 13.46dB,且与滤波器的阶数无关。然而,这个 阻带衰减通常不满足实际中的要求,所以会把多个简单的CIC滤波器进行级联,所以称为 多级CIC滤波器
不过增加CIC滤波器的级数也有不利的影响:通带衰减也随着增加。换句话说,对于给定的通带衰减要求,多 级CIC滤波器的通带范围会随着级数的增加而不断变窄,通带衰减也会随之增加。滤波器的设计不仅要考虑阻带误差容限,还要考虑通带误差容限,设计多级CIC滤波器时要注意考虑这个问题。这里再次强调CIC滤波器就是低通滤波器,至于为什么不使用其他的低通滤波器,而使用CIC滤波器,主要是因为结构简单。

其实,CIC滤波器大多应用于 抗混叠抽取/内插滤波器,也是因为上述的原因。因为在抗混叠应用中,有效信号频带往往远小于采样率,因此总可以设计出同时满足通带和阻带要求的CIC滤波器。

多级CIC滤波器的抽取操作

常见信号的抽取操作如下图:
在这里插入图片描述
从上面我们可以看出一般先进行抗混叠滤波再进行抽取。这事抗混叠滤波就可以使用如下CIC多级滤波器进行级联。
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第1张图片
上面的图是一级CIC,如果感觉阻带衰减不满足要求,那么可以进行多级CIC滤波器的级联。

理论上多级CIC滤波器可以直接由多个单级CIC滤波器级联得到,但根据 Noble恒等式(“先进行抽取或者插值,再进行线性滤波”与“先进行线性滤波,再进行抽取或者插值”这两者是可以等价的) 。这个公式特别重要也是CIC滤波器在抗混叠滤波器应用如此广泛的另一个原因。所以根据这个原理,当抽取时,我们把抽取操作放到CIC滤波器积分与梳状之间。假设抽取个数与CIC滤波器的阶数相同,那么级联的梳状滤波器正好变成一阶,如下图:
在这里插入图片描述
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第2张图片
多级CIC抽取的整个级联图倍简化成上面图形,所以CIC滤波器在抽取中才会那么常用。

多级CIC滤波器的内插操作

上面我们我们已经介绍了CIC滤波器在抽取中的优点以及特殊结构。接下来我们将介绍CIC滤波器在内插中的优点及特殊结构。
常见的内插操作如下:
在这里插入图片描述
从上面我们可以看出一般先进行内插再进行抗混叠滤波。这时抗混叠滤波就可以使用如下CIC多级滤波器进行级联。
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第3张图片
上面的图是一级CIC,如果感觉阻带衰减不满足要求,那么可以进行多级CIC滤波器的级联。

同样,利用 Noble恒等式,我们可以将内插操作放到梳状滤波器与积分滤波器的中间。假设内插的个数与梳状滤波器的阶数相同,那么将内插操作插入到梳状滤波器之后,便可以将梳状滤波器化简为1阶滤波器。从而减少硬件资源量,变化之后的图形如下图:
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第4张图片

多级CIC滤波器的抽取的MATLAB实现

我们实现的功能是,采样率1MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍抽取。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作。最后对比两个结果。我们严格按照变形之后的图形,即经过Noble恒等式变形之后的图形进行编写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);

相信大家经过MATLAB代码与博客理论之间的学习,可以很容易学会CIC滤波器在信号抽取上面的实现。

多级CIC滤波器的抽取的MATLAB结果

我们将上面的MATLAB文件进行运行,结果如下:
在这里插入图片描述
从上面的结果可以看出我们成功实现了CIC抽取操作。
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第5张图片

多级CIC滤波器的内插的MATLAB实现

我们实现的功能是,采样率0.25MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍内插。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作。我们的内插操作也是按照前面Noble恒等式变形之后的图形进行的程序**。这里需要注意一下,上一篇博客关于单级CIC滤波器的内插操作,我们没有按照变形之后的图像操作,只是把CIC当成了一个简单的低通滤波器来进行信号处理。但是抽取部分吗是严格按照变形之后的图形进行的。**,代码如下:

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);

同样从上面的MATLAB代码,相信大家可以很容易的学会基于CIC滤波器的内插操作。

多级CIC滤波器的内插的MATLAB结果

基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第6张图片
从上面的结果可以看出,我们实现的基于CIC滤波器的内插操作成功实现。

多级CIC滤波器的抽取的FPGA实现

由于积分运算会导致数据位宽扩展,首先需要确定积分器的输出数据位宽。可以借助如下公式,当输入信号为Bin位时,积分器最大可能输出位数为:
在这里插入图片描述
R为抽取/插值倍数,D为滤波器级数,N为滤波器阶数。
梳状滤波器模块设计与积分模块很相似,只不过是由寄存器和减法器组成的。该模块的输出即为整个CIC抽取滤波器的输出数据,位宽可由如下公式确定:
在这里插入图片描述
当然我们程序中使用的位宽稍大。
我们此代码得书写严格按照我们博客上面给得结构,也与MATLAB的流程一摸一样,但是输出可以极大的缩小位宽,为了方便原因,我们不再调整。

我们实现的功能是,采样率1MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍抽取。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作

多级CIC滤波器的抽取的FPGA代码

cic模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// 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测试代码

tb模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// 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

上面我们为了方便起见使用了DDS IP来产生正弦波信号,详细的IP定制步骤可以查看我们前面的DDS的文章。

多级CIC滤波器的抽取的FPGA仿真结果

进行运行结果如下:
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第7张图片
放大的局部信息:
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第8张图片
从上面的运行结果中可以看出,我们成功实现了原始信号的四抽取。如果要实现更高倍数的抽取,只需要对代码中稍作修改即可。

多级CIC滤波器的内插的FPGA实现

同样这里梳状滤波器、积分滤波器的输入输出位宽满足多级CIC滤波器的抽取时候的条件。本次实验选取的位宽依旧有很大剩余,这是为了计算的简洁性,但是做学术的时候绝对不可以出现这样的情况。**

我们实现的功能是:采样率0.25MHz,信号2.5KHz的正弦波进行采样,然后将采样之后的信号进行4倍内插。在这个程序中,我们使用的是3级4阶CIC滤波器级联进行滤波操作

多级CIC滤波器的内插的FPGA代码

这里废话不多说,直接给出相应的代码供大家学习,这里需要注意我们使用的结构是经过Noble恒等式优化之后的结构,整个过程与MATLAB仿真完全一摸一样。
CIC_inter模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// 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滤波器在内插时候的操作。

多级CIC滤波器的内插的FPGA测试代码

tb模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// 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

正弦波的产生我们同样使用了DDS IP核。

多级CIC滤波器的内插的FPGA仿真结果

CIC滤波器内插结果如下:
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第9张图片
放大后的细节如下:
基于FPGA的CIC滤波器设计(2)——以数字上下变频为例讲解_第10张图片
由上图可知,我们成功实现了基于CIC滤波器的内插操作。

参考文献

[1]、FPGADesigner——CSDN博主

[2]、长弓的坚持——CSDN博主

[3]、行州人——CSDN博主

[4]、FPGA开源工作室——CSDN博主

总结

在查找一些资料的时候,发现一些博主只给出部分代码,其实这样别人根本看不懂,只有给出整个工程代码才易于知识的传播。创作不易,认为文章有帮助的同学们可以关注、点赞、转发支持。为行业贡献及其微小的一部分。或者对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

你可能感兴趣的:(FPGA)