Produce sine lookup table based on the frequency

Trying to generate sine wave by using LUT. But, the LUT is calculated within the VHDL code as can be seen below. I do know that in VHDL it is not possible to use real. But couldnt figure out how to produce the LUT first and then use it to generate sin wave. Sure I will be able to generate sin wave once I know how to calculate the LUT dynamically in my vhdl code.

In addition, I am getting:

Error (10482):object “sin” is used but not declared

This what I have tried so far:

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

entity SineWave is
    Port ( clk : in STD_LOGIC;
           sine_out : out STD_LOGIC_VECTOR(7 downto 0));
end SineWave;

architecture Behavioral of SineWave is
    constant TABLE_SIZE : integer := 360; -- Number of entries in the lookup table
    type sine_table_type is array (0 to TABLE_SIZE-1) of integer;
    signal sine_table : sine_table_type;

begin
    process(clk)
        variable angle : integer := 0;
          constant fs : integer := 1024;
          variable counter : integer := 0;
          variable frequency : integer := 1; --for now setting frequency manually
    begin
     for i in 0 to TABLE_SIZE-1 loop
      -- Calculate sine value using the formula
      angle := 2 * 180* frequency * (i) * fs; -- formula = sin(2*pie*frequency* n/sampling frequency(fs))
      sine_table(i) <= sin(angle); -- Convert to fixed-point format
      
      -- report "Index: " & integer'image(i) & " Sine Value: " & integer'image(sine_table(i));
    end loop;
        if rising_edge(clk) then
          
          sine_out <= sine_table[counter];
          counter := counter + 1;
          
        end if;
    end process;
end Behavioral;`

  • 1

    It seems, that you later on want to change the frequency dynamically. So you cannot store the look-up-table in a constant, but must store it in a signal. This signal will cause a very big number of flipflops, if you try to synthesize your design. To avoid this you could use another concept for calculating the sin values, for example the cordic algorithm, which does not need any lookup table.

    – 

  • @Tom As your angle is always a multiple of 360, and as you apparently represent angles in degrees, you could get rid of your table because sin(angle) is constant and equal to zero. Note also that floating point (real) and fixed point (that you mention in your comments) are completely different things.

    – 

There is no sin function available for the integer data type in standard libraries, for sin, you need to use the ieee.math_real library.

While it is true real type cannot be used for synthesisable logic, it can generally be used to set up elaboration time constant values. For example, a SIN LUT.

Your example is incorrect as a LUT as it is generating logic for each element of the table. Your code indicates you are trying to re-initialise the table on every clock edge (rising and falling). You simply need to assign the table to a constant and initialise it from an initialisation function, something like the following:


use ieee.numeric_std.all;
use ieee.math_real.all;

...

type sin_table_t type is array(TABLE_SIZE-1 downto 0) of signed(bitwidth-1 downto 0);

function sin_lut_init return sin_table_t is
    variable angle     : real;
    variable sin_angle : real;
    variable table     : sin_table_t;
begin
    for i in table'range loop
        angle      := MATH_PI * real(i) / real(TABLE_SIZE);
        sin_angle  := sin(angle);

        table(i)   := to_signed( integer( real( 2**bit_width ) * angle ) ), bitwidth );
    end loop;

    return table;
end function;

constant SIN_LUT : sin_table_t := sin_lut_init;

Leave a Comment