Forum: FPGA, VHDL & Co. Frage zur DDFS von Lothar Miller


von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe gerade versucht, mit der DDFS von Lothar Miller, einen Sinus zu 
generieren.
http://www.lothar-miller.de/s9y/categories/31-DDFS

Dazu wollte ich den gegebenen VHDL Code etwas umschreiben, damit es für 
mich übersichtlicher wird. (siehe Anhang)

Ich wollte die sign und quadrant Abfrage mit einer case gestalten.

Eigentlich dachte ich, dass
1
if(Quadrant='0') then
2
    Result_sin1 <= Sinus_Rom (   to_integer(Address));
3
  else 
4
    Result_sin1 <= Sinus_Rom (63-to_integer(Address));
5
  end if;
6
  
7
  if (Sign='1') then
8
    Data_sin1 <= Result_sin;
9
  else
10
    Data_sin1 <= std_logic_vector (-signed(Result_sin1));
11
  end if;
und
1
Sign_Quadrant <= Sign & Quadrant;
2
  
3
  case Sign_Quadrant is
4
    when "10" =>   Result_sin2 <= Sinus_Rom (   to_integer(Address));
5
            Data_sin2 <= Result_sin2;
6
            
7
    when "11" =>   Result_sin2 <= Sinus_Rom (63-to_integer(Address));
8
            Data_sin2 <= Result_sin2;
9
            
10
    when "00" =>   Result_sin2 <= Sinus_Rom (   to_integer(Address));
11
            Data_sin2 <= std_logic_vector (-signed(Result_sin2));
12
            
13
    when "01" =>   Result_sin2 <= Sinus_Rom (63-to_integer(Address));
14
            Data_sin2 <= std_logic_vector (-signed(Result_sin2));
15
            
16
    when others =>  null;
17
  end case;
das gleiche ist. Die Simulationsergebnisse haben aber einen kleinen 
Unterschied.

Bei der case-Variante bekomme ich, sobald die Adresse 1 wird, immer 
komische peaks in die Sinuswelle hinein und ich kann mir nicht wirklich 
erklären, wieso das so ist.
Anscheinend springt das Result_sin2 Register einmal mehr um, als es bei 
der originalen If Anweisung der Fall ist.

Kann mir das jemand erklären und mir meinen Fehler zeigen?

Vielen Dank!
Michael

von Obstmann (Gast)


Lesenswert?

Hi!

ohne Gewähr:
Dein Signal "Sign_Quadrant" wird immer erst am Ende des Prozesses 
zugewiesen, d.h. bei einer neuen Adresse hängst du im ersten Taktzyklus 
hinterher.
Wenn Du es direkt so verwenden willst, musst Du "Sign_Quadrant" als 
Variable anlegen.

Gruß

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Obstmann schrieb:
> d.h. bei einer neuen Adresse hängst du im ersten Taktzyklus hinterher.
Weil da gar kein Takt beteiligt ist, kann das keine Latency sein und der 
Fehler muss woanders herkommen...

> Wenn Du es direkt so verwenden willst, musst Du "Sign_Quadrant" als
> Variable anlegen.
Möglich, ist aber ein übler Workaround für einen ganz (all-)gemeinen 
Fehler. Und da haben wir den Klassiker aller Musterbeispiele für 
fehlerhafte Simulationen:
1
process (Sign,Quadrant,Address)   
2
  
3
  subtype sin_data is std_logic_vector (7 downto 0);    
4
  type Rom64x8 is array (0 to 63) of sin_data;      
5
  constant Sinus_Rom : Rom64x8 := (  
6
  x"00",  x"03",  x"06",  x"09",  x"0c",  x"0f",  x"12",  x"15", ....
7
  x"7c",  x"7d",  x"7d",  x"7e",  x"7e",  x"7e",  x"7f",  x"7f");   
8
begin    
9
  
10
  Sign_Quadrant <= Sign & Quadrant;
11
  
12
  case Sign_Quadrant is   -- Sign_Quadrant ändert was am Ergebnis des Prozesses, 
13
                          -- deshalb MUSS es in die Sensitivliste!
14
    when "10" =>   ...
15
                   Data_sin2 <= Result_sin2;   -- genauso Result_sin2  und später  Result_sin1
