линейная интерполяция на микроконтроллере на 8 битов

Я должен делать линейную интерполяцию со временем между двумя значениями на микроконтроллере PIC на 8 битов (Конкретно 16F627 А, но это не должно иметь значения), использование ассемблера PIC. Хотя я ищу алгоритм здесь так же как фактический код.

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

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

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

9
задан jcoder 18 April 2010 в 08:19
поделиться

6 ответов

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

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

7
ответ дан 4 December 2019 в 15:13
поделиться

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

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

1
ответ дан 4 December 2019 в 15:13
поделиться

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

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

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

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

1
ответ дан 4 December 2019 в 15:13
поделиться

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

(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 отсутствуют следующие операции:

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

Вы можете получить сдвиг вправо, используя вместо этого rotate-right, с последующим маскированием лишних битов слева с помощью побитового и. Простой способ умножения 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;
    }
}
2
ответ дан 4 December 2019 в 15:13
поделиться

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

Учитывая два значения X и Y , в основном это:

(X + Y) / 2

или

X / 2 + Y / 2 (для предотвращения нечетного случая, когда A + B может переполнить размер регистра)

Следовательно, попробуйте следующее:

(Псевдо -code)

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
ответ дан 4 December 2019 в 15:13
поделиться

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

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

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

1
ответ дан 4 December 2019 в 15:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: