Знаковый квадратурный коррелятор на ПЛИС

Знаковый квадратурный корреляторКвадратурный знаковый коррелятор вполне известная штука, но в сети об этом нет почти никакой информации. Поэтому вполне законно будет осветить данную тему на элементарном примере. Предположим имеется цифровой сигнал (меандр) длительностью 160 мкс и частотой 200 кГц, тоесть 32 периода данной частоты. Необходимо найти максимум его совпадения с его квадратурной моделью, если выборки делать с частотой на 6.25 кГц меньше - 193.75 кГц.

Для этого поступим следующим образом: создадим так называемые синусную и косинусную модели сигнала и сохраним их в памяти. Нам понадобятся 2х32 ячейки памяти в которых будут храниться единички и нолики формирующие последовательно за 32 такта один период синуса и косинуса в цифровом виде.

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

Квадратурная модель

Далее необходимо осуществить свертку входного цифрового сигнала с синусной и косинусной моделями и подсчитать количество совпадений в процессе свертки. Эту операцию нужно проводить за время между двумя соседними выборками сигнала тоесть с частотой 193.75*32 = 6200 кГц. Итак для построения коррелятора нам понадобятся два элемента памяти один - в который записаны синусная и косинусная цифровые модели сигнала (меандр), другой - память для записи входного сигнала, два счетчика - один на 32 другой на 31, два элемента XOR для определения совпадений сигнала с моделью, два счетчика для подсчета совпадений и сумматор для подсчета общего количества совпадений сигнала с квадратурной моделью. Теперь записывая данные выборок в память, которая прокручивается счетчиком на 31 и ее выходные данные сравниваются с данными памяти модели которая в свою очередь прокручивается счетчиком на 32 можно за время между двумя выборками подсчитать количество совпадений входного сигнала. Поскольку с каждой новой выборкой сигдал будет как-бы наплывать (счет на 1 меньше чем у модели) на свои синусные и косинусные модели то таким образом можно будет определить максимум их совпадений. Этот максимум и называется корреляционным. Если сигнал простой то количество совпадений будет линейно нарастать и спадать образуя что-то вроде корреляционного треугольника. В случае со сложным, например ЛЧМ, сигналом, а это уже тема другого повествования, корреляционный пик будет иметь другой вид.

Код устройства представлен ниже:


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity korrsign is
	Port (
		-- задающий клок 12400кГц
		clk: in std_logic;
		-- общий сброс
		clr: in std_logic;
		--  
		in_s1: in std_logic;
		-- выход переноса 
		out_carry: out std_logic;
		out_clrcnt: out std_logic;
		out_clk_data: out std_logic;
		out_cntsin1: out std_logic_vector(4 downto 0);
		out_cntcos1: out std_logic_vector(4 downto 0);
		out_sumall1: out std_logic_vector(5 downto 0);
		sum_sc_out1: out std_logic_vector(5 downto 0);
		--  
		out_sin: out std_logic;
		out_cos: out std_logic;
		--  
		out_in1: out std_logic;
		-- выход счетчиков модели и сигнала 
		out_clk_mod: 		out std_logic_vector(4 downto 0);
		out_clk_sig_rd: out std_logic_vector(4 downto 0);
		out_clk_sig_wr: out std_logic_vector(4 downto 0)
		);
end korrsign;

architecture Behavioral of korrsign is

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

	component sigdata is

	generic 
	(
		DATA_WIDTH : natural := 1;
		ADDR_WIDTH : natural := 5
	);

	port 
	(
		rclk	: in std_logic;
		wclk	: in std_logic;
		raddr	: in std_logic_vector (0 to ADDR_WIDTH - 1);
		waddr	: in std_logic_vector (0 to ADDR_WIDTH - 1);
		data	: in std_logic;
		we		: in std_logic := '1';
		q		: out std_logic
	);

	end component;

--------------------------------------------------------------------
	-- модель

	component moddata

	generic 
	(
		DATA_WIDTH : natural := 2;
		ADDR_WIDTH : natural := 5
	);

	port 
	(
		rclk	: in std_logic;
		raddr	: in std_logic_vector (0 to ADDR_WIDTH - 1);
		q	: out std_logic_vector((DATA_WIDTH -1) downto 0)
	);
	end component;

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

	-- счетчик модели и сигнала 
	signal clk_mod: std_logic_vector(5 downto 0);	
	signal clk_sig_rd: std_logic_vector(4 downto 0);	
	signal clk_sig_wr: std_logic_vector(4 downto 0);	

	signal clk_data: std_logic;	
	signal clk_sin1: std_logic_vector(4 downto 0);	
	signal clk_cos1: std_logic_vector(4 downto 0);	
	signal sum_all1: std_logic_vector(5 downto 0);	
	signal sum_sc1: std_logic_vector(5 downto 0);	
	signal s_data: std_logic;	
	signal s_outdata: std_logic;	
	-- 					
	signal carry: std_logic;
	signal clr_sincos: std_logic;
	
	signal s_q: std_logic_vector(1 downto 0);

	signal s_dsin1: std_logic;
	signal s_dcos1: std_logic;

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

