123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- my
- #define MAX(a, b) ((a) > (b)) ? (a) : (b)
- #define MIN(a, b) ((a) < (b)) ? (a) : (b)
- #define MIDDLE(a, b, c) MAX(MAX(MIN(a, b), MIN(a, c)), MIN(b, c))
- func (val) {
- static a1, a2 == 0
- //middle = MIDDLE(val, a1, a2)
- if val < a1 and val < a2
- middle = MIDDLE(val, a1, a2)
- else if val > a1 and a2
- middle = MIDDLE(val, a1, a2)
- else middle = val
- a2 = a1
- a1 = val
- return middle
- }
- ===
- http://chipenable.ru/index.php/embedded-programming/item/203-mediannyy-filtr.html
- uint16_t middle_of_3(uint16_t a, uint16_t b, uint16_t c)
- {
- uint16_t 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;
- }
- ===
- http://www.elcojacobs.com/eleminating-noise-from-sensor-readings-on-arduino-with-digital-filtering/
- выжимки из статьи
- Медианный фильтр:
- сортируем массив значений (например 100) от меньшего к большему (?) и берём среднее.
- автор предлагает скомбинировать медианный фильтр и фильтрацию по среднему:
- сортируем массив значений, берём 10 (из 100) средних и из них считаем среднее.
- The final code to read one sensor:
- #define NUM_READS 100
- float readTemperature(int sensorpin){
- // read multiple values and sort them to take the mode
- int sortedValues[NUM_READS];
- for(int i=0;i<NUM_READS;i++){
- int value = analogRead(sensorpin);
- int j;
- if(value<sortedValues[0] || i==0){
- j=0; //insert at first position
- }
- else{
- for(j=1;j<i;j++){
- if(sortedValues[j-1]<=value && sortedValues[j]>=value){
- // j is insert position
- break;
- }
- }
- }
- for(int k=i;k>j;k--){
- // move all values higher than current reading up one position
- sortedValues[k]=sortedValues[k-1];
- }
- sortedValues[j]=value; //insert current reading
- }
- //return scaled mode of 10 values
- float returnval = 0;
- for(int i=NUM_READS/2-5;i<(NUM_READS/2+5);i++){
- returnval +=sortedValues[i];
- }
- returnval = returnval/10;
- return returnval*1100/1023;
- }
- -=-=-=-=-=-=-=-=-=-
- По своей сути, это похоже на алгоритм, которым я когда-то фильтровал значения
- от счётчика гейгера:
- - считаем среднее в массиве измерений,
- - отбираем из массива только те значения, которые укладываются в +-5% от
- полученного среднего,
- - берём среднее от оставшихся значений.
- кажется я просто занулял неподходящие данные, а потом не учитывал их при
- следующем усреднении.
- какой алгоритм точнее, меньше, быстрее -- хз. можно попробовать на Unicharger-е.
- -=-=-=-=-=-=-=-=-=-
- Addional filtering: IIR Butterworth low pass filters
- (I have changed the filters from second order to third order...)
- для медленно меняющихся процессов он предлагает использовать фильтр нижних
- частот Баттервота 4-го порядка.
- Фильтр Баттервота -- это "infinite impulse response filter" (IIR)
- (а теперь гугльтранслейт)
- Это означает, что каждое выходное значение фильтра рассчитывается из истории
- входных значений и предыдущих выходных значений фильтра.
- Поскольку выходной фильтр используется для вычисления будущих значений,
- влияние любого входного значения на будущие выходные -- есть регрессия к
- бесконечности.
- (конец)
- The implementation of a software Butterworth filter is actually very easy, see
- the code snippet below.
- void updateTemperatures(void){ //called every 200 milliseconds
- fridgeTempFast[0] = fridgeTempFast[1];
- fridgeTempFast[1] = fridgeTempFast[2];
- fridgeTempFast[2] = fridgeTempFast[3];
- fridgeTempFast[3] = readTemperature(fridgePin);
-
- // Butterworth filter with cutoff frequency 0.033*sample frequency (FS=5Hz)
- fridgeTempFiltFast[0] = fridgeTempFiltFast[1];
- fridgeTempFiltFast[1] = fridgeTempFiltFast[2];
- fridgeTempFiltFast[2] = fridgeTempFiltFast[3];
- fridgeTempFiltFast[3] = (fridgeTempFast[0] + fridgeTempFast[3]
- + 3 * (fridgeTempFast[1] + fridgeTempFast[2]) )
- / 1.092799972e+03 + (0.6600489526 * fridgeTempFiltFast[0])
- + (-2.2533982563 * fridgeTempFiltFast[1])
- + ( 2.5860286592 * fridgeTempFiltFast[2]);
-
- fridgeTemperatureActual = fridgeTempFiltFast[3];
-
- beerTempFast[0] = beerTempFast[1];
- beerTempFast[1] = beerTempFast[2];
- beerTempFast[2] = beerTempFast[3];
- beerTempFast[3] = readTemperature(beerPin);
-
- // Butterworth filter with cutoff frequency 0.01*sample frequency (FS=5Hz)
- beerTempFiltFast[0] = beerTempFiltFast[1];
- beerTempFiltFast[1] = beerTempFiltFast[2];
- beerTempFiltFast[2] = beerTempFiltFast[3];
- beerTempFiltFast[3] = (beerTempFast[0] + beerTempFast[3]
- + 3 * (beerTempFast[1] + beerTempFast[2]) )
- / 3.430944333e+04 + (0.8818931306 * beerTempFiltFast[0])
- + (-2.7564831952 * beerTempFiltFast[1])
- + ( 2.8743568927 * beerTempFiltFast[2]);
-
- beerTemperatureActual = beerTempFiltFast[3];
- }
-
- void updateSlowFilteredTemperatures(void){ //called every 10 seconds
- // Input for filter
- fridgeTempSlow[0] = fridgeTempSlow[1];
- fridgeTempSlow[1] = fridgeTempSlow[2];
- fridgeTempSlow[2] = fridgeTempSlow[3];
- fridgeTempSlow[3] = fridgeTempFiltFast[3];
-
- // Butterworth filter with cutoff frequency 0.01*sample frequency (FS=0.1Hz)
- fridgeTempFiltSlow[0] = fridgeTempFiltSlow[1];
- fridgeTempFiltSlow[1] = fridgeTempFiltSlow[2];
- fridgeTempFiltSlow[2] = fridgeTempFiltSlow[3];
- fridgeTempFiltSlow[3] = (fridgeTempSlow[0] + fridgeTempSlow[3]
- + 3 * (fridgeTempSlow[1] + fridgeTempSlow[2]) )
- / 3.430944333e+04 + (0.8818931306 * fridgeTempFiltSlow[0])
- + (-2.7564831952 * fridgeTempFiltSlow[1])
- + ( 2.8743568927 * fridgeTempFiltSlow[2]);
-
- beerTempSlow[0] = beerTempSlow[1];
- beerTempSlow[1] = beerTempSlow[2];
- beerTempSlow[2] = beerTempSlow[3];
- beerTempSlow[3] = beerTempFiltFast[3];
-
- // Butterworth filter with cutoff frequency 0.01*sample frequency (FS=0.1Hz)
- beerTempFiltSlow[0] = beerTempFiltSlow[1];
- beerTempFiltSlow[1] = beerTempFiltSlow[2];
- beerTempFiltSlow[2] = beerTempFiltSlow[3];
- beerTempFiltSlow[3] = (beerTempSlow[0] + beerTempSlow[3]
- + 3 * (beerTempSlow[1] + beerTempSlow[2]) )
- / 3.430944333e+04 + (0.8818931306 * beerTempFiltSlow[0])
- + (-2.7564831952 * beerTempFiltSlow[1])
- + ( 2.8743568927 * beerTempFiltSlow[2]);
- }
- (это пиздец, считать на 8-мибитках такую вещественную арифметику...)
- Как видите, здесь использовано 2 быстрых и 2 медленных фильтра. Быстрый фильтр
- обновляется 5 раз в секунду и имеет угловые частоты 0.165 Гц и 0.05 Гц.
- Медленный фильтр обновляется раз в 10 сек и имеет угловую частоту 0.001 Гц.
- Медленный фильтр получает данные от быстрого.
- Почему быстрый и медленный фильтр?
- Каждый причинный фильтр (фильтр который не может заглянуть в будущее) вызывает
- задержку между входом и выходом: если брать среднее от К значений,
- потребуется К обновлений выхода чтобы полностью увидеть именения на входе.
- Каждый IIR low pass filter получает среднее от бесконечности предыдущих
- значений, но с уменьшающим множителем для более старых входных значений.
- Фильтр с меньшей угловой частотой усредняет больше значений и поэтому вызывает
- большую задержку.
- Дальше переводить особого смысла нет.
- Вобщем автора нужда заставила использовать два фильтра с разной угловой
- частотой.
- -=-=-=-=-
- Коэффициенты фильтра можно посчитать здесь:
- http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
|