verilog数字信号处理—实践1-混频器

  • Post author:
  • Post category:其他



目录


1. 实现功能


2. matlab 代码


3. quartus 代码


1)用NCO IP核生成本振信号


2)混频后的信号处理


3)代码分析


4. 激励信号仿真


1) 从.txt文件中打开din输入信号:


2) 将nco产生的本振信号及混频后的信号输出到.txt文件中:


3) 文件读取代码分析


5.  有NCO IP核的modelsim仿真操作及结果


1)仿真出现错误现象


2)正确操作


3)仿真结果


1. 实现功能


2. matlab 代码

1)生成sin输入信号,并生成.coe/.txt文件供FPGA读取;

2)进行上图算法的仿真,生成sin信号,混频、去除直流分量,进行FFT变换,并输出波形;

3. quartus 代码

1)用NCO IP核生成本振信号

使用过程会发现两个问题,一是会卡在generation环节,进度不动,二是报error。这个IP核并不是免费的IP核,需要破解。以上两个问题可以参考下面的博客解决:


(5条消息) Quartus II 13.1 调用NCO IP核无法生成终于搞定了_Mbluer的博客-CSDN博客

参考上面链接重新安装两个java包后,无法启动java程序,并且nco IP核没办法创建。显示如下错误: 查百度,应该是java版本更新后的问题.  重复上面的操作,

在安装第二个java64时有提醒检测到旧的java版本,忽略掉。

再重新尝试,可以成功打开nco IP核设置。

IP核破解可以参考这篇博文:

(7条消息) QUARTUS II中IP核的调用方法之ip核破解_freedomff的博客-CSDN博客

NCO的输出波形公式如下:

PIN定义如下:

2)混频后的信号处理

求均值,滤除直流分量。通过对一个周期波形的8个数据进行求和然后右移3位得到均值,然后用混频后的数据减去均值(直流分量),得到输出结果。

3)代码分析

module Mixer(
	input clk,rst_n,
	input [9:0]din,     //输入单频信号
	output wire [9:0] s_oc,  // 本振信号
	output wire [19:0] dout //混频信号
	//output ldoc,        //本振信号分频后的显示信号
	//output ldmix        //混频信号分频后的显示信号
	);      
	
wire [15:0]	phi_inc_i;
wire clken;
wire [9:0]oc_sin;
assign clken=1'b1;
assign phi_inc_i=16'd8192;  //设置频率为625khz

oc oc(
	.phi_inc_i(phi_inc_i),
	.clk(clk),       //高电平有效的时钟使能信号
	.reset_n(rst_n),  //异步复位,低电平有效
	.clken(clken),    //时钟使能信号,高电平有效
	.fsin_o(oc_sin),  //输出正弦信号
	.out_valid(out_valid));	
reg signed [19:0] mult;   // 转换成有符号数,因为有正负
wire signed[9:0] s_din;
wire signed[9:0]s_oc_sin;
assign s_oc = oc_sin;
assign s_din=din;
assign s_oc_sin=oc_sin;
always @(posedge clk or negedge rst_n)
	if (~rst_n) mult<=20'd0;
	else mult<=s_din*s_oc_sin;	
//求均值 取8个值求平均是因为一个周期的波形是8个数值
reg  signed [19:0]m1,m2,m3,m4,m5,m6,m7;
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		m1<=20'd0;
		m2<=20'd0;
		m3<=20'd0;
		m4<=20'd0;
		m5<=20'd0;
		m6<=20'd0;
		m7<=20'd0;
		end
	else  begin
		m1<=mult;
		m2<=m1;
		m3<=m2;
		m4<=m3;
		m5<=m4;
		m6<=m5;
		m7<=m6;
		end
	end
wire signed [22:0] madd;
wire signed [19:0] mean,mt;
assign madd=mult+m1+m2+m3+m4+m5+m6+m7;
assign mean=madd[22:3];
//滤除直流分量
assign mt=mult-madd;
assign dout=mt;
endmodule

4. 激励信号仿真

1) 从.txt文件中打开din输入信号:

//从外部TX文件(SinIn.txt)读入数据作为激励
integer pattern,file;
reg [9:0]stimulus[1:data_num];
initial begin
	//文件仿真在“工程目录\simulation\modelsim”路径下
	file=$fopen("SinIn.txt","r");
	//$fscanf(file,"%d",stimulus);   //不能这么写
	pattern=0;
	repeat(data_num)
		begin
		$fscanf(file,"%d",stimulus[pattern]);  //需要一个个读,如下方的写一样,不能直接将所有的数据一次性读到stimulus中。
			din=stimulus[pattern];
			pattern=pattern+1;
			#(`clk_period);
		end
	$fclose(file);
	end

