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

Нашел:
http://www.embedded.com/2000/0009/0009feat3.htm
Там есть и описание реализации и связь с БПФ, правда формулы в плохом качестве, но я все понял.

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

Ну я и не предлагаю, тем более столько уже сделано. Просто хотел заметить, что на практике используются другие алгоритмы.
Maverick
Цитата(ZED @ Dec 8 2009, 21:46) *
БПХ это по-моему быстрое преобразование Хартли. Если ссылочку на литературу, где написано по подробнее об этом преобразовании, желательно понятным языком и о его связи с БПФ? С удовольствием бы почитал. Еще бы с удовольствием прочитал бы про быстрое Вейвлет преобразование, как оно аппаратно реализуется.


где взял не помню, даю что есть
Sefo
Цитата(ZED @ Dec 8 2009, 21:46) *
Вот, прикрепляю собранный проект, только я не подсоединил ROM память коэффициентов, т.к. она не написана.
Кстати и вопрос как мы ее будем реализовыватьwhen case?


Реализовать ее стоит на обычных RAM блоках (работающих в режиме ROM). На форуме есть достаточное количество примеров такого описания на HDL. Я бы, правда, сгенерировал бы ее Квартусовским визардом.

Какая у Вас версия ModelSim и умеете ли Вы с ним работать?
ZED
ModelSim 6.5 SE, да немного умею.
Sefo
Цитата(ZED @ Dec 8 2009, 21:46) *
Вот, прикрепляю собранный проект...


Увы, серьезный просчет прямо на верхнем уровне sad.gif. Согласно нашей схеме во время вычисления БПФ на каждый банк памяти подается одни и тот же адрес и достаточно одного на всех WE. Но при загрузке данных в память БПФ перед вычислением все совсем не так. Во-первых в общем случае Вы никогда заранее не знаете порядок прихода данных и, поэтому, для применимости модуля в разных проектах необходимо предоставить внешнему модулю полное управление памятью. Во-вторых, Вы собирались обрабатывать данные с АЦП - таким образом на вход БПФ данные пойдут по порядку. Согласно схеме БПФ точки 1 ... 511 "укладываются" в 0-ой банк, 512 ... 1023 в 1-вый и т.д. Но у Вас так не получится сделать т.к. сейчас Вы не можете в один банк записать, а в другой нет. А Вам нужно сначала заполнить 0-вой банк не трогая остальные и только потом переходить к 1-ому.

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

Как дела с ROM для коэффициентов?
ZED
flipflop и Maverick спасибо за информацию, интересно довольно таки.

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

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

Я так понял, что для каждого банка нужно вывести свой WE.
Цитата
Как дела с ROM для коэффициентов?

Если мы сгенерим Квартусовским визардом, то как мы запихнем ее в ModelSim? А описания применения RAM в качестве ROM на форуме я не нашел.
Sefo
Цитата(ZED @ Dec 14 2009, 09:34) *
Я так понял, что для каждого банка нужно вывести свой WE.


и ADDR_WR тоже, для общности.

Цитата(ZED @ Dec 14 2009, 09:34) *
Если мы сгенерим Квартусовским визардом, то как мы запихнем ее в ModelSim? А описания применения RAM в качестве ROM на форуме я не нашел.


Вообще-то с этим проблем быть не должно - Квартус для Моделсима сгенерирует модель ROM, но даже если, вдруг, и не сгенерирует, то Моделсиму можно самопальную модель подставить. Ведь главное, чтобы на ее ножках было бы тоже самое, что и у плисовского блока, а каким кодом Вы это обеспечите в симуляции не имеет значения - хоть через case.


Еще у Вас в коде верхнего уровня встречаются использования таких однострочных блоков, как mux.vhd. Я бы их прямым кодом заменил - так, на мой взгляд, проще код читать. Ведь выражение y <= x_1 when sel = '0' else x_2; настолько простое для понимания, что нет никакого смысла его в отдельный блок выделять физически, несмотря на то, что на блок-схеме этом мультиплексор может быть отдельно обозначен.
ZED
Я переделал, файл прикрепляю. Коэффициенты не подставлял.
У меня возникли следующие вопросы по ходу выполнения:

1. Выдает Warning:
Код
Warning (14320): Synthesized away node full_butterfly:butterfly|block_multipliers:multipliers|complex_multiplier:mul_3|lpm_mult:Mult1|mult_9g01:auto_generated|le2a[17]"

Не могу понять как его устранить.

2. Код
Код
y <= x_1 when sel = '0' else x_2;
Сгенерит Мультиплексор без регистра, а нам по идее нужны мультиплексоры с регистрами.

3. Хотел посмотреть на какой частоте работает бабочка, так вот обнаружился странный парадокс. Если на выходе самой бабочки ставить регистры, перед блоком умножителей она работает на частоте 88 МГц, при отсутствии регистров частота 300 МГц:
Код
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

use work.fft_pkg.all;

entity butterfly_complex is
    port(CLK: in std_logic;
    switch: in std_logic;
    x: in complex_data_vector;
    y: out complex_data_vector
    );
end entity butterfly_complex;

architecture beh_butter of butterfly_complex is

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

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

signal x_sig: complex_data_p2_vector;
signal y_sig: complex_data_p2_vector;

signal y_reg: complex_data_vector;

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

x_sig(0).re <= (1 downto 0 => x(0).re(data_size-1)) & x(0).re;
x_sig(0).im <= (1 downto 0 => x(0).im(data_size-1)) & x(0).im;
x_sig(1).re <= (1 downto 0 => x(1).re(data_size-1)) & x(1).re;
x_sig(1).im <= (1 downto 0 => x(1).im(data_size-1)) & x(1).im;
x_sig(2).re <= (1 downto 0 => x(2).re(data_size-1)) & x(2).re;
x_sig(2).im <= (1 downto 0 => x(2).im(data_size-1)) & x(2).im;
x_sig(3).re <= (1 downto 0 => x(3).re(data_size-1)) & x(3).re;
x_sig(3).im <= (1 downto 0 => x(3).im(data_size-1)) & x(3).im;

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

