Среднее арифметическое для датчика

Это код, который я сейчас использую, но я хочу добавить арифметику Я имею в виду это. Моя цель: когда пин A0 считывает 5 значений, я получаю среднее значение от которого будет зависеть включение и выключение вентилятора и светодиода, а не 5 отдельных измерений.

int tempPin = A0;
int fan = 3;
int led = 8;
int temp;
int tempreal;
int tempMin = 20;
int tempMax = 30;

void setup() 
{
  Serial.begin(9600);
  pinMode(fan, OUTPUT);
  pinMode(led, OUTPUT);
  pinMode(tempPin, INPUT);
}

void loop() 
{
  temp = analogRead(tempPin);
  tempreal = temp * 0.48828125;
  delay(1);
  if(tempreal > tempMax)
  {
    digitalWrite(fan,HIGH);
    digitalWrite(led,LOW);
    delay(1);
  } 
  else if (tempreal < tempMin)
  {
    digitalWrite(fan,LOW);
    digitalWrite(led,HIGH);
    delay(1);
  } 
  else if (tempreal >  tempMin && tempreal <  tempMax)   
  {
    digitalWrite(fan,LOW);
    digitalWrite(led,LOW);
    delay(1);
  }
}

Изменение Эдгара Бонета – OP добавил в комментарии к моему ответу:

«Я попробовал [усреднить последовательные показания]. Это сработало так, как и ожидалось. но это все еще не решает мою проблему. Мой датчик только становится правильным значения в начале сканирования, а затем оно меняется. Вот почему Я хотел сделать среднее значение, но это все еще не работает. К сожалению, я думаю, Я не смогу поменять датчик, но есть ли другой способ замаскировать эту проблему?

Ниже представлен снимок экрана, на котором показаны как правильный (✓), так и неправильный (✗) ответ. показания:

Примеры показаний

, 👍3


5 ответов


0

Кажется слишком просто. Я что-то упускаю?

--- arithmetic-mean.ino.orig    2017-04-27 19:37:01.386458500 +0200
+++ arithmetic-mean.ino 2017-04-27 19:38:14.458114972 +0200
@@ -16,8 +16,11 @@

 void loop() 
 {
-  temp = analogRead(tempPin);
-  tempreal=temp * 0.48828125;
+  temp = 0;
+  for (int i = 0; i < 5; i++) {
+    temp += analogRead(tempPin);
+  }
+  tempreal = temp * 0.48828125 / 5;
   delay(1);
   if(tempreal > tempMax)
   {
,

1

Фиксированным окном выборки может быть сложно управлять, особенно если вы хотите, чтобы вычисления были рекурсивными, из соображений экономии места и скорости.

Подобных результатов можно добиться с помощью экспоненциального сглаживания.

Yn = (1−α) Yn−1 + α Xn

Где Yn — сглаженный результат, Xn — текущее измерение, а α — вес.

Если немного поразмыслить, то это можно сделать с целыми числами и без потери точности.

редактирование: я провел сравнение экспоненциального сглаживания с (фиксированным окном) скользящей средней. Алгоритм скользящей средней был написан рекурсивным для максимальной скорости.

выбранные данные представляют собой смоделированную синусоидальную волну:

1000 * sin(2pi*n/100) + 100 * шум. n = 0..19999, а шум = -0,5...+0,5.

Таким образом, сигнал/шум = 1000 / 50 = 20:1, или около 5 цифр. Это намного хуже, чем то, с чем вы столкнетесь в 10-битном АЦП.

Я выбрал окно 4.

Как вы можете видеть, оба подхода очень похожи друг на друга. Экспоненциальное сглаживание использует гораздо меньше оперативной памяти и работает намного быстрее. Более старые данные имеют меньший вес на выходе, что обычно желательно в большинстве приложений.

,

1

См. обучающие материалы по Arduino. Сглаживание https://www.arduino.cc/en/tutorial/smoothing

Создайте массив для хранения серии показаний. И переменную для хранения суммы.

Пошагово циклически проходим по массиву, вычитая самое старое значение из суммы и заменяя его в массиве текущим показанием. Разделим на количество показаний для среднего.

Не забудьте предусмотреть задержку в каждом считывании, соответствующую датчику.

,

1

Вы можете использовать скользящее среднее. Оно будет обновляться на каждом цикле, когда вы берете новое показание. Предположим, вы хотите усреднить по N показаниям:

double moving_average(double old_average, double new_value) {
    double new_average = old_average;
    new_average -= old_average/N;
    new_average += new_value/N;
    return new_average;
}

Я отредактировал функцию выше. Я неправильно ввел один из аргументов.

,

1

Мой датчик получает правильные значения только в начале сканирования, а затем они меняются. Вот почему я хотел сделать среднее значение, но оно все еще не работает.

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

Идею можно найти здесь https://forum.arduino.cc/index.php?topic=132813.0

Лучший

Джан Мария

,