Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Реализация БПФ на ПЛИС
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Языки проектирования на ПЛИС (FPGA)
Страницы: 1, 2, 3, 4, 5, 6, 7
Sefo
Цитата(ZED @ Mar 4 2009, 20:05) *
...строго не судите, просто очень сложно все это не в живую обсуждать...


Я Вас понимаю.

Цитата(ZED @ Mar 4 2009, 20:05) *
Алгоритм переделал, по крайней мере я думаю, что так должно быть.


Увы, не так smile.gif Если Вы внимательно посмотрите на предыдущие этапы, то заметите следующее. На первом этапе 1 группа из 512-ти бабочек, на втором этапе – 4 одинаковых группы по 128 бабочек и т.д. В каждой группе нулевая бабочка (будем считать с 0) имеет все коэффициенты W0. Так вот на 6-ом этапе у нас получается 1024 группы по 1 бабочке в каждой – она 0-ая и единственная. Так что все коэффициенты у нее W0. При классическом (как наш) прореживании по частоте на последнем этапе нет умножений (в смысле, что умножаем все на W0 = 1). При прореживании по времени, умножение отсутствует на первом этапе.

Исправляйте...

Цитата(ZED @ Mar 4 2009, 20:05) *
А как дать бабочке сразу 4 отсчета, я просто не представляю это возможным, кроме как через задержку на один так два из них.


Принципиально, это ничем не отличается от того, чтобы подавать 2 отсчета одновременно, или 3, или 5. Что именно Вас смущает в том, чтобы подавать одновременно больше 2-х отсчетов?

Цитата(ZED @ Mar 4 2009, 20:05) *
Мы обсуждали ляп про переключение шины.


Здесь все тоже самое. smile.gif

Цитата(ZED @ Mar 4 2009, 20:05) *
Вы предлагаете подключать данные еще и к 2-х Т.Б. всегда?


У Вас все равно не получится ничего не подать на вход 2-х точечной бабочки. Внутри ПЛИС нет логических ячеек с Z-состоянием на выходе (Quartus на этом прекратит синтез с ошибкой). Но даже в обычной схеме, если вы выход микросхемы А переведете в Z-состояние, то на входе микросхемы Б, на который приходит провод с выхода микросхемы А, не будет "ничего" – микр. Б все равно будет как-то "интерпретировать" то, что будет наводится на входную ножку smile.gif Поэтому все равно, что Вы подадите на 2-х точечную бабочку когда она не нужна – специальную константу, случайные сигнал или то же, что и на 4-х Т.Б. Вам все равно придется поставить мультиплексор, который будет выбирать откуда брать результат – с 2-х или 4-х Т.Б.

Про блок-схему напишу днем или вечером.
ZED
Исправил.
Цитата
Вас смущает в том, чтобы подавать одновременно больше 2-х отсчетов?

Да, меня это смущает, как из памяти сразу считать 4 отсчета, где мы возьмем такую память? Если только сами напишем...
Sefo
Теперь про блок-схему.

Если бы там нужно было только лишь нарисовать АЦП и три зеленые линии, то я не стал бы Вас просить это делать - это нарисовать можно меньше чем за минуту. smile.gif

Я хотел, чтобы Вы немножко подумали как подключить АЦП к БПФ.

Блок-схема она не просто так рисуется – это первое приближение реализации. Она определяет макроблоки (модули) проекта и их взаимодействие. От того, насколько мы удачно разделим устройство на макроблоки зависит простота и удобство дальнейшего проектирования, реализации и отладки. Блок-схема не должна углубляться в детали реализации, но и не может от них абстрагироваться совсем – она должна учитывать реализацию, но в первом приближении. Блок-схема не расписывает детально все сигналы, соединяющие блоки, но она определяет структуру интерфейсов между ними. Макроблок, в свою очередь, не должен быть "перегружен начинкой". Грубо говоря, блок-схему БПФ можно свести и к 2-м квадратам "Память" и "Бабочка", двунаправленной стрелки между ними, стрелки на вход от АЦП и стрелки на выход. Но от такой блок-схемы не будет никакой помощи в реализации. Наоборот возникнет множество вопросов вроде "как это реализовать?", "куда это поместить?" (в "Бабочку" или в "Память"), "как это состыковать?" и т.д. и т.п.

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

1) Я бы не нарисовал вообще ничего из управления, ни блок, ни управляющие сигналы (красные линии). В этом случае каждый блок должен был бы содержать свое собственное управление, работающее независимо от остальных блоков. БПФ смог бы работать только по очень жесткой временной диаграмме. Это все реализуемо, но ... Получаем много дублирующего кода, отсутствие какой-либо гибкости, сложность модификации, повышенную сложность стыковки блоков при сборке воедино, неудобство и повышенную сложность отладки, сложность в использовании блока в другом проекте.

2) Я бы не нарисовал блок управления, но нарисовал бы управляющие сигналы от блока к блоку. Этот вариант гораздо лучше 1-го. В некоторых системах такое распределенное управление бывает даже весьма выгодным и удобным, но в нашем случае оно хуже, чем централизованное. В нашем случае операции в блоках настолько детерминированы, набор их настолько ограничен, а взаимодействия между блоками настолько стационарны, что удобнее управлять всем этим из одного места. При попытке сделать в БПФ распределенное управление, мы столкнемся с трудностью его распределения по блокам.

Идем дальше.

На моей блок-схеме потоки данных, обозначенные синими линиями, одинаковые. Из памяти в бабочку мы передаем 4 точки всегда (2-х Т.Б. может рассматриваться либо как частный случай, когда из 4 точек используются только 2, а можно сделать и две 2-х ТБ – они ведь очень маленькие и сверх простые и схема БПФ нам это позволяет, но об этом позже), из бабочки в умножители тоже 4 точки всегда (неважно, что один из 4-х умножит. физически будет там отсутствовать за перманентной равностью коэффициента 1), из умножителей в память тоже возвращается 4 точки всегда. Мало того, точки-то комплексные!

И тут Вы... , извините,... "втыкаете" АЦП прямо в память! smile.gif Неужели он у Вас выдает комплексный сигнал и по 4 точки за раз?!

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

Насчет памяти не смущайтесь smile.gif когда подойдем к ее реализации все станет ясно.


Предлагаю параллельно с подключением АЦП заняться уже и самой бабочкой.

Сколько разрядов на данные и сколько на коэффициенты Вы предполагаете?

Напишите, пожалуйста VHDL код 4-х точечной бабочки (не забудьте, умножение на доворачивающие множители в нее не входит). Если что-то не ясно, не стесняйтесь, спрашивайте сразу.
sazh
Цитата(Sefo @ Mar 6 2009, 18:42) *
Теперь про блок-схему.

Я хотел, чтобы Вы немножко подумали как подключить АЦП к БПФ.


А кто с утра еще не пЪян,
тот, извините , не улан.
Sefo
smile.gif
ZED
Цитата
В общем, постарайтесь продумать, как его подключить. И, думаю, лучше будет, если Вы накидаете несколько, пусть и сырых, вариантов, чтобы не терять зря время.

Добавил блок квадратурной дискретизации.

Цитата
Сколько разрядов на данные и сколько на коэффициенты Вы предполагаете?

На данные 16 разрядов, на коэффициенты - 12.

