Я пытаюсь найти эффективный способ вычисления обратного на AVR (или аппроксимируя его).
Я пытаюсь рассчитать период импульса для шагового двигателя, чтобы я мог линейно изменять скорость. Период пропорционален обратной скорости ( p = K/v
), но я не могу придумать хороший способ рассчитать это на лету.
Моя формула
p = 202/v + 298; // p in us; v varies from 1->100
При тестировании на Arduino разделение, похоже, полностью игнорируется, оставляя p
фиксированным на 298
(хотя, возможно, в avr-gcc это будет иначе). Я также пытался суммировать v
в цикле, пока он не превысил 202
, и подсчитывал циклы, но это довольно медленно.
Я мог бы создать таблицу поиска и сохранить ее во флэш-памяти, но мне было интересно, есть ли другой способ.
Редактировать : Может быть, заголовок должен быть "эффективный разрыв" ...
Обновление : как указывает Pingswept, моя формула для отображения периода на скорость неверна. Но главная проблема - операция деления.
Редактировать 2 : При дальнейшем исследовании, разделение работает на Arduino, проблема была связана с неправильной формулой выше и переполнением int в другом месте.
источник
Ответы:
Одна хорошая вещь о разделении - то, что все более или менее делают это. Это довольно характерная особенность языка Си, и компиляторы, такие как AVR-GCC (называемый IDE Arduino), выберут лучший алгоритм деления, даже если у микроконтроллера нет инструкции аппаратного деления.
Другими словами, вам не нужно беспокоиться о том, как реализовано деление, если у вас нет очень странного особого случая.
Если вы беспокоитесь, то вам может понравиться чтение официальных предложенных алгоритмов деления Atmel (один оптимизирован для размера кода, а другой оптимизирован для скорости выполнения; ни один не занимает память). Они в:
http://www.atmel.com/dyn/resources/prod_documents/doc0936.pdf
это примечание по применению «AVR200: процедуры умножения и деления», перечисленные на странице Atmel для его (достаточно больших) процессоров Atmega, таких как Atmega 168 и Atmega 328, используемых в стандартных Arduinos. Список технических паспортов и замечаний по применению находится по адресу:
http://www.atmel.com/dyn/products/product_card.asp?part_id=4720
источник
Похоже, все, что вам нужно, это таблица поиска на 100 записей. Не становится намного быстрее, чем это.
РЕДАКТИРОВАТЬ вы на самом деле только справочную таблицу с 68 значениями, поскольку значения v больше 67 всегда оцениваются как 300.
источник
Есть несколько очень хороших методов, упомянутых в книге Генри Уоррена «Восторг хакеров » и на его сайте hackersdelight.org . Для метода, который хорошо работает с микроконтроллерами меньшего размера при делении на константы, посмотрите этот файл .
источник
Кажется, ваша функция не дает желаемого результата. Например, значение 50 возвращает примерно 302, а 100 возвращает примерно 300. Эти два результата почти не приведут к изменению скорости двигателя.
Если я вас правильно понимаю, вы действительно ищете быстрый способ сопоставить числа 1-100 с диапазоном 300-500 (приблизительно), чтобы 1 соответствовал 500, а 100 - 300.
Возможно, попробуйте: р = 500 - (2 * V)
Но я могу ошибаться - вы пытаетесь рассчитать время прямоугольной волны с постоянной частотой? Что за 298?
источник
Эффективный способ приблизить деления - сдвиги. например, если x = y / 103; деление на 103 - это то же самое, что и умножение на 0,0097087, поэтому для аппроксимации сначала выберите «хорошее» число смещения (т. е. число с основанием-2, 2,4,8,16,32 и т. д.)
Для этого примера 1024 хорошо подходит, так как мы можем сказать, что 10/1024 = 0,009765. Тогда можно кодировать:
х = (у * 10) >> 10;
Конечно, помня, что переменная y не переопределяет свой тип при умножении. Это не точно, но это быстро.
источник
С другой стороны, если вы пытаетесь разделить процессор, который не поддерживает разделение, в этой статье Wiki есть действительно классный способ сделать это.
http://en.wikipedia.org/wiki/Multiplicative_inverse
источник
Этот процесс здесь выглядит тси удобно, хотя , возможно , потребуется немного портирования.
Хотя кажется, что LUT будет проще. Вам понадобится всего 100 байт, меньше, если вы используете некоторую интерполяцию, и, поскольку LUT заполнен константами, компилятор может даже найти его в области кода, а не в области данных.
источник
Убедитесь, что деление выполняется с плавающей запятой. Я использую Microchip, а не AVR, но при использовании C18 вам нужно заставить ваши литералы обрабатываться как числа с плавающей запятой. Например. Попробуйте изменить формулу на:
p = 202.0/v + 298.0;
источник
Вы хотите быстро, так что все идет ..... Так как AVR не может эффективно выполнять нормализацию (смещение влево до тех пор, пока вы не можете больше смещаться), игнорируйте любые псевдо-алгоритмы с плавающей запятой. Самый простой способ очень точного и быстрого целочисленного деления в AVR - это обратная таблица поиска. В таблице будут храниться обратные величины, масштабированные большим числом (скажем, 2 ^ 32). Затем вы реализуете умножение unsigned32 x unsigned32 = unsigned 64 в ассемблере, поэтому answer = (Numberrator * inverseQ32 [denominator]) >> 32.
Я реализовал функцию умножения с использованием встроенного ассемблера (в функции ac). GCC поддерживает 64-битные "long long", однако, чтобы получить результат, вы должны умножить 64-битные на 64-битные, а не 32x32 = 64 из-за ограничений языка C на 8-битной архитектуре ......
Недостатком этого метода является то, что вы будете использовать 4K x 4 = 16K флэш-памяти, если хотите разделить на целые числа от 1 до 4096 ......
Очень точное беззнаковое деление теперь достигается примерно за 300 циклов в C.
Вы можете рассмотреть возможность использования 24-битных или 16-битных целых чисел для большей скорости, меньшей точности.
источник
Возвращаемое значение вашего уравнения уже
p=298
таково, так как компилятор сначала делит, а затем добавляет, используйте целочисленное разрешение muldiv, которое:Используя это то же умножение
a*f
, с = целое число f = дробь.Это даёт,
r=a*f
ноf=b/c
потом,r=a*b/c
но пока не работает, потому что положение операторов,r=(a*b)/c
функция final или muldiv, способ вычисления дробных чисел с использованием только целых чисел.источник