Избегайте математических вычислений с плавающей запятой, чтобы ускорить Arduino
Я читал и слышал, что математические вычисления с плавающей запятой выполняются намного медленнее, чем математические вычисления с целыми числами.
И я видел здесь процесс конвертации от чисел с плавающей запятой к целым числам
Итак, я хочу преобразовать мои плавающие математические вычисления в целочисленные.
Вот код, включающий плавающую математику:
float sensval, lpf, lps;
float sensinitial; // используется для хранения исходных данных датчика
float x, y, z;
int heigh;
int dA;
void setup() {
runSensor();
sensval = readSensorData();
sensinitial = sensval; // Установка исходных данных
lpf = lps = sensval;
}
void loop() {
sensval = readSensorData();
heigh = (float)44330 * (1 - pow(((float) sensval/sensinitial), 0.190295));
lpf = lpf + (sensval - lpf) * 0.1;
lps = lps+ (sensval - lps) * 0.05;
x = (lps - lpf) * 50;
y = x+ (z - y) * 0.1;
z = constrain(y, -500, 500);
dA += z * 100 + 2000;
}
readSensorData(); возвращает максимум 7 десятичных знаков (например, 752,4543)
Также есть расчет мощности.
Итак, как мне преобразовать математические вычисления с плавающей запятой в математические с целыми числами?
Любой код оптимизации приветствуется.
@sir mordred, 👍3
Обсуждение2 ответа
Лучший ответ:
То, о чем вы просите, не так просто, особенно если у вас есть это степенная функция, которую может быть трудно аппроксимировать.
Сначала вам нужно определить диапазон и требуемую точность
каждое из чисел с плавающей точкой, которыми вы манипулируете. Вы написали, что
readSensorData()
возвращает 7 знаков после запятой. Если под этим вы подразумеваете, что вы
требуют относительной точности 10−7, тогда я предсказываю, что это будет
чрезвычайно сложно оптимизировать это как расчет с фиксированной точкой. Если
вы можете жить с гораздо меньшей относительной точностью (скажем, около
10−3 или 10−4), то, возможно, стоит попробовать
что-то.
Я бы начал с записи выражения height
как
height = f(sensval/sensinitial-1)
где
f(x) = 44330 * (1 - pow(1+x, 0.190295))
Я ожидаю, что sensval
и sensinitial
будут близки друг к другу,
что означало бы, что x мало. В этот момент вы должны попытаться
оцените вероятный диапазон для x, потому что осуществимость того, что
следует сильно зависит от него. Следующий шаг — аппроксимировать f() с помощью
Многочлен. Простой Тейлор
расширение дает:
f(x) ≈ -x*(8435.78-x*(3415.25-x*2060.2))
Вы можете начать с этого, просто чтобы посмотреть, выглядит ли это нормально или совершенно безнадежно. Вы заметите, что приведенное выше приближение отлично, когда |x| крошечный, но он очень быстро деградирует, когда |x| увеличивается. Вот почему вы не используете разложения Тейлора в реальном приближения, я показал вам это только для того, чтобы дать вам представление о возможность полиномиальной аппроксимации.
Чтобы превзойти Тейлора, вам нужно указать диапазон x, затем вы можно масштабировать этот диапазон до [−1, 1] и расширять на основе Чебышев полиномы. И затем вы можете выполнить тонкую настройку, чтобы получить оптимальную многочлен, но скорее всего, оно будет лишь незначительно лучше, чем расширение Чебышева.
Если все это работает с разумной степенью полинома (скажем, не более 5), то вы можете начать конвертировать в целочисленную математику. Если это не так, вы можно попробовать другой тип приближения, например интерполяцию по табличные значения. Если проблема в том, что диапазон x слишком велик, Вместо этого вы можете записать степенную функцию как
ab = 2b × log2a
и запишите полиномиальные приближения к экспоненте с основанием 2 и логарифм (многочлены должны охватывать только одну октаву). Если вы попробуете приближение рациональной дроби, помните, что деление происходит медленно Платформа AVR.
Если все вышеперечисленное кажется вам слишком сложным или требует слишком много работы, то просто зайдите более быстрый процессор или попытайтесь смириться с медленной работой программы.
Поскольку вы имеете дело с дробями, вы можете использовать арифметику с фиксированной точкой. Например, вы можете использовать unsigned short _Accum
для readSensorData()
, если вам нужно только 8 бит для дробной части. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf рассказывает о типах с фиксированной точкой в языке c.
- Как использовать SPI на Arduino?
- Float печатается только 2 десятичных знака после запятой
- Отправка и получение различных типов данных через I2C в Arduino
- Библиотека DHT.h не импортируется
- Светодиоды: разница между общим анодом и общим катодом
- Как повторить кусок кода
- Разные и самые быстрые способы вычисления синусов и косинусов в Arduino
- Почему эта программа на C++ не может прочитать Serial.write() моего arduino?
Общая идея заключается в том, что вы смотрите на свои вычисления и решаете, сколько двоичных знаков (двоичный эквивалент десятичных знаков) вам нужно в ваших вычислениях или на разных этапах вычислений, и выполняете свои вычисления по порядку и/или со словом. длина, которая позволит избежать переполнения. В своих расчетах вы будете использовать целочисленные типы данных, мысленно отслеживая двоичную точку на каждом этапе расчета. Найдите арифметику с фиксированной запятой, чтобы найти много информации., @JRobert
переполнение не является проблемой, я просто хочу преобразовать мои вычисления с плавающей запятой в целочисленные вычисления, чтобы немного ускорить работу Arduino., @sir mordred
Вы действительно заметили, что он работает слишком медленно? Не пытайтесь оптимизировать без удобного эталона., @BrettAM