Линейная интерполяция
- Войдите на сайт для отправки комментариев
Пт, 16/06/2017 - 21:09

Доброго времени суток.
Нужна ваша помощь.
Разрабатываю систему автоподсоса для автомобиля.
Основой этому будет являться стандартный датчик температуры авто,т.е. обычный термистор.
После этого сервоприд будет поворачиваться в зависимости от температуры.С получение значений сопротивления проблем нет и поворотом сервопривода проблем нет.
Собственно вопрос, как перевести значение сопротивления в температуру, в соответствии с значениями справа (линейной интерполяцией?).Принципиально хочется знать температуру,т.к. в дальнейшем планирую собирать бортовой компьютер.
Просьба ссаными тряпками не кидатся,я только учусь)
#define THERMISTORPIN A0
// сколько показаний берется для определения среднего значения
// чем больше значений, тем дольше проводится калибровка,
// но и показания будут более точными
#define NUMSAMPLES 5
#define SERIESRESISTOR 215 // емкость резистора "подтяжки"
int samples[NUMSAMPLES];
void setup(void) {
Serial.begin(9600); // соединяемся с компьютером и задаём скорость передачи
}
void loop(void) {
uint8_t i;
float average;
// формируем вектор из N значений с небольшой задержкой между считыванием данных
for (i=0; i< NUMSAMPLES; i++) {
samples[i] = analogRead(THERMISTORPIN);
delay(10);
}
// определяем среднее значение в сформированном векторе
average = 0;
for (i=0; i< NUMSAMPLES; i++) {
average += samples[i];
}
average /= NUMSAMPLES;
// конвертируем значение в сопротивление
average = 1023 / average - 1;
average = SERIESRESISTOR / average;
Serial.println(average);
Serial.println("Ом ");
delay(1000);
}
В вашем случае линейная апроксимация, а не линейная интерполяция.
1) Измерить текущее значение сопротивления R
2) Определить в какой из участков линейной апроксимации попадает его текущее значение: R1MIN < R < R1MAX, где R1MIN R1MAX начало и конец участка
3) Вычислить температуру по формуле T=R*k1+k0, где k1 и k0 коэффициенты взятые из графика линейной апроксимации
Думаю, кусочно-линейная аппроксимация здесь не очень подходит. График похож на экспоненту, соответственно, ею и следует аппроксимировать. Если не получится, взять степенную функцию или полином.
Можно подобрать апроксимирующую функцию. На сколько помню есть онлайн калькуляторы или используйте в экселе Регрессионный анализ.
В вашем случае линейная апроксимация, а не линейная интерполяция.
1) Измерить текущее значение сопротивления R
2) Определить в какой из участков линейной апроксимации попадает его текущее значение: R1MIN < R < R1MAX, где R1MIN R1MAX начало и конец участка
3) Вычислить температуру по формуле T=R*k1+k0, где k1 и k0 коэффициенты взятые из графика линейной апроксимации
Скорей всеже интерполяция, т.к. определяем значения между точками по табличным значениям точек. А так по сути почти согласен. В общем заводим массив P записей c парами значений температура T-сопротивление R с константами из графика, типа P[0].T=-40; P[0].R=45314; P[1].T=-35...... Измерили Rизм - в цикле проходим масив в цикле с индексом I покак не находим P[I].R>Rизм && P[I+1].R<=Rизм Как нашли - считаем T=P[I].T+(P[I+1].T-P[I].T)*(Rизм-P[I].R)/(P[I+1].R-P[I].R). Можно оптимизировать за счет того что температура идет с фиксированым шагом 5 градусов и вычислять ей T[I]=-40+5*I.
Сравнивая эту кусочно-ломаную интреполяцию и аппроксимацию експонентой - я бы делал интерполяцию. Не факт что фактически измереные пары R-T совпадут с заданым графиком. При интерполяции просто значения поправите а аппроксимирующую функцию прийдется пересчитать. Да и нет гарантии что експонентой впринципе удастся. Внешне конечно похоже, но не факт что ляжет.
ПС. Вспомнил что есть у меня пример кусочно ломаной интерполяции http://arduino.ru/forum/otvlechennye-temy/v-pomoshch-samogonshchiku?page=2#comment-193782 По температуре кипения крепость самогона расчитывает (жидкости и пара). Только он заоптимизирован вконец. Шаг таблицы по температуре5 градусов и значения выбираем от температуры, что позволяет убрать цикл поиска и т.д.
Logik, если не ляжет на экспоненту (кстати, это вполне обычное явление, и я предложил альтернативы), хотя похоже, то разумнее уж если и искать аппроксимацию, то использовать не кусочно-линейеую, а кусочно-экспоненциальную (либо кусочно линейную в логарифмическом масштабе.)
И еще, даже в случае непостоянного шага нужный интервал выбирать не линейным поиском, а бинарным.
Честно говоря не понял и половины от того,что вы написали.
Сделал в эксэле через апроксимацию взял 5 полиномов ( для точности ),если брать один ,то после сорока валит значения в минус
С этим вроде разобрался, в коде впишу уравнение через If else ,но как возвести число в степень, в интернете нашёл функцию pow ,но не нашёл примера её использования .
Как например в коде будет выглядеть y=-6.453*x^3?
Всё,разобоался
При измерении температуры тела погрешность 2-3 градуса,при кипячении погрешность в градус(возможно дополнительно греется от пара).
Если кому-то нужен код,то ниже
#define THERMISTORPIN A0 // сколько показаний берется для определения среднего значения // чем больше значений, тем дольше проводится калибровка, // но и показания будут более точными #define NUMSAMPLES 5 #define SERIESRESISTOR 215 // емкость резистора "подтяжки" double Temp; int samples[NUMSAMPLES]; void setup(void) { Serial.begin(9600); // соединяемся с компьютером и задаём скорость передачи } void loop(void) { uint8_t i; double average; // формируем вектор из N значений с небольшой задержкой между считыванием данных for (i=0; i< NUMSAMPLES; i++) { samples[i] = analogRead(THERMISTORPIN); delay(10); } // определяем среднее значение в сформированном векторе average = 0; for (i=0; i< NUMSAMPLES; i++) { average += samples[i]; } average /= NUMSAMPLES; // конвертируем значение в сопротивление average = 1023 / average - 1; average = SERIESRESISTOR / average; Serial.print(average); Serial.print("-Ом "); int Temp=0; if (average>34280) //Если температура меньше 35 {Serial.println("Температура менее 35 градусов");} else if (average<=342380 && average > 15460){ // Если температура от -35 до -20 Temp = -631*pow(10,-15) * pow(average,3) + 653144932*pow(10,-16) * pow(average,2) - 28190624735131*pow(10,-16) * average + 103033637805441*pow(10,-13); //y = -0,00000000x3 + 0,00000007x2 - 0,00281906x + 10,30336378 x всегда в степени,а не умножить } else if (average>3790 && average<=15460){ //Если температура от -20 до +10 Temp = 10*pow(10,-16)* pow(average,4) - 544488* pow(10,-16)*pow(average,3) + 11147159921*pow(10,-16)*pow(average,2) - 121399687828754*pow(10,-16)*average + 427488576477714000*pow(10,-16); //y = 0,0000000000000010x4 - 0,0000000000544488x3 + 0,0000011147159921x2 - 0,0121399687828754x + 42,7488576477714000 } else if (average>1370 && average<=3790){ //Если температура от +10 до +40 Temp = -22995361*pow(10,-16)*pow(average,3) + 203802704428*pow(10,-16)*pow(average,2) - 682722421167996*pow(10,-16)*average + 1011941612141160000*pow(10,-16); //y = -0,0000000022995361x3 + 0,0000203802704428x2 - 0,0682722421167996x + 101,1941612141160000 } else if (average>450 && average<=1370){ //Если температура от +40 до +70 Temp = -602377383*pow(10,-16)*pow(average,3) + 1900064578101*pow(10,-16)*pow(average,2) - 2160255302543600*pow(10,-16)*average + 1342243448081070000*pow(10,-16); //y = -0,0000000602377383x3 + 0,0001900064578101x2 - 0,2160255302543600x + 134,2243448081070000 } else if (average>110 && average<=450){ //Если температура от +70 до +120 Temp = -157038*pow(10,-16)*pow(average,5) + 309294646*pow(10,-16)*pow(average,4) - 234553365547*pow(10,-16)*pow(average,3) + 84028462404499*pow(10,-16)*pow(average,2) - 15235314450979400*pow(10,-16)*average + 2128576001940600000*pow(10,-16); //y = -0,0000000000157038x5 + 0,0000000309294646x4 - 0,0000234553365547x3 + 0,0084028462404499x2 - 1,5235314450979400x + 212,8576001940600000 } if (Temp>100) {Serial.println("Перегрев антифриза"); } Serial.print(Temp); Serial.println("-Температура"); delay(2000); }Если уж очень хочется формулой, то Википедия рекомендует уравнение Стейнхарта-Харта:
T = 1 / (A + B*ln(R) + C*(ln(R))^3)
Для этого термистора получается A=1.3e-3; B=2.6e-4; C=1.6485e-7. Температура в уравнении в кельвинах, так что ещё вычесть 273 нужно, чтобы родные градусы цельсия получились.
Значения в таблице верны для конкретного датчика,у моего уже другие.
Если будет время,попробую расчитать.
Как я понял там нужно измерить реальную температуру и сопротивление которое выдаёт теморезистор в трёх точках и потом решить систему.
Верно?
Матрица из примерно 10 значений. Между точками функцией map. Точность примерно один - два градуса.
матрица двумерная: значения АЦП - температура.
Тогда в моём случае этим заниматься смысла нет,у моего отклонения 2-3 градуса
)))
Если устраивает "отклонения 2-3 градуса" - нахрен вобще огород городить? Искать ближайщее табличное и отклонение не превысит 2,5 градусов.
//Матрица из примерно 10 значений.
Это шутка была? На графике 9 точек, ровно девять и матрица соответственно тоже.
//Точность примерно один - два градуса.
Снова шутите? Даже простая линейная для такой гладкой кривой даст точность до 0.2-0.3 градуса. Если получилось 1-2 то искать ошибку.
// Между точками функцией map.
Дак она и есть линейная интерполяция :) Только делает все медлено и кривовато. То же самое но написаное самостоятельно, а это алгебра 5 или 6 класс, формула прямой, как правило лучше.
///Значения в таблице верны для конкретного датчика,у моего уже другие.
Я предупреждал что так будет.
Glinka0, код вы зря выложили, такое людям не показывают ;)
2128576001940600000*pow(10,-16) - унес сюда http://arduino.ru/forum/otvlechennye-temy/narochno-ne-pridumaesh-originalnye-tsitaty-vyskazyvaniya-i-tupizmy-foruma#new
использовать не кусочно-линейеую, а кусочно-экспоненциальную (либо кусочно линейную в логарифмическом масштабе.)
Нет смысла, линейная и так даст точность до пару десятых градуса. Куда уж выше? А все остальное заметно сложней. Что ТС и продемонстрировал ))) Были бы точки реже или точек больше или функция сложней или требования к результату выше (например САУ перегибов не любит и т.д.) - ну тогда еще разные подходы можна искать. А тут нет смысла.
А при поиске подходов в общем случае надо понимать, что почти все требуют работы с плавающей точкой, что конкретно для ардуины на 328р будет медлено и печально. А линейный расчет позволит избежать плавающей точки.
И еще, даже в случае непостоянного шага нужный интервал выбирать не линейным поиском, а бинарным.
Опять же смысла нет. Бинарный найдет за 3-4 итерации, перебор в среднем за 4-5. Но бинарный сложней.
Glinka0, код вы зря выложили, такое людям не показывают ;)
2128576001940600000*pow(10,-16) - унес сюда http://arduino.ru/forum/otvlechennye-temy/narochno-ne-pridumaesh-originalnye-tsitaty-vyskazyvaniya-i-tupizmy-foruma#new
Пожалуйста,мне не жалко.Это мой первый проект на ардуино и он работает.
Да,вы правы насчёт шеснадцати значных цифр я переборщил, но опять-же, это работает.Возможно проще было закинуть терморезистор совместно с Ds18b20 в чайник и из показаний нарисовать таблицу, но до меня это дошло несколько позже.
Glinka0, код вы зря выложили, такое людям не показывают ;)
2128576001940600000*pow(10,-16) - унес сюда http://arduino.ru/forum/otvlechennye-temy/narochno-ne-pridumaesh-originalnye-tsitaty-vyskazyvaniya-i-tupizmy-foruma#new
Пожалуйста,мне не жалко.Это мой первый проект на ардуино и он работает.
Да,вы правы насчёт шеснадцати значных цифр я переборщил, но опять-же, это работает.Возможно проще было закинуть терморезистор совместно с Ds18b20 в чайник и из показаний нарисовать таблицу, но до меня это дошло несколько позже.