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

目录

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博客

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
调制解调器是一种能将数字信号转换为模拟信号并将模拟信号转换为数字信号的设备。在Verilog中,调制解调器可以使用数字电路设计来实现。 调制部分可以使用数字信号处理技术来实现,包括数字滤波器、数字混频器、数字相位锁定环路等。解调部分可以使用模拟信号处理技术来实现,包括滤波器、放大器、鉴频器等。 以下是一个简单的调制解调器的Verilog代码示例: ```verilog module modem ( input clock, input reset, input [7:0] data_in, output reg modulated_out, input demodulated_in, output reg [7:0] data_out ); reg [7:0] phase_accumulator; reg [7:0] carrier_wave; always @(posedge clock) begin if (reset) begin phase_accumulator <= 8'd0; carrier_wave <= 8'd0; modulated_out <= 1'b0; end else begin // generate carrier wave carrier_wave <= carrier_wave + 8'd1; // modulate data onto carrier wave if (data_in[0]) begin modulated_out <= carrier_wave[0]; end else begin modulated_out <= ~carrier_wave[0]; end // update phase accumulator phase_accumulator <= phase_accumulator + 8'd10; if (phase_accumulator >= 8'd256) begin phase_accumulator <= phase_accumulator - 8'd256; end end end always @(posedge clock) begin if (reset) begin data_out <= 8'd0; end else begin // demodulate data from input if (demodulated_in) begin data_out <= data_out + 8'd1; end end end endmodule ``` 该代码包括一个调制器和一个解调器。调制器将输入的8位数字信号调制到一个8位载波波形上,并输出调制后的模拟信号。解调器将输入的模拟信号解调到8位数字信号上,并输出解调后的数字信号。该调制解调器使用一个简单的相位累加器来生成载波波形,并使用一个比特判断来决定将数据编码为正半波还是负半波。解调器使用一个简单的计数器来计算输入信号中的正半波数,以确定解调后的数字信号。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值