Eine unvollständige Sensitivliste...
Nach deren Korrektur klappts auch mit der Nachbarin:
1
process (Sign,Quadrant,Address,Sign_Quadrant,Result_sin2,Result_sin1)

von J. S. (engineer) Benutzerseite


Lesenswert?

Die Tabellenwerte für den Sinus sehen mir ein wenig verdächtig aus - wie 
sind die erzeugt worden?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

J. S. schrieb:
> Die Tabellenwerte für den Sinus sehen mir ein wenig verdächtig aus - wie
> sind die erzeugt worden?
Per Kopie, von einem Franzosen, dessen Name mir nicht mehr einfällt. 
Allerdings bin ich dann auf die Variante mit den berechneten Sinusweten 
umgestiegen...   ;-)
Kennst du die Quelle? Moment, die Welt ist doch klein, ich habs, da 
isses: http://www.alse-fr.com/archive/CplxFPGA_us.pdf

von Michael (Gast)


Lesenswert?

Vielen Dank!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michael schrieb:
> Vielen Dank!
De nada. Und viel Spass mit VHDL in Zukunft... ;-)

von J. S. (engineer) Benutzerseite


Angehängte Dateien:

Lesenswert?

Lothar Miller schrieb:
> Per Kopie, von einem Franzosen, dessen Name mir nicht mehr einfällt.

Lothar, man kopiert grundsätzlich nichts von Franzosen! - Wenigstens 
nicht, ohne es vorher zu prüfen :-)

Was der gute Bert Cuzeau da mit seinem Dokument so vollmundig betreibt, 
ist typisch französisch: "Wir haben den Längsten und wissen alles 
besser".Lies Dir mal den Satz zu den Studenten auf der IP-Core Webseite 
an. Da legst Du Dich nieder. Besonders belustigend finde ich den Satz:

"Sound Digital Design principles must be understood & enforced !"

Recht hat er, der Bert, nur warum macht er es dann nicht? Sein Code ist 
längst nicht optimal. Zwar bezieht er die 0...63 Stützstellen des Sinus 
richtigerweise auf 64 und nicht etwa auf 63, was manche nicht kapieren, 
aber er rundet nicht richtig und hat damit doppltes Rauschen in seinem 
tollen Audio-Sinus.

Wenn man es richtig schlau macht, dann schiebt man die Stützstellen auch 
um einen halben Stützpunkt nach rechts und gelangt zu dem, was ich hier 
im Forum in meinem Artikel zur DDS und Sinuerzeugung beschreibe.

http://www.mikrocontroller.net/articles/Digitale_Sinusfunktion

Das spart einen Berechnungsschritt und auch noch ein bit in der 
Phasenvektorbreite und ist streng genommen mathematisch auch richtiger, 
weil die Punkte nummer dann die Mitte des Phasenbereiches definiert und 
nicht deren linken Rand.

Wenn man es so macht, wie Bertrand Cuzeau, bekommt man ein Problem mit 
dem neuen Punkt im neuen Bogen! Der muss gesondert berechnet werden und 
wer genau hinsieht, erkennt in der Grafik des TO genau diesen Effekt:
Wenn man die Phase an 128 spiegelt kommt man wieder zum Punkt 127, der 
jedoch entspricht dem Wert, den eigentlich Punkt 129 haben müsste.
Man muss also den 128er künstlich erzeugen / Abfangen und den zweiten 
Ast schieben. Nur die Spiegelung an der X-Achse gelingt korrekt.

Der nächste Punkt ist die Skalierung: 127 als Multiplikator ist nur dann 
richtig, wenn man den 90 Grad Punkt benutzt und auch dann müssten es 
"127.5-epsilon sein". Bei geringen Punktezahlen geschieht dies bei 
meiner Kurve nicht und ich kann BEIDE Punkte um die 90 Grad Achse auf 
das Maximum schieben, in dem ich mit mehr als 127 skaliere und so runde, 
dass gerade wieder 127 entstehen. Das bringt - gerade für low cost apps 
- kostenlos mehr Auflösung! Wenn Bert sich und seine Firma ALSE als die 
Audio Experten ansieht, müsste er da mehr bringen :-)

