Forum: FPGA, VHDL & Co. Probleme mit Signalgenerator/Dreieck


von Bucki E. (buckied)


Lesenswert?

Hallo liebe Forumsgemeinde,

ich habe leider ein Problem bzgl. einer weiteren Funktion meines 
Generators.
Ein sehr gut funktionierendes Rechtecksignal ist schon drin (ja auch 
eher eine einfache Übung, aber war mein Einstieg). Undzwar habe ich mir 
einen 7-bit R2R-DAC gebaut und möchte nun eine Dreiecksfunktion 
erstellen.

Jetzt habe ich nur das Problem, dass ich eine laut Simulation 
funktionierende VHDL habe, diese (ich vermute durch den Teiler der 
Auflösung des DAC's) aber sehr unzuverlässige Ergebnisse für die 
Frequenz ausgibt (immer Abweichung von 100Hz ode mehr) . Das bisherige 
Konstrukt funktioniert bisher so, dass ich einen Wert für die Frequenz 
an den FPGA übergebe (50MHz Takt / Wunschfrequenz = Nötige Takte / 
zweifache Auflösung (da aufsteigend und wieder Absteigendes Signal) = 
Counterwert), der Counter so lang läuft und dann in einen je nach Status 
aufsteigenden (weiterer Zähler der die Bits des DAC's schaltet) oder 
absteigenden Zustandsautomaten geht. Also auf 127 rauf zählen und wieder 
runter klappt super, nur die Zeit haut nicht hin.

Ich weis leider absolut nicht, wie ich mir einen relativ genauen 
Dreieckgenerator bauen könnte bzw was ich an meiner VHDL abändern 
müsste.. hat vielleicht jemand einen Tipp oder sowas schonmal umgesetzt?

Grüße Bucki
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity Triangular_Wave_Generator is
6
    Port ( Data_In_Triangular : in  STD_LOGIC_VECTOR (24 downto 0);
7
           Data_Pin_Out : out  STD_LOGIC_VECTOR (19 downto 2);
8
           Enable_Triangular : in  STD_LOGIC;
9
           RST_Triangular : in  STD_LOGIC;
10
           CLK : in  STD_LOGIC);
11
end Triangular_Wave_Generator;
12
13
architecture Behavioral of Triangular_Wave_Generator is
14
15
  type Counter_State is (cnt_up, cnt_down);    -- use of a state machine for the counter to implement a Duty Cycle
16
   signal pr_state : Counter_State := cnt_up;  -- initialisation with state counter_on (means the high time of the sqaure wave)
17
   signal nx_state : Counter_State;
18
  signal state : std_logic := '0';
19
  signal steps : unsigned (19 downto 2) := (others => '0'); 
20
   signal cnt : unsigned (24 downto 0) := (others => '0');
21
22
begin
23
24
  cnt_proc : process(CLK, RST_Triangular, Enable_Triangular) -- send the frequency divided by 255 to generate the right triangular wave form
25
  begin
26
    if rising_edge(CLK) then
27
      if (RST_Triangular = '1' or Enable_Triangular = '0') then  --resetting the counter and the state
28
        cnt <= (others => '0');
29
        state <= '0';
30
         else
31
        if cnt < unsigned(Data_In_Triangular)-1 then
32
          cnt <= cnt + 1;
33
          state <= '0';
34
        else
35
          cnt <= (others => '0');
36
          state <= '1';
37
        end if;
38
      end if;
39
    end if;  
40
  end process cnt_proc;
41
42
  state_process: process(CLK, RST_Triangular, Enable_Triangular)
43
    begin
44
    
45
        if rising_edge(CLK) then
46
            if (RST_Triangular = '1' or Enable_Triangular = '0') then
47
                pr_state <= cnt_up;
48
                nx_state <= cnt_down;
49
           steps <= (others => '0');
50
            else
51
                if Enable_Triangular = '1' then
52
                    pr_state <= nx_state;
53
              
54
              if state = '1' then  
55
                case pr_state is
56
                  when cnt_up =>
57
                            if (steps < 126) then -- 7-bit r2r-dac
58
                                steps <= steps + 1;
59
                            else
60
                      steps <= "000000000001111111";
61
                                nx_state <= cnt_down;
62
                            end if;
63
                  when cnt_down =>
64
                            if (steps > 1) then
65
                                steps <= steps - 1;
66
                            else
67
                      steps <= (others => '0');
68
                                nx_state <= cnt_up;
69
                            end if;                    
70
                end case;
71
              end if;
72
                end if;  
73
            end if;      
74
        end if;
75
76
        Data_Pin_Out <= std_logic_vector(steps);
77
    end process state_process;
78
79
end Behavioral;

: Bearbeitet durch Moderator
von Andreas (Gast)


Lesenswert?

Bucki E. schrieb:
> immer Abweichung von 100Hz ode mehr

Bei welcher nominellen Frequenz?

von Bucki E. (buckied)


Lesenswert?

Z.B. bei einer "eingestellten Frequenz von 4 kHz". Das Problem ist, dass 
ich ja keine Gleitkommazahlen an die VHDL übergeben kann und wenn ich 
mir die nötige Zahl für den Counter berechne immer die Nachkommastellen 
vernachlässige und mir somit einige Counter Ticks/CLK-Ticks fehlen. Bsp:

Gewollte Frequenz ist 4kHz und F_CLK_FPGA ist 50 MHz:

50.000.000Hz/4.000Hz = 12500 CLK Ticks --> 12500 / 256 = 48,828.. --> 
convert to int für VHDL --> 48. Das wäre eine Periodendauer von 
245,76us. Nun fehlen mir ja aber 0,828.. * 256 = 212 CLK-Ticks 
(Periodendauer von 4,24us) die ich irgendwie in das gesamte mit einfügen 
müsste.

Ich bräuchte also einen weiteren Eingang für die VHDL wo ich den modulo 
Rest an diese weitergebe und irgendwie einen weiteren Counter der mir 
asynchron immer mal den normalen Counter verzögert. Also das grobe Wie 
ist mir bekannt, ich habe momentan nur noch keine Vorstellung für ein 
passendes VHDL Konstrukt, um mir diese Funktion umzusetzen.

Grüße Bucki

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


Lesenswert?

Bucki E. schrieb:
> ich habe momentan nur noch keine Vorstellung für ein passendes VHDL
> Konstrukt, um mir diese Funktion umzusetzen.
Der Ansatz über den Teiler bringt bei höher werdenden Frequenzen immmer 
mehr Granularität. Die "letzten" Sprünge wären so gesehen ja 25MHz und 
12,5MHz...

Sieh dir mal das Thema DDFS an. Damit werden üblicherweise solche 
Kurvenformen erzeugt, und damit hast du das "Teilerproblem" nicht, 
sondern du tauscht es gegen einen gewissen Jitter ein:
http://www.lothar-miller.de/s9y/categories/31-DDFS

Genauso leicht wie den Sinus dort kannst du natürlich ein Dreieck ins 
ROM ablegen. Oder sonstwas...

: Bearbeitet durch Moderator
von J. S. (engineer) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Genauso leicht wie den Sinus dort kannst du natürlich ein Dreieck ins
> ROM ablegen. Oder sonstwas...

Das macht aber keinen Sinn, bzw bringt keinen Vorteil. Der Wert des 
Dreiecks lässt sich aus der Phase eindeutig ermitteln. Den Sinus legt 
man - wie andere komplexe Wellenformen auch - nur deshalb als Tabelle 
ab, weil man ihn nicht berechnen möchte.

Der Aspekt der genauen Frequenz, der durch die DDS-Methodik gelöst wird, 
bleibt davon unberührt. Es braucht nur den hoch aufgelösten Phasen-Akku.

Bleibt die Thematik der Bandbreitenbegrenzung des DAC und des 
AA-Filters: Um da ein möglichst sauberes Dreieck rauszubekommen, muss 
man Amplitude und Phase frequenzabhängig vorverzerren.

Ansonsten bliebe noch die direkte Erzeugung eines DSD per PDM:
Beitrag "Re: Zweiklang Ton erzeugen - direkte Ausgabe per PWM"

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


Lesenswert?

Jürgen S. schrieb:
> Der Wert des Dreiecks lässt sich aus der Phase eindeutig ermitteln.
Natürlich kann man das Dreieck auch einfach mit einem Zähler 
realisieren. Man muss ja eigentlich nur den Akku etwas breiter machen...

Mir ging es hier vorrangig darum, zu zeigen, dass man "feine" Auflösung 
nicht per binären Vorteiler macht.

Der Rest der Signalverarbeitung sollte logischerweise die höheren 
Frequenzen, die ein "Nichtsinussignal" hat, verarbeiten können.

> Das macht aber keinen Sinn, bzw bringt keinen Vorteil.
Langfristig nicht. Aber kurzfristig bekommt man nach Schema F das Ding 
schnell ans Laufen und kann sich das dann mal in Ruhe anschauen und auf 
Optimierungen abklopfen.
Und die nächste Kurvenform, die gefragt wird, ist dann sicher schon der 
Sinus... ?

von J. S. (engineer) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Mir ging es hier vorrangig darum, zu zeigen, dass man "feine" Auflösung
> nicht per binären Vorteiler macht.
Huch, da fällt mir eine Webseite ein, auf der eine DDS präsentiert wird, 
die einen solchen Vorteiler hat. Muss ich nochmal schauen, wo das war .. 
:-)

> Und die nächste Kurvenform, die gefragt wird, ist dann sicher schon der
> Sinus... ?
Das ist allerdings wahrscheinlich ja.

Und dann kommt wavetable synthesis, sowie die Frage nach 
formantenneutraler Überblendung. Und danach kommt WSOLA.

von Bucki E. (buckied)


Lesenswert?

Danke euch beiden!

Ich werde mir mal was zum Thema DDFS durchlesen! Für den Dreieck werde 
ich aber wohl den Ansatz des Counters erstmal weiter verfolgen, da ich 
bisher eine max. Frequenz von 40 kHz ausgeben möchte. (Es ist "nur" ein 
Projekt für ein Fach im Studium und mit Rechteck wäre die Note 
eigentlich schon gegessen, ich möchte aber gern die weiteren 
Möglichkeiten eines FPGA's in Hinsicht auf Signalerzeugung erkunden )

Und wie auch richtig erraten, soll Sinus als letzte Form auch noch 
implementiert werden. :-D Aber da hatte ich mich schon vorher etwas 
erkundigt und bin schon auf das Thema der LUT gestoßen. Demnach könnte 
ich ja ( da dieser auch "nur" bis 40kHz) das Dreieckkonstrukt verwenden 
und das signal "steps" nicht als Zähler an und für sich implementieren, 
sondern als Laufvariable für die LUT um dann den jeweiligen Wert 
auszugeben. Wie ihr seht wollte ich das erstmal etwas einfacher halten, 
da dieses Projekt auch mein erster Berührungspunkt mit FPGA's und VHDL 
ist. Man wächst ja an seinen Aufgaben. :)

Grüße Bucki

von J. S. (engineer) Benutzerseite


Lesenswert?

Bucki E. schrieb:

> Ich werde mir mal was zum Thema DDFS durchlesen!
> ich möchte aber gern die weiteren
> Möglichkeiten eines FPGA's in Hinsicht auf Signalerzeugung erkunden )
Es ist schon einigen gelungen mit FPGAs Signale zu erzeugen. Es gibt da 
ein paar Möglichkeiten :-)

