Страница на этапе разработки.
Если не вдаваться в сложные термины и математические формулы, — данный фильтр убирает одиночные, спонтанные помехи в виде шпильки. Для работы фильтра необходимо минимум три точки измерения, алгоритм проверяет все три значения и оставляет среднее значение, то есть убирает максимальное и минимальное. Таким образом шпилька будет удалена.
В нашем примере мы рассмотрим самый простой медианный фильтр который использует три значения, но Вы можете данный алгоритм расширить на большее количество точек измерений.
Для тестирования и демонстрации работы медианного фильтра мы сгенерируем синусоидальный сигнал, добавим в него случайные единичные помехи и после этого пропустим данных сигнал через фильтр и посмотрим как он работает.
Программный код:
int count = 0; // счётчик процесса
bool n = 0;
float signals = 0.0; // чистый сигнал
float noises = 0.0; // сигнал с помехами
float filtrs = 0.0; // отфильтрованный сигнал
#define NUM_READ 10
int insert =0;
int j=0;
void setup() {
Serial.begin(9600);
Serial.flush();
}
void loop() {
Signal();
Serial.print(signals);
Serial.print(‘,’);
noise();
Serial.print(noises);
Serial.print(‘,’);
filtrs = median(noises);
Serial.println((filtrs+3));
count++;
}
void Signal() {
// синусоида
signals = 5.0 * sin(0.5 * radians(count));
// прямоугольный сигнал
// if (count % 100 == 0) n = !n; // каждые 100 тиков инвертируем сигнал
// signals = flag * 5; //амплитуда сигнала 5
}
float noise() {
noises = signals;
// постоянный шум
// noises += (random(-9, 9) / 10.0);
// случайные выбросы
if (!random(10)) noises += random(-5, 5);
return noises;
}
float median(float newVal) {
static float buf[3];
static byte count = 0;
buf[count] = newVal;
if (++count >= 3) count = 0;
float a = buf[0];
float b = buf[1];
float c = buf[2];
float middle;
if ((a <= b) && (a <= c)) {
middle = (b <= c) ? b : c;
} else {
if ((b <= a) && (b <= c)) {
middle = (a <= c) ? a : c;
} else {
middle = (a <= b) ? a : b;
}
}
return middle;
}
В данном алгоритме с помощью функции Signal() генерируем синусоидальный сигнал, после в функции noise() добавляем единичную помеху и уже в функции median() фильтруем сигнал и смотрим результат на мониторе порта.
Теперь мы применим данный алгоритм для фильтрации прямоугольного сигнала:
int count = 0; // счётчик процесса
bool n = 0;
float signals = 0.0; // чистый сигнал
float noises = 0.0; // сигнал с помехами
float filtrs = 0.0; // отфильтрованный сигнал
float filtrs1 = 0.0; // отфильтрованный сигнал
#define NUM_READ 10
int insert =0;
int j=0;
void setup() {
Serial.begin(9600);
Serial.flush();
}
void loop() {
Signal();
noise();
filtrs = median(noises);
filtrs1=runMiddleArifm(filtrs);
Serial.print(noises);
Serial.print(‘,’);
Serial.println(filtrs1+3);
count++;
}
void Signal() {
// синусоида
signals = 5.0 * sin(0.5 * radians(count));
// прямоугольный сигнал
//if (count % 100 == 0) n = !n; // каждые 100 тиков инвертируем сигнал
// signals = n * 5; //амплитуда сигнала 5
}
float noise() {
noises = signals;
// постоянный шум
noises += (random(-9, 9) / 10.0);
// случайные выбросы
if (!random(10)) noises += random(-5, 5);
return noises;
}
float median(float newVal) {
static float buf[3];
static byte count = 0;
buf[count] = newVal;
if (++count >= 3) count = 0;
float a = buf[0];
float b = buf[1];
float c = buf[2];
float middle;
if ((a <= b) && (a <= c)) {
middle = (b <= c) ? b : c;
} else {
if ((b <= a) && (b <= c)) {
middle = (a <= c) ? a : c;
} else {
middle = (a <= b) ? a : b;
}
}
return middle;
}
float runMiddleArifm(float newVal) { // принимает новое значение
static byte idx = 0; // индекс
static float valArray[NUM_READ]; // массив
valArray[idx] = newVal; // пишем каждый раз в новую ячейку
if (++idx >= NUM_READ) idx = 0; // перезаписывая самое старое значение
float average = 0; // обнуляем среднее
for (int i = 0; i < NUM_READ; i++) {
average += valArray[i]; // суммируем
}
return (float)average / NUM_READ; // возвращаем
}