Перейти к содержанию
    

Lookup table синуса

Добрый день!
Я хочу реализовать DDS и для этого логично нужна таблица поиска синуса в ПЗУ, я решил взять способ представления синуса через интерполяцию из книги Титце и Шенка 1982 года (да можно CORDIC или разложение в ряды по Чебышеву или Тейлору, но мне интересно попробовать так), на вход ПЗУ будет поступать 12-и разрядное слово и на выходе тоже будет 12-и разрядное слово, АЦП 10 бит. Возник вопрос, АЦП работает в диапазоне от 0 1024, а на выходе ПЗУ мы получаем дробное число, тогда для адекватного представления данных из АЦП мне надо выходное число из ПЗУ дополнительно умножить на 512 и прибавить 512, но тогда по логике разрядность числа после этих этих операций составит 20 бит минимум, и не понятно как потом его подавать на АЦП, выкинуть 10 бит лишних?

1.png

2.png

3.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/12/2023 at 8:48 AM, Kirill.L said:

 выкинуть 10 бит лишних?

Да, взять только 10 старших бит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Задавать начальную фазу как планируете в интеполяционной реализации?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 минут назад, Maverick_ сказал:

Задавать начальную фазу как планируете в интеполяционной реализации?

Через фазовый аккумулятор, возможно я конечно не понял вопроса.

1.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Kirill.L said:

на выходе ПЗУ мы получаем дробное число

Ничего подобного. В ПЗУ хранится таблица синуса в целых числах, то есть уже умноженных на какую-то степень двойки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use ieee.math_real.all;

entity dds_sine is
port(
  i_clk          : in  std_logic;
  i_rstb         : in  std_logic;
  i_sync_reset   : in  std_logic;
  i_fcw          : in  std_logic_vector(31 downto 0);
  i_start_phase  : in  std_logic_vector(31 downto 0);
  o_sine         : out std_logic_vector(13 downto 0));
end dds_sine;

architecture rtl of dds_sine is

constant C_LUT_DEPTH    : integer := 2**13;  -- 8Kword
constant C_LUT_BIT      : integer := 14;     -- 14 bit LUT
type t_lut_sin is array(0 to C_LUT_DEPTH-1) of std_logic_vector(C_LUT_BIT-1 downto 0);

-- quantize a real value as signed 
function quantization_sgn(nbit : integer; max_abs : real; dval : real) return std_logic_vector is
variable temp    : std_logic_vector(nbit-1 downto 0):=(others=>'0');
constant scale   : real :=(2.0**(real(nbit-1)))/max_abs;
constant minq    : integer := -(2**(nbit-1));
constant maxq    : integer := +(2**(nbit-1))-1;
variable itemp   : integer := 0;
begin
  if(nbit>0) then
    if (dval>=0.0) then 
      itemp := +(integer(+dval*scale+0.49));
    else 
      itemp := -(integer(-dval*scale+0.49));
    end if;
    if(itemp<minq) then itemp := minq; end if;
    if(itemp>maxq) then itemp := maxq; end if;
  end if;
  temp := std_logic_vector(to_signed(itemp,nbit));
  return temp;
end quantization_sgn;

-- generate the sine values for a LUT of depth "LUT_DEPTH" and quantization of "LUT_BIT"
function init_lut_sin return t_lut_sin is
variable ret           : t_lut_sin:=(others=>(others=>'0'));  -- LUT generated
variable v_tstep       : real:=0.0;
variable v_qsine_sgn   : std_logic_vector(C_LUT_BIT-1 downto 0):=(others=>'0');
constant step          : real := 1.00/real(C_LUT_DEPTH);
begin
  for count in 0 to C_LUT_DEPTH-1 loop
    v_qsine_sgn := quantization_sgn(C_LUT_BIT, 1.0,sin(MATH_2_PI*v_tstep));
    ret(count)  := v_qsine_sgn;
    v_tstep := v_tstep + step;
     end loop;
     return ret;
end function init_lut_sin;

-- initialize LUT with sine samples
constant C_LUT_SIN                 : t_lut_sin := init_lut_sin;
signal r_sync_reset                : std_logic;
signal r_start_phase               : unsigned(31 downto 0);
signal r_fcw                       : unsigned(31 downto 0);
signal r_nco                       : unsigned(31 downto 0);
signal lut_addr                    : std_logic_vector(12 downto 0);
signal lut_value                   : std_logic_vector(13 downto 0);

