Forum: Mikrocontroller und Digitale Elektronik DDS Frequenzauflösung


von DDS (Gast)


Lesenswert?

Hallo, Ich habe ein Verständnisproblem zu der Auflösung einer DDS.

Also ich habe gelesen, dass man den Phasenakkumulator für die 
Lookup-Table mit double Werten aufaddieren kann. Ich bin bisher immer 
von ganzen Zahlen (Integer) ausgegangen. Da ist die bestimmung der 
maximalen Auflösung dann für mich eigentlich leicht zu berechnen und 
zwar ausgegangen von einer Binären Zweierpotenz wäre das demnach 
f_auflösung = f_systemtakt / 2^Anzahl_Bits.
Wie berechne ich nun die Auflösung wenn ich eine Reele Zahl habe, 
angenommen ich habe eine Systemfrequenz von 4MHz und eine Bitbreite von 
10 bits wobei 5 Bits für die Nachkomma- und die anderen 5 Bits für die 
Vorkommastelle sind.

Ich stelle mir das bisher so vor und zwar:

nachkomma_stelle = 5 Bits, macht 2^5 - 1 = 31 (Ist die höchste 
darstellbare Nachkommastelle)
vorkomma_stelle = 5 Bits, macht 1 - (1/32) = 0,96875 (Ist die höchste 
darstellbare Vorkommastelle)

f_auflösung wäre demnach = f_systemtakt / 31,96875

Ist meine Annahme richtig oder liege ich auf dem Holzweg?

Durch Einführung in den Reelen Zahlenbereich, bekomme ich ja auch eine 
neue Maximale und Minimale Frequenz die ich darstellen kann, wie 
berechne ich diese?

von Purzel H. (hacky)


Lesenswert?

Sinnvollerweise mancht man die Schritte mit Integern, denn sie solle 
meist in einen hireichen kurzen seit errechnet werden.

Egal, der Phasenakkumulator repraesentiert 2*Pi. Bei Integer Rechnungen 
auf 2^N abgebildet. Bei float kann man sie auch gleiche bei 2*pi 
belassen.

Die unterste Frequenz, resp die Frequenzaufloesung erreicht man mit dem 
minimalen inkrement, sodass man einen Umgang weniger pro Zeiteinheit 
bekommt. Schmeiss mal den Exponenten weg, der bringt nichts. Es geht 
hier um die Anzahl signifikanter Stellen, die Anzahl Bits. Beim double 
format sind das glaub 48 bit. Als maximale Aufloesung. Durch unguenstige 
Anwendung wird die aufloesung kleiner.
Deine 10bit bringen als eine eine Aufloesung von 4MHz/1024, etwa 4kHz. 
Im besten Fall, dh Integer Fall.

Dein Weg reduziert die Aufloesung, ohne Vorteile zu bringen. Was willst 
du mit den Vorkommastellen ? Den Phasenraum als 2^5 gleich 2*Pi 
definieren. Ja, kann man, ist auch auf den 4kHz, und hat immer noch 
nichts gewonnen.

von DDS (Gast)


Lesenswert?

Ja wenn ich auf Double wechseln würde, würde ich eine geringere 
Auflösung bekommen. Aber ich könnte meinen Akkumulator in kleineren 
Schritten Hochzählen lassen, z.B. statt zu Inkrementieren könnte ich auf 
meinen akutellen Wert immer 0,5 drauf addieren, wodurch ich doch meine 
Frequenz verringern könnte.

Es geht mir hierbei nur um das Theorietische Verständnis, nicht um eine 
Sinnvolle Anwendung, denn da wären 10 Bit auch schon sehr mager...

von Axel S. (a-za-z0-9)


Lesenswert?

DDS schrieb:
> Also ich habe gelesen

Wo? Nenne bitte Roß und Reiter. Oder schweige.

> dass man den Phasenakkumulator für die
> Lookup-Table mit double Werten aufaddieren kann.

Kann man sicher. Ergibt nur keinen Sinn.

> Ich bin bisher immer
> von ganzen Zahlen (Integer) ausgegangen. Da ist die bestimmung der
> maximalen Auflösung dann für mich eigentlich leicht zu berechnen und
> zwar ausgegangen von einer Binären Zweierpotenz wäre das demnach
> f_auflösung = f_systemtakt / 2^Anzahl_Bits.

Yep

> Wie berechne ich nun die Auflösung wenn ich eine Reele Zahl habe

Genauso. Nur statt "2^Anzahl_Bits verwendest" du den Endwert des 
Akkumulators geteilt durch das kleinste erlaubte Inkrement. Die stehen 
in einem bestimmten Verhältnis zueinander und das darf nicht größer als 
"2^Anzahl Bits in der Mantisse des Fließkommatyps" sein.