process (switch, x_sig, y_sig)
begin
    if (switch = '0') then

        -- Вычисление y0
        y_sig(0).re <= x_sig(0).re + x_sig(1).re + x_sig(2).re + x_sig(3).re + 2;
        y_sig(0).im <= x_sig(0).im + x_sig(1).im + x_sig(2).im + x_sig(3).im + 2;

        -- Вычисление y1
        y_sig(1).re <= x_sig(0).re + x_sig(1).re - x_sig(2).re - x_sig(3).re + 2;
        y_sig(1).im <= x_sig(0).im - x_sig(1).im - x_sig(2).im + x_sig(3).im + 2;

        -- Вычисление y2
        y_sig(2).re <= x_sig(0).re - x_sig(1).re + x_sig(2).re - x_sig(3).re + 2;
        y_sig(2).im <= x_sig(0).im - x_sig(1).im + x_sig(2).im - x_sig(3).im + 2;

        -- Вычисление y3
        y_sig(3).re <= x_sig(0).re - x_sig(1).re - x_sig(2).re + x_sig(3).re + 2;
        y_sig(3).im <= x_sig(0).im + x_sig(1).im - x_sig(2).im - x_sig(3).im + 2;

        y_reg(0).re <= y_sig(0).re(data_size-1 + 2 downto 2);
        y_reg(0).im <= y_sig(0).im(data_size-1 + 2 downto 2);
        y_reg(1).re <= y_sig(1).re(data_size-1 + 2 downto 2);
        y_reg(1).im <= y_sig(1).im(data_size-1 + 2 downto 2);
        y_reg(2).re <= y_sig(2).re(data_size-1 + 2 downto 2);
        y_reg(2).im <= y_sig(2).im(data_size-1 + 2 downto 2);
        y_reg(3).re <= y_sig(3).re(data_size-1 + 2 downto 2);
        y_reg(3).im <= y_sig(3).im(data_size-1 + 2 downto 2);

    else
        -- Вычисление y0
        y_sig(0).re <= x_sig(0).re + x_sig(1).re + 1;
        y_sig(0).im <= x_sig(0).im + x_sig(1).im + 1;

        -- Вычисление y1
        y_sig(1).re <= x_sig(0).re - x_sig(1).re + 1;
        y_sig(1).im <= x_sig(0).im - x_sig(1).im + 1;
        
        
        -- Вычисление y2
        y_sig(2).re <= x_sig(2).re + x_sig(3).re + 1;
        y_sig(2).im <= x_sig(2).im + x_sig(3).im + 1;

        -- Вычисление y3
        y_sig(3).re <= x_sig(2).re - x_sig(3).re + 1;
        y_sig(3).im <= x_sig(2).im - x_sig(3).im + 1;

        y_reg(0).re <= y_sig(0).re(data_size-1 + 1 downto 1);
        y_reg(0).im <= y_sig(0).im(data_size-1 + 1 downto 1);
        y_reg(1).re <= y_sig(1).re(data_size-1 + 1 downto 1);
        y_reg(1).im <= y_sig(1).im(data_size-1 + 1 downto 1);
        y_reg(2).re <= y_sig(2).re(data_size-1 + 1 downto 1);
        y_reg(2).im <= y_sig(2).im(data_size-1 + 1 downto 1);
        y_reg(3).re <= y_sig(3).re(data_size-1 + 1 downto 1);
        y_reg(3).im <= y_sig(3).im(data_size-1 + 1 downto 1);
    end if;
end process;

-- Выходной Регистр:
    process
    begin
        wait until (rising_edge(CLK));
            y <= y_reg;
    end process;
end beh_butter;


3. Я походу напутал с адресами для памяти коэффициентов ROM: нужно не
Код
10 downto 0
, а
Код
8 downto 0


