Forum: FPGA, VHDL & Co. Simulation digitaler Rauschgenerator


von Dominik (Gast)


Lesenswert?

Hallo zusammen,

vor kurzem bin ich auf den Artikel "Digitaler Rauschgenerator im FPGA" 
von J.S. gestoßen:
https://www.mikrocontroller.net/articles/Digitaler_Rauschgenerator_im_FPGA
und wollten den vorgestellten Realisationsvorschlag umsetzen. Das RTL 
Schematic sieht so aus, wie ich es mir vorstelle. Leider habe ich aber 
bei der Simulation Probleme. Ich vermute eine "Functional Simulation" 
kann hier gar nicht funktionieren. Die "Post-Synthesis Timing 
Simulation" läuft so, wie ich es erwarte. Aber auch die 
"Post-Implementation Timing Simulation" wirft einen Fehler (fatal 
run-time error). Weiß jemand woran das liegen kann bzw. ob es an 
irgendwelchen Simulationseinstellungen liegt? Ich dachte eigentlich, 
dass gerade diese Simulation die realistischsten Ergebnisse liefern 
würde und wundere mich, warum es nicht geht. Ich verwende Vivado 2016.4 
mit einem Artix-7 (XC7A15T).

Vielen Dank bereits im Voraus für alle Tipps und Kommentare!

von Mirko (Gast)


Lesenswert?

Welchen der Vorschläge hast du umgesetzt? Diese Seite zeigt mehrere. 
Poste am Besten dein RTL oder den Code. Womit hast du es simuliert? Bei 
der Simulation von Rückkoppelungen muss an irgendeiner Stelle eine 
Zeitverzögerung eingebaut werden, damit es klappt.

von Dominik (Gast)


Lesenswert?

Vielen Dank für die Antwort!

Ich habe (versucht) den Realisationsvorschlag aus der Grafik in der 
Mitte der Seite umgesetzt (umzusetzen).

Eine Verzögerung für die Simulation habe ich nicht eingebaut. Das könnte 
es also schon sein... Würde hier etwas wie "wait for xxx ns" in der 
Inverterkette reichen?

Hier noch mein Code (um einen Fehler bei der Nutzung einer als Generic 
übergebenen Anzahl an Invertern auszuschließen, habe ich die Anzahl der 
Inverter hier noch fix umgesetzt):
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
entity noise_bit_gen is
5
  Generic (  n_invChain_osc1 : integer := 8; 
6
        n_invChain_osc2 : integer := 12); 
7
    Port (   rst : in std_logic; 
8
        output : out std_logic);
9
end noise_bit_gen;
10
11
-- Quelle: 
12
-- https://www.mikrocontroller.net/articles/Digitaler_Rauschgenerator_im_FPGA
13
14
architecture Behavioral of noise_bit_gen is
15
  
16
  constant k1 : integer := 13; 
17
  constant k2 : integer := 27; 
18
  
19
  constant n_invChain_secondBlock : integer := 4; 
20
  
21
  signal cnt1 : integer range 0 to k1 := 0; 
22
  signal cnt2 : integer range 0 to k2 := 0; 
23
  
24
  signal invChain_osc1 : std_logic_vector(n_invChain_osc1 - 1 downto 0) := (others => '0'); 
25
  signal invChain_osc2 : std_logic_vector(n_invChain_osc2 - 1 downto 0) := (others => '0'); 
26
  
27
  signal invChain_secondBlock_1 : std_logic_vector(n_invChain_secondBlock - 1 downto 0) := (others => '0'); 
28
  signal invChain_secondBlock_2 : std_logic_vector(n_invChain_secondBlock - 1 downto 0) := (others => '0'); 
29
  
30
  signal mux1_out : std_logic := '0'; 
31
  signal mux2_out : std_logic := '0'; 
32
  
33
  signal short_feedback_osc1 : std_logic := '0'; 
34
  signal short_feedback_osc2 : std_logic := '0'; 
35
  
36
  
37
  attribute dont_touch : string;
38
  attribute dont_touch of cnt1 : signal is "true";
39
  attribute dont_touch of cnt2 : signal is "true";
40
  attribute dont_touch of invChain_osc1 : signal is "true";
41
  attribute dont_touch of invChain_osc2 : signal is "true";
42
  attribute dont_touch of invChain_secondBlock_1 : signal is "true";
43
  attribute dont_touch of invChain_secondBlock_2 : signal is "true";
44
  attribute dont_touch of mux1_out : signal is "true";
45
  attribute dont_touch of mux2_out : signal is "true";
46
  attribute dont_touch of short_feedback_osc1 : signal is "true";
47
  attribute dont_touch of short_feedback_osc2 : signal is "true";
48
  
49
  