> 10 bits wobei 5 Bits für die Nachkomma- und die anderen 5 Bits für die
> Vorkommastelle sind.

Das ist dann aber kein Fließkommatyp, sondern Festkomma. Da geht die 
Rechnung genauso wie wenn du gleich mit Integer gerechnet hättest.

> Durch Einführung in den Reelen Zahlenbereich, bekomme ich ja auch eine

1. heißt das reelle Zahlen (mit zwei l)

2. heißt es korrekt Fließkomma-Datentyp; reelle Zahlen kennt nur die 
Mathematik. Computer rechnen immer nur mit Annäherungen, die aus 
mathematischer Sicht rationale Zahlen sind. Und damit nur eine Teilmenge 
der reellen Zahlen.

> neue Maximale und Minimale Frequenz die ich darstellen kann, wie
> berechne ich diese?

Wie gesagt: die kann man innerhalb gewisser Grenzen selber festlegen. 
Wenn man sagt, der Phasenakkumulator soll Winkelgrade zählen, dann geht 
er halt bis 360. Und das Inkrement kann man passend klein wählen, sagen 
wir 0.01 Grad. Wenn man es zu klein wählt, fällt die 
Fließkommaarithmetik auf die Nase. Die Addition tut dann einfach nichts.

Kannst du selber ausprobieren:
1
#include <stdio.h>
2
3
int main(void)
4
{
5
  float x = 1.0;
6
  float y = 1.0;
7
8
  for (int i=0; i<30; i++) {
9
    float z = x+y;
10
    printf("%.15f + %.15f = %.15f\n", x, y, z);
11
    y = y / 2.0;
12
  }
13
}
1
/tmp $gcc -std=c99 -o t1 t1.c
2
3
/tmp $./t1
4
1.000000000000000 + 1.000000000000000 = 2.000000000000000
5
1.000000000000000 + 0.500000000000000 = 1.500000000000000
6
1.000000000000000 + 0.250000000000000 = 1.250000000000000
7
1.000000000000000 + 0.125000000000000 = 1.125000000000000
8
1.000000000000000 + 0.062500000000000 = 1.062500000000000
9
1.000000000000000 + 0.031250000000000 = 1.031250000000000
10
1.000000000000000 + 0.015625000000000 = 1.015625000000000
11
1.000000000000000 + 0.007812500000000 = 1.007812500000000
12
1.000000000000000 + 0.003906250000000 = 1.003906250000000
13
1.000000000000000 + 0.001953125000000 = 1.001953125000000
14
1.000000000000000 + 0.000976562500000 = 1.000976562500000
15
1.000000000000000 + 0.000488281250000 = 1.000488281250000
16
1.000000000000000 + 0.000244140625000 = 1.000244140625000
17
1.000000000000000 + 0.000122070312500 = 1.000122070312500
18
1.000000000000000 + 0.000061035156250 = 1.000061035156250
19
1.000000000000000 + 0.000030517578125 = 1.000030517578125
20
1.000000000000000 + 0.000015258789062 = 1.000015258789062
21
1.000000000000000 + 0.000007629394531 = 1.000007629394531
22
1.000000000000000 + 0.000003814697266 = 1.000003814697266
23
1.000000000000000 + 0.000001907348633 = 1.000001907348633
24
1.000000000000000 + 0.000000953674316 = 1.000000953674316
25
1.000000000000000 + 0.000000476837158 = 1.000000476837158
26
1.000000000000000 + 0.000000238418579 = 1.000000238418579
27
1.000000000000000 + 0.000000119209290 = 1.000000119209290
28
1.000000000000000 + 0.000000059604645 = 1.000000000000000
29
1.000000000000000 + 0.000000029802322 = 1.000000000000000
30
1.000000000000000 + 0.000000014901161 = 1.000000000000000
31
1.000000000000000 + 0.000000007450581 = 1.000000000000000
32
1.000000000000000 + 0.000000003725290 = 1.000000000000000
33
1.000000000000000 + 0.000000001862645 = 1.000000000000000

Float kann zwar kleine Zahlen wie z.B. 0.000000059604645 darstellen, 
aber wenn du sie zu einer hinreichend viel größeren Zahl addierst (hier: 
1) dann passiert einfach nichts. Die Addition hat keinen Effekt. Das DDS 
steht still.

: Bearbeitet durch User
von Purzel H. (hacky)


Lesenswert?

> die gerechnete Tabelle.

Die tabelle ist insofern falsch, wie sie als double angezeigt wird, aber 
als single gerechnet wird.
Double hat 15-16 signifikannte Stellen, Single nur 5-6.
Waehrend Longint 9 Stellen haben kann.