4. И еще (возможно глупый вопрос), когда мы округляем после суммирования в бабочке, мы фактически делаем так: (A+B+C+D)/4 для 4-х точечной бабочки или (A+cool.gif/2 для 2-х точечной. Так вот, когда мы делим на 4 или на 2 мы не теряем ли часть полезного сигнала? Ведь на вход поступает сигнал+шум, а если отношение С/Ш маленькое мы можем потерять полезную информацию.
Может было проще расширить данные до 32-х знаковыми разрядами и после суммирования не нужно было бы округлять и выбирать разряды.
Так вот вопрос все ли мы делаем правомерно? И как вообще лучше делать?

FFT_2048
Sefo
Цитата(ZED @ Dec 15 2009, 12:55) *
2. Код
Код
y <= x_1 when sel = '0' else x_2;
Сгенерит Мультиплексор без регистра, а нам по идее нужны мультиплексоры с регистрами.


Код в файлах mux.vhd, mux_ADDR.vhd и mux_WE.vhd тоже генерировал мультиплексор без регистров (входной сигнал CLK не использовался). Кроме того нам не все мультиплексоры нужны с регистрами на выходе - см. блок-схему и сообщения по этому поводу.




Цитата(ZED @ Dec 15 2009, 12:55) *
3. Хотел посмотреть на какой частоте работает бабочка, так вот обнаружился странный парадокс. Если на выходе самой бабочки ставить регистры, перед блоком умножителей она работает на частоте 88 МГц, при отсутствии регистров частота 300 МГц


В такие чудеса я не верю, поэтому скорее всего, убрав регистры Вы вообще ничего не подали на выход бабочки и 95% проекта была выкинута Квартусом. Оставшаяся часть была блоком управления, для которого 300 МГц не проблема.

Код приведенный в сообщении и в проекте отличаются. Раньше у Вас проект был для Stratix, а теперь для APEX20 - совсем не подходящая ПЛИС для ЦОС, да и вообще не для новых проектов.

Ваш проект для APEX у меня дал 38 МГц с регистрами на выходе бабочки и 24 МГц без регистров - никаких чудес.

Определитесь с ПЛИС, плиз smile.gif Возьмите хотя бы Цыклон - нам нужна нормальная память и DSP блоки.

Цитата(ZED @ Dec 15 2009, 12:55) *
3. Я походу напутал с адресами для памяти коэффициентов ROM: нужно не
Код
10 downto 0
, а
Код
8 downto 0


Угу, и со счета сбились smile.gif - 3-тий пункт уже был.

Цитата(ZED @ Dec 15 2009, 12:55) *
4. И еще (возможно глупый вопрос), когда мы округляем после суммирования в бабочке, мы фактически делаем так: (A+B+C+D)/4 для 4-х точечной бабочки или (A+cool.gif/2 для 2-х точечной. Так вот, когда мы делим на 4 или на 2 мы не теряем ли часть полезного сигнала? Ведь на вход поступает сигнал+шум, а если отношение С/Ш маленькое мы можем потерять полезную информацию.
Может было проще расширить данные до 32-х знаковыми разрядами и после суммирования не нужно было бы округлять и выбирать разряды.
Так вот вопрос все ли мы делаем правомерно? И как вообще лучше делать?


Точность это всегда болезненная тема. В бабочке мы фактически делаем не так как Вы написали а так: (A+B+C+D)/4 + 0.5. Это округление, а не отбрасывание дробной части. Правильнее говорить об ухудшении отношения С/Ш. Увеличение разрядности до 32 Вам не поможет - Вы забыли про комплексные умножители, где мы тоже берем не все разряды. А при умножении, между прочим, разрядность увеличивается в 2 раза, а не на 2 разряда. Ту не помогут даже 320-ти разрядные числа sad.gif

Рекомендую перечитать сообщения по этому вопросу в данной (и не только) теме. Когда все заработает так как спроектировано сейчас, тогда и будете думать что улучшить, а что и так удовлетворяет потребности.

Цитата(ZED @ Dec 15 2009, 12:55) *
И как вообще лучше делать?


Не инженерная постановка вопроса smile.gif Можно арифметику с плавающей точкой вставить - точность повысится, ресурсы возрастут, а в результате окажется, что для решения задачи достаточно было не 16-ти разрядного АЦП, а 8-ми разрядного и при вычислениях в бабочке и умножителях даже округлять не надо, а достаточно просто отбрасывать дробную часть и т.д. и т.п.

Поскольку из-за нехватки времени я от Вас теперь явно отстаю и уже даже имею "долги" придется Вам набраться терпения. Сорри.sad.gif
Sefo
Посмотрел я ваш код внимательно и вот какие ошибки там обнаружились:

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

Далее про логику управления.

Сигналы управление обоими вращателями приходят раньше положенного времени. Например управление входным вращателем синхронно с адресом чтения данных, а должно быть на 1 такт позже него. Собственно говоря, задержки сигналов управления мной были расписаны на временной диаграмме, да и на блок-схеме БПФ они также хорошо видны. Могли бы и сами проверить соотношения.

Сигналы SEL_MUX_IN и STOP не работают. Сигнал STATE работает не правильно.

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

Ну и наконец, на последнем этапе у Вас БПФ стоит наглухо. Таким образом, результатов Вам не видать.

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

Нажмите для просмотра прикрепленного файла

Еще мы с вами, "забраковав" реализацию блока управления с помощь CASE, не разобрали одно существенное преимущество нынешнего подхода. Нынешняя архитектура блока управления обладает хорошей масштабируемостью - как статической, так и динамической.

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

Динамическая масштабируемостью означает, что если в блок управления передавать извне начальные значения, то вы сможете менять количество точек БПФ прямо на лету. Разумеется, что разрядности всех сигналов должны быть заданы на этапе синтеза исходя из максимального количества точек. Изменения кода для динамического управления кол-вом точек так же достаточно просты в выбранной на данный момент архитектуре блока управления.

А вот в случае использования CASE реализация статической масштабируемости весьма затруднительна, а динамической практически невозможна.
ZED
При компиляции Warning:
Код
Warning (10036): Verilog HDL or VHDL warning at FFT_Control.vhd(54): object "BIC_WR_ENABLE_p1" assigned a value but never read
.

А так очень порадовало, что константы в package вынесены, очень удобно. пока буду дальше разбираться.
Sefo
Цитата(ZED @ Jan 11 2010, 09:45) *
При компиляции Warning:
Код
Warning (10036): Verilog HDL or VHDL warning at FFT_Control.vhd(54): object "BIC_WR_ENABLE_p1" assigned a value but never read
.


BIC_WR_ENABLE_p1 на самом деле лишний сигнал. Видимо, когда прикидывал какие сигналы потребуются, решил, что он будет нужен, а когда код написал, то забыл удалить за ненадобностью.
ZED
1) Если можно напишите по подробнее про сигнал ENABLE_d. Хитрая такая задумка... Я вроде так понимаю, но не уверен, что до конца.
Вот как я понимаю: Это фактически сдвиговый регистр, при начале этапа мы записываем в него '1' на каждом такте, а в конце '0'. Таким образом формируя с какого триггера (этого регистра) считывать (constant Addr_Rd_Dly и т.д) мы формируем сигналы разрешения (ADDR_RD_ENABLE и т.д.).
2) BIC это я так понял пометка вращателя, а можно спросить почему именно BIC? ну так для лучшего восприятия? Также интересно узнать смысл обозначений fr, fc, f, ro i, c, dи т.д.
3)И еще, а что там за комментарий -- 517?
Sefo
Цитата(ZED @ Jan 12 2010, 16:34) *
2) BIC это я так понял пометка вращателя, а можно спросить почему именно BIC? ну так для лучшего восприятия? Также интересно узнать смысл обозначений fr, fc, f, ro i, c, dи т.д.


BIC это первые буквы от Block_Interval_Counter. Просто даже длина имени BLOCK_INTRVL_CNTR_xx уже на грани адекватной, а BLOCK_INTRVL_CNTR_xx_ENABLE эту грань пересекает, а самое главное, на мой взгляд, перестает "читаться". При беглом просмотре кода уже очень сложно отличить основной BLOCK_INTRVL_CNTR_xx от его "разрешающего" сигнала. Посмотрел свежим взглядом код и пришел к выводу, что это пример совсем неудачного названия, т.к. сам счетчик блоков у нас вообще виртуальный (в том смысле, что значение счетчика собирается из значений других сигналов) и BIC_xx_ENABLE к BLOCK_INTRVL_CNTR_xx вообще не имеет никакого отношения. Так что, Вы правы, что не восприняли этот сигнал.

