Помогите реализовать запись числа с точкой
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
1. речь идет об AVR? не так ли? этот тип МК нельзя назвать ни быстрым, ни обладающим просторным ОЗУ
2. и большие и маленькие числа можно использовать в предложенным мною варианте, надо просто продумать алгоритм вычислений так, чтобы не было потери точности.
2. и большие и маленькие числа можно использовать в предложенным мною варианте, надо просто продумать алгоритм вычислений так, чтобы не было потери точности.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
-
codenamehawk
- Вымогатель припоя
- Сообщения: 528
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Re: Помогите реализовать запись числа с точкой
ARV писал(а):1. речь идет об AVR? не так ли? этот тип МК нельзя назвать ни быстрым, ни обладающим просторным ОЗУ
1.Да. Далее, МК быстрый ( первый комп с процом Интел был всего на 1 М), но не умеет он выполнять операции с плавающей точкой. ОЗУ мало, но не значит что не хватает.
2. и большие и маленькие числа можно использовать в предложенным мною варианте, надо просто продумать алгоритм вычислений так, чтобы не было потери точности.
2. Можно, но зачем, если автор подтвердил, что нет потери точности.
(По вашему, первому посту, сложно разобраться, как написать алгоритм программы.
Проще тогда уж проще знаки цифр, принятые до запятой, преобразовать в целостной тип и сохранить в одной переменной(целая часть числа),
а знаки цифр принятые после запятой, преобразовать в целостной тип и сохранить в второй переменной(дробная часть числа).
Дальше целочисленная арифметика, как на бумажке.
В данной ситуации надо ли это?)
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
я не знаю, надо ли... я знаю, что без float можно обойтись почти всегда. по поводу быстродействия - можно спорить до усрачки, но есть объективные критерии оценки: если умножение двух флоатов длится долго, использовать их в прерывании, например, становится весьма сложно... мне, в общем-то, все равно, как поступит автор вопросов...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- avreal
- Опытный кот
- Сообщения: 842
- Зарегистрирован: Чт дек 31, 2009 19:27:45
- Откуда: Бровари, Україна
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
Andrey19888 писал(а):Спасибо. Заработало. Единственный момент, что в переменной sdf по прежнему остается неточное значение, а мне с ней нужно будет работать. Как там можно поправить?
А Вам не приходило в голову, что десятичное число 12.075, т.е. дробь 12075 / 1000, имеющая в знаменателе число, раскладываемое на 2-ки и 5-ки, может быть просто непредставимо точно в виде дроби X / 2^N (т.е. числа, имеющего в знаменателе только двойки) с конечным N?
Почитайте про представление чисел с плавающей запятой в двоичной форме.
Простой пример:
число 0.75 раскладывается на 0.5+0.25 и с фиксированной запятой записывается в двоичной форме как 0,11 (1/2 + 1/4)
А 0.76?
0.5+0.25+0,0078125 = 0,7578125, в двоичной форме
0,11000010
и остаток 0,0021875
Т.е. при фиксированной запятой и восьми двоичных знаках после запятой мы можем задать числа
0,11000010 -> 0,7578125
0,11000011 -> 0,76171875
А всё, что между ними - ну никак.
Можем добавить разрядности, получим что-то в духе 0.110000101000111101011100 ошибка уменьшится, но до нуля не упадёт.
0.110000101000111101011100 -> 0,75999999
0.110000101000111101011101 -> 0,76000005
Последний раз редактировалось avreal Ср янв 05, 2011 17:00:59, всего редактировалось 2 раза.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
-
clawham
- Поставщик валерьянки для Кота
- Сообщения: 1957
- Зарегистрирован: Пт окт 31, 2008 09:38:55
- Откуда: Одесса
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
Уважаемые знатоки математики, с моей-то идиократией не поможете обойтись без флоата? ибо кроме разрядности мне реально не хватает скорости...а ещё надо экспоненту....
камень мега 8 генератор 8 мегагерц....внешний кварц - расточительство...
камень мега 8 генератор 8 мегагерц....внешний кварц - расточительство...
Что нас не убило сделало нас осторожней
Не доверяйте русским лужам - это может быть вход в метро.
Не доверяйте русским лужам - это может быть вход в метро.
-
codenamehawk
- Вымогатель припоя
- Сообщения: 528
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Re: Помогите реализовать запись числа с точкой
avreal писал(а):Andrey19888 писал(а):Спасибо. Заработало. Единственный момент, что в переменной sdf по прежнему остается неточное значение, а мне с ней нужно будет работать. Как там можно поправить?
Если почитаете, то это уже опровергли, т.е. точность, для приведенных данных, не теряется.
Чтобы посоветовать автору, что применить, нужно знать какая нужна точность, для бытовых целей сойдет и флоат.
avr писал(а):умножение двух флоатов длится долго, использовать их в прерывании, например, становится весьма сложно
Тут, как говорится и спору нет. А делить еще хуже.
- avreal
- Опытный кот
- Сообщения: 842
- Зарегистрирован: Чт дек 31, 2009 19:27:45
- Откуда: Бровари, Україна
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
Код: Выделить всё
(float)(Gas_in-Mem_Min_Gas)/(Mem_Max_Gas-Mem_Min_Gas)*0x03ff;Код: Выделить всё
(long)(Gas_in-Mem_Min_Gas) * 0x03ff / (Mem_Max_Gas-Mem_Min_Gas);Код: Выделить всё
0x03ffUL * (Gas_in-Mem_Min_Gas) / (Mem_Max_Gas-Mem_Min_Gas);(long) чтобы хватило разрядности
В конкретных ксловиях может оказхаться выгодным выписать на ассемблере (ассемблерными вставками) свои умножения, скажем, 16бит*16бит -> 24 бита или даже 16бит * 8 бит = 24 бита, в зависимости от возможного диапазона изменения как входных, так и выходных переменных.
В данном случае ещё надо глянуть - может (Mem_Max_Gas-Mem_Min_Gas), которые, как я понимаю, берутся из каких-то настроек и меняются относительно медленно, сразу пересчитывать. Т.е. заранее рассчитать коэффициент (перерассчитывать при введении коррекции)
Код: Выделить всё
gas_coeff = 0x03FFUL * SCALE / (Mem_Max_Gas-Mem_Min_Gas);Код: Выделить всё
gas_coeff * (Gas_in-Mem_Min_Gas) / SCALE;Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
- avreal
- Опытный кот
- Сообщения: 842
- Зарегистрирован: Чт дек 31, 2009 19:27:45
- Откуда: Бровари, Україна
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
Что опровергли?codenamehawk писал(а):Если почитаете, то это уже опровергли, т.е. точность, для приведенных данных, не теряется.
Ну дже если не теряется точность для 12.075 то будет теряться для 12.074. Или прикажете вводить с пульта только те числа, для котрых тоность не теряется?
Согласен, для конкретных цеелй float может быть выше крыши по точности, ошибка будет меньше имеющей смысл для рассмотрения (ох-ох, 12.0749999 отличается от 12.075 аж на одну десятимиллионную), но я бы посоветовал не надеяться, что любое даже относительно "короткое" десятичное число будет точно представлено относительно "длинным" двоичным float точно.
Что я и сделал.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
-
Andrey19888
- Родился
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Re: Помогите реализовать запись числа с точкой
И всетаки вы правы. После экспериментов с разными числами, ошибка реально есть. Уже даже не знаю как выйти из ситуации. Разложение на 2 целых числа не вариант т.к. если ввести 23.005 в одну переменную пойдет 23, а в другую то чушь. Или как представить мелкое число, например 0.002?
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- avreal
- Опытный кот
- Сообщения: 842
- Зарегистрирован: Чт дек 31, 2009 19:27:45
- Откуда: Бровари, Україна
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
Просмотрел ещё раз тему, и так и не понял, что "уже опровергли".codenamehawk писал(а):Andrey19888 писал(а):Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет
Это похоже функция sprintf выдает такой результат, а переменная sdf равна 12.075
Нормально отрабатывает функция sprintf.Andrey19888 писал(а):С выводом я уже разобрался. Волновала только проблема что в переменной хранится не правильное число. Но эксперимент показал что функция sprintf не корректно отрабатывает и приходится округлять
Число 12.075 не представимо в виде конечной двоичной дроби, кто не верит, может проверить.
Так что ни в 32-битном float, ни в 64-битном double точно записано быть не может.
Другое дело, что я не пойму, что так волнует - ну округляйте до нужной разрядности, а точности должно хватить.
sprintf не обязан угадывать, "что приблизительно было" и выводить "красивое" число.
Вот на PC
Код: Выделить всё
#include <stdio.h>
float f = 12.075;
int main()
{
printf("%.8f\n", f);
printf("%.6f\n", f);
printf("%.4f\n", f);
printf("%.2f\n", f);
printf("%.1f\n", f);
}12.07499981
12.075000 ; 8-ка в 7-мом знаке после запятой пошла в округление, поэтому вместо 3 девяток вышло 3 нуля
12.0750
12.07 ; 7-ка нечётное, 5-ка округялется вниз, для 12.085 будет 12.09
12.1 ; ну тут, понятно, и 7-ка округлилась
Единственная некорректность Вашего sprintf — так это то, что без указания разрядности, т.е. при формате %f, по умолчанию должно быть 6 знаков после запятой и он должен был округлить до 6 знаков и вывести как во второй строке выдачи выше. Но переменной не 12.075, это двоичный код...
Последний раз редактировалось avreal Ср янв 05, 2011 18:35:45, всего редактировалось 1 раз.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
- avreal
- Опытный кот
- Сообщения: 842
- Зарегистрирован: Чт дек 31, 2009 19:27:45
- Откуда: Бровари, Україна
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
У Вас все числа должны быть не больше 3 десятичных знаков после запятой?Andrey19888 писал(а):Разложение на 2 целых числа не вариант т.к. если ввести 23.005 в одну переменную пойдет 23, а в другую то чушь. Или как представить мелкое число, например 0.002?
Напишите свою функцию разбора строки в число, которая будет выдавать целое число, но умноженное на 1000. Т.е. при вводе числа точку игнорировать, но считать, сколько вышло символов после десятичной точки. И если их меньше 3, то домножать на 10 столько раз, сколько не хватило.
И дальше все рассчёты вести с учётом того, что числа умножены на 1000.
При выводе
Код: Выделить всё
int a = 12075;
sprintf( "%d.%03u", a / 1000, a % 1000);upd - с отрицательными числами, пожалуй, придётся врукопашную, как-то так
Код: Выделить всё
int a = 12075;
char sig;
int b;
if( a > 0) {
sig = ' '; // или '+', по вкусу
b = a;
} else {
sig = '-';
b = -a;
}
sprintf( "%c%d.%03u", sig, a / 1000, a % 1000);Тху!!! Уже ж 5-е число!!!!!!
Конечно, везде sprintf-у буфер указывать

Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
-
codenamehawk
- Вымогатель припоя
- Сообщения: 528
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Re: Помогите реализовать запись числа с точкой
Andrey19888 писал(а):Разложение на 2 целых числа не вариант т.к. если ввести 23.005 в одну переменную пойдет 23, а в другую то чушь.
Во вторую уйдет 005
Andrey19888 писал(а): Или как представить мелкое число, например 0.002?
Мелкое число 0.002
в первой переменной (целая часть) равна 0 , во второй переменной (дробная часть) равна 002
(Приняли цифры до точки, загнали в первую переменную. Далее, после того, как пульт принял точку, начинаете принимать дробную часть.)
-
codenamehawk
- Вымогатель припоя
- Сообщения: 528
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Re: Помогите реализовать запись числа с точкой
Да с ними, как с целыми числами не поработаешь.
-
clawham
- Поставщик валерьянки для Кота
- Сообщения: 1957
- Зарегистрирован: Пт окт 31, 2008 09:38:55
- Откуда: Одесса
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
это то понятно что можно некоторые коэффициенты рассчитать "до того как"
некоторые это разве что дельтагаз
тоесть из кода
вынести за рамки основного цикла кусочек
и всё...а я не думаю что вычитание двух интов получаются очень затратными по времени процессора....
гораздо круче по времени занимают последние две строки - деление и умножение флоата
как-то от них можно избавиться?
может ввести некую предварительно расчитанную переменную delta_gas_div_500 = Delta_Gas/500.0
и сократить
до
всёравно это деление флоатов...тобиш еруньдя...
А вот ещё на последок вторая математическая головоломка:
есть такое понятие как експонента...в авиамоелизме подразумевает нелинейную зависимость выхода от входа а хитрую кривую и с третьего(или 4-го) канала задавать процент влияния этой кривой на выход тоесть при 0 процентах вход=выходу, при 100% выход равен експоненте, а при 50% выход равен среднему между входом и експонентой)

