www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik DDS-Direct Digital Synthesis


Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe anscheinend irgendwo ein Denkfehler. Ich will mittels DDS ein 
Sinussignal erzeugen und komme mit dem Berechnen der Sprungweite nicht 
zurecht. Folgender Ansatz:

float sinustab[1000];

///Sinustabelle füllen

void sinusinit()//Tabelle mit Werten füllen
{
for(i=0;i<1000;i++)
{
sinustab[i]=sin(2*pi*i/1000);
}

//Funktion im DA Wandler

if (Wandler==ready) //Wenn der Wandler fertig ist für den nächsten Wert
{
int i;//
x=sinustab[(i+sprungweite)%1000];//Modulo 1000 wegen 1000 Werten

}


Wie berechne ich die Sprungweite abhängig von der gewünschten Frequenz?
wenn man eine Wandlerfrequenz von 10 kHz annimmt und einen Sinus mit 
10Hz ausgeben will muss man einfach jeden 10. Wert ausgeben. Das würde 
bedeuten:

Sprungweite=Wandlerfrequenz/Anzahl der Abtastwerte

Das ist zu einfach und außerdem fehlt die Ausgabefrequenz. Ist bestimmt 
ganz einfach nur komm ich momentan nicht drauf.

Viele Grüße

Horst

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Horst (Gast)

>x=sinustab[(i+sprungweite)%1000];//Modulo 1000 wegen 1000 Werten

Wenn es schneill gehen soll muss man mit einer 1024er Tabelle arbeiten, 
da kann man das Modulo über ein wesentlich schnelleres AND machen.

>Wie berechne ich die Sprungweite abhängig von der gewünschten Frequenz?
>wenn man eine Wandlerfrequenz von 10 kHz annimmt und einen Sinus mit
>10Hz ausgeben will muss man einfach jeden 10. Wert ausgeben. Das würde
>bedeuten:

Steht in jedem Datenblatt und Grundlagenpapier.

Du suchst das sog. Frequency Tuning Word.

DDS

//frequency tuning word = frequency * 2^32 / Clock DDS

MfG
Falk

Autor: 6632 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Horst, die Genialitaet des DDS ist noch nicht bei dir angekommen. Es 
geht so.
Man nimmt ein Register, dessen N Bits spannen einen Phasenraum von 2^N 
auf. Nehmen wir einen 32Bit zaehler, der zaehlt bis 4e9. Wenn wir nun 
jeden Clock eins addieren, so sind wir nach 2^N clocks rundrun. Bei 
einem 4GHz Clock wuerde das etwa eine Sekunde dauern. Ein Hertz. Wenn 
wir zwei addieren, kommen wir auf 2 Hz, usw. Diesen Phasenraum auf einen 
DAC zu geben waere unsinning, wir machen eine Abbildung, zB auf einem 8 
Bit DAC, dh wir nehmen nur das oberste Byte. Dieser DAC gibt nun eine 
Rampe aus, wir koennten auch eine Tabelle zwischenschalten wo jede 
position sich selbst enthaelt. Dann kriegen wir auch den Dreieck. Oder 
wir laden in die Tabelle einen Sinus, dann kriegen wir einen sinus.

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erst mal vielen Dank für die schnelle Hilfe. Wenn ich das ganze jetzt 
richtig verstanden habe müsste es so funktionieren?


float sinustab[1024];

///Sinustabelle füllen

void sinusinit()//Tabelle mit Werten füllen
{


for(i=0;i<1024;i++)
{
sinustab[i]=sin(2*pi*i/1024);
}

float sprungweite;

sprungweite=(Ausgabefrequenz*2^10)/Wandlerfrequenz;
//Berechnung der Sprungweite



//Funktion im DA Wandler

if (Wandler==ready) //Wenn der Wandler fertig ist für den nächsten Wert
{
float i;
int j;

i=i+sprungweite;
j=(int)i;      //Umwandlung auf den nächsten Wert
j=j&0x3ff;      //Begrenzung auf 1024 Werte
x=sinustab[j];
}

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Autor: 6632 (Gast) schrieb am 24.01.2008 um 20:11 Uhr:

>Horst, die Genialitaet des DDS ist noch nicht bei dir angekommen. Es
>geht so ...

Tolle Erklärung, viel besser als auf

http://de.wikipedia.org/wiki/Direct_Digital_Synthesis

oder

http://en.wikipedia.org/wiki/Direct_digital_synthesis

Autor: 6632 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Horst,
Der float ist unnoetig. Integer genuegt. Und der Phasenraum koennte 
groesser als der Tabellenraum sein. Am einfachsten ist ein Phasenraum 
von 2^16, 2^24, 2^32, 2^40, 2^48.

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke ich glaub jetzt hab ich´s kapiert

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Horst (Gast)

>Danke ich glaub jetzt hab ich´s kapiert

Da fehlt noch ne Kleinigkeit. Der Akkumulator ist meist recht breit, 
24..48 Bit. Aber nur die obersten N Bits werden zur Sinusberechnung 
genutzt. Da fehlt bei dir noch ne Schiebeoperation. Die 20 sind mal 
bezogen auf einen Phasenakku von 32 Bit. Ach ja, der Phasenakku ist KEIN 
float, der ist immer ein Integer! Und die Sinustabelle auch nicht, denn 
den DAC schluckt nur Integer. Nur zur Berechnung braucht man float.

uint8_t sinustab[1024];

///Sinustabelle füllen

void sinusinit()//Tabelle mit Werten füllen
{


for(i=0;i<1024;i++)
{
sinustab[i]=(float)max*sin(2*pi*i/1024);
}

uint32_t sprungweite;

// vorsicht 2^10 ist in C NICHT 2 hoch 10, das ist XOR!!!
// Berechnung auf 64 Bit casten, um Überlauf zu vermeiden

sprungweite= (uint64_t)Ausgabefrequenz*1024/Wandlerfrequenz;

//Berechnung der Sprungweite



uint32_t i;
uint16_t, j;

i=i+sprungweite;
j=i >> 22;      //Umwandlung auf den nächsten Wert
x=sinustab[j];

MfG
Falk

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Falk,
ich verstehe nicht, warum Du in der vorletzten Zeile 22 Bits schiebst.
Kannst Du mir da auf die Sprünge helfen?

Gruß,
Klaus

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Klaus (Gast)

>ich verstehe nicht, warum Du in der vorletzten Zeile 22 Bits schiebst.

Weil i der 32 Bit Phasenakku (Phasenwert) ist. Da wir aber keine 
Sinustabelle mit 2^32 Einträgen haben, verwenden wir nur die oberen 10 
Bits zur Umwandlung Phase -> Sinus. D.h. unser 32 Bit Phasenwert muss um 
22  Bit nach rechts geschoben werden. Damit erhalten wir einen 10 Bit 
Sinuswert mit abgeschnittenen "Nachkommastellen". Damit können wir in 
unsere 1024er Tabelle gehen.

MFG
Falk

Autor: Ralf Schwarz (spacedog) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Als ich mal in der Not war, hab ich ne DDS mit Ausgabe per PWM auf nem 
167 oder so gemacht :-P
Siehe Anhang.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Falk,
wenn ich nach Deinem Beispiel z. B. eine Sprungweite von 1 habe, diese 
auf i addiere wird j aber nur rund alle 4 millionen Durchläufe erhöht. 
D. h. die kleinste sinnvolle Sprungweite müsste 2^22 sein. Das macht 
doch keinen Sinn?!

Gruß,
Klaus

Autor: Hannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch ein Hinweis zum Nachbauen.
im Tuning word steht die 1024 nicht für die Anzahl der stützwerte aus 
der Sinustabelle, sondern für die Größe der Sprungweite bis zum 
Überlauf. Also für uint32_t sprungweite; 32 bit wäre das 2^32=4294967296

Folglich heißt das tuning word hier
sprungweite= (uint64_t)Ausgabefrequenz*4294967296/Wandlerfrequenz;

Quelle:
http://www.analog.com/static/imported-files/tutori...

Seite 8 unten; Formel nur nach m umstellen

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.