Суффикс f означает флаг. fc - комбинаторный, fr - регистровый. Это, собственно говоря, все к вопросу о кодовых стандартах. Помнится, такая тема на форуме уже поднималась. Я флагами называю те сигналы, которые всего лишь отражают истинность или ложность какого-либо одного условия и, что очень важно, строго следуют за изменением истинности/ложности условия. Например, сигнал ENABLE этим критериям не отвечает т.к. он не отражает истинность какого-либо одного условия - он по одному условию устанавливается в 1, а по другому сбрасывается в 0. Он как раз использует флаги - по одному флагу устанавливается в 1, а по другому сбрасывается. Комбинаторный флаг отражает истинность условия синхронно ("мгновенно"), а регистровый с задержкой на один(несколько) такт(ов). Использование комбинаторных флагов дает более медленный код, но зато с ними проще работать. Использование регистровых флагов дает более быстрый код, но работать с ними сложнее - в случаях, когда задержка недопустима и регистровый флаг должен отражать истинность условия синхронно с ним требуется предсказание истинности условия за 1 такт, что, иногда, представляется затруднительным или невозможным.

Входные и выходные сигналы я всегда помечаю постфиксом i и o соответственно. r означает регистровый, c - комбинаторный. Соответственно SIGNAL_ro - это выходной сигнал, "взятый" с регистра, а SIGNAL_co - выходной сигнал, формируемый комбинаторной логикой.

d (delayed) я использую для обозначения задержанных копий. Есть три варианта. 1) пара SIGNAL и SIGNAL_d(n downto 1) т.е. основной и его копии, задержанные на 1 ... n тактов. 2) SIGNAL и SIGNAL_d1, SIGNAL_d2 ... 3) SIGNAL_d(n downto 0) т.е. основным является SIGNAL(0). Выбор зависит от того какой удобнее в конкретной ситуации.

p, соответственно, обозначает сигналы предшествующие n тактов основному.

Выбор между постфиксами p и d делается исходя их смысла кода.

a - асинхронный, s - синхронный (т.е. RESETsn - синхронный сброс)

Чтобы постфиксы и суффиксы не сливались с самим именем сигнала я имя сигнала всегда пишу большими буквами, а суффиксы и постфиксы - маленькими и часто отделяю _.

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

Кроме того, постфиксы i и o автоматически устраняют то неудобство, что в VHDL выходной сигнал не может участвовать в выражениях в качестве источника данных - ему можно только присваивать.

Цитата(ZED @ Jan 12 2010, 16:34) *
1) Если можно напишите по подробнее про сигнал ENABLE_d. Хитрая такая задумка... Я вроде так понимаю, но не уверен, что до конца.
Вот как я понимаю: Это фактически сдвиговый регистр, при начале этапа мы записываем в него '1' на каждом такте, а в конце '0'. Таким образом формируя с какого триггера (этого регистра) считывать (constant Addr_Rd_Dly и т.д) мы формируем сигналы разрешения (ADDR_RD_ENABLE и т.д.).


Цитата(ZED @ Jan 12 2010, 16:34) *
3)И еще, а что там за комментарий -- 517?


На эти вопросы отвечу чуть позже.
Sefo
Цитата(ZED @ Jan 12 2010, 16:34) *
1) Если можно напишите по подробнее про сигнал ENABLE_d. Хитрая такая задумка... Я вроде так понимаю, но не уверен, что до конца.
Вот как я понимаю: Это фактически сдвиговый регистр, при начале этапа мы записываем в него '1' на каждом такте, а в конце '0'. Таким образом формируя с какого триггера (этого регистра) считывать (constant Addr_Rd_Dly и т.д) мы формируем сигналы разрешения (ADDR_RD_ENABLE и т.д.).


Вы правильно поняли принцип, но я немного придерусь к сказанному Вами. Интерпретация, что мы записываем в него '1' на каждом такте неверна. Это действительно сдвиговый регистр. Нулевой бит "задает" форму сигнала, а все остальные ее повторяют с соответствующей задержкой. Что касается нулевого бита, то мы лишь в двух тактах изменяем его значение. При активном флаге fr_START_OF_STAGE мы устанавливаем его в '1', а при активном fr_END_OF_STAGE мы сбрасываем его в '0'. В течение всех остальных тактов мы его не трогаем и он просто сохраняет последнее свое состояние.

Нажмите для просмотра прикрепленного файла

Цитата(ZED @ Jan 12 2010, 16:34) *
3)И еще, а что там за комментарий -- 517?


На самом деле полное время вычисления одного этапа составляет 519 тактов (0…518). На временной диаграмме в сообщении
Цитата(Sefo @ Oct 2 2009, 00:10) *
список сигналов заканчивается адресом записи. Надо еще учесть, что сама память запомнит поданные на нее данные только на следующем такте. Таким образом, если этапы совсем по-честному разделять, то диаграмма будет следующей:
Нажмите для просмотра прикрепленного файла

Но учитывая, что даже если мы на следующем такте попытаемся прочитать данные, записанные по адресу AW511, мы получим правильные данные (D511) нам не обязательно ждать целый такт. А если учесть, что адрес чтения формируется с задержкой на 1 такт от начала этапа, то получается, что мы можем наложить этапы друг на друга на 2 такта. Значение 517 дает честное разнесение этапов во времени, а значение 515 обеспечивает безопасное перекрытие этапов.
Нажмите для просмотра прикрепленного файла

Подобные вещи нужно делать осознанно, чтобы в случае каких-то изменений (типа памяти, например) сразу понимать, что теперь перекрытие не прокатит и здесь нужно честно разнести этапы.
Пара замечаний про флаги. Поскольку флаг fr_START_OF_STAGE регистровый, то нам, как раз, нужно предсказать его значение за 1 такт . В данном случае это делается просто т.к. мы ориентируемся на значение непрерывно инкрементирующегося счетчика. Это гарантирует, что значению 516 будет всегда предшествовать значение 515. В синхронном дизайне практически везде стробы вроде START становятся активными за такт, до реального начала. Стробы типа END активны в самый последний такт, а не за такт до конца. Это достаточно удобно. В моем коде именно так: fr_START_OF_STAGE - за такт до начала этапе, а fr_END_OF_STAGE активен в последний такт этапа.
ZED
Вот, выдалась свободная минутка, прикрепляю собранный проект пока без коэффициентов ROM:
http://webfile.ru/4281201
Sefo
Цитата(ZED @ Feb 6 2010, 14:23) *
Вот, выдалась свободная минутка, прикрепляю собранный проект пока без коэффициентов ROM:
http://webfile.ru/4281201


