FPGA CIC抽取滤波器设计
cic抽取滤波器是一种兼具低通抗混叠与降采样作用的高速率滤波器,内部不需要系数计算也不涉及乘法运算,仅有梳状器comb和积分器integrator组成,一阶cic抽取滤波器结构如下
R为抽取率,M为延迟因子,fs为输入采样率,fs/R为输出采样率,当阶数为N时,只需要将N个积分器串联在一起,N个梳状器串联在一起即可
cic抽取滤波器的z域表达式如下
令z=可得频域表达式
将f=0可得直流增益
因此相比于IIR、FIR数字滤波器,cic的直流增益随着M、R、N的增加指数级上升,因此在数字电路设计位宽时cic输出位宽可根据直流增益的位宽与输入位宽来确定。
cic抽取滤波器截止频率无法精确计算,但可以获取近似值,假设对其进行了直流增益补偿,即整体输出除以直流增益,幅频特性-3db为截止频率点
可见归一化截止频率始终小于归一化那奎斯特频率0.5,同时随着MRN增加而减少,因此可知cic抽取滤波器具有良好的抗混叠能力
因此同时具备抗混叠与降采样功能的cic抽取滤波器广泛应用于数字抗混叠滤波器的设计
在matlab中使用fdatool设计如下
点击实现模型来在simulink中看其具体结构
从这来导出幅频特性图
使用Verilog语言编写如下
`timescale 1ns / 1ps
module CIC_Decimator#(parameter BW_IN = 16 ,parameter BW_OUT = 19 ,parameter ORDER = 3 ,parameter COMB_DLY= 2 ,parameter DSAMP = 3
)(input i_clk ,input i_rst ,input [BW_IN - 1:0] i_data ,input i_vld ,output reg [BW_OUT - 1:0] o_data ,output reg o_vld);// integrationreg signed [BW_OUT - 1:0] r_intg_arr [0:ORDER - 1];wire signed [BW_OUT - 1:0] w_din_sext;bit_extension# (.BW_IN (BW_IN ) ,.BW_OUT (BW_OUT ) ,.SIGNED (1 ))
bit_extension_U(.i_data(i_data ),.o_data(w_din_sext)
);genvar i;generatefor(i = 1; i < ORDER; i = i + 1) beginalways@(posedge i_clk or posedge i_rst) beginif(i_rst)r_intg_arr[i] <= 'd0;else if(i_vld)r_intg_arr[i] <= r_intg_arr[i] + r_intg_arr[i - 1];elser_intg_arr[i] <= r_intg_arr[i];endendendgeneratealways@(posedge i_clk or posedge i_rst) beginif(i_rst)r_intg_arr[0] <= 'd0;else if(i_vld)r_intg_arr[0] <= w_din_sext + r_intg_arr[0];elser_intg_arr[0] <= r_intg_arr[0];end// downsamplingreg [7:0] r_dsamp_cnt ;(*keep = "true"*)reg r_dsamp_vld_cp0 ;(*keep = "true"*)reg r_dsamp_vld_cp1 ;(*keep = "true"*)reg r_dsamp_vld_cp2 ;(*keep = "true"*)reg r_dsamp_vld_cp3 ;always@(posedge i_clk or posedge i_rst) beginif(i_rst)r_dsamp_cnt <= 'd0;else if(i_vld)if(r_dsamp_cnt < DSAMP - 1)r_dsamp_cnt <= r_dsamp_cnt + 1;elser_dsamp_cnt <= 'd0;elser_dsamp_cnt <= r_dsamp_cnt;endreg [BW_OUT - 1:0] r_dsamp_data ;always@(posedge i_clk or posedge i_rst) beginif(i_rst) beginr_dsamp_vld_cp0 <= 'b0;r_dsamp_vld_cp1 <= 'b0;r_dsamp_vld_cp2 <= 'b0;r_dsamp_vld_cp3 <= 'b0;r_dsamp_data <= 'd0;endelse if(i_vld & !r_dsamp_cnt) beginr_dsamp_vld_cp0 <= 'b1;r_dsamp_vld_cp1 <= 'b1;r_dsamp_vld_cp2 <= 'b1;r_dsamp_vld_cp3 <= 'b1;r_dsamp_data <= r_intg_arr[ORDER - 1];endelse beginr_dsamp_vld_cp0 <= 'b0;r_dsamp_vld_cp1 <= 'b0;r_dsamp_vld_cp2 <= 'b0;r_dsamp_vld_cp3 <= 'b0;r_dsamp_data <= r_dsamp_data;endend// combreg signed [BW_OUT - 1:0] r_diff_arr [0:ORDER - 1];reg signed [BW_OUT - 1:0] r_comb_arr [0:ORDER - 1][0:COMB_DLY - 1];generatefor(i = 1; i < ORDER; i = i + 1) beginalways@(posedge i_clk or posedge i_rst) beginif(i_rst)r_diff_arr[i] <= 'd0;else if(r_dsamp_vld_cp1)r_diff_arr[i] <= r_diff_arr[i - 1] - r_comb_arr[i][COMB_DLY - 1];elser_diff_arr[i] <= r_diff_arr[i];endendendgeneratealways@(posedge i_clk or posedge i_rst) beginif(i_rst)r_diff_arr[0] <= 'd0;else if(r_dsamp_vld_cp3)r_diff_arr[0] <= r_dsamp_data - r_comb_arr[0][COMB_DLY - 1];elser_diff_arr[0] <= r_diff_arr[0];endinteger j;generatefor(i = 1; i < ORDER; i = i + 1) beginalways@(posedge i_clk or posedge i_rst) beginif(i_rst) for(j = 0; j < COMB_DLY; j = j + 1) beginr_comb_arr[i][j] <= 'd0;endelse if(r_dsamp_vld_cp2) beginr_comb_arr[i][0] <= r_diff_arr[i - 1];for(j = 1; j < COMB_DLY; j = j + 1) beginr_comb_arr[i][j] <= r_comb_arr[i][j - 1];endendelsefor(j = 0; j < COMB_DLY; j = j + 1) beginr_comb_arr[i][j] <= r_comb_arr[i][j];endendendendgeneratealways@(posedge i_clk or posedge i_rst) beginif(i_rst)for(j = 0; j < COMB_DLY; j = j + 1) beginr_comb_arr[0][j] <= 'd0;endelse if(r_dsamp_vld_cp3) beginr_comb_arr[0][0] <= r_dsamp_data;for(j = 1; j < COMB_DLY; j = j + 1) beginr_comb_arr[0][j] <= r_comb_arr[0][j - 1];endendelsefor(j = 0; j < COMB_DLY; j = j + 1) beginr_comb_arr[0][j] <= r_comb_arr[0][j];endendalways@(posedge i_clk or posedge i_rst) beginif(i_rst) begino_data <= 'd0;o_vld <= 'b0;endelse if(r_dsamp_vld_cp3) begino_data <= r_diff_arr[ORDER - 1];o_vld <= 'b1;endelse begino_data <= o_data;o_vld <= 'b0 ;endendendmodule
tb文件将手写cic与cic ip对比
`timescale 1ns / 1psmodule dds_cic_tb();reg i_clk ;reg i_rst ;reg [15:0] i_data ;reg i_dvld ;reg [31:0] addr ;reg [15:0] sine [0:999];localparam BW_IN = 16 ,BW_OUT = 24 ,ORDER = 4 ,COMB_DLY= 1 ,DSAMP = 4 ;wire w_ip_ready ;wire [BW_OUT - 1:0] w_cic_out ;wire w_cic_ovld ;always@(posedge i_clk) beginif(i_rst) beginaddr <= 'd0;i_data <= 'd0;i_dvld <= 'b0;endelse if(w_ip_ready & ~i_dvld) beginaddr <= addr + 1;i_data <= sine[addr];i_dvld <= 1'b1;endelse beginaddr <= addr;i_data <= i_data;i_dvld <= 'b0;endendCIC_Decimator#(.BW_IN (BW_IN ) ,.BW_OUT (BW_OUT ) ,.ORDER (ORDER ) ,.COMB_DLY (COMB_DLY ) ,.DSAMP (DSAMP ))
CIC_Decimator_U(.i_clk (i_clk ),.i_rst (i_rst ),.i_data (i_data ),.i_vld (i_dvld ),.o_data (w_cic_out ),.o_vld (w_cic_ovld )
); always#10 i_clk = ~i_clk;initial begini_clk = 1;i_rst = 1;$readmemh("G:/FPGA_Prj2025/DDS/sig.txt", sine);#100i_rst = 0;endwire [23:0] w_ipout ;wire w_ipvld ;cic_d
cic_d (.aclk (i_clk ), // input wire aclk.aresetn (~i_rst ),.s_axis_data_tdata (i_data ), // input wire [15 : 0] s_axis_data_tdata.s_axis_data_tvalid (i_dvld ), // input wire s_axis_data_tvalid.s_axis_data_tready (w_ip_ready ), // output wire s_axis_data_tready.m_axis_data_tdata (w_ipout ), // output wire [23 : 0] m_axis_data_tdata.m_axis_data_tvalid (w_ipvld ) // output wire m_axis_data_tvalid
);endmodule
cic ip核配置
波形仿真如下:
其中蓝色为输入波形,白色为手写cic的输出黄色为cic ip核输出
还要注意一点,由于一般需要对直流增益进行缩放补偿,因此可将MR设为2的n倍,这样只需要对cic输出进行n个算数右移即可,即$signed(cic out) >>> n。