Ich habe ein Signal von 50Hz, welches mit 2.5kHz abgetastet wird. Von
diesem Signal soll der quadratische Mittelwert gefiltert werden, um
daraus RMS zu berechnen.
Entsprechend dieses Beitrages
Beitrag "Re: quadratischer mittelwert" mache ich das nach
der Formel, genaugenommen ein digitaler Tiefpass:
y(k+1)=((n-1)*y(k)+x(k+1)*x(k+1))/n
Umgesetzt habe ich das mit:
yqsum = yqsum - (yqsum + N/2) / N + vneu * vneu
yrms = sqrt(yqsum / N)
Damit wird in yqsum der um N vergrößerte Mittelwert zwischengespeichert,
damit die Bits nicht abgeschnitten werden.
Funktioniert soweit, aber die Werte schwanken bei N = 256 noch um etwa
1% des Messwertes. Was auch gut mit der Simulation der Daten
übereinstimmt. Diesen Ripple könnte ich jetzt verhindern, indem ich N
erhöhe, dazu müsste ich allerdings auf N = 4096 oder höher gehen, was
zum einen den Tiefpass sehr langsam macht, zum anderen meine 32bit-Summe
sprengt. Mit 64bit wird dann die Rechnung wieder zu langsam, um die
Werte rechtzeitig abarbeiten zu können.
Die Lösung wäre jetzt ein Filter höherer Ordnung. Kann man sowas digital
implementieren?
Eine Erhöhung der Messfrequenz oder ein "echter" Mittelwertfilter mit
Ringbuffer sind nicht möglich, weil 10 Kanäle abgearbeitet werden und
dafür weder Speicher noch Taktrate ausreichen.
Naja, ein Tiefpass läuft der Sinuswelle halt nach. Lösen kannst Du das
nur mit RAM (mut fifo über ganze Perioden Mitteln), oder über viele
Perioden.
Die erste Methode kostet zwar RAM, aber spart Rechenzeit.
Die Alternative: über ganze Perioden mitteln und nur diese Ergebnisse
exponentiell glätten. Also 25 oder 50 Zyklen nur quadr. addieren.
Karl schrieb:> Ich habe ein Signal von 50Hz, welches mit 2.5kHz> abgetastet wird. Von diesem Signal soll der> quadratische Mittelwert gefiltert werden, um daraus> RMS zu berechnen.>> Entsprechend dieses Beitrages> Beitrag "Re: quadratischer mittelwert" mache ich das> nach der Formel, genaugenommen ein digitaler Tiefpass:> [...]
Warum?
Du hast aufgrund der 50Hz offenbar ein periodisches Signal;
also integriere doch einfach genau über eine Periode (bzw.
über eine GANZE Anzahl von Perioden).
Fünf Vollwellen (=100ms) bieten sich an; das sind gerade
250 Abtastwerte.
Possetitjel schrieb:> Du hast aufgrund der 50Hz offenbar ein periodisches Signal;> also integriere doch einfach genau über eine Periode (bzw.> über eine GANZE Anzahl von Perioden).> Fünf Vollwellen (=100ms) bieten sich an; das sind gerade> 250 Abtastwerte.
Habe ich auch schon überlegt, aber Bedenken: Was passiert, wenn die
Frequenzen nicht genau übereinstimmen? Gibt das dann nicht eine
Schwebung im Ausgangssignal?
Ich müßte also eine PLL der Abtastfrequenz auf das Abtastsignal machen.
Zweites Problem: Division durch 250 ist deutlich zweiraubender als
Division durch 256. Aber ich könnte vielleicht versuchen meine
Abtastfrequenz etwas anzupassen, so dass 256 Messwerte = 5 Perioden
sind.
Moin,
Karl schrieb:> Die Lösung wäre jetzt ein Filter höherer Ordnung. Kann man sowas digital> implementieren?
Klar kann man das machen. Bloss machen halt IIR Filter gerne Malheur
wegen Rundung und Uebersteuerung. Daher werden Filter hoeherer Ordnung
gerne als Kettenschaltung von Filtern mit max. 2. Ordnung realisiert.
Ein ganz simpler Schritt in diese Richtung waer', wenn du einfach das
Ergebnis aus deinem Filter in ein weiteres, gleich aufgebautes Filter
gibst.
Gruss
WK
Karl schrieb:> Possetitjel schrieb:>> Du hast aufgrund der 50Hz offenbar ein periodisches Signal;>> also integriere doch einfach genau über eine Periode (bzw.>> über eine GANZE Anzahl von Perioden).>> Fünf Vollwellen (=100ms) bieten sich an; das sind gerade>> 250 Abtastwerte.>> Habe ich auch schon überlegt, aber Bedenken: Was passiert,> wenn die Frequenzen nicht genau übereinstimmen?
Nicht sehr viel.
> Gibt das dann nicht eine Schwebung im Ausgangssignal?
Ja, klar.
Hast Du mal versucht, die Größe der Auswirkung abzuschätzen?
> Zweites Problem: Division durch 250 ist deutlich> zweiraubender als Division durch 256.
Sicher.
Aber Division durch 256 und anschließendes Multiplizieren
mit 1.024 ist nicht so kompliziert.
Und -- nein, man braucht dazu nicht zwingend Fließkommazahlen.
> Aber ich könnte vielleicht versuchen meine Abtastfrequenz> etwas anzupassen, so dass 256 Messwerte = 5 Perioden sind.
Das geht natürlich auch.
Karl schrieb:> Zweites Problem: Division durch 250 ist deutlich zweiraubender als> Division durch 256.
Wer zwingt dich denn zu einer Abtastfrequenz von 2,5kHz?
Was spricht gegen 2,56kHz?
Dergute W. schrieb:> Ein ganz simpler Schritt in diese Richtung waer', wenn du einfach das> Ergebnis aus deinem Filter in ein weiteres, gleich aufgebautes Filter> gibst.
Was dem elektronischen Äquivalent von zwei hintereinander geschalteten
RC-Tiefpässen entspräche?
Der doppelte Speicherbedarf wäre hier im Gegensatz zum Ringbuffer kein
Problem, die Rechnerei dürfte sich auch auf 32 Bit beschränken und die
Ausführungszeit würde sich knapp verdoppeln... mal probieren.
Possetitjel schrieb:> Ja, klar.> Hast Du mal versucht, die Größe der Auswirkung abzuschätzen?
Die Simulation sagt, bei 50.2Hz und 50 Werten pro Periode 0.4% Ripple,
das ist so viel wie der Tiefpass mit N = 1024 bringt.
Possetitjel schrieb:> Das geht natürlich auch.
Hab das gerade mal durchgerechnet: 256 Werte x 2 Byte x 7 Kanäle (es
werden 10 Kanäle gemessen, aber nur 7 gespeichert) bekomme ich nicht in
den Ram, 128 Werte gehen.
Aktuell habe ich 50 Messungen pro Periode: Um auf 2^n zu kommen müsste
ich auf 32 Messungen pro Periode runtergehen, hätte dann 4 Perioden im
Buffer. Würde halt Auflösung verschenken.
Oder auf 64 Messungen hochgehen, das wird aber seeeehr knapp mit dem
AD-Wandler.
Verdammte Axt! Ich brauche gar keinen riesigen Ringbuffer. Ich brauche
auch keinen gleitenden Mittelwert.
Ich brauche nur einen kleinen Ringbuffer, in den der ADC die Daten
schiebt und der alle paar msec ausgewertet wird. Die Werte quadriere und
summiere ich, zähle dabei mit und wenn 50 Werte zusammen sind, bilde ich
aus der Summe einmal den Mittelwert.
Dann habe ich zwar nur 50 Werte pro Sekunde, aber das reicht allemal.
Über die schiebe ich noch ein IIR mit N = 16 oder 32 und komme unter
0.1% Ripple. Die Frequenz darf halt nicht mehr als 0.2Hz abweichen.
Sollte doch gehen, oder?
Moin,
Karl schrieb:> Sollte doch gehen, oder?
Sollte schon. Zumindest hab ich das auch schon gemacht; da tast' ich im
AVR mit 32kSamples/sec ein Audiosignal ab, jag's durch eine Filterbank
und summiere so die Momentanpegel der einzelnen Frequenzbaender auf, um
sie danach anzuzeigen...
Beitrag ""LED-Spectrumanalyzer"software ohne Fouriertransformation"
Gruss
WK
c-hater schrieb im Beitrag #5320358:
> Schwachsinn (zumindest zur Hälfte)...
Hach Gottchen, was bist Du denn für ein Troll?
Possetitjel schrieb:> Aber Division durch 256 und anschließendes Multiplizieren> mit 1.024 ist nicht so kompliziert.
Ich habe es jetzt mit einem periodischen Mittelwertfilter und einem
nachgeschalteten Tiefpass gelöst.
Die Divison 32 Bit / 50 in Asm optimiert braucht 20µsec, die
Quadratwurzel nochmal ähnlich. Damit kann ich leben.
Karl schrieb:> Ich brauche nur einen kleinen Ringbuffer,
Das ist ja schön, wenn Du die Antworten hier umsetzt, aber erklär doch
mal, wozu Du dann den Ringbuffer einbaust? Er spart Dir doch keine
Rechenzeit.
Achim S. schrieb:> wozu Du dann den Ringbuffer einbaust? Er spart Dir doch keine> Rechenzeit.
Nö, aber der ADC wird per ISR alle 40usec bedient. Die ISR möchte ich so
kurz wie möglich halten, also wirklich nur Wert auslesen, dem passenden
Kanal zuordnen, neuen Kanal setzen und nächste Wandlung fertigmachen.
Die wird dann im Timer-Interrupt gestartet.
Im Hauptprogramm habe ich dann genug Zeit, die bisherigen Werte auf
gültigen Bereich zu prüfen, zu skalieren und zu mitteln. Auch werden
mehrere Kanäle miteinander verrechnet (Offset...), was in der ISR nicht
möglich wäre, weil ich da nur immer den Wert des aktuellen Kanals habe.
Die Berechnung erfolgt über etwa 10 Werte, wobei es auch nicht schlimm
ist wenn mal mehr Werte auflaufen, weil gerade ins Display geschrieben
wird. Die Werte müssen nur so schnell abgearbeitet werden, dass der
Buffer nicht vollläuft, sprich der Write-Pointer den Read-Pointer
einholt.
Karl schrieb:> Nö, aber der ADC wird per ISR alle 40usec bedient. Die ISR möchte ich so> kurz wie möglich halten, also wirklich nur Wert auslesen, dem passenden> Kanal zuordnen, neuen Kanal setzen und nächste Wandlung fertigmachen.> Die wird dann im Timer-Interrupt gestartet
Ich kenne ja Dein Programm nicht, und betrifft auch nicht die
Fragestellung, aber es ist (bei >> 8Bitter) relativ unwahrscheinlich,
dass Y+=adc*adc mehr Zeit braucht, als der Eintrag in einen
interruptfesten Fifo (inclusive der Sperrzeit zum Auslesen, die gehört
ja dazu!).
Wenn Du die Summe geschickt wählst (im Takt Deiner Main-Loop), dann
kannst Du sogar auf jedes blockieren verzichten (und mit
Spiegelvariablen arbeiten).