CIC抽取滤波器MATLAB仿真和FPGA实现(2)
CIC的FPGA实现其实非常简单,但是要想输入输出与MATLAB仿真结果一致就需要一定的技巧和结构变化。CIC理论基础在上个文章里面进行了描述。
在进行FPGA实现时需要明白CIC本质就是一个加法运算。其离散表达式有两种, 1、 传统的分别实现积分环节和梳状环节.
但是这里需要注意的是这两个环节都是不稳定系统,转化到FPGA逻辑表述就是积分环节是一个无限累加的过程,这样就需要不断的增大位宽来放置数据的溢出,微分环节需要不断的去做减法。这样会导致数据的溢出以及截尾导致的较大误差。但是这种在实际应用中也是可以直接实现的,出现的与理论的误差也是避免不了的。 2、采用累加的方式实现传递函数是 这种实现方式比较可控,并且能明确知道滤波器的位宽和增益。但是这种实现方式需要较多的加法运算,针对较小的RM时可以采用直接加的方式,但是若RM为100甚至更大时这种方式就活很消耗资源,因此可以采用下面这种实现方式 采用这种方式可以值进行一次加法和一次减法计算即可。但是会额外的消耗一定的RAM存储资源。
上面说了两种实现CIC方式,下面分别是实现两种方式的FPGA代码(通过实际数据对两种方式对比发现第二种不但节省资源并且与MATLAB处理得到结果一致)
第一种实现方式是对CIC特性进行测试,第二种实现方式是在实际的项目中进行使用,且第二种方式是经过好多轮迭代更新得到的实现方式,有着很高的工程应用价值。
第一种实现方式:
module SigCIC(
rst,clk,din, rdy,dout); input rst; //复位信号,高电平有效 input clk; //FPGA系统时钟,频率为200kHz inputsigned [9:0] din; //数据输入频率为200kHZ
outputrdy; //输出数据有效指示信号
output signed [12:0] dout; //滤波后的输出数据,5倍抽取后的数据,频率为40kHZ reg rdy_tem; reg [2:0] c; reg signed [12:0] tem; reg signed [12:0] dout_tem; always @(posedge clk or posedge rst) if (rst) //初始化寄存器值为0 begin c <= 3'd0; tem <= 13'd0; dout_tem <= 13'd0; rdy_tem <= 1'b0;end
elsebegin
if (c==4) begin rdy_tem<= 1'b1; dout_tem<= tem + din; c =3'd0; tem =13'd0; end else begin rdy_tem<= 1'b0; tem =tem + din; c = c +1; end end assign dout = dout_tem;assign rdy = rdy_tem;
endmodule
第二种实现方式:
module hight_fire_fir(
input wire rst_n ,
input wire clk_125m ,
input wire unwinding_data_out_en ,
input wire [31:0] unwinding_data_out ,
output wire hight_fire_fir_data_out_en ,
output wire [34:0] hight_fire_fir_data_out
);reg unwinding_data_out_en_t ;
reg unwinding_data_out_en_t_t ;
reg unwinding_data_out_en_t_t_t ;
reg [31:0] unwinding_data_out_t ;
reg [10:0] ram_wr_add ;
reg [10:0] ram_rd_add ;
wire [31:0] ram_rd_data ;
wire [32:0] add1_data_out ;
reg [10:0] ram_wr_add2 ;
reg [10:0] ram_rd_add2 ;
wire [34:0] ram_rd_data2 ;
wire [34:0] add2_data_out ;
always@(posedge clk_125m or negedge rst_n )begin
if(rst_n==1’b0) begin
unwinding_data_out_en_t <= 'b0 ;
unwinding_data_out_en_t_t <= 'b0 ;
unwinding_data_out_en_t_t_t <= 'b0 ;
unwinding_data_out_t <= 'b0 ;
end else begin
unwinding_data_out_en_t <=unwinding_data_out_en ;
unwinding_data_out_en_t_t <= unwinding_data_out_en_t ;
unwinding_data_out_en_t_t_t <=unwinding_data_out_en_t_t ;
unwinding_data_out_t <= unwinding_data_out ;
end
end
always@(posedge clk_125m or negedge rst_n )begin
if(rst_n==1’b0) begin
ram_rd_add <= 256 ;
end else if((unwinding_data_out_en==1)&&(ram_rd_add<1535)) begin
ram_rd_add <= ram_rd_add + 1’b1 ;
end else if (ram_rd_add==1535) begin
ram_rd_add <= 'b0 ;
end
end
always@(posedge clk_125m or negedge rst_n )begin
if(rst_n==1’b0) begin
ram_wr_add <= 'b0 ;
end else if((unwinding_data_out_en==1)&&(ram_wr_add<1535)) begin
ram_wr_add <= ram_wr_add + 1’b1 ;
end else if (ram_wr_add==1535) begin
ram_wr_add <= 'b0 ;
end
end
hight_fire_fir_ram1 u_hight_fire_fir_ram1 (
.clka(clk_125m), // input clka
.ena(unwinding_data_out_en), // input ena
.wea(1’b1), // input [0 : 0] wea
.addra(ram_wr_add), // input [8 : 0] addra
.dina(unwinding_data_out), // input [33 : 0]dina
.clkb(clk_125m), // input clkb
.enb(unwinding_data_out_en), // input enb
.addrb(ram_rd_add), // input [8 : 0] addrb
.doutb(ram_rd_data) // output [33 : 0] doutb
);
hight_fire_fir_add1 u_hight_fire_fir_add1 (
.a(unwinding_data_out_t), // input [31 : 0] a
.b(ram_rd_data), // input [34 : 0] b
.clk(clk_125m), // input clk
.ce(unwinding_data_out_en_t), // input ce
.s(add1_data_out) // output [34 : 0] s
);
always@(posedge clk_125m or negedge rst_n )begin
if(rst_n==1’b0) begin
ram_rd_add2 <=0 ;
end else if((unwinding_data_out_en_t==1)&&(ram_rd_add2<255)) begin
ram_rd_add2 <= ram_rd_add2 + 1’b1 ;
end else if (ram_rd_add2==255) begin
ram_rd_add2 <= 'b0 ;
end
end
always@(posedge clk_125m or negedge rst_n )begin
if(rst_n==1’b0) begin
ram_wr_add2 <= 'b0 ;
end else if((unwinding_data_out_en_t_t_t==1)&&(ram_wr_add2<255)) begin
ram_wr_add2 <= ram_wr_add2 + 1’b1 ;
end else if (ram_wr_add2==255) begin
ram_wr_add2 <= 'b0 ;
end
end
hight_fire_fir_ram2 u_hight_fire_fir_ram2 (
.clka(clk_125m), // input clka
.ena(unwinding_data_out_en_t_t_t), // input ena
.wea(1’b1), // input [0 : 0] wea
.addra(ram_wr_add2), // input [8 : 0] addra
.dina(add2_data_out), // input [33 : 0] dina
.clkb(clk_125m), // input clkb
.enb(unwinding_data_out_en_t), // input enb
.addrb(ram_rd_add2), // input [8 : 0] addrb
.doutb(ram_rd_data2) // output [33 : 0] doutb
);
hight_fire_fir_add2 u_hight_fire_fir_add2 (
.a(add1_data_out), // input [31 : 0] a
.b(ram_rd_data2), // input [34 : 0] b
.clk(clk_125m), // input clk
.ce(unwinding_data_out_en_t_t), // input ce
.s(add2_data_out) // output [34 : 0] s
);
assign hight_fire_fir_data_out_en = unwinding_data_out_en_t_t_t ;
assign hight_fire_fir_data_out = add2_data_out ;
endmodule