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


Не стоит так интерпретировать. Дополнительный код подразумевает только один знаковый разрад. Да и то, знаковым его называют только для удобства.

Формат числа с разрядами от X(0) до X(n-1) включительно в дополнительном коде такой

(-(2^(n-1))*X(n-1) + (2^(n-2))*X(n-2) + ... (2^1)*X(1) + (2^0)*X(0).

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

И "расширение знаком" это очень условное название - это не значит, что после расширения знаком у Вас в числе стало n знаковых разрядов smile.gif

Если следовать вашей логике, то формат результата умножения 2-х знаковых чисел получается такой

(-(2^(n+k-1)))*X(n+k-1) - (2^(n+k-2))*X(n+k-2) + ... (2^1)*X(1) + (2^0)*X(0). Надеюсь очевидно, к чему это приведет smile.gif




Опишите, пожалуйста, математическим выражением то, что делают ваши умножители. Попробуйте подставить в эту формулу значение, которое Вы выбрали в качестве 1.0 (т.е. 2047) и проанализируйте, что же получается не совсем честно и какую интерпретацию это имеет с точки зрения БПФ?
ZED
Честно говоря я не совсем понял, в дополнительном коде для числа с разрядностью n:

модуль числа:
(2^(n-2))*X(n-2) + (2^(n-3))*X(n-3) + ... +(2^1)*X(1) + (2^0)*X(0);

X(n-1) - знаковый разряд;

знак числа:
0 - если число положительное;
1- если число отрицательное.

Кроме того для отрицательных чисел все X(n-2) ... X(0) инвертируются и к получившемуся числу прибавляют один.

Расширение знаком предполагает, знак представляют два разряда, например расширим число на один знаковый разряд, тогда разрядность увеличивается на 1 и становится n+1:

X(n) и X(n-1) - знаковые разряды;

знак числа:
00 - если число положительное;
11- если число отрицательное.
Для отрицательных чисел все остается по-прежнему: все X(n-2) ... X(0) инвертируются и к получившемуся числу прибавляют один.
Джеймс
Цитата
Sefo

Как Вы думаете, какое 12-ти разрядное число лучше поставить в соответствовие -1.0 и какое в соответствие +1.0


Цитата
ZED

1.0 это 2047

-1.0 это -2047


Сорри, я всю ветку не читал, но это место бросилось в глаза. Диапазон -1 ... +1 представить нельзя. Можно представить только -1 ... (1-1LSB).
-1 = 0x800
0 = 0
(1-1LSB) = 0x7FF
Sefo
Цитата(Джеймс @ Mar 28 2009, 14:32) *
Сорри, я всю ветку не читал, но это место бросилось в глаза. Диапазон -1 ... +1 представить нельзя. Можно представить только -1 ... (1-1LSB).
-1 = 0x800
0 = 0
(1-1LSB) = 0x7FF


Тут Вы не правы. Если Вы берете 12-ти разрядное знаковое число, то Вы не сможете в -1...1 представить как -2048 ... +2048 т.к. у знакового 12-ти разрядного числа диапазон значений -2048 ... 2047, но Вам совершенно никто не мешает принять за -1 -2047, а за +1 +2047. Равно как и представить -1 ... +1 диапазоном -2000 ... +2000. Такой выбор имеет некоторые "неудобства", но он ничему не противоречит. (про неудобства мы поговорим позже - я бы предпочел, чтобы ZED сам их увидел). Вас никто не обязывает использовать весь диапазон значений 12-ти разрядного числа для представления диапазона от -1.0 до +1.0.

Цитата(ZED @ Mar 28 2009, 11:51) *
модуль числа:
(2^(n-2))*X(n-2) + (2^(n-3))*X(n-3) + ... +(2^1)*X(1) + (2^0)*X(0);

X(n-1) - знаковый разряд;

знак числа:
0 - если число положительное;
1- если число отрицательное.

Кроме того для отрицательных чисел все X(n-2) ... X(0) инвертируются и к получившемуся числу прибавляют один.

Расширение знаком предполагает, знак представляют два разряда ...


sad.gif Да... Вы меня не на шутку огорчили... Придется с дополнительным кодом, да и вообще со способами представления чисел разобраться.

Пока почитайте вот это http://en.wikipedia.org/wiki/Two's_complement (только именно эту статью на английском - аналогичная на русском языке полная фигня) Вечером постараюсь прокомментировать все ваши заблуждения относительно двух знаковых разрядов и пр.

Любопытно стало где Вы учитесь и на какую специальность?
ZED
Я учусь в МЭИ на радиотехника, с вычислилкой туговато, дают общее представление а так вертись как хочешь. Вот так учили, все приходится осваивать самому. я понимаю, со мной очень трудно, но у меня есть желание учиться и спасибо таким людям, как вы, которые помогают разобраться с реальными проблемами на практике... Этого очень не хватает, когда учишься все просто, но кода дело доходит до реализации тут то все и начинается. Я понимаю, что у меня специальность не вычислительная техника или что-то подобное, но мне очень хочется разобраться, для меня это важно... Не сердитесь, просто нам так преподносили материал и мы так привыкли его воспринимать.
Sefo
Прошу прощения, но вынужден взять таймаут до вторника. Пока постарайтесь разобраться по статье википедии. Вопросы по ней можете пока записать здесь... Во вторник продолжим.

P.S. Если Вам так про дополнительный код читали, то преподу жирная 2 с минусом. smile.gif
ZED
Я прочитал статью, ну да знак представляется самым старшим битом.

Я просто не правильно выразился:
Цитата
Расширение знаком предполагает, знак представляют два разряда ...

Знак то представляет по-прежнему один разряд - старший:
Но расширение - это просто добавление справа чисел, тех же , что и знак, т.е.:

(-5)10 это (1011)2

А если расширить до 8 бит:

(-5)10 это (1111 1011)2

Но при перемножении чисел с разрядностями n и k все равно вначале получаем (n+k) битное число. Вопрос только сколько бит мы оставляем при округлении не так ли?
Sefo
lol.gif Не могу понять, что именно меня сбило с толку, но я сам попался на "знаковом разряде" lol.gif Позор! Позор на мою голову! crying.gif maniac.gif

Конечно же в общем случае разрядность результата умножения n+k.

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

Ну ничего, сейчас все расставим по местам.

Я Вас просил
Цитата
Опишите, пожалуйста, математическим выражением то, что делают ваши умножители. Попробуйте подставить в эту формулу значение, которое Вы выбрали в качестве 1.0 (т.е. 2047) и проанализируйте, что же получается не совсем честно и какую интерпретацию это имеет с точки зрения БПФ?


Сделайте это, пожалуйста, оно-то нам и поможет во всем разобраться.
ZED
Я не совсем понял, что значит описать математическим выражением то, что делают умножители, имеется в виду описать с помощью частичных произведений и сложений со сдвинутыми множимыми?
Sefo
Например выход y0_re бабочки = (x0_re + x1_re + x2_re + x3_re + 2)/4.

Примерно также распишите выражение конкретно для вашего комплексного умножителя и проанализируйте.
ZED
Видим о это будет как-то так:

result_re <= (y_re_sig*w_re_sig - y_im_sig*w_im_sig + '1')/4096;
result_im <= (y_re_sig*w_im_sig + y_im_sig*w_re_sig + '1')/4096;
Sefo
Непонятно откуда взялось 4096 - последней версии умножителя это число не соответствует. Должно быть другое. Также непонятно откуда появилось + '1' - в коде умножителя этого нет.

Замените 4096 на правильное, уберите + '1' и
Цитата
Попробуйте подставить в эту формулу значение, которое Вы выбрали в качестве 1.0 (т.е. 2047) и проанализируйте, что же получается не совсем честно и какую интерпретацию это имеет с точки зрения БПФ?
ZED
result_re <= (y_re_sig*w_re_sig + y_im_sig*w_im_sig)/2048;
result_im <= (y_re_sig*w_im_sig - y_im_sig*w_re_sig)/2048;



Деление на 2048 - это сдвиг на 11 разрядов или что эквивалентно берем старшие 17 и отбрасываем 12 младших...



result_re <= (y_re_sig*w_re_sig + y_im_sig*w_im_sig)/2048;
result_im <= (y_re_sig*w_im_sig - y_im_sig*w_re_sig)/2048;



Деление на 2048 - это сдвиг на 11 разрядов или что эквивалентно берем старшие 17 и отбрасываем 12 младших...
Sefo
А вот теперь непонятно, откуда Вы взяли 2048 в формуле для коэффициентов? Вы же сами решили, что диапазон -1.0 ... +1.0 мы представляем числами -2047 ... +2047!

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

С диапазонам данных у Вас тоже бардак! У Вас с АЦП идут знаковые 16-ти разрядные данные, которые мы расширяем знаком до 17-ти разрядных. Делаем мы это для того, чтобы иметь возможность хранить значение +32768, которое появится при вычислениях и которое в 16-ти разрядах знакового числа не помещается и требует для представления 17 разрядов. Если мы будем правильно выполнять все операции, то диапазон значений всегда будет от -32768 до +32768. Еще раз повторяю, для представления такого диапазона значений требуется 17, а не 16 разрядов. Я-то думал, что Вы в симуляции умножителя 60 000 просто так задали, а Вы, оказывается решили, что раз мы увеличили разрядность до 17 бит, так у нас и диапазон в 2 раза вырос.

Исправляйте.
ZED
Цитата
Я-то думал, что Вы в симуляции умножителя 60 000 просто так задали


Честно говоря я его просто так и задал=)) Просто раз уж в симуляции было 60000, так думаю и в формуле написать.

