Въведение
При работа с аналогови сензори често се наблюдават случайни отклонения в измерванията. Независимо дали използваме потенциометър, фоторезистор, температурен датчик, сензор за налягане или друг аналогов източник, винаги съществува определено ниво на шум. Причината може да бъде захранването, електромагнитни смущения, дълги проводници или дори самият аналогово-цифров преобразувател (ADC).
Един от най-добрите начини за подобряване на качеството на измерванията е използването на цифрови филтри. В тази статия ще разгледаме библиотека за MicroPython, предназначена за Raspberry Pi Pico, която реализира два различни метода за филтриране:
- Медианен филтър (Median Filter)
- Trimmed Mean Filter (осредняване след премахване на крайните стойности)
И двата метода значително подобряват качеството на аналоговите измервания без необходимост от допълнителни хардуерни компоненти.
Какво представлява медианният филтър?
Медианният филтър е един от най-популярните цифрови филтри за премахване на импулсен шум.
Вместо да използва осреднена стойност на измерванията, той:
- Прави няколко последователни измервания.
- Подрежда ги във възходящ ред.
- Избира средната стойност.
Например:
120, 119, 121, 118, 3500, 120, 119, 122, 118, 121, 120
След сортиране:
118, 118, 119, 119, 120, 120, 120, 121, 121, 122, 3500
Медианата е: 120
Въпреки че една от стойностите е 3500, тя изобщо не влияе върху крайния резултат.
Именно това прави медианния филтър толкова устойчив на случайни пикове. Прочетете повече за алгоритъма и начина на работа на този филтър в статията ни: Филтриране на аналогови сигнали с Медиален филтър
Какво представлява Trimmed Mean Filter?
Trimmed Mean Filter комбинира предимствата на медианния филтър и обикновеното осредняване (средноаритметична стойност).
Алгоритъмът работи по следния начин:
- Правят се 11 измервания.
- Подреждат се по големина.
- Премахват се трите най-малки и трите най-големи стойности.
- Остават петте централни измервания.
- Изчислява се тяхната средноаритметична стойност.
Например:
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111
След премахване на крайните стойности остават:
104, 105, 106, 107, 108
Средноаритметичната стойност е: 106
Получава се много по-стабилен резултат от обикновеното осредняване, като едновременно с това случайните пикове са елиминирани. За този филтър също може да прочетете в горепосочената ни статия.
Къде може да се използва тази библиотека?
Този тип филтриране е особено полезно при:
- измерване на напрежение;
- четене на потенциометри;
- фоторезистори;
- NTC терморезистори;
- датчици за налягане;
- аналогови джойстици;
- измерване на ток;
- измерване на ниво на батерия;
- всички аналогови сензори с наличие на шум.
Предимството е, че не се изисква никакъв допълнителен хардуер – цялото филтриране се извършва софтуерно.
Код на библиотеката за Медианен и Trimmed Mean Filter
import time
from machine import ADC, Pin
class AnalogFilter:
def __init__(self, pin_num):
"""Инициализира аналогов вход на посочения GPIO пин"""
self.adc = ADC(Pin(pin_num))
self.buffer_size = 11
def _read_raw_buffer(self):
"""Прочита бързо 11 стойности от ADC порта и ги превръща в 12-битови"""
buffer = []
for _ in range(self.buffer_size):
# Прочитане на 16-битова стойност и преобразуване в 12-битова
pot_read_12bit = self.adc.read_u16() >> 4
buffer.append(pot_read_12bit)
time.sleep_us(500)
return buffer
def read_median(self):
"""Връща 12-битова стойност чрез класически медианен филтър"""
data = self._read_raw_buffer()
data.sort()
# Взима централния елемент на позиция 5
return data[5]
def read_trim_median(self):
"""Връща 12-битова стойност чрез Trim Median филтър от 5-те средни елемента"""
data = self._read_raw_buffer()
data.sort()
# Изрязване на 5-те централни елемента (индекси 3, 4, 5, 6, 7)
middle_5 = data[3:8]
# Намиране на средно-аритметично
average_value = sum(middle_5) / 5
return int(average_value)Подробно обяснение на библиотеката
Импортиране на необходимите модули
import time
from machine import ADC, PinИзползваме:
- ADC за достъп до аналоговите входове;
- Pin за избор на GPIO пина;
- time за кратко закъснение между измерванията.
Инициализация
class AnalogFilter:
def __init__(self, pin_num):При създаване на обекта подаваме номера на GPIO пина.
Например:
sensor = AnalogFilter(26)ще използва ADC0 (GPIO26).
След това:
self.adc = ADC(Pin(pin_num))се създава ADC обектът.
self.buffer_size = 11Определя се, че всяко измерване ще използва точно 11 проби.
Този брой е избран така, че винаги да има една ясно определена медиана.
Прочитане на измерванията
def _read_raw_buffer(self):Тази функция е вътрешна и се използва само от останалите методи.
pot_read_12bit = self.adc.read_u16() >> 4ADC на Raspberry Pi Pico връща 16-битова стойност, но реалната разделителна способност е 12 бита. Поради тази причина върнатата стойност от 0 до 65535 се преобразува от 0 до 4095, чрез изместване надясно с четири бита.
След това стойността се записва:
buffer.append(pot_read_12bit)След всяко измерване има кратка пауза:
time.sleep_us(500)Така се избягва четене на абсолютно еднакви стойности и се намалява влиянието на високочестотния шум.
Медианен филтър
def read_median(self):Първо се прочитат всички измервания.
data = self._read_raw_buffer()След това стойностите се подреждат.
data.sort()Понеже са точно 11 елемента, медианата винаги е:
data[5]Това е шестият елемент защото индексацията започва от нула.
Trimmed Mean Filter
def read_trim_median(self):Отново сортираме измерванията.
data.sort()След това избираме само централните пет стойности.
middle_5 = data[3:8]Така автоматично се премахват:
- трите най-малки;
- трите най-големи измервания.
Накрая се изчислява средната стойност.
average_value = sum(middle_5) / 5Получаваме резултат, който е едновременно:
- плавен;
- устойчив на шум;
- по-малко чувствителен към случайни отклонения.
Медианен и Trimmed Mean филтър Примерен код
import time
from medianFilter import AnalogFilter
# Инициализираме филтъра на GPIO26 (ADC0)
sensor = AnalogFilter(26)
print("Стартиране на измерването... Натиснете Ctrl+C за изход.")
while True:
try:
# Избор 1: Ползване на стандартен Медианен филтър
median_result = sensor.read_median()
# Избор 2: Ползване на Trim Median филтър (препоръчително за премахване на шум)
trimmed_result = sensor.read_trim_median()
# Извеждане на резултатите в конзолата
print(f"Медианен: {median_result} | Trim Median (5 средни): {trimmed_result}")
# Пауза между основните измервания
time.sleep(0.5)
except KeyboardInterrupt:
print("\nИзмерването е прекратено от потребителя.")
breakОбяснение на примерната програма
Импортиране на библиотеката
from medianFilter import AnalogFilterИмпортираме създадения клас.
Създаване на обект
sensor = AnalogFilter(26)Избираме GPIO26, който е първият аналогов вход (ADC0).
Безкраен цикъл
while True:Програмата извършва непрекъснати измервания.
Измерване с медианния филтър
median_result = sensor.read_median()Получава се стойност, която практически не се влияе от случайни импулси.
Измерване с Trimmed Mean Filter
trimmed_result = sensor.read_trim_median()Този метод осигурява още по-плавни измервания, като комбинира предимствата на медианния филтър и осредняването.
Печат на резултатите
print(f"Медианен: {median_result} | Trim Median (5 средни): {trimmed_result}")На сериен терминал могат директно да се сравнят двата метода на филтриране и да се наблюдава как Trimmed Mean Filter обикновено осигурява по-стабилни резултати при наличие на шум.
Закъснение
time.sleep(0.5)На всеки половин секунда се извършва ново измерване.
Прекратяване
except KeyboardInterrupt:Позволява програмата да бъде спряна безопасно с Ctrl+C.
Заключение
При работа с аналогови сигнали качеството на измерването е от ключово значение. Представената библиотека предлага два доказани метода за цифрово филтриране, които значително подобряват стабилността на показанията на аналоговите входове на Raspberry Pi Pico.
Медианният филтър е отличен избор, когато трябва да се елиминират единични импулсни смущения, тъй като напълно игнорира екстремните стойности. Trimmed Mean Filter от своя страна комбинира устойчивостта на медианното филтриране с плавността на осредняването, като използва само централните измервания след премахване на най-ниските и най-високите стойности.
Благодарение на компактната реализация и лесния за използване интерфейс, библиотеката може безпроблемно да бъде интегрирана в разнообразни проекти – от прости измервателни устройства до сложни системи за автоматизация, роботика и IoT приложения. Ако разработвате проект с аналогови сензори и искате по-надеждни и стабилни резултати без допълнителен хардуер, тази библиотека е практично и ефективно решение.
Интересна информация може да намерите в тези две статии: medfilt1 и Median filter.