Я не нашел никаких исправлений, касающихся вращателей, о которых я писал 7 января. Входной и выходной по-прежнему одинаковые. Без правильного выходного вращателя ничего не выйдет.
ZED
Да, совсем забыл, вот поправил: http://webfile.ru/4286215

P.S. Что-то у меня сюда не хотят файлы заливаться...
Reddy
Что-то затихло это Великое Дело? sad.gif

Кстати вопрос, а почему такие формулы вычисления гармоник?
--
-- -- Вычисление y1
-- y_sig(1).re <= x_sig(0).re + x_sig(1).re - x_sig(2).re - x_sig(3).re + 2;
-- y_sig(1).im <= x_sig(0).im - x_sig(1).im - x_sig(2).im + x_sig(3).im + 2;

а не такое:
--
-- -- Вычисление y1
-- y_sig(1).re <= x_sig(0).re + x_sig(1).im - x_sig(2).re - x_sig(3).im + 2;
-- y_sig(1).im <= x_sig(0).im - x_sig(1).re - x_sig(2).im + x_sig(3).re + 2;
ZED
Цитата
Кстати вопрос, а почему такие формулы вычисления гармоник?

Да, все верно, спасибо за замечание!
Sefo
Цитата(Reddy @ Mar 1 2010, 01:31) *
Что-то затихло это Великое Дело? sad.gif


Да - времени свободного поубавилось и у меня и, видимо, у ZED. Я сейчас решил "причесать" весь тот код, что написал ZED и оформить это в проект с которым будет удобно дальше работать. Правда быстро сделать это у меня не получится из-за нехватки времени. Думаю, что продолжения можно ожидать в начале апреля. Осталось не так уж и много - протестировать и исправить баги и разобраться с перестановкой гармоник на выходе.
ZED
Да у меня тоже со временем до конца марта туго...
jb83
Цитата(Reddy @ Mar 1 2010, 01:31) *
Кстати вопрос, а почему такие формулы вычисления гармоник?
--
-- -- Вычисление y1
-- y_sig(1).re <= x_sig(0).re + x_sig(1).re - x_sig(2).re - x_sig(3).re + 2;
-- y_sig(1).im <= x_sig(0).im - x_sig(1).im - x_sig(2).im + x_sig(3).im + 2;

а не такое:
--
-- -- Вычисление y1
-- y_sig(1).re <= x_sig(0).re + x_sig(1).im - x_sig(2).re - x_sig(3).im + 2;
-- y_sig(1).im <= x_sig(0).im - x_sig(1).re - x_sig(2).im + x_sig(3).re + 2;


Туда же в догонку:
должно быть

-- Вычисление y3
y_sig(3).re <= x_sig(0).re - x_sig(1).im - x_sig(2).re + x_sig(3).im + 2;
y_sig(3).im <= x_sig(0).im + x_sig(1).re - x_sig(2).im - x_sig(3).re + 2;

З.Ы.
Кстати, (пользуясь случаем biggrin.gif ) посоветуйте, пожалуйста, литературу по алгоритмам БПФ.
Sefo
Цитата(jb83 @ Mar 24 2010, 12:00) *
Кстати, (пользуясь случаем biggrin.gif ) посоветуйте, пожалуйста, литературу по алгоритмам БПФ.


Например, Л. Рабинер и Б. Гоулд "Теория и применение цифровой обработки сигналов".
ViKo
Ричард Лайонс - Цифровая обработка сигналов
jb83
Спасибо, поищу
Maverick
Какой результат, этой титанической работы?

Предложение администрации - вынести эту ветку в шапку

PS На мой взгляд, труд уже проделан очень большой!
Sefo
Цитата(Maverick @ Sep 22 2010, 10:37) *
Какой результат, этой титанической работы?


Осталось уже не так и много. Я не оставляю надежду в октябре найти, все-таки, время и довести дело до конца.
ZED
Я тоже, правда еще понадобится время вспомнить, но я думаю все получится!
Sefo
Продолжим, по-тихоньку. Сейчас написано много кода и, как я уже писал, пора его "причесать" и оформить в проект. Начнем с package. В БПФ у нас есть необходимость выполнять некоторые промежуточные вычисления с "повышенной" разрядностью – поэтому есть необходимость в 2-х операциях расширение знака и извлечение определенных бит (как правило это старшие разряды). Чтобы избежать неудобоваримых выражений вроде "b_size + w_size - 3 downto w_size – 2" (complex_multiplier) в коде, перенесем их в функции, где они никого с толку сбивать не будут. Напишем 2 простые функции expand_sign и get_msb. Добавим в них проверку на корректность параметров. Проверим, что нумерация бит в передаваемом векторе имеет нисходящий порядок ( a downto b ) и что кол-во бит во входном векторе и результате правильно соотносятся друг с другом.

Нажмите для просмотра прикрепленного файла

Теперь поработаем над бабочкой. В синхронном дизайне не стоит оставлять регистры без Reset. Регистры без Reset также могут доставить массу неудобств и при моделировании. В начальный момент выходы регистров устанавливаются в неопределенное состояние 'U'. Далее лавинообразно все зависимые цепи также переходят в 'U', причем 'U' имеет приоритет. К примеру, "0000" and "UUUU" = "UUUU". В результате значительная часть или весь проект быстро переходит в состояние 'U'. Не самое лучшее состояние для анализа smile.gif. Выходит проект из этого состояния гораздо медленнее (тривиальные случаи не в счет), чем попадает, что так же не упрощает анализ. Тип сброса (синхронный/асинхронный) следует выбирать исходя из конкретной задачи и платформы для ее решения. Поскольку в нашем случае никаких ограничений нет, то выбираем синхронный сброс.

Посмотрим на нынешний код бабочки:

Код
process (switch, x_sig, y_sig)
begin
    if (switch = '0') then

        y_sig(0).re <= x_sig(0).re + x_sig(1).re + x_sig(2).re + x_sig(3).re + 2;
        y_sig(0).im <= x_sig(0).im + x_sig(1).im + x_sig(2).im + x_sig(3).im + 2;

        ...

        y_reg(0).re <= y_sig(0).re(data_size-1 + 2 downto 2);
        y_reg(0).im <= y_sig(0).im(data_size-1 + 2 downto 2);

        ...

    else

        y_sig(0).re <= x_sig(0).re + x_sig(1).re + 1;
        y_sig(0).im <= x_sig(0).im + x_sig(1).im + 1;

        ...

        y_reg(0).re <= y_sig(0).re(data_size-1 + 1 downto 1);
        y_reg(0).im <= y_sig(0).im(data_size-1 + 1 downto 1);

        ...

    end if;
