1 、要求
对线性调频信号,采样率100M,带宽80M,脉宽10us,进行距离压缩,精度为16
2、Matlab仿真
略
3、verilog实现
3.1 补零模块
module zero_fill #(
parameter WIDTH = 'd16,
parameter LENGTH='d2048
)(
input clk,
input rstn,
input signed [WIDTH-1:0] x_re,
input signed [WIDTH-1:0] x_im,
output signed [WIDTH-1:0] y_re,
output signed [WIDTH-1:0] y_im,
output working
);
reg signed [WIDTH-1:0] temp_re;
reg signed [WIDTH-1:0] temp_im;
reg [11:0] cnt;
reg ena;
reg flag;
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
temp_re<='d0;
temp_im<='d0;
end
else if(ena==1'b1)begin
if(flag==1)begin
temp_im<=0;
temp_re<=0;
end
else begin
temp_im<=x_im;
temp_re<=x_re;
end
end
else begin
temp_re<='d0;
temp_im<='d0;
end
end
always @(posedge clk,negedge rstn) begin//2048计数器
if(!rstn)begin
cnt<='d0;
end
else if(cnt<(LENGTH+1))begin//cnt范围0~2049
cnt<=cnt+1'b1;
end
else begin
cnt<=LENGTH+1;
end
end
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
ena<=1'b0;
end
else if(cnt<(LENGTH+1))begin
ena<=1'b1;
end
else if(cnt==(LENGTH+1))begin
ena<=1'b0;
end
end
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
flag<='d0;
end
else if(cnt==1000)begin
flag<=1'b1;
end
else if(cnt==(LENGTH+1))begin
flag<=1'b0;
end
end
assign y_im=temp_im;
assign y_re=temp_re;
assign working=ena;
endmodule
3.2 fft模块
module func_fft(
input aclk,
input aresetn,
input wire [23 : 0] s_axis_config_tdata,
input wire s_axis_config_tvalid,
output wire s_axis_config_tready,
input wire [31 : 0] s_axis_data_tdata,
input wire s_axis_data_tvalid,
output wire s_axis_data_tready,
input wire s_axis_data_tlast,
output wire [31 : 0] m_axis_data_tdata,
output wire [23 : 0] m_axis_data_tuser,
output wire m_axis_data_tvalid,
input wire m_axis_data_tready,
output wire m_axis_data_tlast,
input wire m_axis_status_tready,
output wire event_fft_overflow
);
wire event_frame_started;
wire event_tlast_unexpected;
wire event_tlast_missing;
wire event_status_channel_halt;
wire event_data_in_channel_halt;
wire event_data_out_channel_halt;
wire [7 : 0] m_axis_status_tdata;
fft fft2048 (
.aclk(aclk), // input wire aclk
.aresetn(aresetn), // input wire aresetn
.s_axis_config_tdata(s_axis_config_tdata), // input wire [23 : 0] s_axis_config_tdata
.s_axis_config_tvalid(s_axis_config_tvalid), // input wire s_axis_config_tvalid
.s_axis_config_tready(s_axis_config_tready), // output wire s_axis_config_tready
.s_axis_data_tdata(s_axis_data_tdata), // input wire [31 : 0] s_axis_data_tdata
.s_axis_data_tvalid(s_axis_data_tvalid), // input wire s_axis_data_tvalid
.s_axis_data_tready(s_axis_data_tready), // output wire s_axis_data_tready
.s_axis_data_tlast(s_axis_data_tlast), // input wire s_axis_data_tlast
.m_axis_data_tdata(m_axis_data_tdata), // output wire [31 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser), // output wire [23 : 0] m_axis_data_tuser
.m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tready(m_axis_data_tready), // input wire m_axis_data_tready
.m_axis_data_tlast(m_axis_data_tlast), // output wire m_axis_data_tlast
.m_axis_status_tdata(m_axis_status_tdata), // output wire [7 : 0] m_axis_status_tdata
.m_axis_status_tvalid(m_axis_status_tvalid), // output wire m_axis_status_tvalid
.m_axis_status_tready(m_axis_status_tready), // input wire m_axis_status_tready
.event_frame_started(event_frame_started), // output wire event_frame_started
.event_tlast_unexpected(event_tlast_unexpected), // output wire event_tlast_unexpected
.event_tlast_missing(event_tlast_missing), // output wire event_tlast_missing
.event_fft_overflow(event_fft_overflow), // output wire event_fft_overflow
.event_status_channel_halt(event_status_channel_halt), // output wire event_status_channel_halt
.event_data_in_channel_halt(event_data_in_channel_halt), // output wire event_data_in_channel_halt
.event_data_out_channel_halt(event_data_out_channel_halt) // output wire event_data_out_channel_halt
);
endmodule
3.3 复数乘法器模块
module multi #(
parameter WIDTH = 'd32,
parameter LENGTH = 'd2048
)(
input aclk,
input rstn,
input en,
input [31:0] s_axis_a_tdata,//[31:16]imag [15:0]real
input [31:0] s_axis_b_tdata,
output [79 : 0] m_axis_dout_tdata//[72:40]imag [32:0]real
);
wire m_axis_dout_tvalid;
com_mul multiplier (
.aclk(aclk), // input wire aclk
.s_axis_a_tvalid(en), // input wire s_axis_a_tvalid
.s_axis_a_tdata(s_axis_a_tdata), // input wire [31 : 0] s_axis_a_tdata
.s_axis_b_tvalid(en), // input wire s_axis_b_tvalid
.s_axis_b_tdata(s_axis_b_tdata), // input wire [31 : 0] s_axis_b_tdata
.m_axis_dout_tvalid(m_axis_dout_tvalid), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata(m_axis_dout_tdata) // output wire [79 : 0] m_axis_dout_tdata
);
endmodule
3.4 ifft模块
module func_ifft(
input aclk,
input aresetn,
input wire [23 : 0] s_axis_config_tdata,
input wire s_axis_config_tvalid,
output wire s_axis_config_tready,
input wire [79 : 0] s_axis_data_tdata,
input wire s_axis_data_tvalid,
output wire s_axis_data_tready,
input wire s_axis_data_tlast,
output wire [79 : 0] m_axis_data_tdata,
output wire [23 : 0] m_axis_data_tuser,
output wire m_axis_data_tvalid,
input wire m_axis_data_tready,
output wire m_axis_data_tlast,
output wire event_fft_overflow,
input wire m_axis_status_tready
);
wire event_frame_started;
wire event_tlast_unexpected;
wire event_tlast_missing;
wire event_status_channel_halt;
wire event_data_in_channel_halt;
wire event_data_out_channel_halt;
wire [7 : 0] m_axis_status_tdata;
ifft ifft2048 (
.aclk(aclk), // input wire aclk
.aresetn(aresetn), // input wire aresetn
.s_axis_config_tdata(s_axis_config_tdata), // input wire [23 : 0] s_axis_config_tdata
.s_axis_config_tvalid(s_axis_config_tvalid), // input wire s_axis_config_tvalid
.s_axis_config_tready(s_axis_config_tready), // output wire s_axis_config_tready
.s_axis_data_tdata(s_axis_data_tdata), // input wire [79 : 0] s_axis_data_tdata
.s_axis_data_tvalid(s_axis_data_tvalid), // input wire s_axis_data_tvalid
.s_axis_data_tready(s_axis_data_tready), // output wire s_axis_data_tready
.s_axis_data_tlast(s_axis_data_tlast), // input wire s_axis_data_tlast
.m_axis_data_tdata(m_axis_data_tdata), // output wire [79 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser), // output wire [23 : 0] m_axis_data_tuser
.m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tready(m_axis_data_tready), // input wire m_axis_data_tready
.m_axis_data_tlast(m_axis_data_tlast), // output wire m_axis_data_tlast
.m_axis_status_tdata(m_axis_status_tdata), // output wire [7 : 0] m_axis_status_tdata
.m_axis_status_tvalid(m_axis_status_tvalid), // output wire m_axis_status_tvalid
.m_axis_status_tready(m_axis_status_tready), // input wire m_axis_status_tready
.event_frame_started(event_frame_started), // output wire event_frame_started
.event_tlast_unexpected(event_tlast_unexpected), // output wire event_tlast_unexpected
.event_tlast_missing(event_tlast_missing), // output wire event_tlast_missing
.event_fft_overflow(event_fft_overflow), // output wire event_fft_overflow
.event_status_channel_halt(event_status_channel_halt), // output wire event_status_channel_halt
.event_data_in_channel_halt(event_data_in_channel_halt), // output wire event_data_in_channel_halt
.event_data_out_channel_halt(event_data_out_channel_halt) // output wire event_data_out_channel_halt
);
endmodule
3.5 tb_top
module tb_top(
);
parameter LENGTH='d2048;
parameter WIDTH='d16;
parameter PERIORD = 'd10;
parameter MUL_WIDTH='d32;
reg clk;
reg rstn;
reg aresetn;
reg [WIDTH-1:0] mem0_re[999:0];
reg [WIDTH-1:0] mem0_im[999:0];
always #(PERIORD/2) clk=~clk;
/例化补零模块//
initial begin
$readmemb("D:/vivado_projects/pra3_3/pra3_3.srcs/sources_1/new/input_re.txt",mem0_re);
$readmemb("D:/vivado_projects/pra3_3/pra3_3.srcs/sources_1/new/input_im.txt",mem0_im);
end
integer i,j,k;
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
i=-1;
end
else begin
i=i+1;
end
end
wire [WIDTH-1:0] x_im0;
wire [WIDTH-1:0] x_re0;
wire working;
zero_fill #(
.WIDTH(WIDTH),
.LENGTH(LENGTH)
)u_zero_fill(
.clk(clk),
.rstn(rstn),
.x_re(mem0_re[i]),
.x_im(mem0_im[i]),
.y_re(x_re0),
.y_im(x_im0),
.working(working)
);
//例化匹配滤波器fft
reg [23 : 0] s_axis_config_tdata_h;
reg s_axis_config_tvalid_h;
wire s_axis_config_tready_h;
reg [31 : 0] s_axis_data_tdata_h;
reg s_axis_data_tvalid_h;
wire s_axis_data_tready_h;
reg s_axis_data_tlast_h;
wire [31 : 0] m_axis_data_tdata_h;
wire [23 : 0] m_axis_data_tuser_h;
wire m_axis_data_tvalid_h;
reg m_axis_data_tready_h;
wire m_axis_data_tlast_h;
reg m_axis_status_tready_h;
wire event_fft_overflow_h;
//wire [31:0] temp_data={x_im0,x_re0};
reg [31:0] temp_data;
//因为延迟,从补零模块输出需要延迟一个周期
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
temp_data<=0;
end
else begin
temp_data<={x_im0,x_re0};
end
end
//assign s_axis_data_tdata_h={x_re0,x_im0};
func_fft fft_h(
.aclk(clk),
.aresetn(aresetn),
.s_axis_config_tdata(s_axis_config_tdata_h),
.s_axis_config_tvalid(s_axis_config_tvalid_h),
.s_axis_config_tready(s_axis_config_tready_h),
.s_axis_data_tdata(s_axis_data_tdata_h),
.s_axis_data_tvalid(s_axis_data_tvalid_h),
.s_axis_data_tready(s_axis_data_tready_h),
.s_axis_data_tlast(s_axis_data_tlast_h),
.m_axis_data_tdata(m_axis_data_tdata_h),
.m_axis_data_tuser(m_axis_data_tuser_h),
.m_axis_data_tvalid(m_axis_data_tvalid_h),
.m_axis_data_tready(m_axis_data_tready_h),
.m_axis_data_tlast(m_axis_data_tlast_h),
.m_axis_status_tready(m_axis_status_tready_h),
.event_fft_overflow(event_fft_overflow_h)
);
//原信号因fftip核特性,故需要将其虚部取负
wire signed[15:0]fft_im=m_axis_data_tdata_h[31:16];
wire signed[15:0]fft_re=m_axis_data_tdata_h[15:0];
wire signed[15:0]neg_o_x_im=0-fft_im;
integer fft_hand_re;
integer fft_hand_im;
initial begin
fft_hand_re=$fopen("D:/matlabfiles/fpga/fft_out_re.txt");
fft_hand_im=$fopen("D:/matlabfiles/fpga/fft_out_im.txt");
end
always @(posedge clk) begin
if(m_axis_data_tvalid_h==1)begin
$fdisplay(fft_hand_re,"%b",fft_re);
$fdisplay(fft_hand_im,"%b",fft_im);
end
if(m_axis_data_tlast_h==1)begin
$fclose(fft_hand_re);
$fclose(fft_hand_im);
end
end
//例化复数乘法器
wire en_mul=m_axis_data_tvalid_h;
wire [MUL_WIDTH-1:0] s_axis_a_tdata_o={neg_o_x_im,fft_re};
wire [MUL_WIDTH-1:0] s_axis_b_tdata_h={fft_im,fft_re};
wire [79:0] m_axis_dout_tdata;
multi #(
.WIDTH(MUL_WIDTH),
.LENGTH(LENGTH)
)u_mul(
.aclk(clk),
.rstn(rstn),
.en(en_mul),
.s_axis_a_tdata(s_axis_a_tdata_o),
.s_axis_b_tdata(s_axis_b_tdata_h),
.m_axis_dout_tdata(m_axis_dout_tdata)
);
//例化ifft
reg [23 : 0] s_axis_config_tdata_i;
reg s_axis_config_tvalid_i;
wire s_axis_config_tready_i;
wire [79 : 0] s_axis_data_tdata_i;
wire s_axis_data_tvalid_i;
wire s_axis_data_tready_i;
reg s_axis_data_tlast_i;
wire [79 : 0] m_axis_data_tdata_i;
wire [23 : 0] m_axis_data_tuser_i;
wire m_axis_data_tvalid_i;
reg m_axis_data_tready_i;
wire m_axis_data_tlast_i;
reg m_axis_status_tready_i;
wire event_fft_overflow_i;
func_ifft u_ifft (
.aclk(clk), // input wire aclk
.aresetn(aresetn), // input wire aresetn
.s_axis_config_tdata(s_axis_config_tdata_i), // input wire [7 : 0] s_axis_config_tdata
.s_axis_config_tvalid(s_axis_config_tvalid_i), // input wire s_axis_config_tvalid
.s_axis_config_tready(s_axis_config_tready_i), // output wire s_axis_config_tready
.s_axis_data_tdata(s_axis_data_tdata_i), // input wire [79 : 0] s_axis_data_tdata
.s_axis_data_tvalid(s_axis_data_tvalid_i), // input wire s_axis_data_tvalid
.s_axis_data_tready(s_axis_data_tready_i), // output wire s_axis_data_tready
.s_axis_data_tlast(s_axis_data_tlast_i), // input wire s_axis_data_tlast
.m_axis_data_tdata(m_axis_data_tdata_i), // output wire [95 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser_i), // output wire [15 : 0] m_axis_data_tuser
.m_axis_data_tvalid(m_axis_data_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready(m_axis_data_tready_i), // input wire m_axis_data_tready
.m_axis_data_tlast(m_axis_data_tlast_i), // output wire m_axis_data_tlast
.m_axis_status_tready(m_axis_status_tready_i),
.event_fft_overflow(event_fft_overflow_i)
);
initial begin
clk=0;
aresetn=0;
rstn=0;
s_axis_config_tdata_h=8'b0;
s_axis_config_tdata_i=8'b0;
s_axis_config_tvalid_h=0;
s_axis_config_tvalid_i=0;
s_axis_data_tvalid_h=0;
s_axis_data_tdata_h=0;
s_axis_data_tlast_h=0;
m_axis_data_tready_h=0;
m_axis_data_tready_i=0;
i=0;
j=0;
k=0;
#40;
aresetn=1;
rstn=1;
m_axis_data_tready_h=1;
m_axis_data_tready_i=1;
s_axis_config_tvalid_h=1;
s_axis_config_tvalid_i=1;
s_axis_config_tdata_h=23'b00_0000_0010_0010_0000_0000_1;
s_axis_config_tdata_i=23'b00_0000_0010_0010_0000_1000_0;
m_axis_status_tready_i=1;
m_axis_status_tready_h=1;
//#80000;
//s_axis_config_tvalid_h=0;
//aresetn=0;
end
匹配滤波器时序
//working需要打两拍
reg working_delay1;
reg working_delay2;
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
working_delay1<=0;
working_delay2<=0;
end
else begin
working_delay1<=working;
working_delay2<=working_delay1;
end
end
always @(posedge clk,negedge rstn) begin
if((s_axis_data_tready_h==1)&&(working_delay2))begin
s_axis_data_tvalid_h<=1;
s_axis_data_tdata_h<=temp_data;
s_axis_data_tlast_h<=0;
end
else begin
s_axis_data_tvalid_h<=0;
s_axis_data_tlast_h<=1;
end
end
ifft时序
reg en_ifft;
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
en_ifft<=0;
end
else begin
en_ifft<=en_mul;
end
end
assign s_axis_data_tvalid_i=en_ifft;
always @(posedge clk,negedge rstn) begin
if(s_axis_data_tready_i&&m_axis_data_tvalid_h)begin
j=j+1;
s_axis_data_tlast_i<=0;;
if(j==2047)begin
s_axis_data_tlast_i<=1;
end
end
else begin
j=0;
s_axis_data_tlast_i<=1;
end
end
reg [79:0] a;
reg [79:0] b;
wire signed[33:0]temp_i1=m_axis_dout_tdata[72:40];
wire signed[33:0]temp_i2=m_axis_dout_tdata[32:0];
always @(posedge clk,negedge rstn) begin
if(!rstn)begin
a<=0;
b<=0;
end
else begin
a<={7'd0,temp_i1,7'd0,temp_i2};
b<=a;
end
end
assign s_axis_data_tdata_i=b;
/存储最终结果
wire signed[32:0] final_re;
wire signed[32:0] final_im;
assign final_re=m_axis_data_tdata_i[32:0];
assign final_im=m_axis_data_tdata_i[72:40];
integer handle_re;
integer handle_im;
initial begin
handle_re=$fopen("D:/matlabfiles/fpga/output_re.txt");
handle_im=$fopen("D:/matlabfiles/fpga/output_im.txt");
end
always @(posedge clk) begin
if(m_axis_data_tvalid_i==1)begin
$fdisplay(handle_re,"%b",final_re);
$fdisplay(handle_im,"%b",final_im);
end
if(m_axis_data_tlast_i==1)begin
$fclose(handle_re);
$fclose(handle_im);
end
end
endmodule
4、结果输出
仿真采用100MHz时钟,fft加ifft耗时约300us。仿真时将仿真时间设置为350us即可。
上图为fft后输出存储结果,可见精度有损失,当然也跟我输出时候数据设置有些问题。
5、总结
对fft ip核 的一次使用练习,熟悉各个接口和时序。