Hallo, ich benutze eine PT1 Filter in dieser Art: out = alt + k*(in-alt) jedoch will ich eine relative lange Zeitkonstante (deswegen k bei 1e-6), und hab einen uC der float nur mit einfacher Genauigkeit macht (4 Bytes). Jetzt komme ich in Bereiche in denen der Rundungsfehler dazu führt dass ich einen gewissen Totbereich habe, in dem eine dauerhafte kleine Abweichung dazu führt dass out nicht auf in nachgezogen wird sondern unverändert bleibt weil k*(in-alt) so klein ist dass es beim aufaddieren zu "alt" einfach im Rundingsfehler untergeht und "alt" nicht verändert wird. Gibt es eine Standardlösung für diese problem, in der Art dass man auf eine Literaturstelle verweisen kann als "state of the art"? Vielen Dank,
asd schrieb: > out = alt + k*(in-alt) Das ist doch kein PT1 Filter. Ein PT1 Filter sieht folgendermassen aus A/E = K / (1+Ts).
Die Standardlösung ist, mit höherer Wortbreite (Genauigkeit) zu rechnen, das hilft Dir aber nicht weiter. Wie wäre es, wenn Du Dein PT1 mit viel niedriger Samplerate laufen lässt, dann werden die Koeffizienten ja wieder größer. z.B. Faktor 1024 langsamer: Immer 1024 Eingangswerte aufaddieren und das Ergebnis durch 1024 Teilen. Dann das Ergebnis ins langsame PT1 Filter einspeisen.
pt1checker schrieb: > Das ist doch kein PT1 Filter. > A/E = K / (1+Ts). Wenn man deinen PT1 im zeitdiskreten Fall (z-Transformation) betrachtet, dann ergibt das einen IIR-Filter mit der Struktur des vom TO genannten PT1 Filters.
>Gibt es eine Standardlösung für diese problem, in der Art dass man auf >eine Literaturstelle verweisen kann als "state of the art"? MEINE Standardlösung: Du hast beispielsweise Werte in ner 1ms Task und willst die über eine Stunde mitteln. Dann wären das ja 1:3600000 Deshalb nehm ich dann ein PT1 mit 1h Zeitkonstante, das mir alle 1sec einen Eingangswert nimmt, und schalte dem ein PT1 mit 1s Zeitkonstante und 1ms Abtastzeit davor. Das schnelle PT1 Filter wirkt hier also eher wie ein Antialiasing Filter. Da das eine aber 1000mal schneller als das 2. ist, ist es als System betrachtet kein PTn, sondern doch ein PT1 Filter. ich habe jetzt also ein 1:1000 und 1:3600 Verhältnis und die Rundungsfehler sind vernachlässigbar.
Du kannst das Filter auch in Integer rechnen. Bei einem 32-Bit-Integer mit Vorzeichen ist die Auflösung immerhin um den Faktor 128 höher, was etwa 2 zusätzlichen Dezimalstellen entspricht. Ob 32 Bit reichen, hängt davon ab, welche Auflösung die Ausgangswerte haben müssen und wie fein k eingestellt werden können muss.
asd schrieb: > Gibt es eine Standardlösung für diese problem, in der Art dass man auf > eine Literaturstelle verweisen kann als "state of the art"? Rechne den Regler in long. Dann hast du immerhin 9 signifikante Stellen... EDIT: Fenster zu lange offen --> Zweiter... ;-)
:
Bearbeitet durch Moderator
asd schrieb: > jedoch will ich eine relative lange Zeitkonstante (deswegen k bei 1e-6), > und hab einen uC der float nur mit einfacher Genauigkeit macht (4 > Bytes). Im Vergleich zu einem gleichlangen Integer, verschenkst du beim Float Genauigkeit, weil du weniger Bits zur Verfügung hast. Die Bits für den Exponent bringen dir bei Addition/Subtraktion nämlich nicht viel. Du verschenkst praktisch bis zu 8 Bit.
asd schrieb: > Jetzt komme ich in Bereiche in denen der Rundungsfehler dazu führt dass > ich einen gewissen Totbereich habe, in dem eine dauerhafte kleine > Abweichung dazu führt dass out nicht auf in nachgezogen wird sondern > unverändert bleibt weil k*(in-alt) > so klein ist dass es beim aufaddieren zu "alt" einfach im Rundingsfehler > untergeht und "alt" nicht verändert wird. > > Gibt es eine Standardlösung für diese problem, in der Art dass man auf > eine Literaturstelle verweisen kann als "state of the art"? Ist dein Problem dass die Zeitkonstante in dem Bereich generell nicht genau genug ist oder, dass das Filter zwar in weiten Bereichen funktioniert aber eben den Endwert nie erreicht? Für ersteres wurden viele Lösungen genannt. Such dir aus was am besten passt. Das zweite Problem lässt sich mmn nicht so analytisch lösen. In integer inkrementiere ich deshalb den Ausgang oft in jedem Rechenschritt falls noch eine Abweichung besteht und der zweite Summand 0 ist. In float müsste man sich ein geeignetes Inkrement überlegen. Out * eps oder so. Auch die Prüfung auf 0 geht nicht so einfach.
Ein Int32 sollte sicher genuegen. Falls nun der Anspruch kommt, alle ms zu sampeln, und trotzdem eine Zeitkonstante von 1 stunde zu haben kann man das Verfahren zweistufig laugffen laaasn, zB den ersten Tiefpass auf 15 Sekund laufen zu lassen, und alle 15 sekunden den wert in die zweite Stufe zu uebernehmen. Ist dann ein Tiefpass zweiter Ordnung, aber was solls.
Vielen Dank für die Hinweise. Ich werde den Filter zweistufig machen.
asd schrieb: > ich benutze eine PT1 Filter in dieser Art: > out = alt + k*(in-alt) > jedoch will ich eine relative lange Zeitkonstante (deswegen k bei 1e-6), > und hab einen uC der float nur mit einfacher Genauigkeit macht K=1e-6 ist ziemlich unsinnig. Du musst entweder die doppelte Genauigkeit nehmen oder die Abtastzeit verringern (wurde wohl schon gesagt). Außerdem ist das kein PT1 was du da rechnest. Die Berechnung eines PT1-Gliedes ist: X[n] = X[n-1]*(1-Ta/T)+Y[n]*Ta/T Dabei ist: X[n] der neue Ausgangswert, X[n-1] der vorhergehende Wert Y[n] der Eingangswert Ta die Abtastzeit T die Zeitkonstante
Hermann schrieb: > Außerdem ist das kein PT1 was du da rechnest. Haha. Du solltest mal etwas Rechnen lernen. Vor allem: * https://de.serlo.org/mathe/artikel-und-videos-aus-serlo-1-spaeter-loeschen/substitution * https://de.serlo.org/mathe/terme-gleichungen/terme-variablen/zusammenfassen-ausmultiplizieren-faktorisieren/klammern-ausmultiplizieren * https://de.serlo.org/mathe/terme-gleichungen/terme-variablen/zusammenfassen-ausmultiplizieren-faktorisieren/ausklammern
Grundschullehrer schrieb: > Haha. Du solltest mal etwas Rechnen lernen Dann noch mal für Grundschullehrer zum mitsprechen: Neu = Alt*(1-k) + In*k Mit k = Abtastzeit / Zeitkonstante
Siehe auch http://www.ibrtses.com/embedded/exponential.html Man macht die Division am besten als 2^n, sprich nach rechts schieben.
Hermann schrieb: > Dann noch mal für Grundschullehrer zum mitsprechen: Wer im Glashaus sitzt, ... Hermann schrieb: > Neu = Alt*(1-k) + In*k > Mit k = Abtastzeit / Zeitkonstante Neu = Alt*(1-k) + In*k Neu = Alt - Alt*k + In*k (ausmultipliziert) asd schrieb: > out = alt + k*(in-alt) out = alt + k*(in-alt) out = alt + k*in - k*alt (ausmultipliziert) Umgestellt und übereinander geschrieben: asd-Version: out = alt + k*in - k*alt Hermann-Version: Neu = Alt + In*k - Alt*k Aus welchem Bundesland kommst Du?
asd schrieb: > out = alt + k*(in-alt) Ok, das stimmt dann auch. Spart sogar etwas Rechenzeit. Subtraktion statt Multiplikation.
Hallo, warum nicht mal mit der exakten Lösung des PT1-Gliedes arbeiten? for(;;) { y = exp(-t/TAU)* y0 + (1-exp(-t/TAU)) * u; y0=y; } u kommt vom ADC TAU ist die Zeitkonstante, 1/TAU = OmegaEck, also der -3dB-Punkt. t ist die Abtastzeit, die for-Schleife ist alle Abtastzeit zu durchlaufen. y0 die Anfangsbedingung y die Ausgangsgröße des PT1-Gliedes. Damit reduziert sich die Berechnung auf add und mult -> DSP. Dieses PT1-Glied ist solange stabil, wie EXP... mit gewünschter Auflösung berechnet wird. VG Walter
PTx schrieb: > Deshalb nehm ich dann ein PT1 mit 1h Zeitkonstante, das mir alle 1sec > einen Eingangswert nimmt, und schalte dem ein PT1 mit 1s Zeitkonstante > und 1ms Abtastzeit davor. > > Das schnelle PT1 Filter wirkt hier also eher wie ein Antialiasing > Filter. Das Antialiasing ist bei dieser Dimensionierung leider unvollständig. Wenn das Eingangssignal bspw. eine Frequenzkomponente von 1Hz enthält, wird diese durch das Filter mit τ=1s nur um 3db gedämpft. Durch die anschließende Abtastung mit 1Hz kann deswegen ein unerwünschter Gleichanteil entstehen, der durch das nachgeschaltete Filter trotz seiner großen Zeitkonstante von 1h nicht weggefiltert wird. Walter L. schrieb: > warum nicht mal mit der exakten Lösung des PT1-Gliedes arbeiten? > > for(;;) > { > y = exp(-t/TAU)* y0 + (1-exp(-t/TAU)) * u; > y0=y; > } Ersetze exp(-t/TAU) durch 1-k, y durch out, y0 durch alt, u durch in und fasse auf der rechten Seite der Gleichung alle Summanden, die den Faktor k enthalten zusammen, dann erhältst du out = alt + k*(in-alt) also genau die Gleichung, die der TE verwendet hat und deren Berechnung mit 32-Bit-Floats zu große Rundungsfehler aufweist. Auch wenn ich persönlich für solche Anwendungen die Integer-Arithmetik bevorzuge (konstante Auflösung über den gesamten Wertebereich, Fehler besser abschätzbar, auf CPUs ohne FPU oft effizienter usw.), habe ich mich mal in einem Berechnungsverfahren für 32-Bit-Float- Arithmetik versucht, das denselben Filtertyp wie der des TE, aber mit geringeren Abweichungen vom Ideal realisiert. Das Filter des TE (zeitdiskreter Tiefpass 1. Ordnung) wird durch folgende Formel beschrieben, die in jedem Zyklus neu berechnet wird: y' = y + k · (x - y) Das Problem: Macht das Eingangssignal bspw. einen Sprung und bleibt dann konstant auf einem non 0 verschiedenen Wert x0 stehen, nähert sich das Ausgangssignal asymptotisch diesem Wert. In jedem Zyklus wird der Ausgangswert y um Δy=k·(x-y) erhöht. Je mehr sich y x0 annähert, desto kleiner wird Δy. Irgendwann ist Δy relativ zu y so klein, dass die Addition auf Grund der begrenzten Auflösung der Zahlendarstellung zu keiner Änderung von y mehr führt. Zu diesem Zeitpunkt ist Δy zwar winzig, trotzdem hat y zum Zielwert x0 noch einen Abstand von x0-y=Δy/k, was bei sehr kleinem k (beim TE ist k=1e-6) ein nicht zu vernachlässigender Fehler sein kann. Lösungsansatz mit Einschränkungen: Das Problem stellt sich nicht, wenn x0=0 ist, sich y also asymptotisch der 0 annähert. In diesem Fall reduziert sich obige Formel zu Δy = -k · y Ist k größer ist als die relative Auflösung der Zahlendarstellung (bei 32-Bit-Floats 2**-23≈1.2e-7) führt dieses Δy bei der Addition solange zu einer Veränderung von y, bis x=0 wird. Bei einem bekannten Sprung des Eingangssignals könnte man sich diese Eigenschaft zunutze machen, indem man statt des Ausgangssignals y dessen Abstand u zu x0, also u=y-x0 berechnet. Substituiert man in der Formel ganz oben y durch x0+u, erhält man x0 + u' = x0 + u + k · (x - (x0 + u)) => u' = u + k · ((x - x0) - u) Die letzte Gleichung entspricht der ursprünglichen, nur dass y durch u=y-x0 und x durch x-x0 ersetzt worden ist. Sowohl Eingangs- als auch Ausgangssignal werden jetzt also nicht mehr absolut, sondern auf x0 bezogen betrachtet. Diese Vorgehensweise hat eine gewisse Ähnlichkeit mit dem Kleinsignal- verfahren in der Analogelektronik. x-x0 und u=y-x0 sind sozusagen die Kleinsignale des Eingangs- und Ausgangssignals und x0 ist der Arbeits- punkt, auf den sich beide Signale beziehen. Aus u kann man mit y=x0+u jederzeit den Ausgabewert y berechnen, der durch den kleinen Umweg bei der Berechnung jetzt tatsächlich gegen x0 konvergiert und nicht schon vorher auf einem anderen Wert stehenbleibt. Einen wirklichen Nutzen bringt dieser Trick leider nur bei Eingangs- signalen, die nach jeder Änderung über einen längeren Zeitraum konstant sind, so dass man diesen konstanten Wert in der Berechnung jeweils als Arbeitspunkt x0 verwenden kann. Zappelt das Eingangsignal x hingegen wie wild hin und her, kann das Ausgangssignal y beliebig stark von x abweichen, so dass u nicht klein genug ist, um die Auslöschungsfehler wirksam zu bekämpfen. Die eigentliche Lösung: Was spricht aber dagegen, den Arbeitspunkt aus dem – auf Grund der Tiefpassfilterung – deutlich weniger zappeligen Ausgangsignal zu gewinnen? Nichts. Statt auf x0 aus dem Eingangssignal bezieht man die Signal also auf ein y0, das man zu geeigneten Zeitpunkten aus dem Ausgangsignal pickt. Anstelle von u=y-x0 nennen wir das Ausgangskleinsignal jetzt v=y-y0, und die Berechnungsformel lautet jetzt: v' = v + k · ((x - y0) - u) Da sich y nur langsam ändert, kann der Arbeitspunkt y0 über einen längeren Zeitraum beibehalten werden. Erst wenn v einen gewissen Wert übersteigt, so dass bei der Berechnung Auslöschungsfehler drohen, wird y0 auf einen neuen Wert, nämlich das aktuelle y gesetzt. Damit wird v wieder zu 0, und das Spiel beginnt von neuem. Auf diese Weise wird der Fehler der berechneten Ausgangswerte deutlich verringert, und das auch bei zappeligem Eingangsqsignal. Bei einem über längere Zeit konstanten Eingangssignal kann das Ausgangs- signal dennoch schon vor dem Erreichen der Asymptote stehenbleiben. Das passiert immer dann, wenn v auf Grund von Rundungsfehlern gegen einen von der eigentlichen Asymptote verschiedenen Wert konvergiert, und v unterhalb der Grenze bleibt, an der y0 aktualisiert wird. Der dadurch entstehende Fehler ist zwar deutlich kleiner als im ursprünglichen Filteralgorithmus, trotzdem möchte man ihn natürlich gerne vermeiden. Am einfachsten geschieht dies dadurch, dass y0 unabhängig vom Verlauf von v immer nach Ablauf einer vorgegebenen Zeitspanne (bspw. 1τ) aktualisiert wird. Was bringt der ganze Aufwand nun an Genauigkeit? Ich habe die obigen Überlegungen ebenso wie das Originalfilter des TE und das zweistufige (kaskadierte) Filter von "PTx" in C-Funktionen umgesetzt. Im C-Code wird v in ydelta und y0 in ybase umbenannt (viele Programmierer bestehen ja auf etwas längere Variablennamen ;-)). Die arithmetischen Ausdrücke in den drei Filterroutinen sind mit vielen float-Casts gespickt, um die Rundungsfehler auf der Plattform des TE, auf der es keine 64-Bit-Floats gibt, nachzubilden. Ein weiteres Filter entspricht dem des TE, ist aber mit 64-Bit-Float- Arithmetik implementiert, so dass die Fehler im Vergleich zu den anderen Verfahren vernachlässigbar sind. Das Ausgangssignal dieses Filters wird als Referenz bei der Bewertung der anderen Verfahren verwendet. Als Eingangssignale für den Test wird ein Sprung-, ein Rechteck- und ein Rauschsignal generiert (s. signalformen.png im Anhang). Die Berechnung der Ausgangssignale der einzelnen Filter läuft über 20e6 Abtastzyklen. Die jeweiligen Differenzen zum Referenzsignal sind in abweichungen.png dargestellt. Das Originalfilter weicht beim Sprungsignal um bis zu 0,03 von der Referenz ab, was der Grund dafür war, dass der TE diesem Thread gestartet hat. Auch beim Rechtecksignal ist der Fehler noch sehr groß. Nur beim Rauschsignal werden zufriedenstellende Ergebnisse geliefert. Das kaskadierten Filter liefert beim Sprung- und Rauschsignal nach dem Einschwingen gute Ergebnisse, nur direkt nach dem Start bzw. nach dem Sprung sind die Fehler größer. Beim Rechtecksignal zeigt das Filter aber das oben beschrieben Abtastproblem, was in einem so großen Fehler resultiert, dass die Kurve nicht zusammen mit den beiden anderen in einem Digramm dargestellt werden konnte. Bei dem Filter mit der hier beschriebenen dynamischen Verschiebung des Arbeitspunkts sind die Fehler bei den Tests so klein, man sogar die Granularität der 32-Bit-Float-Darstellung erkennen kann. Das bedeutet, dass man (zumindest bzgl. der getesteten Signalformen) nicht mehr viel optimieren kann. Ich kann aber nicht garantieren, dass die Fehler dieses Verfahrens bei beliebigen anderen Signalformen ebenso klein sind. Genauso wie das fiese Rechtecksignal die ansonsten guten Ergebnisse des kaskadierten Filters zunichte macht, gibt es vielleicht auch für mein Verfahren so ein Killersignal. Es war für mich zwar spannend, so etwas auszudenken, zu testen und zu vergleichen, im realen Leben fühle ich mich aber mit einem einfacheren Verfahren, das die gewünschte Genauigkeit mit geeigneteren Datentypen (32- oder 64-Bit-Integer oder 64-Bit-Float) erzielt, deutlich wohler. Wer aber – aus welchen Gründen auch immer – auf 32-Bit-Float-Arithmetik besteht, für den kann dieses Verfahren eine gute Alternative sein.
@yalu >In jedem Zyklus wird der Ausgangswert y um >Δy=k·(x-y) erhöht. Je mehr sich y x0 annähert, desto kleiner wird Δy. >Irgendwann ist Δy relativ zu y so klein, dass die Addition auf Grund der >begrenzten Auflösung der Zahlendarstellung zu keiner Änderung von y mehr >führt. Die Subtraktion ergibt schon eine Fehlerquelle. In der exakten Lösung gibt es keine Subtraktion. VG Walter
asd schrieb: > Jetzt komme ich in Bereiche in denen der Rundungsfehler dazu führt dass > ich einen gewissen Totbereich habe Mache die Rechnung in int, dann hast Du keinen Totbereich: out = sum / k sum = sum - out + in Bei einer konstanten Folge "in" wird nach endlicher Zeit immer "out" == "in". Man nimmt für k auch gerne 2-er Potenzen, dann geht schieben statt dividieren.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.