8位微控制器的线性插值

时间:2010-04-18 08:19:46

标签: algorithm assembly microcontroller

我需要使用PIC汇编语言在8位PIC单片机(特别是16F627A,但这无关紧要)上的两个值之间进行线性插值。虽然我在这里寻找的算法与实际代码一样多。

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

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

有没有人有任何建议在这个硬件上有效地实现这个?

6 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:2)

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

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

听起来不错。如果使用base 255作为定点表示,则会获得两次相同的插值。当x = 255时,你得到B,当x = 0时,你得到新的A.

使用256作为定点系统。除法变为移位,但是需要16位运算和8x8乘法以及16位结果。可以通过简单地忽略高字节中的任何位来修复前一个问题,因为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;
    }
}

答案 2 :(得分:1)

您可以使用8.8定点算法来完成。然后,范围0..255中的数字将被解释为0.0 ... 0.996,您将能够对其进行乘法和标准化。

告诉我你是否需要更多细节,或者它是否足以让你开始。

答案 3 :(得分:1)

您可以将其描述为:

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

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

我的猜测是你不需要X的每个可能值。如果只有少量X值,你可以离线计算它们,对X的特定值进行大小写选择然后实现乘法就固定的移位序列而言,增加了X的特定值。这在代码中非常有效,对PIC来说非常快。

答案 4 :(得分:1)

插值

给出两个值 X &amp; Y ,基本上是:

  

(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.

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

答案 5 :(得分:1)

Eric Bainville和Mads Elvheim所描述的技术将会很好地运作;每个插值使用两个乘法。

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

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