Tutorial · Beginner · 17 min lezen
Sensorruis, bias en filtering in de robotica
Maak ruisvolle robotsensoren begrijpelijk: ruis, bias en drift, hoe je een filter kiest, welke vertraging filtering geeft en wanneer fusie helpt.
Elke robot werkt op metingen die ruis bevatten, vertraagd zijn, een bias hebben en soms ontbreken. Een ruwe meting als waarheid behandelen is de snelste manier om een robot te bouwen die zich onvoorspelbaar gedraagt. Deze gids behandelt de woordenschat en de afwegingen die je nodig hebt voordat je een sensor vertrouwt. Experimenteer met elk effect in de Robot Sensor Simulator.
Ruis, bias en drift zijn verschillende problemen
- Ruis varieert willekeurig van monster tot monster. Gemiddelen of filteren vermindert het.
- Bias is een vaste afwijking van de werkelijke waarde. Filtering verwijdert hem niet; je moet hem bij kalibratie meten en aftrekken.
- Drift is een bias die langzaam in de tijd verandert, meestal met de temperatuur. Een kalibratie die je bij het opstarten neemt houdt gaandeweg op de werkelijkheid te sluiten, en daarom hebben lange runs periodieke herkalibratie of een referentie nodig om tegen te corrigeren.
Deze door elkaar halen leidt tot de verkeerde oplossing — meer filtering geneest nooit een bias.
Een filter kiezen
Drie gangbare filters dekken de meeste gevallen:
- Een voortschrijdend gemiddelde en een exponentieel laagdoorlaatfilter dempen beide willekeurige ruis en ruilen responsiviteit in voor gladheid via hun venster of tijdconstante.
- Een mediaanfilter verwijdert incidentele pieken en uitvallers beter, omdat een paar slechte monsters de middelste waarde niet verplaatsen.
Kies het lichtste filter dat aan de eis van de verbruiker voldoet — niet het filter dat de gladste grafiek oplevert.
Filtering voegt altijd vertraging toe
Elk gladstellend filter loopt achter op het werkelijke signaal, en meer gladstelling betekent meer vertraging. Een laagdoorlaatfilter met een lange tijdconstante onderdrukt meer ruis, maar valt verder terug bij snelle veranderingen. Teken de gefilterde schatting altijd naast zowel de ruwe monsters als de werkelijke waarde, zodat de vertraging zichtbaar is voordat je het filter in een regellus zet, waar vertraging instabiliteit kan veroorzaken.
class LowPass:
def __init__(self, alpha):
self.alpha = alpha # smaller alpha = smoother but more lag
self.value = None
def update(self, sample):
if self.value is None:
self.value = sample
else:
self.value += self.alpha * (sample - self.value)
return self.value
Wat sensorfusie wel en niet kan
Fusie combineert meerdere sensoren tot één schatting, en het helpt alleen wanneer de sensoren complementaire informatie leveren en hun onzekerheid eerlijk wordt weergegeven. Twee bevoordeelde metingen combineren levert geen waarheid op. Een complementair filter vertrouwt bijvoorbeeld op de ene sensor bij hoge frequenties en op de andere bij lage frequenties; een Kalmanfilter weegt elke bron naar haar onzekerheid. Ga in beide gevallen eerst aan de gang met kalibratie, tijdstempels en gedeelde coördinatenframes voordat je iets fuseert.
Zet op alles een tijdstempel
Monsters komen zelden op een volmaakt vast interval binnen, en zowel filtering als fusie veronderstellen dat je weet wanneer elke waarde is gemeten. Tijdstempels laten je jitter detecteren, gegevens van verschillende sensoren uitlijnen en verouderde metingen verwerpen. Log ruwe waarden naast de verwerkte, zodat fouten als clipping en uitvallers reproduceerbaar blijven.
Meet je sensor voordat je hem filtert
Een filter kiezen voordat je weet hoe de ruis eruitziet is gokken. Tien minuten loggen beslist het, en de procedure is voor elke sensor dezelfde:
- Houd de sensor volstrekt stil tegen een bekende, onveranderende invoer.
- Log een paar duizend ruwe monsters met tijdstempels.
- Bereken het gemiddelde en de standaardafwijking.
- Teken de monsters en daarnaast een histogram ervan.
Die vier getallen en twee grafieken vertellen je welke van de drie fouten je hebt:
| Wat je ziet | Wat het is | De oplossing |
|---|---|---|
| Gemiddelde klopt met de werkelijkheid, waarden zwerten symmetrisch | Ruis | Filter het |
| Gemiddelde wijkt af van de werkelijkheid, spreiding is klein | Bias | Meet het en trek het af — filtering helpt nooit |
| Gemiddelde loopt in minuten weg | Drift | Herkalibreer periodiek, of corrigeer tegen een referentie |
| Meestal strak, met af en toe wilde waarden | Uitwissers | Mediaan, geen gemiddelde |
| Waarden vallen op discrete stappen | Kwantisatie | Verwacht; het begrinst je resolutie |
Het histogram is het deel dat mensen overslaan, en het is het meest veelzeggende. Gaussische ruis maakt een bel; uitwissers maken een bel met een paar punten ver in de staarten. Die twee hebben verschillende filters nodig, en geen hoeveelheid staren naar een tijdreeksgrafiek onderscheidt ze zo duidelijk.
Een filter kiezen, gekwantificeerd
| Filter | Doodt gaussische ruis | Doodt uitwissers | Vertraging | Kosten |
|---|---|---|---|---|
| Voortschrijdend gemiddelde, N monsters | Ja — met √N | Nee — smeert één piek over N monsters | (N−1)/2 monsters | Buffer van N monsters |
| Exponentieel laagdoorlaatfilter (EMA) | Ja | Nee | ≈ (1−α)/α monsters | Eén float |
| Mediaan van N | Deels | Volledig, tot N/2 uitwissers | (N−1)/2 monsters | Sorteren, triviaal bij kleine N |
| Mediaan en daarna EMA | Ja | Ja | Beide | Beide |
De √N in de eerste rij is het nuttige getal: gemiddelen over 4 monsters halveert de ruis; gemiddelen over 100 monsters vermindert hem met een factor tien, ten koste van 50 monsters vertraging. Ruisreductie heeft sterk aflopende meeropbrengst en vertraging niet, en daarom zijn zeer lange gemiddelingen vrijwel altijd het verkeerde antwoord.
Voor een EMA relateert de tijdconstante zich aan α via:
tau = dt x (1 - alpha) / alpha
Dus bij een lus van 10 ms geeft α = 0.1 een tijdconstante van 90 ms. α op gevoel instellen is de manier waarop mensen eindigen met filters die veel trager zijn dan ze doorhebben — reken het één keer uit en je weet wat je hebt.
De vertraging is niet gratis, en dit is wat hij kost
Elk gladstellend filter vertraagt het signaal, en binnen een regellus is die vertraging ononderscheidbaar van een proces dat langzamer reageert. Ze vermindert rechtstreeks hoeveel versterking de lus verdraagt voordat hij gaat oscilleren.
| Filter | Vertraging bij een lus van 10 ms | Afgelegde afstand bij 0.3 m/s |
|---|---|---|
| Mediaan van 3 | 10 ms | 3 mm |
| Mediaan van 5 | 20 ms | 6 mm |
| Voortschrijdend gemiddelde van 10 | 45 ms | 14 mm |
| EMA, α = 0.1 | 90 ms | 27 mm |
| EMA, α = 0.02 | 490 ms | 147 mm |
Die laatste rij is het waard om even bij stil te staan. Een α van 0.02 levert een prachtig gladde grafiek en een halve seconde vertraging — de robot stuurt op de plek waar het obstakel 15 cm geleden stond. Dit is de meest voorkomende manier waarop een welbedoeld filter een robot erger maakt, en het is onzichtbaar tenzij je gefilterd tegenover ruw tekent met de werkelijke waarde erbij.
Kies het lichtste filter dat aan de eis voldoet, en controleer altijd wat de vertraging kost in de eenheden waar de robot om geeft — millimeter, of graden, geen monsters.
Een complementair filter, en hoe je de constante kiest
Het complementaire filter is het werkpaardje van hobbyrobotica omdat het drie regels is en het echte probleem oplost: twee sensoren die op omgekeerde manieren falen.
// gyroRate in deg/s, accelAngle in degrees, dt in seconds.
angle = alpha * (angle + gyroRate * dt) + (1.0f - alpha) * accelAngle;
alpha bepaalt de grensfrequentie — daarboven vertrouw je de gyroscope, daaronder de accelerometer:
tau = alpha x dt / (1 - alpha) # the filter's time constant, seconds
f_crossover = 1 / (2 x pi x tau) # Hz
| α bij dt = 5 ms | Tijdconstante | Grensfrequentie | Gedrag |
|---|---|---|---|
| 0.90 | 45 ms | 3.5 Hz | Zeer responsief, duidelijk ruis van de accelerometer |
| 0.98 | 245 ms | 0.65 Hz | De gangbare standaard — een goede balans |
| 0.995 | 1.0 s | 0.16 Hz | Zeer glad, drijft merkbaar vóór de correctie |
| 0.999 | 5.0 s | 0.03 Hz | Vrijwel alleen gyroscope tijdens elk kort manoeuvre |
Kies hem uit de natuurkunde in plaats van uit het gevoel: de tijdconstante moet lang zijn ten opzichte van de storingen die je wilt onderdrukken, en kort ten opzichte van de driftsnelheid van de gyroscope. Een gyroscope met een bias van 1 °/s bereikt 1° fout in een seconde, dus een tijdconstante van meerdere seconden laat echte fout zich opstapelen voordat de accelerometer hem terugtrekt.
Merk ook op dat α van dt afhangt. Een α overnemen uit een project met een andere lusfrequentie geeft je een ander filter — en dat is een veelvoorkomende, onzichtbare bron van “deze versterkingen werken bij mij niet”.
Wat fusie niet kan
Fusie is geen tovertrant, en drie grenzen zijn het waard om plat te zeggen:
Het kan een gedeelde bias niet verwijderen. Twee accelerometers die allebei 2° hoog lezen leveren een gefuseerde schatting die 2° hoog leest. Fusie benut onafhankelijke fouten; een common-modefout blijft onaangeroerd.
Het kan informatie die er niet is niet creëren. Geen hoeveel filtering geeft een zesassige IMU een absolute gierhoek. Gieren heeft geen zwaartekrachtreferentie, dus het drijft, en alleen een magnetometer of een externe referentie verhelpt dat.
Het kan slechte tijdstempels niet repareren. Een GPS-fix van 10 Hz fuseren met een gyroscope van 200 Hz vereist dat je weet wanneer elk gemeten is, tot op een fractie van het snellere interval. Een fix die 100 ms oud is en als actueel wordt behandeld, bederft actief een schatting die de gyroscope alleen wel goed had.
Tijdstempels, concreet
“Alles van een tijdstempel voorzien” is makkelijk om mee in te stemmen en makkelijk over te slaan. De praktische versie:
struct Sample {
float value;
unsigned long micros; // when it was MEASURED, not when it was read
};
// Reject anything too old to be useful, rather than fusing it.
bool isFresh(const Sample &s, unsigned long maxAgeUs) {
return (micros() - s.micros) < maxAgeUs;
}
Leg de tijdstempel vast zo dicht mogelijk bij de meting — in de interrupt, niet na het parsen. Een GPS-zin die 80 ms na de fix is binnengekomen en bij het parsen van een tijdstempel is voorzien, is 80 ms fout, en niets verderop kan dat herstellen.
Storingzoeklijst
| Symptoom | Waarschijnlijke oorzaak | Oplossing |
|---|---|---|
| Meer filtering, geen verbetering | Het is bias, geen ruis | Meet de afwijking in rust en trek hem af |
| Schatting loopt langzaam weg | Drift | Periodieke herkalibratie, of een absolute referentie |
| Af en toe een piek overleeft het filter | Je gebruikt een gemiddelde | Mediaan verwerpt uitwissers; een gemiddelde smeert ze uit |
| Regellus oscilleert na het toevoegen van een filter | Vertraging heeft de stabiele versterking verlaagd | Lichter filter, of opnieuw afstellen |
| Gladde grafiek, robot reageert laat | Tijdconstante veel langer dan bedoeld | Bereken τ uit α — stel α niet op gevoel in |
| Gefuseerde schatting slechter dan één van de sensoren | Verouderde tijdstempels, of een gedeelde bias | Zet de tijdstempel bij de meting; controleer de afwijkingen van beide sensoren |
| Filter werkt op de werkbank, niet op de robot | Trilling is een echt signaal, geen ruis | Zachtmonteer de sensor; het filter kan ze niet onderscheiden |
| Complementair filter gedraagt zich anders dan in een tutorial | α hangt af van dt |
Bereken α voor jouw lusfrequentie |
Probeer het zelf
In de Robot Sensor Simulator kun je ruis, bias, drift en uitvallers instellen en daarna ruwe gegevens vergelijken met laagdoorlaat-, voortschrijdend-gemiddelde- en mediaanschattingen. Het is de snelste manier om de afweging tussen ruis en vertraging te voelen — dezelfde afweging die bepaalt hoe een robot reageert in de Obstacle Avoidance Simulator.
Verken de graaf
Onderdeel van deze bouwprojecten
Projecten en leerroutes waarin deze tutorial voorkomt.
Verder lezen