verilog实现czt变换

一、项目要求

ise,Verilog, 点数 512,czt变换, 分析带宽10khz,中心频率25khz,采样频率625KHz
信号从ram中读取,16bit数据宽度
工作时钟100M

二、分析

原理及实现步骤

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
matlab中参考程序:

fs = 1000;
d = designfilt('lowpassfir','FilterOrder',30,'CutoffFrequency',125, ...
    'DesignMethod','window','Window',@rectwin,'SampleRate',fs);
h = tf(d);
m = 1024;
y = fft(h,m);

f1 = 75;
f2 = 175;
w = exp(-j*2*pi*(f2-f1)/(m*fs));
a = exp(j*2*pi*f1/fs);
z = czt(h,m,w,a);
fn = (0:m-1)'/m;
fy = fs*fn;
fz = (f2-f1)*fn + f1;

plot(fy,abs(y),fz,abs(z))
xlim([50 200])
legend('FFT','CZT')
xlabel('Frequency (Hz)')

在这里插入图片描述

可以看出d是一个截止频率125/1000的低通滤波器,y是对其求1024点fft。
重点看后面czt。f1,f2即分析频率范围,w,a对应ppt中的W,A。
再回过头看要求,分析带宽和中心频率可得f1,f2。
采样率和工作时钟什么关系呢?
之前我以为采样率就是工作时钟。
现在需要重新梳理下采样过程(包括成型滤波和多速率滤波器)
毕设中成型滤波之前码片速率12M,然后经4倍成型滤波,相当于采样率48M,再经2倍半带上采样,相当于采样率96M。
我们来分析一下频谱变化:请添加图片描述
发射端采样率96M,工作时钟就得96M吗?不是的。工作时钟多少都行。采样率与工作时钟频率的关系:天空中信号传输速度与你处理信号的速度(即真实时间与处理时间的关系,一段1分钟的信号我可以1秒钟给运算掉得到运算结果)。所以采样率不一定等于系统时钟频率!!!当然相等也没问题。
例如本项目中系统时钟100M,采样率625K.

三、运算过程

请添加图片描述
首先明确工程输入输出

module czt(
    input clk_in,
    input rst_n,
    input signed [15:0]inputdata,  
    input czt_en,
    input [9:0] addr_din,
    input w_en,
    output wire signed [31:0]czt_ram_out,
    input [8:0] addr_cztout,
    output itr
    );

时钟复位不用多说;16位输入数据,有符号数就给他写个signed吧,用处就是在用*进行乘法运算时会进行有符号数的补位。(一般乘法ip会让选有符号数还是无符号数;复数乘法ip应该默认有符号数)
在这里插入图片描述
czt_en,高脉冲有效,控制何时进行czt变换,要确保在czt_en有效之前ram中数据装载完毕;且czt_en不可连续为高,因为进行czt变换需要时间。
写地址、写使能、输出czt变换结果、输入czt结果ram读地址;
itr指示信号,高脉冲有效,表明刺客ram中写好了,你可以读了。

外面进来的czt_en,工程方给不了单脉冲,需要我自己采一下上升沿生成单脉冲。

reg 	czt_en1_d;
always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin
		czt_en1_d<=1'b0;
	end 
	else begin
		czt_en1_d<=czt_en1;
	end 
end 

wire czt_en_100m;
assign czt_en_100m=czt_en1 &&(!czt_en1_d);

一些信号定义
关于信号的命名,这个以后得好好注意了,增强代码可读性。例如这样adr_cnu_wr, adr表示这个信号为地址线,cnu表明是哪个模块的,wr表明是写地址。延迟信号后面加_dly或_s,要用的信号前一拍信号加_temp,还有vld,suc,rdy,strt,flag_pipa,trig_sgl等可以用。
//常数定义

parameter M = 10'd512;  
parameter L = 11'd1024;  

//地址
reg [8:0] wndata_addr;


//数据
wire signed [15:0]inputdatareal_r;      
wire signed [15:0]wndatareal_r;  
wire signed [15:0]wndataimg_r; 

reg signed  [15:0]input_data;   
reg signed [15:0]wndatareal;  
reg signed [15:0]wndataimg;  



wire signed [15:0]hdatareal_r;  
wire signed [15:0]hdataimg_r;

wire signed [31:0]data_g_real;  
wire signed [31:0]data_g_img;     

ram读地址乒乓操作。写进来的数据是625k的数据,所以需要一个ram缓存下,这就是跨时钟域!!!终于遇到了。不过是dsp和fpga之间跨时钟域。数据写的太慢,我可以ram缓存一下。那乒乓操作又是为何呢?如果没有乒乓操作,读进来512个数据我得停一下,进行数据处理(czt变换),然后再读。所以要求输入数据有停顿,浪费时间不说,还得要求外部模块停一下这是不现实的,所以不行。乒乓后,可以处理A数据同时读进B数据。
这里是慢时钟域到快时钟域。
工程文件

