линейная интерполяция на 8-битном микроконтроллере - PullRequest
9 голосов
/ 18 апреля 2010

Мне нужно выполнить линейную интерполяцию по времени между двумя значениями на 8-битном микроконтроллере PIC (в частности, 16F627A, но это не должно иметь значения), используя язык ассемблера PIC. Хотя я ищу алгоритм здесь столько же, сколько и реальный код.

Мне нужно взять 8-битное начальное значение, 8-битное конечное значение и позицию между ними (в настоящее время представлено как 8-битное число 0-255, где 0 означает, что выход должен быть начальным значением, а 255 означает, что он должен будет окончательным значением, но оно может измениться, если есть лучший способ представить это) и вычислить интерполированное значение.

Теперь у PIC нет инструкции деления, поэтому я мог бы кодировать подпрограмму деления общего назначения и эффективно вычислять (BA) / (x / 255) + A на каждом шаге, но я чувствую, что, возможно, есть гораздо лучший способ сделать это на микроконтроллере, чем я делал бы это на ПК в c ++

Кто-нибудь получил какие-либо предложения для эффективной реализации этого на этом оборудовании?

Ответы [ 6 ]

7 голосов
/ 18 апреля 2010

Значение, которое вы ищете - (A*(255-x)+B*x)/255. Требуется только умножение 8x8 и окончательное деление на 255, которое можно аппроксимировать, просто взяв старший байт суммы.

Выбор x в диапазоне 0..128, аппроксимация не требуется: возьмите старший байт (A*(128-x)+B*x)<<1.

2 голосов
/ 18 апреля 2010

Предполагая, что вы интерполируете последовательность значений, где предыдущая конечная точка является новой начальной точкой:

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

звучит как плохая идея. Если вы используете базу 255 в качестве представления с фиксированной точкой, вы получите один и тот же интерполант дважды. Вы получаете B, когда x = 255, и B как новый A, когда x = 0.

Использовать 256 в качестве системы с фиксированной точкой. Деления становятся сдвигами, но вам нужна 16-битная арифметика и умножение 8x8 с 16-битным результатом. Предыдущая проблема может быть исправлена ​​простым игнорированием любых битов в старших байтах, когда x mod 256 становится 0. Это предложение использует 16-битное умножение, но не может переполниться. и вы не интерполируете по одному и тому же x дважды.

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

256 - x становится просто вычитанием с заимствованием, поскольку вы получаете 0 - x.

В PIC отсутствуют следующие операции в наборе команд:

  • Сдвиг вправо и влево. (как логическое, так и арифметическое)
  • Любая форма умножения.

Вы можете получить сдвиг вправо, используя вместо этого вращение-вправо, а затем замаскировав дополнительные биты слева с помощью побитового и. Прямой способ умножения 8x8 с 16-битным результатом:

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;
    }
}
1 голос
/ 23 мая 2010

Методы, описанные Эриком Бейнвиллом и Мэдсом Эльвхаймом, будут работать отлично; каждый использует два умножения на интерполяцию.

Скотт Даттало и Тони Кубек соединили супер-оптимизированную методику интерполяции, специфичную для PIC, под названием " твист ", которая немного быстрее, чем два умножения за интерполяцию.

Стоит ли использовать эту сложную для понимания технику немного быстрее?

1 голос
/ 18 апреля 2010

Интерполяция

С учетом двух значений X & 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.

Фактический код такой же простой. Только я не помню регистров и инструкций от руки.

1 голос
/ 18 апреля 2010

Вы можете охарактеризовать это как:

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

, используя диапазон значений x = 0..255, предварительно вычислите значения 256 / (x + 1) как число с фиксированной точкой в ​​таблице, а затем закодируйте умножение общего назначения, скорректируйте положение бинарная точка Это не может быть маленьким в пространстве; Я ожидаю, что вам понадобится таблица из 256 записей с 16-битными значениями и код умножения. (Если вам не нужна скорость, это может означать, что ваш метод деления в порядке.). Но требуется только одно умножение и добавление.

Я предполагаю, что вам не нужно каждое возможное значение X. Если существует только несколько значений X, вы можете вычислить их в автономном режиме, выполните case-select для конкретного значения X и затем выполните умножение с точки зрения фиксированной последовательности сдвигов и добавок для конкретного значения X. Это, вероятно, будет довольно эффективным в коде и очень быстрым для PIC.

1 голос
/ 18 апреля 2010

Вы можете сделать это, используя 8.8 арифметику с фиксированной точкой. Тогда число из диапазона 0..255 будет интерпретировано как 0.0 ... 0.996, и вы сможете умножить и нормализовать его.

Скажите, если вам нужно больше подробностей или достаточно для начала.

...