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

Реализация БПФ на ПЛИС

Доброго времени суток!

 

Нужно реализовать алгоритм БПФ с прореживанием по частоте на ПЛИС, но при реализации возникают трудности, вот некоторые из них:

  1. Поворачивающие множители являются числами по модулю меньше либо равно единицы: |W|<=1. Я так понял, чтобы перейти к целым числам требуется умножать их на (2^N) и то, что после запятой отсекать (N - разрядность). Нужно ли то же самое делать с входными данными (x1 и x2) или не обязательно?
  2. Нужно реализовать операции умножения и сложения со знаковыми числами, тут у меня такая задумка: преобразовать в integer соответствующего диапазона: от -(2^N)/2 до (2^N)/2 - 1, произвести нужные арифметические операции и преобразовать обратно std_logic_vector, код прилагается:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity butterfly is
generic (b_size: natural := 14);
port (
x1, x2, w: in std_logic_vector(b_size - 1 downto 0);
y1, y2: out std_logic_vector(b_size - 1 downto 0)
);
end entity butterfly;

architecture behavioral of butterfly is
signal x1_int, x2_int, w_int: integer range -8192 to 8191;
signal y1_int: integer range -8192 to 8191;
signal y2_int: integer range -134217728 to 134217727; -- Т.к. производится умножение на поворачивающий множитель
begin
process (CLK) is
begin
-- Преобразовываю в тип integer:
x1_int <= conv_integer(x1);
x2_int <= conv_integer(x2);
w_int <= conv_integer(w);
y1_int <= conv_integer(y1);
y2_int <= conv_integer(y2);

-- Вычисляю бабочку и преобразовываю обратно в std_logic_vector (b_size - 1 downto 0):
y1 <= conv_std_logic_vector(x1_int + x2_int, b_size);
y2 <= conv_std_logic_vector((x1_int - x2_int) * w_int, b_size);
end process;
end architecture behavioral;

Вопрос будет ли так корректно сделать или все делается совершенно по-другому?

Буду рад любым вашим замечаниям, предложениям, советам и ссылкам. Заранее спасибо!

 

P.S. На форуме я искал и не нашел ответа на свои вопросы, тем более я уверен далее появятся новые, думаю лучше, чтоб это все было в одной теме...

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


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

1. Чтобы поворачивающий множитель W, меньший единицы, преобразовать в целое число, имеющее разрядность N бит, надо выполнить следующее преобразование:

round(W*(N-1)) - если число положительное,

(2^N) - round(abs(W)*(N-1)) - если число отрицательное.

 

Правила приведены для дополнительного кода.

 

2. Для умножения знаковых чисел надо пользоваться специальной мегафункцией, указав ей параметр "SIGNED"

 

3. Если вы делаете БПФ на ПЛИС, то надо смотреть на алгоритмы по основанию 4, а не по основанию 2.

Получается намного удобнее и эффективнее. Классическая бабочка - наследие от процессоров DSP, где она сделана аппаратно. Ядром алгоритма БПФ по основанию 4 является более сложный 4-х точечный БПФ, где все поворачивающие множители равны либо 1, либо -1. На ПЛИС удобно реализуется на сумматорах, можно сделать комбинаторную сехему, выполняющею этот самый 4-х точечный БПФ за один такт. Я такое делал, железно работало на частотах выше 100 МГц.

 

Ну, а если время на выполнение БПФа достаточно много, то можно обойтись обычным ДПФ-ом, легко реализуется,

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

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


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

Вопрос будет ли так корректно сделать или все делается совершенно по-другому?

Буду рад любым вашим замечаниям, предложениям, советам и ссылкам. Заранее спасибо!

Сам не знаю как лучше, но все-же, а если посмотреть как делает та-же Альтера или Ксалинкс?

Возможность посмотреть исходники вроде есть.

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


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

Сам не знаю как лучше, но все-же, а если посмотреть как делает та-же Альтера или Ксалинкс?

Возможность посмотреть исходники вроде есть.

Пишу в квартусе, стало быть ПЛИС Альтера, если можно дайте ссылочку на исходник. У Калинкса нашел там для фиксированной запятой, пытался разобраться, не получилось...

 

Для умножения знаковых чисел надо пользоваться специальной мегафункцией, указав ей параметр "SIGNED"

Так и думал, что сначала нужно перевести к типу SIGNED.

Нужно ли то же самое делать с входными данными (x1 и x2) или не обязательно?

 

Если вы делаете БПФ на ПЛИС, то надо смотреть на алгоритмы по основанию 4, а не по основанию 2.

Тоже к этому склоняюсь. буду думать...

 

round(W*(N-1)) - если число положительное,

вот это не совсем понял

Изменено пользователем ZED

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


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

Я малость ошибся правильно будет так:

 

round(W*(2^(N-1)-1))

 

Пример:

допустим, поворачивающий множитель равен W=0.077391

и нужно преобразовать в 16-разрядную целочисленную форму, представленную в дополнительном коде (1 знаковый бит + 15 бит мантисса).

 

(2^15) - 1 = 32767.

 

0.077391 * 32767 = 2535.8709 - дробную часть нельзя просто отбросить, нужно выполнять честное округление,

чтобы ошибка была центрированая, поэтому

round(2535.8709) = 2536.

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


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

Я малость ошибся правильно будет так:

round(W*(2^(N-1)-1))

Теперь понятно, спасибо!

 

