adc_filter.txt 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. my
  2. #define MAX(a, b) ((a) > (b)) ? (a) : (b)
  3. #define MIN(a, b) ((a) < (b)) ? (a) : (b)
  4. #define MIDDLE(a, b, c) MAX(MAX(MIN(a, b), MIN(a, c)), MIN(b, c))
  5. func (val) {
  6. static a1, a2 == 0
  7. //middle = MIDDLE(val, a1, a2)
  8. if val < a1 and val < a2
  9. middle = MIDDLE(val, a1, a2)
  10. else if val > a1 and a2
  11. middle = MIDDLE(val, a1, a2)
  12. else middle = val
  13. a2 = a1
  14. a1 = val
  15. return middle
  16. }
  17. ===
  18. http://chipenable.ru/index.php/embedded-programming/item/203-mediannyy-filtr.html
  19. uint16_t middle_of_3(uint16_t a, uint16_t b, uint16_t c)
  20. {
  21. uint16_t middle;
  22. if ((a <= b) && (a <= c)){
  23. middle = (b <= c) ? b : c;
  24. }
  25. else{
  26. if ((b <= a) && (b <= c)){
  27. middle = (a <= c) ? a : c;
  28. }
  29. else{
  30. middle = (a <= b) ? a : b;
  31. }
  32. }
  33. return middle;
  34. }
  35. ===
  36. http://www.elcojacobs.com/eleminating-noise-from-sensor-readings-on-arduino-with-digital-filtering/
  37. выжимки из статьи
  38. Медианный фильтр:
  39. сортируем массив значений (например 100) от меньшего к большему (?) и берём среднее.
  40. автор предлагает скомбинировать медианный фильтр и фильтрацию по среднему:
  41. сортируем массив значений, берём 10 (из 100) средних и из них считаем среднее.
  42. The final code to read one sensor:
  43. #define NUM_READS 100
  44. float readTemperature(int sensorpin){
  45. // read multiple values and sort them to take the mode
  46. int sortedValues[NUM_READS];
  47. for(int i=0;i<NUM_READS;i++){
  48. int value = analogRead(sensorpin);
  49. int j;
  50. if(value<sortedValues[0] || i==0){
  51. j=0; //insert at first position
  52. }
  53. else{
  54. for(j=1;j<i;j++){
  55. if(sortedValues[j-1]<=value && sortedValues[j]>=value){
  56. // j is insert position
  57. break;
  58. }
  59. }
  60. }
  61. for(int k=i;k>j;k--){
  62. // move all values higher than current reading up one position
  63. sortedValues[k]=sortedValues[k-1];
  64. }
  65. sortedValues[j]=value; //insert current reading
  66. }
  67. //return scaled mode of 10 values
  68. float returnval = 0;
  69. for(int i=NUM_READS/2-5;i<(NUM_READS/2+5);i++){
  70. returnval +=sortedValues[i];
  71. }
  72. returnval = returnval/10;
  73. return returnval*1100/1023;
  74. }
  75. -=-=-=-=-=-=-=-=-=-
  76. По своей сути, это похоже на алгоритм, которым я когда-то фильтровал значения
  77. от счётчика гейгера:
  78. - считаем среднее в массиве измерений,
  79. - отбираем из массива только те значения, которые укладываются в +-5% от
  80. полученного среднего,
  81. - берём среднее от оставшихся значений.
  82. кажется я просто занулял неподходящие данные, а потом не учитывал их при
  83. следующем усреднении.
  84. какой алгоритм точнее, меньше, быстрее -- хз. можно попробовать на Unicharger-е.
  85. -=-=-=-=-=-=-=-=-=-
  86. Addional filtering: IIR Butterworth low pass filters
  87. (I have changed the filters from second order to third order...)
  88. для медленно меняющихся процессов он предлагает использовать фильтр нижних
  89. частот Баттервота 4-го порядка.
  90. Фильтр Баттервота -- это "infinite impulse response filter" (IIR)
  91. (а теперь гугльтранслейт)
  92. Это означает, что каждое выходное значение фильтра рассчитывается из истории
  93. входных значений и предыдущих выходных значений фильтра.
  94. Поскольку выходной фильтр используется для вычисления будущих значений,
  95. влияние любого входного значения на будущие выходные -- есть регрессия к
  96. бесконечности.
  97. (конец)
  98. The implementation of a software Butterworth filter is actually very easy, see
  99. the code snippet below.
  100. void updateTemperatures(void){ //called every 200 milliseconds
  101. fridgeTempFast[0] = fridgeTempFast[1];
  102. fridgeTempFast[1] = fridgeTempFast[2];
  103. fridgeTempFast[2] = fridgeTempFast[3];
  104. fridgeTempFast[3] = readTemperature(fridgePin);
  105. // Butterworth filter with cutoff frequency 0.033*sample frequency (FS=5Hz)
  106. fridgeTempFiltFast[0] = fridgeTempFiltFast[1];
  107. fridgeTempFiltFast[1] = fridgeTempFiltFast[2];
  108. fridgeTempFiltFast[2] = fridgeTempFiltFast[3];
  109. fridgeTempFiltFast[3] = (fridgeTempFast[0] + fridgeTempFast[3]
  110. + 3 * (fridgeTempFast[1] + fridgeTempFast[2]) )
  111. / 1.092799972e+03 + (0.6600489526 * fridgeTempFiltFast[0])
  112. + (-2.2533982563 * fridgeTempFiltFast[1])
  113. + ( 2.5860286592 * fridgeTempFiltFast[2]);
  114. fridgeTemperatureActual = fridgeTempFiltFast[3];
  115. beerTempFast[0] = beerTempFast[1];
  116. beerTempFast[1] = beerTempFast[2];
  117. beerTempFast[2] = beerTempFast[3];
  118. beerTempFast[3] = readTemperature(beerPin);
  119. // Butterworth filter with cutoff frequency 0.01*sample frequency (FS=5Hz)
  120. beerTempFiltFast[0] = beerTempFiltFast[1];
  121. beerTempFiltFast[1] = beerTempFiltFast[2];
  122. beerTempFiltFast[2] = beerTempFiltFast[3];
  123. beerTempFiltFast[3] = (beerTempFast[0] + beerTempFast[3]
  124. + 3 * (beerTempFast[1] + beerTempFast[2]) )
  125. / 3.430944333e+04 + (0.8818931306 * beerTempFiltFast[0])
  126. + (-2.7564831952 * beerTempFiltFast[1])
  127. + ( 2.8743568927 * beerTempFiltFast[2]);
  128. beerTemperatureActual = beerTempFiltFast[3];
  129. }
  130. void updateSlowFilteredTemperatures(void){ //called every 10 seconds
  131. // Input for filter
  132. fridgeTempSlow[0] = fridgeTempSlow[1];
  133. fridgeTempSlow[1] = fridgeTempSlow[2];
  134. fridgeTempSlow[2] = fridgeTempSlow[3];
  135. fridgeTempSlow[3] = fridgeTempFiltFast[3];
  136. // Butterworth filter with cutoff frequency 0.01*sample frequency (FS=0.1Hz)
  137. fridgeTempFiltSlow[0] = fridgeTempFiltSlow[1];
  138. fridgeTempFiltSlow[1] = fridgeTempFiltSlow[2];
  139. fridgeTempFiltSlow[2] = fridgeTempFiltSlow[3];
  140. fridgeTempFiltSlow[3] = (fridgeTempSlow[0] + fridgeTempSlow[3]
  141. + 3 * (fridgeTempSlow[1] + fridgeTempSlow[2]) )
  142. / 3.430944333e+04 + (0.8818931306 * fridgeTempFiltSlow[0])
  143. + (-2.7564831952 * fridgeTempFiltSlow[1])
  144. + ( 2.8743568927 * fridgeTempFiltSlow[2]);
  145. beerTempSlow[0] = beerTempSlow[1];
  146. beerTempSlow[1] = beerTempSlow[2];
  147. beerTempSlow[2] = beerTempSlow[3];
  148. beerTempSlow[3] = beerTempFiltFast[3];
  149. // Butterworth filter with cutoff frequency 0.01*sample frequency (FS=0.1Hz)
  150. beerTempFiltSlow[0] = beerTempFiltSlow[1];
  151. beerTempFiltSlow[1] = beerTempFiltSlow[2];
  152. beerTempFiltSlow[2] = beerTempFiltSlow[3];
  153. beerTempFiltSlow[3] = (beerTempSlow[0] + beerTempSlow[3]
  154. + 3 * (beerTempSlow[1] + beerTempSlow[2]) )
  155. / 3.430944333e+04 + (0.8818931306 * beerTempFiltSlow[0])
  156. + (-2.7564831952 * beerTempFiltSlow[1])
  157. + ( 2.8743568927 * beerTempFiltSlow[2]);
  158. }
  159. (это пиздец, считать на 8-мибитках такую вещественную арифметику...)
  160. Как видите, здесь использовано 2 быстрых и 2 медленных фильтра. Быстрый фильтр
  161. обновляется 5 раз в секунду и имеет угловые частоты 0.165 Гц и 0.05 Гц.
  162. Медленный фильтр обновляется раз в 10 сек и имеет угловую частоту 0.001 Гц.
  163. Медленный фильтр получает данные от быстрого.
  164. Почему быстрый и медленный фильтр?
  165. Каждый причинный фильтр (фильтр который не может заглянуть в будущее) вызывает
  166. задержку между входом и выходом: если брать среднее от К значений,
  167. потребуется К обновлений выхода чтобы полностью увидеть именения на входе.
  168. Каждый IIR low pass filter получает среднее от бесконечности предыдущих
  169. значений, но с уменьшающим множителем для более старых входных значений.
  170. Фильтр с меньшей угловой частотой усредняет больше значений и поэтому вызывает
  171. большую задержку.
  172. Дальше переводить особого смысла нет.
  173. Вобщем автора нужда заставила использовать два фильтра с разной угловой
  174. частотой.
  175. -=-=-=-=-
  176. Коэффициенты фильтра можно посчитать здесь:
  177. http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html