Да, про 2048 я накосячил, только сейчас проснулся и понял, сразу за комп, тогда нам лучше делить (мне так кажется) на 2047:

result_re <= (y_re_sig*w_re_sig + y_im_sig*w_im_sig)/2047;
result_im <= (y_re_sig*w_im_sig - y_im_sig*w_re_sig)/2047;

Но это число не очень хорошее (опять же как мне кажется), ибо не является степенью двойки... Не уж то опять придется расширять до 2048?
Sefo
Есть 2 варианта. Либо, как и в бабочке увеличить разрядность коэффициентов на 1 бит и -1.0 ... +1.0 представлять диапазоном -2048 ... +2048, либо оставить разрядность как есть, но опуститься до -1024 ... +1024.

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

Деление на 2047 потребует честного делителя, что не так уж и здорово. Обходиться сдвигами вместо честного деления куда приятнее и ресурсы экономятся.
ZED
Я склоняюсь ко 2 варианту. с точки зрения БПФ мы получаем "дополнительный шум" не знаю только как его обозвать. Мне так кажется, а так не знаю.
Sefo
Если говорить очень кратко, то в силу того, что значения всех коэффициентов уменьшаются (пусть даже всего-то на 1/2048), коэффициенты перестают быть значениями e^(-j*2*pi*n/N) в соответствующих точках и теряют свое главное свойство - ортогональность.