von Axel S. (a-za-z0-9)


Lesenswert?

Und falls die Demonstration nicht überzeigend war, hier noch eine 
Variante mit double. Der Phasenakkumulator soll bis 360 gehen. Wir 
testen immer kleiner (um Faktor 10) werdende Inkremente.
1
#include <stdio.h>
2
3
int main(void)
4
{
5
  double x = 360.0;
6
  double y = 1.0;
7
8
  for (int i=0; i<20; i++) {
9
    double z = x+y;
10
    printf("inkrement soll: %.20e, ist: %.20e\n", y, z-x);
11
    y = y / 10;
12
  }
13
}
1
inkrement soll: 1.00000000000000000000e+00, ist: 1.00000000000000000000e+00
2
inkrement soll: 1.00000000000000005551e-01, ist: 1.00000000000022737368e-01
3
inkrement soll: 1.00000000000000002082e-02, ist: 9.99999999999090505298e-03
4
inkrement soll: 1.00000000000000002082e-03, ist: 9.99999999976353137754e-04
5
inkrement soll: 1.00000000000000004792e-04, ist: 9.99999999748979462311e-05
6
inkrement soll: 1.00000000000000008180e-05, ist: 9.99999997475242707878e-06
7
inkrement soll: 1.00000000000000016651e-06, ist: 9.99999997475242707878e-07
8
inkrement soll: 1.00000000000000021945e-07, ist: 1.00000022484891815111e-07
9
inkrement soll: 1.00000000000000018636e-08, ist: 1.00000079328310675919e-08
10
inkrement soll: 1.00000000000000026908e-09, ist: 9.99989424599334597588e-10
11
inkrement soll: 1.00000000000000029493e-10, ist: 9.99875737761612981558e-11
12
inkrement soll: 1.00000000000000026261e-11, ist: 1.00044417195022106171e-11
13
inkrement soll: 1.00000000000000018184e-12, ist: 1.02318153949454426765e-12
14
inkrement soll: 1.00000000000000015659e-13, ist: 1.13686837721616029739e-13
15
inkrement soll: 1.00000000000000015659e-14, ist: 0.00000000000000000000e+00
16
inkrement soll: 1.00000000000000007771e-15, ist: 0.00000000000000000000e+00
17
inkrement soll: 1.00000000000000010236e-16, ist: 0.00000000000000000000e+00
18
inkrement soll: 1.00000000000000007154e-17, ist: 0.00000000000000000000e+00
19
inkrement soll: 1.00000000000000007154e-18, ist: 0.00000000000000000000e+00
20
inkrement soll: 1.00000000000000009562e-19, ist: 0.00000000000000000000e+00

Obwohl der double Typ  Werte kleiner 10^-13 problemlos darstellen 
kann;  auch mit vielen Nachkommastellen, so kann man so kleine Werte 
nicht mehr zu 360 addieren. Außerdem sieht man auch schön, daß der 
Rechenfehler vorher bereits ansteigt. Bei 10^-12 sind es 2%, bei 10^-13 
schon 13% Fehler.

von Egon D. (Gast)


Lesenswert?

Name H. schrieb:

> Double hat 15-16 signifikannte Stellen, Single nur 5-6.

Etwas untertrieben -- zumindest, was die einfache
Genauigkeit angeht. Die Mantisse ist 24 Bit lang (wovon
nur 23 Bit gespeichert werden müssen); das entspricht
ziemlich genau 7 geltenden Ziffern.

von Purzel H. (hacky)


Lesenswert?

Ja, bei 15 darzustellenden Stellen ist Schluss. Deswegen kann man auch 
gleich bei Festkomma bleiben. Oder bei Integer Zahlen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

DDS schrieb:
> Hallo, Ich habe ein Verständnisproblem zu der Auflösung einer DDS.
>
> Also ich habe gelesen, dass man den Phasenakkumulator für die
> Lookup-Table mit double Werten aufaddieren kann.

Das nenne ich mal astreine Fake-News!

> Ich bin bisher immer
> von ganzen Zahlen (Integer) ausgegangen.

Eben!

> Da ist die bestimmung der
> maximalen Auflösung dann für mich eigentlich leicht zu berechnen und
> zwar ausgegangen von einer Binären Zweierpotenz wäre das demnach
> f_auflösung = f_systemtakt / 2^Anzahl_Bits.
> Wie berechne ich nun die Auflösung wenn ich eine Reele Zahl habe,
> angenommen ich habe eine Systemfrequenz von 4MHz und eine Bitbreite von
> 10 bits wobei 5 Bits für die Nachkomma- und die anderen 5 Bits für die
> Vorkommastelle sind.

