Hallo Forum,
zur Zeit beschäftigt mich mein Spartan3 in dem ein NCO realisiert wurde.
Daran angeschlossen ein 8 Bit D/A Wandler (DAC0800) an dem ein Sinus
Signal mit 12 Vss am Ausgang sich messen läst.
Nun meine Frage wie bekomm ich die AM Modulation hin?
Klar DAC_out <= NCO Sinus * der Wert vom z.b A/D
Das Problem ist:
Vollaussteuerung = +-6Vss <= ist OK
Halbe = 0V bis -6V <= sollte +-3V sein
viertel = -3 bis -6V <= sollte +-1,5V
wenn ich nun ein addierer rein mach hab ich das Prob bei
Vollaussteuerung.
Wer kann Helfen?
c.u
Commtel
> Nun meine Frage wie bekomm ich die AM Modulation hin?
Eine AM-Modulation ist wie ein LCD-Display :-o
Nämlich doppelt gemoppelt:
Amplitudenmodulation-Modulation
> Nun meine Frage wie bekomm ich die AM Modulation hin?
Du solltest die Multiplikation signed machen (weil du ja auch -6V..+6V
hast). Offenbar machst du es bisher unsigned und sagst dann 0 = -6V.
Aber ohne Code ist das nur Raten auf Raten... ;-)
Hallo Lothar,
hier der Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use ieee.math_real.all;
--library UNISIM;
--use UNISIM.VComponents.all;
entity DDS is
Generic ( ADC_size : natural := 8;
DAC_size : natural := 8;
Phase0_Akku_Size : natural := 32;
Freq0_Reg_Size : natural := 32;
Phase0_Reg_Size : natural := 12
);
Port ( ADC_in : in STD_LOGIC_VECTOR (ADC_size -1 downto 0);
DAC_out : out STD_LOGIC_VECTOR (DAC_size -1 downto 0);
Clk : in STD_LOGIC --16Mhz = 62,5ns
);
end DDS;
architecture Behavioral of DDS is
signal Phase0_Akkumulator : unsigned (Phase0_Akku_Size -1 downto 0) :=
(others=> '0');
signal Freq0_Reg : unsigned (Freq0_Reg_Size -1 downto 0) :=
x"02000000";
signal Phase0_Reg : unsigned (Phase0_Reg_Size-1 downto 0) := (others=>
'0');
signal Sigma0_Phase_Freq : unsigned (Phase0_Akku_Size -1 downto 0);
signal DAC0_temp0 : signed (7 downto 0);
signal DAC0_temp1 : signed (15 downto 0);
signal DAC0_temp2 : signed (15 downto 0);
signal DAC0_Amplitude : signed (7 downto 0);
type Rom256x8 is array (0 to 255) of signed (7 downto 0);
signal Sinus_Rom : Rom256x8 ;
begin
process
begin
for i in 0 to 255 loop
Sinus_Rom(i) <= to_signed(integer((sin(2.0*MATH_PI*real(i)/256.0)
+1.0)*127.5),8);
end loop;
wait until rising_edge(Clk);
DAC0_Amplitude <= signed(ADC_in);
Phase0_Akkumulator <= Phase0_Akkumulator + Freq0_Reg;
Sigma0_Phase_Freq <= Phase0_Akkumulator + Phase0_Reg;
DAC0_temp1 <= (DAC0_temp0 - DAC0_Amplitude);
DAC0_temp2 <= (DAC0_temp1 * DAC0_Amplitude) ;
end process;
--DAC_out <= STD_LOGIC_VECTOR(Sigma0_Phase_Freq(31 downto 24));
--DAC_out <=
STD_LOGIC_VECTOR(Sinus_Rom(to_integer(unsigned(Sigma0_Phase_Freq(31
downto 24)))));
DAC0_temp0 <= signed(Sinus_Rom(to_integer(signed(Sigma0_Phase_Freq(31
downto 24)))));
DAC_out <= STD_LOGIC_VECTOR(DAC0_temp2(15 downto 8));
end Behavioral;
Vielen Dank für deine Antwort leider hab ich es bis jetzt noch nicht
ganz verstanden in welcher reihenfolge das gehen soll.
Was machst du denn hier mit dem +1.0 ?
Damit wird doch dein ganzer Sinus doch in den positiven Bereich
geschoben...
> Vielen Dank für deine Antwort leider hab ich es bis jetzt noch nicht> ganz verstanden in welcher reihenfolge das gehen soll.
Gehe doch erst mal her und gib einfach mal einen Sinus aus. Und dann
machst du deine Amplitudenmodulation (Multiplikation) genau dort, wo der
Sinus auf DAC_out ausgegeben wird.
> signed(ADC_in);> Ist das so?> Ist ADC_in=x"00" wirklich 0V am Eingang> und ADC_in=x"80" der negativste Wert> und ADC_in=x"7F" der positivste Wert?
nein natürlich nicht
ich hätte gern
ADC 0V = DAC x"7F" entspricht beim DAC0800 0V
ADC 2,5V = DAC x"7F" + dem Sinus +- 3F also DAC offset 7F - 3F und 7F +
3F
ADC 5V = DAC X"7F" + dem Sinus +- 7F also DAC offset 7F - 7F und 7F + 7F
> Gehe doch erst mal her und gib einfach mal einen Sinus aus. Und dann> machst du deine Amplitudenmodulation (Multiplikation) genau dort, wo der> Sinus auf DAC_out ausgegeben wird.
Lothar das geht ja auch
z.b FF kommt vom ADC und ich bekommt 00 bis FF Sinus
7F vom ADC bekomm ich die hälfte an Sinus ist ja auch OK
aber an den DAC wird 00 bis 7F gesendet was dem Bereich
-6 bis 0 entspricht.
Es sollten aber +3 bis -3V sein das muß doch möglich sein ?
Mfg
Commtel
> nein natürlich nicht.> ich hätte gern...
Du hast meine Frage nicht beantwortet.
Ich möchte nicht wissen, was du gerne hättest, sondern was du hast.
>>> Spartan3 in dem ein NCO realisiert wurde.>>> Vollaussteuerung = +-6Vss <= ist OK
Also, ist doch schön, wenn das funktioniert.
Dann mußt du doch nur noch ein klitzeklein wenig verstehen was da gerade
passiert und danach auch nur eine Klitzekleinigkeit ändern.
Was mußt du (ganz ohne AM und ADC) am DAC ausgeben, um -6V zu erhalten?
Was, um 0V zu erhalten und was, um +6V zu erhalten?
Kontrollier doch mal die Tabellen und korrigier die Werte ggfs.:
DAC-Wert Ausgangsspannung
0x00 -6V ?
0x7f -0V ?
0x80 +0V ?
0xff +6V ?
> ADC 0V = DAC x"7F" entspricht beim DAC0800 0V> ADC 2,5V = DAC x"7F" ....> ADC 5V = ...
Wieso steht hier jetzt was von 0V und 2,5V und 5V?
Wie passt das jetzt schon wieder auf die -6V...+6V?
Und wenn wir schon am definieren sind, dann zeig doch mal die
Wandlungsfunktion des ADCs:
Eingangsspannung ADC-Wert
0V 0x00 ?
2,5V 0x80 ?
5V 0xFF ?
> Was mußt du (ganz ohne AM und ADC) am DAC ausgeben, um -6V zu erhalten?> Was, um 0V zu erhalten und was, um +6V zu erhalten?> Kontrollier doch mal die Tabellen und korrigier die Werte ggfs.:> DAC-Wert Ausgangsspannung> 0x00 -6V ?> 0x7f -0V ?> 0x80 +0V ?> 0xff +6V ?
Genau so ist die Ausgabe
> ADC 0V = DAC x"7F" entspricht beim DAC0800 0V> ADC 2,5V = DAC x"7F" ....> ADC 5V = ...> Wieso steht hier jetzt was von 0V und 2,5V und 5V?> Wie passt das jetzt schon wieder auf die -6V...+6V?> Und wenn wir schon am definieren sind, dann zeig doch mal die> Wandlungsfunktion des ADCs:> Eingangsspannung ADC-Wert> 0V 0x00 ?> 2,5V 0x80 ?> 5V 0xFF ?
nochmals genau wobei ich die Eingänge des FPGA s jetzt als PullUP
defeniert sind und ich die 0x80 über Schiebeschalter einstell.
> Genau so ist die Ausgabe
Dann ist es doch gar nicht so schwer:
1) du berechnest mit der DDS deinen DAC-Wert (der ist unsigned!!!!)
2) du ziehst den Offset 0x80 ab (jetzt ist er signed)
3) du multiplizierst den erhaltenen Wert mit dem ADC-(Dipschalter-)Wert
4) du addierst wieder den Offset von 0x80 drauf
5) du gibst den Wert an den DAC aus
So Cam funzt endlich.
Hallo Lothar erst mal vielen Dank für deine Mühe.
Wie du siehst (hoffe Anhang kommt mit) geht es leider immer noch nicht
Das Signal fängt bei Offset 0x80 an.
Entschuldige bitte die schlechte Quali.
Hoffe du kannst was damit anfangen
Achso beide Codes haben das gleiche Ergebnis auf dem Oszi.
Gedanklich wäre es ja perfekt gewesen das Signal um die Nullachse
wandern zu lassen und den Offset dazuaddieren.
Ich hab mir ja auch von c't den DDS Code angesehen.
Die machen ein XOR nach der Tabellenausgabe.
Ich vermute wir sollten die "Lookup" Tabelle ändern.
Leider komm ich mit deiner Sinus_Rom(i) <=
to_signed(integer((sin(2.0*MATH_PI*real(i)/256.0)+1.0) *127.5),8);
nicht ganz mit.
Mfg
Commtel
Ich hatte erwartet, dass genau dieses Signal aus deiner DDFS
herauskommt. Denn du initialiisert ein signed-Array mit einem Offset
(meine Frage im Beitrag "Re: DDS mit AM Modulation").
Lass doch mal das +1.0 raus...
Dann hast du einen 8 Bit breiten signed Sinus. Und der braucht für die
Ausgabe dann nur noch die Skalierung mit dem ADC-(Dipschalter-)Wert und
anschliessend die Addition von 0x80 für die Ausgabe von 0V, wenn auch
die DDFS 0 ausgibt.
Commtel @msn schrieb:> Nadelimpuls nach unten
Gib Dir doch mal im Simulator alle Werte aus. Vielleicht erfolgt an der
Stelle des Nadelpulses ein Überlauf?
Rick
Hallo Rick Dangerus,
freu mich einen weiteren Mitstreiter in der Runde zu haben
Der Nadelimpuls ist was ich gerade feststelle unabhängig von
DAC0_Amplitude.
Aber der Impuls ist jetzt weniger das Problem sondern das die Regelung
immer noch nicht tut.
Amplitude fängt bei 0x7F an * Schalterstellung 0x3F
> m**t Foto
Aber noch ohne deinen aktuellen Quelltext.
BTW:
die Idee mit der Simulation ist übrigens wirklich nicht schlecht :-o
Das kann man alles super gut simulieren, und man sieht gleich ob das
Verfahren prinzipiell klappt.
Hast Du denn eine Testbench für Deinen Code? Dann könnte man das ganz im
heimischen Simulator mal durchspielen.
Deinen DAC kann man ja als Verhaltensmodell nachbilden. Er schreibt dann
alle Werte in eine Datei. Und für den ADC kann man sich auch was
geeignetes einfallen lassen. z.B. einen Rampengenerator.
Rick
Nun nicht direkt ich hab Modelsim 6.5 das ich aus ISE 11.4 herraus
starte.
In Modelsim bin ich noch neu daher weis ich jetzt nicht ob da eine Datei
erzeugt wird die ihr benutzen könnt.
Ich war die ganze Zeit am Überlegen ob es nicht möglich ist
Halbwellen zu erzeugen diese mit dem Offset zu versehen dann zu
multiplizieren und jede 2. umzuklappen.
Bleibt die Frage offen ob das mit anderen Signalformen auch möglich ist.
@ Lothar der aktuelle Code ist das was du vorgeschlagen hast.
Achso der Peak ist jetzt weg
Sinus_Rom(i) <= to_signed(
integer(sin(2.0*MATH_PI*real(i)/256.0)*127.5),8);
geändert zu
Sinus_Rom(i) <=
to_signed(integer(sin(2.0*MATH_PI*real(i)/256.0)*127.0),8);
sorry Admin für dieses Doppelpost wie man merkt bin ich in Gedanken
wieder beim Code.
Ich versuch es zu vermeiden in Zukunft
> @ Lothar der aktuelle Code ist das was du vorgeschlagen hast.
Naja, ich habe so viel vorgeschlagen...
> Achso der Peak ist jetzt weg
Aber dafür ist der Minimalwert nur -127 (möglich wäre -128) :-o
Besser wäre integer(sin(2.0*MATH_PI*real(i)/256.0)*127.5-0.5)
Jungs ihr dürft die Hosen runter lassen LOL
begin
process
begin
for i in 0 to 255 loop
Sinus_Rom(i) <= to_signed(integer(sin(2.0*MATH_PI*real(i)/256.0)
*127.5 -0.5),8);
end loop;
wait until rising_edge(Clk);
DAC0_Amplitude <= unsigned(ADC_in);
Phase0_Akkumulator <= Phase0_Akkumulator + Freq0_Reg;
Sigma0_Phase_Freq <= Phase0_Akkumulator + Phase0_Reg;
DAC0_temp0 <=
unsigned(Sinus_Rom(to_integer(unsigned(Sigma0_Phase_Freq(31 downto
24)))));
DAC0_temp2 <= (DAC0_temp1 * DAC0_Amplitude) ; -- Gain z.b vom A/D
DAC0_temp3 <= (DAC0_temp2 + x"8000"); --Offset (0 Linie)
if DAC0_temp0(7) = '1' then --Sinus "Gleichrichten"
DAC0_temp1 <= not (DAC0_temp0);
else
DAC0_temp1 <= DAC0_temp0;
end if;
if DAC0_temp0(7) = '1' then --Sinus "umklappen"
DAC0_temp4 <= not (DAC0_temp3);
else
DAC0_temp4 <= DAC0_temp3;
end if;
DAC_out <= STD_LOGIC_VECTOR(DAC0_temp4(15 downto 8));
end process;
end Behavioral;
Es geht mit einem aber.
Kleine Peaks an den null durchgängen (0x80).
Latency??
4 Tage google mit Kopfzerbrechen
Darauf ein Bier
Commtel @msn schrieb:> Ich war die ganze Zeit am Überlegen ob es nicht möglich ist> Halbwellen zu erzeugen diese mit dem Offset zu versehen dann zu> multiplizieren und jede 2. umzuklappen.
Natürlich ist das möglich.
Aber es geht auch mit einem Viertel des Speichers als Lookup-Table bzw.
mit der 4-fachen Phasenauflösung bei gleichem Speicherverbrauch:
Es genügt völlig, eine Viertelwelle der Sinusfunktion zu speichern.
Die Tabelle wird dann mit den Quadranten abwechselnd vorwärts und
rückwärts ausgelesen, und im 3. und 4. Quadranten wird zusätzlich das
Vorzeichen des Ausgangs umgekehrt.
So erreichst Du die 4-fache Phasenauflösung mit einer 8-Bit Adresse für
die Lookup-Table:
Sigma0_Phase_Freq[31..22] liefert insgesamt die Adresse für die
Sinuswelle.
Sigma0_Phase_Freq[31] ist ist das Vorzeichen für den Ausgangswert, wenn
dieses Bit 1 ist, muß der Ausgang negiert werden.
Sigma0_Phase_Freq[30] bestimmt, wie die unteren Bits die Adresse für die
Lookup-Table liefern:
Wenn Bit30 = 0 ist, liefert Sigma0_Phase_Freq[29..22] die Adresse
direkt.
Wenn Bit30 = 1 ist, wird (255 - Sigma0_Phase_Freq[29..22]) als Adresse
an die Lookup-Table geliefert und damit die Ausleserichtung umkekehrt.
Jetzt muß nur noch die Tabelle mit der passenden Viertelwelle geladen
werden: Die Sinuswerte der Tabelle müssen symmetrisch zwischen Maximum
und Nulldurchgang liegen, also in der Phase um einen Offset von 1/2 der
Phasenauflösung verschoben.
also:
Habe derartige Generatoren bereits praktisch realisiert, allerdings
nicht in VHDL, sondern in Schematic-Entry...
Meiner läuft bei einer Abtastrate von 27MHz mit 13 Bit Phasenauflösung
sowie 16 Bit Ausgangssignal.
Allerdings mit einem Takt von 108MHz, so daß ich aus dem einen Generator
4 Signale erhalte: Sinus und Cosinus jeweils einmal frequenzmoduliert
und unmoduliert.
Fittet problemlos in einem Spartan 3AN mit Speedgrade -4.
Gruß,
Thorsten
Lothar Miller schrieb:> Aber dafür ist der Minimalwert nur -127 (möglich wäre -128) :-o> Besser wäre integer(sin(2.0*MATH_PI*real(i)/256.0)*127.5-0.5)
Damit hast Du aber einen DC-Offset, würde ich von daher nicht empfehlen.
Hallo Thorsten S. ,
auch du hertzlich Willkommen.Dein Generator gefällt mir. :-)
Ja dieses Prinzip mit der Viertelwelle hab ich im c't DDS Generator
gesehen.
Ich frag mich gerade ob dieses Prinzip auch für andere Signalformen in
Verbindung mit der Verstärkung funktioniert.
Hast du das Erfahrung z.b Sägezahn mit Rückwärtszählen wird da nix.
> Damit hast Du aber einen DC-Offset, würde ich von daher nicht empfehlen.
Das kommt auf den DAC an. Mit -127 bis +127 hast du auf jeden Fall 1 LSB
verloren.
>> Ich war die ganze Zeit am Überlegen ob es nicht möglich ist>> Halbwellen zu erzeugen diese mit dem Offset zu versehen dann zu>> multiplizieren und jede 2. umzuklappen.> Es genügt völlig, eine Viertelwelle der Sinusfunktion zu speichern.
Hier meine Lösung mit dem Viertel-Sinus:
http://www.lothar-miller.de/s9y/categories/31-DDFS
EDIT:
>> Ich frag mich gerade ob dieses Prinzip auch für andere Signalformen in>> Verbindung mit der Verstärkung funktioniert.
Bei Sinus-, Dreieck- und anderen Punktsymmetrischen Wellenformen geht
das.
@ Lothar Miller
wär vieleicht ein weiterer Artikel für deine Seite AM Modulation.
Wie gesagt beim googeln hab ich nix dergleichen gefunden.
Ich werd jetzt mal versuchen ein weiteren Weg der AM Modulation zu
testen.
Positive Halbwellen werden durch Multiplikation weitergegeben.
Negative werden durch Multiplikation subtrahiert.
Mfg
Commtel
Commtel @msn schrieb:> Hast du das Erfahrung z.b Sägezahn mit Rückwärtszählen wird da nix.
für'n Sägezahn kannst Du das ROM weglassen. Die Adresse (die oberen Bits
vom Phasenakku + Phasenoffset) liefern direkt einen Sägezahn. Da mußt Du
für vorzeichenbehaftete Werte nur den Offset subtrahieren, also bei 8
Bit Werten -0x80.
Für alle unsymmetrischen Signalformen benötigt man (mindestens) ein ROM
mit eienr Vollwelle des Signals.
Da man für Mischer, Quadraturmodulatoren oder -Demodulatoren aber
normalerweise nur Sinus und Cosinus benötigt ist das Sparkonzept mit dem
Viertelwellen-ROM hier ressourcenschonend einsetzbar.
Gruß,
Thorsten
Commtel @msn schrieb:> Ich werd jetzt mal versuchen ein weiteren Weg der AM Modulation zu> testen.> Positive Halbwellen werden durch Multiplikation weitergegeben.> Negative werden durch Multiplikation subtrahiert.
Die Beschreibung irritiert mich jetzt etwas. Hört sich für mich nicht so
an, als käme damit eine AM heraus...
Ein normaler Amplituden-Modulator arbeitet als Multiplizierer signed x
unsigned. Die Modulation darf keine Trägerphasen-Umkehrung bewirken, der
Modulationsgrad ist stets < 100%, damit ein minimaler Restträger
erhalten bleibt.
Das Trägersignal (Sinusschwingung aus dem DDFS) kommt an den
Signed-Input des Multilplizierers, die Modulation muß als unsigned
vorliegen (ein normales signed-Audiosignal wäre dementsprechend mit
einem Offset in Höhe des MSB zu versehen).
Der Offset sorgt auch dafür, daß der Träger mit halber Maximalamplitude
am Ausgang erscheint, wenn das Modulationssignal Null ist.
Eine signed x signed Multiplikation des Modulationssignals mit dem
Träger bewirkt eine Trägerunterdrückung. Ohne Modulationssignal gibts
kein Ausgangssignal; bei Modulation erscheinen nur die Seitenbänder am
Ausgang.
Wenn man jetzt noch durch einen passenden Bandpaß das obere oder untere
Seitenband ausfiltert, hat man einen SSB-Sender.
Gruß,
Thorsten
Hallo Thorsten
hast du was mit Funktechnik zu tun?
Wo finde ich ähnliche Projekte wie das was du beschreibst?
Eventuell als VHDL Code oder wer hat ein Link.
Commtel @msn schrieb:> hast du was mit Funktechnik zu tun?
nicht direkt. Bin in früher Jugend durch Radiobasteln zur Elektronik
gekommen...
Interesse habe ich auch noch am Amateurfunk, bin nur bislang vor allem
aus Zeitgründen nie dazu gekommen, die Prüfung abzulegen.
Beschäftige mich beruflich u.a. mit digitaler Signalverarbeitung.
> Wo finde ich ähnliche Projekte wie das was du beschreibst?> Eventuell als VHDL Code oder wer hat ein Link.
Damit kann ich leider nicht dienen...
Ein paar gute Hinweise zur Amplitudenmodulation, kannst Du aus dem
entsprechenden Wikipedia-Artikel entnehmen:
http://de.wikipedia.org/wiki/Amplitudenmodulation
AM mit unterdrücktem Träger:
http://de.wikipedia.org/wiki/Amplitudenmodulation_mit_unterdr%C3%BCcktem_Tr%C3%A4ger
SSB: http://de.wikipedia.org/wiki/Einseitenbandmodulation
Was hast Du mit Deinem Oszillator eigentlich vor?
Gruß,
Thorsten
Es sollte später mal ein Arbiträr-Funktionsgenerator werden.
Um erst mal erfahrungen zu sammeln hab ich den DAC0800
gewählt(Krustelkiste gefunden).
Sinusausgabe hat ja im ersten Durchlauf funktioniert FM
(Schiebeschalter) auch.
Tja dacht ich mir AM sollt auch ganz einfach sein. ;-)
Nun gut aber so richtig zufireden bin ich mit meiner Lösung noch nicht.
Die Links sind mir bekannt und auch
http://www.mikrocontroller.net/attachment/70196/sinus.txt> Interesse habe ich auch noch am Amateurfunk, bin nur bislang vor allem> aus Zeitgründen nie dazu gekommen, die Prüfung abzulegen.
so geht es mir leider auch.
Was genau machst du mit deinem Funktionsgernerator?
Ist der fix fertig mit Tastatur,Endstufe in einem Gehäuse?
Schönen Sontag euch allen.
c.u
Commtel
Commtel @msn schrieb:> Was genau machst du mit deinem Funktionsgernerator?> Ist der fix fertig mit Tastatur,Endstufe in einem Gehäuse?
Nein, der dient nicht als Funktionsgenerator...
Der Oszillator ist nur ein kleiner Building-Block in einem
größeren Design, dient dort als Farbträgeroszillator in einem
volldigitalen Videoencoder, der alle gängigen Standards ausgeben kann.
In meiner Freizeit beschäftige ich mich u.a. mit der Entwicklung eines
leistungsfähigen Ultraschalldetektors zur Fledermausbeobachtung...
Die Ultraschallsignale werden in einem Multiplizierer mit dem
Sinussignal aus dem Oszillator gemischt, (signed x signed) so daß am
Ausgang nur die Summen- und Differenzfrequenz von Ultraschallsignal und
Oszillator erscheinen. Das Signal wird Tiefpaß-gefiltert, so daß nur
die Differenzfrequenz übrig bleibt.
Damit lassen sich die Ultraschallsignale hörbar machen.
Gruß,
Thorsten