2016-06-03 8 views
1

У меня есть функция (показана ниже), в которой мне нужен совет. Функция возвращает наклон линии, которая подходит (по методу наименьших квадратов) к n точкам данных. Чтобы дать вам контекст, мой проект - баритометрический высотомер, который использует эту функцию для определения скорости, основанной на n самых последних пар высоты. Эти пары высотного времени хранятся в 2 глобальных массивах (times[] и alts[]).Arduino: функция float возвращает inf

Моя проблема не в том, что этот метод не работает. Обычно это происходит. Но иногда я запускаю высотомер, и эта функция вернет значение 'inf', перемежающееся с кучей других неправильных значений (я также видел «NaN», но это реже). Есть несколько областей подозрительности, которые у меня есть на данный момент, но я хотел бы получить новую перспективу. Вот некоторая дополнительная контекстная информация, которая может или не может быть полезным:

  • Я использую прерывание для квадратурного энкодера
  • times[] массив имеет типа unsigned long
  • alts[] массива типа float
  • n является const int, в этом случае n = 9
  • на ATmega328 double такой же, как float .. Arduino-double

    float velF() { // uses the last n data points, fits a line to them, 
           // and uses the slope of that line as the velocity at that moment 
        float sumTY = 0, sumT = 0, sumY = 0, sumT2 = 0; 
        for (int i = 0; i < n; i++) { 
         sumTY += (float)times[i] * alts[i]/1000; 
         sumT += (float)times[i]/1000; 
         sumY += alts[i]; 
         sumT2 += (float)times[i] * times[i]/1000000; 
        } 
        return (n*sumTY - sumT*sumY)/(n*sumT2 - sumT*sumT); 
    } 
    

Любая помощь или совет будет весьма признателен!

+3

У вас есть подразделение. Вы проверили знаменатель на ноль? –

+0

Когда OP говорит * «Иногда я запускаю высотомер, и эта функция вернет значение« inf », перемежающееся с кучей других неправильных значений» * вы говорите о интерфейсе альтиметра? –

+0

Вот еще информация, которая может помочь: http://forum.arduino.cc/index.php?topic=46912.0 http://en.cppreference.com/w/cpp/language/operator_arithmetic –

ответ

2

Код, безусловно, выполняет деление на ноль.

По целому ряду причин n*sumT2 - sumT*sumT будет равен нулю. @John Bollinger В большинстве случаев верхний (дивиденд) деления также будет равен нулю, и допустимое значение равным нулю будет приемлемым.

float velF(void) { 
    float sumTY = 0, sumT = 0, sumY = 0, sumT2 = 0; 
    for (size_t i = 0; i < n; i++) { 

     // insure values are reasoable 
     assert(alts[i] >= ALT_MIN && alts[i] <= ALT_MAX); 
     assert(times[i] >= TIME_MIN && times[i] <= TIME_MAX); 

     sumTY += (float)times[i] * alts[i]/1000; 
     sumT += (float)times[i]/1000; 
     sumY += alts[i]; 
     sumT2 += (float)times[i] * times[i]/1000000; 
    } 

    float d = n*sumT2 - sumT*sumT; 
    if (d == 0) return 0; 
    return (n*sumTY - sumT*sumY)/d; 
} 

Сторона примечания: можно было бы отделить подразделение для повышения точности и скорости. Предложите выполнить последний расчет как double.

float velF(void) { 
    float sumTY = 0, sumT = 0, sumY = 0, sumT2 = 0; 
    for (size_t i = 0; i < n; i++) { 
     float tf = (float) times[i]; 
     sumTY += tf * alts[i]; 
     sumT += tf; 
     sumY += alts[i]; 
     sumT2 += tf * tf; 
    } 

    double nd = n; 
    double sumTd = sumT; 
    double d = nd*sumT2 - sumTd*sumTd; 
    if (d == 0) return 0; 
    return (nd*sumTY - sumTd*sumY)*1000/d; 
} 
+1

У меня высокий уровень уверенности в том, что он выполняет деление на ноль. Предложение @ chux будет отличным способом изолировать знаменатель и подтвердить эту теорию с помощью старой старой Serial.print() отладки. Это позволит мне подойти к ответу на реальный вопрос: почему эта функция работает иногда, а не другие? Я просто не могу «выкинуть» значения, которые возвращают «inf». Тот факт, что программа считает, что моя скорость бесконечно велика, свидетельствует о более похожей проблеме. Я обязательно отправлю ответ, когда найду его! –

+0

Боковое примечание на стороне примечание: у меня создалось впечатление, что на ATMEGA328 двойной был таким же, как плавающий? https://www.arduino.cc/ru/Reference/Double –

+1

@Ben Stringer Предложение 'double' было для общих платформ. Кажется, у вас нет никакой пользы. – chux

Смежные вопросы