В нашей работе мы постоянно обрабатываем данные получаемые с различных датчиков. Это могут быть контактные датчики (кнопки) или электронные, к примеру движения или освещенности.
В зависимости от получаемых данных мы меняем состояние других устройств, работа которых зависит от состояния окружающей среды или каких-либо внешних действий.
Нас окружают источники помех: электромагнитных, контактных и т.д. Помехи могут вызвать ложные срабатывания разрабатываемых нами устройств. При этом устранить причину бывает довольно сложно. Ложные сигналы с датчика движения или датчика освещённости могут вызвать включение ламп освещения, что может стать неприятным сюрпризом.
Аналоговые значения можно фильтровать с помощью радиоэлементов, к примеру – RC цепей. Со случайными значениями получаемыми от цифровых датчиков бороться сложнее.
Предлагаю разобрать алгоритм цифровой фильтрации. Алгоритм построен на базе экспоненциального сглаживания. В данном примере мы обрабатываем данные получаемые (на каждом цикле) с аналогового датчика освещённости. На экран выводим разность между реальным и фильтрованным значением. Интересные результаты получаются при включении диммируемого источника света.
#include <Arduino.h>
int nSize = 20; //размер массива
int n = 0;
double *arVal; //указатель на массив
uint32_t tTime = 0;
double Alpha = 0.1; //Чем меньше Alpha, тем в большей степени фильтруются, подавляются колебания исходного ряда и шума.
uint16_t valueA0; //промежуточное значение, для наглядности
void setup() {
arVal = new double(nSize);
//проверить, что не NULL
Serial.begin(9600);
}
double func(double *ar, int& nSize){ //вычисляем среднее значение массива накопленных данных
double sum = 0;
for(int i=0; i < nSize; ++i){ //суммируем все элементы массива
sum += ar[i];
}
return sum / nSize; //возвращаем среднее значение
}
void loop() {
valueA0 = analogRead(A0); //данные с датчика
if(millis() - tTime > 300){ //выводим с задержкой, что бы успеть разглядеть результат
Serial.println((long)arVal[n] - valueA0); //выводим разность между фильтрованным значением и текущим значением с датчика освещенности.
tTime = millis();
}
arVal[n] = valueA0 * Alpha + (1-Alpha) * func(arVal, nSize); //расчет очередного значения
if(++n == nSize)n = 0; //массив обрабатывается циклически.
}
Код с классами:
#include <Arduino.h>
#include <ArduinoSTL.h>
using namespace std;
class FilterES {
const double Alpha;
int nSize;
std::vector<double> arVect;
std::vector<double>::iterator it, end1, begin1;
public:
FilterES(int, double);
double FilterAnalog(double);
void outArray();
double getValue();
};
//********************************************
void FilterES::outArray(){
for(auto& iT: arVect){
Serial.print(iT);
Serial.print(" ");
}
Serial.println(" -----");
}
//********************************************
FilterES::FilterES(int size, double Alpha = 0.1):nSize(size), Alpha(Alpha){
arVect.resize(nSize);
begin1 = it = arVect.begin();
end1 = arVect.end();
if(arVect.empty())Serial.println("ERROR: Vector is empty.");
}
//********************************************
double FilterES::FilterAnalog(double val){
double sum = 0.;
for(auto& itT:arVect)sum += itT; //сумма всех элементов массива
*it = Alpha * val + (1-Alpha) * sum / nSize;
it++;
if(it == end1) it = begin1;
return *it;
}
//********************************************
double FilterES::getValue(){return *it;}
//+++++++++++++++++++++++++++++++++++++++++++++
FilterES *fes;
uint32_t tTime = 0;
double valueA0;
void setup() {
Serial.begin(9600);
fes = new FilterES(20, 0.1);
}
//------------------------------------------------
void loop() {
valueA0 = analogRead(A0);
fes->FilterAnalog(valueA0);
if(millis() - tTime > 100){
tTime = millis();
Serial.println(fes->getValue());
// Serial.println(fes->getValue() - valueA0);
// fes->outArray();
}
}