Как получить среднее значение 16-битного АЦП?

У меня есть аналогово-цифровой преобразователь Adafruit ADS1115, настроенный в одностороннем режиме. Я хочу усреднить показания трех датчиков, чтобы повысить стабильность показаний.

  //инициализируем переменные
  int16_t rawData, ambient;
  int i=0;

  // запускаем цикл
  while(i<3) {
      rawData = ads.readADC_SingleEnded(0); //читаем из АЦП
      // делим показания датчика на три
      // (это после суммирования приведет к переполнению)
      rawData=rawData/3;                    
      Serial.println(rawData); // распечатываем данные в последовательный порт для отладки (ОК)
      ambient+=rawData;
      i+=1;
      delay(100);
      Serial.println("I LIVVVVEEE"); // распечатываем текст в последовательный порт для отладки (ОК)
  }

  // Сигнал печати (НЕ ОК)
  Serial.print("Ambient is ");
  Serial.println(ambient);

Необработанные данные правильно печатаются на последовательном мониторе. Однако значение «окружающего воздуха» может быть сумасшедшим: результирующий результат более чем на порядок выше. Почему-то кажется, что суммирование выполняется неправильно.

, 👍1

Обсуждение

это не в среднем 3 чтения. это сумма 1/3 показаний, @Juraj


2 ответа


2

Если вы пытаетесь сначала усреднить показания АЦП трех датчиков, вам нужно сохранить и сложить их все, а затем разделить на 3.

 int16_t rawData =0;
 int32_t avg=0,ambient=0;
  int i=0;


 while(i<3) {
      rawData = ads.readADC_SingleEnded(0); //читаем из АЦП
      // делим показания датчика на три
      // (это после суммирования приведет к переполнению)
     Serial.println(rawData); // распечатываем данные в последовательный порт для отладки (ОК)
     avg += rawData;
      i++;
      delay(100);
      Serial.println("I LIVVVVEEE"); // распечатываем текст в последовательный порт для отладки (ОК)
  }
  abmient = avg /3;
  avg = 0;
  // Сигнал печати (НЕ ОК)
  Serial.print("Ambient is ");
  Serial.println(ambient);
,

Этот подход отлично подходит для небольших чисел. Однако АЦП 16-битный. Добавление трех 16-битных значений может (может) привести к переполнению буфера для «ambient»., @plasma

@plasma, сумма трех 16-битных чисел не исчерпывается 32-битными, @Juraj

@Юрай, ничего такого нет. Я только что внес изменения в его программу., @Vaibhav

оценил...., @Vaibhav

на самом деле вы получите более стабильные показания, если возьмете _медиану_ трех показаний вместо _среднего_. рассмотрите возможность чтения 12,13,5, когда истинное показание равно 13. с avg вы получите 10 (ошибка = 3), но с медианой вы получите 12 (ошибка = 1). Я использовал этот метод для проекта цифрового мультиметра, и он имел ОГРОМНОЕ отличие по сравнению с моим наивным методом oversample+avg... Вы также можете настроить количество собираемых внутренних выборок AD1115 и за счет времени чтения получить более стабильный набор ценностей с самого начала., @dandavis

@dandavis Не обязательно, чтобы медиана всегда была правильным значением. Это может произойти в вашем случае, но я тестировал это на контроллере ST, где я беру среднее значение из 4 показаний и получаю ожидаемое значение, хотя я рассчитал напряжение с помощью АЦП, полученная ошибка составляет около -0,01 В от фактического напряжения., @Vaibhav

Расчет среднего значения так, как это делает ОП, абсолютно верен. Не имеет значения, делится ли сумма или слагаемые на количество значений. Ваш код может решить проблему, но это потому, что вы явно инициализируете переменные., @Sim Son


2

Вы забыли инициализировать ambient равным нулю, поэтому он получил все, что находилось в том месте памяти, когда он был создан. Какие-то непредсказуемые, на первый взгляд случайные данные.

,

вы говорите, что int16_tambient; Serial.println(ambient, DEC); может показать что-то кроме 0?, @dandavis

@dandavis: Да, абсолютно. Значение слова «окружающий» здесь неопределенно. В некоторых случаях использование такого значения может даже привести к [неопределённому поведению](https://stackoverflow.com/questions/11962457/why-is-using-an-uninitialized-variable-undefined-behavior)., @Edgar Bonet