Im Ernst: Das Thema wird hier seit 10 Jahren alle 3 Monate durchgekaut, 
bis in die letzten Fragestellungen:

Beitrag "Nicht-Sinus DDS"
Beitrag "DDS Grundlagenfrage"
Beitrag "Simpler VCO in VHDL"
Beitrag "Universell programmierbarer DDS-Funktionsgenerator"
Beitrag "DDS bis 100Mhz, Probleme mim Ausgangssignal"
Beitrag "Frequenzgenerator in VHDL"
Beitrag "DDS Interpolation";
Beitrag "DDS erster Versuch"
Beitrag "Sinustabelle mit 2 Geschwindigkeiten"
Beitrag "FPGA als digitaler Oszillator?"
Beitrag "Sinus per DDS, warum 2. Harmonische?"

: Bearbeitet durch User
von Bucki E. (buckied)


Lesenswert?

Danke Jürgen für die Verlinkungen!

Nach doch mal rantrauen an die DDS und einfach mal durchsimulieren ist 
das Ganze gar nicht mal so schwer und sogar recht verständlich.

Als Grundlage dafür habe ich den Code von Lothar Miller zu Rande 
gezogen. Etwas sehr spärlich kommentiert, aber nach der Simulation war 
soweit alles klar. Nun läuft zumindest in der Simulation das Dreieck 
(ohne LUT) und der Sinus (mit LUT) super durch. Bei ungünstigem 
Teilerverhältnis habe ich zwar noch bis zu 11 Hz Abweichung, aber das 
tut bei eingestellten 37,52kHz nicht mehr viel zur Sache, da das ganze 
"nur" ein Projekt für ein Modul im Studium ist.

