Datum: 14.05.2008 17:38
Hallo, mein Controller liest von 10 Kanälen 16-Bit Messwerte mit ca. 10 Hz ein. Die Messwerte sind mit ca. 4 Bit ziemlich verrauscht. Mit 3 Hz soll ein geglätteter Messwert ausgegeben werden. Welche Methode wäre dafür geeignet (ausreichend schnell, aber ressourcenschonend)? Eine long Variable pro Kanal zum aufaddieren und anschließender Division scheint mir zu ressourcenintensiv. Eine exponentielle Glättung ist sicher zu langsam. Was gäbe es noch für Möglichkeiten? Grüße, Bastian
Datum: 14.05.2008 17:41
Bastian G. wrote: > Hallo, > > mein Controller liest von 10 Kanälen 16-Bit Messwerte mit ca. 10 Hz ein. > Die Messwerte sind mit ca. 4 Bit ziemlich verrauscht. Mit 3 Hz soll ein > geglätteter Messwert ausgegeben werden. > Welche Methode wäre dafür geeignet (ausreichend schnell, aber > ressourcenschonend)? > Eine long Variable pro Kanal zum aufaddieren und anschließender Division > scheint mir zu ressourcenintensiv. Du kriegst von Atmel kein Geld zurück, wenn sich der µC langweilt. Bei deinen Timing Werten kann der µC zwischendurch noch ein paar hundert teuflisch schwierige quadratische Gleichungen (tm) lösen ehe er vor Langeweile ins Koma fällt.
Datum: 14.05.2008 17:54
Addiere einfach z.B. 16 Messwerte und mache dann ein Rechtsshift um 4 Stellen. Da kommt der Controller auch nicht in schwitzen ;) Gruß
Datum: 14.05.2008 19:45
Bastian G. wrote: > Eine long Variable pro Kanal zum aufaddieren und anschließender Division > scheint mir zu ressourcenintensiv. > Eine exponentielle Glättung ist sicher zu langsam. Da sieht man mal wieder was heute fuer Vorstellungen von Rechenleistung bestehen. Unter 64Bit bei 3GHz geht garnix... ne? ;)
Datum: 14.05.2008 19:53
Nimm 2^n Werte und du brauchst nur logisch zu schieben. Bei 10ksps die der Atmel locker mitmacht kannst du pro Kanal 1024 Samples aufnehmen und hast immernoch 10Hz. Und wenn du den ADC Interrupt benutzt hast du sogar noch massig Rechenzeit für andere Dinge über. Ach ja, und die Genauigkeit wird am Ende wohl eher bei 12..14 Bit liegen.
Datum: 14.05.2008 20:16
Du könntest die Abtastrate im Eingang auf 12 Hz hochdrehen, Dann kannst Du 4 Messwerte addieren und das Ergebnis durch 4 teilen. Durch 4 teilt man durch Schieben um 2 bit nach rechts (in C der Operator ">>"). Wenn Du die long-Variable vermeiden willst, kannst Du auch vor dem Addieren jeden einzelnen Messwert durch 4 teilen. Dadurch verlierst Du Genauigkeit, aber bei 4 bit Rauschen ist das vielleicht nicht so wichtig.
Datum: 14.05.2008 21:27
>Eine exponentielle Glättung ist sicher zu langsam. http://www.ibrtses.com/embedded/exponential.html
Datum: 15.05.2008 08:20
ich bevorzuge die gleitende Mittelwertbildung.
Wert = Wert(alt) *3 + Wert (neu)
--------------------------
4
danach wird Wert zu wert (alt)
Voila
Datum: 15.05.2008 08:24
man kann auch sehr schön folgendes machen bei Kontinuierlichen Sachen die sich nicht sprunghaft ändern (geschwindigkeit, temperatur...) WERT_neu/2 + Wert_alt1/4 + Wert_alt2/8 + Wert_alt3/8 to be continued...
Datum: 15.05.2008 08:31
Danke schonmal für eure Anregungen! Diesmal benutze ich keinen Atmel, sondern einen Freescale MC9S12. Hätte ich erwähnen sollen. Die Messwerte kommen über den I2C Bus, nicht von den internen ADCs. Was die Prozessorauslastung hochtreibt ist allerdings das kontinuierliche Senden von Messwerten über die serielle Schnittstelle. Die Routinen dazu sind nicht optimal (Polling statt IRQ), lassen sich jetzt aber nicht mehr ändern. @Matt: Danke für den Link. Ich hatte diesen schon in einem älteren Posting gefunden und mal mit Excel durchgerechnet. Erschien mir auf den ersten Blick aber, selbst mit N = 0,25, sehr langsam.
Datum: 15.05.2008 11:18
Im Anhang ein kleiner Vergleich verschiedener Methoden. Sehr gut, da schnelle Reaktion auf Änderungen, gefällt mir die Variante von Läubi. Allerdings müssen pro Kanal 4 Werte gespeichert werden. Bei 10 Kanälen ist das nicht wenig.
Datum: 15.05.2008 11:36
>Allerdings müssen pro Kanal 4 Werte gespeichert werden. Bei >10 Kanälen ist das nicht wenig. Irgendwo wirst du wohl Prioritäten setzen müssen. Qualität vs. Speicherbedarf vs. Rechenaufwand. Ich bevorzuge Stephans Methode. Ist schnell implementiert und liefert gute Resultate. Bei deinen Messwerten reicht ggf. schon folgende Glättung: Wert = Wert(alt) + Wert (neu) -------------------------- 2 Das reagiert noch einen Ticken schneller und braucht kaum Speicher.
Datum: 15.05.2008 17:41
@Stephan und Kai: ich verwende eine ähnliche, aber bessere Methode: Aver = Aver + ADC - (Aver >> x); Das hat zur Folge, dass Aver auf den 2^x-fachen Wert von ADC ansteigt. Entweder ich rechne gleich mit Aver weiter, oder teile ihn durch 2^x (und runde) in dem Augenblick, in dem ich ihn brauche (was in der Regel seltener als die Abtastrate ist). Wenn ADC 16 Bit hat, bleibt nichts anderes als für Aver 24 oder 32 bit zu verwenden. Oder wie Wolfgang schrieb, kannst Du es auch so machen: Aver = Aver + (ADC >> y) - (Aver >> x); Aver ist dann im Bereich ADC * (2^(x-y)) Bei z.B. x = y = 2 reichen dann auch für Aver 16 Bit aus. Da war ich auch schonmal versucht, sowas zu schreiben, um einen Shift zu sparen: Aver = Aver + ((ADC - Aver) >> x); Aber der Effekt ist nicht wie erwünscht, Aver ist dann immer einen Tick zu klein. Eine andere Methode wäre ein echter Digitalfilter (Tiefpass FIR oder IIR) ala Bessel, Butterworth, Tschebyscheff.... Der reagiert schnell auf Änderungen und filtert trotzdem gut. Ansonsten empfehle ich immer, die Ursache zu suchen und weniger an den Symptomen zu doktern: Vermutlich hast Du eine Gnd-Schleife oder ähnliches, also ein Analog-Problem. Auch die digitalen Signale (SDA und SCL) können die Wandlung beeinflussen. Da würde ich mal jeweils auf der Treiberseite einen Dämpfungswiderstand (10-82 Ohm) einfügen. Welche Sprache? Um welche Signale handelt es sich? Welche Wandler verwendest Du? Habe mit der ADS125x-Familie (24 Bit Delta-Sigma) sehr gute Erfahrung gemacht (mit erhöhtem externen Aufwand 18 echte Bits bei 100 Hz).
Datum: 15.05.2008 17:52
Hallo, die Form xk+1 = (a*uk+1 + b*xk)/(a+b) ist die zeitdiskrete Form eines Tiefpassfilters erster Ordnung. xk+1 = a*uk+1 + (1-a)*xk mit 0<=a<=1 als "Filterzeitkonstante". Wenn a=1 kein Filter, wenn a=0 alles gefiltert (alles tot). Man kann also mit a spielen und so das Filter anpassen.
Datum: 15.05.2008 18:06
Bastian G. wrote: > Im Anhang ein kleiner Vergleich verschiedener Methoden. > Sehr gut, da schnelle Reaktion auf Änderungen, gefällt mir die Variante > von Läubi. Allerdings müssen pro Kanal 4 Werte gespeichert werden. Bei > 10 Kanälen ist das nicht wenig. Ich benutz das um die Digitalanzeige meines Tachos vorm "zittern" zu bewahren, klappt ganz gut, allerdings noch mit einer Stufe mehr. Und 40Werte a 16bit sind gerade mal 80bytes Ram das ist auch noch nicht soooo viel.
Datum: 20.05.2008 17:47
Ich habe nochmal nachgerechnet, auch das Filter von
Autor: Stephan (Gast)
Datum: 15.05.2008 08:20
ich bevorzuge die gleitende Mittelwertbildung.
Wert(alt) *3 + Wert (neu)
Wert = ---------------------------
4
danach wird Wert zu wert (alt)
erreicht übrigens auch nie den Eingangswert.
Das ganze hatten wir übrigens erst vor kurzem:
Beitrag "Digitales Filter"
Antwort schreiben
Die Angabe einer Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
- Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
- Aussagekräftigen Betreff wählen
- Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
- Groß- und Kleinschreibung verwenden
- Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
- JPEG-Dateien (.jpg) nur für Fotos und Scans verwenden
- Schaltpläne, Screenshots usw. als PNG oder GIF anhängen
Formatierung (mehr Informationen...)
- [c]C-Code[/c]
- [avrasm]AVR-Assembler-Code[/avrasm]
- [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
- [math]Formel in LaTeX-Syntax[/math]
- [[Titel]] - Link zu Artikel
