数字频率合成器的FPGA实现方案
0赞数字控制振荡器
数字控制振荡器在DDC中相对来说是比较复杂的,也是决定DDC性能的最主要因素之一.NCO的目标就是产生一个理想的正弦或余弦波(下面用正弦来通称正弦或余弦),更确切地说是产生一个频率可变的正弦波样本,如下式:
S(n)=cos(2π*(flo/fs)*n)
式中,flo为本地振荡频率;fs为DDC输入信号的采样频率。
查表法产生正弦波样本
正弦波样本可以用实时计算的方法产生,但这只适用于信号采样频率很低的情况.在软件无线电超高速信号采样频率的情况下,NCO实时计算的方法实现比较困难.此时NCO产生正弦波样本最有效、最简便的方法就是查表法,即事先根据各个NCO正弦波相位计算好相位的正弦值,并按相位角度作为地址存储该相位的正弦值数据。
DDC工作时,每向DDC输入一个待下变频的信号采样样本,NCO就增加一个2π(flo/fs)相位增量,然后按照∑2π(flo/fs)相位累加角度作为地址,检查该地址上的数值并输出到数字混频器,与信号样本相乘,乘积样本再经低通滤波器滤波后输出,这样就完成了数字下变频。
由以上分析可以看出数控本振由三部分组成:包括相位累加器、相位加法器及正弦表只读存储器.相位累加器的作用就是将数字本振频率和本振偏移频率之和转换成相位,每来一个时钟脉冲,相位在原来基础上增加一个相位增量,相位加法器的功能是设置一个的初始相位以满足某些应用的需要。
基于上述原理,在下面的这个实验的主时钟(也即采样频率)为50MHz,而输入8bit的fre的底四位值大小代表(1-9)KHz,而高四位大小代表MHz(1-5)。仿真中激励设置先后依次为5KHz,1MHz,5MHz。得到的正余弦波形如下:
Verilog代码如下:(利用IP core生成了一个cos sin模块,其内部结构也是基于查找表的。)
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 16:56:45 05/30/08
// Design Name:
// Module Name: dds_top
// Project Name:
// Target Device:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module dds_top(clk,rst,fre,en,sin,cos,rdy);
input clk;
input rst;
input[7:0] fre;
input en;
output[15:0] sin,cos;
output rdy;
wire rdy_ph;
wire[15:0] phase;
phasegenerate phasegenerate( .clk(clk),
.rst(rst),
.en(en),
.fre(fre),
.rdy(rdy_ph),
.phase(phase));
sin_cos sin_cos( .phase_in(phase),
.clk(clk),
.ce(rdy_ph),
.x_out(cos),
.y_out(sin),
.rdy(rdy));
Endmodule
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 16:57:55 05/30/08
// Design Name:
// Module Name: phasegenerate
// Project Name:
// Target Device:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module phasegenerate(clk,rst,en,fre,rdy,phase);
input clk;
input rst;
input en;
input[7:0] fre;
output rdy;
output[15:0] phase;
reg rdy;
reg[15:0] phadd;
reg[15:0] phase;
always @ (posedge clk) begin
if(rst) begin
phase <= 16'h9b82;
end
else if(en) begin
rdy <= 1;
if( (phase + phadd < 16'h8000) && (phase + phadd > 16'h6487) ) begin
phase <= 16'h9b82; //-pi
end
else begin
phase <= phase + phadd;
end
end
else begin
phase <= 16'h9b82;
end
end
always @ (fre) begin
if(rst) begin
phadd <= 0;
end
else
case(fre)
8'h01: phadd <= 16'h0066; //1KHz
8'h02: phadd <= 16'h00cc; //2KHz
8'h03: phadd <= 16'h0132; //3KHz
8'h04: phadd <= 16'h0198; //4KHz
8'h05: phadd <= 16'h01fe; //5KHz
8'h06: phadd <= 16'h0264; //6KHz
8'h07: phadd <= 16'h02ca; //7KHz
8'h08: phadd <= 16'h0330; //8KHz
8'h09: phadd <= 16'h0396; //9KHz
8'h10: phadd <= 16'h0405; //1MHz
8'h20: phadd <= 16'h080a; //2MHz
8'h30: phadd <= 16'h0c0f; //3MHz
8'h40: phadd <= 16'h1014; //4MHz
8'h50: phadd <= 16'h1419; //5MHz
default: phadd <= 16'h0000;
endcase
end
endmodule