end process;


process
begin

    wait until (rising_edge(CLK));
      y <= y_reg;

end process;


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

В коде есть копирование в вектор с большей разрядностью с расширением знака:

Код
x_sig(0).re <= (1 downto 0 => x(0).re(b_size-1)) & x(0).re;
x_sig(0).im <= (1 downto 0 => x(0).im(b_size-1)) & x(0).im;
...

и извлечение старших бит:
Код
y(0).re <= y_sig(0).re(b_size-1 + 2 downto 2);
y(0).im <= y_sig(0).im(b_size-1 + 2 downto 2);
...

Для того, чтобы избавиться от множества одинаковых строк с разными индексами мы не ограничимся использованием функций expand_sign и get_msb из FFT_Package. Добавим в Butterfly свои expand_sign и get_msb, которые будут вызывать функции из FFT_Package для всех членов complex_data_bus.

Нажмите для просмотра прикрепленного файла
Sefo
Модули памяти я предпочел переименовать т.к. у нас есть не только память данных, но и память коэффициентов. Организацию памяти я оставил как она была у ZED, однако сам код написал несколько иначе. Стоит отметить, что Data_Memory является платформо зависимым модулем. В зависимости от того, какая ПЛИС будет выбрана, будет ли использована внутренняя память ПЛИС или внешняя микросхема начинка этого модуля может меняться. В некоторых случаях, может быть выгодно объединить Re и Im данные в один банк памяти (сейчас они храняться раздельно).