Вот этот график...
есть в екселе все его циферки )
есть формула но она сложная и не думаю что это реально - впихать её в МК
некоторые это разве что дельтагаз
тоесть из кода
Код: Выделить всё
TempA = (float)(In_Gas);
TempA = TempA - (float)(Mem_Min_Gas);
Delta_Gas = Mem_Max_Gas;
Delta_Gas-= Mem_Min_Gas;
TempA = TempA/Delta_Gas;
TempA = TempA * 500.0;
вынести за рамки основного цикла кусочек
Код: Выделить всё
Delta_Gas = Mem_Max_Gas;
Delta_Gas-= Mem_Min_Gas;и всё...а я не думаю что вычитание двух интов получаются очень затратными по времени процессора....
гораздо круче по времени занимают последние две строки - деление и умножение флоата
как-то от них можно избавиться?
может ввести некую предварительно расчитанную переменную delta_gas_div_500 = Delta_Gas/500.0
и сократить
Код: Выделить всё
TempA = TempA/Delta_Gas;
TempA = TempA * 500.0;до
Код: Выделить всё
TempA = TempA/delta_gas_div_500;всёравно это деление флоатов...тобиш еруньдя...
А вот ещё на последок вторая математическая головоломка:
есть такое понятие как експонента...в авиамоелизме подразумевает нелинейную зависимость выхода от входа а хитрую кривую и с третьего(или 4-го) канала задавать процент влияния этой кривой на выход тоесть при 0 процентах вход=выходу, при 100% выход равен експоненте, а при 50% выход равен среднему между входом и експонентой)

