Les 4 · Module 1 · De ESP32 als sensorknooppunt
Meten, filteren en kalibreren
Maak de metingen van het meetstation betrouwbaar: ruis begrijpen, mediaan- en voortschrijdend-gemiddeldefilters, uitschieters weggooien, kalibreren met een referentie en afgeleide waarden zoals het dauwpunt.
🎯 Na deze les kun je
- ruis en uitschieters in sensorwaarden herkennen
- een mediaanfilter en een exponentieel voortschrijdend gemiddelde implementeren
- een sensor kalibreren met een offset ten opzichte van een referentie
- afgeleide waarden berekenen en afronden op zinvolle precisie
Lees je de sensor tien keer achter elkaar, dan krijg je tien net iets andere waarden. Soms zit er ook een uitschieter tussen. Op een
dashboard wil je een rustige, eerlijke lijn. In deze les bouw je lib/filter.py.
Ruis bekijken
import time
from sensor import SHT31
...
for _ in range(20):
t, rv = s.lees()
print("%.3f" % t)
time.sleep_ms(200)
Je ziet waarden die een paar honderdsten van een graad schommelen. De SHT31 is nauwkeurig tot ongeveer ±0,2 °C; het derde cijfer achter de komma is dus vooral ruis.
Mediaanfilter tegen uitschieters
# lib/filter.py
def mediaan(waarden):
w = sorted(waarden)
n = len(w)
m = n // 2
return w[m] if n % 2 else (w[m - 1] + w[m]) / 2
def meet_mediaan(sensor, n=5, pauze_ms=50):
import time
ts, rvs = [], []
for _ in range(n):
try:
t, rv = sensor.lees()
ts.append(t); rvs.append(rv)
except Exception:
pass
time.sleep_ms(pauze_ms)
if len(ts) < (n // 2 + 1):
raise ValueError("te weinig geldige metingen")
return mediaan(ts), mediaan(rvs)
Voorspel eerst: vijf metingen zijn 21.1, 21.2, 85.0, 21.1, 21.2. Wat geeft het gemiddelde, en wat de mediaan?
Uitkomst
Gemiddelde: 33,9, een flinke vertekening door één fout. Mediaan: 21,2: de middelste van de gesorteerde waarden, onaangetast door één uitschieter. Een mediaan van 5 metingen overleeft tot 2 uitschieters. Daarom meet je per "meting" een paar keer snel achter elkaar en neem je de mediaan.
Glad maken over de tijd: EMA
Tussen metingen (bijv. elke 10 s) wil je de lijn rustig houden zonder alles te onthouden. Een exponentieel voortschrijdend gemiddelde:
class EMA:
def __init__(self, alfa=0.3):
self.alfa = alfa
self.waarde = None
def update(self, x):
self.waarde = x if self.waarde is None else self.alfa * x + (1 - self.alfa) * self.waarde
return self.waarde
Een kleine alfa (0,1) geeft een rustige maar trage lijn; een grote (0,7) volgt snel maar laat meer ruis door. Eén getal geheugen: ideaal
voor een microcontroller.
Uitschieters weigeren
Fysiek onmogelijke waarden gooi je weg voordat ze in het filter komen:
def plausibel(t, rv, vorige_t=None):
if not (-40 <= t <= 85 and 0 <= rv <= 100):
return False
if vorige_t is not None and abs(t - vorige_t) > 5: # 5 °C sprong in 10 s binnenshuis: verdacht
return False
return True
Kalibreren
Elke sensor wijkt een beetje af. Leg hem een uur naast een betrouwbare thermometer (op dezelfde plek, uit de zon) en noteer het verschil.
# config.py
KAL_T = -0.4 # sensor meet 0,4 °C te hoog
KAL_RV = 1.5
temp = temp + config.KAL_T
Een offset is meestal genoeg. Wijkt hij bij lage en hoge temperatuur verschillend af, dan meet je op twee punten en gebruik je een
lineaire correctie (a * x + b).
Afgeleide waarden
Het dauwpunt zegt meer over "benauwd" of "kans op condens" dan de relatieve vochtigheid (Magnus-formule):
import math
def dauwpunt(t, rv):
a, b = 17.62, 243.12
g = math.log(rv / 100) + a * t / (b + t)
return b * g / (a - g)
Rond af op wat zinvol is: temperatuur op 0,1 °C, vochtigheid op hele procenten. Meer decimalen suggereren een nauwkeurigheid die er niet is.
Typische fouten
ValueError: math domain errorindauwpunt:rvis 0 (log van 0). Weiger die meting.- EMA "blijft hangen": je maakt elke meting een nieuw
EMA-object; maak het één keer buiten de lus. - Kalibreren in de zon of naast de laptop: de referentie en de sensor moeten dezelfde lucht meten.
Oefenen
- Schrijf
lib/filter.pymetmediaan,meet_mediaanenEMA. - Test
mediaanop je computer met gewone Python en de getallen uit Voorspel eerst. - Vergelijk ruwe en EMA-gefilterde waarden met
alfa0,1 en 0,5 terwijl je op de sensor ademt. - Kalibreer je sensor tegen een referentie en voeg het dauwpunt toe aan de uitvoer.
Modelantwoord oefening 1
Zie de codeblokken. Plaats plausibel ook in filter.py.
Modelantwoord oefening 2
python3 -c "import sys; sys.path.insert(0,'lib'); from filter import mediaan; print(mediaan([21.1,21.2,85.0,21.1,21.2]))"
# 21.2
Pure functies zonder machine kun je zo op je computer testen: sneller dan op het bordje.
Modelantwoord oefening 3
Met alfa=0.5 stijgt de gefilterde lijn binnen twee à drie metingen; met 0.1 duurt het tien metingen of meer. Voor een kamermeetstation
is 0,2–0,3 een goede middenweg.
Modelantwoord oefening 4
Bij 21 °C en 50% is het dauwpunt ongeveer 10,2 °C. Toon het met "%.1f" % dauwpunt(t, rv).
Lokaal oefenen
Geen live lab. De filterfuncties kun je met gewone Python op je computer testen; de sensor heb je alleen voor het echte meten nodig.
Samenvatting
- Meet een paar keer snel en neem de mediaan tegen uitschieters.
- EMA maakt de lijn over de tijd rustig, met één getal geheugen.
- Weiger onmogelijke waarden; kalibreer met een offset ten opzichte van een referentie.
- Rond af op zinvolle precisie; bereken afgeleide waarden als het dauwpunt.
- Volgende les: een display aansturen.