Нажмите для просмотра прикрепленного файла
ZED
В архиве единственная непустая папка RTL, где хранятся vhdl-файлы описания компонентов бабочки, памяти и файл констант FFT_Package.
Мне пока не очень понятна целесообразность введения всех этих функций.
Jhonny.
Здравствуйте. Спасибо за очень полезную тему. У меня есть несколько вопросов касательно БПФ.
Необходимо реализовать преобразователь на 1152, 1024, 704 и 448 отсчетов, при этом длина должна выбираться динамически. Возможно ли сделать такой универсальный преобразователь или лучше сделать четыре отдельных с фиксированной длиной? Как я понял, здесь применим алгоритм Cooley-Tukey со смешанными основаниями, т.е. например, 1152 раскладывается как 43322. Также читал про алгоритм Блуштейна (Bluestein's chirp-z) и ряд других. Какой лучше подходит для данной задачи?
Может кто-то сталкивался с подобной проблемой? Буду признателен за советы.
ZED
Динамически тут будет сделать трудно, ибо для каждого из Ваших БПФ (на 1152, 1024, 704 и 448 отсчетов) используются разные виды "бабочек" - двухточечная, трехточечная и четырехточечная. Таким образом, алгоритм не имеет постоянной структуры вычислений. Вот если бы, например, Вам нужно было вычислить БПФ на 512, 1024 и 2048 точек, то нет проблем динамически задавать какое из этих БПФ должно выполняться, т.к. можно взять в качестве базовой операции двухточечную "бабочку", а меняется только количество этапов и количество итераций в этапе. Ну это мое мнение, оно может быть ошибочно.
Касательно второго вопроса, на сколько я помню (опять же могу ошибаться), алгоритм Блуштейна включает в себя вычисление свертки, которое вычисляется с помощью БПФ. Т.е. также очень сложно будет постороить алгоритм с динамическим выбором длины.
Наверное, проще всего будет дополнять исходные массивы (1152, 1024, 704 и 448) нулями до степени 2 (получатся БПФ на 2048, 1024, 1024 и 512 отсчетов соответственно), выбрать в качестве базовой операции двухточечную бабочку и делать как я описал выше.
Jhonny.
К сожалению, нулями дополнить нельзя. БПФ нужно для демодулятора OFDM, соответственно длительность OFDM-символа определяет количество точек преобразования (если я все правильно понял).
Sefo
Цитата(Jhonny. @ Nov 28 2010, 11:44) *
Необходимо реализовать преобразователь на 1152, 1024, 704 и 448 отсчетов, при этом длина должна выбираться динамически. Возможно ли сделать такой универсальный преобразователь или лучше сделать четыре отдельных с фиксированной длиной?


Можно сделать универсальный. Наличие разнородных бабочек, безусловно, усложняет реализацию, но структура вычислений остается постоянной. Рекомендую посмотреть книжку Л. Рабинер и Б. Гоулд "Теория и применение цифровой обработки сигналов". На странице 418 есть пример 30-ти точечного БПФ, состоящего из 5-ти, 3-х и 2-х точечных бабочек. Сравнив структуру с 32-х точечны БПФ на стр. 420 или 64-х точечного БПФ на стр. 646 Вы увидите, насколько все одинаково по структуре. Поэтому я бы реализовывал универсальный преобразователь.

Цитата(ZED @ Nov 11 2010, 16:00) *
В архиве единственная непустая папка RTL, где хранятся vhdl-файлы описания компонентов бабочки, памяти и файл констант FFT_Package.
Мне пока не очень понятна целесообразность введения всех этих функций.


Целесообразность введения всех этих функций в том, что во-первых это учебный проект и, думаю, многим начинающим будет интересно посмотреть пример использования функций и атрибутов в VHDL. Во-вторых, есть основные операции и, так скажем, вспомогательные - расширение знаком, к примеру. Когда вспомогательная операция требует несколько строк кода не отличающегося читаемостью, из которого не всегда очевидно, что производится какая-то элементарная операция вроде расширения знаком:
Код
x_sig(0).re <= (1 downto 0 => x(0).re(b_size-1)) & x(0).re;
x_sig(0).im <= (1 downto 0 => x(0).im(b_size-1)) & x(0).im;
x_sig(1).re <= (1 downto 0 => x(1).re(b_size-1)) & x(1).re;
x_sig(1).im <= (1 downto 0 => x(1).im(b_size-1)) & x(1).im;
x_sig(2).re <= (1 downto 0 => x(2).re(b_size-1)) & x(2).re;
x_sig(2).im <= (1 downto 0 => x(2).im(b_size-1)) & x(2).im;
x_sig(3).re <= (1 downto 0 => x(3).re(b_size-1)) & x(3).re;
x_sig(3).im <= (1 downto 0 => x(3).im(b_size-1)) & x(3).im;


я предпочитаю не полениться и написать пару функций чтобы не засорять код:

Код
D := expand_sign(D_i);


Функции не сложные, но зато универсальные - не зависят от разрядности и размерности complex_data_bus. Захотите, например, 8-ми точечную бабочку и придется еще 8 строк добавлять чтобы знаком расширить, а с функциями вспомогательные выражения (да и сами функции) редактировать не придется - только основной код нужно будет поменять.

Получается более читаемый код, особенно для тех кто его не писал. Читающий первый раз имеет возможность не вдаваться во второстепенные подробности. Выражение D := expand_sign(D_i) понятно и без комментариев. Если назначение функции не совсем ясно, то можно ограничится чтением комментариев к ней не вдаваясь в подробности реализации.

Что касается пустоты папок, так я только начал их наполнять. За столь медленный темп извиняюсь, но быстрее, пока никак не получается. Сначала я доработаю код, затем начнем наполнять папку Modelsim.
ZED
Цитата
Наличие разнородных бабочек, безусловно, усложняет реализацию, но структура вычислений остается постоянной.

Вычисление 30-ти точечного БПФ, состоящего из 5-ти, 3-х и 2-х точечных бабочек отличается от вычисления 32-х точечного БПФ. По всей видимости для каждого из БПФ (на 1152, 1024, 704 и 448 отсчетов) придется писать свою управляшку, и подключать ее в зависимости от размерности БПФ, а это не очень удобно мне кажется. Ну и подключение бабочек разной размерности.
Sefo
Цитата(ZED @ Nov 29 2010, 16:42) *
Вычисление 30-ти точечного БПФ, состоящего из 5-ти, 3-х и 2-х точечных бабочек отличается от вычисления 32-х точечного БПФ.


Но структура и принцип "соединения" бабочек остается одинаковым.

Цитата(ZED @ Nov 29 2010, 16:42) *
По всей видимости для каждого из БПФ (на 1152, 1024, 704 и 448 отсчетов) придется писать свою управляшку, и подключать ее в зависимости от размерности БПФ, а это не очень удобно мне кажется.


Бабочки все равно придется делать всех типов - от этого не уйти.

Но вот с универсальным управлением как раз особых проблем быть не должно - просто когда появляется 3-х точечная бабочка, то пропадает кратность степеням двойки и вычисления в блоке управления придется делать "честным" образом.

Основная проблема с нечетными бабочками заключается в организации памяти, но эта проблема существует и при реализации нескольких вариантов БПФ под свое кол-во точек. Так что лучше уж решить эту проблему в общем виде и получить одно БПФ для разного кол-ва точек.

Jhonny.
Спасибо за ответыsmile.gif.
То, что принцип соединения бабочек одинаков, интуитивно понятно. Вызывает затруднение количество разнородных бабочек. Для чисел 1152, 1024, 704, 448 я выделил 2-х, 3-х, 4-х, 7-ми и 11-ти точечные бабочки.

Цитата(Sefo @ Nov 30 2010, 02:58) *
Но вот с универсальным управлением как раз особых проблем быть не должно - просто когда появляется 3-х точечная бабочка, то пропадает кратность степеням двойки и вычисления в блоке управления придется делать "честным" образом.

Это значит, обходиться без хитрых сдвигов и маскирований?

Цитата(Sefo @ Nov 30 2010, 02:58) *
Основная проблема с нечетными бабочками заключается в организации памяти, но эта проблема существует и при реализации нескольких вариантов БПФ под свое кол-во точек. Так что лучше уж решить эту проблему в общем виде и получить одно БПФ для разного кол-ва точек.


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

И еще, все сказанное Вами относится к БПФ типа пинг-понг (разрабатываемого в этой теме)? У Рабинера, Гоулда написано про поточный метод, мне показалось, там проще организация памяти.
Sefo
Цитата(Jhonny. @ Nov 30 2010, 13:28) *
Спасибо за ответыsmile.gif.
То, что принцип соединения бабочек одинаков, интуитивно понятно. Вызывает затруднение количество разнородных бабочек. Для чисел 1152, 1024, 704, 448 я выделил 2-х, 3-х, 4-х, 7-ми и 11-ти точечные бабочки.


Я бы 2-х точечную бабочку из списка исключил бы - она неэффективная. Лучше 5-ти точечную добавить - при наличии 7-ми и 11-ти точечных она уже погоды не сделает.

Цитата(Jhonny. @ Nov 30 2010, 13:28) *
И еще, все сказанное Вами относится к БПФ типа пинг-понг (разрабатываемого в этой теме)? У Рабинера, Гоулда написано про поточный метод, мне показалось, там проще организация памяти.


Все сказанное относится к подавляющему большинству реализаций БПФ.

Поточный метод у Рабинера и Гоулда не для современного железа - сильно устаревший и по ресурсам жутко неэффективный. К тому же легко реализуем только если на всех этапах одинаковые бабочки (ну или хотя бы с кратным числом точек). В общем, решите реализовать поточный метод - ищите современные примеры.

Цитата(Jhonny. @ Nov 30 2010, 13:28) *
Это значит, обходиться без хитрых сдвигов и маскирований?


Угу.

Цитата(Jhonny. @ Nov 30 2010, 13:28) *
Насколько общим должен быть вид? Ведь от конкретного числа точек зависят количество этапов и применяемые бабочки?

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


Нужно сначала определиться с ресурсами и быстродействием и исходя из этого думать какие методы реализации подойдут.
Sefo
Вот "причесанный" код нашего БПФ (\RTL). Так же прилагается Квартусовский проект. Проект пока формальный – т.е. он компилируется, но это еще ничего не значит, кроме отсутствия синтаксических ошибок. В качестве микросхемы стоит Cyclone III, что не принципиально. Для компиляции один файл (\Quartus\FPGA_RTL\Coef_Memory_Bank.vhd) требует поддержки VHDL-2008 т.к использует unconstrained array of string. При отсутствии соответствующей версии Квартуса можно воспользоваться несколько кривоватым приемом подходящим для более ранних стандартов VHDL, описанным в комментариях (код так же приведен). Файлы \Quartus\FPGA_RTL\ROM_*.mif для инициализации ROM коэффициентов взяты из проекта ZED и содержат просто sin и cos, что неправильно.

Следующим этапом – моделирование и исправление багов. Пока я готовлю соответствующие файлы просьба ZEDу сгенерировать mif-файлы с правильным набором коэффициентов.

Нажмите для просмотра прикрепленного файла
ZED
Вот коэффициенты ROM_x.mif плюс файл Matlab для их генерации. Надеюсь ничего не напутал.
Sefo
Цитата(ZED @ Jan 11 2011, 07:14) *
Вот коэффициенты ROM_x.mif плюс файл Matlab для их генерации. Надеюсь ничего не напутал.


Увы sm.gif напутали. Придется Вам пролистать эту тему и найти то место, где обсуждалось как правильно рассчитать коэффициенты. Вкратце проблема следующая:

В арифметике с фиксированной точкой Вы берете за 1 некое число Х. Если нужно посчитать чему равно 0.3 от некоего числа D, то делаем так
1) предвычисляем целочисленный коэффициент Y = round(0.3 * X), соответствующий 0.3.
2) R = Y * D
3) Q = R / X

