CIC滤波器和FPGA实现

CIC滤波器

CIC滤波器是用不同抽样频率进行数字信号处理的一种FIR滤波器。主要用于数字信号的抽取和内插。

CIC滤波器由一对或多对积分-梳状滤波器组成,在抽取CIC中,输入信号依次经过积分、降采样,以及与积分环节数目相同的梳状滤波器。在内插CIC中,输入信号依次经过梳状滤波器,升采样,以及与梳状数目相同的积分环节。

什么是多采样率数字滤波器?

一般的滤波器都只有一种采样频率,有些情况下,系统内部需要不同采样频率的数字信号,这样就需要使用CIC滤波器对信号进行上采样或者下采样,进而获得相应采样率下的信号。

基于初始采样频率f1,第二采样频率要么是高于f1,要么是低于f1。前者实现的原理是内插,后者是抽取。

抽取

含义:一个有用的正弦波模拟信号经采样频率为f1的抽样信号抽样后得到了数字信号,很明显这个数字信号序列是在f1频率下得到的,现在,假如我隔几个点抽取一个信号,比如就是5吧,我隔5个点抽取一个信号,是不是就是相当于我采用了1/5倍f1的采样频率对模拟信号进行采样了?所以,抽取的过程就是降低抽样率的过程,但是我们知道,这是在时域的抽样,时域的抽样等于信号在频域波形的周期延拓,周期就是采样频率,所以,为了避免在频域发生频谱混叠,抽样定理也是我们要考虑的因素(通常下级需要滤波器滤出周期性频率)。

抽取造成的问题之一就是频谱的混叠。因为时域的抽样等于信号在频域波形的周期延拓,如果下采样倍数太小,就会造成频谱在频域混叠。根据采样定理,

当采样频率fs是信号(最高)频率f0的2倍时,正好不发生频谱混叠。

下采样时也要遵循相同的定理,即下采样后的采样频率fs/M,至少是信号频率f0的2倍。

下图是对信号进行f1抽样得到的频谱

CIC滤波器和FPGA实现

故在下采样前需要对信号进行抗混叠滤波,其效果就是滤出频谱中 1/2 * (F1/M)之后的频率。


CIC

级联积分梳妆滤波器(Cascade Intergrator Comb),将积分器和梳妆滤波器级联而得。

Need To Know:

  1. 低通滤波特性
  2. 滤波系数为1,无需对系数进行存储,节省存储单元,无需乘法器
  3. 结构规则,设置抽取/插值因子时候不改变滤波器整体结构。
  4. 输入信号通过CIC滤波器后会引起位增长问题,工程上要适当截位。

CIC滤波器和FPGA实现

从上图可以看出:

  • 在内插系统中,CIC滤波器的级联方式是:积分器+抽样因子+梳状滤波器
  • 积分器结构:输出延迟y(n-1)后与输入x(n)相加
  • 梳状滤波器器结构:输入延迟x(n-1)后与输入x(n)相减

积分器

积分器是一个具有单极点的、同一反馈系数的IIR滤波器,积分器在时域上的表达式是:

CIC滤波器和FPGA实现

积分器的结构如下图所示:

CIC滤波器和FPGA实现

梳状滤波器

梳状滤波器在高采样率fs、抽取因子为R的情况下,是一个奇异的FIR滤波器,在时域上的表达式:

CIC滤波器和FPGA实现

其中,R,M为整数,决定了梳妆滤波器的延迟长度。

基本梳状滤波器的结构是:

CIC滤波器和FPGA实现

FPGA实现CIC滤波器

下图所示一个N级抽取系统的结构图(抽样倍数为D):

CIC滤波器和FPGA实现

参考代码

`timescale 1ns/1ns


module CIC #(parameter  width = 12 ) (
                                      input 	wire                 clk,
                                      input 	wire                 rst,
                                      input 	wire        [ 15:0 ] decimation_ratio,  //抽取因子
                                      input 	wire signed [ 7:0 ]  d_in,
                                      output 	reg signed   [ 7:0 ]  d_out,
                                      output 	reg                   d_clk             //输出下采样后的时钟
) ;

    reg signed[ width-1:0 ] d_tmp,
        d_d_tmp ;

    // Comb stage registers-梳妆滤波器
    reg signed[ width-1:0 ] d6,
        d_d6 ;
    reg signed[ width-1:0 ] d7,
        d_d7 ;
    reg signed[ width-1:0 ] d8,
        d_d8 ;
    reg signed[ width-1:0 ] d9,
        d_d9 ;
    reg signed[ width-1:0 ] d10 ;

    reg[ 15:0 ] count ; //抽取计数器
    reg v_comb ;  // Valid signal for comb section running at output rate
    reg d_clk_tmp ;

    // Integrator stage registers-积分器
    //CIC级联数目为5
    reg signed[ width-1:0 ] d1 ;
    reg signed[ width-1:0 ] d2 ;
    reg signed[ width-1:0 ] d3 ;
    reg signed[ width-1:0 ] d4 ;
    reg signed[ width-1:0 ] d5 ;
    always @(posedge clk) begin
        if (rst) begin
            d1    <= 0 ;
            d2    <= 0 ;
            d3    <= 0 ;
            d4    <= 0 ;
            d5    <= 0 ;
            count <= 0 ;
        end
        else begin
            // Integrator section-y(n) = x(n) + y(n-1)
            d1 <= d_in + d1 ;
            d2 <= d1 + d2 ;
            d3 <= d2 + d3 ;
            d4 <= d3 + d4 ;
            d5 <= d4 + d5 ;
            // Decimation-抽取
            if (count == decimation_ratio - 1) begin
                count     <= 16'b0 ;
                d_tmp     <= d5 ;
                d_clk_tmp <= 1'b1 ;
                v_comb    <= 1'b1 ;
            end
            else if (count == decimation_ratio >> 1) begin
                d_clk_tmp <= 1'b0 ;
                count     <= count + 16'd1 ;
                v_comb    <= 1'b0 ;
            end
            else begin
                count  <= count + 16'd1 ;
                v_comb <= 1'b0 ;
            end
        end
    end

    always @(posedge clk) begin  // Comb section running at output rate
        d_clk <= d_clk_tmp ;
        if (rst) begin
            d6    <= 0 ;
            d7    <= 0 ;
            d8    <= 0 ;
            d9    <= 0 ;
            d10   <= 0 ;
            d_d6  <= 0 ;
            d_d7  <= 0 ;
            d_d8  <= 0 ;
            d_d9  <= 0 ;
            d_out <= 8'b0 ;
        end
        else begin
            if (v_comb) begin   //v_comb set 1 when count == decimation_ratio
                                // Comb section-y(n) = x(n) - x(n-1)
                d_d_tmp <= d_tmp ;
                d6      <= d_tmp - d_d_tmp ;
                d_d6    <= d6 ;
                d7      <= d6 - d_d6 ;
                d_d7    <= d7 ;
                d8      <= d7 - d_d7 ;
                d_d8    <= d8 ;
                d9      <= d8 - d_d8 ;
                d_d9    <= d9 ;
                d10     <= d9 - d_d9 ;
                d_out   <= d10 >>> (width - 8) ;
            end
        end
    end
endmodule