2) 将nco产生的本振信号及混频后的信号输出到.txt文件中:

//将仿真数据dout写入到外部txt文件中(out.txt)
 integer file_out;
 initial begin
	file_out=$fopen("out.txt","w");
	if(!file_out)begin
		$display("could not open file!");
		$finish;
		end
	end
 
 wire rst_write;
 wire signed[19:0] dout_s;
 assign dout_s=dout;
 assign rst_write=clk&(rst_n); //产生写入时钟信号,复位状态时不写入数据
 
 always@(posedge rst_write)  $fdisplay(file_out,"%d",dout_s);

//将仿真数据s_oc写入到外部txt文件中(oc.txt)
 integer file_oc;
 initial begin
	file_oc=$fopen("oc.txt");
	if(!file_oc)begin
		$display("could not open file!");
		$finish;
		end
	end
 
 wire signed[9:0] oc_s;
 assign oc_s=s_oc;

 always@(posedge rst_write)  $fdisplay(file_oc,"%d",oc_s);

3) 文件读取代码分析

本次代码中,联调matlab和quartus的txt文件中用的都是有符号的十进制数,因此在matlab中生成的sin和处理的数据均是十进制的,因此直接用十进制输出,而在quartus中,用$readmem函数只能直接读取二进制和十六进制的数,因此用了$fscanf函数读取十进制,同时在实践中尝试发现只能按照指针一个个数据读取保存到数组中,不能像$readmemb一次性读取。

$readmemb(“文件名”,存储单元,文件中要存入存储单元的起始地址,文件中要存入存储单元的终了地址):对于$readmemb系统任务,每个数字必须使

二进制数字

,对于$readmemh系统任务,每个数字必须是

十六进制数

。$readmem只能读取二进制和十六进制。

$fscanf(文件指针,读取格式,数组);返回值为1表示成功,读取格式可以为%b,%d,%h(注意,如果读取格式为二进制,则文件中只能识别0 1.)

同时,$fscanf(file,”%d”,stimulus);必须一次写一个数,不能这样直接一次性将文件的数据全部写入stimulus中。


verilog中$readmemb和$readmemh的使用_m0_38037810的博客-CSDN博客


verilog读入.txt的有符号十进制数,把有符号十进制数写入到.txt文件中_芒果爱火锅的博客-CSDN博客

5.  有NCO IP核的modelsim仿真操作及结果

1)仿真出现错误现象

仿真时出现找不大IP核调用的模块文件,显示如下错误:

# ** Error: E:/yanghaizhu/FPGA_PRO/11_mixer/quartus/ip/oc_st.v(135): Module ‘asj_dxx’ is not defined.

# ** Error: (vopt-7) Failed to open info file “work/_info” in read mode.

# No such file or directory. (errno = ENOENT)

# ** Error: E:/yanghaizhu/FPGA_PRO/11_mixer/quartus/ip/oc_st.v(142): Module ‘asj_nco_aprid_dxx’ is not defined.

# ** Error: (vopt-7) Failed to open info file “work/_info” in read mode.

主要原因时缺少库,解决方法参考下面博客:


MODELSIM仿真 QUARTUS生成的NCO IP核出现找不到asj等库文件问题的解决方法_little_pants的博客-CSDN博客

2)正确操作

首先,quartus下 tool-run trl simulation,打开modelsim-SE;

然后,library–>work–> 点击oc.v,再点击上面的菜单栏compile,选择oc.vo文件编译。然后接着点击simluate–>start simluate–>在design下,选择work里的tb文件,如下图所示,design unit会出现work.xx名称,

然后点击library–>add,将本项目modelsim–simulation下的verilog_libs下的6个库依次添加进去,然后点击OK。

编译没有错误,如下图:

此时需要手动将想要观察的信号添加进波形,然后run-all,结果如下:

3)仿真结果

问题1:有符号数相乘的结果不对,即得到的dout输出不对。

分析波形如下:mult<=din*s_oc,但是乘积项不是同一时刻的值,有错位。但是乘法运算本身是正确的。 猜测原因是时钟比较大,在时钟锁存数据时就已经完成了assign赋值加非阻塞赋值。

问题2:往.txt中写入的dout数据不对,而写入的oc_s是对的。

这里需要注意,.txt每次运行后都会重新更新,而打开的.txt需要关闭再重新打开,不会再打开的状态下更新。

参考:

Verilog学习笔记——有符号数的乘法和加法_DengFengLai123的博客-CSDN博客



版权声明:本文为weixin_41155462原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。