2012-11-26 8 views
5

Ich habe gerade ein DDS-Projekt auf einem Atmel AVR mit ASM abgeschlossen und bin zu dem Schluss gekommen, dass eine 8 Bit Look-Up-Tabelle und 8 Bit DAC zu viel Quantisierung erzeugen Verzerrung bei niedrigen Frequenzen; aus Mangel an besserem Wortlaut bekomme ich eine Sinuswelle mit einem Leiter-Effekt auf meinem Oszilloskop.DDS Interpolation - 8bit Atmel AVR ASM zu 12 bit DAC

Offensichtlich, wenn ich die Wellenform mit einem großen LPF glätten, habe ich Probleme mit der Amplitude in höheren Frequenzen.

Theoretisch sollte die Aufrüstung von einem 8 Bit auf 12 Bit DAC und die Verwendung von Interpolation mit den 4 niedrigstwertigen Bits den Grenzpunkt meines Filters deutlich genug erhöhen, um Probleme mit der Wellenformamplitude bei höheren Frequenzen zu verringern. Mein Problem ist, dass ich keine Ahnung habe, wie man das macht oder ob es einen einfacheren Weg gibt, den Reissverschluss-Effekt zu entfernen. Vielleicht 12-Bit-Look-Up-Tabellen?

Bisher habe ich eine Endlosschleife erstellt und jedes Mal, wenn die Schleife einen Zyklus beendet, wird ein Wert an den DAC gesendet, basierend auf der Position des Zeigers, der sich auf die Nachschlagetabelle bezieht. Hier bin ich verwirrt. Ich habe eine Menge Informationen darüber gelesen und habe immer noch kein funktionierendes Beispiel gefunden. Wenn ich eine Endlosschleife habe, wie soll ich die Interpolationswerte zwischen den Tabellennachschlagewerten stopfen? Über das Beste, was ich mir vorstellen kann, ist (a + b)/2; Ich kann das wahrscheinlich implementieren und ein zusätzliches Bit oder das Äquivalent einer Nachschlagetabelle mit 512 Punkten erhalten, aber ich würde gerne glauben, dass es einen einfacheren Weg oder etwas gibt, das möglicherweise bessere Ergebnisse liefern könnte. Ich weiß nicht, C oder wie man es anwendet, aber ich werde es versuchen, wenn es umsichtig ist.

Momentan ist meine Uhr bei 1MHz und ich könnte bei Bedarf zu 16MHz gehen. Hier

ist eine Probe von meinem Code:

; Setze Sinuswellenausgabe als Standard

ldi  ZH, High(sine*2); setup Z pointer hi 
    ldi  ZL, Low(sine*2) ; setup Z pointer lo 

; Klarer Akkumulator

clr  r29    ; clear accumulator 

; Setup-Addierer-Register

ldi  r24,0x50  ; Fine adder value change register 
    ldi  r25,0x08  ; Middle adder value change register 
    ldi  r26,0x00  ; Coarse adder value change register 

LOOP1:

add  r28,r24   ; 1 Adder values carry over to higher registers. Higher registers raise freq. in larger steps 
    adc  r29,r25   ; 1 
    adc  r30,r26   ; 1 r30 is database address pointer for Z register 
    lpm  r0, Z   ; 3 (Load Program Memory) Reads byte from database into the destination register based on Z pointer 
    out  PORTD,r0 


    rjmp LOOP1   ; 2 => 9 cycles 

Antwort

2

Wenn Ihre LUT 256 Einträge hat, können Sie zunächst die Register r29 verwenden (die anscheinend von 0 bis 255 geht) als Skalierungsfaktor zwischen zwei aufeinanderfolgenden Proben .

Output = (LUT[r30] * (256 - r29) + LUT[r30+1] * r29) >> 8;

Also this thread diskutiert viele praktische Alternativen zur Sinuswellenerzeugung.

EDIT Die Formel implementiert Textbuch Linearinterpolation

y = a*(1-t) + b*t, with 0<=t<1 

Damit y = a, wenn t 0 und y = b =, wenn t = 1 ist. Shifting by 8 bedeutet, dass der Interpolationsterm t nach der Multiplikation durch 256 geteilt wird. Im Ausdruck LUT [r30 + 1] nehme ich eine implizite Modulo-256-Arithmetik an, da r30 8-Bit ist (nicht wahr?).

LUT-Erweiterung auf 12 Bit muss separat durchgeführt werden, da die Division durch 4 stattdessen nur den Quantisierungsfehler in der LUT erhöhen würde.

enter image description here

Die Interpolation geschieht auf ganzzahlige Indizes in der LUT immer relativ unabhängig, wenn viele Proben auf den gleichen Bereich fallen zB. LUT 2 und LUT [3]. Mathematisch ist Lut [R], LUT [R + 1] korrekter als [R-1], [R], aber im wirklichen Leben gibt es keinen Unterschied, da das menschliche auditorische System keine absolute Referenzphase hat.

+0

Danke für Ihre Antwort. Ich verstehe es aber nicht. Warum acht Bits nach rechts verschieben? Der erste Teil der Gleichung könnte die Register sehr leicht überlaufen lassen. Würde nicht LUT [r30 + 1] die Phase der Wellenform ändern, nicht zum nächsten zeitempfindlichen Schritt des Zeigers vorrücken? Wäre es nicht sinnvoller, den vorherigen Zeigerschritt abzufragen? –