Generar Onda Senoidal en FPGA

#1
Hola a todos!

Estoy trabajando en un proyecto con FPGA, necesito basicamente saber como puedo generar una señal senoidal de 50 Hz y tambien señales triangulares, esto es para hacer modulacion PWM. He visto que se puede hacer mediante look up table o mediante programacion de un algoritmo CORDIC, pero no me queda claro como implementarlo en la FPGA.

Ojala me puedan ayudar

Saludos

Edgardo
 
#3
Muchas Gracias Elvic

La pagina es muy buena, ahora mismo la estoy viendo, en caso de resultarme mis simulaciones, lo posteo acá...

Saludos

 
#5
saludos jaeq

Originalmente el código que aparece en el link es solamente para generar la onda sinusoidal.
EL pin "SEL"( de seleccionar), se agrego, puesto el código debería también generar la onda triangular, por esa razón fue ese pin

sin embargo la salida "wave_out" debe aparecer pues es de hay donde se toman los datos.


suerte
 
#7
saludos

en el archivo (sine_package) que se debe adjuntar a la compilación, hay una lista de valores (table_value) que formara la onda sinusoidal; esa misma tabla se modifica y se ponen los números correspondiente para generar la onda triangular.

por ejemplo este es parte de la tabla de datos paar generar la onda sinusoidal

Código:
case table_index is
      when 0 =>
        table_value := 1;
      when 1 =>
        table_value := 2;
      when 2 =>
        table_value := 4;
      when 3 =>
        table_value := 5;
      when 4 =>
        table_value := 7;
      when 5 =>
        table_value := 9;
      when 6 =>
        table_value := 10;
      when 7 =>
        table_value := 12;
la siguiente seria la tabla modificada para generar la triangular
Código:
 case table_index is
      when 0 =>
        table_value := 1;
      when 1 =>
        table_value := 1;
      when 2 =>
        table_value := 2;
      when 3 =>
        table_value := 3;
      when 4 =>
        table_value := 4;
      when 5 =>
        table_value := 5;
      when 6 =>
        table_value := 6;
      when 7 =>
        table_value := 7;
o podrias usar la misma variable "table_index" para de hay tomar los valores para la onda triangular

suerT
 
#9
Hola, saludos a todos.. yo soy nuevo en el lenguaje VHDL y tambien en la programacion de FPGA's, aun no puedo obtener la forma de onda que aparece en la imagen de ELVIC, estoy simulando con ModelSim SE PLUS 6.5 .. espero me puedan ayudar..

kristoft dijo:
Hola, saludos a todos.. yo soy nuevo en el lenguaje VHDL y tambien en la programacion de FPGA's, aun no puedo obtener la forma de onda que aparece en la imagen de ELVIC, estoy simulando con ModelSim SE PLUS 6.5 .. espero me puedan ayudar..
Hola Elvic, intente una vez mas con el programa model sim y pude obtener la onda senoidal. Ahora tengo otra pregunta, ¿Como puedo modificar la frecuencia de esa señal?.

Espero me puedan ayudar.

Saludos y buen dia :)
 

Adjuntos

Última edición:
#10
saludos amigos espero no haber llegado demasiado tarde a este tema, soy novato en esto de VHDL y pues he utilizado este codigo para simular la onda senoidal con el modelsim pero el problema es que en la onda de salida solo veo valores numericos, como un vector. Que debo configurar para lograr ver la forma de onda?
 
#12
Gracias Scooter, ya supe luego de mucho buscar jeje, resulta que se debe cambiar el formato de la señal a analogica y listo.

Ya he logrado simular tanto la sinuidal como la señal triangular, ahora me pregunto como cambiar la frecuencia de dicha señal
 
Última edición:
#14
La frecuencia de la señal depende de la velocidad a la que se generan las muestras. Si se genera una señal que funcione, por ejemplo, a la mitad de la frecuencia del reloj principal y con ella se habilita la generacion de nuevos valores, la frecuencia de salida sera la mitad.

Para cambiar la amplitud, hay que multiplicar los valores de salida por un valor de "amplificacion".
 
#15
La frecuencia de la señal depende de la velocidad a la que se generan las muestras. Si se genera una señal que funcione, por ejemplo, a la mitad de la frecuencia del reloj principal y con ella se habilita la generacion de nuevos valores, la frecuencia de salida sera la mitad.

Para cambiar la amplitud, hay que multiplicar los valores de salida por un valor de "amplificacion".
Gracias chclau, ya pude variar la frecuencia a discreción; pero sin embargo, con respecto a la amplitud, aún no me queda del todo claro esa ganancia o valor de "amplificación"
 
#16
Gracias chclau, ya pude variar la frecuencia a discreción; pero sin embargo, con respecto a la amplitud, aún no me queda del todo claro esa ganancia o valor de "amplificación"