Jetzt habe ich "nur noch" das Problem, dass beim Einbinden der Sinus LUT 
bei Altium Designer mir eine Fehlermeldung ausgespuckt wird, dass das 
Modul keine Last treiben würde und dadurch wegoptimiert wird. Hatte 
jemand jemals schonmal so eine Meldung bei sich? Laut Synthesetool und 
Simulation läuft eigentlich alles durch, nur den Bit File will er mir 
damit nicht generieren... kann es sein, dass der BRAM zu ungünstig auf 
dem Chip liegt?

Grüße
Bucki

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


Lesenswert?

Bucki E. schrieb:
> Als Grundlage dafür habe ich den Code von Lothar Miller zu Rande
> gezogen. Etwas sehr spärlich kommentiert
Das soll das Mitdenken anregen... ?

> dass beim Einbinden der Sinus LUT bei Altium Designer mir eine
> Fehlermeldung ausgespuckt wird, dass das Modul keine Last treiben würde
> und dadurch wegoptimiert wird
Kommt nur diese eine Meldung? Oder kommen vorher schon Warnungen, die 
sich auf diese Ecke beziehen? Und mit welchem Code genau? Und wie sieht 
die "Einbindung" aus?

von Bucki E. (buckied)


Lesenswert?

Also der Dreieck ohne die LUT läuft perfekt und sehr präzise.

