FPGA中Verilog HDL/VHDL实现NCO(数字控制振荡器)

数控振荡器(NCO,numerically controlled oscillator)软件无线接收机,直接频率合成器(DDS),快速傅里叶变换(FFT)的重要组成部分,NCO采用全数字技术实现,具有分辨率高,频率切换快,相位噪声低等优点。
一般实现NCO的方法是查表法,即实现计算好各个相位的正余弦值存储在查找表中,然后通过寻址输出相应的正余弦值。
下面利用查表法分两步实现一个基于FPGA以及VerilogHDL语言的NCO。
1.利用matlab软件将所需要的相位的正余弦值计算好待用
其中利用matlab产生正余弦值的程序如下:

clear,clc,close all
%%设置参数
sam_clk=20; %%采样频率
out_freq=1;%%输出频率
data_width=18;%%数据位宽, 量化位数
N=20;
%%计算正弦值
sin_1=-sin(([0:N])*2*pi*out_freq/sam_clk);
sin_1_out=round(sin_1*2^(data_width-1));
 %%计算余弦值
cos_1=cos(([0:N])*2*pi*out_freq/sam_clk);
cos_1_out=round(cos_1*2^(data_width-1));
%%调整输出格式
sin=[sin_1_out];
cos=[cos_1_out];

sin_bin=zeros(1,2001);
cos_bin=zeros(1,2001);
sin_bin=[];
cos_bin=[];
for cnt=1:20
sin_bin=[sin_bin    ; dec2binPN(sin(cnt),18)];
end 
for cnt=1:20
cos_bin=[cos_bin    ; dec2binPN(cos(cnt),18)];
end 

将得到的值plot得正余弦波形如下:
matlab中得到的正余弦波形
2.FPGA中实现nco
首先将上一步matlab中生成的数据导出,存入mif表中,然后在quartus中调用两个rom并用mif分别进行初始化,然后通过程序调用这两个rom,分别根据地址输出对应的值,编写的verilog HDL程序如下:

module nco(
     input clk,
	 input nco_en,
	 input rst,
	 
	 output [17:0]nco_I,
	 output [17:0]nco_Q
);
     
	 reg [4:0]addr;
	 
	 always@(posedge clk or negedge rst)
	 if(rst==1'b0)
	    begin 
	     addr<=5'd0;  
		end 
	 else 
	    begin 
		    if(nco_en==1'b0) 
			  addr<=5'd0;
			else 
			  begin 
			    if(addr==5'd19) 
				  addr<=5'd0;
				else 
				  addr<=addr+1'd1;
			  end 
		end 
		
	 wire [17:0] nco_I_temp;
	 wire [17:0] nco_Q_temp;
	 
	 rom_I  my_rom_I(
	                .address(addr),
	                .clock(clk),
	                .q(nco_I_temp));
					
	 rom_Q  my_rom_Q(
	                .address(addr),
	                .clock(clk),
	                .q(nco_Q_temp));
					
	assign nco_I=nco_I_temp;
	assign nco_Q=nco_Q_temp;

endmodule
	 
	 

编写测试代码如下:

`timescale 1ps/1ps
`define clock_period  20 

module nco_tb;
        reg rst;
		  reg clk;
		  reg nco_en;

		  wire [17:0]nco_I;
		  wire [17:0]nco_Q;
		  
	nco  my_nco(
         .clk(clk),
	      .nco_en(nco_en),
	      .rst(rst),
			.nco_I(nco_I),
	      .nco_Q(nco_Q));
			
		  initial 
		     begin 
		        clk=1'b1;
			  end 
		   always #(`clock_period/2) clk=~clk;	  
			
			initial 
			   begin 
				   rst=1'b0;
				   #(`clock_period*10)
					rst=1'b1;
					nco_en=1'b1;
					#(`clock_period*200)
					$stop;
				 end 
endmodule		   

经过quartus ii 软件调用modelsim仿真软件验证所编写nco程序,得到结果如下:
仿真得到的nco输出正余弦波形
以上就基于查表法实现了数控振荡器nco

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值