Если столь краткое объяснение будет не понятным, то дайте знать - объясню подробнее.
ZED
Да, все понятно, спасибо!
Sefo
Тогда продолжим.

Во-первых, подправьте код умножителей под диапазон коэффициентов -1024 ... +1024, поскольку после умножения делить нам надо теперь на 1024.

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

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

В-четвертых, все блоки нашего БПФ имеют на входе и выходе один и тот же набор сигналов (относящийся к данным БПФ) и эти сигналы представляют собой комплексные числа. Я предлагаю воспользоваться такой возможностью языка как record и задать тип complex_data и complex_coef для данных и коэффициентов. Еще задать тип complex_data_vector и complex_coef_vector с параметризованной размерностью, чтобы не "таскать" везде по четыре сигнала данных и по три сигнала с коэффициентами. Все это, для удобства, объявить в package - скажем fft_pkg. Все сказанное в это пункте никак не влияет на работоспособность, поэтому если не хотите, то можете этого не делать.

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

Вы с ModelSim работали?
ZED
Цитата
Во-первых, подправьте код умножителей под диапазон коэффициентов -1024 ... +1024, поскольку после умножения делить нам надо теперь на 1024.

Поправил, прилагается;

Цитата
о-вторых, теперь, когда мы разобрались с умножением, нужен ли нам 0-ой умножитель в блоке умножителей?

Думаю нет, зачем нам постоянно умножать на 1?

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

Вот тут я не совсем понял, получается мне код для умножителей нужно впихнуть в код для бабочки? Код бабочки прилагаю: http://webfile.ru/3392071

Цитата
В-четвертых, все блоки нашего БПФ имеют на входе и выходе один и тот же набор сигналов (относящийся к данным БПФ) и эти сигналы представляют собой комплексные числа. Я предлагаю воспользоваться такой возможностью языка как record и задать тип complex_data и complex_coef для данных и коэффициентов. Еще задать тип complex_data_vector и complex_coef_vector с параметризованной размерностью, чтобы не "таскать" везде по четыре сигнала данных и по три сигнала с коэффициентами. Все это, для удобства, объявить в package - скажем fft_pkg. Все сказанное в это пункте никак не влияет на работоспособность, поэтому если не хотите, то можете этого не делать.

Сделаю позже, пока нужно с 3 пунктом разобраться.

Цитата
Вы с ModelSim работали?

Работал немного.
Sefo
Цитата(ZED @ Apr 7 2009, 18:03) *
Вот тут я не совсем понял, получается мне код для умножителей нужно впихнуть в код для бабочки?