Dieser sieht so aus:
1
entity Triangular_Wave_Generator is
2
    Port (  CLK       : in  std_logic;
3
            EN        : in std_logic;
4
            RST       : in std_logic;
5
            Freq_Data : in  std_logic_vector (19 downto 0);
6
            Dout      : out std_logic_vector (19 downto 2)
7
         );
8
end Triangular_Wave_Generator;
9
10
architecture Behavioral of Triangular_Wave_Generator is
11
12
   signal Result   : unsigned (6 downto 0); -- chosen Value for DAC output
13
   signal Phase_Accumulator    : unsigned (29 downto 0) := (others=>'0'); 
14
   signal Half_of_Wave : std_logic; -- left side of the halvwave or right side of the half wave
15
16
begin
17
   clocked_data : process (CLK)
18
   begin
19
     if rising_edge(CLK) then
20
        if RST = '0' then
21
           if EN = '1' then
22
               Phase_Accumulator <= Phase_Accumulator + unsigned(Freq_Data); -- for more information look for "DDS - Direct Digital Synthesis"
23
           end if;
24
        else
25
            Phase_Accumulator <= (29 => '1', others => '0');
26
        end if;
27
   end if;
28
   end process;
29
30
   Half_of_Wave <= Phase_Accumulator(Phase_Accumulator'left); -- look at MSB  --> if 1000 0000 ..... the half wave is reached --> calculate direction changes
31
             
32
   Result  <=    unsigned(Phase_Accumulator(Phase_Accumulator'high-1 downto Phase_Accumulator'high-7))  when (Half_of_Wave='0') else 
33
               127-unsigned(Phase_Accumulator(Phase_Accumulator'high-1 downto Phase_Accumulator'high-7));
34
                -- for example at the change of "Half_of_Wave" 0 to 1 Phase Accumulator equals 0111 1111 10...., so the 'high equals the MSB, that minus 1 to MSB - 7
35
                -- equals the part "111 1111" and is 127 in decimal --> so the last value of the Triangular
36
                -- for better understanding use ModelSim and simulate all values 
37
    
38
   Dout     <= b"000_0000_0000" & std_logic_vector(  Result); -- resize the vector for the 19 downto 2 User Header
39
end Behavioral;

Beim Sinus bekomme ich leider folgende zwei Meldungen:

"ERROR:PhysDesignRules:368 - the signal 
<U_sine_wave_generator/ram_255/clk> is incomplete. The signal is not 
driven by any source pin in your design."

"ERROR:PhysDesignRules:10 - the network 
<U_sine_wave_generator/ram_255/clk> is completly unrouted."
1
entity LUT_Driven is
2
    Port (  CLK       : in  std_logic;
3
            EN        : in std_logic;
4
            RST       : in std_logic;
5
            Freq_Data : in  std_logic_vector (18 downto 0);
6
            Dout      : out std_logic_vector (7 downto 0)
7
         );
8
end LUT_Driven;
9
10
architecture Behavioral of LUT_Driven is
11
 
12
    signal Result   : unsigned (7 downto 0); -- chosen Value for DAC output
13
    signal Phase_Accumulator    : unsigned (28 downto 0) := (others=>'0'); 
14
    signal Address  : integer range 0 to 63; -- address of the LUT
15
    signal LUTAddr : integer range 0 to 63;
16
    signal Half_of_Wave : std_logic; -- left side of the halvwave or right side of the half wave
17
    signal Pos_Neg_Wave  : std_logic; -- positive or negative halfwave
18
     
19
    type LUT64x7 is array (0 to 63) of unsigned (7 downto 0);
20
  
21
    constant LUT_Rom: LUT64x7 := (
22
    x"40", x"41", x"43", x"44", x"46", x"47", x"49", x"4B",
23
    x"4C", x"4E", x"4F", x"51", x"52", x"54", x"55", x"57",
24
    x"58", x"5A", x"5B", x"5C", x"5E", x"5F", x"61", x"62",
25
    x"63", x"65", x"66", x"67", x"68", x"6A", x"6B", x"6C",
26
    x"6D", x"6E", x"6F", x"70", x"71", x"72", x"73", x"74",
27
    x"75", x"76", x"76", x"77", x"78", x"79", x"79", x"7A",
28
    x"7B", x"7B", x"7C", x"7C", x"7D", x"7D", x"7D", x"7E",
29
    x"7E", x"7E", x"7F", x"7F", x"7F", x"7F", x"7F", x"7F");
30
  
31
begin
32
     
33
   clocked_data : process (CLK)
34
   begin
35
     if rising_edge(CLK) then 
36
        if RST <= '0' and EN <= '1' then                    
37
            LUTAddr <= Address; -- clocked adress for BRAM
38
            Phase_Accumulator <= Phase_Accumulator + unsigned(Freq_Data); -- for more information look for "DDS - Direct Digital Synthesis"
39
            Pos_Neg_Wave <= Phase_Accumulator(Phase_Accumulator'left); -- look at the MSB of Phase Accumulator, if 1000 0000 ... the halfwave is reached --> sign change                    
40
        else
41
            Phase_Accumulator <= (28 => '1', others => '0');
42
        end if;
43
     end if;
44
   end process;
45
46
   Result <= unsigned(LUT_Rom(LUTAddr)); -- look in the LUT for the actual DAC value
47
   Half_of_Wave <= Phase_Accumulator(Phase_Accumulator'left-1); -- look at MSB - 1 --> if 0100 0000 ..... the quarter wave is reached --> calculate direction changes
48
             
49
   Address  <=    to_integer(Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7))  when (Half_of_Wave='0') else 
50
               63-to_integer(Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7));
51
                -- for example at the change of "Half_of_Wave" 0 to 1 Phase Accumulator equals 0011 1111 01...., so the 'high equals the MSB, that minus 2 to MSB - 7
52
                -- equals the part "11 1111" and is 63 in decimal --> so the last Adress/value in the LUT
53
                -- for better understanding use ModelSim and simulate all values 
54
    
55
   Dout     <= std_logic_vector(  Result)   when (Pos_Neg_Wave='1') else  -- if pos wave the output equals the normal result else the inverted result
56
              std_logic_vector(127-Result);
57
end Behavioral;
Irgendwie funktioniert das Source-Code einbinden nicht richtig... 
vielleicht könnte das ein netter Mod wieder ordentlich einbinden. :)

