基于FPGA线性调频信号LFM的产生

本文用了DDS来产生LFM信号,DDS的原理可以查看赛灵思的官方文档,这里不做赘述,同时对于LFM信号也不做赘述,直接上工程实现及其方法。

首先,我们要确定脉宽和PRI,在这里脉宽选取10us,PRI选取200us(fpga内部时钟用来100MHz),所以使用计数器去实现这两个信号的计数,当计数器计数到一定值的时候,使用使能信号来反应该计数状态,根据使能信号和成脉冲门信号,在脉冲门信号里面对DDS进行频率的步进,达到最后的输出效果。

DDS配置如下:

 

 其余保持默认配置

`timescale 1ns / 1ps
//
// Company: xidian
// Engineer: CC
// 
// Create Date: 2023/04/29 20:03:54
// Design Name: 
// Module Name: lfm_gen
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module  lfm_gen
#(
    parameter   CNT_TAO_MAX = 10'd999,
	parameter   CNT_PRI_MAX = 15'd19_999     //实际pri=(19999+1)*10ns*2=400us
)
(
    input    wire  sys_clk,
    input    wire  sys_rst_n,

//    output   wire  meng,
//    output   wire  [31:0]data,
//	output   wire  [15:0]sin_imag,
//	output   wire  [15:0]cos_real,
    output   wire  wr_en,
	output   wire  [13:0]data_out,
	output   wire  clk_125M
);

reg    pri_en;
reg    tao_en;

reg     cnt_ctrl1;  //脉宽前沿检测
reg     cnt_ctrl2;  //脉宽后沿检测
reg     cnt_ctrl3;  //PRI后沿检测

reg     [9:0]cnt_tao;
reg     [14:0]cnt_pri;

reg     [7:0]tao_reg;  //一个周期内对脉宽的计数

reg     freq_en;

reg     [31:0]dds_pinc_in;
reg     [31:0]dds_poff_in;

wire    [63:0]s_axis_phase_tdata;

parameter   FREQ_START = 32'd858_993_460;  //起始频率为20MHz
parameter   FREQ_STEP = 32'd214_749;       //步进频率为5KHz

wire   [31:0] data;
wire   meng;
wire  [15:0]sin_imag;
wire  [15:0]cos_real;
wire  [13:0]data_reg;

//pri计数器,产生对应时间的脉冲间隔
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        cnt_pri <= 15'b0;
	else if (cnt_pri == CNT_PRI_MAX)
	    cnt_pri <= 15'b0;
	else
	    cnt_pri <= cnt_pri + 1'b1;

//脉冲前沿信号产生
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        cnt_ctrl1 <= 1'b0;
	else if (cnt_pri == CNT_PRI_MAX && tao_reg == 8'b0 ) 
	    cnt_ctrl1 <= 1'b1;
	else 
	    cnt_ctrl1 <= 1'b0;

//脉冲后沿信号产生
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        cnt_ctrl2 <= 1'b0;
	else if (tao_reg == 8'b0 && cnt_tao == CNT_TAO_MAX)
	    cnt_ctrl2 <= 1'b1;
	else
	    cnt_ctrl2 <= 1'b0;

//PRI后沿检测
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        cnt_ctrl3 <= 1'b0;
	else if (cnt_pri == CNT_PRI_MAX && pri_en == 1'b0)
	    cnt_ctrl3 <= 1'b1;
	else 
	    cnt_ctrl3 <= 1'b0;

//tao计数器,产生对应时间的脉宽
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        cnt_tao <= 10'b0;
	else if (pri_en == 1'b1) 
	    cnt_tao <= cnt_tao + 1'b1;
	else if (cnt_ctrl2 == 1'b1)  //cnt_tao == CNT_TAO_MAX && tao_reg == 8'b1
	    cnt_tao <= 10'b0;
	else if (pri_en == 1'b0)
	    cnt_tao <= 10'b0;

//pri使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        pri_en <= 1'b0;
	else if (cnt_ctrl1 == 1'b1) 
	    pri_en <= 1'b1;
	else if (tao_reg == ((CNT_PRI_MAX + 1'b1)/(CNT_TAO_MAX + 1'b1)) - 1'b1) 
	    pri_en <= 1'b0;
	else 
	    pri_en <= pri_en;

//tao使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        tao_en <= 1'b0;
	else if (cnt_ctrl1 == 1'b1)
	    tao_en <= 1'b1;
	else if (cnt_ctrl2 == 1'b1)
	    tao_en <= 1'b0;
	else 
	    tao_en <= tao_en;

//一个周期内对脉宽的计数
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        tao_reg <= 8'b0;
	else if (pri_en == 1'b1 && cnt_tao == CNT_TAO_MAX)
	    tao_reg <= tao_reg + 1'b1;
	else if (tao_reg == ((CNT_PRI_MAX + 1'b1)/(CNT_TAO_MAX + 1'b1)) - 1'b1)
	    tao_reg <= 8'b0;

//脉冲门信号合成
assign meng = tao_en;

//频率控制字使能
always@(posedge sys_clk or negedge sys_rst_n)
    if (sys_rst_n == 1'b0)
        freq_en <= 1'b0;
	else if (cnt_ctrl1 == 1'b1)
	    freq_en <= 1'b1;
	else if (cnt_tao == CNT_TAO_MAX/2)
	    freq_en <= 1'b0;
	else 
	    freq_en <= freq_en;

//频率控制字产生
//always @(posedge sys_clk or posedge sys_rst_n) //正在TAO内累加,在TAO外面清除
//    if(sys_rst_n == 1'b0) 
//	    begin
//            dds_pinc_in <= FREQ_START;
//            dds_poff_in <= 32'b0;   
//        end 
//    else if(freq_en == 1'b1 && tao_en == 1'b1) 
//	    begin
//            dds_pinc_in <= dds_pinc_in - (FREQ_STEP/2);//hband_phase + (step_phase/2)  
//            dds_poff_in <= 32'b0000_0000;//init_phase   
//        end 
//    else if(freq_en == 1'b0 && tao_en == 1'b1) 
//	    begin
//            dds_pinc_in <= dds_pinc_in - (FREQ_STEP/2);//dds_pinc_in + step_phase(10,976,027) 159,243,070,680 4,294,967,296
//            dds_poff_in <= 32'b0000_0000;//init_phase    
//        end 
//	else 
//	    begin
//            dds_pinc_in <= FREQ_START;//32'b0;
//            dds_poff_in <= 32'b0;            
//        end

always @(posedge sys_clk or posedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
	    begin
            dds_pinc_in <= FREQ_START;
            dds_poff_in <= 32'b0; 
        end
    else if(tao_en == 1'b1) 
	    begin
            dds_pinc_in <= dds_pinc_in - (FREQ_STEP/2);//hband_phase + (step_phase/2)  
            dds_poff_in <= 32'b0000_0000;//init_phase   
        end 
	else 
	    begin
            dds_pinc_in <= FREQ_START;
            dds_poff_in <= 32'b0;            
        end



assign s_axis_phase_tdata={dds_poff_in[31:0],dds_pinc_in[31:0]}; 

//雷达信号产生
dds dds_inst (
  .aclk(sys_clk),                                // input wire aclk
  .aclken(tao_en),                            // input wire aclken
  .s_axis_phase_tvalid(tao_en),  // input wire s_axis_phase_tvalid
  .s_axis_phase_tdata(s_axis_phase_tdata),    // input wire [63 : 0] s_axis_phase_tdata
  .m_axis_data_tvalid(),    // output wire m_axis_data_tvalid
  .m_axis_data_tdata(data),      // output wire [15 : 0] m_axis_data_tdata
  .m_axis_phase_tvalid(),  // output wire m_axis_phase_tvalid
  .m_axis_phase_tdata()    // output wire [31 : 0] m_axis_phase_tdata
);

  clk clk_inst
   (
    // Clock out ports
    .clk_out1(clk_125M),     // output clk_out1
    // Status and control signals
    .reset(~sys_rst_n), // input reset
    .locked(),       // output locked
   // Clock in ports
    .clk_in1(sys_clk));      // input clk_in1

assign sin_imag = data[31:16];
assign cos_real = data[15:0];
assign data_reg = data[31:18];
assign data_out = data_reg + 8192;
assign wr_en = clk_125M;

ila_0 ila_inst (
	.clk(sys_clk), // input wire clk


	.probe0(data_out) // input wire [13:0] probe0
);

endmodule

其中代码中例化的ila和clk是为了上板,才例化的(可以根据自己的板子修改)

仿真代码如下:

`timescale 1ns / 1ps
//
// Company: xidian
// Engineer: CC
// 
// Create Date: 2023/04/29 20:37:23
// Design Name: 
// Module Name: tb_lfm_gen
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_lfm_gen();

