Среднее арифметическое для датчика
Это код, который я сейчас использую, но я хочу добавить арифметику Я имею в виду это. Моя цель: когда пин 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 добавил в комментарии к моему ответу:
«Я попробовал [усреднить последовательные показания]. Это сработало так, как и ожидалось. но это все еще не решает мою проблему. Мой датчик только становится правильным значения в начале сканирования, а затем оно меняется. Вот почему Я хотел сделать среднее значение, но это все еще не работает. К сожалению, я думаю, Я не смогу поменять датчик, но есть ли другой способ замаскировать эту проблему?
Ниже представлен снимок экрана, на котором показаны как правильный (✓), так и неправильный (✗) ответ. показания:
@hehexd, 👍3
5 ответов
Кажется слишком просто. Я что-то упускаю?
--- 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)
{
Фиксированным окном выборки может быть сложно управлять, особенно если вы хотите, чтобы вычисления были рекурсивными, из соображений экономии места и скорости.
Подобных результатов можно добиться с помощью экспоненциального сглаживания.
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.
Как вы можете видеть, оба подхода очень похожи друг на друга. Экспоненциальное сглаживание использует гораздо меньше оперативной памяти и работает намного быстрее. Более старые данные имеют меньший вес на выходе, что обычно желательно в большинстве приложений.
См. обучающие материалы по Arduino. Сглаживание https://www.arduino.cc/en/tutorial/smoothing
Создайте массив для хранения серии показаний. И переменную для хранения суммы.
Пошагово циклически проходим по массиву, вычитая самое старое значение из суммы и заменяя его в массиве текущим показанием. Разделим на количество показаний для среднего.
Не забудьте предусмотреть задержку в каждом считывании, соответствующую датчику.
Вы можете использовать скользящее среднее. Оно будет обновляться на каждом цикле, когда вы берете новое показание. Предположим, вы хотите усреднить по 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;
}
Я отредактировал функцию выше. Я неправильно ввел один из аргументов.
Мой датчик получает правильные значения только в начале сканирования, а затем они меняются. Вот почему я хотел сделать среднее значение, но оно все еще не работает.
У меня была похожая проблема. Оказалось, что я слишком быстро читал, писал и передавал. Это значит, что поскольку кажется, что чтение и запись могут прерываться во время «их работы», когда вы читаете переменную и в то же время кто-то пишет в нее, вы читаете мусор. По-моему, это можно исправить применением «семафоров» или мьютекса или уменьшением вызова чтения. Случайно это будет происходить снова, но реже.
Идею можно найти здесь https://forum.arduino.cc/index.php?topic=132813.0
Лучший
Джан Мария
- DS18B20 дает высокие показания. Как заставить его вернуть правильную температуру?
- Проблема с датчиком температуры и влажности DHT11
- Что выбрать между датчиками температуры и влажности: AM230x или DHT22?
- Сокращение времени считывания показаний датчиков температуры DS18B20.
- Проблемы с подключением I2C на ESP8266 — 12F, какие контакты использовать?
- DHT11 возвращает неверные значения
- Данные DHT11 из Arduino UNO в Firebase через ESP8266
- Как изменить разрешение DS18B20?