Jump to content

    

Вывод ЧМ синусоиды на ЦАП

Здравствуйте.

Стоит задача сделать частотную модуляцию на плис. Плис - spartan 6.

На вход подается значение 8-бит - частота, фаза и амплитуда заданы жестко.

На выходе нужна частотно-модулированная синусоида.

Модуляция в общих чертах понятна, но у меня следующие требования:

минимальная частота синусоиды - 4.25 МГц;

максимальная частота синусоиды - 4.756 МГц;

следовательно в этот промежуток мне надо уложить 256 шагов.

Вот есть алгоритм DDS

  library IEEE;
  use IEEE.std_logic_1164.all;
  use IEEE.numeric_std.all;
  use IEEE..std_logic_unsigned.all;
--------------------------------------------------
Entity DDFS is
--------------------------------------------------
   Port ( CLK       : in  std_logic;
          Freq_Data : in  std_logic_vector (7 downto 0);
          Dout      : out std_logic_vector (7 downto 0)
        );
   end DDFS;
--------------------------------------------------

Architecture RTL of DDFS is
--------------------------------------------------
  signal Result   : signed (7 downto 0);
  signal Accum    : unsigned (20 downto 0) := (others=>'0'); 
  signal Address  : integer range 0 to 63;
  signal RomAddr  : integer range 0 to 63;
  signal Quadrant : std_logic; 
  signal Sign     : std_logic; 

  type Rom64x8 is array (0 to 63) of signed (7 downto 0); 
  constant Sinus_Rom : Rom64x8 := (
    x"02",  x"05",  x"08",  x"0b",  x"0e",  x"11",  x"14",  x"17",
    x"1a",  x"1d",  x"20",  x"23",  x"26",  x"29",  x"2c",  x"2f",
    x"32",  x"36",  x"39",  x"3c",  x"3e",  x"40",  x"43",  x"46",
    x"48",  x"4b",  x"4d",  x"50",  x"52",  x"54",  x"57",  x"59",
    x"5b",  x"5d",  x"5f",  x"62",  x"64",  x"65",  x"67",  x"69",
    x"6b",  x"6d",  x"6e",  x"70",  x"71",  x"73",  x"74",  x"75",
    x"76",  x"77",  x"79",  x"79",  x"7a",  x"7b",  x"7c",  x"7d",
    x"7d",  x"7e",  x"7e",  x"7f",  x"7f",  x"7f",  x"7f",  x"7f");
begin
   -- Phasenakkumulator   
   process begin
     wait until rising_edge(CLK);
     Accum <= Accum + unsigned(Freq_Data);
   end process;

   -- BROM      
   process begin
     wait until rising_edge(CLK);
     RomAddr <= Address;          -- getaktete Adresse --> BRAM
   end process;
   Result   <= signed(Sinus_Rom(RomAddr));

   Quadrant <= Accum(Accum'left-1);
   Address  <=    to_integer(Accum(Accum'high-2 downto Accum'high-7))  when (Quadrant='0') else 
               63-to_integer(Accum(Accum'high-2 downto Accum'high-7));
 
   -- 1 Takt Latency wegen BROM
   process begin
     wait until rising_edge(CLK);
     Sign    <= Accum(Accum'left);
   end process;
   Dout     <= std_logic_vector(  Result) + x"7f" when (Sign='1') else  
               std_logic_vector(0-Result) - x"7f";
end RTL;

Но этот алгоритм по тактировании 100 МГц выдает максимальную частоту синусоины порядка 15 кГц. А мне надо от 4.25 МГц до 4.756МГц.

Как вариант делать огромную таблицу на допустим 4096 значений, и при большой частоте синусоиды считывать не каждое значение а каждое 16 допустим, это относительно точности.

А какие-то не табличные быстрые методы получения чм синусоиды есть?

В моем проекте тактирование вывода синусоиды - 108 МГц, хотя может быть можно поднять, но на много все равно не получиться.

Подскажите, благодарю.

Edited by Kostochkin

Share this post


Link to post
Share on other sites

ну если Accum <= Accum + 255 получается около 15кГц (хотя при 21битном аккумуляторе вроде как должно быть 100e6/(2^21/256) = 12кГц)

то может просто сделать Accum <= Accum + 89128 + 42 * Freq_Data;

константы только правильно подогнать, чтобы точнее в требуемые частоты попадали.

Share this post


Link to post
Share on other sites
1 hour ago, _pv said:

ну если Accum <= Accum + 255 получается около 15кГц (хотя при 21битном аккумуляторе вроде как должно быть 100e6/(2^21/256) = 12кГц)

то может просто сделать Accum <= Accum + 89128 + 42 * Freq_Data;

константы только правильно подогнать, чтобы точнее в требуемые частоты попадали.

Благодарю.

но при 100 МГц, между крайними частотами синусоиды войдут 2 значения, так как мин шаг 10нс. Получается я могу подвинуть синусоиду на 4 положения и все,

хотелось бы больше, хотя бы 32 значения..

Share this post


Link to post
Share on other sites

сделайте нормальный DDS. 1/4 синуса в таблицу 4к-16к точек, 14-16 бит фазы, 14-16 блочков памяти и все у вас будет.

Share this post


Link to post
Share on other sites
6 minutes ago, des00 said:

сделайте нормальный DDS. 1/4 синуса в таблицу 4к-16к точек, 14-16 бит фазы, 14-16 блочков памяти и все у вас будет.

Зачем 14-16 бит фазы?

А где взять такую таблицу от 4000 до 16000 значений?

Благодарю

Share this post


Link to post
Share on other sites
11 минут назад, Kostochkin сказал:

А где взять такую таблицу от 4000 до 16000 значений?

А в Matlab-е посчитать и в файл записать. Я так делал. Не для синуса только, а оконную функцию.

Share this post


Link to post
Share on other sites
23 minutes ago, Kostochkin said:

но при 100 МГц, между крайними частотами синусоиды войдут 2 значения, так как мин шаг 10нс. Получается я могу подвинуть синусоиду на 4 положения и все,

хотелось бы больше, хотя бы 32 значения..

Математику не обманете :) При 5 MHz (округлил вверх) на выходе и 100 на входе у вас есть максимум 20 точек на период синусоиды (т.е. 5 на четверть периода). Это будет довольно 'грубая' синусоида.

Если вас такая устроит (по спектру выходного сигнала), то дальше выбираете размерность аккумулятора и величину, которую будете прибавлять.

Share this post


Link to post
Share on other sites
2 минуты назад, xvr сказал:

Математику не обманете :) При 5 MHz (округлил вверх) на выходе и 100 на входе у вас есть максимум 20 точек на период синусоиды (т.е. 5 на четверть периода). Это будет довольно 'грубая' синусоида.