С чего Вы это взяли? Никто никого не обязывает ставить регистры на выходе блока. Чисто комбинаторный блок это вполне нормально. Я имел ввиду, что бабочка у нас не будет содержать регистров - будет чисто комбинаторной, а умножители будут иметь регистры на выходе. Впрочем, если хотите, то можете поставить регистры на выходе и бабочки и умножителей - это увеличит pipeline на 1 и практически никак не повлияет на скорость вычисления самого БПФ (ну будет БПФ вычисляться на 6 тактов дольше, ну и что...)

Кстати, о бабочке. Пока Вы не убрали из нее регистры, объясните мне пожалуйста, почему бабочка тратит на вычисления аж 2 такта вместо 1? Зачем Вы сделали двойное защелкивание? Бабочка (в отличие, например, от умножителей, особенно если их синтезировать на обычных ячейках, а не на DSP-блоках) выполняет настолько простые операции, что защелкивать промежуточный результат абсолютно бессмысленно - лишняя трата регистров smile.gif.
ZED
Цитата
Чисто комбинаторный блок это вполне нормально. Я имел ввиду, что бабочка у нас не будет содержать регистров - будет чисто комбинаторной, а умножители будут иметь регистры на выходе.

Да, но бабочка содержит процесс, а это уже регистр. процесс убрать нельзя, т.к. конструкция if последовательная, а значит может содержаться только в процессе. Тут вижу выход только описывать эти 2 бабочки как компоненты, а затем применять конструкцию if generate. Ну можно в процесс засунуть тупо все сигналы, чтобы он запускался при изменении каждого из них.

Цитата
Кстати, о бабочке. Пока Вы не убрали из нее регистры, объясните мне пожалуйста, почему бабочка тратит на вычисления аж 2 такта вместо 1? Зачем Вы сделали двойное защелкивание?

Я его не хотел делать, так вышло=)) Но тем не менее Quartus ставит промежуточный регистр. Это происходит как раз из-за различных назначений сигналам yi_re_sig/yi_im_sig, i=0,1,2,3 при конструкции if else/
ZED
На счет if generate я погорячился, даже сказал бы тупанул, можно просто каждый сигнал yi_re_sig/yi_im_sig, i=0,1,2,3 посадить на case/ Таким образом уберется процесс и сгенеряться мультиплексоры. бабочка станет чисто комбинационной. Вечером попробую...
Sefo
Цитата(ZED @ Apr 8 2009, 20:12) *
Да, но бабочка содержит процесс, а это уже регистр.



Цитата(ZED @ Apr 9 2009, 07:50) *
На счет if generate я погорячился, даже сказал бы тупанул, можно просто каждый сигнал yi_re_sig/yi_im_sig, i=0,1,2,3 посадить на case/ Таким образом уберется процесс и сгенеряться мультиплексоры. бабочка станет чисто комбинационной. Вечером попробую...


Спокойствие... только спокойствие.

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

Синтезатор "детектирует" наличие регистра по конструкциям вида
CLK'event and CLK = '1', rising_edge(clk) и т.д.

Если Вы напишите такой, например, код
CODE
process(SEL,B,C,D,E)
begin
if SEL = '0' then
A <= B or C;
else
A <= C and D;
end if;
end process

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

Причем, если вместо process(SEL,B,C,D,E) Вы напишите process(SEL,B,C), то синтезатор все сделает правильно, но вот симулятор просимулирует неправильно.

Если вне всякого процесса Вы напишите
CODE
A <= B when rising_edge(CLK) else A;

то получите регистр и без использования process.
ZED
Цитата
process никогда и ни при каких обстоятельствах не является признаком регистра.

Я знаю. Я в принципе так и указал:
Цитата
Ну можно в процесс засунуть тупо все сигналы, чтобы он запускался при изменении каждого из них.

Просто сигналов уж больно много.
Вот проект: http://webfile.ru/3398933
ZED
Я переправил, просто исправил позже, чем вы ответили...
Sefo
Ok. А как обстоят дела с введением record?
ZED
В процессе, сейчас хочу все соединить поскорее, а recordом я не пользовался, нужно почитать, постараюсь завтра сделать.

Соеденил:
http://webfile.ru/3399176
ZED
Прошу прощения забыл регистры, на выходе для отсчетов y0_re, y0_im:
http://webfile.ru/3400144
Sefo
наконец-то выдалось немного свободного времени - посмотрел Ваш код.

1) Зачем, всетаки, приставка but к портам бабочки ?

2) Зачем в умножителе Вы ввели еще один промежуточный сигнал result_re_buf ? Чем Вам не нравится такой код smile.gif ?
CODE
process(CLK)
begin
if (rising_edge(CLK)) then
result_re <= std_logic_vector(result_re_sig(b_size + w_size - 3 downto w_size - 2 ));
result_im <= std_logic_vector(result_im_sig(b_size + w_size - 3 downto w_size - 2));
end if;
end process;


