DDS频率控制字设计详解
前言:
DDS的频率精度受限于\(fs/2^N\),其中,\(2^N\)为频率控制字寄存器宽度。书上说,N可以比查找表的地址宽度大,到时候只需要截取高位送到查找表即可。说的很粗糙,怎么量化分析这个过程?为什么只需要截取高位呢?本文将带你分析一下这个问题。
首先,假定我们需要产生模拟域频率为\(f_c\)的正弦信号,时钟频率为\(f_s\),采样周期为\(T_s=1/fs\)。
如果查找表存了整个周期的正弦值,那么地址范围从\([0:1:2^N-1]\)对应了相位的\([0:1/2^N:1-2^{-N}]\),在式\(\eqref{signal_expression}\)中,相位为
那么查找表的地址就应该是
当时间无限延展,地址也会无限扩展,显然,由于信号是周期的,我们可以对地址进行绕回,也就是
如此生成的正弦波,将会是一个更为精确的数字。
算法中有一个关键的问题:
1.n是无限延展的,如何用定点数表示?
2.如何进行mod操作?
先来解答第一个问题,分析式\(\eqref{addr}\),可以看出,每次addr的增量是固定的,即fc/fs2^N,那么我们可以把乘法替代为累加运算,也就是改写为addr = addr + fc/fs2^N的形式,发生溢出时正常溢出即可,因为无符号数溢出不会影响低位的正确性。
第二个问题,如何进行mod操作?这个也简单,直接取整数部分的低位即可。
给出一个设计的例子。
\(fs=12MHz,\ fc = 18Hz\),查找表深度为\(2^{16}\)。
首先,对 1/fs 进行定点化。
>> fi(1/12e6,0,12)
ans =
8.3324e-08
DataTypeMode: Fixed-point: binary point scaling
Signedness: Unsigned
WordLength: 12
FractionLength: 35
>> bin(ans)
ans =
'101100101111'
对输入频率进行量化,假定指定输入频率定点方案为u(16,0),即输入范围为0Hz~2^17-1Hz
对其进行全精度运算,const0=u(12,35)*u(16,0)=u(28,35)
计算地址增量,对const0乘2^16,相当于小数点右移16bit,结果为addr_delta = u(28,19),二进制表示不变
对addr_temp做加法,addr_temp需要确保有16位整数值,以容纳所有可能的wrap,故运算结果应为u(35,19)
addr为取了整数位的addr_temp,即量化方式位wrap,量化结果为u(16,0)。这一步实际上就是引言中对频率控制字寄存器取高位的步骤。
给出伪Verilog代码:
module dds_inftyPrecise
(
input clk,rstn
input [15:0] fc,
output [15:0] addr
)
wire [11:0] 1_fs = 12'b101100101111;
wire [27:0] const0 = fc*1_fs;
wire [34:0] addr_delta = {7'b0,const0};
reg [34:0] addr_temp;
always @(posedge clk or negedge rstn)
if(rstn==0)
addr_temp<=0;
else
addr_temp<=addr_temp+addr_delta;
assign addr = addr_temp[34-:16];
endmodule