CIC插值抽取滤波器的matlab仿真及FPGA实现

2 篇文章 1 订阅
1 篇文章 0 订阅

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

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学技术得猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值