3) Зачем Вам resize в умножителе? Если бы это был просто умножитель предназначенный для чего угодно, то требуется учесть возможность переполнения при +/-. Но тогда и выход должен уже быть не 17 разрядов, а 18. Наш умножитель он только для нашего БПФ годится, а в нашем БПФ в умножителе уже не будет переполнения при +/-. Кстати, объясните почему?

4) Зачем в бабочке регистр на y0? Очень плохая идея и стиль выравнивать задержки не там где создается "перекос". У нас регистры стоят в умножителях, 0-ой умножитель удален за ненадобностью, но раз имменно в нем был регистр, то именно вместо него в блоке умножителей и надо поставить регистр для выравнивания, а не в бабочке.

Пока мы разбираемся с кодом бабочки и умножителя и вводим record (как там дела? ) давайте параллельно подумаем про память - нам скоро ей заниматься. Посмотрите, пожалуйста, на последнюю версию блок схемы. Согласно блок-схеме у нас получаются два совершенно разных блока памяти. Что нужно добавить на блок схеме, чтобы блоки памяти у нас были совершенно одинаковыми?
ZED
Цитата
1) Зачем, всетаки, приставка but к портам бабочки ?

Чтобы не запутаться, убрал...

Цитата
2) Зачем в умножителе Вы ввели еще один промежуточный сигнал result_re_buf

Опять же, чтобы не запутаться, убрал...=)

Цитата
3) Зачем Вам resize в умножителе? Если бы это был просто умножитель предназначенный для чего угодно, то требуется учесть возможность переполнения при +/-. Но тогда и выход должен уже быть не 17 разрядов, а 18. Наш умножитель он только для нашего БПФ годится, а в нашем БПФ в умножителе уже не будет переполнения при +/-. Кстати, объясните почему?

Resize не нужен т.к. мы расширили до 17 разрядов отчсеты и до 12 разрядов поворачивающие множители, убрал...

Цитата
4) Зачем в бабочке регистр на y0? Очень плохая идея и стиль выравнивать задержки не там где создается "перекос". У нас регистры стоят в умножителях, 0-ой умножитель удален за ненадобностью, но раз имменно в нем был регистр, то именно вместо него в блоке умножителей и надо поставить регистр для выравнивания, а не в бабочке.

Перенес регистр из бабочки в блок умножителей.

Цитата
Пока мы разбираемся с кодом бабочки и умножителя и вводим record (как там дела? )

Не было времени разобраться.

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

Не хватает мультиплексора, исправил, прилагаю: http://webfile.ru/3409277

Код полной бабочки: http://webfile.ru/3409275
ZED
Никак не пойму, что нужно с записью сделать, как она должна выглядеть, вот до чего я пока додумался:
Код
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

package fft_pkg is
    constant b_size: natural := 17;
    constant w_size: natural := 12;
    
    type complex_data is record
        x_re: std_logic_vector(b_size - 1 downto 0);
        x_im: std_logic_vector(b_size - 1 downto 0);
    end record;
    
    type complex_coef is record
        w_re: std_logic_vector(w_size - 1 downto 0);
        w_im: std_logic_vector(w_size - 1 downto 0);
    end record;
    
    type complex_data_vector is record
        x0: complex_data;
        x1: complex_data;
        x2: complex_data;
        x3: complex_data;
    end record;
    
    type complex_coef_vector is record
        w1: complex_coef;
        w2: complex_coef;
        w3: complex_coef;
    end record;
end package fft_pkg;



Акак же тогда с проектом быть придется задавать только входной сигнал x, сигнал для коэффициентов w и оперировать типа так:
x.x0.x_re это будет x0_re?

и с компонентами тогда как получится можно ли будет сделать так:
Код
entity full_butterfly is
generic (b_size: natural := 17;
         w_size: natural := 12);
