先上代码
module Carrier_NCO
(
clock,
reset,
f_carrier_nco, //载波NCO频率控制字
cos_I, //余弦输出
sin_Q //正弦输出
);
parameter CARR_NCO_WIDTH = 8; //载波NCO累加位数
input clock;
input reset;
input [CARR_NCO_WIDTH-1 : 0] f_carrier_nco;
output [8:0] cos_I;
output [8:0] sin_Q;
reg [CARR_NCO_WIDTH-1 : 0] phase;
wire [7:0] phase_key;
wire [CARR_NCO_WIDTH-1 : 0] accum_sum;
///
//32位相位累加//
///
always @(posedge clock)
begin
if(reset==1'b1)
phase <= 0;
else
phase <= accum_sum[CARR_NCO_WIDTH-1:0];
end
assign accum_sum = phase + f_carrier_nco;
assign phase_key = accum_sum[CARR_NCO_WIDTH-1:0];
///
//本地正弦相位查找表产生//
///
cos_table cos_talbe_m1(
.address(phase_key),
.clken(1'b1),
.clock(clock),
.q(cos_I)
);
sin_table sin_talbe_m1(
.address(phase_key),
.clken(1'b1),
.clock(clock),
.q(sin_Q)
);
/*********************************************************************************/
/************************************程序段结束***********************************/
/*********************************************************************************/
endmodule
输入一个nco频率控制字f_carrier_nco。输出一个正弦波和余弦波。
上图是一个DDS(直接数字频率合成器)原理图。其主要部分是一个数字控制振荡器(NCO,numerically controlled oscillator)。
NCO三大组成部分:频率控制字、相位累加器、rom查找表
程序中相位累加器采用8位,则输入频率控制字最大为8位。累加器模型就是x=x+a.其中累加过程采用组合逻辑直接赋值;x的更新采用时序逻辑。
累加采用组合逻辑assign直接赋值assign accum_sum = phase + f_carrier_nco;
phase的更新采用时序逻辑
always @(posedge clock)
begin
if(reset==1'b1)
phase <= 0;
else
phase <= accum_sum[CARR_NCO_WIDTH-1:0];
end
然后把相位累加器的值作为地址,送入rom中。
rom核的生成
以生成一个sin数据为例。生成前先想好数据深度和宽度。数据深度就是一个周期的采样点数由于前面相位累加器(rom地址)采用8位,这里就把数据深度设置为2^8=256。数据宽度就是一个采样点用几位数据表示,这个可以随便设(依实际需求设),我这里设置为9位有符号数。以下为matlab生成.mif文件程序。
depth=256;width=9;
max=2^(width-1)-1;
n=0:depth-1;
t=n./depth*2*pi;
s=sin(t);
s=s*max;
s=round(s);
c=cos(t);
c=c*max;
c=round(c);
fidc = fopen('SIN.mif','wt')
fprintf(fidc , 'depth = %d;\n',depth);
fprintf(fidc, 'width = %d;\n',width);
fprintf(fidc, 'address_radix = UNS;\n');%地址用无符号数表示
fprintf(fidc,'data_radix = DEC;\n');%数据用有符号十进制表示
fprintf(fidc,'content begin\n');
for(x = 0 : depth-1)
fprintf(fidc,'%d:%d;\n',x,s(x+1));
end
fprintf(fidc, 'end;');
fclose(fidc);
fidc = fopen('COS.mif','wt')
fprintf(fidc , 'depth = %d;\n',depth);
fprintf(fidc, 'width = %d;\n',width);
fprintf(fidc, 'address_radix = UNS;\n');
fprintf(fidc,'data_radix = DEC;\n');
fprintf(fidc,'content begin\n');
for(x = 0 : depth-1)
fprintf(fidc,'%d:%d;\n',x,c(x+1));
end
fprintf(fidc, 'end;');
fclose(fidc);
注意:生成的mif文件虽然可以直接在quartus中加载,但是不能在modelsim中加载(加载进去不报错,但是仿真出来某一地址下的数据是与文件中不一样的)。所以这里要在quartus中将.mif文件另存为.hex文件,然后再加载.hex。