mikrocontroller.net

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


Autor: Bucki E. (buckied)
Datum:

Bewertung
0 lesenswert
nicht 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

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Triangular_Wave_Generator is
    Port ( Data_In_Triangular : in  STD_LOGIC_VECTOR (24 downto 0);
           Data_Pin_Out : out  STD_LOGIC_VECTOR (19 downto 2);
           Enable_Triangular : in  STD_LOGIC;
           RST_Triangular : in  STD_LOGIC;
           CLK : in  STD_LOGIC);
end Triangular_Wave_Generator;

architecture Behavioral of Triangular_Wave_Generator is

  type Counter_State is (cnt_up, cnt_down);    -- use of a state machine for the counter to implement a Duty Cycle
   signal pr_state : Counter_State := cnt_up;  -- initialisation with state counter_on (means the high time of the sqaure wave)
   signal nx_state : Counter_State;
  signal state : std_logic := '0';
  signal steps : unsigned (19 downto 2) := (others => '0'); 
   signal cnt : unsigned (24 downto 0) := (others => '0');

begin

  cnt_proc : process(CLK, RST_Triangular, Enable_Triangular) -- send the frequency divided by 255 to generate the right triangular wave form
  begin
    if rising_edge(CLK) then
      if (RST_Triangular = '1' or Enable_Triangular = '0') then  --resetting the counter and the state
        cnt <= (others => '0');
        state <= '0';
         else
        if cnt < unsigned(Data_In_Triangular)-1 then
          cnt <= cnt + 1;
          state <= '0';
        else
          cnt <= (others => '0');
          state <= '1';
        end if;
      end if;
    end if;  
  end process cnt_proc;

  state_process: process(CLK, RST_Triangular, Enable_Triangular)
    begin
    
        if rising_edge(CLK) then
            if (RST_Triangular = '1' or Enable_Triangular = '0') then
                pr_state <= cnt_up;
                nx_state <= cnt_down;
           steps <= (others => '0');
            else
                if Enable_Triangular = '1' then
                    pr_state <= nx_state;
              
              if state = '1' then  
                case pr_state is
                  when cnt_up =>
                            if (steps < 126) then -- 7-bit r2r-dac
                                steps <= steps + 1;
                            else
                      steps <= "000000000001111111";
                                nx_state <= cnt_down;
                            end if;
                  when cnt_down =>
                            if (steps > 1) then
                                steps <= steps - 1;
                            else
                      steps <= (others => '0');
                                nx_state <= cnt_up;
                            end if;                    
                end case;
              end if;
                end if;  
            end if;      
        end if;

        Data_Pin_Out <= std_logic_vector(steps);
    end process state_process;

end Behavioral;


: Bearbeitet durch Moderator
Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bucki E. schrieb:
> immer Abweichung von 100Hz ode mehr

Bei welcher nominellen Frequenz?