Вот такой еще вопрос возник, нужно реализовать ПЗУ (ROM) для поворачивающих множителей, планирую подавать адрес и читать из файла, но Квартус синтезирует RAM память, а не ROM со всякими там WE, data_in и т.д., которые соответственно подключены либо к генератору нуля или единицы. А из файла не читает, не пойму может я где ошибся или нужно что-то указывать при синтезе, вот мой код:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use std.textio.all;

entity fft_rom is

generic(addr_size : natural := 5;
data_size : natural := 14);

port(
clk: in std_logic;
addr: in std_logic_vector (addr_size - 1 downto 0);
data: out std_logic_vector (data_size - 1 downto 0)
);
end entity fft_rom;

architecture behavioral of fft_rom is

type RomType is array (0 to 2**5) of bit_vector(data_size - 1 downto 0);
-- Функция чтения из файла:
function FillRom (RomFileName: in string)
return
    RomType is
    file RomFile: text is in RomFileName;
    variable RomFileLine : line;
    variable ROM: RomType;
begin
    for i in RomType'range loop
        readline(RomFile, RomFileLine);
        read (RomFileLine, ROM(i));
    end loop;
    return ROM;
end function;
-- конец функции

signal ROM: RomType := FillRom("C:\ROM.dat");

begin
    process(clk)
        begin
            if (clk'event and clk = '1') then
                data <= to_stdlogicvector(ROM(conv_integer(addr)));
            end if;
    end process;
end architecture behavioral;

С Квартусом никогда не работал, может кто чего посоветует?

 

P.S. Также остается открытым вопрос, корректно таким способом организовать бабочку или же это делается другими методами?

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

entity butterfly is
    generic (b_size: natural := 14);
    
    port(CLK: in std_logic; 
         x1: in std_logic_vector(b_size - 1 downto 0);
         x2: in std_logic_vector(b_size - 1 downto 0);
         w: in std_logic_vector(b_size - 1 downto 0);
         y1: out std_logic_vector(b_size - 1 downto 0);
         y2: out std_logic_vector(b_size- 1 downto 0)
        );
end entity butterfly;


architecture behavioral of butterfly is

signal x1_int : integer range -8192 to 8191;
signal x2_int : integer range -8192 to 8191;
signal w_int : integer range -8192 to 8191;
signal y1_int : integer range -8192 to 8192;
signal y2_int : integer range -13427728 to 13427727;

begin
x1_int <= to_integer(signed (x1));
x2_int <= to_integer(signed (x2));
w_int <= to_integer(signed (w));

process (CLK)
begin
if (rising_edge(CLK)) then
    y1_int <= x1_int + x2_int;
    y2_int <= (x1_int - x2_int)*w_int;
end if;
end process;
y1 <= std_logic_vector(to_signed(y1_int, b_size));
y2 <= std_logic_vector(to_signed(y2_int, b_size));
end behavioral;

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


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

Не силен в Verilog. Помочь не могу.

А не пробовали использовать мегафункцию FFT?

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


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

Не силен в Verilog. Помочь не могу.

А не пробовали использовать мегафункцию FFT?

 

Это VHDL, мегафункцию не пробовал, кстати посоветуете какую и где скачать? Но просто хочется самому реализовать, "ручками" так сказать. Я вот тоже к сожалению не силен в vhdl, но очень хочу его освоить, вот и задаю вопросы. В книжках она как правило не освещены, либо я читаю не те книжки. Кстати слышал вышла книжка: Перельройзен Е.З. Проектируем на VHDL. - М.: Изд-во "СОЛОН-Пресс", 2004. Читал кто? Как она? К сожалению уже все раскупили, где достать не знаю...

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


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

ALTERA FFT Compiler - все основное там есть. Для моделирования достаточно оригинальной версии,

посмотрите, поиграете параметрами - выберете что Вам подойдет.

Там еще хелп достаточно полезный приложен.

Если не подойдут Вам оригинальные варианты, то берем Рабинера-Голда, и впред, создавать свою реализацию.

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


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

Если не подойдут Вам оригинальные варианты, то берем Рабинера-Голда, и впред, создавать свою реализацию.

Рабинер Голд имеется, но вот с языком проблемы, вот я и спрашиваю как то или иное реализовать на vhdl, почему так или иначе синтезирует квартус и т.д.

ALTERA FFT Compiler - все основное там есть. Для моделирования достаточно оригинальной версии,

посмотрите, поиграете параметрами - выберете что Вам подойдет.

Спасибо, документацию нашел, а вот сам файл не смог скачать...

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


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

Для ознакомительной работы в режиме OpenCore можно скачать без проблем. Пробуйте.

 

Еще погуглите кракнутый FFT Compiler, в сети полно этого добра. Для начала подойдет любая, не обязательно самая свежая версия.

Там можно будет и исходники посмотреть, они как раз на VHDL.

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


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

Вопрос по vhdl остается открытым, но похоже кроме soldat_shveyk и меня эта тема (БПФ) никого не интересует...

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


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

Откопал у себя исходники всех альтеровских БПФ-ов, если надо, пришлю.

Исходники рабочие, пользовался, проверял.

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


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

Возникла еще одна проблема, реализую БПФ по схеме "пинг-понг", т.е бабочка, две ОЗУ и одно ПЗУ для хранения поворачивающих множителей. Бабочку нужно подключать то к одной памяти на чтение, а к другой на запись, то на оборот:

 

ОЗУ - 1 | Чтение | Запись | Чтение | Запись |

-------------------------------------------------------------

ОЗУ - 2 | Запись | Чтение | Запись | Чтение |

 

И т.д. Вопрос такой, как это сделать, пробовал делать мультиплексирование, но ничего не выходит, может кто подскажет как это реализовать?

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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