Цитата
Напишите, пожалуйста VHDL код 4-х точечной бабочки (не забудьте, умножение на доворачивающие множители в нее не входит).

Попробовал, прилагаю, не забыл biggrin.gif

Цитата
Если что-то не ясно, не стесняйтесь, спрашивайте сразу.

Спасибо!
ZED
Там нужно еще библиотеку добавить:
Код
use IEEE.std_logic_unsigned.all;
Sefo
После просмотра и синтеза вашего кода в Квартусе у меня появились следующие вопросы:

1) Зачем Вы поставили регистры на входе?

2) Зачем Вы используете тип integer? Тем более, что разрядность входных данных у Вас задана через параметр, а диапазон значений integer жестко фиксирован.

3)Просинтезируйте (просто отдельным проектом только butterfly_complex.vhd) и посмотрите в RTL Viewer во что превращается ваш код. Проанализируйте, во что Квартус его превратил.
ZED
Цитата
Зачем Вы поставили регистры на входе?

Да, действительно, все CONV_INTEGER нужно вынести за процесс...
Цитата
Зачем Вы используете тип integer? Тем более, что разрядность входных данных у Вас задана через параметр, а диапазон значений integer жестко фиксирован.

Квартус сам разберется складывать целые числа, а потом просто переведет их в std_logic_vector нужной нам размерности, лишнее уберет...
Цитата
Просинтезируйте (просто отдельным проектом только butterfly_complex.vhd) и посмотрите в RTL Viewer во что превращается ваш код. Проанализируйте, во что Квартус его превратил.

Если вынести за процесс конвертацию в integer? то синтезирует следующее:
Sefo
В том то и дело, что Квартус плохо разобрался как сложить числа. Посмотрите внимательно, чтобы сложить 4 числа нужно всего 3 сумматора, а Квартус вставил еще и четвертый. Спрашивается зачем? Можно предположить, что для округления, но попробуйте при симуляции задать на вход 1,1,1,0 или -2,-2,-2,-1. На одном из выходов (где чистое сложение) в первом случае будет 3/4 = 0.75, что при округлении должно дать 1, а у Вас будет 0, во втором случае -7/4 = -1.75, что при округлении должно давать -2, а у Вас будет -1. Спрашивается зачем нужны четвертые сумматоры, если дробная часть не округляется, а отбрасывается? "Честный" код без integer и без округлений после синтеза занимает в 1.6 раз меньше места.
Sefo
Попробовали написать код без integer?
ZED
Попробовал, но не могу проверить (Quartus сломался) и не знаю, вообще так это делается или нет. Вот код:
Код
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity butterfly_complex is
    generic (b_size: natural := 16);
    
    port(CLK: in std_logic;
         x1_re: in std_logic_vector(b_size - 1 downto 0);
         x1_im: in std_logic_vector(b_size - 1 downto 0);
         x2_re: in std_logic_vector(b_size - 1 downto 0);
         x2_im: in std_logic_vector(b_size - 1 downto 0);
         x3_re: in std_logic_vector(b_size - 1 downto 0);
         x3_im: in std_logic_vector(b_size - 1 downto 0);
         x4_re: in std_logic_vector(b_size - 1 downto 0);
         x4_im: in std_logic_vector(b_size - 1 downto 0);        
        
         y1_re: out std_logic_vector(b_size - 1 downto 0);
         y1_im: out std_logic_vector(b_size - 1 downto 0);
         y2_re: out std_logic_vector(b_size - 1 downto 0);
         y2_im: out std_logic_vector(b_size - 1 downto 0);
         y3_re: out std_logic_vector(b_size - 1 downto 0);
         y3_im: out std_logic_vector(b_size - 1 downto 0);
         y4_re: out std_logic_vector(b_size - 1 downto 0);
         y4_im: out std_logic_vector(b_size - 1 downto 0)        
        );
end entity butterfly_complex;


architecture beh_butter of butterfly_complex is
-- Сигналы для конвертации типов std_logic -> signed:
signal x1_re_sig : signed(b_size + 2 downto 0);
signal x1_im_sig : signed(b_size + 2 downto 0);
signal x2_re_sig : signed(b_size + 2 downto 0);
signal x2_im_sig : signed(b_size + 2 downto 0);
signal x3_re_sig : signed(b_size + 2 downto 0);
signal x3_im_sig : signed(b_size + 2 downto 0);
signal x4_re_sig : signed(b_size + 2 downto 0);
signal x4_im_sig : signed(b_size + 2 downto 0);

signal y1_re_sum : signed(b_size + 2 downto 0);
signal y1_im_sum : signed(b_size + 2 downto 0);
signal y2_re_sum : signed(b_size + 2 downto 0);
signal y2_im_sum : signed(b_size + 2 downto 0);
signal y3_re_sum : signed(b_size + 2 downto 0);
signal y3_im_sum : signed(b_size + 2 downto 0);
signal y4_re_sum : signed(b_size + 2 downto 0);
signal y4_im_sum : signed(b_size + 2 downto 0);

signal y1_re_sig : signed(b_size - 1 downto 0);
signal y1_im_sig : signed(b_size - 1 downto 0);
signal y2_re_sig : signed(b_size - 1 downto 0);
signal y2_im_sig : signed(b_size - 1 downto 0);
signal y3_re_sig : signed(b_size - 1 downto 0);
signal y3_im_sig : signed(b_size - 1 downto 0);
signal y4_re_sig : signed(b_size - 1 downto 0);
signal y4_im_sig : signed(b_size - 1 downto 0);

begin
        x1_re_sig <= resize(SIGNED(x1_re), b_size + 3);
        x1_im_sig <= resize(SIGNED(x1_im), b_size + 3);
        x2_re_sig <= resize(SIGNED(x2_re), b_size + 3);
        x2_im_sig <= resize(SIGNED(x2_im), b_size + 3);
        x3_re_sig <= resize(SIGNED(x3_re), b_size + 3);
        x3_im_sig <= resize(SIGNED(x3_im), b_size + 3);
        x4_re_sig <= resize(SIGNED(x4_re), b_size + 3);
        x4_im_sig <= resize(SIGNED(x4_im), b_size + 3);
        
        -- Вычисление y1_re:
        y1_re_sum <= x1_re_sig + x2_re_sig + x3_re_sig + x4_re_sig + "0000000000000000100";
        
        -- Вычисление y1_im:
        y1_im_sum <= x1_im_sig + x2_im_sig + x3_im_sig + x4_im_sig + "0000000000000000100";

        -- Вычисление y2_re:
        y2_re_sum <= x1_re_sig + x2_im_sig - x3_re_sig - x4_im_sig + "0000000000000000100";

        -- Вычисление y2_im:
        y2_im_sum <= x1_im_sig - x2_re_sig - x3_im_sig + x4_re_sig + "0000000000000000100";

        -- Вычисление y3_re:
        y3_re_sum <= x1_re_sig - x2_re_sig + x3_re_sig - x4_re_sig + "0000000000000000100";

        -- Вычисление y3_im:
        y3_im_sum <= x1_im_sig - x2_im_sig + x3_im_sig - x4_im_sig + "0000000000000000100";

        -- Вычисление y4_re:
        y4_re_sum <= x1_re_sig - x2_im_sig - x3_re_sig + x4_im_sig + "0000000000000000100";

        -- Вычисление y4_im:
        y4_im_sum <= x1_im_sig + x2_re_sig - x3_im_sig - x4_re_sig + "0000000000000000100";
        
        y1_re_sig(b_size - 1 downto 0) <= y1_re_sum(b_size + 2 downto 3);
        y1_im_sig(b_size - 1 downto 0) <= y1_im_sum(b_size + 2 downto 3);
        y2_re_sig(b_size - 1 downto 0) <= y2_re_sum(b_size + 2 downto 3);
        y2_im_sig(b_size - 1 downto 0) <= y2_im_sum(b_size + 2 downto 3);
        y3_re_sig(b_size - 1 downto 0) <= y3_re_sum(b_size + 2 downto 3);
        y3_im_sig(b_size - 1 downto 0) <= y3_im_sum(b_size + 2 downto 3);
        y4_re_sig(b_size - 1 downto 0) <= y4_re_sum(b_size + 2 downto 3);
        y4_im_sig(b_size - 1 downto 0) <= y4_im_sum(b_size + 2 downto 3);
        