Если вас такая устроит (по спектру выходного сигнала), то дальше выбираете размерность аккумулятора и величину, которую будете прибавлять.

Ну и есть промежуточные варианты. Можно с блока обработки частоты - PLL или DCM взять в качестве клока сигнал, сдвинутый от основной частоты на 180 или 90 градусов. Но вот как потом его заправить в ЦАП - это надо будет решать отдельно...

 

Share this post


Link to post
Share on other sites

Приветствую!

11 minutes ago, Kostochkin said:

Зачем 14-16 бит фазы?

Разрядность аккумулятора фазы  влияет на точность частоты которую вы можете генерировать  - чем  больше чем более точнее можете задавать генерируемую частоту.   А размер выходной таблицы  sin/cos влияет на величину гармоник.  Так как вход задания частоты у вас всего 8 бит  то  надо масштабировать его  перед суммированием в аккумуляторе ( Kfi = Kfin*A + B).  Ну и для уменьшения размера таблиц  sin|cos можно использовать интерполяцию . 

Удачи! Rob.

Share this post


Link to post
Share on other sites
2 hours ago, _pv said:

ну если Accum <= Accum + 255 получается около 15кГц (хотя при 21битном аккумуляторе вроде как должно быть 100e6/(2^21/256) = 12кГц)

то может просто сделать Accum <= Accum + 89128 + 42 * Freq_Data;

константы только правильно подогнать, чтобы точнее в требуемые частоты попадали.

20 точек на период меня устраивает, пока.

И решение Accum <= Accum + 89128 + 42 * Freq_Data - тоже, только мне надо более точно задавать частоту синусоиды. Правильно ли я понимаю, что для этого мне надо увеличить размерность аккумулятора?

Благодарю.

Share this post


Link to post
Share on other sites
6 минут назад, RobFPGA сказал:

Ну и для уменьшения размера таблиц  sin|cos можно использовать интерполяцию . 

Можно еще в таблицу загнать не "sin|cos", а разницу между sin(x) и y=x... 

 

Share this post


Link to post
Share on other sites

В Xilinx DDS готовый блок есть. пара блок рам и , выбор sfdr ...

Share this post


Link to post
Share on other sites
1 hour ago, Kostochkin said:

но при 100 МГц, между крайними частотами синусоиды войдут 2 значения, так как мин шаг 10нс. Получается я могу подвинуть синусоиду на 4 положения и все,

хотелось бы больше, хотя бы 32 значения..

ничего не понял, какие 2 значения, какие 4 положения,

если freq_data == 0, частота на выходе = 100e6/(2^21/(89128)) = 4249954,2 Гц

если freq_data == 1, частота на выходе = 100e6/(2^21/(89128+42*1)) = 4252004,6 Гц

...

если freq_data == 255, частота на выходе = 100e6/(2^21/(89128 + 42*255)) = 4760694,5 Гц

 

если надо абсолютную частоту точнее задавать чтобы не 4249954,2 а 4250000,0 то да, увеличивайте аккумулятор,  но 8 бит Freq_Data всё равно будет делить заданный диапазон частот на 256 значений.

и как уже подсказали таблицу тоже надо бы привести в соответствии с выходными 8 битами данных, то есть как минимум 256*2*Pi/4 ~512, а не 64 - раз в 8 побольше сделать.

делается даже не в матлабе, а достаточно экселя =ROUND(255*SIN(A1*2*PI()/2048);0).

 

но готовый DDS блок будет взять гораздо проще, если только это не какая-нибудь лаба/курсовик.

Share this post


Link to post
Share on other sites
1 hour ago, _pv said:

ничего не понял, какие 2 значения, какие 4 положения,

если freq_data == 0, частота на выходе = 100e6/(2^21/(89128)) = 4249954,2 Гц

если freq_data == 1, частота на выходе = 100e6/(2^21/(89128+42*1)) = 4252004,6 Гц

...

если freq_data == 255, частота на выходе = 100e6/(2^21/(89128 + 42*255)) = 4760694,5 Гц

 

если надо абсолютную частоту точнее задавать чтобы не 4249954,2 а 4250000,0 то да, увеличивайте аккумулятор,  но 8 бит Freq_Data всё равно будет делить заданный диапазон частот на 256 значений.

и как уже подсказали таблицу тоже надо бы привести в соответствии с выходными 8 битами данных, то есть как минимум 256*2*Pi/4 ~512, а не 64 - раз в 8 побольше сделать.

делается даже не в матлабе, а достаточно экселя =ROUND(255*SIN(A1*2*PI()/2048);0).

 

но готовый DDS блок будет взять гораздо проще, если только это не какая-нибудь лаба/курсовик.

Благодарю.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now