Hallo in die Runde. Ich generiere mir eine PWM im Phase Correct Modus des Atmega 8A via Atmel Studio 6. Hierzu habe ich ein samples-Array mit 256 Werten von 0-511-0. Als Phasenakku verwende ich eine uint16_t Variable die dann über ein Schieberegister >>8 die Indizes für den jeweiligen Wert ausgibt. Im Prinzip muss ich beim Programmstart nur noch die gewünschte Ausgangsfrequenz meines Signals eingeben und die restlichen Werte (Indexschrittweite etc.) werden automatisch berechnet. Jetzt zur Frage: Aktuell wird meine Schrittweite durch eine 16Bit Variable bestimmt. Meine PWM-Frequenz liegt bei 3,6kHz. Für ein Sinussignal mit 20Hz brauche ich dann 3600/(2*20) = 90 Werteänderungen je Halbwelle. Das ergibt dann für meine Indexschrittweite einen Wert von 2,844444444. In mein Highbyte schreibe ich also die 2 und in das obere nibble des Lowbytes die 8 und in das unter nibble die 4. Jetzt erzeuge ich allerdings immernoch einen Rundungsfehler, da ja meine Schrittweite eigentlich 65635/90=728,17777 sein müsste. 0x284 entspricht dezimal aber einer Schrittweite von 644. Kann mir jemand eine Möglichkeit nennen dieser Abweichung entgegenzuwirken?
Guck mal in die Appnote von atmel in sachen DTMF: http://www.atmel.com/dyn/resources/prod_documents/DOC1982.PDF Die machen da ja auch nur etwas DDS und verkleinern mit einen kleinen TRick den Fehler. Ganz wech kricht man den nicht.
Martin Wende schrieb: > Guck mal in die Appnote von atmel in sachen DTMF: > http://www.atmel.com/dyn/resources/prod_documents/DOC1982.PDF > > Die machen da ja auch nur etwas DDS und verkleinern mit einen kleinen > TRick den Fehler. > Ganz wech kricht man den nicht. Ah ok ich schau mir das mal an. Notfalls kann ich mit der Abweichung leben.
@ Peter A. (elkopeter) >Hierzu habe ich ein samples-Array mit 256 Werten von 0-511-0. >Als Phasenakku verwende ich eine uint16_t Variable die dann über ein >Schieberegister >>8 die Indizes für den jeweiligen Wert ausgibt. Schiebeoperation. Ein Schieberegister ist was anderes, nämlich ein logisches Bauteil. >Aktuell wird meine Schrittweite durch eine 16Bit Variable bestimmt. >Meine PWM-Frequenz liegt bei 3,6kHz. Für ein Sinussignal mit 20Hz >brauche ich dann 3600/(2*20) = 90 Werteänderungen je Halbwelle. ??? Die Berechnung des Frequenzeinstellwortes ist doch einfach. ftw = fa * 2^n / fs = 20 * 2^16 / 3600 = 364,0888888 wobe n die Bitbreite deines Phasenakkus ist. Das ist klar und deutlich. Klar gibt es einen Rundungsfehler, weilö man nur ganzzahlige Werte als Increment nutzen kann. D.h. deine Frequenz weicht etwas ab, in diesem Fall kommen halt 19,9951171875 Hz raus. Den Rundungsfehler kann man verkleinern, indem man die Bitbreite des Phasenakkus erhöht. Für deine Anwendung sollte das aber akademisch sein. Denn die Frequnenzauflösung leigt bei DDS immer bei fsa = fs / 2^n = 3600 / 2^16 = 0,054931640625 Hz. >Das ergibt dann für meine Indexschrittweite einen Wert von 2,844444444. Nö. Siehe oben. >In mein Highbyte schreibe ich also die 2 und in das obere nibble des >Lowbytes die 8 und in das unter nibble die 4. Mann O Mann. Du bist ein echter Künstler im umständlich ausdrücken. Normale Leute hätten einfach gesagt, dein Increment is 0x284 oder 644. >Jetzt erzeuge ich allerdings immernoch einen Rundungsfehler, da ja meine >Schrittweite eigentlich 65635/90=728,17777 sein müsste. 0x284 entspricht >dezimal aber einer Schrittweite von 644. ??? >Kann mir jemand eine Möglichkeit nennen dieser Abweichung >entgegenzuwirken? Deine Rechung stimmt nicht.
Peter A. schrieb: > Das ergibt dann für meine Indexschrittweite einen Wert von 2,844444444. > In mein Highbyte schreibe ich also die 2 und in das obere nibble des > Lowbytes die 8 und in das unter nibble die 4. Das ist schlicht falsch. Es handelt sich um einen Binärbruch, nicht um eine BCD-Darstellung. Den korekten Wert berechnest du, indem du einfach deinen Dezimalbruch mit 256 multiplizierst. Das Ergebnis ist 0x2D8. > Jetzt erzeuge ich allerdings immernoch einen Rundungsfehler Das ist kein Rundungsfehler, sondern einfach ein ganz normaler Fehler. Der Rundungsfehler ist dann das, was bei korrekter Umsetzung noch überbleibt. Im konkreten Fall rund 0.025% > Kann mir jemand eine Möglichkeit nennen dieser Abweichung > entgegenzuwirken? Man versteht, was man da benutzt? Naja, immerhin bist du deutlich weiter als die meisten normalen Codeklauer. Du überprüfst und hinterfragst das Ergebnis. Sehr guter Ansatz, da helfe ich dann auch gern weiter. Der nächste Schritt ist dann die Erkenntnis, daß Fehler immer zuallererst im eigenen Code zu suchen sind...
Falk Brunner schrieb: > Den Rundungsfehler kann man > verkleinern, indem man die Bitbreite des Phasenakkus erhöht. Oder ein etwas clevereres Konzept verwendet... Aber natürlich scheitern auch die clevereren Konzepte irgendwann an den Gesetzmäßigkeiten der Mathematik. Nur eben später als triviale Konzepte wie der sog. "Phasenakku" (der letzlich nichts anderes als eine primitive Festkomma-Addition darstellt)
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.