IIR-Filter
Bei der Verarbeitung von Sensorwerten mit einem Mikrocontroller treten häufig Probleme auf, da die Sensorwerte verrauscht oder mit Störimpulsen überlagert sind. In der Analogtechnik würde man ein analoges Filter, beispielsweise ein RC-Glied als Tiefpass, einsetzen. In der Digitaltechnik gibt es entsprechend digitale Filter. Ein RC-Glied in der Analogtechnik entspricht einem digitalen IIR-Filter (Infinite Impulse Response). Ein solches Filter entsteht, indem ein neuer Sensorwert mit einem aus den vergangenen Sensorwerten gespeicherten Wert verrechnet wird und der berechnete Wert für den nächsten Sensorwert gespeichert wird
Theorie
Die Formel für einen IIR-Tiefpass 1. Ordnung
lautet:
Da im Durchlassbereich keine Veränderung der
Amplitude erfolgen soll, muss
sein. Damit gilt dann
Bei einem 8-Bit-Microcontroller wie dem Arduino
UNO ist eine Berechnung mit Gleitkommazahlen
sehr zeitaufwendig. Auch eine Multiplikation
oder Division mit ganzzahligen Werten ist
„teuer”. Beides sollte vermieden werden. Um auf
ganzzahlige Werte zu kommen, wird die obige
Gleichung mit einem Faktor n multipliziert,
sodass
wird:
oder
Mit etwas geringerer Genauigkeit können wir auch
mit der folgenden Gleichung rechnen:
Wenn der Faktor n nun eine 2er-Potenzen ist
(),
dann kann die Multiplikation oder Division auch
vermieden und durch Shift-Operationen um s Bits
ersetzt werden. Dies schränkt allerdings die
Wahl der Grenzfrequenz des Filters sehr stark
ein. Diese Grenzfrequenz
des Filters berechnet sich in Anhängigkeit des
Sampling Frequenz
nach der Formel:
Hier einige praxisnahe Werte:
| n | s | ||
|---|---|---|---|
| 0,5 | 2 | 1 | |
| 0,25 | 4 | 2 | |
| 0,125 | 8 | 3 |
Implementierung
Für die Implantierung betrachten wir die
folgende Formel, bei der Shift-Operatoren
anstelle von Multiplikation und Division
verwendet werden:
Wie man sieht, berechnen wir den Wert
,
verwenden aber nachher in der Subtraktion den
Wert
.
Dadurch leidet die Genauigkeit. Es empfiehlt
sich daher, die Subtraktion mit höherer
Genauigkeit zu berechnen. Wir kommen dann zu
folgender Formel:
Es liegt jetzt nahe, statt dem Wert
für die nächste Berechnung den Wert
zu speichern.
Überläufe bei der Berechnung müssen unbedingt vermieden werden. Man sieht sofort, dass die Breite der Eingabewerte (z.B. Sensorwerte) plus dem Shiftfaktor s die Wortbreite der Berechnung (beispielswese 16-Bit Arithmetik) nicht überschreiten darf. Kritisch ist aber wieder die Subtraktion. Hier kann es bei einem Sprung vom höchsten auf den niedrigsten Wert zu einem Überlauf kommen. Wir benötigen also noch ein Bit in Reserve. Bei einer angenommenen 16-Bit-Arithmetik können aber mit 12-Bit-Sensorwerten aber immer noch die Shiftfaktoren 1 bis 3 verwendet werden. Entsprechende Überlegungen können auch für andere Wertebereiche und Shiftfaktoren angestellt werden.
Damit kommen wir jetzt zu dieser sehr einfachen und schnellen Implementation eines Tiefpass Filters mit 6dB Flankensteilheit:
int16_t IIRfilter_6dB(int16_t input, int8_t s) {
static int16_t alt = 0; // wir speichern hier schon den geschifteten Wert alt << s
alt = alt + (((input << s) - alt) >> s);
return alt >> s; // den Shitfaktor im gespeicherten Wert müssen wir bei der Rückgabe wieder abziehen
}
Ein Filter höherer Ordnung erhält man durch Hintereinanderschaltung zweier Filter:
int16_t IIRfilter_12dB(int16_t input, int8_t s) {
static int16_t alt1 = 0;
static int16_t alt2 = 0;
alt1 = alt1 + (((input << s) - alt1) >> s);
alt2 = alt2 + ((alt1 - alt2) >> s);
return alt2 >> s;
}
Um in anderen Fällen (beispielsweise 16Bit ADC) Überläufe zu vermeiden, muss man mit geringerer Genauigkeit rechnen,.
int16_t IIRfilter(int16_t input, int8_t s) {
static int16_t alt = 0; // hier wird ein 15-Bit Wert gespeichert
alt = alt + (((input >> 1) - alt) >> s);
return alt << 1; // intern wird ja mit 15-Bit gerechnet
}
Die Alternative wäre, in der Routine mit höherer Genauigkeit zu rechnen:
int16_t IIRfilter(int16_t input, int8_t s) {
static int24_t alt = 0; // wir speichern hier schon den geschifteten Wert alt << s
alt = alt + ((((int24_t)input << s) - alt) >> s);
return int16_t(alt >> s);
}
Hier der Frequenzgang zweier IIR-Filter mit 6db und 12db Steilheit und jeweils den Grenzfrequenzen von ca 1/10 und 1/20 der Samplingfrequenz.


Hier der Vergleich zweier IIR-Filter mit 6dB und Grenzfrequenz ca. 1/10 der Sampling Frequenz und eine 12dB Filter mit der halben Grenzfrequenz.

Zu dem letzten Fall hier noch die Sprungantwort der beiden Filter

Das es sich bei der Simulation tatsächlich um ein digitale Filter handelt sieht man, wenn man den Frequenzgang etwas weiter ausdehnt. Die maximale Filterdämpfung ist bei der halben Samplingfrequenz, bei Vielfachen dieser Frequenz ist keine Filterwirkung zu erkennen.

Fazit
Diese Art der Filterung ist nur für bestimmte Anwendungsfälle geeignet.
- Der genaue Wert der Grenzfrequenz ist nicht entscheidend.
- Die Berechnungsgeschwindigkeit ist entscheidend.
Dies ist beispielsweise bei 8-Bit-Prozessoren wie dem Arduino Uno und der Verarbeitung von Sensorwerten der Fall. Wenn man dort mit einer Sampling-Frequenz von 10 kHz oder bis zu 50 kHz arbeitet, bleiben nur wenige µs zur Verarbeitung der Werte übrig.
Wenn genauere Werte für die Grenzfrequenz eingehalten werden müssen, kommt man um eine Rechnung mit höherer Wortbreite nicht herum. Wir müssen dann zur ursprünglichen Formel für das Filter zurückkehren und unseren Shiftfaktor so wählen, dass ganzzahlig wird. K liegt dann im Wertebereich .
Diese Formel liegt dem Algorithmus in dem im
Link genannten Artikel zugrunde. Wie viele Bit
benötigen wir jetzt für die Berechnung? Bisher
waren es die Breite der Eingabewerte plus der
Shiftfaktor s plus 1, jetzt kommen durch die
Multiplikation mit K noch einmal s Bits dazu.
Dann sind wir schnell bei einer Wortbreite von
32 Bit für die Berechnung. Für einen
32-Bit-Prozessor ist das alles kein Problem.
Links
- Carsten Meyer: Digital filtern und oszillieren, Make-Magazin 6/2022: Heise Verlag Hannover 2022
#Arduino, #Analogeingang, #Filter