Brüße
Bucki

: Bearbeitet durch Moderator
von Audiomann (Gast)


Lesenswert?

Bucki E. schrieb:

> <vhdl>
Du nimmst die falschen Klammern!

von Bucki E. (buckied)


Lesenswert?

Oh durchaus.. doof wenn man nicht lesen kann.. :D Aber hier steht auch 
Verschiedenstes auf den Seiten. ^^ Nur bei Augenmerk auf die 
Antworten-Schaltfläche und ich hätte das Richtige rausgefunden.. haha

Aber nochmal zum Problem: Heute hab ich es wieder versucht aber die 
Block RAM Methode funktioniert leider genausowenig wie das Array als 
Distributed RAM auszuführen. (Ähnlich dem Beispiel von Lothar Miller)

Leider komme ich erst am Mittwoch wieder an das Board, wenn bis dahin 
keiner einen eventuell guten Vorschlag für mich hätte werde ich es mal 
mit einer "direkten LUT" probieren. Habe zumindest gerade die VHDL mit 
einem "With select"-Statement umgeschrieben und auch dies erfolgreich 
Simuliert. Vielleicht mag er es eher als normale LUT eingebunden haben 
... nur werde ich sonst aus der Fehlermeldung nicht weiter schlau... :/

Grüße
Bucki

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


Lesenswert?

Bucki E. schrieb:
> Aber nochmal zum Problem
Das ist mit hoher Wahrscheinlichkeit in dieser Zeile:
1
        if RST <= '0' and EN <= '1' then
Sind da nicht zwei < zu viel? Was kommt bei einem "kleiner-gleich" 
Vergleich mit einem einzelnen std_logic heraus?
Offenbar kommt der Synthesizer zum Schluss, dass immer der else-Zweig 
aktiv ist und deshalb die ganze Takterei wegoptimiert werden kann.

von Rolf S. (audiorolf)


Lesenswert?

Aus der Beschreibung lese ich das aber nicht ab. Es müsste den Fall RST 
= 1 und EN = 1 schon geben.

Aber ist das überhaupt noch ein Vergleich? Weist er nicht einfach die 
Signale zu und legt RST auf 1, was dann andere Schaltungsteile 
wegoptimieren lässt?

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


Lesenswert?

