声呐直线阵正交混频实验(HEU信息与信号处理创新实践项目一)

写在前面

这个实验原要求是要实现 96 96 96 通道的正交混频变换(后来老师说只要不是单通道都行),因此必须使用 F I R FIR FIR IP核(手搓FIR一两个通道还行,96通道就太费劲了),所以实验成功的关键就是要确保你的Quartus能够正常的生成 FIR IP核。在所有的破解版中本人实测Quartus 18.0 Prime Standard是唯一能够正常生成IP核不会卡死或生成失败的。Quartus 13.0、Quartus 15.0和Quartus 20.0的破解版均无法正常生成(Quartus 20.0的问题是很多IP核没有密钥授权)。
本实验由于是期末周做的,来不及换Quartus完成了,所以是手搓FIR实现的,仅供参考。

相关参数(实际)

  • 直线阵通道数: 2 2 2
  • 信号载波频率: 100 k H z 100kHz 100kHz
  • 采样率: 400 k H z 400kHz 400kHz
  • 低通 F I R FIR FIR 阶数: 15 15 15
  • 低通滤波器截止频率: 20 k H z 20kHz 20kHz

实验原理

正交混频原理图
​ 由于载波频率与采样频率满足 1 : 4 1:4 1:4 的关系,因此,对于 c o s w t coswt coswt 通道,采样点按照以 4 4 4 为周期分别与 { 1 , 0 , − 1 , 0 1,0,-1,0 1010} 相乘;对于 − s i n w t -sinwt sinwt 通道,则为 { 0 , − 1 , 0 , 1 0,-1,0,1 0,1,0,1} 相乘,通过观察可以发现,两个通道相加的结果实际上跟一个开关电路差不多,即二选一其中一个通道的输出结果,因此对已调信号再进行混频解调信号时,等价于已调信号采样点与{ 1 , 0 , 1 , 0 1,0,1,0 1,0,1,0} 和{ 0 , 1 , 0 , 1 0,1,0,1 0,1,0,1}相乘,也就是 s ( t ) s(t) s(t) 与 { 1 , 0 , 1 , 0 1,0,1,0 1,0,1,0} 和{ 0 , 1 , 0 , 1 0,1,0,1 0,1,0,1}相乘。

实验过程

1.测试信号生成

​ 按照实验要求,测试信号格式应当为:第一通道第一时刻采样点、第二通道第一时刻采样点、第一通道第二时刻采样点、第二通道第二时刻采样点 ⋯ \cdots 这种格式生成。实验中输入的已调信号利用 s i n _ g e n e r a t i o n . c p p sin\_generation.cpp sin_generation.cpp 生成,生成文件为 d a t a s e t . v h dataset.vh dataset.vh。通道波形参数定义如下:

通道一:基带信号为 10 k H z 10kHz 10kHz 正弦信号,相位为 0 0 0

通道二:基带信号为 10 k H z 10kHz 10kHz 正弦信号,相位为 π 2 \frac{\pi}{2} 2π

​ 各通道信号长度均为 2048 2048 2048,量化精度为 8 b i t 8bit 8bit

sin_generation.cpp

#include<bits/stdc++.h>
#define pi 3.1415926
using namespace std;
int main(){
	float t=0;
	int f1=10000;
	int f2=10000;
	int f=100000;
	float fs=400000;
	float tmp;
	freopen("dataset.vh","w",stdout);
/*	for (int i=0; i<114514; i++){
		t=(float)i/fs;
		tmp=sin(2*pi*f1*t)+sin(2*pi*f2*t);
		tmp=tmp*4096;
		cout<<(int)tmp<<','<<endl;
	}*/
	for (int i=0; i<2048; i++)
	{
		t=i/fs;
		for (int j=0; j<2; j++){
			if (j==0)
				tmp=sin(2*pi*f1*t);//*cos(2*pi*f*t)-sin(2*pi*f1*t)*sin(2*pi*f*t);
			else
				tmp=sin(2*pi*f2*t+pi/2.0);//*cos(2*pi*f*t)-sin(2*pi*f2*t+pi/2.0)*sin(2*pi*f*t);
			tmp=tmp*256;
			if (i==2047 && j==1)
				cout<<(int)tmp;
			else
				cout<<(int)tmp<<','<<endl;
		}
	}
	fclose(stdout);
	return 0;
}