process (CLK)
begin
    if (rising_edge(CLK)) then

        -- Вычисление y1_re:
        
        y1_re_sum <= CONV_STD_LOGIC_VECTOR(y1_re_sig, b_size);

        -- Вычисление y1_im:
        y1_im_sum <= CONV_STD_LOGIC_VECTOR(y1_im_sig, b_size);

        -- Вычисление y2_re:
        y2_re_sum <= CONV_STD_LOGIC_VECTOR(y2_re_sig, b_size);

        -- Вычисление y2_im:
        y2_im_sum <= CONV_STD_LOGIC_VECTOR(y2_im_sig, b_size);

        -- Вычисление y3_re:
        y3_re_sum <= CONV_STD_LOGIC_VECTOR(y3_re_sig, b_size);

        -- Вычисление y3_im:
        y3_im_sum <= CONV_STD_LOGIC_VECTOR(y3_im_sig, b_size);

        -- Вычисление y4_re:
        y4_re_sum <= CONV_STD_LOGIC_VECTOR(y4_re_sig, b_size);

        -- Вычисление y4_im:
        y4_im_sum <= CONV_STD_LOGIC_VECTOR(y4_im_sig, b_size);

    end if;
end process;

end beh_butter;
Sefo
Кроме того, что код оказался не компилируем, различных преобразований, все же, многовато smile.gif. С разрядностью тоже переборщили, хотя и всего на 1 разряд. По этой же причине (неправильная разрядность), видимо, Вы для округления прибавляете 4, вместо 2 - это приведет к неправильным вычислениям.

Разберемся с разрядностью. При сложении 4 чисел самое большое | маленькое, что мы можем получить это max(x)*4 | min(x)*4. Поскольку умножение на 4 есть не что иное как сдвиг влево на 2 разряда, то

1) переполнение при любых числах на входе БПФ не может превысить 2 разряда.
2) в обоих крайних случаях мы получим "00" в двух младших разрядах.

Из 1) и 2) следует, что разрядность сумы должна быть только лишь на 2 разряда больше, чем данные и для округления перед делением на 4 мы можем прибавить "000000000000000010" (т.е. 2) не опасаясь переполнения.

Для бабочки достаточно использования только std_logic_vector. Кстати, лучше нумеровать точки с 0. Вот код.

CODE

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

entity butterfly_complex is
generic (b_size: natural := 16);

port(CLK: in std_logic;
x0_re: in std_logic_vector(b_size-1 downto 0);
x0_im: in std_logic_vector(b_size-1 downto 0);
x1_re: in std_logic_vector(b_size-1 downto 0);
x1_im: in std_logic_vector(b_size-1 downto 0);
x2_re: in std_logic_vector(b_size-1 downto 0);
x2_im: in std_logic_vector(b_size-1 downto 0);
x3_re: in std_logic_vector(b_size-1 downto 0);
x3_im: in std_logic_vector(b_size-1 downto 0);

y0_re: out std_logic_vector(b_size-1 downto 0);
y0_im: out std_logic_vector(b_size-1 downto 0);
y1_re: out std_logic_vector(b_size-1 downto 0);
y1_im: out std_logic_vector(b_size-1 downto 0);
y2_re: out std_logic_vector(b_size-1 downto 0);
y2_im: out std_logic_vector(b_size-1 downto 0);
y3_re: out std_logic_vector(b_size-1 downto 0);
y3_im: out std_logic_vector(b_size-1 downto 0)
);
end entity butterfly_complex;

architecture beh_butter of butterfly_complex is

signal x0_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x0_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x1_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x1_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x2_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x2_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x3_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x3_im_sig : std_logic_vector(b_size-1 + 2 downto 0);

signal y0_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y0_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y1_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y1_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y2_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y2_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y3_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y3_im_sig : std_logic_vector(b_size-1 + 2 downto 0);

Begin --=======================================================

x0_re_sig <= (1 downto 0 => x0_re(b_size-1)) & x0_re;
x0_im_sig <= (1 downto 0 => x0_im(b_size-1)) & x0_im;
x1_re_sig <= (1 downto 0 => x1_re(b_size-1)) & x1_re;
x1_im_sig <= (1 downto 0 => x1_im(b_size-1)) & x1_im;
x2_re_sig <= (1 downto 0 => x2_re(b_size-1)) & x2_re;
x2_im_sig <= (1 downto 0 => x2_im(b_size-1)) & x2_im;
x3_re_sig <= (1 downto 0 => x3_re(b_size-1)) & x3_re;
x3_im_sig <= (1 downto 0 => x3_im(b_size-1)) & x3_im;

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

-- Вычисление y0
y0_re_sig <= x0_re_sig + x1_re_sig + x2_re_sig + x3_re_sig + 2;
y0_im_sig <= x0_im_sig + x1_im_sig + x2_im_sig + x3_im_sig + 2;

-- Вычисление y1
y1_re_sig <= x0_re_sig + x1_im_sig - x2_re_sig - x3_im_sig + 2;
y1_im_sig <= x0_im_sig - x1_re_sig - x2_im_sig + x3_re_sig + 2;

-- Вычисление y2
y2_re_sig <= x0_re_sig - x1_re_sig + x2_re_sig - x3_re_sig + 2;
y2_im_sig <= x0_im_sig - x1_im_sig + x2_im_sig - x3_im_sig + 2;

-- Вычисление y3
y3_re_sig <= x0_re_sig - x1_im_sig - x2_re_sig + x3_im_sig + 2;
y3_im_sig <= x0_im_sig + x1_re_sig - x2_im_sig - x3_re_sig + 2;

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

process (CLK)
begin
if (rising_edge(CLK)) then

y0_re <= y0_re_sig(b_size-1 + 2 downto 2);
y0_im <= y0_im_sig(b_size-1 + 2 downto 2);
y1_re <= y1_re_sig(b_size-1 + 2 downto 2);
y1_im <= y1_im_sig(b_size-1 + 2 downto 2);
y2_re <= y2_re_sig(b_size-1 + 2 downto 2);
y2_im <= y2_im_sig(b_size-1 + 2 downto 2);
y3_re <= y3_re_sig(b_size-1 + 2 downto 2);
y3_im <= y3_im_sig(b_size-1 + 2 downto 2);

end if;
end process;


end beh_butter;