Aber wie Bertrand Cuzeau selbst richtig schreibt: "Not all Books & 
Training Courses are good …"

Ich habe das in der angehängten Grafik nochmal mit nur 4x8 Werten (statt 
4x64 wie bei Cuzeau) deutlich gemacht. Dargestellt sind die Winkel in 
Punkten und Prozent, sowie Winkelgrade und der skalierte Sinuswert, 
teilweis ungerundet. Man erkennt, dass nur bei der grünen Kurve, die 
Nummer des Punktes tatsächlich die Mitte der Bereiches markiert und den 
zugehörigen Sinuswert repräsentiert. Man tastet einfach von 0..7 ab und 
denkt sich die +0,5 in die Tabelle hinein. Der negierte 
PhasenVektor/SinusWert für die anderen Quadranten werden dann einfach 
per Negation gebildet. Das ist kleiner, genauer und in der maximalen 
Taktfrequenz potenziell schneller.

> Allerdings bin ich dann auf die Variante mit den berechneten Sinusweten
> umgestiegen...   ;-)

Das hier wären meine Werte:

002 005 008 011 014 017 020 023
026 029 032 035 038 041 044 047
050 053 056 059 061 064 067 070
072 075 077 080 082 084 087 089
091 093 095 098 100 101 103 105
107 109 110 112 113 115 116 117
118 119 121 121 122 123 124 125
125 126 126 127 127 127 127 127

Wenn es als DDS benutzt wird, sollte man die jeweils abgetasteten Werte 
noch mit einem IIR filtern. Dabei lässt sich die Auflösung nochmal etwas 
erhöhen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

J. S. schrieb:
> Lothar, man kopiert grundsätzlich nichts von Franzosen! -
> Wenigstens nicht, ohne es vorher zu prüfen :-)
Richtig, diese doppelte 0 ist arg unschön...   :-/

Ich werde mit deiner freundlichen Genehmigung und mit einem Verweis auf 
deinen Artikel diese Tabelle übernehmen... ;-)

von J. S. (engineer) Benutzerseite


Lesenswert?

Lothar Miller schrieb:
> Ich werde mit deiner freundlichen Genehmigung
genehmigt :-)

von Uwe Bonnes (Gast)


Lesenswert?

Habt Ihr auch mal an einen Cordic zur Sinusumsetzung gedacht?

von Thomas (Gast)


Lesenswert?

> in seinem tollen Audio-Sinus.
Ich bin nicht sicher, ob er wirklich einen Audio-Sinus gemeint hat, denn 
"Sound Digital Design" /= "Digital Sound Design" :-)

Uwe Bonnes schrieb:
> Habt Ihr auch mal an einen Cordic zur Sinusumsetzung gedacht?
Wieviele Resourcen braucht der?

von J. S. (engineer) Benutzerseite


Lesenswert?

Thomas schrieb:
> ob er wirklich einen Audio-Sinus gemeint hat
Du hast wohl Recht! Mit "sound" war wahrscheinlich "gesund" = "gut" 
gemeint, ist aber egal, denn der Sinus ist weder für Messtechnik noch 
Consumeranwendungen optimal - ich verweise nach wie vor auf meine DDS 
und meine Art, den Sinus in die Tabelle zu definieren.

von Rudi Ratlos (Gast)


Lesenswert?

Wie ich sehe, arbeiten eure DFFs mit vergleichweise kleinen Tabellen. 
Gibt es eine Möglichkeit, im Vorhinein abzuschätzen, wie gross eine 
solche Tabelle sein muss, um einen definierte SNr heraus zu bekommen, 
OHNE es zu bauen und durchzumessen?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Solange die Tabelle komplett durchlaufen wird, ist das relativ einfach: 
pro Bit Wortbreite und entsprechend angepasster Tabellenlänge sind es 6 
dB. Wenn aber der Akku zu kurz ist und die Frequenz zu hoch, dann werden 
einzelne Tabellenwerte ausgelassen und die SNR nimmt zu. Aber un jedem 
Fall kann die SNR nicht nur abgeschätzt, sondern genau ausgerechnet 
werden...

von J. S. (engineer) Benutzerseite


Lesenswert?