Rolf S. schrieb:
> Aus der Beschreibung lese ich das aber nicht ab.
Ein Problem ist hier, dass wieder die Zeilen vor "entity" fehlen. 
Deshalb kann ich es auch nur vermuten. Aber in allen derartigen Fällen, 
die mir bisher untergekommen war das nicht gewollt und der Fehler.
Mir erscheint auch nicht sinnvoll, den neuwertigen std_logic irgendwie 
zu vergleichen. Wie soll denn 0 mit H oder X oder Z verglichen werden?

> Weist er nicht einfach die Signale zu
Niemals an dieser Stelle. Wir sind hier nicht bei C, wo man jederzeit 
irgendwas zuweisen kann, und deshalb für einen Vergleich einen eigenen 
Operator hat.

: Bearbeitet durch Moderator
von J. S. (engineer) Benutzerseite


Lesenswert?

Bucki E. schrieb:
> Phase_Accumulator <= (29 => '1', others => '0');

Du machst das zu komplziert. Z.B. das händische Umklappen des Signums 
mit dem Phasenakku ist vollkommen unnötig. Es reicht:

1) Akku = Akku + Frequenz   und dann
2) Wert = Akku - Range/2   bzw -Akku + 3* Range/2
mit dem höchsten Akku-bit als Entscheidung / Signum und dem Range/2 als 
Offset zur Verschiebung auf 0.

Du produzierst auch kein gutes Dreieck, weil einige Werte doppelt 
vorkommen. Der Lauf ist in etwa der 0,1,2 .... 126,127, 127, 126 ....

Besser bei den kleinen Werten ist 0,1, ....126,127     128,127,126 .... 
2,1  loop , d.h. der Rücklauf ist um 1 erhöht.

Bei großen Akku/Amplituden-Werten ist das aus Symmetriegründen besser, 
allerdings sollte dann der Phasenvektor um 1 erhöht aufgelöst gerechnet 
werden, wegen dem "0,5 - Problem". Dann kann man die Phasenwerte auch 
direkt auf Oberwellen umrechnen.

von J. S. (engineer) Benutzerseite


Angehängte Dateien:

Lesenswert?

Bucki E. schrieb:
> Aber nochmal zum Problem: Heute hab ich es wieder versucht aber die
> Block RAM Methode funktioniert leider genausowenig wie das Array als
> Distributed RAM auszuführen. (Ähnlich dem Beispiel von Lothar Miller)

Was soll daran nicht gehen? Die oberen Bits des Akkus sind die Adresse. 
Der Rest ist Phasendrehung und Amplitudendrehung für die 4 Fälle der 
90-Grad-Bereiche einer typischen Funktion.

Wenn das Dreieck dann irgendwann mal funzt, ist es an der Zeit, mehrere 
davon zu nehmen und zu einem Sinus zusammenzubauen.

 Man nehme die Fourieranalyse des Dreiecks und ziehe weitere Dreiecke 
mit entsprechender Frequenz so ab, dass sich die Oberwellen eliminieren.

Das Spektrum wäre also  d1:  1(f) - (3f)/9  + (5f)/25  - (7f)/49  + 
(9f)/81    ...   (15f)
und die erste Vielfache d3:       + (3f)/9                        - 
(9f)/81/9  ...   (15f) ... (21f)
die folgende zweite V.  d5:                 - (5f)/25 
(15f)               (25f)

d.h. man kann die nächsten Wellen mit ihren Fourieranteilen skalieren, 
um sie abzuziehen, muss aber aufpassen, was sie selber wieder an 
Oberwellen erzeugen und die mit den schon vorhandenen Verrechnen.

Mit der 7. Oberwelle bekommt man das Bild oben, das noch Knicke zeigt. 
Die rote Kurve ist der um Faktor 10 verstärkte Fehler zum Sinus. Sind 2% 
maximal. Mit der 15. Oberwelle erhalte ich einen Sinus besser, als 0,1%.

Man kann das Ganze weiter verbessern, wenn man mit verschobenen 
Dreiecken arbeitet. Dann entstehen andere Fourierkoeffizienten, die es 
erlauben mit weniger Operationen zu arbeiten, produzieren aber auch 
geradzahlige Komponenten. Diese sind musikalisch günstiger, weil sie in 
die Oktaven gehen. Daher arbeitete einer meiner ersten Synths mit 
parabolisch erzeugen Sinuswellen.

: Bearbeitet durch User
von Bucki E. (buckied)


Angehängte Dateien:

Lesenswert?

Danke nochmal für eure vielen Hinweise!