Вот этот график...
есть в екселе все его циферки )
есть формула но она сложная и не думаю что это реально - впихать её в МК
- Вложения
-
- экспонента.xls
- тот самый екселик
- (30.5 КБ) 157 скачиваний
Что нас не убило сделало нас осторожней
Не доверяйте русским лужам - это может быть вход в метро.
Не доверяйте русским лужам - это может быть вход в метро.
- avreal
- Опытный кот
- Сообщения: 842
- Зарегистрирован: Чт дек 31, 2009 19:27:45
- Откуда: Бровари, Україна
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
Я имел ввиду другое - по виду имени переменные Mem_* навевают мысль о том, что это некие корректирующие коэффициенты, которые меняются редко и сохраняются где-то.clawham писал(а):это то понятно что можно некоторые коэффициенты рассчитать "до того как"
...
вынести за рамки основного цикла кусочеки всё...а я не думаю что вычитание двух интов получаются очень затратными по времени процессора....Код: Выделить всё
Delta_Gas = Mem_Max_Gas;
Delta_Gas-= Mem_Min_Gas;
гораздо круче по времени занимают последние две строки - деление и умножение флоата
Если это так, то можно при изменении сразу пересчитывать в более сложные коэффициенты и уже их использовать каждый раз в формулах.
Ну и к фиксированной запятой перейти аккуратно.
Любое деление выполняется гораздо дольше, чем умножение. Для AVR даже целочисленное деление 32 бит может выполняться дольше плавающего умножения. Так что если есть возможность пересчитать 1/coeff заранее, то лучше так сделать и умножать, чем делить.
Попробуйте аппроксимировать кубической параболой. Что-то в духеclawham писал(а):А вот ещё на последок вторая математическая головоломка:
есть такое понятие как експонента...в авиамоелизме подразумевает нелинейную зависимость выхода от входа а хитрую кривую и с третьего(или 4-го) канала задавать процент влияния этой кривой на выход тоесть при 0 процентах вход=выходу, при 100% выход равен експоненте, а при 50% выход равен среднему между входом и експонентой)
Код: Выделить всё
y = 50 + ((x-50)^3) / 250Код: Выделить всё
y = 50 + k * ((x-50)^3) / 250 / 100 + (100 - k) * (x - 50) / 100 Порисуйте графики, гляньте отличие в %-тах, может устроит.
И, опять таки, смотря сколько раз в секунду пересчитывается y из x и сколько раз в секунду меняется k - можно заготавливать коэффициенты заранее, кроме k туда включать и константы и только множить, а в конце только поделить один раз.
Скажем (это математически формулы, а не запись на С)
Код: Выделить всё
y * 65536 = 50 * 65536 + 65536 * k * ((x-50)^3) / 25000 + 65536 * (100 - k) * (x - 50) / 100
= 50 * 65536 + 65536 * k * ((x-50)^3) / 8 / 3125 + 655 * (100 - k) * (x - 50)
21 отличается от 65526 / 3125 на 0.13%
655 отличается от 65536 / 100 на 0.05%
= 3276800 + 21 * k * ((x-50)^3) / 8 + 655 * (100 - k) * (x - 50) // [1]
k1 = 21 * k
k2 = 655 * (100-k)
= 3276800 + k1 * (x - 50) * (x - 50) * (x - 50) / 8 + k2 * (x - 50) // 4 умножения + 3 сдвига на бит
= 3276800 + (x - 50) * (k1 * (x - 50) * (x - 50) / 8 + k2) // 3 умножения + 3 сдвига на бит Почему я и говорил о выписывании арифметики на 24 бита -- надо внимательно глянуть, и если промежуточные результаты не выходят за пределы 25 бит, то может быть выгодно выписать всё на 3 байта.
Теперь при изменении k пересчитываются k1 и k2 - это будет выгодно, если k меняется в несколько раз реже, чем производится пересчёт y.
Если нет - считать как по формуле [1] с учётом схемы Горнера для полинома для уменьшения умножений хотя бы на одно
В таком варианте всё в целых числах и без делений.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Re: Помогите реализовать запись числа с точкой
avreal писал(а):Попробуйте аппроксимировать кубической параболой.
А она и есть кубическая парабола ( или квадратичная со знаком y = sign(x) * x^2 ), бо экспонента при отрицательных аргументах асимптотически приближается к 0 ( для чисел > 1 ).
Вообще-то я не представляю, что это за устройство ( если не прецизионный вольтметр ) , где точность 10^-6 уже напрягает. Авиамодель ? Хм... Видимо, какой-то ПИД-регулятор с запасом точности в 3 порядка.
А тут вообще считать нечего не надо: задал таблично десяток точек и пот`ом апроксимация полиномом не очень большой степени.
-
clawham
- Поставщик валерьянки для Кота
- Сообщения: 1957
- Зарегистрирован: Пт окт 31, 2008 09:38:55
- Откуда: Одесса
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
Mem_Max_Gas и прочие @mem@ это инициализация...только при включении модифицируются а в последней версии вообще из еепромины кешируются...
сколько раз в секунду? всего 50
а саму экспоненту я хочу вообще в таблицу занести...всего-то 100 значений...помоему 100 байт памяти программ это пыль
кстати эта экспонента - всего лишь примерное действо...нужно просто чтоб в начале движения ручки на 10% влево вправо вызывало только 1 процент изменения выхода а если дернуть до 70% ручку то и выход должен уже быть 70%
ну примерно...тоесть вначале как бы более высокая точность....
все Delta_Gas и прочие это числа от 1000 до 2000 не более...так что попробую покумекать..мож и вправду нафик этот флоат ведь всёравно у меня результат - это значение регистра pwm 500 максимум целого числа
что это за устройство? контроллер соосного вертолёта
суть в том что есть два мотора один крутит нижний винт по часовой стрелке
второй мотор - крутит верхний винт против часовой стрелки
когда ты с пульта даёш плавно газу то моторы раскручиваются и создают крутящие моменты на валу и сворачивают корпус в противоположную сторону ... обои эти усилия равны и верт никуда(в идеале) не дрейфует вокруг оси вращения винтов
ещё на борту есть гироскоп....маханькое цифровое пьезоэлектрическое устройство....суть его работы проста как 2х2:
изначально при включении питания он на выход даёт 1520 микросекунд....
когда вертолёт взлетел и чтото или ктото заставил нарушиться балансу сил двух моторов(провернуло корпус по часовой стрелке) то этот гироскоп(в зависимости от чувствительности которая тоже настраивается плавно с пульта) начинает уменьшать длительность выхода накапливая ошибку) мой контроллер принимает это отклонение от 1520 и начинает уменьшать мощность ( скважностью) двигателя который крутит верхний винт против часовой стрелке(а корпус по часовой) и соответственно поддавать газу второму мотору....корпус получит ускорение в обратную сторону и будет получать это ускорение до тех пор пока выход с гироскопа снова не прийдёт к 1520(ну или сколько там получится)
гироскоп при этом сам знает скорость и инерцию вертолёта, на подходе к расчетному направлению - может выдать в обратную сторону импульс чтоб компенсировать инерциюи остановиться там же где и начал...
даже если один мотор пригорел или одby винт поврежден - гирик всёравно будет стараться держать первоначальное направление смотря на свой датчик....правда датчик хреновенький...и от перепада температур появляется дрейф(самопроизвольное смещение центра но то уже мои проблемы...
с пульта в гиру приходят сигнал уровня чувствительности и сигнал требуемой скорости поворота в заданную сторону...
вот такое вот кино
есть проблемы:
1) иногда входит в самоколебания перелетая нужное направление
2) иногда сильно обезточенный мотор долго раскручивается(хотя усилие уже создаёт) и вертолёт проседает по высоте при рулении
3) когда батарея на 70% кончилась ты невольно задираеш газ до 80-90% и тут уде начинаются упирания "подгазовывающего" мотора в максимум газа...и работа по стабилизации ложится на притормаживающий.....
но меня в данный момент бесит и мешает именно задержка в управлении...реакции...изза этого и гира не может нормально фунциклировать и высота плавает...
сколько раз в секунду? всего 50
а саму экспоненту я хочу вообще в таблицу занести...всего-то 100 значений...помоему 100 байт памяти программ это пыль
кстати эта экспонента - всего лишь примерное действо...нужно просто чтоб в начале движения ручки на 10% влево вправо вызывало только 1 процент изменения выхода а если дернуть до 70% ручку то и выход должен уже быть 70%
все Delta_Gas и прочие это числа от 1000 до 2000 не более...так что попробую покумекать..мож и вправду нафик этот флоат ведь всёравно у меня результат - это значение регистра pwm 500 максимум целого числа
что это за устройство? контроллер соосного вертолёта
суть в том что есть два мотора один крутит нижний винт по часовой стрелке
второй мотор - крутит верхний винт против часовой стрелки
когда ты с пульта даёш плавно газу то моторы раскручиваются и создают крутящие моменты на валу и сворачивают корпус в противоположную сторону ... обои эти усилия равны и верт никуда(в идеале) не дрейфует вокруг оси вращения винтов
ещё на борту есть гироскоп....маханькое цифровое пьезоэлектрическое устройство....суть его работы проста как 2х2:
изначально при включении питания он на выход даёт 1520 микросекунд....
когда вертолёт взлетел и чтото или ктото заставил нарушиться балансу сил двух моторов(провернуло корпус по часовой стрелке) то этот гироскоп(в зависимости от чувствительности которая тоже настраивается плавно с пульта) начинает уменьшать длительность выхода накапливая ошибку) мой контроллер принимает это отклонение от 1520 и начинает уменьшать мощность ( скважностью) двигателя который крутит верхний винт против часовой стрелке(а корпус по часовой) и соответственно поддавать газу второму мотору....корпус получит ускорение в обратную сторону и будет получать это ускорение до тех пор пока выход с гироскопа снова не прийдёт к 1520(ну или сколько там получится)
гироскоп при этом сам знает скорость и инерцию вертолёта, на подходе к расчетному направлению - может выдать в обратную сторону импульс чтоб компенсировать инерциюи остановиться там же где и начал...
даже если один мотор пригорел или одby винт поврежден - гирик всёравно будет стараться держать первоначальное направление смотря на свой датчик....правда датчик хреновенький...и от перепада температур появляется дрейф(самопроизвольное смещение центра но то уже мои проблемы...
с пульта в гиру приходят сигнал уровня чувствительности и сигнал требуемой скорости поворота в заданную сторону...
вот такое вот кино
есть проблемы:
1) иногда входит в самоколебания перелетая нужное направление
2) иногда сильно обезточенный мотор долго раскручивается(хотя усилие уже создаёт) и вертолёт проседает по высоте при рулении
3) когда батарея на 70% кончилась ты невольно задираеш газ до 80-90% и тут уде начинаются упирания "подгазовывающего" мотора в максимум газа...и работа по стабилизации ложится на притормаживающий.....
но меня в данный момент бесит и мешает именно задержка в управлении...реакции...изза этого и гира не может нормально фунциклировать и высота плавает...
Что нас не убило сделало нас осторожней
Не доверяйте русским лужам - это может быть вход в метро.
Не доверяйте русским лужам - это может быть вход в метро.
-
Andrey19888
- Родился
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Re: Помогите реализовать запись числа с точкой
avreal писал(а):У Вас все числа должны быть не больше 3 десятичных знаков после запятой?Andrey19888 писал(а):Разложение на 2 целых числа не вариант т.к. если ввести 23.005 в одну переменную пойдет 23, а в другую то чушь. Или как представить мелкое число, например 0.002?
Напишите свою функцию разбора строки в число, которая будет выдавать целое число, но умноженное на 1000. Т.е. при вводе числа точку игнорировать, но считать, сколько вышло символов после десятичной точки. И если их меньше 3, то домножать на 10 столько раз, сколько не хватило.
И дальше все рассчёты вести с учётом того, что числа умножены на 1000.
При выводеКод: Выделить всё
int a = 12075;
sprintf( "%d.%03u", a / 1000, a % 1000);
upd - с отрицательными числами, пожалуй, придётся врукопашную, как-то такКод: Выделить всё
int a = 12075;
char sig;
int b;
if( a > 0) {
sig = ' '; // или '+', по вкусу
b = a;
} else {
sig = '-';
b = -a;
}
sprintf( "%c%d.%03u", sig, a / 1000, a % 1000);
Тху!!! Уже ж 5-е число!!!!!!
Конечно, везде sprintf-у буфер указывать![]()
Числа у меня не больше 3 знаков после запятой ... пределы изменения это [0.001-99.999]
Числа вводятся как дробные так и целые
Отрицательных значений не будет
Помимо вывода на экран, введенное число необходимо будет сравнивать и если попадает в той или иной предел выполняется действие.
Если честно я немного не понял с этими домножениями. Как быть когда вводится например 0,001 т.е. 0 постоянно множатся и в итоге 1 умножится на 1000 т.е. число 0,001 эквивалентно 1000?
Если не трудно подскажите подробнее алгоритм, что-то я уже совсем запутался
Жизнь как рояль: клавиша белая, клавиша черная, крышка
Re: Помогите реализовать запись числа с точкой
clawham писал(а):есть проблемы:
1) иногда входит в самоколебания перелетая нужное направление
Как я и предполагал - это ПИД регулятор. И это явление объяснимо: астатичность системы с интегратором в цепи обратной связи и обеспечивается именно колебаниями относительно расчетной точки. Настройка ПИД регулятора - тонкая штука, я хоть и руководил дипломными проектами студней специальности "Автоматика", в реале этим не занимался. Но нам хоть удалось убедить автора, что запредельная точность и головоломные Float-вычисления ни к чему.
Желаю успешных полетов
PS надеюсь, ничего противозаконного на борту не будет ?
-
clawham
- Поставщик валерьянки для Кота
- Сообщения: 1957
- Зарегистрирован: Пт окт 31, 2008 09:38:55
- Откуда: Одесса
- Контактная информация:
Re: Помогите реализовать запись числа с точкой
это суперумный пидрегулятор на арме 133 мегагерца и 32 разрядном АЦП 
150 доларов стоит штучка...гирик всмысле...
в общем я обошелся вообще без вычислений задрав частоту камня до 16 мегагерц кварцем получилось что вход в два раза меньший нормы а pwm один-в-один задаёт длительность выхода в микровекундах и код расчета превратился в
вот такой вот безвычислительный блочек...всё на интах..деления не используется....скорость реакции - 8 миллисекунд(по сути время требуемое на замер длительности входных каналов
150 доларов стоит штучка...гирик всмысле...
в общем я обошелся вообще без вычислений задрав частоту камня до 16 мегагерц кварцем получилось что вход в два раза меньший нормы а pwm один-в-один задаёт длительность выхода в микровекундах и код расчета превратился в
Код: Выделить всё
//ждём пока вход Газ упадёт в нуль
while(Gas_in);
//теперь ждём поднятия в 1
//TCCR2=TimOn;
TCCR0 = 0x00; // таймер глушим
Timer_ext = 0; // обнуляем накопитель таймера
TCNT0 = 0;
while(!Gas_in);
//запускаем таймер
TCCR0 = TimOn;
// ждём пока вход Газ упадёт вниз
while(Gas_in);
//срочно тормозим таймер
TCCR0 = 0x00;
// расчитываем кол-во отсчетов от нуля
In_Gas = TCNT0+Timer_ext;
In_Gas = In_Gas>>1;
//ждём пока вход Гиры упадёт в нуль
while(Gyro_in);
//теперь ждём поднятия в 1
//TCCR2=TimOn;
TCCR0 = 0x00; // таймер глушим
Timer_ext = 0; // обнуляем накопитель таймера
TCNT0 = 0; // обнулили и сам таймер
while(!Gyro_in);
//запускаем таймер
TCCR0 = TimOn;
// ждём пока вход Гирo упадёт вниз
while(Gyro_in);
//срочно тормозим таймер
TCCR0 = 0x00;
// расчитываем кол-во отсчетов от нуля
In_Gyro = TCNT0+Timer_ext;
In_Gyro = In_Gyro>>1;
if((In_Gas>2200)||(In_Gyro>2200)||(In_Gyro<800))
continue;
#asm("wdr")
if(In_Gas<1050)
continue;
TempA = In_Gas;
TempB = In_Gas;
if(In_Gyro>1520)
{
// гирик скрутило вверх - первый канал увеличиваем, второй уменьшаем
TempC=In_Gyro-1520; // получили микросекунды смещения
TempA+=(TempC>>1);
TempB-=(TempC>>1);
if(TempA>2000)
{
// перелетели максимум - вернем его в минус второго канала
TempB-=TempA-2000;
}
}
if(In_Gyro<1520)
{
// гирик скрутило вниз - второй канал увеличиваем, первый уменьшаем
TempC=1520-In_Gyro; // получили микросекунды смещения
TempA-=(TempC>>1);
TempB+=(TempC>>1);
if(TempB>2000)
{
// перелетели максимум - вернем его в минус первого канала
TempA-=TempB-2000;
}
}
if(TempA<1000)
TempA = 1000;
if(TempA>2000)
TempA = 2000;
if(TempB<1000)
TempB = 2000;
if(TempB>2000)
TempB = 2000;
OCR1A = TempA;
OCR1B = TempB;
вот такой вот безвычислительный блочек...всё на интах..деления не используется....скорость реакции - 8 миллисекунд(по сути время требуемое на замер длительности входных каналов
Что нас не убило сделало нас осторожней
Не доверяйте русским лужам - это может быть вход в метро.
Не доверяйте русским лужам - это может быть вход в метро.