2.测试平台(fir_test_tb.sv)

​ 测试平台主要包括 t i m e s c a l e timescale timescale 描述、输入输出信号定义,时钟初值设定, . v h .vh .vh 采样文件读取。完整文件见 f i r _ t e s t _ t b . s v fir\_test\_tb.sv fir_test_tb.sv

输入输出信号定义

reg clk; //系统工作主频时钟
reg clk_400khz; //400khz采样时钟
reg rst_n; //复位信号线
wire [15:0] xin; //文件采样数据读入
wire read_en;  //文件读入使能信号
	
wire signed [36:0] yout_ch1_real;   //通道一实部解调信号FIR输出
wire signed [36:0] yout_ch1_imag;   //通道一虚部解调信号FIR输出
wire signed [36:0] yout_ch2_real;   //通道二实部解调信号FIR输出
wire signed [36:0] yout_ch2_imag;   //通道二虚部解调信号FIR输出

时钟初值与频率设定

initial begin
	clk=0;
	clk_400khz=0;
	#0ns rst_n=0; //reset
	#1400ns rst_n=1; //normal
	$display("Running testbench");  
end

//define of testbench's timescale
always #10 	 clk=~clk; //50Mhz
always #1250 clk_400khz=~clk_400khz; //400kHz

模块参数传递

//parameters transmission
fir_test u0_fir(
    .clk	(clk),	//模块工作主时钟
    .clk_400khz (clk_400khz), //400khz采样时钟
    .rst_n		(rst_n), //复位信号,用于data_to_file.sv
    .xin		(xin), //输入采样点信号
    .read_en (read_en), //文件读入使能
    .yout_ch1_real (yout_ch1_real), //通道一实部FIR输出
    .yout_ch1_imag (yout_ch1_imag), //通道一虚部FIR输出
    .yout_ch2_real (yout_ch2_real), //通道二实部FIR输出
    .yout_ch2_imag	(yout_ch2_imag) //通道二虚部FIR输出
);

dataset.vh波形采样文件读取

//read .vh file

