2010-10-11 18 views
5

我正在研究C中的微控制器DDS项目,并且在计算线性插值以平滑输出值时遇到一些困难。现在的程序
使用24位累加器的前8位作为8位输出值数组的索引。我需要提出一个函数,它将采用累加器的中间和低位字节,并在数组中的“上一个”和“下一个”值之间生成一个值。在快速硬件上这将是直截了当的,但由于我使用微控制器,我真的需要避免做任何浮点操作或分区!由于这些限制,我不能确定从我的两个8位输入数字和累加器的较低2位取得8位插值,这代表了两者之间的“距离”输入值。预先感谢您的任何建议!直接数字合成中的线性插值

澄清

DDS =直接数字合成

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

+0

什么是_DDS_? –

+0

DDS =直接数字合成 - 用于音频/无线电/通信/等的波形生成 –

回答

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 
+0

我可能没有正确理解你 - 但是使用24位累加器并不意味着我必须在我的表中的每个点之间为所有2^16增量存储增量值?如果我有这样的空间,我会以更高的分辨率存储表格,而不会被插值困扰! :) – Bitrex

+0

@Bitrex - 如果你有一个N点表(例如N = 256),那么你只需要第二个N点表作为增量,其中'LUT_delta [i] = LUT [i + 1] - LUT [i ]'。 –

+0

啊,我明白了。我觉得我有足够的空间放置一张大小合适的桌子! – Bitrex

-1

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

这在简单的硬件中很容易,不涉及分割或浮点。

除以2 ==右移一位。

+0

只能插入中点 - 对于上述问题,您可能需要内插任意点。 –

+0

“任意”?中点似乎与任何其他点一样随心所欲。 –

+1

@ S.Lott:如果你读到他正在用相位累加器进行DDS的问题 - 相位累加器的小数部分决定了你需要插值的两个值之间的点。至于 “任意”,我的字典说:* 2。数学(一个常量或其他数量)未指定的值* –

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; 
4

为了使线性插值而不做除法,你应该确保你的分母是2

值(X)=前的功率,
值(x + 1)= next value(x + dx)= previous +(next - previous)* dx

您的问题是,我该如何计算dx?关键是要具有计算的内插指数(您的累加器的低16位),以使最大值(DX = 1)是二的幂:

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

在这里,你已经计算的步长值,因此最大步长为1024,对应于dx = 1。索引= 512是对于dx = 0.5等...

+0

我看,所以在我的情况下,使用前8位作为索引(2^16步长值)的24位累加器,除法应该是2^16或16位右移。 – Bitrex

+0

是的,问题在于您必须能够在您的计算中存储(下一个 - 上一个)* 2^16。 – shodanex