Das Problem hat sich aber glücklicherweise mit meiner Lösung 
verabschiedet. Anscheinend hat das Board/Altium Designer wirklich das 
Problem, dass es keinen freien BRAM mehr hatte (obwohl der Endreport was 
anderes sagte, noch 50% frei). Ich habe das Ganze nun mit dem 
with-select Statement realisiert wo die Software dies auch direkt als 
LUT erkannt hat.

Meine Lösung sieht nun Schlussendlich so aus:
1
entity Sin_Wave_Generator is
2
    Port (  CLK       : in  std_logic;
3
            EN        : in std_logic;
4
            RST       : in std_logic;
5
            Freq_Data : in  std_logic_vector (18 downto 0);
6
            Dout      : out std_logic_vector (19 downto 2)
7
         );
8
end Sin_Wave_Generator;
9
10
architecture Behavioral of Sin_Wave_Generator is
11
12
    signal Data : unsigned (7 downto 0);
13
    signal Address   : unsigned (7 downto 0); 
14
    signal Result   : unsigned (7 downto 0); -- chosen Value for DAC output
15
    signal Phase_Accumulator    : unsigned (28 downto 0) := (others=>'0');
16
    signal Quarter_Wave : std_logic; -- left side of the halvwave or right side of the half wave
17
    signal Half_of_Wave : std_logic;
18
    
19
begin
20
   clocked_data : process (CLK)
21
   begin
22
     if rising_edge(CLK) then
23
        if RST = '0' then
24
           if EN = '1' then
25
               Phase_Accumulator <= Phase_Accumulator + unsigned(Freq_Data); -- for more information look for "DDS - Direct Digital Synthesis"
26
           end if;
27
        else
28
            Phase_Accumulator <= (others => '0');
29
        end if;
30
   end if;
31
   end process;
32
33
        ------------------------------------------------------------------------------
34
        --                      LUT for Sine Gen                                    --
35
        ------------------------------------------------------------------------------
36
        
37
        with Address select Result <=
38
            x"2D" when x"00", x"2E" when x"01", x"2F" when x"02", x"30" when x"03",
39
            x"31" when x"04", x"32" when x"05", x"33" when x"06", x"34" when x"07",
40
            x"35" when x"08", x"36" when x"09", x"37" when x"0A", x"39" when x"0B",
41
            x"3A" when x"0C", x"3B" when x"0D", x"3C" when x"0E", x"3D" when x"0F",
42
            x"3E" when x"10", x"3F" when x"11", x"40" when x"12", x"41" when x"13",
43
            x"42" when x"14", x"43" when x"15", x"44" when x"16", x"45" when x"17",
44
            x"46" when x"18", x"46" when x"19", x"47" when x"1A", x"48" when x"1B",
45
            x"49" when x"1C", x"4A" when x"1D", x"4B" when x"1E", x"4C" when x"1F",
46
            x"4C" when x"20", x"4D" when x"21", x"4E" when x"22", x"4F" when x"23",
47
            x"4F" when x"24", x"50" when x"25", x"51" when x"26", x"51" when x"27",
48
            x"52" when x"28", x"52" when x"29", x"53" when x"2A", x"54" when x"2B",
49
            x"54" when x"2C", x"55" when x"2D", x"55" when x"2E", x"56" when x"2F",
50
            x"56" when x"30", x"56" when x"31", x"57" when x"32", x"57" when x"33",
51
            x"57" when x"34", x"58" when x"35", x"58" when x"36", x"58" when x"37",
52
            x"58" when x"38", x"59" when x"39", x"59" when x"3A", x"59" when x"3B",
53
            x"59" when x"3C", x"59" when x"3D", x"59" when x"3E", x"59" when x"3F",
54
            x"00" when others;
55
            
56
        -------------------------------------------------------------------------------
57
        
58
    Half_of_Wave <= Phase_Accumulator(Phase_Accumulator'high); -- look at MSB  --> if 1000 0000 ..... the half wave is reached --> calculate direction changes
59
    Quarter_Wave <= Phase_Accumulator(Phase_Accumulator'high-1); -- Quarter Wave            
60
              
61
    Address  <= b"00" & unsigned(Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7))  when (Quarter_Wave='0') else 
62
               63 - unsigned(b"00" & Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7));
63
                -- for example at the change of "Half_of_Wave" 0 to 1 Phase Accumulator equals 0111 1111 10...., so the 'high equals the MSB, that minus 1 to MSB - 7
64
                -- equals the part "111 1111" and is 127 in decimal --> so the last value of the Triangular
65
                -- for better understanding use ModelSim and simulate all values 
66
    Data <= Result when Half_of_Wave = '0' else 89 - Result;
67
68
    Dout     <= b"00_0000_0000" & std_logic_vector(Data); -- resize the vector for the 19 downto 2 User Header
