1 多级CIC的noble等式简要概述
如下图所示
2.matlab仿真实现
根据noble等式,仿真CIC插值及滤波,同时根据FPGA定点计算位宽。仿真程序抽取滤波器结果如下所示。
插值滤波结果如下
同时仿真定点下位数变化如下所示
给出matlab仿真程序如下图所示
clc;
clear all;
fs=20e6;%sample frequency
f1=0.1e6;
f2=8e6;
fc=4e6;%滤波截止信号
N_CIC=ceil(fs/fc);%N_CIC为CIC滤波器长度,阶数为N_CIC-1
k=3;%K级CIC级数
N_sample=fs/f1*5;
t=0:1/fs:(N_sample-1)/fs;
s1=cos(2*pi*f1*t);%有用信号
s2=cos(2*pi*f2*t);%干扰信号
s3=s1+s2;%混频信号
%--------量化信号----------
lianghua_bit=12;
s3_lianghua=round(s3/max(abs(s3))*(2^(lianghua_bit-1)-1));
fid=fopen('D:\desktop\stuy\coe_txt\hun_singnal.txt','w');
fprintf(fid,'%d\n',s3_lianghua);
fprintf(fid,';');
fclose(fid);
s1_lianghua=round(s1/max(abs(s1))*(2^(lianghua_bit-1)-1));
fid=fopen('D:\desktop\stuy\coe_txt\s1_singnal.txt','w');
fprintf(fid,'%d\n',s1_lianghua);
fprintf(fid,';');
fclose(fid);
%%————————————————————————————————————————————————————————————————
%CIC通带容限,阻带容限计算
%%————————————————————————————————————————————————————————————————
fp=fs/N_CIC/8; %通带截止频率
fp=0:200:fs/N_CIC/8;
%Ep=(1/6)*(pi*N_CIC*fp/2).^2; %通带截止频率归一化,1/2fs为1 fs=2
Ep=(1/6)*(pi*N_CIC*fp./fs).^2;
Ep=Ep*k;
Ap=20*log10((1+Ep)./(1-Ep));
fx=1e6; %阻带截止频率
fx=0:200:fs/N_CIC; %阻带截止频率归一化
Ex=fx*N_CIC/fs;
Ax=20*log10(Ex);
Ax=Ax*k;
figure(1)
subplot(211);
plot(fp,Ap);
xlabel('频率');ylabel('通带衰减');
subplot(212);
plot(fx,Ax);
xlabel('频率');ylabel('阻带衰减');
%%————————————————————————————————————————————————————————————————
%CIC滤波器性质及滤波作用
%%————————————————————————————————————————————————————————————————
b=ones(1,N_CIC);
a=[1,zeros(1,N_CIC-1)];
CIC_rom=zeros(k,k*N_CIC);
[CIC_rom(1,:),fm] = impz(b,a,k*N_CIC);
for i = 2:k
CIC_rom(i,:)=filter(b,1,CIC_rom(i-1,:));
end
b_k=CIC_rom(k,:);
s4=filter(b,1,s3);%一级CIC
s5=filter(b_k,1,s3);%多级CIC
figure(2)
subplot(3,1,1)
plot(s3)
title('混频信号')
subplot(3,1,2)
plot(s4)
title('单级CIC滤波后信号')
subplot(3,1,3)
plot(s5)
title('多级CIC滤波后信号')
%-----CIC滤波器性质-------------
figure(3)
freqz(b,1)
title('单级CIC滤波器幅频响应')
figure(4)
freqz(b_k,1)
title('多级CIC滤波器幅频响应')
figure(5)
dstep(b,a,k*N_CIC)
title('单级CIC阶跃响应')
dStep_para =dstep(b,a,k*N_CIC);%计算单位阶跃响应,判断输出相对输入的位宽变化,便于定点设计
fprintf('单级CIC滤波FPGA定点输出相对输入扩展=%d bit\n',ceil(log2(max(abs(dStep_para))))-1);
%不采用阶跃信号,直接理论计算ceil(log2(N_CIC))-1 k为级联参数,M为抽取倍数,N_CIC为阶数
fprintf('单级CIC滤波FPGA定点过程中运算相对输入扩展=%d bit\n',ceil(N_CIC*log2(N_CIC))-1);
fprintf('CIC滤波器通带=%f fs\n',2/N_CIC);%Fs为采样频率
figure(6)
a_k=[1,zeros(1,length(b_k)-1)];
dstep(b_k,a_k,k*N_CIC)
title('多级CIC阶跃响应')
dStep_para_mul =dstep(b_k,a_k,k*N_CIC);%计算单位阶跃响应,判断输出相对输入的位宽变化,便于定点设计
fprintf('多级CIC滤波FPGA定点输出相对输入扩展=%d bit\n',ceil(log2(max(abs(dStep_para_mul))))-1);
%不采用阶跃信号,直接理论计算ceil(k*log2(N_CIC))-1 k为级联参数,M为抽取倍数,N_CIC-1为阶数
fprintf('多级CIC滤波FPGA定点过程中运算相对输入扩展=%d bit\n',ceil(N_CIC*log2(N_CIC*k))-1);
fprintf('CIC滤波器通带=%f fs\n',2/N_CIC);%Fs为采样频率
figure(7)
subplot(4,1,1)
impz(b,1,k*N_CIC)
title('单级CIC单位脉冲响应')
subplot(4,1,2)
zplane(b,a);
title('单级CIC零极点图')
subplot(4,1,3)
impz(b_k,1,k*N_CIC)
title('多级CIC单位脉冲响应')
subplot(4,1,4)
zplane(b_k,a_k);
title('多级CIC零极点图')
%%————————————————————————————————————————————————————————————————
%多级CIC抽取——Noble不等式
%%————————————————————————————————————————————————————————————————
figure(8)
subplot(3,1,1)
stem(s3)
title('原始混频信号')
%----------采用传统反馈结构滤波抽取----------
% b_tradition=[1,zeros(1,N_CIC-2),-1];
% a_tradition=[1,-1];
% s6=filter(b_tradition,a_tradition,s3);%此处只有单级CIC
s6=filter(b_k,1,s3_lianghua);
y1 = downsample(s6,N_CIC,0);
subplot(3,1,2)
stem(y1)
title('传统反馈方式滤波器抽取')
%-------采用Noble不等式优化后抽取-----
a_Noble=[1,-1];
b_Noble=[1,-1];
len=length(s3);
%integerater
CIC_Noble_a=zeros(k,len);
CIC_Noble_a(1,:)= filter(1,a_Noble,s3_lianghua);
for i = 2:k
CIC_Noble_a(i,:)=filter(1,a_Noble,CIC_Noble_a(i-1,:));
end
ya = downsample(CIC_Noble_a(k,:),N_CIC,3);
%comb
CIC_Noble_b=zeros(k,len/N_CIC);
CIC_Noble_b(1,:)= filter(b_Noble,1,ya);
for i = 2:k
CIC_Noble_b(i,:)=filter(b_Noble,1,CIC_Noble_b(i-1,:));
end
y2 =CIC_Noble_b(k,:);
subplot(3,1,3)
stem(y2)
title('Noble不等式优化后滤波器抽取')
%%————————————————————————————————————————————————————————————————
%多级CIC插值——Noble不等式
%%————————————————————————————————————————————————————————————————
intsinal=s1_lianghua;
figure(9)
subplot(3,1,1)
stem(intsinal)
title('原始信号')
%----------采用传统反馈结构滤波插值----------
yc = upsample(intsinal,N_CIC,0);
y3 = filter(b_k,1,yc);
subplot(3,1,2)
stem(y3)
title('传统反馈方式滤波器插值')
%-------采用Noble不等式优化后插值-----
%%内插滤波器的时候需要先用两级半带滤波器进行4倍上采样让后再用CIC滤波器,此时同频带最多为1/8fs,而抽取滤波正好相反
lenc=length(intsinal);
%comb
CIC_Noble_bc=zeros(k,lenc);
CIC_Noble_bc(1,:)= filter(b_Noble,1,intsinal);
for i = 2:k
CIC_Noble_bc(i,:)=filter(b_Noble,1,CIC_Noble_bc(i-1,:));
end
yd = upsample(CIC_Noble_bc(k,:),N_CIC,0);
%integerater
CIC_Noble_ac=zeros(k,lenc*N_CIC);
CIC_Noble_ac(1,:)= filter(1,a_Noble,yd);
for i = 2:k
CIC_Noble_ac(i,:)=filter(1,a_Noble,CIC_Noble_ac(i-1,:));
end
y4 =CIC_Noble_ac(k,:);
subplot(3,1,3)
stem(y4)
title('Noble不等式优化后滤波器插值')
%%————————————————————————————————————————————————————————————————————————————————
%CIC补偿滤波器ISOP滤波器(1+c*z^-I+Z^-2I)/(c+2) 其中,I=hR,R为抽取因子
%%————————————————————————————————————————————————————————————————————————————————
h=1;
R=N_CIC;
c=-5.592;
a_compensate=[c+2,zeros(1,2*h*R-1)];
b_compensate=[1,zeros(1,h*R-1),c,zeros(1,h*R-1),1];
figure(10)
freqz(b_compensate,a_compensate)
figure(11)
b_k_compensate=filter(b_compensate,a_compensate,b_k);
freqz(b_k_compensate,1)
3 基于FPGA的CIC插值及抽取滤波器实现
根据matlab仿真模型,FPGA编写仿真抽取结果如下所示
CIC插值结果如下
给出完整程序如下
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 21:57:19 07/025/2023
// Design Name:
// Module Name: CIC_filter
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module CIC_filter
#( parameter datain_width = 12,
parameter width_expand = 19,
parameter dataout_width = 18,
parameter MR_order=5, //CIC级联滤波器长度,用noble等式,也为抽取或插取个数
parameter cascade=3, //CIC级联个数
parameter R_directon=1'd1 //1:CIC抽取 0:CIC插值
)
(
input clk,
input rst_n,
input signed[datain_width-1:0] din,
output LOCKED,
output signed[dataout_width-1:0] dout
);
/***********积分器integrator*************/
reg signed[datain_width+width_expand-1:0] int_d [cascade-1:0];
wire signed[datain_width+width_expand-1:0] int_d_out [cascade-1:0];
wire signed[datain_width+width_expand-1:0] dout_int;
reg signed[datain_width+width_expand-1:0] int_dint [cascade-1:0];
wire signed[datain_width+width_expand-1:0] int_dint_out[cascade-1:0];
wire signed[datain_width+width_expand-1:0] dout_interp;
/*************梳状器***********/
reg signed[datain_width+width_expand-1:0] comb_d[cascade:0];
reg signed[datain_width+width_expand-1:0] comb_subtrct[cascade:0];
wire signed[datain_width+width_expand-1:0] dout_comb;
/**************抽取内插与级数cascade相等,采用boble等式************/
reg signed[datain_width+width_expand-1:0] dout_r;
wire signed[datain_width+width_expand-1:0] dout_dwR;
reg [7:0] cnt;
reg R_rdy;
/**************内插与级数cascade相等,采用boble等式************/
reg signed[datain_width+width_expand-1:0] dout_Interpolate ;
wire signed[datain_width+width_expand-1:0] dout_inteR;
reg [7:0] cnt_inte;
/***************内插时钟************************************************/
wire clk_int;
//wire LOCKED;
//————————————————————————————————————————————————————————
/***********积分器integrator*************/
//————————————————————————————————————————————————————————
always@(posedge clk or negedge rst_n)//y(n) = x(n) + y(n-1)
if(!rst_n)
begin
int_d[0] <= 'd0;
end
else begin
int_d[0] <= int_d_out[0];
end
assign int_d_out[0]=int_d[0]+{{width_expand{din[datain_width-1]}},din};
genvar die;
generate
for (die = 0; die <cascade-1; die=die+1)
begin: dieLoop
always@(posedge clk or negedge rst_n)//y(n) = x(n) + y(n-1)
if(!rst_n)begin
int_d[die+1] <= 'd0;
end
else begin
int_d[die+1] <= int_d_out[die+1];
end
assign int_d_out[die+1]=int_d[die+1]+int_d_out[die];
end
endgenerate
assign dout_int = int_d_out[cascade-1];
//————————————————————————————————————————————————————————
/**************抽取内插与滤波长度相等,采用boble等式************/
//————————————————————————————————————————————————————————
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 'b0;
end
else begin
if (cnt == MR_order-1)begin
cnt <= 'b0;
end
else begin
cnt <= cnt+1'd1;
end
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
dout_r <= 'b0;
R_rdy <= 'b0;
end
else begin
if(cnt == MR_order-1)begin
dout_r <= dout_int;
R_rdy <= 'b1;
end
else begin
dout_r <= dout_r;//置零还是保持
R_rdy <= 'b0;
end
end
end
assign dout_dwR=dout_r;
//————————————————————————————————————————————————————————
/*************梳状器***********/
//————————————————————————————————————————————————————————
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
comb_d[0] <= 'd0;
comb_subtrct[0] <= 'd0;
end
else if(R_directon)
begin
if(R_rdy)
begin
comb_d[0] <= dout_dwR;
comb_subtrct[0] <= dout_dwR-comb_d[0];
end
else
begin
comb_d[0] <= comb_d[0];
comb_subtrct[0] <= comb_subtrct[0];
end
end
else
begin
comb_d[0] <= {{width_expand{din[datain_width-1]}},din};
comb_subtrct[0] <= {{width_expand{din[datain_width-1]}},din}-comb_d[0];
end
genvar die_comb;
generate
for (die_comb = 0; die_comb <cascade; die_comb=die_comb+1)
begin: die_combLoop
always@(posedge clk or negedge rst_n)//y(n) = x(n) + y(n-1)
if(!rst_n)
begin
comb_d[die_comb+1] <= 'd0;
comb_subtrct[die_comb+1] <= 'd0;
end
else if(R_directon)
begin
if(R_rdy)
begin
comb_d[die_comb+1] <= comb_subtrct[die_comb];
comb_subtrct[die_comb+1] <= comb_subtrct[die_comb]-comb_d[die_comb+1];
end
else
begin
comb_d[die_comb+1] <= comb_d[die_comb+1];
comb_subtrct[die_comb+1] <= comb_subtrct[die_comb+1];
end
end
else
begin
comb_d[die_comb+1] <= comb_subtrct[die_comb];
comb_subtrct[die_comb+1] <= comb_subtrct[die_comb]-comb_d[die_comb+1];
end
end
endgenerate
assign dout_comb=comb_d[cascade];
//————————————————————————————————————————————————————————————————————
/**************内插与级数cascade相等,采用boble等式************/
//————————————————————————————————————————————————————————————————————
clk_inter clkout
(// Clock in ports
.CLK_IN1(clk), // IN
// Clock out ports
.CLK_OUT1(clk_int), // OUT clk_int时钟波形出来比clk慢很多,为保持数据有效性,将LOCKED高电平作为插值数据输入的起点
// Status and control signals
.RESET(!rst_n),// IN
.LOCKED(LOCKED)); // OUT
always@(posedge clk_int or negedge rst_n)
if(!rst_n)
cnt_inte <='b0;
else if (cnt_inte == MR_order-1)
cnt_inte <='b0;
else
cnt_inte <=cnt_inte+1'd1;
always@(posedge clk_int or negedge rst_n)
if(!rst_n)
dout_Interpolate <= 'd0;
else if(cnt_inte == MR_order-1)
dout_Interpolate <= dout_comb;
else
dout_Interpolate <= 0;//置零还是保持
assign dout_inteR=dout_Interpolate;
//————————————————————————————————————————————————————————————————————
/***********内插积分器integrator*************/
//————————————————————————————————————————————————————————————————————
always@(posedge clk_int or negedge rst_n)//y(n) = x(n) + y(n-1)
if(!rst_n)
begin
int_dint[0] <= 'd0;
end
else begin
int_dint[0] <= int_dint_out[0];
end
assign int_dint_out[0]=int_dint[0]+dout_inteR;
genvar die_int;
generate
for (die_int = 0; die_int <cascade-1; die_int=die_int+1)
begin: dieLoop_inter
always@(posedge clk_int or negedge rst_n)//y(n) = x(n) + y(n-1)
if(!rst_n)begin
int_dint[die_int+1] <= 'd0;
end
else begin
int_dint[die_int+1] <= int_dint_out[die_int+1];
end
assign int_dint_out[die_int+1]=int_dint[die_int+1]+int_dint_out[die_int];
end
endgenerate
assign dout_interp = int_dint_out[cascade-1];
assign dout =R_directon?dout_comb[dataout_width-1:0]:dout_interp[dataout_width-1:0];
endmodule
4 工程文件如下
https://download.csdn.net/download/qq_35028634/88112303