Forum: FPGA, VHDL & Co. Sinus (real) für Testbench erzeugen


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Holger (Gast)


Lesenswert?

Hallo zusammen,

ich möchte gerne in einem Testbench ein analoges Sinussignal für ein mir 
gegebenes ADC Modell mit Datentyp REAL generieren.
1
use ieee.math_real.all;
2
...
3
input_gen : process
4
  variable v_grad : real := 0;
5
begin
6
  v_grad := v_grad + 0.001;
7
  if v_grad_multi = 360 then
8
    v_grad_multi = 0;
9
  end if;
10
  adc_in <= (1.5 * sin(math_pi * v_grad / 180.0));
11
end process;
Damit wollte ich mir ein Sinussignal mit Amplitude 1,5V (Vref des ADC) 
erzeugen, das sich der ADC dann absamplen kann, je nachdem wann der 
Start Befehl kommt.

Nun bin ich soweit und wollte anfangen zu simulieren. da fällt mir auf, 
dass ich ja noch rein gar keine Zeitbasis habe. In getakteten Systemen 
gibt die Zeitbasis die Taktperiode vor. Aber hier in diesem Prozess habe 
ich keinen Takt und auch noch keine Angabe, wie schnell und oft die 
Grad-Variable hochgezählt wird und mir damit meine Frequenz vorgibt.

Ich versuche zum ersten Mal auf diese Art und Weise zu simulieren, so 
dass mir die Grundbegriffe für diese sehr weit von der Hardware 
entfernte Simulation fehlen.

Ich wäre für Hinweise sehr dankbar!
Vielen Dank!
Holger

PS: Der nächste Schritt wäre dann den Sinus so weit parametrierbar zu 
machen, dass ich Amplitude, Frequenz usw. in einer Datei ablege und die 
vhdl-Testbench diese Datei dann ausliest und die Signalerzeugung 
entsprechend parametriert. So kann ich mir ein ständiges neues 
kompilieren des Projektes sparen und brauch nur die Datei ändern. Aber 
das ist erst der nächste Schritt....

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


Lesenswert?

Holger schrieb:
> da fällt mir auf, dass ich ja noch rein gar keine Zeitbasis habe
Nimm die Funktion now. Die gibt dir den aktuellen Simualtionszeitpunkt 
zurück. Diese Zeit geteilt durch z.B. 1ns ergibt einen Integer, der zum 
weiterrechnen verwendet werden kann...

Allerdings musst du schon sowas wie einen "Takt" einführen, sonst 
rechnet sich der Simulator zu Tode:
1
library ieee;
2
use ieee.STD_LOGIC_1164.all;
3
use ieee.NUMERIC_STD.all;
4
use ieee.MATH_REAL.all;  
5
6
entity Waves is
7
    Generic ( period : time     := 1 ms;
8
              width  : integer  := 8 
9
              );
10
    Port    ( D   : out std_logic_vector(width-1 downto 0);
11
              clk : in  std_logic
12
              );
13
end Waves;
14
15
architecture Sine of Waves is --> ok
16
begin
17
   process (clk)
18
   variable x, s : real;
19
   variable tact, tper : real;
20
   begin
21
     tper := real(period/1 ns);
22
     tact := real(NOW/1 ns);
23
     x := tact/tper;
24
     s := sin(2.0*MATH_PI*X);
25
     D <= std_logic_vector(to_signed(integer(s*(2**real(width)/2.0-1.0)),width));
26
   end process;
27
end Sine;
28
29
architecture Sine of Waves is -- nanosec --> ok
30
begin
31
   process (clk)
32
   begin
33
     D <= std_logic_vector(to_signed(integer(sin(2.0*MATH_PI*real(NOW/1 ns)/real(period/1 ns))*(2**real(width)/2.0-1.0)),width));
34
   end process;
35
end Sine;
36
37
architecture Sine of Waves is -- picosec --> ok
38
begin
39
   process (clk)
40
   begin
41
     D <= std_logic_vector(to_signed(integer(sin(2.0*MATH_PI*real(NOW/1 ps)/real(period/1 ps))*(2**real(width)/2.0-1.0)),width));
42
   end process;
43
end Sine;

Das mit dem Takt kannst du natürlich auch einfach so machen:
1
 : 
2
 :
3
architecture Sine of Waves is -- nanosec --> ok
4
begin
5
   process begin
6
     wait for 10 ns; -- "Pseudotakt"
7
     D <= std_logic_vector(to_signed(integer(sin(2.0*MATH_PI*real(NOW/1 ns)/real(period/1 ns))*(2**real(width)/2.0-1.0)),width));
8
   end process;
9
end Sine;

von Andi (Gast)


Lesenswert?

wäre es nicht am sinnvollsten, einfach die Simulatorauflösung als "Takt" 
zu nehmen? Genauer geht es nicht und krumme Werte führen zur 
Interferenz, nehme ich an.

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


Lesenswert?

Jede (virtuelle) ps den Sinus berechnen, auch wenn der evtl. nur 1 kHz 
hat? Viel Spass beim Warten. Es geht doch ganz ohne Takt, denn du wirst 
auch im echten Leben keinen "synchronen" Sinus sehen...

von Holger (Gast)


Lesenswert?

Vielen Dank Lothar!
Der Kniff mit NOW ist ideal, auch für andere Zwecke!

Meine Lösung:
1
entity sin_generator is
2
  generic (VREF : real := 1.55);
3
  port (
4
    ADC_IN   : out real
5
    );
6
end sin_generator;
7
...
8
process 
9
     variable period : time     := 100 us;
10
     variable resolution: time  := 1 ns;
11
   begin
12
     wait for resolution;
13
     ADC_IN <= VREF * sin(2.0 * MATH_PI * real(NOW/resolution)/real(period/resolution));
14
   end process;

Vielen Dank!

von just Now (Gast)


Lesenswert?

Leider begrenzt NOW die Simulationszeit.

Stell einfach mal resolution auf 1 ms und simulier. Nach 8 s stürzt die 
Simulation ab.

Also nicht später mal wundern.

von Holger (Gast)


Lesenswert?

just Now schrieb:
> Stell einfach mal resolution auf 1 ms und simulier. Nach 8 s stürzt die
> Simulation ab.
Kann ich so nicht bestötigen, habe gerade mal 16s simuliert und alles 
läuft noch... die Grenze scheint also irgendwo weiter oben zu liegen :)

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.