Если X выбран так, что не является степенью 2, то на шаге 3 нужно выполнять честное деление, а если X = 2^n, то Q = R >> n.

В умножителях на поворачивающие коэффициенты у нас нет деления - у нас сдвиг.

Так что вспоминайте как мы собирались вычислять коэффициенты.
ZED
А ну да, коэффициенты у нас лежат в диапазоне от -1024 до 1024.
Jhonny.
Попытался оптимизировать бабочку, убрав повторяющиеся операции. Вот что получилось:

Код
architecture RTL of Butterfly is
    
    signal D : complex_data_p2_bus;

    signal add01_re : std_logic_vector(fft_data'high + 2 downto 0);
    signal add01_im : std_logic_vector(fft_data'high + 2 downto 0);
    signal add23_re : std_logic_vector(fft_data'high + 2 downto 0);
    signal add23_im : std_logic_vector(fft_data'high + 2 downto 0);

    signal sub01_re : std_logic_vector(fft_data'high + 2 downto 0);
    signal sub01_im : std_logic_vector(fft_data'high + 2 downto 0);
    signal sub23_re : std_logic_vector(fft_data'high + 2 downto 0);
    signal sub23_im : std_logic_vector(fft_data'high + 2 downto 0);

    signal sub01    : std_logic_vector(fft_data'high + 2 downto 0);
    signal sub02    : std_logic_vector(fft_data'high + 2 downto 0);
    signal sub13    : std_logic_vector(fft_data'high + 2 downto 0);

begin

    D <= expand_sign(D_i);

    add01_re <= D(0).re + D(1).re + 1;
    add01_im <= D(0).im + D(1).im + 1;

    sub01_re <= D(0).re - D(1).re + 1;
    sub01_im <= D(0).im - D(1).im + 1;

    add23_re <= D(2).re + D(3).re + 1;
    add23_im <= D(2).im + D(3).im + 1;

    sub23_re <= D(2).re - D(3).re + 1;
    sub23_im <= D(2).im - D(3).im + 1;

    sub01    <= D(0).re - D(1).im;
    sub02    <= D(0).im - D(2).im;
    sub13    <= D(1).re - D(3).re;
                
    process (CLK)    
    variable Y: complex_data_p2_bus;
    begin
            
        if rising_edge(CLK) then
            if RESETsn = '0' then                
                Y_ro <= (others => (re => (others => '0'), im => (others => '0')));
            else    
                if (MODE_i = Butterfly_4_Point) then
                    Y(0).re := add01_re + add23_re;
                    Y(0).im := add01_im + add23_im;

                    Y(1).re := sub01 - D(2).re - D(3).im + 2;
                    Y(1).im := sub02 - sub13 + 2;                                    
              
                    Y(2).re := sub01_re + sub23_re;
                    Y(2).im := sub01_im + sub23_im;

                    Y(3).re := sub01 - D(2).re + D(3).im + 2;
                    Y(3).im := sub02 + sub13 + 2;                                  
                              
                    Y_ro <= get_msb(Y, 0);
                else
                    Y(0).re := add01_re;
                    Y(0).im := add01_im;
              
                    Y(1).re := sub01_re;
                    Y(1).im := sub01_im;
                    
                    Y(2).re := add23_re;
                    Y(2).im := add23_im;
              
                    Y(3).re := sub23_re;
                    Y(3).im := sub23_im;
              
                    Y_ro <= get_msb(Y, 1);
                end if;                            
            end if;
        end if;
    
    end process;
end RTL;


Синтезировал в Xilinx ISE 12.3, до этого было
18-bit adder : 6
18-bit subtractor : 2
19-bit adder : 19
19-bit subtractor :11
После стало так 19-bit adder : 18, 19-bit subtractor :10.

Имеет ли право на жизнь такая реализация, или есть другие варианты оптимизации?
chirik
Добрый день!
Я разбираюсь с БПФ и не могу понять, как на практике вычисляются поворачивающий множитель W ?, в книжках написано W= e^(-j*2*p*n*k/N), k- номер отсчета, N- длина последовательности, n- текущий номер, толи я не те книжки читаю(
ZED
Цитата
Добрый день!
Я разбираюсь с БПФ и не могу понять, как на практике вычисляются поворачивающий множитель W ?, в книжках написано W= e^(-j*2*p*n*k/N), k- номер отсчета, N- длина последовательности, n- текущий номер, толи я не те книжки читаю(


Все правильно. Вы читаете именно те книжки.
chirik
Почитав еще литературы стало яснее, что как правило, коэффициенты вычисляются заранее и хранятся в ОЗУ, или их можно через синусы посчитать W= cos(2*p*k/N) - j*sin(2*p*k/N).
Костян
Почему для W используется разрядность всего 12 бит , тогда как данные 17 ?
Из каких соображений разрядность W взята меньше, чем входных данных ?
almost
Цитата(Костян @ Sep 28 2011, 17:26) *
Почему для W используется разрядность всего 12 бит , тогда как данные 17 ?
Из каких соображений разрядность W взята меньше, чем входных данных ?


По всей видимости, чтобы за грубить результаты вычислений, при этом экономя память.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.