├── .gitattributes
├── .github
└── workflows
│ └── tg-send.yml
├── LICENSE
├── README.md
├── README_EN.md
├── examples
├── GFilterRA
│ └── GFilterRA.ino
├── GLinear_arrays
│ ├── GLinear_arrays.ino
│ └── excel.jpg
├── GLinear_running
│ └── GLinear_running.ino
├── RingAverage
│ └── RingAverage.ino
├── alphabeta_example
│ └── alphabeta_example.ino
├── fastFilter
│ └── fastFilter.ino
├── filters_comparsion
│ └── filters_comparsion.ino
├── kalman_example
│ └── kalman_example.ino
├── median3_example
│ └── median3_example.ino
└── median_example
│ └── median_example.ino
├── keywords.txt
├── library.properties
└── src
├── GyverFilters.h
└── filters
├── FastFilter.h
├── RingAverage.h
├── alfaBeta.h
├── kalman.h
├── linear.h
├── median.h
├── median3.h
└── runningAverage.h
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/workflows/tg-send.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Telegram Message
3 | on:
4 | release:
5 | types: [published]
6 | jobs:
7 | build:
8 | name: Send Message
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: send telegram message on push
12 | uses: appleboy/telegram-action@master
13 | with:
14 | to: ${{ secrets.TELEGRAM_TO }}
15 | token: ${{ secrets.TELEGRAM_TOKEN }}
16 | disable_web_page_preview: true
17 | message: |
18 | ${{ github.event.repository.name }} v${{ github.event.release.tag_name }}
19 | ${{ github.event.release.body }}
20 | https://github.com/${{ github.repository }}
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 AlexGyver
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/GyverLibs/GyverFilters/releases/latest/download/GyverFilters.zip)
2 | [](https://registry.platformio.org/libraries/gyverlibs/GyverFilters)
3 | [](https://alexgyver.ru/)
4 | [](https://alexgyver.ru/support_alex/)
5 | [](https://github-com.translate.goog/GyverLibs/GyverFilters?_x_tr_sl=ru&_x_tr_tl=en)
6 |
7 | [](https://t.me/GyverLibs)
8 |
9 | # GyverFilters
10 | GyverFilters - библиотека с некоторыми удобными фильтрами для Arduino
11 | - GFilterRA - компактная альтернатива фильтра экспоненциальное бегущее среднее (Running Average)
12 | - GMedian3 - быстрый медианный фильтр 3-го порядка (отсекает выбросы)
13 | - GMedian - медианный фильтр N-го порядка. Порядок настраивается в GyverFilters.h - MEDIAN_FILTER_SIZE
14 | - GABfilter - альфа-бета фильтр (разновидность Калмана для одномерного случая)
15 | - GKalman - упрощённый Калман для одномерного случая (на мой взгляд лучший из фильтров)
16 | - GLinear - линейная аппроксимация методом наименьших квадратов для двух массивов
17 | - FastFilter - быстрый целочисленный экспоненциальный фильтр
18 | - RingAverage - бегущее среднее с кольцевым буфером (не работает для float!)
19 |
20 | Основано на [уроке по цифровым фильтрам](https://alexgyver.ru/lessons/filters/)
21 |
22 | ### Совместимость
23 | Совместима со всеми Arduino платформами (используются Arduino-функции)
24 |
25 | ### Документация
26 | К библиотеке есть [расширенная документация](https://alexgyver.ru/GyverFilters/)
27 |
28 | ## Содержание
29 | - [Установка](#install)
30 | - [Использование](#usage)
31 | - [Версии](#versions)
32 | - [Баги и обратная связь](#feedback)
33 |
34 |
35 | ## Установка
36 | - Библиотеку можно найти по названию **GyverFilters** и установить через менеджер библиотек в:
37 | - Arduino IDE
38 | - Arduino IDE v2
39 | - PlatformIO
40 | - [Скачать библиотеку](https://github.com/GyverLibs/GyverFilters/archive/refs/heads/main.zip) .zip архивом для ручной установки:
41 | - Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
42 | - Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32)
43 | - Распаковать и положить в *Документы/Arduino/libraries/*
44 | - (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив
45 | - Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA)
46 | ### Обновление
47 | - Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи
48 | - Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить"
49 | - Вручную: **удалить папку со старой версией**, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам!
50 |
51 |
52 |
53 | ## Использование
54 | ```cpp
55 | // =========== ALPHA-BETTA alfaBeta.h ===========
56 | // период дискретизации (измерений), process variation, noise variation
57 | GABfilter(float delta, float sigma_process, float sigma_noise);
58 |
59 | // период дискретизации (измерений), process variation, noise variation
60 | void setParameters(float delta, float sigma_process, float sigma_noise);
61 |
62 | // возвращает фильтрованное значение
63 | float filtered(float value);
64 |
65 | // ========== FAST FILTER FastFilter.h ==========
66 | FastFilter;
67 | FastFilter(uint8_t k = 20); // коэффициент 0-31, dt 0
68 | FastFilter(uint8_t k = 20, uint16_t dt = 0); // коэффициент 0-31, dt в миллисекундах
69 |
70 | void setK(uint8_t k); // коэффициент 0-31
71 | void setDt(uint16_t dt); // установить период фильтрации в мс
72 | void setPass(uint8_t pass); // установить режим пропуска (FF_PASS_MAX / FF_PASS_MIN)
73 | void setRaw(long raw); // установить исходное значение для фильтрации
74 | void setFil(long fil); // установить фильтрованное значение
75 | bool checkPass(long val); // проверка на переполнение
76 | void compute(); // расчёт по таймеру
77 | void computeNow(); // произвести расчёт сейчас
78 | int getFil(); // получить фильтрованное значение
79 | int getRaw(); // получить последнее сырое значение
80 |
81 | // =========== SIMPLE KALMAN kalman.h ===========
82 | // разброс измерения, разброс оценки, скорость изменения значений
83 | GKalman(float mea_e, float est_e, float q);
84 | // разброс измерения, скорость изменения значений (разброс измерения принимается равным разбросу оценки)
85 | GKalman(float mea_e, float q);
86 |
87 | // разброс измерения, разброс оценки, скорость изменения значений
88 | void setParameters(float mea_e, float est_e, float q);
89 |
90 | // разброс измерения, скорость изменения значений (разброс измерения принимается равным разбросу оценки)
91 | void setParameters(float mea_e, float q);
92 |
93 | // возвращает фильтрованное значение
94 | float filtered(float value);
95 |
96 | // ======== LINEAR APPROXIMATION linear.h =======
97 | GLinear<тип_данных> filter;
98 |
99 | void compute(*x_array, *y_array, arrSize); // аппроксимировать
100 | float getA(); // получить коэффициент А
101 | float getB(); // получить коэффициент В
102 | float getDelta(); // получить аппроксимированное изменение
103 |
104 | // ============= MEDIAN N median.h ==============
105 | GMedian<порядок, тип_данных> median;
106 |
107 | тип_данных filtered(тип_данных value); // получить результат
108 |
109 | // ============= MEDIAN 3 median3.h ==============
110 | GMedian3<тип_данных> median;
111 |
112 | тип_данных filtered(тип_данных value); // получить результат
113 |
114 | // ========= RING AVERAGE RingAverage.h =========
115 | RingAverage<тип_данных, порядок> filter;
116 | // не работает для float!
117 |
118 | тип_данных filtered(тип_данных val); // получить результат
119 | float filteredFloat(тип_данных val); // получить результат float
120 |
121 | // ====== RUNNING AVERAGE runningAverage.h ======
122 | GFilterRA filter;
123 | GFilterRA(float coef); // установить коэффициент
124 | GFilterRA(float coef, uint16_t interval); // установить коэффициент и период
125 |
126 | void setCoef(float coef); // установить коэффициент
127 | void setPeriod(uint16_t interval); // установить период
128 | float filteredTime(float value); // получить результат по таймеру
129 | float filtered(float value); // получить результат сейчас
130 | ```
131 |
132 |
133 | ## Версии
134 | - v1.6 от 12.11.2019
135 | - v1.7: исправлен GLinear
136 | - v1.8: небольшие улучшения
137 | - v2.0:
138 | - Улучшен и исправлен median и median3
139 | - Улучшен linear
140 | - Смотрите примеры! Использование этих фильтров чуть изменилось
141 | - v2.1: Исправлен расчёт дельты в линейном фильтре
142 | - v2.2: Исправлена ошибка компиляции
143 | - v3.0: Добавлен FastFilter и RingAverage
144 | - v3.1: Оптимизация кода у многих фильтров
145 | - v3.1.1: Исправлена ошибочка
146 | - v3.2: мелкие фиксы, обновлена документация
147 |
148 |
149 | ## Баги и обратная связь
150 | При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru)
151 | Библиотека открыта для доработки и ваших **Pull Request**'ов!
152 |
153 |
154 | При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать:
155 | - Версия библиотеки
156 | - Какой используется МК
157 | - Версия SDK (для ESP)
158 | - Версия Arduino IDE
159 | - Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде
160 | - Какой код загружался, какая работа от него ожидалась и как он работает в реальности
161 | - В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код
162 |
--------------------------------------------------------------------------------
/README_EN.md:
--------------------------------------------------------------------------------
1 | This is an automatic translation, may be incorrect in some places. See sources and examples!
2 |
3 | # GyverFilters
4 | GyverFilters - library with some handy filters for Arduino
5 | - GFilterRA - a compact alternative to the filter exponential running average (Running Average)
6 | - GMedian3 - fast 3rd order median filter (cuts out outliers)
7 | - GMedian - N-th order median filter. The order is configured in GyverFilters.h - MEDIAN_FILTER_SIZE
8 | - GABfilter - alpha-beta filter (Kalman version for one-dimensional case)
9 | - GKalman - a simplified Kalman for the one-dimensional case (in my opinion the best of the filters)
10 | - GLinear - linear least squares approximation for two arrays
11 | - FastFilter - fast integer exponential filter
12 | - RingAverage - running average with ring buffer
13 |
14 | Based on [Digital Filters Tutorial](https://alexgyver.ru/lessons/filters/)
15 |
16 | ### Compatibility
17 | Compatible with all Arduino platforms (using Arduino functions)
18 |
19 | ### Documentation
20 | The library has [extended documentation](https://alexgyver.ru/GyverFilters/)
21 |
22 | ## Content
23 | - [Install](#install)
24 | - [Usage](#usage)
25 | - [Versions](#versions)
26 | - [Bugs and feedback](#feedback)
27 |
28 |
29 | ## Installation
30 | - The library can be found by the name **GyverFilters** and installed via the library manager in:
31 | - Arduino IDE
32 | - Arduino IDE v2
33 | - PlatformIO
34 | - [Download library](https://github.com/GyverLibs/GyverFilters/archive/refs/heads/main.zip) .zip archive forfor manual setting:
35 | - Unzip and put in *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
36 | - Unzip and put in *C:\Program Files\Arduino\libraries* (Windows x32)
37 | - Unpack and put in *Documents/Arduino/libraries/*
38 | - (Arduino IDE) automatic installation from .zip: *Sketch/Include library/Add .ZIP library…* and specify the downloaded archive
39 | - Read more detailed instructions for installing libraries [here] (https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE% D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA)
40 |
41 |
42 | ## Usage
43 | ```cpp
44 | // =========== ALPHA-BETTA alfaBeta.h ===========
45 | // sampling period (measurements), process variation, noise variation
46 | GABfilter(float delta, float sigma_process, float sigma_noise);
47 |
48 | // sampling period (measurements), process variation, noise variation
49 | void setParameters(float delta, float sigma_process, float sigma_noise);
50 |
51 | // returns the filtered value
52 | float filtered(float value);
53 |
54 | // ========== FAST FILTER FastFilter.h ==========
55 | fastfilter;
56 | FastFilter(uint8_t k = 20); // coefficient 0-31, dt 0
57 | FastFilter(uint8_t k = 20, uint16_t dt = 0); // coefficient 0-31, dt in milliseconds
58 |
59 | void setK(uint8_tk); // coefficient 0-31
60 | void setDt(uint16_t dt); // set filtering period in ms
61 | void setPass(uint8_t pass); // set pass mode (FF_PASS_MAX / FF_PASS_MIN)
62 | void setRaw(long raw); // set initial value for filtering
63 | void setFil(long fil); // set filtered value
64 | bool checkPass(long val); // check for overflow
65 | void compute(); // timer calculation
66 | void computeNow(); // calculate now
67 | int getfil(); // get filtered value
68 | int getRaw(); // get last raw value
69 |
70 | // =========== SIMPLE KALMAN kalman.h ===========
71 | // measurement spread, estimate spread, speedvalue changes
72 | GKalman(float mea_e, float est_e, float q);
73 | // measurement scatter, rate of change of values (measurement scatter is taken equal to the estimate scatter)
74 | GKalman(float mea_e, float q);
75 |
76 | // measurement spread, estimate spread, rate of change of values
77 | void setParameters(float mea_e, float est_e, float q);
78 |
79 | // measurement scatter, rate of change of values (measurement scatter is taken equal to the estimate scatter)
80 | void setParameters(float mea_e, float q);
81 |
82 | // returns the filtered value
83 | float filtered(float value);
84 |
85 | // ======== LINEAR APPROXIMATION linear.h =======
86 | GLinear filter;
87 |
88 | void compute(*x_array, *y_array, arrSize); // approximate
89 | float getA(); // get factor A
90 | float getB(); // get factor B
91 | float getDelta(); // get approximate change
92 |
93 | // ============= MEDIAN N median.h ==============
94 | GMedian median;
95 |
96 | data_type filtered(data_type value); // get result
97 |
98 | // ============= MEDIAN 3 median3.h ==============
99 | GMedian3 median;
100 |
101 | data_type filtered(data_type value); // get result
102 |
103 | // ========= RING AVERAGE RingAverage.h =========
104 | RingAverage filter;
105 |
106 | datatype filtered(datatype val); // get result
107 | float filteredFloat(datatype val); // get float result
108 |
109 | // ====== RUNNING AVERAGE runningAverage.h ======
110 | GFilterRA filter;
111 | GFilterRA(floatcoef); // set coefficient
112 | GFilterRA(float coef, uint16_t interval); // set coefficient and period
113 |
114 | void setCoef(floatcoef); // set coefficient
115 | void setPeriod(uint16_t interval); // set period
116 | float filteredTime(float value); // get result by timer
117 | float filtered(float value); // get result now
118 | ```
119 |
120 |
121 | ## Versions
122 | - v1.6 from 11/12/2019
123 | - v1.7: fixed GLinear
124 | - v1.8: minor improvements
125 | - v2.0:
126 | -Improved and fixed median and median3
127 | - Improved linear
128 | - See examples! The use of these filters has changed slightly
129 | - v2.1: Fixed delta calculation in linear filter
130 | - v2.2: Compilation error fixed
131 | - v3.0: Added FastFilter and RingAverage
132 | - v3.1: Code optimization for many filters
133 | - v3.1.1: Bug fixed
134 | - v3.2: minor fixes, updated documentation
135 |
136 |
137 | ## Bugs and feedback
138 | When you find bugs, create an **Issue**, or better, immediately write to the mail [alex@alexgyver.ru](mailto:alex@alexgyver.ru)
139 | The library is open for revision and your **Pull Request**'s!
--------------------------------------------------------------------------------
/examples/GFilterRA/GFilterRA.ino:
--------------------------------------------------------------------------------
1 | #include "GyverFilters.h"
2 | GFilterRA analog0; // фильтр назовём analog0
3 |
4 | void setup() {
5 | Serial.begin(9600);
6 |
7 | // установка коэффициента фильтрации (0.0... 1.0). Чем меньше, тем плавнее фильтр
8 | analog0.setCoef(0.01);
9 |
10 | // установка шага фильтрации (мс). Чем меньше, тем резче фильтр
11 | analog0.setStep(10);
12 | }
13 |
14 | void loop() {
15 | Serial.println(analog0.filteredTime(analogRead(0)));
16 | }
17 |
--------------------------------------------------------------------------------
/examples/GLinear_arrays/GLinear_arrays.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Пример линейной аппроксимации методом наименьших квадратов
3 | Два массива: по оси Х и по оси У
4 | Линейная аппроксимация повозоляет получить уравнение прямой,
5 | равноудалённой от точек на плоскости ХУ. Удобно для расчёта
6 | роста изменяющейся шумящей величины. Уравнение вида у = A*x + B
7 | В папке с данным примером есть скриншот из excel,
8 | иллюстрирующий работу аппроксимации с такими же исходными
9 | */
10 |
11 | // два массива с данными (одинаковой размероности и размера)
12 | int x_array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
13 | int y_array[] = {1, 5, 2, 8, 3, 9, 10, 5, 15, 12};
14 |
15 | #include
16 | GLinear test; // указываем тип данных в <>
17 |
18 | void setup() {
19 | Serial.begin(9600);
20 |
21 | // передаём массивы и размер одного из них
22 | test.compute((int*)x_array, (int*)y_array, 10);
23 |
24 | // Уравнение вида у = A*x + B
25 | Serial.println(test.getA()); // получить коэффициент А
26 | Serial.println(test.getB()); // получить коэффициент В
27 | Serial.println(test.getDelta()); // получить изменение (аппроксимированное)
28 | }
29 |
30 | void loop() {
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/examples/GLinear_arrays/excel.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GyverLibs/GyverFilters/a66f63b561c219b303d96894a0b87ee0611cf246/examples/GLinear_arrays/excel.jpg
--------------------------------------------------------------------------------
/examples/GLinear_running/GLinear_running.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Пример линейной аппроксимации методом наименьших квадратов
3 | Два массива: по оси Х и по оси У
4 | Наполнение массивов осуществляется динамически: сдвигом и записью в крайнюю ячейку,
5 | то есть аппроксимация по последним ARRAY_SIZE изменениям!!
6 | */
7 | #define ARRAY_SIZE 10 // размер пространства для аппроксимации
8 |
9 | // два массива с данными (одинаковой размероности и размера)
10 | int x_array[ARRAY_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // ось x от 1 до 10, допустим СЕКУНД
11 | int y_array[ARRAY_SIZE]; // значения по оси У будем брать с датчика
12 |
13 | #include
14 | GLinear test; // указываем тип данных в <>
15 |
16 | void setup() {
17 | Serial.begin(9600);
18 | }
19 |
20 | void loop() {
21 | for (byte i = 0; i < ARRAY_SIZE - 1; i++) { // счётчик от 0 до ARRAY_SIZE
22 | y_array[i] = y_array[i + 1]; // сдвинуть массив давлений КРОМЕ ПОСЛЕДНЕЙ ЯЧЕЙКИ на шаг назад
23 | }
24 | // последний элемент массива теперь - новое значение (просто с аналог. датчика)
25 | y_array[ARRAY_SIZE - 1] = analogRead(0);
26 |
27 | // передаём массивы и размер одного из них
28 | test.compute((int*)x_array, (int*)y_array, sizeof(x_array));
29 |
30 | // по нашим исходным данным это будет производная, т.е. "изменение единиц в секунду"
31 | Serial.println(test.getDelta()); // получить изменение (аппроксимированное)
32 |
33 | delay(1000); // секундная задержка
34 | }
35 |
--------------------------------------------------------------------------------
/examples/RingAverage/RingAverage.ino:
--------------------------------------------------------------------------------
1 | #include "GyverFilters.h"
2 | RingAverage fil;
3 |
4 | void setup() {
5 | Serial.begin(9600);
6 | }
7 |
8 | void loop() {
9 | Serial.println(fil.filtered(random(50)));
10 | delay(10);
11 | }
12 |
--------------------------------------------------------------------------------
/examples/alphabeta_example/alphabeta_example.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Пример альфа-бета фильтра
3 | */
4 |
5 | #include "GyverFilters.h"
6 |
7 | // параметры: период дискретизации (измерений), process variation, noise variation
8 | GABfilter testFilter(0.08, 40, 1);
9 |
10 | void setup() {
11 | Serial.begin(9600);
12 | }
13 |
14 | void loop() {
15 | delay(80);
16 | int value = analogRead(0);
17 | value += random(2) * random(-1, 2) * random(10, 70);
18 | Serial.print("$");
19 | Serial.print(value);
20 | Serial.print(" ");
21 | value = testFilter.filtered((int)value);
22 | Serial.print(value);
23 | Serial.println(";");
24 | }
25 |
--------------------------------------------------------------------------------
/examples/fastFilter/fastFilter.ino:
--------------------------------------------------------------------------------
1 | // быстрый запаздывающйи фильтр
2 |
3 | #include
4 | FastFilter fil(29); // 0-32
5 | void setup() {
6 | Serial.begin(9600);
7 | fil.setK(30);
8 | fil.setRaw(1000);
9 | fil.setFil(0);
10 | }
11 |
12 | void loop() {
13 | fil.computeNow();
14 | Serial.println(fil.getFil());
15 | delay(100);
16 | }
17 |
--------------------------------------------------------------------------------
/examples/filters_comparsion/filters_comparsion.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Сравнение калмана и бегущего среднего
3 | */
4 | #include "GyverFilters.h"
5 |
6 | // параметры: разброс измерения, разброс оценки, скорость изменения значений
7 | // разброс измерения: шум измерений
8 | // разброс оценки: подстраивается сам, можно поставить таким же как разброс измерения
9 | // скорость изменения значений: 0.001-1, варьировать самому
10 |
11 | GKalman kalman(90, 90, 0.5);
12 | GFilterRA average(0.5, 80);
13 |
14 | void setup() {
15 | Serial.begin(9600);
16 | }
17 |
18 | void loop() {
19 | int value = analogRead(0);
20 | value += random(2) * random(-1, 2) * random(50, 100);
21 | Serial.print("$");
22 | Serial.print(value);
23 | Serial.print(" ");
24 |
25 | Serial.print((int)kalman.filtered(value));
26 | Serial.print(" ");
27 | Serial.print((int)average.filtered(value));
28 | Serial.println(";");
29 | delay(80);
30 | }
31 |
--------------------------------------------------------------------------------
/examples/kalman_example/kalman_example.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Пример простого одномерного фильтра
3 | */
4 |
5 | #include "GyverFilters.h"
6 |
7 | // параметры: разброс измерения, разброс оценки, скорость изменения значений
8 | // разброс измерения: шум измерений
9 | // разброс оценки: подстраивается сам, можно поставить таким же как разброс измерения
10 | // скорость изменения значений: 0.001-1, варьировать самому
11 |
12 | GKalman testFilter(40, 40, 0.5);
13 |
14 | // также может быть объявлен как (разброс измерения, скорость изменения значений)
15 | // GKalman testFilter(40, 0.5);
16 |
17 | void setup() {
18 | Serial.begin(9600);
19 | }
20 |
21 | void loop() {
22 | delay(80);
23 | int value = analogRead(0);
24 | value += random(2) * random(-1, 2) * random(10, 70);
25 | Serial.print("$");
26 | Serial.print(value);
27 | Serial.print(" ");
28 | value = testFilter.filtered((int)value);
29 | Serial.print(value);
30 | Serial.println(";");
31 | }
32 |
--------------------------------------------------------------------------------
/examples/median3_example/median3_example.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Пример использования быстрого медианного фильтра 3 порядка
3 | */
4 |
5 | #include "GyverFilters.h"
6 | GMedian3 testFilter; // указываем тип данных в <>
7 |
8 | void setup() {
9 | Serial.begin(9600);
10 | }
11 |
12 | void loop() {
13 | int value = analogRead(0);
14 | // добавляем шум "выбросы"
15 | value += random(2) * random(2) * random(-1, 2) * random(50, 250);
16 | Serial.print(value);
17 | Serial.print(',');
18 | value = testFilter.filtered(value);
19 | Serial.println(value);
20 | delay(80);
21 | }
22 |
--------------------------------------------------------------------------------
/examples/median_example/median_example.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Пример использования медианного фильтра.
3 | */
4 |
5 | #include "GyverFilters.h"
6 |
7 | // указываем размер окна и тип данных в <>
8 | GMedian<10, int> testFilter;
9 |
10 | void setup() {
11 | Serial.begin(9600);
12 | }
13 |
14 | void loop() {
15 | delay(80);
16 | int value = analogRead(0);
17 | // добавляем шум "выбросы"
18 | value += random(2) * random(2) * random(-1, 2) * random(50, 250);
19 | Serial.print(value);
20 | Serial.print(',');
21 | value = testFilter.filtered(value);
22 | Serial.println(value);
23 | }
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 | #######################################
2 | # Syntax Coloring Map For GyverFilters
3 | #######################################
4 |
5 | #######################################
6 | # Datatypes (KEYWORD1)
7 | #######################################
8 |
9 | GyverFilters KEYWORD1
10 | GFilterRA KEYWORD1
11 | GMedian3 KEYWORD1
12 | GMedian KEYWORD1
13 | GABfilter KEYWORD1
14 | GKalman KEYWORD1
15 | GLinear KEYWORD1
16 | RingAverage KEYWORD1
17 | FastFilter KEYWORD1
18 |
19 | #######################################
20 | # Methods and Functions (KEYWORD2)
21 | #######################################
22 |
23 | setK KEYWORD2
24 | setCoef KEYWORD2
25 | setPeriod KEYWORD2
26 | filteredTime KEYWORD2
27 | filtered KEYWORD2
28 | setParameters KEYWORD2
29 | getA KEYWORD2
30 | getB KEYWORD2
31 | getDelta KEYWORD2
32 | setRaw KEYWORD2
33 | setFil KEYWORD2
34 | computeNow KEYWORD2
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=GyverFilters
2 | version=3.2
3 | author=AlexGyver
4 | maintainer=AlexGyver
5 | sentence=Library with few filters for data processing
6 | paragraph=Library with few filters for data processing
7 | category=Data Processing
8 | url=https://github.com/GyverLibs/GyverFilters
9 | architectures=*
--------------------------------------------------------------------------------
/src/GyverFilters.h:
--------------------------------------------------------------------------------
1 | /*
2 | GyverFilters - библиотека с некоторыми удобными фильтрами для Arduino
3 | Документация: https://alexgyver.ru/gyverfilters/
4 | GitHub: https://github.com/GyverLibs/GyverFilters
5 | - GFilterRA - компактная альтернатива фильтра экспоненциальное бегущее среднее (Running Average)
6 | - GMedian3 - быстрый медианный фильтр 3-го порядка (отсекает выбросы)
7 | - GMedian - медианный фильтр N-го порядка. Порядок настраивается в GyverFilters.h - MEDIAN_FILTER_SIZE
8 | - GABfilter - альфа-бета фильтр (разновидность Калмана для одномерного случая)
9 | - GKalman - упрощённый Калман для одномерного случая (на мой взгляд лучший из фильтров)
10 | - GLinear - линейная аппроксимация методом наименьших квадратов для двух массивов
11 | - FastFilter - быстрый целочисленный экспоненциальный фильтр
12 | - RingAverage - бегущее среднее с кольцевым буфером
13 |
14 | AlexGyver, alex@alexgyver.ru
15 | https://alexgyver.ru/
16 | MIT License
17 |
18 | Версии:
19 | v1.6 от 12.11.2019
20 | v1.7: исправлен GLinear
21 | v1.8: небольшие улучшения
22 | v2.0:
23 | - Улучшен и исправлен median и median3
24 | - Улучшен linear
25 | - Смотрите примеры! Использование этих фильтров чуть изменилось
26 | v2.1: Исправлен расчёт дельты в линейном фильтре
27 | v2.2: Исправлена ошибка компиляции
28 | v3.0: Добавлен FastFilter и RingAverage
29 | v3.1: Оптимизация кода у многих фильтров
30 | v3.1.1: Исправлена ошибочка
31 | v3.2: мелкие фиксы, обновлена документация
32 | */
33 |
34 | #ifndef _GyverFilters_h
35 | #define _GyverFilters_h
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #endif
--------------------------------------------------------------------------------
/src/filters/FastFilter.h:
--------------------------------------------------------------------------------
1 | // быстрый целочисленный экспоненциальный фильтр
2 |
3 | #ifndef _FastFilter_h
4 | #define _FastFilter_h
5 |
6 | #define FF_PASS_MAX 1
7 | #define FF_PASS_MIN 2
8 |
9 | class FastFilter {
10 | public:
11 | // коэффициент 0-31
12 | FastFilter(uint8_t k = 20, uint16_t dt = 0) {
13 | setK(k);
14 | setDt(dt);
15 | }
16 |
17 | // коэффициент 0-31
18 | void setK(uint8_t k) {
19 | _k1 = k;
20 | _k2 = 32 - k;
21 | }
22 |
23 | // установить период фильтрации
24 | void setDt(uint16_t dt) {
25 | _dt = dt;
26 | }
27 |
28 | // установить режим пропуска (FF_PASS_MAX / FF_PASS_MIN)
29 | void setPass(uint8_t pass) {
30 | _pass = pass;
31 | }
32 |
33 | // установить исходное значение для фильтрации
34 | void setRaw(long raw) {
35 | _raw = raw;
36 | }
37 |
38 | // установить фильтрованное значение
39 | void setFil(long fil) {
40 | _raw_f = fil;
41 | }
42 |
43 | // проверка на переполнение
44 | bool checkPass(long val) {
45 | if (_pass == FF_PASS_MAX && val > _raw_f) {
46 | _raw_f = val;
47 | return 1;
48 | } else if (_pass == FF_PASS_MIN && val < _raw_f) {
49 | _raw_f = val;
50 | return 1;
51 | }
52 | return 0;
53 | }
54 |
55 | // расчёт по таймеру
56 | void compute() {
57 | if (_dt == 0 || millis() - _tmr >= _dt) {
58 | _tmr = millis();
59 | computeNow();
60 | }
61 | }
62 |
63 | // произвести расчёт сейчас
64 | void computeNow() {
65 | _raw_f = ((long)_k1 * _raw_f + _k2 * _raw) >> 5;
66 | }
67 |
68 | // получить фильтрованное значение
69 | long getFil() {
70 | return _raw_f;
71 | }
72 |
73 | // получить последнее сырое значение
74 | long getRaw() {
75 | return _raw;
76 | }
77 |
78 | private:
79 | uint32_t _tmr = 0;
80 | uint16_t _dt = 0;
81 | uint8_t _k1 = 20, _k2 = 12;
82 | uint8_t _pass = 0;
83 | long _raw_f = 0, _raw = 0;
84 | };
85 | #endif
--------------------------------------------------------------------------------
/src/filters/RingAverage.h:
--------------------------------------------------------------------------------
1 | // бегущее среднее с кольцевым буфером
2 |
3 | #ifndef _RingAverage_h
4 | #define _RingAverage_h
5 |
6 | template < typename TYPE, int SIZE >
7 | class RingAverage {
8 | public:
9 | RingAverage() {
10 | for (int i = 0; i < SIZE; i++) buf[i] = 0;
11 | }
12 | TYPE filtered(TYPE val) {
13 | if (++t >= SIZE) t = 0; // перемотка t
14 | sum -= buf[t]; // вычитаем старое
15 | sum += val; // прибавляем новое
16 | buf[t] = val; // запоминаем в массив
17 | return (sum / SIZE);
18 | }
19 | float filteredFloat(TYPE val) {
20 | if (++t >= SIZE) t = 0; // перемотка t
21 | sum -= buf[t]; // вычитаем старое
22 | sum += val; // прибавляем новое
23 | buf[t] = val; // запоминаем в массив
24 | return ((float)sum / SIZE);
25 | }
26 |
27 | private:
28 | TYPE buf[SIZE];
29 | int32_t sum = 0;
30 | int t = 0;
31 | };
32 | #endif
--------------------------------------------------------------------------------
/src/filters/alfaBeta.h:
--------------------------------------------------------------------------------
1 | // альфа-бета фильтр
2 |
3 | #ifndef _GABfilter_h
4 | #define _GABfilter_h
5 |
6 | class GABfilter {
7 | public:
8 | // период дискретизации (измерений), process variation, noise variation
9 | GABfilter(float delta, float sigma_process, float sigma_noise) {
10 | setParameters(delta, sigma_process, sigma_noise);
11 | }
12 |
13 | // период дискретизации (измерений), process variation, noise variation
14 | void setParameters(float delta, float sigma_process, float sigma_noise) {
15 | dt = delta;
16 | float lambda = (float)sigma_process * dt * dt / sigma_noise;
17 | float r = (4.0 + lambda - sqrt(8.0 * lambda + lambda * lambda)) / 4.0;
18 | a = 1.0 - r * r;
19 | b = 2.0 * (2.0 - a) - 4.0 * sqrt(1.0 - a);
20 | }
21 |
22 | // возвращает фильтрованное значение
23 | float filtered(float value) {
24 | xm = value;
25 | xk = xk_1 + (float)vk_1 * dt;
26 | vk = vk_1;
27 | rk = xm - xk;
28 | xk += (float)a * rk;
29 | vk += (float)b * rk / dt;
30 | xk_1 = xk;
31 | vk_1 = vk;
32 | return xk_1;
33 | }
34 |
35 | private:
36 | float dt;
37 | float xk_1, vk_1, a, b;
38 | float xk, vk, rk;
39 | float xm;
40 | };
41 | #endif
--------------------------------------------------------------------------------
/src/filters/kalman.h:
--------------------------------------------------------------------------------
1 | // упрощённый Калман для одномерного случая
2 |
3 | #ifndef _GKalman_h
4 | #define _GKalman_h
5 |
6 | class GKalman {
7 | public:
8 | // разброс измерения, разброс оценки, скорость изменения значений
9 | GKalman(float mea_e, float est_e, float q) {
10 | setParameters(mea_e, est_e, q);
11 | }
12 |
13 | // разброс измерения, скорость изменения значений (разброс измерения принимается равным разбросу оценки)
14 | GKalman(float mea_e, float q) {
15 | setParameters(mea_e, mea_e, q);
16 | }
17 |
18 | // разброс измерения, разброс оценки, скорость изменения значений
19 | void setParameters(float mea_e, float est_e, float q) {
20 | _err_measure = mea_e;
21 | _err_estimate = est_e;
22 | _q = q;
23 | }
24 |
25 | // разброс измерения, скорость изменения значений (разброс измерения принимается равным разбросу оценки)
26 | void setParameters(float mea_e, float q) {
27 | setParameters(mea_e, mea_e, q);
28 | }
29 |
30 | // возвращает фильтрованное значение
31 | float filtered(float value) {
32 | float _kalman_gain, _current_estimate;
33 | _kalman_gain = _err_estimate / (_err_estimate + _err_measure);
34 | _current_estimate = _last_estimate + _kalman_gain * (value - _last_estimate);
35 | _err_estimate = (1.0 - _kalman_gain)*_err_estimate + fabs(_last_estimate-_current_estimate)*_q;
36 | _last_estimate=_current_estimate;
37 | return _current_estimate;
38 | }
39 |
40 | private:
41 | float _err_measure = 0.0;
42 | float _err_estimate = 0.0;
43 | float _q = 0.0;
44 | float _last_estimate = 0.0;
45 | };
46 | #endif
--------------------------------------------------------------------------------
/src/filters/linear.h:
--------------------------------------------------------------------------------
1 | // линейная аппроксимация методом наименьших квадратов
2 |
3 | #ifndef _GLinear_h
4 | #define _GLinear_h
5 |
6 | template < typename TYPE >
7 | class GLinear {
8 | public:
9 | // аппроксимировать
10 | void compute(TYPE *x_array, TYPE *y_array, int arrSize) {
11 | int32_t sumX = 0, sumY = 0, sumX2 = 0, sumXY = 0;
12 | for (int i = 0; i < arrSize; i++) { // для всех элементов массива
13 | sumX += x_array[i];
14 | sumY += (int32_t)y_array[i];
15 | sumX2 += x_array[i] * x_array[i];
16 | sumXY += (int32_t)y_array[i] * x_array[i];
17 | }
18 | a = (int32_t)arrSize * sumXY - (int32_t)sumX * sumY; // расчёт коэффициента наклона приямой
19 | a = (float)a / (arrSize * sumX2 - sumX * sumX);
20 | b = (float)(sumY - (float)a * sumX) / arrSize;
21 | delta = a * (x_array[arrSize-1] - x_array[0]); // расчёт изменения
22 | }
23 |
24 | // получить коэффициент А
25 | float getA() {
26 | return a;
27 | }
28 |
29 | // получить коэффициент В
30 | float getB() {
31 | return b;
32 | }
33 |
34 | // получить аппроксимированное изменение
35 | float getDelta() {
36 | return delta;
37 | }
38 |
39 | private:
40 | float a, b, delta;
41 | };
42 |
43 | /*
44 | Сам алгоритм выглядит так:
45 | void loop() {
46 | sumX = 0;
47 | sumY = 0;
48 | sumX2 = 0;
49 | sumXY = 0;
50 | for (int i = 0; i < steps; i++) {
51 | sumX += X[i];
52 | sumY += Y[i];
53 | sumX2 += X[i] * X[i];
54 | sumXY += X[i] * Y[i];
55 | }
56 | a = (steps * sumXY - sumX * sumY) / (steps * sumX2 - sumX * sumX);
57 | b = (sumY - a * sumX) / steps;
58 | int delta = steps * a;
59 | }
60 | */
61 | #endif
--------------------------------------------------------------------------------
/src/filters/median.h:
--------------------------------------------------------------------------------
1 | // медианный фильтр N-го порядка
2 |
3 | #ifndef _GMedian_h
4 | #define _GMedian_h
5 |
6 | template < uint8_t SIZE, typename TYPE >
7 | class GMedian {
8 | public:
9 | TYPE filtered(TYPE newVal) {
10 | buffer[_count] = newVal;
11 | if ((_count < SIZE - 1) && (buffer[_count] > buffer[_count + 1])) {
12 | for (int i = _count; i < SIZE - 1; i++) {
13 | if (buffer[i] > buffer[i + 1]) {
14 | TYPE buff = buffer[i];
15 | buffer[i] = buffer[i + 1];
16 | buffer[i + 1] = buff;
17 | }
18 | }
19 | } else {
20 | if ((_count > 0) && (buffer[_count - 1] > buffer[_count])) {
21 | for (int i = _count; i > 0; i--) {
22 | if (buffer[i] < buffer[i - 1]) {
23 | TYPE buff = buffer[i];
24 | buffer[i] = buffer[i - 1];
25 | buffer[i - 1] = buff;
26 | }
27 | }
28 | }
29 | }
30 | if (++_count >= SIZE) _count = 0;
31 | return buffer[SIZE / 2];
32 | }
33 | private:
34 | TYPE buffer[SIZE];
35 | uint8_t _count = 0;
36 | };
37 | #endif
--------------------------------------------------------------------------------
/src/filters/median3.h:
--------------------------------------------------------------------------------
1 | // быстрый медианный фильтр 3-го порядка
2 |
3 | #ifndef _GMedian3_h
4 | #define _GMedian3_h
5 |
6 | template < typename TYPE >
7 | class GMedian3 {
8 | public:
9 | TYPE filtered(TYPE value) { // возвращает фильтрованное значение
10 | buf[_counter] = value;
11 | if (++_counter > 2) _counter = 0;
12 | return (max(buf[0], buf[1]) == max(buf[1], buf[2])) ? max(buf[0], buf[2]) : max(buf[1], min(buf[0], buf[2]));
13 | }
14 |
15 | private:
16 | TYPE buf[3];
17 | uint8_t _counter = 0;
18 | };
19 | #endif
--------------------------------------------------------------------------------
/src/filters/runningAverage.h:
--------------------------------------------------------------------------------
1 | // экспоненциальное бегущее среднее
2 |
3 | #ifndef _GFilterRA_h
4 | #define _GFilterRA_h
5 |
6 | class GFilterRA {
7 | public:
8 | GFilterRA(){}
9 |
10 | GFilterRA(float coef, uint16_t interval) {
11 | _coef = coef;
12 | _prd = interval;
13 | }
14 |
15 | GFilterRA(float coef) {
16 | _coef = coef;
17 | }
18 |
19 | void setCoef(float coef) {
20 | _coef = coef;
21 | }
22 |
23 | void setPeriod(uint16_t interval) {
24 | _prd = interval;
25 | }
26 |
27 | float filteredTime(float value) {
28 | if (millis() - _tmr >= _prd) {
29 | _tmr += _prd;
30 | filtered(value);
31 | }
32 | return _fil;
33 | }
34 |
35 | float filtered(float value) {
36 | return _fil += (value - _fil) * _coef;
37 | }
38 |
39 | //
40 | void setStep(uint16_t interval) {
41 | _prd = interval;
42 | }
43 |
44 | private:
45 | float _coef = 0.0, _fil = 0.0;
46 | uint32_t _tmr = 0;
47 | uint16_t _prd = 0;
48 | };
49 | #endif
--------------------------------------------------------------------------------