【问题标题】:linear interpolation on 8bit microcontroller8位微控制器上的线性插值
【发布时间】:2010-04-18 08:19:46
【问题描述】:

我需要使用 PIC 汇编语言在 8 位 PIC 微控制器(特别是 16F627A,但没关系)上的两个值之间随时间进行线性插值。虽然我在这里寻找的算法和实际代码一样多。

我需要取一个 8 位起始值、一个 8 位结束值和两者之间的位置(当前表示为 8 位数字 0-255,其中 0 表示输出应该是起始值,255 表示应该是最终值,但如果有更好的方法来表示它,那可能会改变)并计算插值。

现在 PIC 没有除法指令,因此我可以编写一个通用除法例程并在每一步有效地计算 (B-A)/(x/255)+A,但我觉得可能有更好的方法在微控制器上执行此操作,而不是在 C++ 中的 PC 上执行此操作

有没有人有任何建议可以在此硬件上有效地实现这一点?

【问题讨论】:

    标签: algorithm assembly microcontroller


    【解决方案1】:

    您要查找的值是(A*(255-x)+B*x)/255。它只需要 8x8 乘法,最后除以 255,可以通过简单地取和的高字节来近似。

    在0..128范围内选择x,不需要近似值:取(A*(128-x)+B*x)<<1的高字节。

    【讨论】:

    • 如果你不介意做 two 一般乘法,这是一个很好的答案。如果你这样走,使用256而不是255,然后“取高字节近似”真的很不错。
    • 这看起来就是我需要的。我希望避免在主代码中进行除法,因为它总是很乱,这将满足我的需要。
    【解决方案2】:

    假设您插入一系列值,其中前一个端点是新的起点:

    (B-A)/(x/255)+A
    

    听起来是个坏主意。如果您使用基数 255 作为定点表示,您将获得两次相同的插值。当 x=255 时得到 B,当 x=0 时得到 B 作为新的 A。

    使用 256 作为定点系统。除法变为移位,但您需要 16 位算术和 16 位结果的 8x8 乘法。前面的问题可以通过简单地忽略高字节中的任何位来解决,因为x mod 256 变为 0。这个建议使用 16 位乘法,但不能溢出。并且您不会在同一个 x 上插值两次。

    interp = (a*(256 - x) + b*x) >> 8
    

    256 - x 变成了一个借位减法,当你得到0 - x

    PIC 在其指令集中缺少这些操作:

    • 左右移动。 (逻辑和算术)
    • 任何形式的乘法。

    您可以通过使用 rotate-right 来实现右移,然后使用 bitwise-and 屏蔽左侧的多余位。用 16 位结果进行 8x8 乘法的直接方法:

    void mul16(
        unsigned char* hi, /* in: operand1, out: the most significant byte */
        unsigned char* lo  /* in: operand2, out: the least significant byte */
    )
    {
        unsigned char a,b;
    
        /* loop over the smallest value */
        a = (*hi <= *lo) ? *hi : *lo;
        b = (*hi <= *lo) ? *lo : *hi;
        *hi = *lo = 0;
        while(a){
            *lo+=b;
            if(*lo < b) /* unsigned overflow. Use the carry flag instead.*/
                *hi++;
            --a;
        }
    }
    

    【讨论】:

      【解决方案3】:

      Eric Bainville 和 Mads Elvheim 描述的技术可以正常工作;每个插值使用两个乘法。

      Scott Dattalo 和 Tony Kubek 组合了一种名为“twist”的超级优化的 PIC 专用插值技术,它比每次插值两次乘法略快。

      使用这种难以理解的技术值得跑得快一点吗?

      【讨论】:

      【解决方案4】:

      您可以使用 8.8 定点算法来做到这一点。然后,0..255 范围内的数字将被解释为 0.0 ... 0.996,您将能够对其进行乘法和归一化。

      如果您需要更多详细信息,或者是否足以让您开始,请告诉我。

      【讨论】:

        【解决方案5】:

        您可以将其描述为:

        (B-A)*(256/(x+1))+A
        

        使用 x=0..255 的取值范围,将 256/(x+1) 的值预先计算为表格中的定点数,然后编写通用乘法,调整二进制点。这在空间上可能不小;我希望您需要一个 256 个 16 位值的条目表和乘法代码。 (如果您不需要速度,这表明您的划分方法很好。)。但它只需要一次乘法和一次加法。

        我的猜测是您不需要 X 的所有可能值。如果 X 的值很少,您可以离线计算它们,对 X 的特定值进行案例选择,然后实现乘法就固定的移位序列和 X 的特定值相加而言。这在代码中可能非常高效,对于 PIC 来说非常快。

        【讨论】:

          【解决方案6】:

          插值

          给定两个值 XY ,它基本上是:

          (X+Y)/2

          X/2 + Y/2(防止 A+B 可能溢出寄存器大小的奇怪情况)

          因此尝试以下操作:

          (伪代码)

          Initially A=MAX, B=MIN
          
          Loop {
          
              Right-Shift A by 1-bit.
          
              Right-Shift B by 1-bit.
          
              C = ADD the two results.
          
              Check MSB of 8-bit interpolation value
          
              if MSB=0, then B=C
          
              if MSB=1, then A=C
          
              Left-Shift 8-bit interpolation value
          
          }Repeat until 8-bit interpolation value becomes zero.
          

          实际的代码同样简单。只有我不记得手头的寄存器和指令。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-11-24
            • 2012-01-13
            • 1970-01-01
            • 1970-01-01
            • 2015-06-19
            • 2010-09-21
            相关资源
            最近更新 更多