Bueno, aqui adjunto un ejemplo. El archivo "saw" genera una onda triangular simetrica, pero acepta tambien un parametro de ganancia.

El archivo genera la "ROM" con los datos de la funcion en forma automatica en la primera seccion (Generate)

El primer proceso actualiza el acumulador de fase.
El segundo proceso calcula los valores de salida segun los valores de tabla y los afecta con la ganancia.

A continuacion la fuente:

Código:
-- File Name   : saw.vhd
--  Comments   : Generate sawtooth wave
------------------------------------------------------------------
LIBRARY ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.ALL;

ENTITY saw IS

PORT (	
	clk 		: in std_logic;
	reset 		: in std_logic;
	
	gain		: in std_logic_vector(3 downto 0);
	dout 		: out std_logic_vector(7 downto 0)
);
END saw ;--
--
ARCHITECTURE rtl OF saw IS

	CONSTANT ROMSIZE : INTEGER  := 16;
	CONSTANT ROM_W   : INTEGER  := 7;
	TYPE VALTAB IS ARRAY(0 TO ROMSIZE-1) OF signed (7 DOWNTO 0);
	
	signal VALROM: VALTAB;
	signal phase_accum : unsigned(3 downto 0); 
	signal dout_gain   : signed(11 downto 0); 
	
BEGIN

	-- Create saw values table,
	GENROM:
	FOR idx in 0 TO ROMSIZE-1 GENERATE
		CONSTANT offset: 	INTEGER := -8;
		CONSTANT ysc:   	INTEGER := idx+offset;
		CONSTANT yn: 	    SIGNED (7 DOWNTO 0) := TO_SIGNED(ysc, 8);
	BEGIN
		VALROM(idx) <= yn; 
	END GENERATE; 
	
	-- phase accumulator
        process (clk, reset) begin
        if (reset = '1') then
            phase_accum <= (others => '0');
        elsif (rising_edge(clk)) then
	    phase_accum <= phase_accum + 1;
	end if;	
	end process;

	-- phase lookup + gain
        process (clk, reset) begin
        if (reset = '1') then
            dout_gain	<= (others => '0');
        elsif (rising_edge(clk)) then
	    dout_gain	<= signed(gain) * VALROM(to_integer(phase_accum));
	end if;
	end process;
	
	dout <=	std_logic_vector(dout_gain(7 downto 0));
	
END;
Aqui tienes un test bench que verifica la funcion del archivo


Código:
-- File Name   : tb_saw.vhd
--  Comments   : Test bench for the saw waveform generator
------------------------------------------------------------------
library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_textio.all;
    use ieee.numeric_std.ALL;
    
entity tb_saw is
end entity;

architecture test of tb_saw is

    constant PERIOD  : time    := 20 ns;		-- clk = 50MHz
    signal clk       : std_logic := '0';
    signal reset     : std_logic := '1';
    signal gain      : std_logic_vector (3 downto 0);
    signal saw_out   : std_logic_vector (7 downto 0);
    signal endSim	 : boolean   := false;

    component saw is

	PORT (	
		clk 		: in std_logic;
		reset 		: in std_logic;
		gain		: in std_logic_vector(3 downto 0);
		dout 		: out std_logic_vector(7 downto 0)
	);
	END component;
    

begin
        clk    	<= not clk after PERIOD/2;
	
	stim_proc: process
	begin
		wait for PERIOD*5;
		reset   <= '0';
		gain   <= std_logic_vector(to_signed(1, 4));
		wait for PERIOD*80;
		gain   <= std_logic_vector(to_signed(3, 4));
		wait for PERIOD*80;
		gain   <= std_logic_vector(to_signed(-1, 4));
		wait for PERIOD*80;
		wait until (clk = '1');
		
		endSim  <= true;
	end process;
		
	-- End the simulation
	process 
	begin
		if (endSim) then
			assert false 
				report "End of simulation." 
				severity failure; 
		end if;
		wait until (clk = '1');
	end process;	

    saw_inst : saw
    port map (
        clk      => clk,
        reset    => reset,
        gain     => gain,
	dout	 => saw_out
    );

end architecture;
El banco de pruebas usa tres ganancias, uno, tres y menos uno, y se puede ver el resultado del mismo en la forma de onda:

saw.jpg

Te dejo una pregunta para ti, para que la pienses y practiques. Que sucede si usas distintos valores de la triangular, o de ganancia, tales que el resultado se escapa de la precision que tiene esta solucion?

Ejemplo, los valores de la tabla asi como esta van de -8 a 7 con ganancia unitaria. Que pasaria si permites que la ganancia sea mas grande, por ejemplo de 8 bits, y al multiplicar 7 por la maxima ganancia en este caso que es 127, el resultado desborda ya que obviamente no puede ser representado con ocho bits.

Como se ve la falla que ocurre y como lo resolverias?
 
Última edición:
Arriba