Теперь идем дальше. 2-х точечная бабочка это всего лишь A+B и A-B. Как несложно видеть и то и другое со всеми входными данными и в разных комбинациях у нас есть в формулах 4-х Т.Б. (недаром же ее можновычислить через 2-х Т.Б. smile.gif). Учитывая, что у нас из памяти за такт вычитывается по 4 точки, то нам неплохо бы "выжать" из формул 4-х Т.Б. две 2-х Т.Б. В качестве входа для первой 2-х Т.Б. возьмем Х0 и Х1, а в для второй Х2 и Х3. Разумеется, на вход бабочки нужно добавить сигнал управления типом бабочки, а выходные регистры должны должны защелкивать соответствующий результат.

Дерзайте.
ZED
Пока на ум пришло только это:
Код
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity butterfly_complex is
generic (b_size: natural := 16);

port(CLK: in std_logic;
x0_re: in std_logic_vector(b_size-1 downto 0);
x0_im: in std_logic_vector(b_size-1 downto 0);
x1_re: in std_logic_vector(b_size-1 downto 0);
x1_im: in std_logic_vector(b_size-1 downto 0);
x2_re: in std_logic_vector(b_size-1 downto 0);
x2_im: in std_logic_vector(b_size-1 downto 0);
x3_re: in std_logic_vector(b_size-1 downto 0);
x3_im: in std_logic_vector(b_size-1 downto 0);

switch: in std_logic_vector;

y0_re: out std_logic_vector(b_size-1 downto 0);
y0_im: out std_logic_vector(b_size-1 downto 0);
y1_re: out std_logic_vector(b_size-1 downto 0);
y1_im: out std_logic_vector(b_size-1 downto 0);
y2_re: out std_logic_vector(b_size-1 downto 0);
y2_im: out std_logic_vector(b_size-1 downto 0);
y3_re: out std_logic_vector(b_size-1 downto 0);
y3_im: out std_logic_vector(b_size-1 downto 0)
);
end entity butterfly_complex;

architecture beh_butter of butterfly_complex is

signal x0_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x0_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x1_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x1_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x2_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x2_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x3_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x3_im_sig : std_logic_vector(b_size-1 + 2 downto 0);

signal y0_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y0_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y1_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y1_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y2_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y2_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y3_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y3_im_sig : std_logic_vector(b_size-1 + 2 downto 0);

Begin --=======================================================

x0_re_sig <= (1 downto 0 => x0_re(b_size-1)) & x0_re;
x0_im_sig <= (1 downto 0 => x0_im(b_size-1)) & x0_im;
x1_re_sig <= (1 downto 0 => x1_re(b_size-1)) & x1_re;
x1_im_sig <= (1 downto 0 => x1_im(b_size-1)) & x1_im;
x2_re_sig <= (1 downto 0 => x2_re(b_size-1)) & x2_re;
x2_im_sig <= (1 downto 0 => x2_im(b_size-1)) & x2_im;
x3_re_sig <= (1 downto 0 => x3_re(b_size-1)) & x3_re;
x3_im_sig <= (1 downto 0 => x3_im(b_size-1)) & x3_im;

--------------------------------------
if (switch = '0') then

-- Вычисление y0
y0_re_sig <= x0_re_sig + x1_re_sig + x2_re_sig + x3_re_sig + 2;
y0_im_sig <= x0_im_sig + x1_im_sig + x2_im_sig + x3_im_sig + 2;

-- Вычисление y1
y1_re_sig <= x0_re_sig + x1_im_sig - x2_re_sig - x3_im_sig + 2;
y1_im_sig <= x0_im_sig - x1_re_sig - x2_im_sig + x3_re_sig + 2;

-- Вычисление y2
y2_re_sig <= x0_re_sig - x1_re_sig + x2_re_sig - x3_re_sig + 2;
y2_im_sig <= x0_im_sig - x1_im_sig + x2_im_sig - x3_im_sig + 2;

-- Вычисление y3
y3_re_sig <= x0_re_sig - x1_im_sig - x2_re_sig + x3_im_sig + 2;
y3_im_sig <= x0_im_sig + x1_re_sig - x2_im_sig - x3_re_sig + 2;

--------------------------------------
else

-- Вычисление y0
y0_re_sig <= x0_re_sig + x1_re_sig + 1;
y0_im_sig <= x0_im_sig + x1_im_sig + 1;

-- Вычисление y1
y1_re_sig <= x0_re_sig - x1_im_sig + 1;
y1_im_sig <= x0_im_sig - x1_re_sig + 1;

-- Вычисление y2
y2_re_sig <= x2_re_sig + x3_re_sig + 1;
y2_im_sig <= x2_im_sig + x3_im_sig + 1;

-- Вычисление y3
y3_re_sig <= x2_re_sig - x3_im_sig + 1;
y3_im_sig <= x2_im_sig - x3_re_sig + 1;


process (CLK)
begin
if (rising_edge(CLK)) then
if (switch = '0') then
y0_re <= y0_re_sig(b_size-1 + 2 downto 2);
y0_im <= y0_im_sig(b_size-1 + 2 downto 2);
y1_re <= y1_re_sig(b_size-1 + 2 downto 2);
y1_im <= y1_im_sig(b_size-1 + 2 downto 2);
y2_re <= y2_re_sig(b_size-1 + 2 downto 2);
y2_im <= y2_im_sig(b_size-1 + 2 downto 2);
y3_re <= y3_re_sig(b_size-1 + 2 downto 2);
y3_im <= y3_im_sig(b_size-1 + 2 downto 2);
else
y0_re <= y0_re_sig(b_size-1 + 1 downto 1);
y0_im <= y0_im_sig(b_size-1 + 1 downto 1);
y1_re <= y1_re_sig(b_size-1 + 1 downto 1);
y1_im <= y1_im_sig(b_size-1 + 1 downto 1);
y2_re <= y2_re_sig(b_size-1 + 1 downto 1);
y2_im <= y2_im_sig(b_size-1 + 1 downto 1);
y3_re <= y3_re_sig(b_size-1 + 1 downto 1);
y3_im <= y3_im_sig(b_size-1 + 1 downto 2);
end if;
end process;


end beh_butter;
Sefo
"if" не может быть использован вне процесса. Этот код не компилируем.

Вне процесса можно A <= B when x = y else C;

Исправляйте. Либо поместите в процесс, либо примените конструкцию с when.

Еще однобитовый switch не может быть std_logic_vector smile.gif Максимум std_logic.
ZED
Цитата
"if" не может быть использован вне процесса. Этот код не компилируем.

Да точно, забыл...

Цитата
Вне процесса можно A <= B when x = y else C;

Да, но нескольким значениям значений не присвоишь, а жаль...

Цитата
Исправляйте. Либо поместите в процесс, либо примените конструкцию с when.

Выход только поместить в процесс...

Цитата
Еще однобитовый switch не может быть std_logic_vector smile.gif Максимум std_logic.

CTL+C CTL+V =)) Исправил, просинтезировать нет возможности...

Код
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity butterfly_complex is
generic (b_size: natural := 16);

