首页 文章

直接数字合成中的线性插值

提问于
浏览
5

我正在研究C中的微控制器DDS项目,并且在确定如何计算线性插值以平滑输出值方面遇到了一些麻烦 . 现在的计划
使用24位累加器的前8位作为8位输出值数组的索引 . 我需要提出一个函数,它将占用累加器的中间和低位字节,并在数组中的"previous"和"next"值之间生成一个值 . 这对于快速硬件来说足够简单,但由于我使用的是微控制器,我真的需要避免做任何浮点运算或划分!

有了这些限制,我不确定如何从我的两个8位输入数字和累加器的低2个字节获得8位插值,这表示两个输入值之间的“距离” . 提前感谢任何建议!

CLARIFICATION

DDS =直接数字合成

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

5 回答

  • -1

    假设您有一个波形值表(一个象限或四个象限,无关紧要),那么一个可能的优化是存储连续表值之间的增量值 . 即如果你有例如 N = 256 和波形表 LUT[N] 然后您还有一个delta值表, LUT_delta[N] . 两个预先计算的表之间的关系是 LUT_delta[i] = LUT[i+1] - LUT[i] . 因此,不是查找两个连续的表值 LUT[i]LUT[i+1] ,减去这些值以获得增量,然后进行插值,只需查找第一个表值 LUT[i] 和delta, LUT_delta[i] 然后计算插值 . 这需要相同数量的表查找,但数学运算较少 . 如果're using a DSP, otherwise it'是通用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
    
  • 4

    要进行线性插值而不进行除法,应确保分母的幂为2 .

    value(x)= previous,
    value(x 1)=下一个值(x dx)= previous(next - previous)* dx

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

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

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

  • 0

    如果你想要更好的精度,我建议先检查累加器的低位 . 例如,如果我们想要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;
    
  • 7

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

  • 1

    两个值之间的线性插值a和b是(a b)/ 2 .

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

    除以2 = =右移一位 .

相关问题