Man könnte es diskret machen, indem man die Werte aus den Tabellen, 
genauer deren in den Datenstrom eingeprägten Fehler für die gewünschte 
Situation bewertet, z.B. in Excel. Allerdings ist das von der Frequenz, 
der Startphase und auch von dem Betrachtungszeitpunkt abhängig.

Denkbar wäre, es in Modelsim in INT und REAL gleichzeitig zu simulieren 
und das Rauschen permanent zu bilden und formell aufzuintegrieren. Dann 
bekommt man für jeden Zeitpunkt einen Wert (der sich permanent leicht 
ändert). Der Mittelwert (oder der Maxert?) wäre dann der SNR-Wert.

von gerhard (Gast)


Lesenswert?

Rudi Ratlos schrieb:
> Wie ich sehe, arbeiten eure DFFs mit vergleichweise kleinen Tabellen.
> Gibt es eine Möglichkeit, im Vorhinein abzuschätzen, wie gross eine
> solche Tabelle sein muss, um einen definierte SNr heraus zu bekommen,
> OHNE es zu bauen und durchzumessen?

Mein sin/cos core auf opencores.org

< http://opencores.org/project,sincos >

hat einen DDS als Testbett, der die erzeugten sin-Werte in files
schreibt. Man kann dann per FFT in Matlab o.ä. gleich sehen, was man
mit den gewählten Parametern bekommt.

Die Tabellentiefe / Breite  wird automatisch gleich
passend zu den Dimensionen den angeschlossenen Busse gemacht.

Pipelining ist wählbar von kombinatorisch bis 10 Stufen,
gleich sinnvoll verteilt, damit der Register-Balancer nicht so
viel zu tun hat.

Ich habe ziemlich viel Aufwand in die Symmetrie der Faltung der
Tabelle und die Rundung zum nächsten LSB reingesteckt.

Reines VHDL, für's Testbett braucht man den Modelsim o.ä.

Gruß, Gerhard

von Heidenheini (Gast)


Lesenswert?

gerhard schrieb:
> für's Testbett
Was nennst Du denn hier bitte "Testbett"?

von gerhard (Gast)


Lesenswert?

Die 80% des Codes, die nicht zu Hardware compiliert werden
und nur dazu dienen, die Benutzung der eigentlichen entity
zu demonstrieren und zu prüfen, ob sie tut was von ihr
erwartet wird.

von FPGA-Vollprofi (Gast)


Lesenswert?

Testbett ist hier nichts anderes, als Testbench. Der Name ist auch 
ziemlich Wurscht.

>Pipelining ist wählbar von kombinatorisch bis 10 Stufen,
>gleich sinnvoll verteilt, damit der Register-Balancer nicht so
>viel zu tun hat.
Bist Du Dir da ganz sicher, dass das was bringt?

>Lothar, man kopiert grundsätzlich nichts von Franzosen
Da stimme ich uneingeschränkt zu, beim folgenden aber nicht:

>Das spart einen Berechnungsschritt und auch noch ein bit in der
>Phasenvektorbreite und ist streng genommen mathematisch auch richtiger,
Warum soll das "richtiger" sein?

Dann:
Du hast zwar Recht, mit Deiner Methode wird ein bit weniger gebraucht, 
aber wen kümmert bitte ein lumpiges bit mehr bei der Vektorbeschreibung?





>weil die Punkte nummer dann die Mitte des Phasenbereiches definiert und
>nicht deren linken Rand.

von gerhard (Gast)


Lesenswert?

FPGA-Vollprofi schrieb im Beitrag #3390116:

>>Pipelining ist wählbar von kombinatorisch bis 10 Stufen,
>>gleich sinnvoll verteilt, damit der Register-Balancer nicht so
>>viel zu tun hat.
> Bist Du Dir da ganz sicher, dass das was bringt?

Zumindest vor knapp 3 Jahren, als ich das veröffentlicht habe,
war die ISE nicht in der Lage, ein Blockram zu inferieren wenn
das nicht in einem getakteten Prozess war. Ein D-FF direkt
dahinter war nicht deutlich genug.
(Block Rams gibt's nur synchron)

Das spricht nicht dafür, dass da große Anstrengungen gemacht
werden, asynchrone Logik sauber in den Pipelinestufen zu
verteilen, so dass fmax möglichst groß wird.

Da macht man besser von Hand sinnvolle Vorgaben und hofft,
dass sie nicht verschlimmbessert werden.

Mit Mentor Precision oder sowas mag das besser gehen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

gerhard schrieb:
> war die ISE nicht in der Lage, ein Blockram zu inferieren wenn
> das nicht in einem getakteten Prozess war. Ein D-FF direkt
> dahinter war nicht deutlich genug.
Ein BRAM wird nicht dadurch erzeugt, dass die zu lesenden Daten 
zwischengespeichert werden, sondern dadurch, dass die Leseadresse 
registriert wird:
http://www.lothar-miller.de/s9y/archives/20-RAM.html#extended

von J. S. (engineer) Benutzerseite


Lesenswert?

FPGA-Vollprofi schrieb im Beitrag #3390116:
> Testbett ist hier nichts anderes, als Testbench. Der Name ist auch
> ziemlich Wurscht.
Da bin ich etwas anderer Meinung:

gerhard schrieb
> Die 80% des Codes, die nicht zu Hardware compiliert werden
Eigentlich bezeichnet man damit durchaus eine Hardware- und zwar eine 
nicht ganz unbedeutended Grosse. Was hier aber besprochen wurde ist die 
klassische Testbench, also die virtuelle Umgebung im Simulator.

>>Pipelining ist wählbar von kombinatorisch bis 10 Stufen,
>>gleich sinnvoll verteilt, damit der Register-Balancer nicht so
>>viel zu tun hat.
> Bist Du Dir da ganz sicher, dass das was bringt?
Wäre mal zu untersuchen. Ich z.B. meine, ja, es bringt was - allerdings 
lasse ich mich auch vom Gegenteil überzeugen, dass es mit einer Zahl 
zusätzlicher Register und "register balancing" genausso rasch geht.

>>man kopiert grundsätzlich nichts von Franzosen
> Da stimme ich uneingeschränkt zu,
Das war als gag gedacht und bezog sich auf das o.g. Beispiel. Ich war 
ein wenig über deren Webseite erstaunt, die sich las, als seien es die 
Gurus im FPGA-Design schlechthin. Fand ich etwas übertrieben, angesichts 
der in diesem Beispiel präsentierten Standardlösung. Vor allem las ich 
dort einen Aufruf an die Studenten, nicht einfach alles zu kopieren, 
sondern selber nachzudenken. Das unterstreiche ich in diesem Fall 
ausdrücklich :-)

>>Das spart einen Berechnungsschritt und auch noch ein bit in der
>>Phasenvektorbreite und ist streng genommen mathematisch auch richtiger,
> Warum soll das "richtiger" sein?
Weil es bei meiner Definition egal ist, mit vielen Stützstellen man 
arbeitet- die resultierende Kurve ist nach einer idealen Filterung exakt 
wieder dieselbe und hat keinen anderen Offset. Bei der herkömmlichen 
Definition gibt es einen leicht veränderten Phasenversatz. Erst wenn die 
Zahl der Stützstellen gegen unendlich geht, läuft sie auf meine Lösung 
zu.

> Du hast zwar Recht, mit Deiner Methode wird ein bit weniger gebraucht,
> aber wen kümmert bitte ein lumpiges bit mehr bei der Vektorbeschreibung?
Hatte ich glaube ich schon mal geschrieben. Es gibt langsame 
Technologien, mit denen man beim speed etwas genauer hinsehen muss. Mit 
meiner Definition ist esmöglich, die Negation der Viertelkurven allein 
mit Invertern zu generieren. Ansonsten muss ein Sub her.

gerhard schrieb:
> Das spricht nicht dafür, dass da große Anstrengungen gemacht
> werden, asynchrone Logik sauber in den Pipelinestufen zu
> verteilen, so dass fmax möglichst groß wird.
Die BRAMs bestehen nicht aus verschiebbaren Zellen. Auch die internen 
FFs vor und nach den RAMs sind ortsfest. Nur die zusätzlichen Register 
FFswerden u.u. als fabric erzeugt und wären damit rein funktionelle FFs, 
die irgendwo sitzen können.

: Bearbeitet durch User
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.