69
    
70
end Behavioral;

Der Sinus sieht um den Nullpunkt nur relativ schlecht aus, da ich beim 
Conrad um die Ecke nur an 5% Widerstände ran kam... dient ja eher den 
Demonstrationszwecken fürs Modul.

Danke nochmal an alle, von mir aus kann der Thread gern geschlossen 
werden.

Grüße,
Bucki

von Victor (Gast)


Lesenswert?

Bucki E. schrieb:
> Anscheinend hat das Board/Altium Designer wirklich das
> Problem, dass es keinen freien BRAM mehr hatte

Du baust FPGA mit Altium Designer? Seit wann kann das VHDL-Code 
übersetzen?

Bucki E. schrieb:
> 50.000.000Hz/4.000Hz = 12500 CLK Ticks --> 12500 / 256 = 48,828.
Aussergewöhnliche Frequenz. Warum setzt die halbe Welt eigentlich diesen 
krummen Wert ein? Ist das ein neuer Standard?

Jürgen S. schrieb:
> Wenn das Dreieck dann irgendwann mal funzt, ist es an der Zeit, mehrere
> davon zu nehmen und zu einem Sinus zusammenzubauen.
Mit welcher Begründung soll man eine Sinusfunktion mit Dreiecken 
erzeugen wollen? Das bringt nur Fehler, die sich mit eine einfache 
Tabelle meiden lassen. Und warum so umständlich? Warum nicht einfach 
gerade Abschnitte?

von Bucki E. (buckied)


Lesenswert?

Hallo Victor!

Altium hat mal selbst Eval Boards verkauft, wir nutzen in der Hochschule 
das Altium NanoBoard 2. Und zumindest beim Altium Designer 14 und 16 
kann man damit auch VHDL Codes synthetisieren und co. Ob das Programm 
dazu ein externes Tool nutzt kann ich aber nicht sagen, das läuft im 
Hintergrund ab.

Und zur Frequenz, dass ist die vom Board zur Verfügung gestellte. Ich 
hätte natürlich auch einen CLK Divider von 5 nehmen können und hätte 
super Werte, dabei würde ich aber bei der Auflösung des Sinus etc 
eingeschränkt werden.

Grüße
Bucki

von J. S. (engineer) Benutzerseite


Lesenswert?

Bucki E. schrieb:
> Und zumindest beim Altium Designer 14 und 16
> kann man damit auch VHDL Codes synthetisieren und co.

Aktium ist der Nachfolger von Protel und da war schon in den 90ern die 
Entwicklung von PLDs gut ins Tool integriert, hieß "Protel Advanced 
PLD".

Man hat z.B. ein digitales Gatter platziert ohne vorab Rücksicht darauf 
zu nehmen, ob es in ein reales 7400er Gehäuse wandert oder in ein PLD. 
Ich fand das eigentlich ziemlich gelungen. Wenn Du das heute machen 
willst, suchst du bei anderen tools vergeblich. Bei Mentor z.B. kriegst 
du design-Fragmente nicht einfach so zwischen HDL-Designer und Board 
Architect hin und her geschoben.

von J. S. (engineer) Benutzerseite


Lesenswert?

Victor schrieb:
> Bucki E. schrieb:
>> 50.000.000Hz/4.000Hz = 12500 CLK Ticks --> 12500 / 256 = 48,828.
> Aussergewöhnliche Frequenz. Warum setzt die halbe Welt eigentlich diesen
> krummen Wert ein? Ist das ein neuer Standard?
Ich glaube, dass ist nur eine Vereinfachung. Vielleicht deshalb, weil 
viele heute mit der eigentlichen Digitaltechnik nicht mehr viel zu tun 
haben und es verlernt haben, ein bisschen trickreich zu denken :-)

Ich habe in wenigstens 10 verschiedenen Foren in den letzten Dekaden 
schon meine Lösung gepostet, die da lautet 29/59 und die aus den 
25MHz-Quarzen und ihren Freunden fast perfekte S/PDIF Frequenzen 
liefert. Ausgehend von den 192000Hz kriegt man alles, was man möchte. 
Bei FPGAs die Zwischenoszillatorfrequenzen von 1,5GHz verkraften, kann 
man mit 50Meg direkt 384kHz produzieren.


> Mit welcher Begründung soll man eine Sinusfunktion mit Dreiecken
> erzeugen wollen?

- Die Einteilung in eine ganzzahlige Anzahl von Abschnitten erzeugt 
musikalisch wertvolle Oberwellen auf den Oktaven

- Die Benutzung von Dreiecksfunktionen lässt es zu deren Phase zu 
verschieben und wandernde Oberwellenprofile zu generieren.

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.