module czt(
    input clk_in,
    input rst_n,
    input signed [15:0]inputdata,  
    input czt_en,
    input [9:0] addr_din,
    input w_en,
    output wire signed [31:0]czt_ram_out,
    input [8:0] addr_cztout,
    
    output itr
    );
    


reg 	czt_en_d;
always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin
		czt_en_d<=1'b0;
	end 
	else begin
		czt_en_d<=czt_en;
	end 
end 

wire czt_en_100m;
assign czt_en_100m=czt_en &&(!czt_en_d);

			
		



//数据
wire signed [15:0]inputdata_r;      
wire signed [15:0]wndatareal_r;  
wire signed [15:0]wndataimg_r; 
wire signed [15:0]hdatareal_r;  
wire signed [15:0]hdataimg_r;

  
    

 
reg [9:0]addr_din_rd;

always @ (posedge clk_in or negedge rst_n )begin
    if (!rst_n) begin
    	addr_din_rd<=10'b0;
    end 
    else if(czt_en_100m)begin
    	addr_din_rd<={
    
    !addr_din[9],9'b0};
    end  
    else if(addr_din_rd[8:0]==9'd511) begin
    	addr_din_rd[8:0]<=9'd511;
    end 
    else begin
    	addr_din_rd<=addr_din_rd+10'b1;	
    end 
end 

reg rstb;  
always @ (posedge clk_in or negedge rst_n )begin
    if (!rst_n) begin
    	rstb<=1'b0;
    end 
    else if(czt_en_100m)begin
    	rstb<=1'b0;
    end  
    else if(addr_din_rd[8:0]==9'd511) begin
    	rstb<=1'b1;
    end 
    else begin
    	rstb<=rstb;
    end 
end   
  
//计算din*wn
wire signed[31:0]xn_re,xn_im;
mul_g2 mul_g2 (   //delay 4
  .clk(clk_in),
  .ai(16'b0),
  .bi(wndataimg_r), 
  .ar(inputdata_r),
  .br(wndatareal_r),
  .pi(xn_im),
  .pr(xn_re)
);
 



//准备fft1信号  
wire [9:0] xn_index;
wire [9:0] xk_index;
wire signed[42:0] xk_re;
wire signed[42:0] xk_im;
	
reg[9:0] start1;
wire start;
assign start=start1[4] ;    //延迟1+1+4    start需要提前一个clk,所以共需要延迟5
 
always@(posedge clk_in or negedge rst_n)begin
  	if(!rst_n)begin
  		start1<=10'b0;
  	end 
  	else begin
  		start1<={
    
    start1[8:0],czt_en_100m};
  	end 
end 

wire fwd_inv,fwd_inv_we,fwd_inv_ifft;

reg fwd_inv_we1,fwd_inv_we1_r;
assign fwd_inv=1;
assign fwd_inv_ifft=0;
assign fwd_inv_we=(fwd_inv_we1 && !fwd_inv_we1_r);
always@(posedge clk_in or negedge rst_n)begin
  	if(!rst_n)begin
  		fwd_inv_we1<=1'b0;
  		fwd_inv_we1_r<=1'b0;
  	end 
  	else begin
  		fwd_inv_we1<=1'b1;
  		fwd_inv_we1_r<=fwd_inv_we1;
  	end 
end 




	fft1 fft4mul (
		.clk(clk_in), 
		.start(start), 
		.fwd_inv(fwd_inv), 
		.fwd_inv_we(fwd_inv_we), 
		.rfd(rfd), 
		.busy(busy), 
		.edone(edone), 
		.done(done), 
		.dv(dv), 
		.xn_re(xn_re), 
		.xn_im(xn_im), 
		.xn_index(xn_index), 
		.xk_index(xk_index), 
		.xk_re(xk_re), 
		.xk_im(xk_im)
	);



reg signed [42:0] xk_re_s,xk_im_s;
always@(posedge clk_in or negedge rst_n)begin
  	if(!rst_n)begin
  		xk_re_s<=0;
  		xk_im_s<=0;
  	end 
  	else begin
  		xk_re_s<=xk_re;
  		xk_im_s<=xk_im;
  	end
end 


wire signed [31:0]q_im,q_re;
mul2 mul2 (         //delay 8
  .clk(clk_in), 
  .ai(xk_im_s), 
  .bi(hdataimg_r), 
  .ar(xk_re_s), 
  .br(hdatareal_r), 
  .pi(q_im), 
  .pr(q_re)
);



    reg [9:0]start2;
    wire rfd2;
	wire busy2;
	wire edone2;
	wire done2;
	wire dv2;
	wire [9:0] xn_index2;
	wire [9:0] xk_index2;
	wire signed[42:0] xk_re2;
	wire signed[42:0] xk_im2;     

always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin
		start2<=10'b0;
	end 
	else begin
	    start2<={
    
    start2[8:0],edone};
    end 
end 


fft1 ifft (
		.clk(clk_in), 
		.start(start2[8]),                    //1+1+8-1=9
		.fwd_inv(fwd_inv_ifft), 
		.fwd_inv_we(fwd_inv_we), 
		.rfd(rfd2), 
		.busy(busy2), 
		.edone(edone2), 
		.done(done2), 
		.dv(dv2), 
		.xn_re(q_re), 
		.xn_im(q_im), 
		.xn_index(xn_index2), 
		.xk_index(xk_index2), 
		.xk_re(xk_re2), 
		.xk_im(xk_im2)
	); 


//最后乘以因子
reg signed [42:0]xk_re2_s,xk_im2_s;
always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin
		xk_re2_s<=0;
		xk_im2_s<=0;
	end 
	else begin
		xk_re2_s<=xk_re2;
		xk_im2_s<=xk_im2;
	end 
end 



wire  signed [31:0] czt_datareal_r,czt_dataimg_r;
//reg  signed [31:0] czt_datareal,czt_dataimg;
wire signed [15:0]hdatareal_r1,hdataimg_r1;
//wire  signed [59:0] czt_datareal_r1,czt_dataimg_r1;
mul_factor mul_factor (     //delay11
  .clk(clk_in), 
  .ai(xk_im2_s), 
  .bi(hdataimg_r1), 
  .ar(xk_re2_s), 
  .br(hdatareal_r1), 
  .pi(czt_dataimg_r), 
  .pr(czt_datareal_r)
);


//取模
wire signed [63:0] squ_re,squ_im;
squ squa (                  //delay 6
  .clk(clk_in), 
  .a(czt_datareal_r), 
  .b(czt_datareal_r), 
  .p(squ_re)
);

squ squb (
  .clk(clk_in), 
  .a(czt_dataimg_r), 
  .b(czt_dataimg_r), 
  .p(squ_im)
);


wire signed[31:0] squ_re_r,squ_im_r;
assign squ_re_r=squ_re[63:32];
assign squ_im_r=squ_im[63:32];
wire signed [32:0] aqu_sum;
assign aqu_sum=squ_re_r+squ_im_r;
wire signed[31:0]czt_data;
sqrt sqrt (             //delay 17
  .clk(clk_in), 
  .x_in(aqu_sum), 
  .x_out(czt_data)
);





reg [35:0] en_w;
always@(posedge clk_in or negedge rst_n)begin
  	if(!rst_n)begin
  		en_w<=36'b0;
  	end 
  	else begin
  		en_w<={en_w[34:0],edone2};
  	end 
end 
reg [8:0]addr_w_cztout;
 
always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin	
		addr_w_cztout<=9'b0;
	end 
	else if(en_w[34])begin       //1+1+11+6+17-1=35
		addr_w_cztout<=9'b0;
	end 
	else begin
		addr_w_cztout<=addr_w_cztout+1'b1;
	end 
end 


reg w_en_out;
always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin	
		w_en_out<=1'b0;
	end
	else if(en_w[34])begin
		w_en_out<=1'b1;
	end 
	else if(addr_w_cztout==9'd511)begin
		w_en_out<=1'b0;
	end
end 
reg w_en_out_d;
always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin	
		w_en_out_d<=1'b0;
	end
	else begin
		w_en_out_d<=w_en_out;
	end
end 
assign itr=!w_en_out &&w_en_out_d;





 
 
SDPRAM512X2_WRAP U_SDPRAM512X2_WRAP_A (
   .clka(clk_in),
	.wea(w_en),
	.addra(addr_din),
	.dina(inputdata),
	.clkb(clk_in),
	.rstb(rstb),
	.addrb(addr_din_rd),
	.doutb(inputdata_r)
); 


czt_out czt_out(
  .clka(clk_in),
  .wea(w_en_out),
  .addra(addr_w_cztout),
  .dina(czt_data),
  .clkb(clk_in),
  .addrb(addr_cztout),
  .doutb(czt_ram_out)
);
  


gen_wn_real gen_wn_real(
    .clka(clk_in),
    .addra(addr_din_rd[8:0]),
    .douta(wndatareal_r)
); 

gen_wn_imag gen_wn_imag(
    .clka(clk_in),
    .addra(addr_din_rd[8:0]),
    .douta(wndataimg_r)
); 


gen_h gen_h_real(
    .clka(clk_in),
    .addra(xk_index),
    .douta(hdatareal_r)
); 

gen_h_img gen_h_imag(
    .clka(clk_in),
    .addra(xk_index),
    .douta(hdataimg_r)
); 

wire [8:0]  addr_factor;
assign addr_factor=xk_index2[8:0];
gen_factor_real gen_factor_real(
    .clka(clk_in),
    .addra(addr_factor),
    .douta(hdatareal_r1)
); 

gen_factor_img gen_factor_img(
    .clka(clk_in),
    .addra(addr_factor),
    .douta(hdataimg_r1)
); 





  
endmodule

おすすめ

転載: blog.csdn.net/weixin_44884357/article/details/120622624