port(CLK: in std_logic;
x0_re: in std_logic_vector(b_size-1 downto 0);
x0_im: in std_logic_vector(b_size-1 downto 0);
x1_re: in std_logic_vector(b_size-1 downto 0);
x1_im: in std_logic_vector(b_size-1 downto 0);
x2_re: in std_logic_vector(b_size-1 downto 0);
x2_im: in std_logic_vector(b_size-1 downto 0);
x3_re: in std_logic_vector(b_size-1 downto 0);
x3_im: in std_logic_vector(b_size-1 downto 0);

switch: in std_logic;

y0_re: out std_logic_vector(b_size-1 downto 0);
y0_im: out std_logic_vector(b_size-1 downto 0);
y1_re: out std_logic_vector(b_size-1 downto 0);
y1_im: out std_logic_vector(b_size-1 downto 0);
y2_re: out std_logic_vector(b_size-1 downto 0);
y2_im: out std_logic_vector(b_size-1 downto 0);
y3_re: out std_logic_vector(b_size-1 downto 0);
y3_im: out std_logic_vector(b_size-1 downto 0)
);
end entity butterfly_complex;

architecture beh_butter of butterfly_complex is

signal x0_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x0_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x1_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x1_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x2_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x2_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x3_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal x3_im_sig : std_logic_vector(b_size-1 + 2 downto 0);

signal y0_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y0_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y1_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y1_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y2_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y2_im_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y3_re_sig : std_logic_vector(b_size-1 + 2 downto 0);
signal y3_im_sig : std_logic_vector(b_size-1 + 2 downto 0);

Begin --=======================================================

x0_re_sig <= (1 downto 0 => x0_re(b_size-1)) & x0_re;
x0_im_sig <= (1 downto 0 => x0_im(b_size-1)) & x0_im;
x1_re_sig <= (1 downto 0 => x1_re(b_size-1)) & x1_re;
x1_im_sig <= (1 downto 0 => x1_im(b_size-1)) & x1_im;
x2_re_sig <= (1 downto 0 => x2_re(b_size-1)) & x2_re;
x2_im_sig <= (1 downto 0 => x2_im(b_size-1)) & x2_im;
x3_re_sig <= (1 downto 0 => x3_re(b_size-1)) & x3_re;
x3_im_sig <= (1 downto 0 => x3_im(b_size-1)) & x3_im;

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

process (CLK)
begin
if (rising_edge(CLK)) then
if (switch = '0') then

-- Вычисление y0
y0_re_sig <= x0_re_sig + x1_re_sig + x2_re_sig + x3_re_sig + 2;
y0_im_sig <= x0_im_sig + x1_im_sig + x2_im_sig + x3_im_sig + 2;

-- Вычисление y1
y1_re_sig <= x0_re_sig + x1_im_sig - x2_re_sig - x3_im_sig + 2;
y1_im_sig <= x0_im_sig - x1_re_sig - x2_im_sig + x3_re_sig + 2;

-- Вычисление y2
y2_re_sig <= x0_re_sig - x1_re_sig + x2_re_sig - x3_re_sig + 2;
y2_im_sig <= x0_im_sig - x1_im_sig + x2_im_sig - x3_im_sig + 2;

-- Вычисление y3
y3_re_sig <= x0_re_sig - x1_im_sig - x2_re_sig + x3_im_sig + 2;
y3_im_sig <= x0_im_sig + x1_re_sig - x2_im_sig - x3_re_sig + 2;

y0_re <= y0_re_sig(b_size-1 + 2 downto 2);
y0_im <= y0_im_sig(b_size-1 + 2 downto 2);
y1_re <= y1_re_sig(b_size-1 + 2 downto 2);
y1_im <= y1_im_sig(b_size-1 + 2 downto 2);
y2_re <= y2_re_sig(b_size-1 + 2 downto 2);
y2_im <= y2_im_sig(b_size-1 + 2 downto 2);
y3_re <= y3_re_sig(b_size-1 + 2 downto 2);
y3_im <= y3_im_sig(b_size-1 + 2 downto 2);

else

-- Вычисление y0
y0_re_sig <= x0_re_sig + x1_re_sig + 1;
y0_im_sig <= x0_im_sig + x1_im_sig + 1;

-- Вычисление y1
y1_re_sig <= x0_re_sig - x1_im_sig + 1;
y1_im_sig <= x0_im_sig - x1_re_sig + 1;

-- Вычисление y2
y2_re_sig <= x2_re_sig + x3_re_sig + 1;
y2_im_sig <= x2_im_sig + x3_im_sig + 1;

-- Вычисление y3
y3_re_sig <= x2_re_sig - x3_im_sig + 1;
y3_im_sig <= x2_im_sig - x3_re_sig + 1;

y0_re <= y0_re_sig(b_size-1 + 1 downto 1);
y0_im <= y0_im_sig(b_size-1 + 1 downto 1);
y1_re <= y1_re_sig(b_size-1 + 1 downto 1);
y1_im <= y1_im_sig(b_size-1 + 1 downto 1);
y2_re <= y2_re_sig(b_size-1 + 1 downto 1);
y2_im <= y2_im_sig(b_size-1 + 1 downto 1);
y3_re <= y3_re_sig(b_size-1 + 1 downto 1);
y3_im <= y3_im_sig(b_size-1 + 1 downto 2);
end if;
end if;
end process;


end beh_butter;
Sefo
Когда у Вас будет возможность просинтезировать код? Потому что мы подошли к самому интересному - во что Квартус превращает наш код и как его заставить сделать то, что нам нужно.

Попробуйте просинтезировать Квартусом простое выражение (в отдельном проекте) R = A+B+1 (или R = A+B+'1'), где R,A и B есть std_logic_vector(15 downto 0) и посмотрите в RTL Viewer что получилось.

Как Вы думаете, что должно было получиться, если бы Квартус был бы "умнее"? Какую стандартную операцию представляет из себя выражение A+B+1?
ZED
Квартус синтезирует 2 сумматора, на вход одного из которых подана единица. Операция должна быть округлением...
Sefo
Вот это-то и плохо. У нас обычное суммирование с переносом. A+B+carry - это полный сумматор. Это мы его используем для округления, а еще такой сумматор используется для вычисления суммы чисел на нескольких полных сумматорах, когда разрядность самих чисел больше разрядности сумматора. Самое обидное, что ячейки ПЛИС все это позволяют. Если запустить Квартусовский Мегавизард, то Вы найдете там сумматор со входом переноса, который при синтезе будет занимать ровно столько ячеек, сколько разрядов и ни одной больше. А на наш код он ставит аж 2 сумматора!

К сожалению, Квартус не отличается хорошей оптимизацией математических выражеий. Если он видит два '+' он ставит 2 сумматора.

Есть идеи, как его заставить реализовать A+B+1 на одном сумматоре в VHDL, не прибегая к использованию его мегафункций?
ZED
Если только самому как-то описывать полный сумматор, а так идей нету.
Sefo
Извиняюсь за длительную паузу. Прием очень простой. Если обоим операндам приписать по одному разряду справа равному '1', то при сложении неизбежно образуется перенос, который сложится со младшим разрядом (точнее, бывшим младшим разрядом) суммы, а т.к. результат самого сложения двух констант, равных '1' никогда использоваться не будет, то Квартус в процессе оптимизации эту ячейку удалит. Да даже если и не удалит, то такой "довесок" в n раз меньше, чем второй сумматор на n разрядов.

signal A : std_logic_vector(n-1 downto 0);
signal B : std_logic_vector(n-1 downto 0);

