DDS-Direct Digital Synthesis

Gast #761358
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
#761372
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
Gast #761393
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.
Gast #761425
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];
}
#761492
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.

1
uint8_t sinustab[1024];
2

3
///Sinustabelle füllen
4

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

8

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

14
uint32_t sprungweite;
15

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

19
sprungweite= (uint64_t)Ausgabefrequenz*1024/Wandlerfrequenz;
20

21
//Berechnung der Sprungweite
22

23

24

25
uint32_t i;
26
uint16_t, j;
27

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

MfG
Falk
#1075121
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
Gast #1078283
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
Gast #2409687
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/tutorials/450968421DDS_Tutorial_rev12-2-99.pdf

Seite 8 unten; Formel nur nach m umstellen

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren