Hallo, falls Jemand eine Sinustabelle für einen 1024 Punkte Sinus sucht, hier ist ein Quadrant mit 256 Punkten:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
|
Anzeige
|
Sinustabelle 256x8Hallo, falls Jemand eine Sinustabelle für einen 1024 Punkte Sinus sucht, hier ist ein Quadrant mit 256 Punkten:
Gast
#3863700
An dem 2. und dem letzten Wert kann man sehen, dass da was faul ist. Die Werte müssten gesättigt verlaufen. Sieh Dir mal den Wiki-Artikel hier an.
Gast
#3863709
Also ich hab das mit Python gemacht, also sin((90/128)*x) mit x von 1 bis 128. Und das dann mal 255 damit das Maximum statt 1 dann 255 ist. Und das dann als Integer. Ist die Herangehensweise falsch oder wie lässt man das berechnen? -gb- schrieb: 1. Ist es nicht schön wenn sich Gäste in einem Tread mit immer neuen Namen anmelden. > Also ich hab das mit Python gemacht, also sin((90/128)*x) mit x von 1 > bis 128. Und das dann mal 255 damit das Maximum statt 1 dann 255 ist. > Und das dann als Integer. 2. ist die Formel seltsam. 3. und ergibt nicht die oben angegebenen Werte 4. die irgentwie nicht wirklich stimmen. > Ist die Herangehensweise falsch oder wie lässt man das berechnen? Ich würd's so rechnen: A(N) = SIN(((Pi/2)/256)*N)*256 [N=1->255] /* Die vielen Klammern sind /* nur zur Verdeutlichung A(0) = 0 /* Die Werte für "0" A(256) = 256 /* und "256" muss man nicht /* berechnen Ich verweise da mal auf den recht übersichtlichen Artikel [[Digitale Sinusfunktion]]
Gast
#3863781
Max Mustermann schrieb: > A(0) = 0 /* Die Werte für "0" > A(256) = 256 /* und "256" muss man nicht Das wären dann 257 Stützstellen und ein Wert von 256 in ein Byte? Nicht wirklich...
Gast
#3863783
Max Mustermann schrieb: > A(N) = SIN(((Pi/2)/256)*N)*256 [N=1->255] /* Die vielen Klammern sind Besser, dir Formel gilt auch für N=0, 256 ;-) Gustl Buheitel schrieb: > hier ist ein Quadrant mit 256 Punkten: Man kann die Tabelle auch vom Synthesizer rechnen lassen: http://www.lothar-miller.de/s9y/archives/37-DDFS-mit-BROM.html Für die 256 Punkte des ersten Quadranten eines 9-Bit-Sinus (8+Vorzeichen) wäre das dann:
MWS schrieb: > Max Mustermann schrieb: >> A(0) = 0 /* Die Werte für "0" >> A(256) = 256 /* und "256" muss man nicht > > Das wären dann 257 Stützstellen und ein Wert von 256 in ein Byte? > Nicht wirklich... OK. Das ist natürlich QUATSCH! Ich schieb's mal auf die Uhrzeit;-) Habs geändert: A(N) = SIN(((Pi/2)/255)*(N+0,5))*255 [N=0->255] /* Die vielen Klammern sind /* nur zur Verdeutlichung Ich würd's allerdings nicht zur Laufzeit berechnen sondern als Tabelle mit reincompilieren damit es nicht im RAM oder ROM liegt sondern im Flash. Lieg ich damit falsch? Lothar Miller schrieb: > Für die 256 Punkte des ersten Quadranten eines 9-Bit-Sinus > (8+Vorzeichen) wäre das dann Wozu Vorzeichen? Alle Werte eines Quadranten haben das gleiche Vorzeichen. Max Mustermann schrieb: > Wozu Vorzeichen? > Alle Werte eines Quadranten haben das gleiche Vorzeichen. Weil aber ein einzelner Quadrant in freier Wildbahn kaum vorkommt, wird für den kompletten Sinus ein Bit mehr benötigt. Das ist das erwähnte Vorzeichen. Max Mustermann schrieb: > damit es nicht im RAM oder ROM liegt sondern im Flash. Wir sind hier im Forum: FPGA, VHDL...
Gast
#3863973
Das Vorzeichen kann man aber auch nachträglich ranmachen und muss es nicht in der Tabelle speichern die ja Platz kostet. Ich werde nachher das Python Posten. Lothar Miller schrieb: > Max Mustermann schrieb: >> Wozu Vorzeichen? >> Alle Werte eines Quadranten haben das gleiche Vorzeichen. > Weil aber ein einzelner Quadrant in freier Wildbahn kaum vorkommt, wird > für den kompletten Sinus ein Bit mehr benötigt. Das ist das erwähnte > Vorzeichen. Du wills also für einen kompletten Sinus 1024*9Bit abspeichern? > > Max Mustermann schrieb: >> damit es nicht im RAM oder ROM liegt sondern im Flash. > Wir sind hier im Forum: FPGA, VHDL... Sorry, nicht gesehen. Was über "alle Foren" auf diesen Tread geraten. Max Mustermann schrieb: >> Weil aber ein einzelner Quadrant in freier Wildbahn kaum vorkommt, wird >> für den kompletten Sinus ein Bit mehr benötigt. Das ist das erwähnte >> Vorzeichen. > Du wills also für einen kompletten Sinus 1024*9Bit abspeichern? Nein, natürlich nicht. Die Tabelle hat 256 Einträge im Bereich von 0..255 (8 Bit). Siehe hier: Lothar Miller schrieb: > type Rom256x8 is array (0 to 255) of unsigned (7 downto 0); > -- Sinus von 0° bis 90° (0 bis PI/2) > signal Sinus_Rom : Rom256x8; Das Argument der Sinusfunktion bewegt sich im Bereich 0..1023 (10 Bit), damit ein kompletter Vollkreis abgedeckt wird. Die Funktionswerte bewegen sich im Bereich -255..+255 (9 Bit). Was in den bisherigen Beiträgen fehlt und vielleicht zum besseren Verständnis beitragen würde, ist die Realisierung der Sinus-Funktion selber, d.h. einer Logik, die 10 Eingangs- und 9 Ausgangsleitungen hat und die aus dem Eingangswert unter Zuhilfenahme der Tabelle den Funktionswert bestimmt. Das geht ganz leicht: Ist das Argument n Bit breit, legen Bit n-1 und Bit n-2 den Quadranten fest:
Die restlichen n-2 Bits (Bit n-3 bis Bit 0) liefern den Index auf die Tabelle, wobei dieser Index für die Quadranten 2 und 4 (also wenn des zweithöchste Bit gesetzt ist) negiert werden muss, und zwar so, dass das Ergebnis wieder n-2 Bits breit ist. Der aus der Tabelle ausgelesene Wert muss für die Quadranten 3 und 4 (also wenn Bit n-1 des Arguments gesetzt ist) ebenfalls negiert werden, und zwar so, dass das Ergebnis 1 Bit breiter als die Tabelleneinträge ist. Wie das für einen Mikrocontroller mit einem 8-Bit-Argument geht, habe ich hier gezeigt: Beitrag "Re: SINUS - COSINUS / KOSINUS - BEISPIEL (Assembler) ATmega8" Das Ganze in Verilog oder VHDL umzusetzen ist eine nette Übungsaufgabe für Anfänger auf diesem Gebiet :) -gb- schrieb: > Das Vorzeichen kann man aber auch nachträglich ranmachen und muss es > nicht in der Tabelle speichern die ja Platz kostet. So hatte ich das auch gedacht. Aber Lothar kam irgentwie mit 8+1 Bit auf. Und ich hatte das so verstanden das er das Vorzeichenbit mit in der Tabelle speichern wollte. Von FPGA, VHDL und Python hab ich NULL Ahnung und werd mich deshalb jetzt aus diesem Forum raushalten.
Gast
#3864021
Genau, so hab ich das auch gemacht:
Gast
#3864055
Und so sah mein Python aus:
-gb- schrieb: > Und so sah mein Python aus: > >
Das ergibt aber Werte die imho nicht richtig sein können. Wenn ich das richtig rechne erhalte ich für i=0 den Wert "Null". Das kann aber nicht richtig sein. Wenn du dir damit aus der Tabell durch Negieren u. Spiegeln einen kompletten Sinus zusammenbaust hast du am Nulldurchgang 2mal hintereinander den Ausgabewert "Null". Das würde aber bedeuten das die Kurve dort die Steigung "Null"hat. Das kann aber für einen Sinus hinkommen. Wenn man den Quadranten in 256 Intervalle aufteilt dann liegt die Mitte des ersten Intervalls bei (Pi/2)/512 .(plenk;-) Ich würde daher die Formel benutzen: x = hex(int((math.sin(((math.pi/2)/(255+0,5))*i))*255)) Vielen Dank! Lothar hat das weiter oben auch schon beschrieben. Wusste nicht, dass man sich die ROM Inhalte generieren lassen kann, eine sehr coole Möglichkeit! Jetzt habe ich eine weitere Frage: Also ich habe den 1024 Punkte Sinus und einen Zähler von 0 ... 1023. Dann habe ich einen Takt mit sagen wir weil es schön ist 128MHz. Dann ist die maximale Frequenz des Sinus 128M/1024=125kHz wenn ich in jedem Takt um 1 weiterzähle. Jetzt will ich die Frequenz veränderbar machen, also hab ich mir noch einen Zähler dazugenommen mit einstellbarer Obergrenze. Wenn die Obergrenze erreicht ist, dann wird der Zähler auf 0 gesetzt und der Zähler für das SinusROM um 1 erhöht. Jetzt kann ich den Zähler für das SinusROM variabel alle 1 ... 4096 Takte um 1 erhöhen und so schön die Frequenz verändern. Wenn ich statt jeden Takt nur jeden 2. Takt den Zähler für das SinusROM um 1 erhöhe, dann halbiert sich die Frequenz, wenn ich das nur jeden 3. Takt mache, dann ist es nurnoch 1/3 der Maximalfrequenz. Schneller machen kann man das auch indem man den Zähler für das SinusROM nicht nur um 1 erhöht, sondern größere Werte. Erhöht man diesen Zähler in jedem Takt um 2 bekommt man einen 512 Punkte Sinus der doppelten Frequenz, erhöht man immer um 3 bekommt man einen 1024/3 Punkte Sinus der dreifachen(?) Frequenz. Ich hab das schön einstellbar gemacht, der Zähler für das SinusROM kann also alle 1 ... 4096 Takte um 1 erhöht werden, aber auch jeweils um 1 ... 16 für dann einen 1024/64=16 Punkte Sinus deutlich höherer Frequenz. Guckt man sich die Frequenzänderung an, dann ist das aber nicht linear: Ändert man die Anzahl der Takte bir zur Erhöhung des SinusROM Zählers um 1 von 4096 bis 1, dann geht das schon nicht linear, aber wenn man danach die Erhöhung des SinusROM Zählers je Takt noch von 1 ... 16 verändert dann auch nicht. Das ist irgendwie ein seltsames Verhalten, dass es dann bei der Einstellung einen Punkt gibt bei dem eine Veränderung um 1 gleich eine Verdopplung/Halbierung der Frequenz bewirkt, davor und danach aber nur eine kleinere Veränderung der Frequenz bewirkt. Kann man das irgendwie linear bekommen? Oder wenn nicht dann irgendwie so dass zumindest die Änderung der Frequenz linear bleibt? Sieh dir einfach mal den von mir hier schon des Öfteren geposteten Link auf meine HP an... :-/ Du kannst auch einfach da mal schauen: http://www.lothar-miller.de/s9y/categories/31-DDFS Danke! Ja das Konzept ist mir neu und auch nicht soooo leicht zu verstehen. Ich habe derzeit einen Zähler für das SinusROM und einen Zähler mit einstellbarer Obergrenze mit dem man bestimmen kann wie schnell der SinusROM-Zähler hochgezählt wird. Mit diesem "Akku" macht man das jetzt irgendwie beides in einem? Sehe ich das richtig? Dann müsste ich eigentlich nur die Schrittgröße variabel einstellen mit der der Akku zählt. Gustl Buheitel schrieb: > Mit diesem "Akku" macht man das jetzt irgendwie beides in einem? Sehe > ich das richtig? Ja. Der Akku zählt jedesmal um den Incrementwert hoch. Und wenn du z.B. deine Zählfrequenz richtig wählst, dann kannst du mit dem Wert 10000 weine Frequenz von 10000 Hz erhalten, und mit dem Wert 10001 eine Frequenz von 10001 Hz. Das ist unmittelbar logisch, wenn man sich vor Augen hält, dass mit einer "etwas" größeren Zahl der Zähler (=Akkumulator) "etwas" schneller überläuft. Und mit einer "sehr viel" größeren Zahl läuft er "sehr viel" schneller über... Sehr cooles Prinzip! Jetzt hab ich also meinen Frequenzgenerator und kann die Frequenz in sagen wir 0,1Hz Schritten einstellen. Dann klappt das doch auch nur für niedrige Frequenzen. Oder? Ich meine diese 0,1Hz sind bei niedrigen Frequenzen sehr viele Takte, aber bei schnellen Frequenzen, wie ist das da? Also wenn das niederwertigste Index-Bit schon jeden Takt kippt? Das macht trotzdem nichts, es werden halt Werte in der Tabelle übersprungen. Damit geht einem natürlich die Genauigkeit der Tabelle verloren und man bekommt immer mehr deutliches Rauschen ausserhalb der eigentlichen Frequenz. Wenn die Werte rein digital bleiben, könnte man noch interpolieren. D.h. aus den "Nachkommastellen" des Phasenakkus und den beiden Tabellenstützpunkten einen Zwischenwert ausrechnen. Das wäre dann lineare Interpolation. Ginge auch komplizierter (kubisch, sinc, ...), kostet aber auch alles Logik und evtl. Geschwindigkeit. Möglicherweise ist es dann einfacher, gleich mit der doppelten Frequenz zu laufen, die Tabellengrösse ist ja inzwischen eher selten ein Problem. Wenn der Sinus über einen Wandler analog ausgegeben wird, braucht man eigentlich auch einen Ausgangsfilter, der alles über der halben Samplefrequenz dämpft. Der sorgt auch dafür, dass bei schnellen Durchläufen die wenigen Stützpunkte "analog" interpoliert werden. Theoretisch müssen es ja auch deutlich mehr als zwei Werte pro Periode werden, damit der Sinus auch danach aussieht (Abtasttheorem)... Ok, verstanden. Jetzt soll das ein Funktionsgenerator für mich werden. Bei niedrigen Frequenzen würde ich die gerne mit einer Genauigkeit von 0,1Hz einstellen können. Aber ich will auch auf mehrere MHz hochdrehen können. Das wären sehr viele Werte um die ich den Wert ändern müsste mit einem Drehencoder oder so. Wie macht man das am besten als Bedieninterface? Sowas wie < 100Hz in 0,1HZ Schritten, bis 1000Hz in 1Hz Schritten, bis 10kHz in 10Hz Schritten, ...
Gast
#3864498
In einem FPGA ist es nicht immer sinnvoll nur einen Quadranten abzulegen. Wenn man im vorliegenden Fall für die Tabelle einen BRAM verwendet, ist dieser bei weiten nicht ausgenutzt. BRAMs sind typischerweise 4 bis 8 mal so gross. Man kann also die ganze Periode ablegen und sich die Quadrantenlogik sparen. Das muss man zwar zusätzöoch das Vorzeichen mit speichern. aber die BRAMs lassen sich meistens auch als 2k * 9 konfigurieren, man hat also keinen Genauigkeitsverlust. Für einen Funktionsgenerator ist das erst recht sinnvoll, da man dann auch asymetrische periodische Signale erzeugen kann.
Gast
#3865012
Das Vorzeichen braucht man nicht wirklich, ist ja nur eine Inversion, wenn die Punktenummerierung stimmt. Und die Grösse der BRAMS würde ich nutzen, um nicht nur 8 Bit oder 256 Werte zu nehmen. Das gibt ja keinen Sinus mehr, wenn mit krummen Werten angesteuert wird.
Gast
#3865024
M. W. schrieb: > Das Vorzeichen braucht man nicht wirklich, ist ja nur eine Inversion, Falsch, im 2er Komplement muss man nach der Inversion eine eins dazuaddieren. Und die Ausgabe sollte im 2er Komplement sein wenn man es weiterverarbeiten möchte, es sei den man gibt es auf einen DAC der auch 1er Komplement oder Betrag mit Vorzeichen kann. > wenn die Punktenummerierung stimmt. Und die Grösse der BRAMS würde ich > nutzen, um nicht nur 8 Bit oder 256 Werte zu nehmen. Das gibt ja keinen > Sinus mehr, wenn mit krummen Werten angesteuert wird. Das ist nur eine Frage der erforderlichen Genauigkeit. Man muss nicht immer alles im Audiophilen 32bit Format machen (ok, das war jetzt etwas pöse). Gustl Buheitel schrieb: > Ok, verstanden. > > Jetzt soll das ein Funktionsgenerator für mich werden. Bei niedrigen > Frequenzen würde ich die gerne mit einer Genauigkeit von 0,1Hz > einstellen können. Aber ich will auch auf mehrere MHz hochdrehen können. > Das wären sehr viele Werte um die ich den Wert ändern müsste mit einem > Drehencoder oder so. Wie macht man das am besten als Bedieninterface? > > Sowas wie < 100Hz in 0,1HZ Schritten, bis 1000Hz in 1Hz Schritten, bis > 10kHz in 10Hz Schritten, ... Ich erklärs mal so: Du hast einen festen Takt einerseits, und eine Sinus-Tabelle andererseits. Die 1024 Stützstellen Deiner Tabelle adressierst Du nun mit einem Zeiger, der jedesmal um einen beliebig fein abgestuften PHASENSPRUNG inkrementiert wird. Dieser Phasensprung ist direkt proportional zu der ausgegebenen Frequenz. Und das heißt, dass Du den gesamten Frequenzbereich bis zur Nyquist-Grenze (=halbe Taktfrequenz) in Schritten von z.B 0,1Hz linear einstellen kannst. Ich meinte etwas Anderes: Wenn ich bei einer 1024Punkte Tabelle und einen Takt von 128MHz eine Sinusfrequenz von 0,1Hz einstellen will, und der Akku je Takt um 1 erhöht werden soll, dann muss der Akku bis 1280M zählen. Ist das richtig? Davon gingnen dann die oberen 10Bits an den Tabellenindex. Edit1: Die oberen 10 Bits gehen aber nicht von 0 ... 1023. Wie macht man das am geschicktesten mit einem Akku, dass die oberen Bits tatsächlich den gesamten Index durchwandern? Meine Idee wäre wie schon vorher den Akku in zwei Zähler zu teilen, einen der von 1 ... 1250k zählt und einen der dann von 0 ... 1023 zählt. Das mit einem Akku wäre aber trotzdem hybscher irgendwie. /Edit Edit2: Also jetzt habe ich die 1280M mal auf einen vollen Binärwert aufgefüllt und komme auf 2147,4...*10^6 also auf einen Takt von 214,7MHz. Wenn ich eine Stelle weniger nehme, dann ist es die Hälfte, also 107,3MHz. Und dann laufe ich da in Genauigkeitsprobleme weil ich es nie schaffe im FPGA einen Takt zu erzeugen der auf 9 Stellen genau ist. Oder kann das der DCM im Spartan3? Als Alternative kann ich natürlich weiterhin bis 1280M zählen mit dem Akku. Die oberen 10 Bits laufen aber nur von 0 bis 610, ich könnte also eine kleinere Tabelle machen für den Sinus, also 611/4 Werte. Was würdet ihr machen? /Edit Jetzt ist 1280M sehr viel, aber der Aku wird da bei 0,1Hz je Takt nur um 1 erhöht. Bei einer maximalen (erwünschten) Sinusfrequenz von 8MHz muss dann der Akku je Takt um 1280/16=80M oder 8MHz*10=80M erhöht werden. Das wäre dann der 8MHz Sinus mit 16 Punkten. Will man das variabel einstellbar, muss der Benutzer Werte von 0 ... bis 80M einstellen können. Wie macht man das mit einem Dreh-Encoder? Also um gleichzeitig fein aber auch sehr grob einstellen zu können? Gustl Buheitel schrieb: > Wie macht man das mit einem Dreh-Encoder? Also um gleichzeitig fein aber > auch sehr grob einstellen zu können? Man macht es so: wenn schnell und ausdauernd gedreht wird, dann wird schnell inkrementiert. Sonst eben nur langsam. In C sieht das so aus: http://www.lothar-miller.de/s9y/archives/71-Drehgeberauswertung-mit-Beschleunigung.html Das kann man sicher einfach nach VHDL portieren. Ok, wunderbar, ich zähle also z. B. die Zahl der Impulse je 0,1s die vom Encoder kommen und nehme die dann zum Quadrat oder multipliziere die mit einem Wert. Mit dem Ergebnis wird dann der Akku gezählt. Wie sollte ich das Problem mit dem Akku lösen, das ich oben in den Edit-Sektionen beschrieben habe? Also dass die oberen 10Bits des Akkus nicht alle Indizes erreichen?
Gast
#3865639
Gustl Buheitel schrieb: > > Wie sollte ich das Problem mit dem Akku lösen, das ich oben in den > Edit-Sektionen beschrieben habe? Also dass die oberen 10Bits des Akkus > nicht alle Indizes erreichen? Wenn du exakte 0.1 Hz Auflösung haben: 1. Ein Refezenzoscillator der eine passende Frequenz hat: z.B. wenn 20 ppm absolute Genauigkeit reichen: 13,422 MHz. oder 2. Mit einem Hilfsakku den Phasenincrement des Hauptakkus zwischen 2 Werten springen lassen. 3. die Sinustabelle in der Länge anpassen und den Akkuüberlauf enstprechend behandeln. Pseudocode: Temp = Akku + Schrittweite if (Temp < Akkulänge) Akku = Temp else Akku = Temp - Akkulänge. Also ich habe mich jetzt entschieden ein SinusROM mit 611 Einträgen zu verwenden und zwar für eine komplette Periode. Das Ergebnis ist nicht ganz wie ich mir das vorstelle. Eigentlich ist es nicht viel:
Das Python liefert ordentliche Werte:
Gast
#3865646
4. Den Akku lang genaug machen, dass der Fehler kleiner als die Genauigkeit des Referenztaktes ist.
Gast
#3865651
Noch ein Nachtrag: > 4. Den Akku lang genaug machen, dass der Fehler kleiner als die > Genauigkeit des Referenztaktes ist. wenn ich mir es genau überlege ist 2) und 4) identisch. Einen Fehler habe ich schon gefunden in meinem Code oben. Und zwar laufen Integer, wenn sie nicht garade auf eine Zweierpotenz limitiert sind, nicht bei der Limitierung über. Das musste ich noch einbauen.
Gast
#3865664
Lattice User schrieb: > Falsch, im 2er Komplement muss man nach der Inversion eine eins > dazuaddieren. Warum, es führt nur zu einem Offset: Hier ist ein Beispiel für das Dreieick: Q1 0 0 0 0 ( 0 ) 0 0 0 1 ( 1 ) 0 0 1 0 ( 2 ) 0 0 1 1 ( 3 ) 0 1 0 0 ( 4 ) 0 1 0 1 ( 5 ) 0 1 1 0 ( 6 ) 0 1 1 1 ( 7 ) Q2 0 1 1 1 ( 7 ) 0 1 1 0 ( 6 ) 0 1 0 1 ( 5 ) 0 1 0 0 ( 4 ) 0 0 1 1 ( 3 ) 0 0 1 0 ( 2 ) 0 0 0 1 ( 1 ) 0 0 0 0 ( 0 ) Q3 1 1 1 1 ( -1 ) 1 1 1 0 ( -2 ) 1 1 0 1 ( -3 ) 1 1 0 0 ( -4 ) 1 0 1 1 ( -5 ) 1 0 1 0 ( -6 ) 1 0 0 1 ( -7 ) 1 0 0 0 ( -8 ) Q4 1 0 0 0 ( -8 ) 1 0 0 1 ( -7 ) 1 0 1 0 ( -6 ) 1 0 1 1 ( -5 ) 1 1 0 0 ( -4 ) 1 1 0 1 ( -3 ) 1 1 1 0 ( -2 ) 1 1 1 1 ( -1 ) Die Werte in den Quadranten Q3 und Q4 sind einfache Bitinversionen >> wenn die Punktenummerierung stimmt. > Das ist nur eine Frage der erforderlichen Genauigkeit. ? Ich meinte, die richtigen X-Werte anzuwählen
Gast
#3865695
M. W. schrieb: > Lattice User schrieb: >> Falsch, im 2er Komplement muss man nach der Inversion eine eins >> dazuaddieren. > > Warum, es führt nur zu einem Offset: > Der Offset ist aber nur in der negativen Halbwelle da. Du addierst damit effektiv ein Rechtecksignal zur Ausgabe. > > >>> wenn die Punktenummerierung stimmt. >> Das ist nur eine Frage der erforderlichen Genauigkeit. > ? > > Ich meinte, die richtigen X-Werte anzuwählen Und ich meinte die Anforderung an das Ergebnis. Die richtigen X Werte auswählen braucht in der Tat nur eine Inversion wenn man die Tabelle wie Max vorgeschlagen hat erzeugt. Wenn die Genaugigkeit für die Amplitude von 8 bit reicht, wozu dann Resourcen verschwenden? 256 Punkte für den Quadranten reichen in diesem Falle.
Gast
#3865719
Gustl Buheitel schrieb: > Einen Fehler habe ich schon gefunden in meinem Code oben. Und zwar > laufen Integer, wenn sie nicht garade auf eine Zweierpotenz limitiert > sind, nicht bei der Limitierung über. Das musste ich noch einbauen. Hat sich überschnitten, aber das entspricht meinem Vorschlag 3. Nur macht das keiner so, Analog Devices z.B. verwendet in ihren DDS Generator bis zu 48bit Akkus (z.B. AD9912). Wenn man sich auf 2er Potenzen beschränkt benötigt man weniger Logik und erreicht damit höhere Taktraten für die DDS. Ok, aber dann braucht man auch einen recht genauen Takt oder? Und wo ich noch drüber gestolpert bin war, dass signed natürlich das Vorzeichen bei negativen Zahlen gestezt hat. Man kann es also nicht einfach ausgeben und bekommt den Sinus sondern muss noch das Vorzeichen invertieren. Hier ein paar Online Generatoren: http://meraman.com/htmls/en/sinTable.html http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml Das muss man heute meistens nicht mehr selber errechnen.
Gast
#3865764
Gustl Buheitel schrieb: > Ok, aber dann braucht man auch einen recht genauen Takt oder? Auch nicht genauer als deine Anforderung an die absolute Genauigket. Deine CLK128 ist 128 MHz? Bei einem 48bit Akku entspricht 0.1 Hz dann einen Wert von 219902. D.h. du musst vielfache davon in das Increment (Speed) Register schreiben. Diese Multiplikation muss man aber nicht in einem Takt der 128 MHz rechnen, selbst die serielle Implememtation mit Schieberegister und Addierer bremst dich nicht aus. Verlockend ... erstmal reicht mir aber meine aktuelle Lösung. Jetzt hab ich schon AM mit zwei unabhängigen Sinussignalen und gleich kommt noch FM was leicht anspruchsvoller wird. Unzufrieden bin ich noch mit der Einstllungemöglichkeit für den Benutzer. Klar kann man mit dem Encoder verschiedene Geschwindigkeiten erkennen und das mache ich auch, aber ... das muss noch schneller gehen. weiterbastel Gustl Buheitel schrieb: > das muss noch schneller gehen. Du könntest mit dem Drucktaster im Encoder die Zehnerstellen bzw. Einstellgeschwindigkeit umschalten... Jetzt zähle ich die Encoderimpulse für immer eine Viertelsekunde ca. und rechne dann 2 hoch diese Zahl. Damit ändere ich den Wert (Geschwindigkeit) um den der Akku je Takt erhöht wird. Also ich habe zweimal einen variablen Sinus, ich habe AM, und ich habe FM angefangen. Dazu mache ich folgendes:
Nur so grab als Skizze, das ist in Wirklichkeit signed und ich beachte auch das Vorzeichen. Mein Problem: Bei schnellen Sinusfrequenzen der Trägerfrequenz Sin_A macht die Amplitude von Sin_B (0 ... 511) viel aus, bei langsamer Trägerfrequenz macht das aber kaum noch was. Irgendwie hätte ich das gerne dass sich das aufhebt und die FM immer gleich sichtbar ist. Also der Wert um den der Sin_A_Akku erhöht wird der wird mit steigender Frequenz eher exponentiell kleiner, jetzt müsste bei mir die Amplitude von Sin_B das auch machen damit es sich aufhebt. Morgen guck ich mir das mal genauer an ...
Gast
#3866504
Lattice User schrieb: > Der Offset ist aber nur in der negativen Halbwelle da. Du addierst damit > effektiv ein Rechtecksignal zur Ausgabe. Ok, von der Theorie her stimmt das wohl, aber mein Dreieck von der Tabelle oben ist kontinuierlich. So wäre es auch mit einem Sinus, meine ich.
Gast
#3866540
ist es nicht so, dass ein Sinus, der als 'signed' intern in der Logik laeuft, einfach einen Offset braucht wenn man ihn ueber einen DAC ausgibt? Der Screenshot deutet darauf hin... Also einfach 1/2 DAC-Ausgangsspannung auf den 'signed' Sinuswert draufaddieren, dann kommt da ja ein richtiger Sinus am DAC raus... Ja, genau ist signed, und "leider" ist das Vorzeichenbit genau dann '1' wenn die Zahl negativ ist. Ich musste also das Vorzeichenbit invertieren was quasi der Offset um das MSB ist. Dann passt das. Zu meinem Problem mit der FM: Statt
sollte ich wohl
schreiben, also eine Multiplikation, dann ist das Verhältnis der FM immer konstant und unabhängig von der Trägerfrequenz. Muss ich mal ausprobieren :-) Und dann kommen noch variable Amplituden der beiden Sinusschwingungen dazu. So, FM ist fertig und zwar so, dass die Trägerfrequenz maximal verdoppelt und minimal halbiert wird. Im Prinzip habe ich einen Sinus A der der Träger ist mit Sin_A_Inkrement um das der Akku dieses Sinus je Takt erhöht wird. Und ich habe ein Signal Sinus B das darauf moduliert wird. Daraus wird Sinus C mit Sin_C_Inkrement. Sin_C_Inkrement = (Sin_A_Inkrement/1024)*((Sin_B*3)+512) Die Werte von Sin_B gehen unsigned von 0 ... 511. Ist der Wert 511, dann erhält man: Sin_C_Inkrement = (Sin_A_Inkrement/1024)*((511*3)+512) = = (Sin_A_Inkrement/1024)*(2045) = Sin_A_Inkrement*1.997 Ist der Wert 0, dann erhält man: Sin_C_Inkrement = (Sin_A_Inkrement/1024)*((0*3)+512) = = (Sin_A_Inkrement/1024)*(512) = Sin_A_Inkrement*0.5 So sähe es für den Akku von Sin_C aus: Sin_C_Akku = Sin_C_Akku + (Sin_A_Inkrement/1024)*((Sin_B*3)+512) Aber weil das erste /1024 vermutlich die Genauigkeit sehr stört, habe ich das nach hinten gezogen, also: Sin_C_Akku = Sin_C_Akku + ((Sin_A_Inkrement)*((Sin_B*3)+512))/1024 Fertig sieht es so aus aufgeteilt auf 3 Schritte:
Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|