port (
CLK: in std_logic;
switch: in std_logic;
x : in complex_data_vector;

w : in complex_coef_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 full_butterfly;

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

component butterfly_complex is
generic (b_size: natural := 17);
port(
CLK: in std_logic;
switch: in std_logic;
x: in complex_data_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 component butterfly_complex;


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

butterfly: butterfly_complex
port map(
CLK => CLK,
switch => switch,
x => x;
y0_re => y0_re_connect,
y0_im => y0_im_connect,
y1_re => y1_re_connect,
y1_im => y1_im_connect,
y2_re => y2_re_connect,
y2_im => y2_im_connect,
y3_re => y3_re_connect,
y3_im => y3_im_connect
);
Sefo
Цитата(ZED @ Apr 13 2009, 21:12) *
Resize не нужен т.к. мы расширили до 17 разрядов отчсеты и до 12 разрядов поворачивающие множители, убрал...


К сожалению, объяснить отсутствие переполнения только лишь увеличением разрядности недостаточно. Представьте, к примеру, что x_re = 32768, x_im = 32768, w_re = 1024 и w_im = 1024. В этом случае result_im = (x_re *w_im + x_im *w_re)/1024 = 65536 - однозначно переполнение... Здесь дело в свойствах БПФ. Если все реализовано правильно, то точки, поступающие на вход БПФ всегда находятся внутри единичной окружности на комплексной плоскости. Коеффициенты - это точки лежащие на краю единичной окружности ( w_re = cos(a), w_im = sin(a) ). Так что если w_re = 1024, то w_im неизбежно будет = 0. Поворачивающими их называют не случайно - при умножении на них точка всего лишь поворачивается на угол a. Она никогда не выйдет за пределы этой единичной окружности - это и есть главная причина отсутствия переполнения. Таким образом, если все сделано правильно, то случай x_re = x_im = 32768 исключен так же как и w_re = w_im = 1024.

С record Вы все сделали правильно за исключением ненужных услохнений с именами членов record. Достаточно так:
CODE
type complex_data is record
re: std_logic_vector(b_size - 1 downto 0);
im: std_logic_vector(b_size - 1 downto 0);
end record;


Что касается complex_data_vector / complex_coef_vector, то я имел ввиду следующее:

type complex_data_vector is array (natural range <>) of complex_data;
type complex_coef_vector is array (natural range <>) of complex_coef;

Впрочем, (natural range <>) – это больше для тренировки в освоении языка. При таком задании типа complex_data_vector Вы размерность указываете при использовании. т.е. Вы можете написать

CODE
entity full_butterfly is
port
(
CLK : in std_logic;

switch : in std_logic;

x : in complex_data_vector(3 downto 0);

w : in complex_coef_vector(3 downto 1);

y : out complex_data_vector(3 downto 0)
);
end full_butterfly;


В нашем случае, я, все же, склоняюсь задать размерность жестко. Т.е.

type complex_data_vector is array (3 downto 0) of complex_data;
type complex_coef_vector is array (3 downto 1) of complex_coef;

тогда

CODE
entity full_butterfly is
port
(
CLK : in std_logic;

switch : in std_logic;

x : in complex_data_vector;

w : in complex_coef_vector;

y : out complex_data_vector
);
end full_butterfly;


обратите внимание, что y, являясь выходным сигналом, тоже может быть complex_data_vector.

К сожалению, в record не возможно параметризовать размерность членов (как можно параметризовать размерность самого array) - ее приходится задавать жестко или с помощью констант. Поэтому, что касается внутренних сигналов в бабочке, то ввиду необходимости сделать их на 2 разряда больше не остается ничего другого, как прямо внутри бабочки задать "служебный" тип complex_data_p2_vector:

CODE
architecture beh_butter of butterfly_complex is

type complex_p2 is record
re : std_logic_vector(complex.re'high + 2 downto 0);
im : std_logic_vector(complex.im'high + 2 downto 0);
end record complex_p2;

type complex_data_p2_vector is array (complex_data_vector'range) of complex2;


Выносить его в общий package нет никакого смысла т.к. нигде кроме бабочки он не будет востребован.

В результате вместо замысловатого x.x0.x_re будет x(0).re, что по-моему, весьма читаемо и удобно.

Про память. Т.к. память у нас не тривиальная, то нарисуйте, пожалуйста, блок-схему ее реализации, как Вы ее себе представляете. Могу сразу сказать, что т.к. мы должны вычитывать/сохранять по 4 точки за такт, то без четырех блоков памяти не обойтись, но и 4 блока это далеко не все. Чтобы понять что там еще нужно посмотрите внимательно схему вычисления БПФ.
ZED
Ну, если предположить, что каждая память состоит из 4 блоков памятей, то нам нужны 4 самих этих блока + схема, которая будет преобразовывать адреса для каждого блока памяти:



Код
If (addr_in_0 >= 0) and (addr_in_0 <= 511) then
    addr_out_0 <= addr_in_0;
elsif (addr_in_0 >= 512) and (addr_in_0 <= 1023) then
    addr_out_0 <= addr_in_0 - 512;
elsif (addr_in_0 >= 1024) and (addr_in_0 <= 1535) then
    addr_out_0 <= addr_in_0 - 1024;
else
    addr_out_0 <= addr_in_0 - 1536;
end if


Вот что-то типа этого я думаю и так для каждого сигнала: addr_in_1, addr_in_2, addr_in_3.

Т.е. получатся схемы сравнения (компараторы) и мультиплексоры...
Sefo
Такая коррекция адреса – бессмысленный расход логических ячеек и "проводов". Лучше сразу в управляющей логике формировать правильные адреса.

Но Вы, похоже, увлекшись адресами не заметили проблему. Из вашей схемы следует, что точки 0..511 Вы собираетесь сохранять в RAM0, точки 512...1023 в RAM1, точки 1024...1535 в RAM2 и точки 1536...2047 в RAM3. Пройдитесь мыссленно по схеме алгоритма и попробуйте увидеть что получится (точнее чего не получится) если распределить точки по блокам памяти таким образом. Очень важно не забывать, что мы должны вычитывать/сохранять по 4 точки одновременно.
ZED
Цитата
Лучше сразу в управляющей логике формировать правильные адреса

Тогда вооще не понимаю в чем проблема, 4 памяти - пишем одновременно во все 4. WE только поставить и все.
Sefo
Цитата(ZED @ Apr 20 2009, 19:13) *
Тогда вооще не понимаю в чем проблема, 4 памяти - пишем одновременно во все 4. WE только поставить и все.


Эх... Ленитесь... cool.gif

Ну давайте разбираться. Заливаем память данными АЦП. В RAM0 точки 0..511, в RAM1 - 512...1023, в RAM2 - 1024...1535 и RAM3 - 1536...2047. Начинаем считать БПФ. В первую бабочку идут точки 0,512,1024 и 1536. Во вторую бабочку идут точки 1, 513, 1025 и 1537 и т.д. Каждая из 4-х точек идущих на одну и ту же бабочку лежит в своем отдельном банке памяти. После вычисления бабочки результаты складываются по тем же адресам и тем же номерам банков (только в другую память). Все замечательно. Но начинается след. этап и видим, что на первую бабочку нам надо подать данные из адресов 0, 128, 256 и 384. Спрашивается, где они лежат? Все до одного в RAM0. И как же Вы их собираетесь вычитывать все сразу за один такт из RAM0? Ведь любой блок RAMx за такт может вычитать/записать только одно данное. Так что уже на втором этапе мы имеем проблему т.к. любой бабочке нужны одновременно данные, которые лежат в одном и том же банке памяти. При этом, входы/выходы бабочки жестко связаны с банками памяти. Теперь, надеюсь, осознаете проблему и догадываетесь чего не хватает для ее разрешения?
Sefo
Цитата(Sefo @ Apr 21 2009, 19:41) *
Теперь, надеюсь, осознаете проблему и догадываетесь чего не хватает для ее разрешения?


Что-то ответа на этот вопрос от Вас не слышно... Времени нет или идей?
ZED
Цитата(Sefo @ Apr 24 2009, 18:21) *
Что-то ответа на этот вопрос от Вас не слышно... Времени нет или идей?

Честно говоря и того и другого нету. Я вообще не представляю как из памяти можно считать 4 отсчета сразу, при том, что она на это не рассчитана. Чувствую, что все кроется видимо в мультиплексировании, но как.
Sefo
Да. Дело в мультиплексировании. Как именно напишу на днях - со временем сейчас тоже напряженно.

Пока пишу про память оформите, пожалуйста, код бабочки и умножителей в окончательный вид с учетом выше написанных замечаний про record.
Reddy
А прикольное Руко-водство! Давно такое искал. Ребята Молодцы! Sefo - просто Герой! Всё таки хочется чтоб до конца дошли! rolleyes.gif
ZED
Вот с recordом, только он не как шины распознает, а как отдельные сигналы: http://webfile.ru/3458200
Sefo
Цитата(Reddy @ Apr 30 2009, 19:56) *
А прикольное Руко-водство! Давно такое искал. Ребята Молодцы! Sefo - просто Герой! Всё таки хочется чтоб до конца дошли! rolleyes.gif


Спасибо. Рад что это интересно не только ZEDу.

Т.к. текст с картинками, то решил загрузить его в pdf формате (fft.pdf). Читать его нужно одновременно имея перед глазами дополненную схему алгоритма (FFT_2048_a09_05_01.rar).

Задания будут следующие:
1) В качестве упражнения дополните, пожалуйста, схемы этапов 3,4,5 картой банков памяти как я это сделал для этапов 1 и 2.
2) Последний 6-й этап выбивается из общего алгоритма - объясните почему. Если с объяснением проблем не возникнет, то предложите решение проблемы.
3) Напишите, как бы Вы стали реализовывать генерацию адресов, управление миксерами и сами миксеры. Код пока не пишите, просто объясните и/или нарисуйте схему.

Код посмотрю вечером.
Reddy
Можно тогда тоже поучаствовать? - У меня вопрос! - Была у вас такая тема - оптимизация суммы A + B + 1. Сразу оговарюсь что я использую Quartus 8. Так вот - если смотреть после синтеза RTL, то там действительно выдаётся 2 сумматора, но если проимплементировать весь проект и посмотреть что в итоге получится в Chip Planner-е - то результат для C <= A + B + 1 и sigTmp <= (A & '1') + (B & '1'); С <= sigTmp(8 downto 1); будет один и тот же. Причём с эти я сталкиваюсь не первый раз. Тут видимо есть какая-то недороботка, но на конечный результат похоже это не влияет!?
Maverick
Цитата(Reddy @ Apr 30 2009, 18:56) *
А прикольное Руко-водство! Давно такое искал. Ребята Молодцы! Sefo - просто Герой! Всё таки хочется чтоб до конца дошли! rolleyes.gif


Полностью согласен Sefo - очень классный учитель, хорошо и толково объясняет!!! Дай Бог чтобы у них все получилось!!! ZED - не в обиду будет сказано, хороший ученик и видно, что хочет дойти до конца и во всем разобраться!
PS Надеюсь своим детищем поделяться rolleyes.gif
ZED
Цитата
ZED - не в обиду будет сказано, хороший ученик и видно, что хочет дойти до конца и во всем разобраться!

Спасибо, стараюсь!!! smile.gif

Прикрепляю свои инсинуации, надеюсь нигде не напутал.
Sefo
Цитата(Reddy @ May 4 2009, 11:02) *
Можно тогда тоже поучаствовать? - У меня вопрос! - Была у вас такая тема - оптимизация суммы A + B + 1. Сразу оговарюсь что я использую Quartus 8. Так вот - если смотреть после синтеза RTL, то там действительно выдаётся 2 сумматора, но если проимплементировать весь проект и посмотреть что в итоге получится в Chip Planner-е - то результат для C <= A + B + 1 и sigTmp <= (A & '1') + (B & '1'); С <= sigTmp(8 downto 1); будет один и тот же. Причём с эти я сталкиваюсь не первый раз. Тут видимо есть какая-то недороботка, но на конечный результат похоже это не влияет!?


Это происходит потому, что сначала синтезатор из кода пытается выделить стандартные операторы: сумматоры, умножители, мультиплексоры, декодеры, регистры и т.д. Т.е. получается нечто среднее между языком описания аппаратуры высокого уровня и gate level. Далее полученные операторы "раскладываются" по технологическим ячейкам ПЛИС. Вот именно на этом уровне и происходит оптимизация и объединение, по возможности, нескольких операторов в одну техн. ячейку. Простой код не вызывает проблем у любого синтезатора, но вот в случае сложного кода результаты могут существенно отличаться от синтезатора к синтезатору. Например по своему опыту могу сказать, что Precision на сложном коде стабильно выигрывает у Quartus.

Что касается конкретно А+В+1, то просто полезно знать как можно "заставить" абсолютно любой синтезатор поставить 1 сумматор вместо двух, да и просто знать некоторые тонкости арифметической логики.

Precision, например, в отличие от Quartus, в конструкци A+B+1 сразу видит 1 полный сумматор вместо 2-х, что гарантирует, что при раскладке по технологическим ячейкам ПЛИС Precision очень постарается smile.gif разложить его как полный сумматор.

Цитата(ZED @ May 4 2009, 19:31) *
Спасибо, стараюсь!!! smile.gif

Прикрепляю свои инсинуации, надеюсь нигде не напутал.


Напутали smile.gif С адресами напутали. Как бы мы не формировали адреса, но на каждом этапе из каждого банка должны быть прочитаны все 512 точек хранящиеся в каждом банке памяти и, соответственно, все без исключения 2048 вычисленых результатов должны быть записаны на свои индивидуальные места в банках памяти. У Вас получается, чем дальше, тем больше Вы читаете из одного и того же места и записываете разные результаты в одно и то же место, затирая предудущие. На 5-ом этапе у Вас и нумерация банков в последнем блоке, почему-то, неверная (на остальных правильно).
ZED
Поправил, ох уж этот Ctl+C Ctl+V laughing.gif
Sefo
Вы не тот файл выложили - там нет ни одного отличия от того, что Вы выложили 4 мая. Причем файлы совпадают до бита smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.