CIC 滤波器原理与结构
CIC(级联积分梳状)滤波器是一种高效的多速率信号处理滤波器,属于无乘法器的线性相位 FIR 滤波器。它在数字下变频(DDC)和数字上变频(DUC)中应用广泛。最大的优势在于不需要乘法器,仅由加法器、减法器和寄存器组成,在 FPGA 资源占用上极具竞争力。
CIC 滤波器主要有三种工作模式:
- 抽取滤波器:数据流由高速输入变为低速输出,常用于降低采样率。其核心结构包含积分器和梳状器。
- 插值滤波器:数据流由低速输入变为高速输出,用于提升采样率。
- 单纯滤波器:数据流速率不变,积分器和梳状器工作在相同采样率下,主要用于移动平均滤波。
基本架构
CIC 的核心由积分器(Integrator)和梳状器(Comb Filter)组成。积分器执行累加运算,状态方程为 $y[n] = y[n-1] + x[n]$;梳状器执行差分运算,状态方程为 $y[n] = x[n] - x[n-R]$,其中 R 为抽取倍数。
举个例子,如果输入信号采样率为 100MHz,抽取因子为 10,那么降采样后的信号速率就是 10MHz。由于单级 CIC 的第一旁瓣阻带衰减固定为 13.46dB,抑制效果有限,实际工程中常通过级联多级的方式来提升性能。可以将 CIC 想象成多层过滤系统:一级像纱网,二级加滤布,级数越高过滤越纯净,但系统'阻力'(资源消耗和位宽增长)也会增加。通常 N=5 或 N=6 是性能和资源的平衡点。
最大位宽计算
在 FPGA 实现中,位宽管理至关重要。积分器的累加效应会导致内部数据位宽随级数线性增长。若位宽不足,极易发生溢出。
最大位宽计算公式如下:
$$B_{max} = B_{in} + N \times \lceil \log_2(R \times M) \rceil$$
其中:
- $B_{in}$:输入位宽
- $R$:抽取/插值因子
- $M$:差分延迟(通常为 1)
- $N$:级数
假设输入位宽为 16 位,抽取因子为 64,级数为 3 时,最大位宽约为 34 位;若级数增加到 6 位,则需 52 位。这意味着每增加一级,寄存器和逻辑资源消耗都会显著上升。同时需注意,级数增加虽然提升了阻带抑制能力,但也会带来通带衰减的副作用,必要时需在 CIC 后级联补偿 FIR 滤波器。
FPGA 实现细节
下面以级数为 3、抽取因子为 16 为例,展示具体的 Verilog 实现思路。代码重点在于积分器的累加逻辑、降采样计数以及梳状器的差分处理。
核心模块代码
`timescale 1ns / 1ps
module cic_down_sample#(
parameter DATA_IN_WIDTH = 8,
parameter DATA_OUT_WIDTH = 8,
parameter CIC_FACTORS = 16, // 抽取因子
parameter MAX_WIDTH = 20 // 最大位宽
)(
input clk,
input rstn,
input signed [DATA_IN_WIDTH-1:0] data_in,
input data_in_valid,
output signed [DATA_OUT_WIDTH-1:0] data_out
);
wire signed[MAX_WIDTH-1:0] add_data_0;
wire signed[MAX_WIDTH-1:0] add_data_1;
wire signed[MAX_WIDTH-1:0] add_data_2;
reg signed[MAX_WIDTH-1:0] data_0;
reg signed[MAX_WIDTH-1:0] data_1;
reg signed[MAX_WIDTH-1:0] data_2;
reg [4:0] cnt_div;
reg sample_flag; // 采样标志
reg signed[MAX_WIDTH-1:0] comb_in;
wire signed[MAX_WIDTH-1:0] add_comb_0;
wire signed[MAX_WIDTH-1:0] add_comb_1;
wire signed[MAX_WIDTH-1:0] add_comb_2;
reg signed[MAX_WIDTH-1:0] comb_0;
reg signed[MAX_WIDTH-1:0] comb_1;
reg signed[MAX_WIDTH-1:0] comb_2;
// 积分器部分
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
data_0 <= 'd0;
data_1 <= 'd0;
data_2 <= 'd0;
end else begin
data_0 <= add_data_0;
data_1 <= add_data_1;
data_2 <= add_data_2;
end
end
assign add_data_0 = {{12{data_in[7]}}, data_in} + data_0;
assign add_data_1 = add_data_0 + data_1;
assign add_data_2 = add_data_1 + data_2;
// 降采样计数器
always @(posedge clk or negedge rstn) begin
if (!rstn)
cnt_div <= 'd0;
else if (cnt_div == CIC_FACTORS - 1)
cnt_div <= 'd0;
else
cnt_div <= cnt_div + 1;
end
// 生成采样使能信号
always @(posedge clk or negedge rstn) begin
if (!rstn)
sample_flag <= 1'b0;
else if (cnt_div == CIC_FACTORS - 1)
sample_flag <= 1'b1;
else
sample_flag <= 1'b0;
end
// 梳状器部分
always @(posedge clk or negedge rstn) begin
if (!rstn)
comb_in <= 'd0;
else if (sample_flag)
comb_in <= add_data_2;
end
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
comb_0 <= 'd0;
comb_1 <= 'd0;
comb_2 <= 'd0;
end else if (sample_flag) begin
comb_0 <= comb_in;
comb_1 <= add_comb_0;
comb_2 <= add_comb_1;
end
end
assign add_comb_0 = comb_in - comb_0;
assign add_comb_1 = add_comb_0 - comb_1;
assign add_comb_2 = add_comb_1 - comb_2;
// 输出截取高位,避免低位噪声影响
assign data_out = add_comb_2[19:12];
endmodule



