5

我正在使用 C 语言开发一个微控制器 DDS 项目,并且在弄清楚如何计算线性插值以平滑输出值时遇到了一些麻烦。现在的程序
使用 24 位累加器的前 8 位作为 8 位输出值数组的索引。我需要想出一个函数,它将获取累加器的中字节和低字节,并在数组中的“上一个”和“下一个”值之间生成一个值。这在快速硬件上已经足够简单了,但是由于我使用的是微控制器,所以我真的需要避免进行任何浮点运算或除法!

有了这些限制,我不确定从我的两个 8 位输入数字和累加器的低 2 个字节中获取 8 位内插值的方法,它代表两个输入值之间的“距离”。提前感谢您的任何建议!

澄清

DDS = 直接数字合成

在 DDS 中,波形是使用相位累加器从查找表中生成的。相位累加器通常包含一个整数分量和一个小数分量。整数部分用作查找表的索引。在简单的 DDS 实现中,小数部分被忽略,但为了获得更高质量的输出,小数部分用于在相邻查找表值之间进行插值(通常只是线性插值)。对于上述问题,我们正在研究如何有效地在给定分数 f 的两个查找表值之间执行这种线性插值,其中0 <= f < 1

4

5 回答 5

7

假设您有一个波形值表(一个象限或四个象限,没关系),那么一种可能的优化是存储连续表值之间的增量值。即,如果你有N = 256一个波形表LUT[N],那么你也有一个增量值表LUT_delta[N]。两个预计算表之间的关系是LUT_delta[i] = LUT[i+1] - LUT[i]。因此,无需查找两个连续的表值LUT[i]LUT[i+1],减去这些值以获得增量,然后进行插值,您只需查找第一个表值LUT[i]和 增量,LUT_delta[i]然后计算插值。这需要相同数量的表查找,但更少的数学运算。如果您使用的是 DSP,您应该能够使用单个乘法累加指令进行插值,否则它是通用 CPU 上的乘法 + 缩放 + 加法。此外,如果您交错LUTLUT_delta值,您可能能够通过单次读取查找LUT[i]并解压缩这两个值。LUT_delta[i]

伪代码:

extract integer LUT index, i, from accumulator // just need a shift for this
extract fractional part of accumulator, f // mask or subtract to get f
get p = LUT[i] // lookup waveform value
get delta = LUT_delta[i] // lookup delta
calculate p_interp = p + p_delta * f // single multiply-accumulate instruction on most DSPs - need scaling on general purpose CPUs
于 2010-10-11T11:58:25.253 回答
4

要在不进行除法的情况下进行线性插值,您应该确保分母是 2 的幂。

值(x) = 上一个,
值(x+1) = 下一个值(x + dx) = 上一个 + (下一个 - 上一个) * dx

你的问题是,我如何计算 dx ?诀窍是计算您的插值索引(累加器的 16 低位),以便最大值(dx = 1)是 2 的幂:

value(x + dx) = previous + ((next - previous) * index) / 1024

在这里,您已经计算了步长值,因此最大步长为 1024 并且对应于 dx=1。Index = 512 用于 dx=0.5 等...

于 2010-10-11T12:23:06.487 回答
1

如果你想要更好的精度,我建议先检查累加器的低位。例如,如果我们想要 4 个输出值而不是 1:

Acc += 0x2000;
uint lower_bits = Acc & 0xffff;
int rl = LUT[ Acc >> 16];
int rh = LUT[(Acc >> 16) + 1];
if (lower_bits < 0x4000)
    return rl;
if (lower_bits < 0x8000)
    return (rl * 3 + rh) >> 2;
if (lower_bits < 0xC000)
    return (rl + rh) >> 1;
return (rl + rh * 3) >> 2;
于 2010-10-11T11:38:20.900 回答
0

如果您真的需要速度,请查看AVR assembler

于 2010-10-11T11:36:12.963 回答
-2

两个值ab之间的线性插值是 (a+b)/2。

这在简单的硬件中很容易,并且不涉及除法或浮点。

除以 2 == 右移一位。

于 2010-10-11T11:21:10.313 回答