Решение моей функции для среднего значения дает случайные значения - PullRequest
0 голосов
/ 11 февраля 2020

Я использую Mikro C, чтобы попытаться запрограммировать PIC4550 для получения данных от датчика pH. Программа состоит из извлечения данных 40 раз и вычисления их среднего значения с помощью функции Среднее ниже

double Average(int* arr, int number)
{
    int i;
    int ave;
    int sum = arr[0];
    for(i = 0;i<number;i++)
    {
        sum=sum+arr[i];
    }
    ave = sum/number;
    return ave;
}

Моя проблема в том, что большую часть времени она дает случайные значения, очень далекие от правильного ответа. Например, правильный ответ - 633, но он дает -185. Кто-нибудь может указать на мою ошибку? Спасибо. Весь мой код ниже

#define volt 5.00 //system voltage
#define arraylength 40 // number of data collection
#define offsetph 5   //deviate compensate

double Average(int*, int);

void main() {
     float ph_res=0;
     float pHsensor_output[40];
     double avepH;
     double pHvoltage;
     float offsetpH=0.38;  //change to actual pH offset
     float pHlevel;
     char testing[20];
     char pher[20];
     int i;
     int pH_index=0;
     UART1_Init(9600);
     ADCON1=0x00;
     CMCON=7;

     TRISA=0xFF;


   while(1){
    UART1_Write_Text("Reading pH....\r\n");
     for(i = 0; i<40; i++) {
            pHsensor_output[i] = ADC_Read(1);
            sprintf(testing,"READING: %.2f\r\n",pHsensor_output[i]);
            UART1_Write_Text(testing);
            delay_us(1000);
        }
        avepH = Average(pHsensor_output, 40);
        sprintf(testing,"AVG: %f\r\n",avepH);
        UART1_Write_Text(testing);
        pHvoltage = avepH*5/1024;
        pHlevel = 3.5*pHvoltage+offsetph;
        if(pHlevel!=pH_res){
            pH_res = pHlevel;

        }
             sprintf(pher,"pH: %f\r\n",pH_res);
            UART1_Write_Text(pher);

     delay_ms(2000);
       } }
double Average(int* arr, int number)
{
    int i;
    int ave;
    int sum = arr[0];
    for(i = 0;i<number;i++)
    {
        sum=sum+arr[i];
    }
    ave = sum/number;
    return ave;
}

1 Ответ

3 голосов
/ 11 февраля 2020

В некоторых комментариях указывалось, что вы рискуете переполниться во время суммирования. Если это 16-битный компьютер, INT_MAX равен 32767. В соответствии с вашим примером, вы не приближаетесь к этому, но с этим нужно быть осторожным.

В любом случае, вы собираете значения в массив floats:

 float pHsensor_output[40];
 ...
 pHsensor_output[i] = ADC_Read(1);

Но позже передать его функции, ожидающей массив int s:

double Average(int* arr, int number)
...
  avepH = Average(pHsensor_output, 40);

(Тот факт, что Average вычисляется с помощью int s и возвращает double означает, что вы могли бы получить усеченный ответ, но здесь проблема не в этом.)

Ваш компьютер сейчас просматривает комбинацию битов, которая может быть «633» при просмотре как число с плавающей точкой, но почти наверняка не будет при просмотре как целое число. Итак, кто знает, каков будет результат, если вы возьмете их среднее значение?!

Попробуйте изменить свою функцию на что-то вроде:

double Average(float* arr, int number)
{
    int i;
    double ave;
    double sum = 0.0; // NOTE: not arr[0];
    for(i = 0;i<number;i++)
    {
        sum=sum+arr[i];
    }
    ave = sum/number;
    return ave;
}

Приложение: ваш компилятор действительно должен был жаловаться на это. Это действительно молчал? G CC немедленно barfs.

error: cannot convert ‘float*’ to ‘int*’ for argument ‘1’ to ‘double Average(int*, int)’

Редактировать: Всегда приятно понимать , видя, поэтому я попробовал небольшой пример. У меня рабочий стол, а не PI C, поэтому int 32-битный, а не 16, но, надеюсь, суть та же ....

int main()
{
    union {
        float my_float;
        int my_int;
    } hack;

    printf ("sizeof(float) %lu, sizeof(int) %lu\n", sizeof(float), sizeof(int));

    hack.my_float = 633.0;
    printf( "%f -> %d\n", hack.my_float, hack.my_int );

    int sum = 40 * hack.my_int;
    int average = sum / 40;

    printf( "sum %d  -->  %d\n", sum, average );

    return 0;
}

Выход:

sizeof(float) 4, sizeof(int) 4
633.000000 -> 1142833152
sum -1531314176  -->  -38282854

Это «показывает», что хороший float становится сумасшедшим int (когда один и тот же шаблон битов рассматривается по-разному 1 ), и после этого все ставки отключаются. Очевидно, что суммирование переполняется, и, следовательно, среднее получается отрицательным; совсем не то, что вы ожидали!

1 «Объединенный взлом», который я использовал в моем примере, говорит компьютеру: «Возьмите ячейку памяти, содержащую float, и посмотрите в точно таких же битах, но притворяются, что это int. Это то, что происходит, когда вы передаете указатель на некоторые числа с плавающей запятой функции, ожидающей указатель на целые числа.

Но если вы выполняете присваивание «чисто», вы получите то, что ожидаете:

    int nice_int = hack.my_float;  // 633.0
    printf( "good %f  ->  %d\n", hack.my_float, nice_int );

доходность:

good 633.000000  ->  633
...