数控振荡器(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得正余弦波形如下:
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