目标反射回波检测算法及其FPGA实现之三:
平方、积分电路及算法的顶层实现
前段时间,接触了一个声呐目标反射回波检测的项目。声呐接收机要实现的核心功能是在含有大量噪声的反射回波中,识别出发射机发出的激励信号的回波。我会分几篇文章分享这个基于FPGA的回波识别算法的开发过程和原码,欢迎大家不吝赐教。以下原创内容欢迎网友转载,但请注明出处: https://www.cnblogs.com/helesheng。
在本系列博文的第一篇中,根据仿真结果,我认为采用“反射回波和激励信号互相关”的结果来计算目标距离的方法具有较高性能和计算效率。在本系列的第二篇博文中,我在Cyclone系列的低成本FPGA中采用半并行的“双存储器式的卷积节”结构实现了数据的互相关/卷积/FIR滤波器计算。作为本系列的第三篇博文,我将实现互相关信号的平方和积分计算,并将所有算法在顶层文件中结合为一个整体。
从而通过寻找 的极值点所在位置来确定目标反射回波出现的时间点。
(1)式中的是互相关算法部分,其FPGA实现已在前文中介绍过。根据前文定义的符号,将离散化后的互相关信号记为R[k]。进一步离散化后可将(1)改写为如下FPGA能够实现的形式:
一、平方电路的实现
使用Quartus-II中的MegaWizard配置平方计算电路,其结构如下图所示。
图1 平方电路配置
二、积分电路设计
根据(2)式,要计算目标函数P[n]的值,还需要对历史上的 值求和(积分)。我们当然可以用缓冲器存储历史上的k0个 值,并在每次结果输出之前对缓冲器中的k0个值求和。如果让k0等于激励信号的长度N,则每次输出P[n]之前都需要计算N-1个加法。当N为64时(如前文所述),这几乎是不可完成的任务。我设计了下图所示的电路结构来实现64个历史数据的求和。
图2 积分器电路结构
其中一位深度为64的移位寄存器的作用是提供64个采样之前的“历史数据”。首先对当前数据和最老的历史数据求差(补码),再对差不断求和。这样根据加法交换律,最终求和结果就相当于加入了当前数据,减去了最老的历史数据。只要移位寄存器的初值全为0,在进行了64次操作后,从输出得到的就是64个历史数据的和(积分)了。其中用MegaWizard配置的移位寄存器结构如下图所示。
图3 移位寄存器的结构
前级减法器的结构如下图所示。
图4 减法器的结构
累加器采用硬件描述语言实现,代码如下。
1 always @ (posedge start or negedge rst_n) 2 begin 3 if(!rst_n) 4 acc_out[39:0] <= 40'd0; 5 else begin 6 acc_out[39:0] = $signed(acc_out[39:0]) + $signed(acc_in[31:0]); 7 end 8 end
其中的关键字$signed表示有符号数的加法器。
三、算法的顶层设计
为了将前述的A/D和D/A口控制电路、互相关/卷积/FIR滤波电路、平方和积分电路连接为一个系统,还需要在顶层设计文件中对上述模块电路进行例化和连接。另外顶层设计文件还将对系统的整体工作时序进行控制。我设计的顶层文件如下所示。
1 module CONV_POW_AD_DA( 2 ///////////顶层模块,负责调用ADC采集数据,卷积,然后用DAC输出卷积/FIR的结果///////// 3 input rst_n,//低电平复位信号 4 input iclk20,//外部晶体输入的20MHz 5 output sck_da,//D/A转换器的SPI时钟 6 output mosi_da,//D/A转换器的SPI数据信号 7 output cs_da,//D/A转换器的片选信号 8 output ld_da,//D/A转换器的双通道数据加载信号 9 output sck_ad,//A/D转换器的SPI时钟 10 output mosi_ad,//A/D转换器的SPI数据输出 11 input miso_ad,////A/D转换器的SPI数据输入 12 output cs_ad//A/D转换器的SPI口片选信号 13 ); 14 wire clk; 15 reg start; 16 reg[15:0] cnt;//用于产生总体周期的计时器 17 reg[11:0] tst_data;//用于产生测试数据的计数器 18 parameter CNT_NUM = 16'd2000;//100M时钟下,2000分频意味着50KHz溢出率 19 wire[11:0] ad_data;//AD转换结果的内部连线 20 wire[11:0] data_cha;//A通道数据 21 wire[11:0] data_chb;//B通道数据 22 wire[15:0] shft_data1;//在卷积的两个节之间传递的数据 23 wire[15:0] shft_data2;//在卷积的两个节之间传递的数据 24 wire[15:0] shft_data3;//在卷积的两个节之间传递的数据 25 wire[15:0] shft_data4;//在卷积的两个节之间传递的数据 26 wire[39:0] conv_res1;//第一节的卷积的结果 27 wire[39:0] conv_res2;//第2节的卷积的结果 28 wire[39:0] conv_res3;//第3节的卷积的结果 29 wire[39:0] conv_res4;//第4节的卷积的结果 30 wire[39:0] conv_res;//总的卷积的结果 31 wire[33:0] acc_sum;//最后计算每一节的累加和的结果 32 wire[31:0] shiftout;//移位寄存器的移出数据 33 wire[15:0] ac_sig;//去除直流偏置后的交流信号 34 wire[31:0] pow_sig;//信号的能量 35 wire signed[31:0] acc_in;//求和累加器的输入,也是加法/减法器的输出 36 reg signed[39:0] acc_out;//累加器输出的结果 37 wire signed[19:0] data_out;//累加结果开方后的输出 38 39 //assign data_cha[11:0] = acc_out[25:14];//通道a输出64个点能量累加结果 40 //assign data_cha[11:0] = shiftout[18:7];//通道a输出的数据 41 assign data_cha[11:0] = pow_sig[19:8];//通道a输出交流信号的平方 42 //assign data_cha[11:0] = ad_data[11:0];//通道a输出的数据 43 //assign data_cha[11:0] = shft_data