signal SUM : std_logic_vector(n-1 downto 0); -- SUM = (A + B + 1);

Объявляем промежуточный сигна на один разряд больше.

signal S std_logic_vector(n downto 0);

Тогда

S <= (A & '1') + (B & '1');

SUM <= S(n downto 1);

Кстати, к A+B+m, где m > 1 описанный прием уже не применить.

Предлагаю Вам с этим немного поэкспериментировать на досуге.

Идем дальше. К сожалению, все вышесказанное (не только конкретно в этом сообщении) про сложение не работает для вычитания. Для A-B+1 придется ставить 2 сумматора.
Кроме того, в отличие от A+B, A-B уже не гарантирует '0' в младшем разряде в крайних случаях. Для сложения крайние случаи это когда оба слагаемых либо максимальны, либо минимальны, а для вычитания – когда одна переменная имеет максимальное значение, а другая минимальное. А поскольку '0' не гарантирован, то при отбрасывании младшего разряда при сдвиге вправо ничего страшного не произойдет, а вот при округлении (т.е. прибавлении 1 перед сдвигом) результат может переполнится больше чем на 1 разряд по сравнению с разрядностью исходных переменных.
Пример:
( (-32768) – (32767) + 1 ) >> 1 = (-65535 + 1) >> 1 = -65534 >> 1 = -32767 все в порядке - разность переполнилась на один "законный" разряд, после сложения переполнения не произошло и после деления на 2 все вернулось обратно к 16-ти разрядам.
Теперь другой пример:
( (32767) – (-32768) + 1 ) >> 1 = (65535 + 1) >> 1 = -65536 >> 1 = -32768 фигня получилась - разность переполнилась на один "законный" разряд, а после добавления 1 переполнилась еще раз, превратившись в отрицательное число.
Такое поведение вычитания обусловлено как раз несимметричностью дополнительного кода – модуль максимального числа на 1 меньше модуля минимального. При вычитании, так скажем, самого отрицательного числа smile.gif оно меняет знак, станивится положительным и... для его представления нужно уже на 1 разряд больше т.к. оно становится всего на единицу больше максимального положительного числа.

Какие отсюда следуют выводы?

1) избавиться от лишних сумматоров нам удасться лишь для y0_re и y0_im (для случая 2-х Т.Б. еще и y2), где у нас сплошное суммирование. С этим должно быть все понятно.

2) при вычислении y1,2,3 у нас может возникнуть переполнение. Тут нужно учесть, что локально увеличить разрядность мы не можем т.к. это переполнение не устраняется делением на 4 или 2.

Есть 2 варианта:

Первый, увеличить разрядность данных повсеместно на 1 и расширить диапазон значений только на нехватающую 1 т.е. 16-ти разрядные данные сделать 17-ти разрядными, а диапазон сделать от -32768 до +32768. Этот способ очень прост т.к. достаточно 16-ти разрядные данные АЦП расширить знаком до 17-ти разрядных и все.

Второй, это на выходе из АЦП заменять -32768 на 32767. Не очень "честно", но если сохранять разрядность, то "честно" все равно не получится, а резать в бабочке гораздо более затратно по ресурсам ПЛИС.

Что касается оптимизации сумматоров в бабочке, то предлагаю ее сейчас не делать чтобы сохранить легкость чтения кода – этим можно заняться потом. Главное, что на ее примере Вы увидели где и как можно экономить.

Что касается переполнения, то выбирайте, увеличим разрядность или срежем на выходе АЦП?

Вопросы есть?
ZED
Прошу прощения, что долго не отвечал, просто по учебе загрузили, надеюсь все к среде разрулить и вплотную заняться делом!
Sefo
Ну как, разрулили?
ZED
Да, спасибо, разрулил более менее, надеюсь еще какое-то время меня трогать не будут=))

Да, вопросы есть:

1. Не совсем понятно , что значит "локально увеличить разрядность". Это имеется ввиду в ПЛИС resize?

2. Почему бы в ПЛИС не сделать так:

Код
signal A : std_logic_vector(n-1 downto 0);
signal B : std_logic_vector(n-1 downto 0);
signal SUM_buf : std_logic_vector(n downto 0);
signal SUM : std_logic_vector(n downto 0);

SUM_buf <= resize(A, n+1) -  resize(B, n+1)
SUM <= SUM_buf(n downto 1);
Sefo
1) Локально, это имеется ввиду внутри бабочки. В случае (A+B+C+D)/4 с округлением (т.е. (A+B+C+D+2) >> 2) мы можем (и делаем) объявить внутри бабочки сигналы A_ B_ C_ D_ с разрядностью на 2 больше, чем A,B,C,D. Складываем их, прибавляем 2 (для округления) и отбросываем 2 младших разряда (т.е. /4). В этом случае, выполнив все необходимые операции, мы снова возвращаемся к разрядности такой же как и у A,B,C,D. У нас на входе разрядность n, внутри бабочки разрядность n+2, а на выходе опять n. И при этом мы нигде ничего не реряем. При наличие вычитания, если мы не будем округлять, а просто отбрасывать 2 младших разряда, то мы тоже ничего не потеряем и разрядность результата будет такая же как и разрядность входных данных. Но при наличие вычитания и желания проделать операции с округлением результата мы в некоторых случаях сможем получить результат (именно конечный результат), для представления которого нам не хватит разрядности такой же как и у входных данных - нам потребуется на один разряд больше. (см пример в пред. сообщении) Т.е. выход будет на один разряд больше ==> выход умножителей придется сделать на 1 разряд больше ==> разрядность памяти придется увеличить на 1 разряд ==> вход бабочки тоже увеличится на 1 разряд - круг замкнулся т.к. наши данные во время вычисления БПФ "гуляют" по кругу.

