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