Das sind aber keine double im Sinne von C sondern immer noch Integer mit 
Festkommaarithmetik.

> f_auflösung wäre demnach = f_systemtakt / 31,96875
>
> Ist meine Annahme richtig oder liege ich auf dem Holzweg?

Holzweg.

> Durch Einführung in den Reelen Zahlenbereich, bekomme ich ja auch eine
> neue Maximale und Minimale Frequenz die ich darstellen kann, wie
> berechne ich diese?

Da ist alles Unsinn. Bleib bei der DDS wie sie ist und gut.

von Purzel H. (hacky)


Lesenswert?

Die hoechstaufgeloesten mir bekannten DDS haben einen Phasenraum von 48 
bit, erlauben also bei 100MHz noch eine Aufloesung von sub-mHz. Die 
meisten haben 32 bit, und die einfachen haben 24 Bit.
https://www.analog.com/en/parametricsearch/11018

von Wolfgang (Gast)


Lesenswert?

DDS schrieb:
> Also ich habe gelesen, dass man den Phasenakkumulator für die
> Lookup-Table mit double Werten aufaddieren kann.

Das bringt dir gegenüber einer Integeraddition überhaupt keinen Vorteil. 
Gegenüber einer gleichlangen Integeraddition verschenkst du sogar 
Stellen für den Exponenten. Ob du die Periode in 2*pi, 2^n oder sonstwas 
aufteilst, ist prinzipiell völlig egal. Auch bei Double oder Float wird 
die Stellenzahl für das Ergebnis nicht durch das Phaseninkrement, 
sondern immer durch den Akkumulator bestimmt, weil vor der Addition 
sowieso erstmal auf gleichen Exponent mit dem Akku hingeschoben werden 
muss.

von W.S. (Gast)


Lesenswert?

DDS schrieb:
> Hallo, Ich habe ein Verständnisproblem zu der Auflösung einer DDS.
>
> Also ich habe gelesen, dass man den Phasenakkumulator für die
> Lookup-Table mit double Werten aufaddieren kann.

O je.

Versuche doch zu allererst, das Prinzip eines DDS Generators zu 
verstehen!

Wenn du das kapiert hast, ist dir ohnehin alles klar.

Also: Nehmen wir mal an, du hast ein DDS mit einem Phasenakku von 10 
Bit. Damit kann man von 0 bis 1023 zählen. Damit ist die kleinste 
Frequenz, die du damit erzeugen kannst diejenige, bei der das 
Phaseninkrement (also das, was bei jedem Takt aufaddiert wird) gleich 1 
ist. Wenn du 0 nimmst, dann steht der DDS-Generator.

Bemerke bitte, daß es hier in dieser Rechnerei keine Vor- und 
Nachkomma-Stellen beim Phaseninkrement gibt. Streng genommen gilt, daß 
alle 10 Bit des Phasenakkus echt gebrochene Zahlen sind, nämlich von 0 
bis Vollkreis-LSB. Der Wert in der Klammer weiter unten ist eben die 
kleinste gebrochene Zahl, bei der der DDS noch was anderes als 
Gleichspannung ausgibt. Aber die Leute heutzutage kapieren nicht mehr, 
was gebrochene Zahlen sind, deswegen habe ich hier auch mit 
Integerzahlen hantiert. Damit ist das kleinste Inkrement eben 1 und eine 
Periode ist 1024 groß.

So. Also nun ist 1 das kleinste Phaseninkrement und für eine ganze 
Periode braucht man damit 1024 Additionen sprich Takte der 
Referenzfrequenz. Jetzt nehmen wir mal an, daß du als Takt 4 MHz hast 
(wie oben geschrieben).

Also ist die kleinste Ausgangsfrequenz

4 MHz * (1/1024)

und das ergibt 3906.25 Hz
Das Umrechnen auf real existierende DDS-IC's und deren Phasenakku kannst 
du jetzt selbst tun.

W.S.

von Axel S. (a-za-z0-9)


Lesenswert?

W.S. schrieb:
> Versuche doch zu allererst, das Prinzip eines DDS Generators zu
> verstehen!

<seufz>

Das ist nicht hilfreich.

[längliche Erklärung gesnipt]

Das hat der TE offensichtlich alles schon verstanden. Das kriegt man 
auch mit, wenn man den Eröffnungspost mal aufmerksam liest. Er war nur 
durch irgendwelchen Unsinn verwirrt, den er irgendwo im Web 
aufgeschnappt hat. Ich würde ja immer noch gerne wissen, wo das war.

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
Noch kein Account? Hier anmelden.