БПФ на 8 точек (FFT 8 point) на VHDL

FFT 8 point на VHDLБПФ на ПЛИС построить несложно, поскольку для этого существуют готовые ядра, в том числе и с открытым кодом. Но все дело в том, что минимальное количество точек в готовых ядрах БПФ равно 64. Если нужно количество точек меньше чем 64, например 16 или даже 8 то вполне приемлимый вариант написать код БПФ самостоятельно. Заодно можно протестировать и выбранный алгоритм построения БПФ на ПЛИС. В данном посте представлен VHDL код FFT 8 point выполненый по алгоритму прореживания по времени. Код довольно громоздкий но на его базе можно уяснить общий принцип написания и как все крутится.

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

fft 8 point прореживание по времени

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

FFT бабочка прореживание по времени

В коде на VHDL это выглядит предельно просто:


-- Бабочка (прореживание по времени)
-- A = x + Wn * y;
-- A_r + j*A_i = (x_r + j* x_i) + ( w_r + j*w_i) *(y_r + j*y_i);
-- A_r + j*A_i = (x_r + (w_r * y_r ) –( w_i *y_i)) + j*(x_i +( w_i *y_r) +( w_r * y_i));
-- A_r = x_r + (w_r * y_r ) –( w_i *y_i);
-- A_i = x_i +( w_i *y_r) +( w_r * y_i);
-- B = x - Wn * y;
-- B_r + j*B_i = (x_r + j* x_i) - ( w_r + j*w_i) *(y_r + j*y_i);
-- B_r + j*B_i = ( x_r - (w_r *y_r) + (w_i * y_i)) + (x_i – (w_r *y_i ) – (w_i * y_r ));
-- B_r =( x_r - (w_r *y_r) + (w_i * y_i);
-- B_i = x_i – (w_r * y_i ) – (w_i * y_r );

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

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.numeric_std.all;

entity fft8vhd is
	Generic (
		-- размерность входных данных
		b_size: natural := 15;
		-- размерность пов. множит
		w_size: natural := 12
		);
	Port (
		-- тактовая частота
		clk : in std_logic;
		-- общий сброс
		rst	: in std_logic;
		-- входные данные реал
		dinr0	: in std_logic_vector(b_size downto 0);
		dinr1	: in std_logic_vector(b_size downto 0);
		dinr2	: in std_logic_vector(b_size downto 0);
		dinr3	: in std_logic_vector(b_size downto 0);
		dinr4	: in std_logic_vector(b_size downto 0);
		dinr5	: in std_logic_vector(b_size downto 0);
		dinr6	: in std_logic_vector(b_size downto 0);
		dinr7	: in std_logic_vector(b_size downto 0);
		-- входные данные мним
		dini0	: in std_logic_vector(b_size downto 0);
		dini1	: in std_logic_vector(b_size downto 0);
		dini2	: in std_logic_vector(b_size downto 0);
		dini3	: in std_logic_vector(b_size downto 0);
		dini4	: in std_logic_vector(b_size downto 0);
		dini5	: in std_logic_vector(b_size downto 0);
		dini6	: in std_logic_vector(b_size downto 0);
		dini7	: in std_logic_vector(b_size downto 0);
		-- импульс записи данных 
		wrdata	: in std_logic;

		-- выход счетчика стадий 
		ctfout	: out std_logic_vector(2 downto 0);
		-- выходы данных реал
		doutr0	: out std_logic_vector(b_size downto 0);
		doutr1	: out std_logic_vector(b_size downto 0);
		doutr2	: out std_logic_vector(b_size downto 0);
		doutr3	: out std_logic_vector(b_size downto 0);
		doutr4	: out std_logic_vector(b_size downto 0);
		doutr5	: out std_logic_vector(b_size downto 0);
		doutr6	: out std_logic_vector(b_size downto 0);
		doutr7	: out std_logic_vector(b_size downto 0);
		-- выходы данных мним
		douti0	: out std_logic_vector(b_size downto 0);
		douti1	: out std_logic_vector(b_size downto 0);
		douti2	: out std_logic_vector(b_size downto 0);
		douti3	: out std_logic_vector(b_size downto 0);
		douti4	: out std_logic_vector(b_size downto 0);
		douti5	: out std_logic_vector(b_size downto 0);
		douti6	: out std_logic_vector(b_size downto 0);
		douti7	: out std_logic_vector(b_size downto 0);

		-- тестовые выходы бабочки	
		dout_r_tst_up		: out std_logic_vector(b_size downto 0);
		dout_i_tst_up		: out std_logic_vector(b_size downto 0);
		dout_r_tst_down	: out std_logic_vector(b_size downto 0);
		dout_i_tst_down	: out std_logic_vector(b_size downto 0)
		);
end fft8vhd;

architecture behavioural of fft8vhd is
attribute multstyle : string;
-- на базе логики
attribute multstyle of behavioural : architecture is "logic";
-- на базе встроенных умножителей
--attribute multstyle of behavioural : architecture is "dsp";

	-- счетчик стадий
	signal s_ctf 	: std_logic_vector(2 downto 0);
	-- признак загрузки данных 
	signal s_ld 	: std_logic;
	-- флаг разрешения преобразования
	signal s_begpr 	: std_logic;
---------------------------------------------------------------
	-- буферные сигналы реал
	subtype sdbr is signed(b_size downto 0);
	type memory_sdbr is array(7 downto 0) of sdbr;
	signal s_in_r_sig : memory_sdbr;
	-- буферные сигналы мним
	subtype sdbi is signed(b_size downto 0);
	type memory_sdbi is array(7 downto 0) of sdbi;
	signal s_in_i_sig : memory_sdbi;
-----------------------------------------------------------------
	-- сигналы умножения 1_ой стадии реал
	subtype mult1_re_sig is signed(b_size + w_size + 1 downto 0);
	type memory_mult1_re_sig is array(3 downto 0) of mult1_re_sig;
	signal s_mult1_re_sig : memory_mult1_re_sig;
	-- сигналы умножения 1_ой стадии мним
	subtype mult1_im_sig is signed(b_size + w_size + 1 downto 0);
	type memory_mult1_im_sig is array(3 downto 0) of mult1_im_sig;
	signal s_mult1_im_sig : memory_mult1_im_sig;

	-- сигналы суммы 1_ой стадии реал
	subtype sum1_re_sig is signed(b_size downto 0);
	type memory_sum1_re_sig is array(7 downto 0) of sum1_re_sig;
	signal s_sum1_re_sig : memory_sum1_re_sig;
	-- сигналы суммы 1_ой стадии мним
	subtype sum1_im_sig is signed(b_size downto 0);
	type memory_sum1_im_sig is array(7 downto 0) of sum1_im_sig;
	signal s_sum1_im_sig : memory_sum1_im_sig;
-------------------------------------------------------------------
	-- сигналы умножения 2_ой стадии реал
	subtype mult2_re_sig is signed(b_size + w_size + 1 downto 0);
	type memory_mult2_re_sig is array(3 downto 0) of mult2_re_sig;
	signal s_mult2_re_sig : memory_mult2_re_sig;
	-- сигналы умножения 2_ой стадии мним
	subtype mult2_im_sig is signed(b_size + w_size + 1 downto 0);
	type memory_mult2_im_sig is array(3 downto 0) of mult2_im_sig;
	signal s_mult2_im_sig : memory_mult2_im_sig;

	-- сигналы суммы 2_ой стадии реал
	subtype sum2_re_sig is signed(b_size downto 0);
	type memory_sum2_re_sig is array(7 downto 0) of sum2_re_sig;
	signal s_sum2_re_sig : memory_sum2_re_sig;
	-- сигналы суммы 2_ой стадии мним
	subtype sum2_im_sig is signed(b_size downto 0);
	type memory_sum2_im_sig is array(7 downto 0) of sum2_im_sig;
	signal s_sum2_im_sig : memory_sum2_im_sig;
-----------------------------------------------------------------
	-- сигналы умножения 3_й стадии реал
	subtype mult3_re_sig is signed(b_size + w_size + 1 downto 0);
	type memory_mult3_re_sig is array(3 downto 0) of mult3_re_sig;
	signal s_mult3_re_sig : memory_mult3_re_sig;
	-- сигналы умножения 3_й стадии мним
	subtype mult3_im_sig is signed(b_size + w_size + 1 downto 0);
	type memory_mult3_im_sig is array(3 downto 0) of mult3_im_sig;
	signal s_mult3_im_sig : memory_mult3_im_sig;

	-- сигналы суммы 3_й стадии реал
	subtype sum3_re_sig is signed(b_size downto 0);
	type memory_sum3_re_sig is array(7 downto 0) of sum3_re_sig;
	signal s_sum3_re_sig : memory_sum3_re_sig;
	-- сигналы суммы 3_й стадии мним
	subtype sum3_im_sig is signed(b_size downto 0);
	type memory_sum3_im_sig is array(7 downto 0) of sum3_im_sig;
	signal s_sum3_im_sig : memory_sum3_im_sig;

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

	-- сигналы для поворачивающих множителей реал
	signal s_w_r_8_0_sig: signed(w_size - 1 downto 0);
	signal s_w_r_8_1_sig: signed(w_size - 1 downto 0);
	signal s_w_r_8_2_sig: signed(w_size - 1 downto 0);
	signal s_w_r_8_3_sig: signed(w_size - 1 downto 0);
	-- сигналы для поворачивающих множителей мним
	signal s_w_i_8_0_sig: signed(w_size - 1 downto 0);
	signal s_w_i_8_1_sig: signed(w_size - 1 downto 0);
	signal s_w_i_8_2_sig: signed(w_size - 1 downto 0);
	signal s_w_i_8_3_sig: signed(w_size - 1 downto 0);

	-- поворачивающие множители
	-- round(cos(2*pi*n/8)*1024)
	-- round(sin(2*pi*n/8)*1024)
	-- n = 0...3
	-- реал
	constant c_w_r_8_0  : integer := 1024;	
	constant c_w_r_8_1  : integer := 724;	
	constant c_w_r_8_2  : integer := 0;	
	constant c_w_r_8_3  : integer := -724;	
	-- мним
	constant c_w_i_8_0  : integer := 0;	
	constant c_w_i_8_1  : integer := -724;	
	constant c_w_i_8_2  : integer := -1024;	
	constant c_w_i_8_3  : integer := -724;	

begin

-- счетчик стадий
process(clk, s_ctf)
begin
	if clk'event and clk = '1' then
		if rst = '0' then	
			s_ctf <= (others => '0');
			s_begpr <= '0';
		elsif s_ld = '1' and s_begpr = '0' then 
			s_begpr <= '1';
		end if;
		if s_begpr = '1' then	
			s_ctf <= s_ctf + 1;	
			if s_ctf = 6 then
				s_ctf <= (others => '0');
				s_begpr <= '0';
			end if;	
		end if;
	end if;

	ctfout <= s_ctf;
	
end process;		
	
-- загрузка данных
process(clk)
begin
	if clk'event and clk = '1' then
		if rst = '0' or s_ctf = 6 then	
			s_ld <= '0';
		elsif wrdata = '1' and s_ld = '0' then 
			-- реал входные данные
			s_in_r_sig(0) <= signed(dinr0);
			s_in_r_sig(1) <= signed(dinr1);
			s_in_r_sig(2) <= signed(dinr2);
			s_in_r_sig(3) <= signed(dinr3);
			s_in_r_sig(4) <= signed(dinr4);
			s_in_r_sig(5) <= signed(dinr5);
			s_in_r_sig(6) <= signed(dinr6);
			s_in_r_sig(7) <= signed(dinr7);
			-- мним входные данные
			s_in_i_sig(0) <= signed(dini0);
			s_in_i_sig(1) <= signed(dini1);
			s_in_i_sig(2) <= signed(dini2);
			s_in_i_sig(3) <= signed(dini3);
			s_in_i_sig(4) <= signed(dini4);
			s_in_i_sig(5) <= signed(dini5);
			s_in_i_sig(6) <= signed(dini6);
			s_in_i_sig(7) <= signed(dini7);
			-- реал поворачивающие множители
			s_w_r_8_0_sig <= to_signed(c_w_r_8_0, w_size);
			s_w_r_8_1_sig <= to_signed(c_w_r_8_1, w_size);
			s_w_r_8_2_sig <= to_signed(c_w_r_8_2, w_size);
			s_w_r_8_3_sig <= to_signed(c_w_r_8_3, w_size);
			-- мним поворачивающие множители
			s_w_i_8_0_sig <= to_signed(c_w_i_8_0, w_size);
			s_w_i_8_1_sig <= to_signed(c_w_i_8_1, w_size);
			s_w_i_8_2_sig <= to_signed(c_w_i_8_2, w_size);
			s_w_i_8_3_sig <= to_signed(c_w_i_8_3, w_size);
			-- загрузка состоялась
			s_ld <= '1';
		end if;
	end if;

end process;	

-- операция fft8 (прореживание по времени)

-- architecture behavioral of fft_radix_2 is
-- signal product_1,product_2 : std_logic_vector(32 downto 0);
-- begin
-- product_1 <= (y_r*w_r) - (y_i*w_i);
-- product_2 <= (y_r*w_i) + (y_i*w_r);
-- A_r <= x_r + product_1(15 downto 0);
-- A_i <= x_i + product_2(15 downto 0);
-- B_r <= x_r - product_1(15 downto 0);
-- B_i <= x_i - product_2(15 downto 0);

process(clk, s_sum3_re_sig, s_sum3_im_sig, s_sum1_re_sig, s_sum1_im_sig, s_sum2_re_sig, s_sum2_im_sig)
begin
	if clk'event and clk = '1' then
		-- 1_я стадия fft8 s_ctf = 1,2
		if s_ctf = 1 and s_begpr = '1' then
			-- комплексное умножение 1_я стадия (результат в b_size + w_size + 2)
			-- 1_я бабочка
			s_mult1_re_sig(0) <= resize((s_in_r_sig(4)*s_w_r_8_0_sig - s_in_i_sig(4)*s_w_i_8_0_sig), b_size + w_size + 2);
			s_mult1_im_sig(0) <= resize((s_in_r_sig(4)*s_w_i_8_0_sig + s_in_i_sig(4)*s_w_r_8_0_sig), b_size + w_size + 2);
			-- 2_я бабочка
			s_mult1_re_sig(1) <= resize((s_in_r_sig(6)*s_w_r_8_0_sig - s_in_i_sig(6)*s_w_i_8_0_sig), b_size + w_size + 2);
			s_mult1_im_sig(1) <= resize((s_in_r_sig(6)*s_w_i_8_0_sig + s_in_i_sig(6)*s_w_r_8_0_sig), b_size + w_size + 2);
			-- 3_я бабочка
			s_mult1_re_sig(2) <= resize((s_in_r_sig(5)*s_w_r_8_0_sig - s_in_i_sig(5)*s_w_i_8_0_sig), b_size + w_size + 2);
			s_mult1_im_sig(2) <= resize((s_in_r_sig(5)*s_w_i_8_0_sig + s_in_i_sig(5)*s_w_r_8_0_sig), b_size + w_size + 2);
			-- 4_я бабочка
			s_mult1_re_sig(3) <= resize((s_in_r_sig(7)*s_w_r_8_0_sig - s_in_i_sig(7)*s_w_i_8_0_sig), b_size + w_size + 2);
			s_mult1_im_sig(3) <= resize((s_in_r_sig(7)*s_w_i_8_0_sig + s_in_i_sig(7)*s_w_r_8_0_sig), b_size + w_size + 2);
			
		elsif s_ctf = 2 and s_begpr = '1' then
			-- комплексное суммирование 1-я стадия (результат в b_size)
			-- 0_вой выход 1_ой стадии
			s_sum1_re_sig(0) <= s_in_r_sig(0) + s_mult1_re_sig(0)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(0) <= s_in_i_sig(0) + s_mult1_im_sig(0)(b_size + w_size - 2 downto w_size - 2);
			-- 1_вый выход 1_ой стадии
			s_sum1_re_sig(1) <= s_in_r_sig(0) - s_mult1_re_sig(0)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(1) <= s_in_i_sig(0) - s_mult1_im_sig(0)(b_size + w_size - 2 downto w_size - 2);

			-- 2_ой выход 1_ой стадии
			s_sum1_re_sig(2) <= s_in_r_sig(2) + s_mult1_re_sig(1)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(2) <= s_in_i_sig(2) + s_mult1_im_sig(1)(b_size + w_size - 2 downto w_size - 2);
			-- 3_ий выход 1_ой стадии
			s_sum1_re_sig(3) <= s_in_r_sig(2) - s_mult1_re_sig(1)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(3) <= s_in_i_sig(2) - s_mult1_im_sig(1)(b_size + w_size - 2 downto w_size - 2);
			
			-- 4_ый выход 1_ой стадии
			s_sum1_re_sig(4) <= s_in_r_sig(1) + s_mult1_re_sig(2)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(4) <= s_in_i_sig(1) + s_mult1_im_sig(2)(b_size + w_size - 2 downto w_size - 2);
			-- 5_ый выход 1_ой стадии
			s_sum1_re_sig(5) <= s_in_r_sig(1) - s_mult1_re_sig(2)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(5) <= s_in_i_sig(1) - s_mult1_im_sig(2)(b_size + w_size - 2 downto w_size - 2);
			
			-- 6_ой выход 1_ой стадии
			s_sum1_re_sig(6) <= s_in_r_sig(3) + s_mult1_re_sig(3)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(6) <= s_in_i_sig(3) + s_mult1_im_sig(3)(b_size + w_size - 2 downto w_size - 2);
			-- 7_ой выход 1_ой стадии
			s_sum1_re_sig(7) <= s_in_r_sig(3) - s_mult1_re_sig(3)(b_size + w_size - 2 downto w_size - 2);
			s_sum1_im_sig(7) <= s_in_i_sig(3) - s_mult1_im_sig(3)(b_size + w_size - 2 downto w_size - 2);

---------------------------------------------------------------------------------------
						
		-- 2_я стадия fft8 s_ctf = 3,4
		elsif (s_ctf = 3) and s_begpr = '1' then
			-- комплексное умножение 2_я стадия (результат в b_size + w_size + 2)
			-- 1_я бабочка
			s_mult2_re_sig(0) <= resize((s_sum1_re_sig(2)*s_w_r_8_0_sig - s_sum1_im_sig(2)*s_w_i_8_0_sig), b_size + w_size + 2);
			s_mult2_im_sig(0) <= resize((s_sum1_re_sig(2)*s_w_i_8_0_sig + s_sum1_im_sig(2)*s_w_r_8_0_sig), b_size + w_size + 2);
			-- 2_я бабочка
			s_mult2_re_sig(1) <= resize((s_sum1_re_sig(3)*s_w_r_8_2_sig - s_sum1_im_sig(3)*s_w_i_8_2_sig), b_size + w_size + 2);
			s_mult2_im_sig(1) <= resize((s_sum1_re_sig(3)*s_w_i_8_2_sig + s_sum1_im_sig(3)*s_w_r_8_2_sig), b_size + w_size + 2);
			-- 3_я бабочка
			s_mult2_re_sig(2) <= resize((s_sum1_re_sig(6)*s_w_r_8_0_sig - s_sum1_im_sig(6)*s_w_i_8_0_sig), b_size + w_size + 2);
			s_mult2_im_sig(2) <= resize((s_sum1_re_sig(6)*s_w_i_8_0_sig + s_sum1_im_sig(6)*s_w_r_8_0_sig), b_size + w_size + 2);
			-- 4_я бабочка
			s_mult2_re_sig(3) <= resize((s_sum1_re_sig(7)*s_w_r_8_2_sig - s_sum1_im_sig(7)*s_w_i_8_2_sig), b_size + w_size + 2);
			s_mult2_im_sig(3) <= resize((s_sum1_re_sig(7)*s_w_i_8_2_sig + s_sum1_im_sig(7)*s_w_r_8_2_sig), b_size + w_size + 2);

		elsif s_ctf = 4 and s_begpr = '1' then
			-- комплексное суммирование 2_я стадия (результат в b_size)
			-- 0_вой выход 2_й стадии
			s_sum2_re_sig(0) <= s_sum1_re_sig(0) + s_mult2_re_sig(0)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(0) <= s_sum1_im_sig(0) + s_mult2_im_sig(0)(b_size + w_size - 2 downto w_size - 2);
			-- 2_ой выход 2_ой стадии
			s_sum2_re_sig(2) <= s_sum1_re_sig(0) - s_mult2_re_sig(0)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(2) <= s_sum1_im_sig(0) - s_mult2_im_sig(0)(b_size + w_size - 2 downto w_size - 2);

			-- 1_й выход 2_й стадии
			s_sum2_re_sig(1) <= s_sum1_re_sig(1) + s_mult2_re_sig(1)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(1) <= s_sum1_im_sig(1) + s_mult2_im_sig(1)(b_size + w_size - 2 downto w_size - 2);
			-- 3_й выход 2_ой стадии
			s_sum2_re_sig(3) <= s_sum1_re_sig(1) - s_mult2_re_sig(1)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(3) <= s_sum1_im_sig(1) - s_mult2_im_sig(1)(b_size + w_size - 2 downto w_size - 2);

			-- 4_й выход 2_й стадии
			s_sum2_re_sig(4) <= s_sum1_re_sig(4) + s_mult2_re_sig(2)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(4) <= s_sum1_im_sig(4) + s_mult2_im_sig(2)(b_size + w_size - 2 downto w_size - 2);
			-- 6_й выход 2_ой стадии
			s_sum2_re_sig(6) <= s_sum1_re_sig(4) - s_mult2_re_sig(2)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(6) <= s_sum1_im_sig(4) - s_mult2_im_sig(2)(b_size + w_size - 2 downto w_size - 2);

			-- 5_й выход 2_й стадии
			s_sum2_re_sig(5) <= s_sum1_re_sig(5) + s_mult2_re_sig(3)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(5) <= s_sum1_im_sig(5) + s_mult2_im_sig(3)(b_size + w_size - 2 downto w_size - 2);
			-- 7_й выход 2_ой стадии
			s_sum2_re_sig(7) <= s_sum1_re_sig(5) - s_mult2_re_sig(3)(b_size + w_size - 2 downto w_size - 2);
			s_sum2_im_sig(7) <= s_sum1_im_sig(5) - s_mult2_im_sig(3)(b_size + w_size - 2 downto w_size - 2);

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

		-- 3_я стадия fft8 s_ctf = 5,6
		elsif (s_ctf = 5) and s_begpr = '1' then
			-- комплексное умножение 3_я стадия (результат в b_size + w_size + 2)
			-- 1_я бабочка
			s_mult3_re_sig(0) <= resize((s_sum2_re_sig(4)*s_w_r_8_0_sig - s_sum2_im_sig(4)*s_w_i_8_0_sig), b_size + w_size + 2);
			s_mult3_im_sig(0) <= resize((s_sum2_re_sig(4)*s_w_i_8_0_sig + s_sum2_im_sig(4)*s_w_r_8_0_sig), b_size + w_size + 2);
			-- 2_я бабочка
			s_mult3_re_sig(1) <= resize((s_sum2_re_sig(5)*s_w_r_8_1_sig - s_sum2_im_sig(5)*s_w_i_8_1_sig), b_size + w_size + 2);
			s_mult3_im_sig(1) <= resize((s_sum2_re_sig(5)*s_w_i_8_1_sig + s_sum2_im_sig(5)*s_w_r_8_1_sig), b_size + w_size + 2);
			-- 3_я бабочка
			s_mult3_re_sig(2) <= resize((s_sum2_re_sig(6)*s_w_r_8_2_sig - s_sum2_im_sig(6)*s_w_i_8_2_sig), b_size + w_size + 2);
			s_mult3_im_sig(2) <= resize((s_sum2_re_sig(6)*s_w_i_8_2_sig + s_sum2_im_sig(6)*s_w_r_8_2_sig), b_size + w_size + 2);
			-- 4_я бабочка
			s_mult3_re_sig(3) <= resize((s_sum2_re_sig(7)*s_w_r_8_3_sig - s_sum2_im_sig(7)*s_w_i_8_3_sig), b_size + w_size + 2);
			s_mult3_im_sig(3) <= resize((s_sum2_re_sig(7)*s_w_i_8_3_sig + s_sum2_im_sig(7)*s_w_r_8_3_sig), b_size + w_size + 2);

		elsif s_ctf = 6 and s_begpr = '1' then
			-- комплексное суммирование 3_я стадия (результат в b_size)
			-- 0_вой выход 3_й стадии
			s_sum3_re_sig(0) <= s_sum2_re_sig(0) + s_mult3_re_sig(0)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(0) <= s_sum2_im_sig(0) + s_mult3_im_sig(0)(b_size + w_size - 2 downto w_size - 2);
			-- 1_ой выход 3_ой стадии
			s_sum3_re_sig(1) <= s_sum2_re_sig(1) + s_mult3_re_sig(1)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(1) <= s_sum2_im_sig(1) + s_mult3_im_sig(1)(b_size + w_size - 2 downto w_size - 2);

			-- 2_й выход 3_й стадии
			s_sum3_re_sig(2) <= s_sum2_re_sig(2) + s_mult3_re_sig(2)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(2) <= s_sum2_im_sig(2) + s_mult3_im_sig(2)(b_size + w_size - 2 downto w_size - 2);
			-- 3_й выход 3_ой стадии
			s_sum3_re_sig(3) <= s_sum2_re_sig(3) + s_mult3_re_sig(3)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(3) <= s_sum2_im_sig(3) + s_mult3_im_sig(3)(b_size + w_size - 2 downto w_size - 2);

			-- 4_й выход 3_й стадии
			s_sum3_re_sig(4) <= s_sum2_re_sig(0) - s_mult3_re_sig(0)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(4) <= s_sum2_im_sig(0) - s_mult3_im_sig(0)(b_size + w_size - 2 downto w_size - 2);
			-- 5_й выход 3_ой стадии
			s_sum3_re_sig(5) <= s_sum2_re_sig(1) - s_mult3_re_sig(1)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(5) <= s_sum2_im_sig(1) - s_mult3_im_sig(1)(b_size + w_size - 2 downto w_size - 2);

			-- 6_й выход 3_й стадии
			s_sum3_re_sig(6) <= s_sum2_re_sig(2) - s_mult3_re_sig(2)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(6) <= s_sum2_im_sig(2) - s_mult3_im_sig(2)(b_size + w_size - 2 downto w_size - 2);
			-- 7_й выход 3_ой стадии
			s_sum3_re_sig(7) <= s_sum2_re_sig(3) - s_mult3_re_sig(3)(b_size + w_size - 2 downto w_size - 2);
			s_sum3_im_sig(7) <= s_sum2_im_sig(3) - s_mult3_im_sig(3)(b_size + w_size - 2 downto w_size - 2);

		end if;	 
	end if; 
	
	-- выходной результат 
	doutr0 <= std_logic_vector(s_sum3_re_sig(0));
	doutr1 <= std_logic_vector(s_sum3_re_sig(1));
	doutr2 <= std_logic_vector(s_sum3_re_sig(2));
	doutr3 <= std_logic_vector(s_sum3_re_sig(3));
	doutr4 <= std_logic_vector(s_sum3_re_sig(4));
	doutr5 <= std_logic_vector(s_sum3_re_sig(5));
	doutr6 <= std_logic_vector(s_sum3_re_sig(6));
	doutr7 <= std_logic_vector(s_sum3_re_sig(7));

	douti0 <= std_logic_vector(s_sum3_im_sig(0));
	douti1 <= std_logic_vector(s_sum3_im_sig(1));
	douti2 <= std_logic_vector(s_sum3_im_sig(2));
	douti3 <= std_logic_vector(s_sum3_im_sig(3));
	douti4 <= std_logic_vector(s_sum3_im_sig(4));
	douti5 <= std_logic_vector(s_sum3_im_sig(5));
	douti6 <= std_logic_vector(s_sum3_im_sig(6));
	douti7 <= std_logic_vector(s_sum3_im_sig(7));


	-- тестовые выходы бабочи
	dout_r_tst_up <= std_logic_vector(s_sum2_re_sig(1));
	dout_i_tst_up <= std_logic_vector(s_sum2_im_sig(1));
	dout_r_tst_down <= std_logic_vector(s_sum1_re_sig(1));
	dout_i_tst_down <= std_logic_vector(s_sum1_im_sig(1));
	
end process;	

end behavioural;

Все выполняется за 7 тактов тактовой частоты, после полной загрузки данных в буфер. Данный код не является идеалом, предназначен для общего понимания операций с комплексными числами на VHDL.

Для лучшего понимания, как все крутится, представлен готовый проект FFT 8 точек на VHDL для Quartus90. В проекте также представлен файл симулятора где показано, что все работает верно. На вход подаются две сдвинутые на 90 градусов друг относительно друга синусоиды. Синусоиды представлены в виде 8-ми выборок через 45 градусов. После завершения работы БПФ, получаем всплеск на одном из выходов, мнимом или действительном. При этом на других выходах нули. Кому проект пригодился оставьте свой коммент. Предложения и замечания тоже по ссылке для добавления комментов.

Top.Mail.Ru