Autor: Bucki E. (buckied)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Jürgen S. (engineer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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"

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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... 😉

Autor: Jürgen S. (engineer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bucki E. (buckied)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jürgen S. (engineer) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht 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
Autor: Bucki E. (buckied)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Bucki E. (buckied)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also der Dreieck ohne die LUT läuft perfekt und sehr präzise.

Dieser sieht so aus:
entity Triangular_Wave_Generator is
    Port (  CLK       : in  std_logic;
            EN        : in std_logic;
            RST       : in std_logic;
            Freq_Data : in  std_logic_vector (19 downto 0);
            Dout      : out std_logic_vector (19 downto 2)
         );
end Triangular_Wave_Generator;

architecture Behavioral of Triangular_Wave_Generator is

   signal Result   : unsigned (6 downto 0); -- chosen Value for DAC output
   signal Phase_Accumulator    : unsigned (29 downto 0) := (others=>'0'); 
   signal Half_of_Wave : std_logic; -- left side of the halvwave or right side of the half wave

begin
   clocked_data : process (CLK)
   begin
     if rising_edge(CLK) then
        if RST = '0' then
           if EN = '1' then
               Phase_Accumulator <= Phase_Accumulator + unsigned(Freq_Data); -- for more information look for "DDS - Direct Digital Synthesis"
           end if;
        else
            Phase_Accumulator <= (29 => '1', others => '0');
        end if;
   end if;
   end process;

   Half_of_Wave <= Phase_Accumulator(Phase_Accumulator'left); -- look at MSB  --> if 1000 0000 ..... the half wave is reached --> calculate direction changes
             
   Result  <=    unsigned(Phase_Accumulator(Phase_Accumulator'high-1 downto Phase_Accumulator'high-7))  when (Half_of_Wave='0') else 
               127-unsigned(Phase_Accumulator(Phase_Accumulator'high-1 downto Phase_Accumulator'high-7));
                -- 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
                -- equals the part "111 1111" and is 127 in decimal --> so the last value of the Triangular
                -- for better understanding use ModelSim and simulate all values 
    
   Dout     <= b"000_0000_0000" & std_logic_vector(  Result); -- resize the vector for the 19 downto 2 User Header
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."
entity LUT_Driven is
    Port (  CLK       : in  std_logic;
            EN        : in std_logic;
            RST       : in std_logic;
            Freq_Data : in  std_logic_vector (18 downto 0);
            Dout      : out std_logic_vector (7 downto 0)
         );
end LUT_Driven;

architecture Behavioral of LUT_Driven is
 
    signal Result   : unsigned (7 downto 0); -- chosen Value for DAC output
    signal Phase_Accumulator    : unsigned (28 downto 0) := (others=>'0'); 
    signal Address  : integer range 0 to 63; -- address of the LUT
    signal LUTAddr : integer range 0 to 63;
    signal Half_of_Wave : std_logic; -- left side of the halvwave or right side of the half wave
    signal Pos_Neg_Wave  : std_logic; -- positive or negative halfwave
     
    type LUT64x7 is array (0 to 63) of unsigned (7 downto 0);
  
    constant LUT_Rom: LUT64x7 := (
    x"40", x"41", x"43", x"44", x"46", x"47", x"49", x"4B",
    x"4C", x"4E", x"4F", x"51", x"52", x"54", x"55", x"57",
    x"58", x"5A", x"5B", x"5C", x"5E", x"5F", x"61", x"62",
    x"63", x"65", x"66", x"67", x"68", x"6A", x"6B", x"6C",
    x"6D", x"6E", x"6F", x"70", x"71", x"72", x"73", x"74",
    x"75", x"76", x"76", x"77", x"78", x"79", x"79", x"7A",
    x"7B", x"7B", x"7C", x"7C", x"7D", x"7D", x"7D", x"7E",
    x"7E", x"7E", x"7F", x"7F", x"7F", x"7F", x"7F", x"7F");
  
begin
     
   clocked_data : process (CLK)
   begin
     if rising_edge(CLK) then 
        if RST <= '0' and EN <= '1' then                    
            LUTAddr <= Address; -- clocked adress for BRAM
            Phase_Accumulator <= Phase_Accumulator + unsigned(Freq_Data); -- for more information look for "DDS - Direct Digital Synthesis"
            Pos_Neg_Wave <= Phase_Accumulator(Phase_Accumulator'left); -- look at the MSB of Phase Accumulator, if 1000 0000 ... the halfwave is reached --> sign change                    
        else
            Phase_Accumulator <= (28 => '1', others => '0');
        end if;
     end if;
   end process;

   Result <= unsigned(LUT_Rom(LUTAddr)); -- look in the LUT for the actual DAC value
   Half_of_Wave <= Phase_Accumulator(Phase_Accumulator'left-1); -- look at MSB - 1 --> if 0100 0000 ..... the quarter wave is reached --> calculate direction changes
             
   Address  <=    to_integer(Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7))  when (Half_of_Wave='0') else 
               63-to_integer(Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7));
                -- 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
                -- equals the part "11 1111" and is 63 in decimal --> so the last Adress/value in the LUT
                -- for better understanding use ModelSim and simulate all values 
    
   Dout     <= std_logic_vector(  Result)   when (Pos_Neg_Wave='1') else  -- if pos wave the output equals the normal result else the inverted result
              std_logic_vector(127-Result);
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
Autor: Audiomann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bucki E. schrieb:

> <vhdl>
Du nimmst die falschen Klammern!

Autor: Bucki E. (buckied)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bucki E. schrieb:
> Aber nochmal zum Problem
Das ist mit hoher Wahrscheinlichkeit in dieser Zeile:
        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.

Autor: Rolf S. (audiorolf)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Jürgen S. (engineer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen S. (engineer) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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
Autor: Bucki E. (buckied)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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:
entity Sin_Wave_Generator is
    Port (  CLK       : in  std_logic;
            EN        : in std_logic;
            RST       : in std_logic;
            Freq_Data : in  std_logic_vector (18 downto 0);
            Dout      : out std_logic_vector (19 downto 2)
         );
end Sin_Wave_Generator;

architecture Behavioral of Sin_Wave_Generator is

    signal Data : unsigned (7 downto 0);
    signal Address   : unsigned (7 downto 0); 
    signal Result   : unsigned (7 downto 0); -- chosen Value for DAC output
    signal Phase_Accumulator    : unsigned (28 downto 0) := (others=>'0');
    signal Quarter_Wave : std_logic; -- left side of the halvwave or right side of the half wave
    signal Half_of_Wave : std_logic;
    
begin
   clocked_data : process (CLK)
   begin
     if rising_edge(CLK) then
        if RST = '0' then
           if EN = '1' then
               Phase_Accumulator <= Phase_Accumulator + unsigned(Freq_Data); -- for more information look for "DDS - Direct Digital Synthesis"
           end if;
        else
            Phase_Accumulator <= (others => '0');
        end if;
   end if;
   end process;

        ------------------------------------------------------------------------------
        --                      LUT for Sine Gen                                    --
        ------------------------------------------------------------------------------
        
        with Address select Result <=
            x"2D" when x"00", x"2E" when x"01", x"2F" when x"02", x"30" when x"03",
            x"31" when x"04", x"32" when x"05", x"33" when x"06", x"34" when x"07",
            x"35" when x"08", x"36" when x"09", x"37" when x"0A", x"39" when x"0B",
            x"3A" when x"0C", x"3B" when x"0D", x"3C" when x"0E", x"3D" when x"0F",
            x"3E" when x"10", x"3F" when x"11", x"40" when x"12", x"41" when x"13",
            x"42" when x"14", x"43" when x"15", x"44" when x"16", x"45" when x"17",
            x"46" when x"18", x"46" when x"19", x"47" when x"1A", x"48" when x"1B",
            x"49" when x"1C", x"4A" when x"1D", x"4B" when x"1E", x"4C" when x"1F",
            x"4C" when x"20", x"4D" when x"21", x"4E" when x"22", x"4F" when x"23",
            x"4F" when x"24", x"50" when x"25", x"51" when x"26", x"51" when x"27",
            x"52" when x"28", x"52" when x"29", x"53" when x"2A", x"54" when x"2B",
            x"54" when x"2C", x"55" when x"2D", x"55" when x"2E", x"56" when x"2F",
            x"56" when x"30", x"56" when x"31", x"57" when x"32", x"57" when x"33",
            x"57" when x"34", x"58" when x"35", x"58" when x"36", x"58" when x"37",
            x"58" when x"38", x"59" when x"39", x"59" when x"3A", x"59" when x"3B",
            x"59" when x"3C", x"59" when x"3D", x"59" when x"3E", x"59" when x"3F",
            x"00" when others;
            
        -------------------------------------------------------------------------------
        
    Half_of_Wave <= Phase_Accumulator(Phase_Accumulator'high); -- look at MSB  --> if 1000 0000 ..... the half wave is reached --> calculate direction changes
    Quarter_Wave <= Phase_Accumulator(Phase_Accumulator'high-1); -- Quarter Wave            
              
    Address  <= b"00" & unsigned(Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7))  when (Quarter_Wave='0') else 
               63 - unsigned(b"00" & Phase_Accumulator(Phase_Accumulator'high-2 downto Phase_Accumulator'high-7));
                -- 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
                -- equals the part "111 1111" and is 127 in decimal --> so the last value of the Triangular
                -- for better understanding use ModelSim and simulate all values 
    Data <= Result when Half_of_Wave = '0' else 89 - Result;

    Dout     <= b"00_0000_0000" & std_logic_vector(Data); -- resize the vector for the 19 downto 2 User Header
    
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

Autor: Victor (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Bucki E. (buckied)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jürgen S. (engineer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen S. (engineer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.