reg signed [15:0] ad_data[4096] = {`include "dataset.vh"};	
reg [11:0] k = 0;
reg signed [15:0] data = 0;
reg [2:0] kk=0;

always @(negedge clk)
	begin
        if (read_en) begin //使能数据读入
			//kk=kk+1;
			if (k<=4096 && kk<2) //3
				begin
					k<=k+1; //读一个新的采样数据
					data<=ad_data[k];
					kk<=kk+1; 
				end
		end
		else begin
			kk<=0;
			data<=0;
		end
		
	end
	
assign xin=data;

自定义主逻辑模块(fir_test.sv)

​ 自定义模块共由四个部分组成:

  • d a t a _ r e a d _ p r e p a r a t i o n data\_read\_preparation data_read_preparation:数据读入。
  • Q u a d r a t u r e   M o d u l a t i o n & D e m o d u l a t i o n Quadrature\ Modulation\&Demodulation Quadrature Modulation&Demodulation:正交调制与解调,将输入信号分别与 c o s w t coswt coswt − s i n w t -sinwt sinwt 混频(两次),得到解调波形。
  • P a r a l l e l   15 − o r d e r   F I R   f o r   2   C h a n n e l s Parallel\ 15-order\ FIR\ for\ 2\ Channels Parallel 15order FIR for 2 Channels:并行十五阶双通道 F I R FIR FIR 低通滤波器。
  • d a t a _ t o _ f i l e : data\_to\_file: data_to_file: M o d e l S i m ModelSim ModelSim 波形数据导出模块。

各模块时序逻辑如下:

data_read_preparation

​ 以主时钟 c l k clk clk 信号读入测试平台中的 . v h .vh .vh 文件数据,但要以 400 k h z 400khz 400khz 采样速度读取该数据,留出空闲的大量 c l k clk clk 时钟周期的目的是给未来其他的扩展操作留下足够空间。以下是处理一个各通道一个采样点的时序(读->完成正交变换->FIR低通滤波的)。
数据读入时序,一个50Mhz时钟周期完成新数据的读入
​ 新数据点的处理在 c l k _ 400 k h z clk\_400khz clk_400khz 下降沿到达时开始处理,因此首先需要捕获 c l k _ 400 k h z clk\_400khz clk_400khz 下降沿信号再拉高 r e a d _ e n read\_en read_en 使能新数据的读取。 d a t a _ c h _ r e a l data\_ch\_real data_ch_real d a t a _ c h _ i m a g data\_ch\_imag data_ch_imag 信号为正交变换处理后的信号(未经过滤波),下降沿捕获的逻辑代码如下所示:

assign negedge_of_clk_400khz=~clk_400khz_a0&clk_400khz_a1;
always @ (posedge clk)
	begin
		clk_400khz_a0<=clk_400khz;
		clk_400khz_a1<=clk_400khz_a0;
	end

​ 通道指针 s t e p step step 的迭代比测试文件更新慢半个 c l k clk clk 时钟的好处是可以确保 x i n xin xin 的数据一定能被正确读到。

Quadrature Modulation&Demodulation

​ 载波频率与采样频率满足 1 : 4 1:4 1:4 的关系,因此 c o s w t coswt coswt 变换可以等价为每个 c l k _ 400 k h z clk\_400khz clk_400khz 时钟读到的信号与 { 1 , 0 , − 1 , 1 1,0,-1,1 1,0,1,1} 相乘,对于 − s i n w t -sinwt sinwt 可以等价为与 { 0 , − 1 , 0 , 1 0,-1,0,1 0,1,0,1} 相乘。正交变换的逻辑代码较长,请见 f i r _ t e s t . s v fir\_test.sv fir_test.sv。变换后各通道 M o d e l S i m ModelSim ModelSim 波形如下所示。
正交混频后的实虚部波形

Parallel 15-order FIR for 2 Channels

​ 由于我电脑的 Q u a r t u s Quartus Quartus 版本问题, F I R   I P FIR\ IP FIR IP 核一直无法自动生成成功,因此实验中使用的是自己用 V e r i l o g Verilog Verilog 写的 F I R FIR FIR 。考虑到时序资源的利用率以及未来可能的多通道处理,因此 F I R FIR FIR 滤波器应设计为并行 F I R FIR FIR 滤波器,这样一个 c l k clk clk 周期就能完成所有通道的 F I R FIR FIR 低通滤波输入。由于直接型 F I R FIR FIR 滤波器的抽头系数具有对称性,因此在运算时可以合并处理,这样可以用一半的阶数长度(本实验中是 8 8 8 )完成一次 F I R FIR FIR 低通滤波的所有运算。

​ 本实验使用的十五阶 F I R FIR FIR 低通滤波器抽头系数由 M a t l a b   F i l t e r   D e s i g n e r Matlab\ Filter\ Designer Matlab Filter Designer 生成,具体如下:
Matlab FDA Tool生成滤波器参数,如果使用FIR核的话,生成的参数直接复制到FIR配置界面里就行,注意不同类型的FIR滤波器频率响应性能有区别

​ 由于 r e g reg reg 类型变量无法存储小数,因此需要先将生成的抽头系数放大,然后去尾取整,理论上放大倍数越大,能够保留的精度越高,但对内存资源消耗就越大。

​ 最终,低通滤波后的四路信号 M o d e l S i m ModelSim ModelSim 波形如下所示:
低通滤波后各通道波形

3.data_to_file.sv

d a t a _ t o _ f i l e . s v data\_to\_file.sv data_to_file.sv 文件是老师提供的,具体的用法是放到 f i r _ t e s t . s v fir\_test.sv fir_test.sv 文件内,要输出哪个信号线的波形数据,就例化一个 d a t a _ t o _ f i l e data\_to\_file data_to_file 模块。
data_to_file
注意此模块的所有非中文注释部分绝对不可以删掉,这些语句是命令,删掉后会影响模块的正常工作!!
​ 通过 d a t a _ t o _ f i l e . s v data\_to\_file.sv data_to_file.sv 的分析可知,文件输出仅在 v a l i d valid valid 有效时成立,因此需要写一个使能输出的逻辑,控制文件的读取。文件读取的时序设计要点是使能应该是在 F I R FIR FIR 低通滤波结束后,以 400 k h z 400khz 400khz 为采样频率记录一次,记录期间使能信号高电平持续长度应为一个 c l k clk clk 周期。实验中实现的方法是:已知新数据的读入操作是从 c l k _ 400 k h z clk\_400khz clk_400khz 的下降沿到达时刻开始,完成两个通道数据读入、延迟等待、正交变换、 F I R FIR FIR 低通滤波等操作总的时钟周期开销不超过 15 15 15 c l k clk clk 周期。因此可以在 c l k _ 400 k h z clk\_400khz clk_400khz 上升沿到来时,以一个 c l k clk clk 周期将各通道 F I R FIR FIR 输出数据写入文件。上升沿的捕获逻辑与前面下降沿捕获类似。
在这里插入图片描述
​ 可以看出,这个逻辑下确实可以有效保证各通道读到的数据是已经经过 F I R FIR FIR 滤波器的数据。

4.结果验证

​ 结果验证主要是两点: M o d e l S i m ModelSim ModelSim 波形频率与相位差的验证; M o d e l S i m ModelSim ModelSim 归一化波形与仿真归一化波形的比对验证。

ModelSim波形验证

在这里插入图片描述
结论:时序正确。
在这里插入图片描述
结论:频率正确。
在这里插入图片描述

结论:相位差相差 π 2 \frac{\pi}{2} 2π ,正确。

归一化波形数据对比

​ 以通道一实部输出为例,其他三个通道方法相同,结论也相同。

验证方法: c m d cmd cmd 控制台命令 f c   10 k d a t a _ w a v e . d a t   y o u t _ c h 1 _ r e a l . d a t fc\ 10kdata\_wave.dat\ yout\_ch1\_real.dat fc 10kdata_wave.dat yout_ch1_real.dat ,比较两个文件是否存在差异,若找不到差异,则两个文件的数据完全一致,即: M o d e l S i m ModelSim ModelSim 波形数据与仿真结果完全一样。
在这里插入图片描述
​ 使用 g n u p l o t gnuplot gnuplot 工具直接将上述两个文件的波形绘制出来(此处时域为采样点序号)
在这里插入图片描述
在这里插入图片描述
​ 对比的仿真数据集文件由 10 k _ g e n e r a t i o n . c p p 10k\_generation.cpp 10k_generation.cpp 生成,完全使用 M o d e l S i m ModelSim ModelSim 仿真中的参数与算法。

10k_generation.cpp

#include<bits/stdc++.h>
#define pi 3.1415926
using namespace std;
int main(){
	float t=0;
	int f1=10000;
	int f=100000;
	float fs=400000;
	float tmp;
	freopen("10kdata_wave.dat","w",stdout);
	for (int i=0; i<2048; i++){
		t=i/fs;
		tmp=sin(2*pi*f1*t);
		tmp=tmp*256;
		//正交变换 
	/*	if (i%4==1 || i%4==3)
			tmp=0;
		if (i%4==2)
			tmp=-tmp;*/
		cout<<(int)tmp<<endl;
		//cout<<t<<' '<<(int)tmp<<endl;
	}
	
	fclose(stdout);
	return 0;
}

结论: M o d e l S i m ModelSim ModelSim 归一化波形与仿真波形完全一致(紫色线条为仿真生成数据,绿色线条为 M o d e l S i m ModelSim ModelSim 生成数据),完全重合,证明了实验结果的正确性。
综合验证
​ 结论:上述仿真代码可以综合,且逻辑门资源利用合理,可下载到开发板上。

工程文件

链接:https://pan.baidu.com/s/1iqAAlNRZaJsezku20_OjKQ?pwd=0x7f
提取码:0x7f

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值