2)Так как Вы написали - это (A-cool.gif/2 без округления (т.е. (A-cool.gif>>1), а Вы в бабочке округляете (т.е. (A-B+1)>>1). Я же ведь даже конкретный пример привел - просимулируйте.


Теперь понятно?

На всякий случай повторю - не делай мы в бабочке округления при делении на 4 никаких проблем бы не было.
Azatot
Господа,так ведь же есть уже готовые БПФ ядра и у Xilinx, и у Altera. Лично пользуюсь Xilinx ядром, вроде, не плохо получается. В своем проекте мы вешаем на вход АЦП и потоком гоняем 1024 точки.
Sefo
В данном случае преследуются учебные цели. Понятно, что для работы, если есть готовое IP и, к тому же, бесплатно, то глупо им не воспользоваться. Но для ПЛИС довольно много полезных и бесплатных IP, вроде БПФ, включено в состав средств разработки, а если ASIC надо делать? Увы, для ASIC IP задорма никто не дает. Я вот, однажды делал БПФ для ASIC. Там нужна была небольшая постобработка результатов их анализ и формирование выборок из спектра по заданным критериям - большую чать этого довеска удалось встроить прямо в последнюю стадию БПФ и задействовав вычислительные ресурсы самого БПФ. Получился существенный выигрыш и по быстродействию и площадь здорово сэкономили. С покупным IP так удачно не получилось бы.

В общем, надо пользоваться готовым IP там, где это можно, но хороший инженер должен уметь реализовать это IP и сам.

Так что я очень поддерживаю желание ZEDa собрать свой собственный "велосипед" свомим руками.
ZED
Ну я так и имел ввиду:

Код
signal A : std_logic_vector(n-1 downto 0);
signal B : std_logic_vector(n-1 downto 0);
signal SUM_buf : std_logic_vector(n downto 0);
signal SUM : std_logic_vector(n downto 0);

SUM_buf <= resize(A, n+1) -  resize(B, n+1) + '1'
SUM <= SUM_buf(n downto 1);


resize расширяет число знаковым разрядом, соответственно при сложении/вычитании 4 отсчетов resize(OTSCHOT, n+2), а потом отбрасываем.

Понятно, спасибо, в том числе и за поддержку.
Sefo
Теперь мне не очень понятно, поняли ли Вы меня правильно. smile.gif

Код

CODE
signal A : std_logic_vector(n-1 downto 0);
signal B : std_logic_vector(n-1 downto 0);
signal SUM_buf : std_logic_vector(n downto 0);
signal SUM : std_logic_vector(n-1 downto 0);

SUM_buf <= resize(A, n+1) - resize(B, n+1) + '1'
SUM <= SUM_buf(n downto 1);


в случае A = (2^n)-1 и B = -(2^n) даст неверный результат.

Вы симулировать пробовали? Если да, то выложите полный проект, чтобы было видно как именно Вы это делали. Если нет, то просимулируйте... и выложите полный проект, чтобы было видно как именно Вы это делали smile.gif
ZED
Чего-то не симулируется, квартус лагает, вот проект:
Код
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity summator is
    generic (b_size: natural := 16
             );
    
    port(A: in std_logic_vector(b_size - 1 downto 0);
         B: in std_logic_vector(b_size - 1 downto 0);
         SUM: out std_logic_vector(b_size - 1 downto 0)
        );
end entity summator;


architecture beh_summator of summator is

signal A_sig : std_logic_vector(b_size downto 0);
signal B_sig : std_logic_vector(b_size downto 0);
signal SUM_buf : std_logic_vector(b_size downto 0);

begin
A_sig <= (0 => A(b_size-1)) & A;
B_sig <= (0 => B(b_size-1)) & B;
SUM_buf <= A_sig - B_sig + '1';
SUM <= SUM_buf(b_size downto 1);

end beh_summator;
Sefo
Что значит не симулируется? Под проектом я понимаю все квартусовские файлы.
ZED
Цитата
Что значит не симулируется?

Временная диаграмма не работает - выдает одни иксы: XXXXXXX и т.д. Что-то с Квартусом или компом, я его стабильно раз в неделю переставляю. А может и я что-то не так делаю...
Проект прикрепляю.
Sefo
biggrin.gif Вы просто не тот файл смотрите. Результаты симуляции лежат в каталоге db\ и называется файл summator.sim.vwf. Вообще-то этот файл Квартус Вам должен был сам показать по окончании симуляции в одном из окон репорта. Если Вы в этом файле измените формат отображения для SUM с Binary на Signed Decimal, то Вы увидите, что результат = -32768, что неверно.
sazh
Цитата(ZED @ Mar 21 2009, 23:12) *
Временная диаграмма не работает - выдает одни иксы: XXXXXXX и т.д. Что-то с Квартусом или компом, я его стабильно раз в неделю переставляю. А может и я что-то не так делаю...
Проект прикрепляю.


Если я что то и переставляю, так это новую версию Квартуса. Чего и вам желаю.
А выдавать неопределенности (при функционале) он может, если только галочка не стоит на опции Overwrite.....
Иначе cмотрите в опции report.
Что касается Вашего сумматора, ничего сказать не могу. Потому что текст не понимаю (понятно только, что он не правильно работает. А в своих библиотеках сами копайтесь.


Цитата(Sefo @ Mar 22 2009, 11:35) *
biggrin.gif Вы просто не тот файл смотрите. Результаты симуляции лежат в каталоге db\ и называется файл summator.sim.vwf. Вообще-то этот файл Квартус Вам должен был сам показать по окончании симуляции в одном из окон репорта. Если Вы в этом файле измените формат отображения для SUM с Binary на Signed Decimal, то Вы увидите, что результат = -32768, что неверно.


Интересно, в каком семестре мы подойдем к изучению умножителей.
Иль дайте есть, иль ешьте сами.
ZED
Вот, что у меня получилось:
Sefo
Цитата(sazh @ Mar 22 2009, 13:20) *
Если я что то и переставляю, так это новую версию Квартуса. Чего и вам желаю.
А выдавать неопределенности (при функционале) он может, если только галочка не стоит на опции Overwrite.....
Иначе cмотрите в опции report.
Что касается Вашего сумматора, ничего сказать не могу. Потому что текст не понимаю (понятно только, что он не правильно работает. А в своих библиотеках сами копайтесь.

Интересно, в каком семестре мы подойдем к изучению умножителей.
Иль дайте есть, иль ешьте сами.


А можно поинтересоваться, с чего вдруг вы тут это "ляпнули"? Как-то очень не впопад smile.gif

Цитата(sazh @ Mar 22 2009, 13:20) *
Что касается Вашего сумматора, ничего сказать не могу. Потому что текст не понимаю (понятно только, что он не правильно работает. А в своих библиотеках сами копайтесь.


Не понимаю, чего Вы так възелись на сумматор? Не хотите, не разбирайтесь - я же от Вас этого не требую... и даже не прошу этого делать! smile.gif

Цитата(sazh @ Mar 22 2009, 13:20) *
Интересно, в каком семестре мы подойдем к изучению умножителей.


Мне интересно, а Вам-то какая разница? Да, с бабочкой (точнее с ее вычитателями) несколько затянулось, но ведь задача стоит разобраться, а не как можно скорее получить код БПФ.

Цитата(sazh @ Mar 22 2009, 13:20) *
Иль дайте есть, иль ешьте сами.


Что Вы имеете ввиду?

--------- Для всех кто читает эту тему ----------

Еще раз повторяю, эта тема преследует исключительно учебные цели.

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

Если Вы без труда можете написать БПФ, но не хотите поделиться этим знанием с теми, кто еще только начинает, если БПФ Вам не нужно/неинтересно, если Вас раздражает, что кому-то могут быть непонятны вещи, которые по вашему мнению являются элементарными, то Вам действительно нет никакого смысла читать эту тему (и уж тем более что-то сюда писать). Вы не найдете здесь ничего интересного.



Цитата(ZED @ Mar 22 2009, 13:48) *
Вот, что у меня получилось:


Теперь Вам понятно, почему при (A+B +1) >> 1 результат всегда занимает столько же разрядов, сколько операнды, а при (A-B+1) >> 1 результат может потребовать для хранения на один разряд больше, чем сами операнды?

На всякий случай привожу правильный код вычитателя.

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

entity subtractor is
generic (b_size: natural := 16
);

port(A: in std_logic_vector(b_size - 1 downto 0);
B: in std_logic_vector(b_size - 1 downto 0);
SUM: out std_logic_vector(b_size downto 0)
);
end entity subtractor;


architecture beh_subtractor of subtractor is

signal A_sig : std_logic_vector(b_size + 1 downto 0);
signal B_sig : std_logic_vector(b_size + 1 downto 0);
signal SUM_buf : std_logic_vector(b_size + 1 downto 0);

begin
A_sig <= (1 downto 0 => A(b_size-1)) & A;
B_sig <= (1 downto 0 => B(b_size-1)) & B;
SUM_buf <= A_sig - B_sig + '1';
SUM <= SUM_buf(b_size + 1 downto 1);

end beh_subtractor;
ZED
Да, но результат суммирования теперь увеличился на один разряд, я так понимаю, что полное окуругление мы произведем после умножения?
Sefo
Все-таки, Вы не поняли. sad.gif

Округление мы уже произвели. Собственно, из-за него и приходится увеличить разрадность сигнала для хранения результата на 1.

Вы в каком городе живете?
ZED
В Москве.
Просто вы писали:
Цитата
В случае (A+B+C+D)/4 с округлением (т.е. (A+B+C+D+2) >> 2) мы можем (и делаем) объявить внутри бабочки сигналы A_ B_ C_ D_ с разрядностью на 2 больше, чем A,B,C,D. Складываем их, прибавляем 2 (для округления) и отбросываем 2 младших разряда (т.е. /4). В этом случае, выполнив все необходимые операции, мы снова возвращаемся к разрядности такой же как и у A,B,C,D. У нас на входе разрядность n, внутри бабочки разрядность n+2, а на выходе опять n. И при этом мы нигде ничего не реряем.

Т.е. на выходе бабочки должна быть разрядность такая как и на входе.

Но тут же вы писали:
Цитата
Но при наличие вычитания и желания проделать операции с округлением результата мы в некоторых случаях сможем получить результат (именно конечный результат), для представления которого нам не хватит разрядности такой же как и у входных данных - нам потребуется на один разряд больше. (см пример в пред. сообщении) Т.е. выход будет на один разряд больше ==> выход умножителей придется сделать на 1 разряд больше ==> разрядность памяти придется увеличить на 1 разряд ==> вход бабочки тоже увеличится на 1 разряд - круг замкнулся т.к. наши данные во время вычисления БПФ "гуляют" по кругу.


Вот меня это и поставило в тупик будет ли у нас увеличиваться разрядность на каждом этапе?

И возникает вопрос стоит ли округление таких затрат?
Sefo
Видимо, словами "круг замкнулся" я Вас запутал.

Разрядность бабочки у нас не будет увеличиваться на каждом этапе.

Я пытался объяснить, что при наличие вычитания в операциях бабочки с округлением потребует от нас повсеместного (т.е. в каждом блоке, но не на каждом этапе ! ) увеличения разрядности на 1 поскольку диапазон значений данных с АЦП от -32768 до +32767, а при вычислениях БПФ диапазон результатов будет от -32768 до +32768 ( независимо от этапа). Такой диапазон чисел для представления требует не 16, а 17 разрядов.

Забегая вперед, кроме бабочки, в умножителе, когда -32768 Вы умножите на -1.0, то получите +32768 - это число для представления требует опять таки 17 разрядов (как видите, даже если убрать округление в бабочке, то нам все равно не избежать этой проблемы в умножителях).

Из-за этого нам нужно либо исключить число -32768 из входного потока данных с АЦП (тогда при любых вычислениях БПФ мы никогда не получим +32768 - т.е. будем всегда иметь диапазон от -32767 до +32767) либо сделать 17-ти разрядные шины данных, чтобы по ним можно было бы "гонять" +32768.

Надеюсь, теперь все встало на свои места.

Если нет, то тогда могу только предложить созвониться и обсудить это по телефону (я в Питере)- иначе мы еще долго с этим будем возиться.
ZED
Все вроде понял, т.е. мы сразу после АЦП добавляем знаковыми разрядами до 17 разрядов и гоним в паямть с 17 разрядными словами и уже работаем с 17 разрядными данными.
Sefo
Да. cheers.gif

Ура! Ттеперь можно перейти к умножителям. smile.gif

Вы хотели на коэффициенты заложить 12 разрядов. У коэффициентов БПФ диапазон Re и Im частей от -1.0 до +1.0. Как Вы думаете, какое 12-ти разрядное число лучше поставить в соответствовие -1.0 и какое в соответствие +1.0? И почему?

Опыт бабочки должен Вам помочь.
ZED
1.0 это 2047

-1.0 это -2047

Чтобы не увеличивать разрядность:

Цитата
Забегая вперед, кроме бабочки, в умножителе, когда -32768 Вы умножите на -1.0, то получите +32768 - это число для представления требует опять таки 17 разрядов (как видите, даже если убрать округление в бабочке, то нам все равно не избежать этой проблемы в умножителях).
Sefo
Давайте пока так начнем. Впроцессе реализации сами догадаетесь, почему это не самый лучший вариант. Хотя так тоже можно. Кстати, надеюсь, что написав
Цитата
Чтобы не увеличивать разрядность

Вы имели ввиду разрядность коэффициентов.

Все данные с бабочки мы направим на блок комплексных умножителей. В этом блоке будет 4 умножителя, один из которых всегда умножает на (1.0 + j0). Такой подход удобен т.к. все данные (все 4 точки) идут единым путем и каждый блок нашего БПФ сам заботится о том, чтобы одни данные не "отстали"/"опередили" другие.

Итак:

1) жду от Вас код блока комплексных умножителей

2) код самого комплексного умножителя.
ZED
Вот комплексный перемножитель, не знаю правильно ли я все сделал, но вроде умножает=))
Sefo
Хорошо. Код внимательно посмотрю завтра - навскидку, вместо

CODE
entity complex_multiplier is
generic (b_size: natural := 17;
w_size: natural := 12
);
port (
y_re: in std_logic_vector(b_size downto 0);
y_im: in std_logic_vector(b_size downto 0);
...


наверное должно было быть

CODE
entity complex_multiplier is
generic (b_size: natural := 17;
w_size: natural := 12
);
port (
y_re: in std_logic_vector(b_size-1 downto 0);
y_im: in std_logic_vector(b_size-1 downto 0);
...


Присланное закрывает пункт 2, а что с пунктом 1 ? Где блок умножителей согласно блоксхеме?
Sefo
Цитата(ZED @ Mar 24 2009, 18:32) *
вроде умножает=))


Я Вас попрошу серьезнее относиться к результатам симуляции. Ни черта он у Вас не умножает.

Результат должен был быть 58593 + j 0, а у Вас в 2 раза меньше.

Вопрос на засыпку - Вы уже на нем засыпались smile.gif, но теперь, надеюсь, ответите правильно:

Чему равна разрядность произведения двух знаковых чисел, если разрядость одного числа n, а другого k?
ZED
Цитата
Чему равна разрядность произведения двух знаковых чисел, если разрядость одного числа n, а другого k?


n+k

Вот, теперь выдает то, что нужно...
Блок умножителей я так понимаю лучше сделать компонентами...

А вот вроде как блок, не знаю то или не то, голова уже не работает, вроде по RTL 4 комплексных перемножителя в одном блоке...
Sefo
Цитата(ZED @ Mar 25 2009, 20:23) *
n+k


Не угадали. smile.gif n+k это для беззнаковых операндов. А для знаковых чуть-чуть иначе. Ну, подумайте же как следует!
ZED
По-моему что для знаковых, что для беззнаковых произведение будет размерности n+k, только для знаковых старшие два разряда знаковые. Если вы это имеете ввиду, то можно сказать, что для знаковых размерность будет n + k -1.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.