begin
	
	-- входные данные 
	s_data <= in_s1;

	-- память данных
	usigdata : sigdata
	generic map (1, 5)
	port map (
		rclk => not clk_mod(0),
		wclk => carry, 
		raddr => clk_sig_rd, 
		waddr => clk_sig_wr, 
		data => s_data,
		q => s_outdata
		); 

	-- записанные данные на выход 
	out_in1 <= s_outdata;

	-- память модели
	umoddata : moddata
	generic map (2, 5)
	port map (
		rclk => not clk_mod(0), 
		raddr => clk_mod(5 downto 1), 
		q => s_q
		); 

	-- модель на выход
	out_sin <= s_q(0);  
	out_cos <= s_q(1);  

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

-- счетчик на 64 с переносом (модель чтение)
process(clk)

begin
	if clr = '0' then 
		clk_mod <= (others => '0');
		carry <= '1';
	elsif(rising_edge(clk))then
		clk_mod <= clk_mod + 1 ;
		carry <= '1';
		if clk_mod = 63 then 
			carry <= '0';
		else	
			carry <= '1';
		end if;
	end if;

end process;

	-- частота опроса 
	clk_data <= clk_mod(0);
	-- частота опроса на выход
	out_clk_data <= clk_data;
	-- перенос на выход
	out_carry <= carry;
	-- опрос модели на выход
	out_clk_mod <= clk_mod(5 downto 1);
	-- укороченный перенос
	clr_sincos <= not (not carry and not clk); 
	-- укороченный перенос на выход
	out_clrcnt <= clr_sincos;


	s_dsin1 <= not (s_q(0) xor s_outdata);
	s_dcos1 <= not (s_q(1) xor s_outdata);

-- счетчик на 31(сигнал чтение)
process(clk_mod(0))

begin
	if clr = '0' then 
		clk_sig_rd <= (others => '0');
	elsif(falling_edge(clk_data))then
		clk_sig_rd <= clk_sig_rd + 1 ;
		if clk_sig_rd = 30 then 
			clk_sig_rd <= (others => '0');
		end if;	
	end if;

end process;

	-- сигнал чтение на выход
	out_clk_sig_rd <= clk_sig_rd;

-- счетчик на 31(сигнал запись)
process(clk_mod(0))

begin
	if clr = '0' then 
		clk_sig_wr <= (others => '0');
	elsif(rising_edge(clk_data))then
		clk_sig_wr <= clk_sig_wr + 1 ;
		if clk_sig_wr = 30 then 
			clk_sig_wr <= (others => '0');
		end if;	
	end if;

end process;

	-- сигнал запись на выход
	out_clk_sig_wr <= clk_sig_wr;

-- двунаправленный счетчик sin sig1
process(clk)

begin
	if clr = '0' or clr_sincos = '0' then 
		clk_sin1 <= (others => '0');
	elsif(rising_edge(clk_data))then
		if s_dsin1 = '1' then
			clk_sin1 <= clk_sin1 + 1 ;
		end if;	
	end if;

	out_cntsin1 <= clk_sin1;

end process;

-- двунаправленный счетчик cos sig1
process(clk)

begin
	if clr = '0' or clr_sincos = '0' then 
		clk_cos1 <= (others => '0');
	elsif(rising_edge(clk_data))then
		if s_dcos1 = '1' then
			clk_cos1 <= clk_cos1 + 1 ;
		end if;	
	end if;

	out_cntcos1 <= clk_cos1;

end process;

	sum_sc1 <= conv_std_logic_vector((conv_integer(clk_sin1) + conv_integer(clk_cos1)), 6);
	sum_sc_out1 <= sum_sc1;

-- регистр после сумматора
process(clk)

begin
	if(falling_edge(carry))then
		if sum_sc1 > sum_all1 then
			sum_all1 <= sum_sc1;
		end if;	
	end if;

end process;

	out_sumall1 <= sum_all1;

end Behavioral;

Диаграмма свертки: в начале совпадений только 32 затем они постепенно увеличиваются до 48 и это и будет максимум.

Знаковый квадратурный коррелятор

Проект квадратурного знакового коррелятора для Quartus90 можно получить по ссылке ниже по тексту.

Top.Mail.Ru