我刚刚在采用 ASM 的 Atmel AVR 上完成了一个 DDS 项目,得出的结论是 8 位查找表和 8 位 DAC 在低频下会产生过多的量化失真;由于缺乏更好的措辞,我在示波器上得到了一个具有阶梯效应的正弦波。
显然,如果我用大 LPF 平滑波形,我会在较高频率下遇到振幅问题。
从理论上讲,从 8 位 DAC 升级到 12 位 DAC 并使用 4 个最低有效位进行插值应该可以让我将滤波器的截止点提高到足够大的程度,以缓解更高频率下波形幅度的问题。我的问题是我不知道如何执行此操作,或者是否有更简单的方法来消除 zipper 效果……也许是 12 位查找表?
到目前为止,我已经创建了一个无限循环,每次循环完成一个循环时,都会根据与查找表相关的指针位置向 DAC 发送一个值。这就是我感到困惑的地方。我已经阅读了大量关于此的信息,但仍然没有找到一个有效的例子。如果我有一个无限循环,我应该如何填充表查找值之间的插值?关于我能想到的最好的事情是 (a + b)/2;我可能可以实现这个并获得额外的一点或相当于 512 点查找表,但我想认为有更简单的方法或可能提供更好结果的方法。我不知道 C 或如何使用它,但如果谨慎的话,我会尝试一下。
目前,我的时钟频率为 1MHZ,如有必要,我可能会调至 16MHZ。
这是我的代码示例:
;将正弦波输出设置为默认值
ldi ZH, High(sine*2); setup Z pointer hi
ldi ZL, Low(sine*2) ; setup Z pointer lo
;清除累加器
clr r29 ; clear accumulator
;设置加法器寄存器
ldi r24,0x50 ; Fine adder value change register
ldi r25,0x08 ; Middle adder value change register
ldi r26,0x00 ; Coarse adder value change register
循环 1:
add r28,r24 ; 1 Adder values carry over to higher registers. Higher registers raise freq. in larger steps
adc r29,r25 ; 1
adc r30,r26 ; 1 r30 is database address pointer for Z register
lpm r0, Z ; 3 (Load Program Memory) Reads byte from database into the destination register based on Z pointer
out PORTD,r0
rjmp LOOP1 ; 2 => 9 cycles
最佳答案
如果您的 LUT 有 256 个条目,您可以首先使用寄存器 r29(显然是从 0 到 255)作为两个连续样本之间的比例因子。
输出 = (LUT[r30] * (256 - r29) + LUT[r30+1] * r29) >> 8;
Also this thread讨论了正弦波生成的许多实用替代方案。
EDIT 公式实现课本线性插值
y = a*(1-t) + b*t, with 0<=t<1
因此当 t=0 时 y=a,当 t=1 时 y=b。移位 8 表示插值项 t 在乘法后除以 256。在表达式 LUT[r30+1] 中,我假设一个隐式模 256 算术,因为 r30 是 8 位(不是吗?)。
LUT 扩展到 12 位必须单独完成,因为除以 4 只会增加 LUT 中的量化误差。
插值总是相对于 LUT 中的整数索引发生,无论是否有许多样本落在同一范围内,例如。查找表2和查找表 [3]。数学上 Lut[R]、LUT[R+1] 比 [R-1]、[R] 更正确,但在现实生活中没有区别,因为人类的听觉系统没有绝对的引用相位。
关于c - DDS 插值 - 8 位 Atmel AVR ASM 到 12 位 DAC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13558090/