reg    sys_clk;
reg    sys_rst_n;

//wire   meng;
//wire   [31:0]data;
//wire   [15:0]sin_imag;
//wire   [15:0]cos_real;
wire   [13:0]data_out;
wire   clk_125M;
wire   wr_en;

initial
    begin
	    sys_clk = 1'b0;
	    sys_rst_n = 1'b0;
	    #20 
	    sys_rst_n = 1'b1;
	end

always #5 sys_clk = ~sys_clk;

lfm_gen
#(
    .CNT_TAO_MAX (10'd999),
	.CNT_PRI_MAX (15'd19_999)
)
lfm_gen_inst
(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),

//    .meng(meng),
//    .data(data),
//	.sin_imag(sin_imag),
//	.cos_real(cos_real),
    .wr_en(wr_en),
    .clk_125M(clk_125M),
	.data_out(data_out)
);

endmodule

仿真图

 (注意:输出的data_out是无符号数,在最后输出到板子上的时候要将有符号数转换成无符号数)

 信号说明:

clk_125M是板子上DAC的采样时钟

wr_en是DAC的写入使能

data_out是fpga给DAC的信号

pri_en在一个pri周期内会拉高,但是由于下一个pri周期会和上一个pri周期是连续的,会影响下一个脉冲前沿的赋值,所以这里了pri_en不是正真意义上的一个pri周期,在上一个pri周期快要结束的时候要提前拉低,这里就用到了tao_reg计数器,tao_reg = pri / tao。

tao_en在脉冲出现的地方拉高。

cnt_ctrl1脉冲前沿信号

cnt_ctrl2脉冲后沿信号

cnt_ctrl3 pri周期开始信号及其结束信号

cnt_tao脉宽计数器

cnt_pri pri计数器

tao_reg pri的时间和tao时间的比值

dds_pinc_in相位增加量的计算信号

dds_poff_in相位偏移量的计算

data dds输出的数据

 

 从上图我们可以看出已近产生了对应的脉宽和pri

由于加入了tao_ref计数器,所以可以灵活的修改你想要的脉宽和pri参数

 上图就是改变pri为100us时候的结果。

下面介绍频率控制字的计算:

 

上式是对于调谐率的计算,因为条斜率决定了频率变换的快慢。

 带宽是10M,从20M变换到10M,Fbase是开始频率,detaF是变化频率,所以 Fout输出频率就是开始频率加变化频率(计算公式在赛灵思的官方手册中有说明)

硬件实现(zynq7010 + an9767)

 

 

  • 9
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值