50
begin
51
52
  ----------------------------------------------------------------------------
53
  -- OSC 1 
54
  
55
  -- inverter chain OSC1
56
  invChain_osc1(0) <= not(mux2_out) when (rst = '0') else '0'; 
57
  invChain_osc1(1) <= not(invChain_osc1(0)) when (rst = '0') else '0'; 
58
  invChain_osc1(2) <= not(invChain_osc1(1)) when (rst = '0') else '0'; 
59
  invChain_osc1(3) <= not(invChain_osc1(2)) when (rst = '0') else '0'; 
60
  invChain_osc1(4) <= not(invChain_osc1(3)) when (rst = '0') else '0'; 
61
  invChain_osc1(5) <= not(invChain_osc1(4)) when (rst = '0') else '0'; 
62
  invChain_osc1(6) <= not(invChain_osc1(5)) when (rst = '0') else '0'; 
63
  invChain_osc1(7) <= not(invChain_osc1(6)) when (rst = '0') else '0'; 
64
  
65
  -- signle inverter
66
  short_feedback_osc1 <= not(invChain_osc1(invChain_osc1'left)) when (rst = '0') else '0'; 
67
  
68
  -- inverter chain OSC1 second block 
69
  invChain_secondBlock_1(0) <= not(short_feedback_osc1) when (rst = '0') else '0'; 
70
  invChain_secondBlock_1(1) <= not(invChain_secondBlock_1(0)) when (rst = '0') else '0'; 
71
  invChain_secondBlock_1(2) <= not(invChain_secondBlock_1(1)) when (rst = '0') else '0'; 
72
  invChain_secondBlock_1(3) <= not(invChain_secondBlock_1(2)) when (rst = '0') else '0'; 
73
  
74
  -- counter for OSC1 
75
  process 
76
  begin 
77
    wait until rising_edge(invChain_osc1(invChain_osc1'left)); 
78
    if cnt1 < k1 then 
79
      cnt1 <= cnt1 + 1; 
80
    else 
81
      cnt1 <= 0; 
82
    end if; 
83
  end process; 
84
  
85
  -- comparator and multiplexer 
86
  mux1_out <= short_feedback_osc1 when (cnt1 < (k1/2)) else
87
        invChain_secondBlock_1(3); 
88
  
89
  ----------------------------------------------------------------------------
90
  ----------------------------------------------------------------------------
91
  
92
  
93
  ----------------------------------------------------------------------------
94
  -- OSC 2 
95
  
96
  -- inverter chain OSC1
97
  invChain_osc2(0) <= not(mux1_out) when (rst = '0') else '0';
98
  invChain_osc2(1) <= not(invChain_osc2(0)) when (rst = '0') else '0'; 
99
  invChain_osc2(2) <= not(invChain_osc2(1)) when (rst = '0') else '0'; 
100
  invChain_osc2(3) <= not(invChain_osc2(2)) when (rst = '0') else '0'; 
101
  invChain_osc2(4) <= not(invChain_osc2(3)) when (rst = '0') else '0'; 
102
  invChain_osc2(5) <= not(invChain_osc2(4)) when (rst = '0') else '0'; 
103
  invChain_osc2(6) <= not(invChain_osc2(5)) when (rst = '0') else '0'; 
104
  invChain_osc2(7) <= not(invChain_osc2(6)) when (rst = '0') else '0'; 
105
  invChain_osc2(8) <= not(invChain_osc2(7)) when (rst = '0') else '0'; 
106
  invChain_osc2(9) <= not(invChain_osc2(8)) when (rst = '0') else '0'; 
107
  invChain_osc2(10) <= not(invChain_osc2(9)) when (rst = '0') else '0'; 
108
  invChain_osc2(11) <= not(invChain_osc2(10)) when (rst = '0') else '0'; 
109
  
110
  -- signle inverter
111
  short_feedback_osc2 <= not(invChain_osc2(invChain_osc2'left)) when (rst = '0') else '0'; 
112
  
113
  -- inverter chain OSC1 second block 
114
  invChain_secondBlock_2(0) <= not(short_feedback_osc2) when (rst = '0') else '0'; 
115
  invChain_secondBlock_2(1) <= not(invChain_secondBlock_2(0)) when (rst = '0') else '0'; 
116
  invChain_secondBlock_2(2) <= not(invChain_secondBlock_2(1)) when (rst = '0') else '0'; 
117
  invChain_secondBlock_2(3) <= not(invChain_secondBlock_2(2)) when (rst = '0') else '0'; 
118
  
119
  -- counter for OSC1 
120
  process 
121
  begin 
122
    wait until rising_edge(invChain_osc2(invChain_osc2'left)); 
123
    if cnt2 < k2 then 
124
      cnt2 <= cnt2 + 1; 
125
    else 
126
      cnt2 <= 0; 
127
    end if; 
128
  end process; 
129
  
130
  -- comparator and multiplexer 
131
  mux2_out <= short_feedback_osc2 when (cnt2 < (k2/2)) else
132
        invChain_secondBlock_2(3); 
133
134
  ----------------------------------------------------------------------------
135
  ----------------------------------------------------------------------------
136
  
137
  
138
  ----------------------------------------------------------------------------
139
  -- output 
140
  
141
  output <= invChain_osc1(invChain_osc1'left) XOR invChain_osc2(invChain_osc2'left); 
142
  
143
  ----------------------------------------------------------------------------
144
  ----------------------------------------------------------------------------
145
  
146
end Behavioral;

von J. S. (engineer) Benutzerseite


Lesenswert?

Man soll nicht alles ungeprüft nachbauen, was andere empfehlen :-)

Nee, also die Schaltung funktioniert schon. Am Wochenende kann ich was 
posten, wenn du möchtest. Was ich auf den ersten Blick sehe: Soweit ist 
es richtig umgesetzt. Anders ist nur:

- Ich habe zu den "don't touch" noch "keep" kommandiert.

- Wichtig scheint mir der Verzicht auf eine Initialisierung, weil sich 
die ja mit dem Syntheseergebnis beißt

- Auch habe ich nur ein Bit resettet und zwar jeweils das, welches 
anhand der MUX rückkoppelt.

- Etwas aufpassen muss man mit der Weiterverwendung der toggelnden LUTs 
als Takt: Da muss ein Buffer dazwischen gesetzt werden. War jedenfalls 
bei der Xilinx Version in der ISE so. Werde das am WE mal ins Vivado 
importieren.

- Ich meine es in einer späteren Version so gemacht zu haben, dass das 
toogle-Bit mit einem regulären Takt einsynchronisiert wird und zweifach 
verzögert interpretiert wird. Bei Flankenwechsel wird der jeweilige MUX 
umgeschaltet, der die Inverterketten verkürzt.

- verodert werden dann auch die einsynchronisierten Bits

- ich habe in der finalen Version 3 Generatoren benutzt

von Dominik (Gast)


Lesenswert?

Hallo Jürgen,

vielen Dank für deine Antwort und die ganzen Tipps!! Ich versuche es 
gleich anzupassen!
Arbeit am Wochenende musst du dir wegen mir wirklich nicht machen. Ich 
fand den Beitrag sehr interessant, will es aber derzeit nur als 
Spielerei nutzen und um meine VHDL Kenntnisse etwas zu erweitern.

von J. S. (engineer) Benutzerseite



Lesenswert?

Anbei die Timing Simulation von Vivado (post P&R) und ModelSIM 
(logisch).

Um die logische Simulation ins Laufen zu bekommen, kann man 
"after"-Konstrukte einsetzen. Das unterbricht den unweigerlichen Loop.

In beiden Simulationen bekommt man nichts Reales, weil die Einflüsse, 
die man ja haben möchte, fehlen. Man kann aber prüfen, ob es prinzipiell 
geht. Am Besten ist noch die post P&R bei Vivado.

Insgesamt ist das Rauschen eben recht zufällig, d.h. eben auch zufällig 
schlecht mit seher ungleich verteilten Spektren. Wie im Artikel schon 
angedeutet, spielt da auch der Rest des designs im FPGA eine Rolle, z.B: 
was das an Strom zieht und wie.

Sauberes Rauschen geht besser deterministisch, siehe Klangbeispiel:
Beitrag "Re: Farbiges Rauschen im FPGA - the coloured noise generator"

von Dominik (Gast)


Lesenswert?

Hallo Jürgen,

vielen Dank für die Datei und deine Bemühungen! Und wieder mal habe ich 
viel dazugelernt!!

von Andi (chefdesigner)


Lesenswert?

Jürgen S. schrieb:
> In beiden Simulationen bekommt man nichts Reales,
und damit stellt sich die Frage, was es denn dann bringt. Entweder, man 
kann das Verhalten einer Schaltung vorhersagen, oder nicht. Schaltungen 
deren Verhalten nicht durch Simulation vorhersagbar sind, lassen sich 
auch nicht sicher einsetzen, oder?

von Gustl B. (-gb-)


Lesenswert?

Rauschen will man für manche Anwendungen nicht vorhersagen können.

von J. S. (engineer) Benutzerseite


Lesenswert?

Gustl B. schrieb:
> Rauschen will man für manche Anwendungen nicht vorhersagen können.
Das ist auffallend richtig und aus dem Grund kann ich mit der mangelnden 
Simulationsfähigkeit meines RGs prima leben. :-)

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.