begin

p_nco : process(i_clk,i_rstb)
begin
  if(i_rstb='0') then
    r_sync_reset      <= '1';
    r_start_phase     <= (others=>'0');
    r_fcw             <= (others=>'0');
    r_nco             <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    r_sync_reset      <= i_sync_reset   ;
    r_start_phase     <= unsigned(i_start_phase);
    r_fcw             <= unsigned(i_fcw);
    if(r_sync_reset='1') then
      r_nco             <= r_start_phase;
    else
      r_nco             <= r_nco + r_fcw;
    end if;
  end if;
end process p_nco;

p_rom : process(i_clk)
begin
  if(rising_edge(i_clk)) then
    lut_addr   <= std_logic_vector(r_nco(31 downto 19));
    lut_value  <= C_LUT_SIN(to_integer(unsigned(lut_addr)));
  end if;
end process p_rom;

p_sine : process(i_clk,i_rstb)
begin
  if(i_rstb='0') then
    o_sine     <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    o_sine     <= lut_value;
  end if;
end process p_sine;

end rtl;

у меня так сделано

PS при симуляции не забудь сделать   o_sine         : out std_logic_vector(13 downto 0));  => signed  иначе будете наблюдать в Analog представлении не синус

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Видимо я плохо понял, что к чему, может кто то пояснить как я могу сделать эту несчастную таблицу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мое описание не вариант?  там автоматически генерируется

второй вариант через матлаб скрипт - инициализируете память

10 minutes ago, Kirill.L said:

Видимо я плохо понял, что к чему, может кто то пояснить как я могу сделать эту несчастную таблицу.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавлю немного из истории математики.

Легендарные таблицы Брадиса были сделаны при помощи полиномов Чебышева.

Сначала определялся необходимый порядок полинома, для того чтобы ошибка в результате вычислений не превышала некий допуск, а затем вперед и с песней, заполняем таблицу.

Кстати в области EECS floating point, Ieee754 и библиотеки glibc под *nix всем этим пользуются втихую, но поскольку комментариев там в коде нету -- они все делают вид что это ноу-хау и константы, подставляемые в SIMD/SSE2/AVX-регистры для вычислений взялись "из воздуха".

 

 

И да, при наличии "железячной" реализации операции умножения стоит оценить затраты по сравнению с CORDIC. Для потоковых вычислений с плавающим углом вектора CORDIC конечно будет интереснее, а во всех других случаях - нужно такты считать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 hours ago, krux said:

Добавлю немного из истории математики.

Кстати в области EECS floating point, Ieee754 и библиотеки glibc под *nix всем этим пользуются втихую, но поскольку комментариев там в коде нету -- они все делают вид что это ноу-хау и константы, подставляемые в SIMD/SSE2/AVX-регистры для вычислений взялись "из воздуха".

Тоже добавлю немного истории HARD+SOFT: легендарный математический сопроцессор фирмы Motorolla MC68881 поддерживал  в том числе тригонометрические функции.

The monadic operations available with the FPCP are as follows:

  • FABS Absolute Value
  • FLOG2 Log Base 2
  • FACOS Arc Cosine
  • FLOGN Log Base e
  • FASIN Arc Sine
  • FLOGNP1 Log Base e of (x+ 1)
  • FATAN Arc Tangent
  • FNEG Negate
  • FATANH Hyperbolic Arc Tangent
  • FSIN Sine
  • FCOS Cosine
  • FSINCOS Simultaneous Sine and Cosine
  • FCOSH Hyperbolic Cosine
  • FSINH Hyperbolic Sine
  • FETOX e to the x Power
  • FSORT Square Root
  • FETOXM1 e to the x Power - 1
  • FTAN Tangent
  • FGETEXP Get Exponent
  • FTANH Hyperbolic Tangent
  • FGETMAN Get Mantissa
  • FTENTOX 10 to the x Power
  • FINT Integer Part
  • FTST Test
  • FINTRZ Integer Part (Truncated)
  • FTWOTOX 2 to the x Power
  • FLOG 10 Log Base 10

В последствии все вычисления FPU встроили в 68040/68060, убрав при этом все эти sin/cos.

Получившуюся несовместимость с уже существующим софтом решали программно: вызовом библиотек через срабатывающие исключения, поэтому многие алгоритмы на 68881 работали быстрее чем на 68060 🙂

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...