МАРСОХОД

Open Source Hardware Project

Добро пожаловать, Гость
Логин: Пароль: Запомнить меня

ТЕМА: Радиоприемник на ПЛИС

Радиоприемник на ПЛИС 3 года 7 мес. назад #6149

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Сам хочу попробовать заменить все смесители несколькими каскадами децимирующих фильтров, тк дециматор==смеситель+фильтр в одном флаконе. Принцип такой: узким полосовым фильтром выделяется одна из старших зон Найквиста, которая после децимации перенесется в первую зону. И так 2-3 раза.

Попробовал синтез полосового фильтра, в pdf синим - результат работы fir1, красным - самопальным алгоритмом. :silly:
(Потом выложу, когда практически проверю).
Вложения:

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Последнее редактирование: от Leka.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6150

Сделал КИХ фильтр 89-го порядка:





Отличий особых не заметил.
Нашел что за помехи по краям панорамы.
Частота помехи = частота станции + - 156,25 кГц.
156,25 кГц - это частота работы КИХ фильтра.
Но перед ним стоит сумматор-интегратор,
понижающий частоту до 156,25 кГц.
Где-то тут собака зарыта.
На следующей картинке станция на своей частоте:



На следующих - помехи от нее на частотах + - 156,25 кГц:





Николай.
Вложения:

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6151

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Кстати, зачем для SDR использовать NCO с аккумулятором фазы?
Ведь долговременная/абслоютная точность частоты не нужна. А если отказаться от аккумулятора фазы, можно вычислять sin/cos по рекуррентной формуле(каждое следующее значение - по двум предыдущим):
sin[x*n]=k*sin[x*(n-1)]-sin[x*(n-2)];
cos[x*n]=k*cos[x*(n-1)]-cos[x*(n-2)];
k=2*cos(x); x - шаг.
+периодическая коррекция, чтобы sin/cos не разбегались.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Последнее редактирование: от Leka.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6152

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54

+периодическая коррекция

это обязательно, иначе неустойчивая генерация.
Проще всего задавать требуемую частоту f с достаточно большим шагом, например, 1кГц при Fs=20000кГц.
Тогда x=2*pi*f/Fs (в формулах выше). В этом случае через каждые 20000 тактов Fs регистры генератора можно сбрасывать к начальным условиям, и при ~30-разрядной арифметике это дает ~20-разрядную точность амплитуды.
В Марсоходах 18-разрядные DSP-блоки, на 36-разрядное умножение требуется ~100 ЛЕ и 4 DSP-блока.

В фазофильтровом приемнике точную частоту можно задать вторым смесителем, тк после дециматора Fs' много меньше (например, ~100кГц, и тогда f' можно будет задавать с шагом ~10Гц).

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Последнее редактирование: от Leka.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6166

Победа! Немного работы паяльником и теперь можно одновременно принимать аналоговый сигнал и отправлять данные через Ethernet шилд. Угловой пин в шилде не подключен к чипу Realtek, а значит свободно используется для АЦП. В ПЛИС - прием данных , устранение постоянной составляющей, буферизация данных и формирование UDP пакетов. В деле построения приемника на ПЛИС возможно кому-то пригодится.
Вложения:

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6170

Победил появление сигнала на частотах F +- 156,25 кГц на краях полосы пропускания.
Сделал каскадное соединение фильтров с разными характеристиками.
Пока не разобрался с CIC фильтрами, ставлю вместо них сумматоры-аккумуляторы со
схожими с CIC АЧХ. При моделировании CIC фильтры показывают лучший результат по
сравнению с сумматорами-аккумуляторами, а на реальном сигнале уровень шума выше.
Что-то еще не понимаю.
Сначала после ПЗУ понижаю частоту в 32 раза до 625 кГц, затем ставлю КИХ фильтр
21-го порядка с частотой минимума 140 кГц(т.е. вырезаю частоты преобразования
кратные 156,25 кГц).
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity lpf32iq is
  port(
	i_in  : in std_logic_vector(7 downto 0);
	q_in  : in std_logic_vector(7 downto 0);
	clk, nres : in std_logic;
	term : out std_logic;
	i_out : out std_logic_vector(12 downto 0);
	q_out : out std_logic_vector(12 downto 0)
	);
end;

architecture behavior of lpf32iq is
	signal siReg: std_logic_vector(12 downto 0);
	signal sqReg: std_logic_vector(12 downto 0);
	signal scnt : std_logic_vector(4 downto 0);
	signal sterm : std_logic;
begin

term <= sterm;

mk_sreg:  
process(nres,clk,sterm,i_in,q_in)
begin
	if nres = '0' then
		siReg <= "0000000000000" after 1 ns;
		sqReg <= "0000000000000" after 1 ns;
	elsif (clk = '1' and clk'event) then
		if sterm = '1' then
			siReg <= i_in(7) & i_in(7) & i_in(7) & i_in(7) & i_in(7) & i_in after 1 ns;
			sqReg <= q_in(7) & q_in(7) & q_in(7) & q_in(7) & q_in(7) & q_in after 1 ns;
		else
			siReg <= siReg + (i_in(7) & i_in(7) & i_in(7) & i_in(7) & i_in(7) & i_in) after 1 ns;
			sqReg <= sqReg + (q_in(7) & q_in(7) & q_in(7) & q_in(7) & q_in(7) & q_in) after 1 ns;
		end if;
	end if;        
end process;

mk_iq_out:  
process(nres,clk,sterm,siReg,sqReg)
begin
	if nres = '0' then
		i_out <= "0000000000000" after 1 ns;
		q_out <= "0000000000000" after 1 ns;
	elsif (clk = '1' and clk'event) then
		if sterm = '1' then
			i_out <= siReg after 1 ns;
			q_out <= sqReg after 1 ns;
		else
		end if;
	end if;        
end process;

mk_scnt:  
process(nres,clk)
begin
	if nres = '0' then
		scnt <= "00000" after 1 ns;
		sterm <= '0' after 1 ns;
	elsif (clk = '1' and clk'event) then
		scnt <= scnt + "00001" after 1 ns;
		if scnt = "11111" then
			sterm <= '1' after 1 ns;
		else
			sterm <= '0' after 1 ns;
		end if;
	end if;        
end process;

end;  
--/*
--
--FIR filter designed with
--http://t-filter.appspot.com
--
--sampling frequency: 625000 Hz
--
--fixed point precision: 16 bits
--
--* 0 Hz - 19000 Hz
--  gain = 1
--  desired ripple = 1 dB
--  actual ripple = n/a
--
--* 140000 Hz - 312500 Hz
--  gain = 0
--  desired attenuation = -100 dB
--  actual attenuation = n/a
--
--*/
--
--#define FILTER_TAP_NUM 21
--
--static int filter_taps[FILTER_TAP_NUM] = {
--  -11,	   xFFF5
--  -56,	   xFFC8
--  -139,	   xFF75
--  -180,	   xFF4C
--  58,		   x003A
--  933,	   x03A5
--  2741,	   x0AB5
--  5435,	   x153B
--  8459,	   x210B
--  10881,	   x2A81
--  11810,	   x2E22
--  10881,
--  8459,
--  5435,
--  2741,
--  933,
--  58,
--  -180,
--  -139,
--  -56,
--  -11
--};
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity fir21_625kHz_2_filtr is
	port(
		clk : in std_logic; --- clock 20 MHz
		nres : in std_logic; --- active low
		idata : in std_logic_vector(12 downto 0);
		start : in std_logic; --- active high 625 kHz
		odata : out std_logic_vector(31 downto 0)
		);
end;

architecture behavior of fir21_625kHz_2_filtr is
	signal s0reg: std_logic_vector(15 downto 0);
	signal s1reg: std_logic_vector(15 downto 0);
	signal s2reg: std_logic_vector(15 downto 0);
	signal s3reg: std_logic_vector(15 downto 0);
	signal s4reg: std_logic_vector(15 downto 0);
	signal s5reg: std_logic_vector(15 downto 0);
	signal s6reg: std_logic_vector(15 downto 0);
	signal s7reg: std_logic_vector(15 downto 0);
	signal s8reg: std_logic_vector(15 downto 0);
	signal s9reg: std_logic_vector(15 downto 0);
	signal s10reg: std_logic_vector(15 downto 0);
	signal s11reg: std_logic_vector(15 downto 0);
	signal s12reg: std_logic_vector(15 downto 0);
	signal s13reg: std_logic_vector(15 downto 0);
	signal s14reg: std_logic_vector(15 downto 0);
	signal s15reg: std_logic_vector(15 downto 0);
	signal s16reg: std_logic_vector(15 downto 0);
	signal s17reg: std_logic_vector(15 downto 0);
	signal s18reg: std_logic_vector(15 downto 0);
	signal s19reg: std_logic_vector(15 downto 0);
	signal s20reg: std_logic_vector(15 downto 0);
	signal s11cnt: std_logic_vector(3 downto 0);
	signal s0en: std_logic;
	signal s1en: std_logic;
	signal s2en: std_logic;
	signal ostart: std_logic;
	signal sstart: std_logic_vector(1 downto 0);
	constant cK0: std_logic_vector(15 downto 0) := x"FFF5";
	constant cK1: std_logic_vector(15 downto 0) := x"FFC8";
	constant cK2: std_logic_vector(15 downto 0) := x"FF75";
	constant cK3: std_logic_vector(15 downto 0) := x"FF4C";
	constant cK4: std_logic_vector(15 downto 0) := x"003A";
	constant cK5: std_logic_vector(15 downto 0) := x"03A5";
	constant cK6: std_logic_vector(15 downto 0) := x"0AB5";
	constant cK7: std_logic_vector(15 downto 0) := x"153B";
	constant cK8: std_logic_vector(15 downto 0) := x"210B";
	constant cK9: std_logic_vector(15 downto 0) := x"2A81";
	constant cK10: std_logic_vector(15 downto 0) := x"2E22";
	signal sopa: std_logic_vector(15 downto 0);
	signal sopb: std_logic_vector(15 downto 0);
	signal smr: std_logic_vector(31 downto 0);
	signal sdmr: std_logic_vector(31 downto 0);
	signal sacc: std_logic_vector(31 downto 0);
begin

-- SIGN MULT:
U1: entity work.firmult
port map (
		opa       => sopa,
		opb       => sopb,
		clk       => clk,
		ce        => s0en,
		nres      => nres,
		y         => smr
		);

mk_sopa_sopb:
process (s11cnt,s0reg,s1reg,s2reg,s3reg,s4reg,s5reg,s6reg,s7reg,s8reg,s9reg,s10reg,s11reg,s12reg,
s13reg,s14reg,s15reg,s16reg,s17reg,s18reg,s19reg,s20reg)
begin
	case s11cnt is
		when "0001" => sopa <= s0reg + s20reg; sopb <= cK0;
		when "0010" => sopa <= s1reg + s19reg; sopb <= cK1;
		when "0011" => sopa <= s2reg + s18reg; sopb <= cK2;
		when "0100" => sopa <= s3reg + s17reg; sopb <= cK3;
		when "0101" => sopa <= s4reg + s16reg; sopb <= cK4;
		when "0110" => sopa <= s5reg + s15reg; sopb <= cK5;
		when "0111" => sopa <= s6reg + s14reg; sopb <= cK6;
		when "1000" => sopa <= s7reg + s13reg; sopb <= cK7;
		when "1001" => sopa <= s8reg + s12reg; sopb <= cK8;
		when "1010" => sopa <= s9reg + s11reg; sopb <= cK9;
		when "1011" => sopa <= s10reg; sopb <= cK10;
		when others => sopa <= x"0000"; sopb <= x"0000";
	end case;
end process;

mk_s8cnt:  
process(nres,clk,start)
begin
	if nres = '0' then
		s11cnt <= "1011" after 1 ns;
		s0en <= '0' after 1 ns;
		s1en <= '0' after 1 ns;
		s2en <= '0' after 1 ns;
		sstart <= "00" after 1 ns;
		ostart <= '0' after 1 ns;
	elsif (clk = '1' and clk'event) then
		s1en <= s0en after 1 ns;
		s2en <= s1en after 1 ns;
		sstart <= sstart(0) & start after 1 ns;
		ostart <= sstart(1) and not sstart(0) after 1 ns;
		if ostart = '1' then
			s11cnt <= "0000" after 1 ns;
			s0en <= '0' after 1 ns;
		elsif s11cnt < "1011" then
			s11cnt <= s11cnt + "0001" after 1 ns;
			s0en <= '1' after 1 ns;
		else s0en <= '0' after 1 ns;
		end if;
	end if;        
end process;

mk_sregs:  
process(nres,clk,ostart,idata)
begin
	if nres = '0' then
		s0reg <= x"0000" after 1 ns;
		s1reg <= x"0000" after 1 ns;
		s2reg <= x"0000" after 1 ns;
		s3reg <= x"0000" after 1 ns;
		s4reg <= x"0000" after 1 ns;
		s5reg <= x"0000" after 1 ns;
		s6reg <= x"0000" after 1 ns;
		s7reg <= x"0000" after 1 ns;
		s8reg <= x"0000" after 1 ns;
		s9reg <= x"0000" after 1 ns;
		s10reg <= x"0000" after 1 ns;
		s11reg <= x"0000" after 1 ns;
		s12reg <= x"0000" after 1 ns;
		s13reg <= x"0000" after 1 ns;
		s14reg <= x"0000" after 1 ns;
		s15reg <= x"0000" after 1 ns;
		s16reg <= x"0000" after 1 ns;
		s17reg <= x"0000" after 1 ns;
		s18reg <= x"0000" after 1 ns;
		s19reg <= x"0000" after 1 ns;
		s20reg <= x"0000" after 1 ns;
	elsif (clk = '1' and clk'event) then
		if ostart = '1' then
			s0reg <= (idata(12) & idata(12) & idata(12) & idata) after 1 ns;
			s1reg <= s0reg after 1 ns;
			s2reg <= s1reg after 1 ns;
			s3reg <= s2reg after 1 ns;
			s4reg <= s3reg after 1 ns;
			s5reg <= s4reg after 1 ns;
			s6reg <= s5reg after 1 ns;
			s7reg <= s6reg after 1 ns;
			s8reg <= s7reg after 1 ns;
			s9reg <= s8reg after 1 ns;
			s10reg <= s9reg after 1 ns;
			s11reg <= s10reg after 1 ns;
			s12reg <= s11reg after 1 ns;
			s13reg <= s12reg after 1 ns;
			s14reg <= s13reg after 1 ns;
			s15reg <= s14reg after 1 ns;
			s16reg <= s15reg after 1 ns;
			s17reg <= s16reg after 1 ns;
			s18reg <= s17reg after 1 ns;
			s19reg <= s18reg after 1 ns;
			s20reg <= s19reg after 1 ns;
		end if;
	end if;        
end process;

mk_sacc:  
process(nres,clk,s1en,s2en,smr,ostart)
begin
	if nres = '0' then
		sacc <= x"00000000" after 1 ns;
		sdmr <= x"00000000" after 1 ns;
		odata <= x"00000000" after 1 ns;
	elsif (clk = '1' and clk'event) then
		if ostart = '1'	then
			odata <= sacc after 1 ns;
		end if;
		if ostart = '1'	then
			sdmr <= x"00000000" after 1 ns;
		elsif s1en = '1' then
			sdmr <= smr after 1 ns;
		end if;
		if ostart = '1'	then
			sacc <= x"00000000" after 1 ns;
		elsif s2en = '1' then
			sacc <= sacc + sdmr after 1 ns;
		else
		end if;
	end if;        
end process;

end;  

Затем еще понижаю частоту в 4 раза до частоты 156,25 кГц и после этого ставлю
КИХ фильтр 89-го порядка с частотой минимума 27 кГц. Затем понижаю частоту в 4 раза
и подаю на выход.
КИХ фильтры сделал по структуре, описаной в книге Л.РАБИНЕР, Б.ГОУЛД "ТЕОРИЯ И
ПРИМЕНЕНИЕ ЦИФРОВОЙ ОБРАБОТКИ СИГНАЛОВ" издательство МИР Москва 1978.



Иногда принимаю сигналы любительских радиостанций на диапазонах 3,65 МГц, 7,1 МГц
и 14,15 МГц (20000 кГц - 14150 кГц = 5850 кГц). Но сигналы слабые, явно не хватает
радиолюбительской антенны. На входе усилителя ВЧ поставил низкодобротный преселектор
в виде дросселя на 2 мкГ и переменного конденсатора. При резонансной настройке
сигналы становятся чуть громче. Хочу попробовать поставить хороший высокодобротный
двухконтурный преселектор. Но это как-нибудь потом.
Еще принял неизвестный сигнал на частоте 4880 кГц(20000 кГц - 15120 кГц = 4880 кГц).
Подозреваю что это DRM. Но настроить HDSDR не смог на декодирование этого сигнала.
Не нашел информации как это сделать.



Николай.
Вложения:
Спасибо сказали: SOVA

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6178

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Заработала автономная радиосвязь между ПЛИС (DE0-nano с батарейным питанием, но передатчик д/б заземлен) - светодиоды приемника отображают амплитудную модуляцию передатчика (меандр с периодом ~2сек). Много непонятного. Не могу даже грубо оценить чувствительность приемника из-за паразитных наводок (сигнал ловится даже без приемной антенны, расстояние 10м). Буду перепаивать.

Передатчик: 1м заземленный штырь, пока подключен напрямую к 3.3В выходу ПЛИС. Куплю детали, сделаю выходной LC контур на 28МГц.
Приемник: схему давал раньше, частота оцифровки 75кГц (несущая 28МГц).
Усиление нелинейное, как пересчитывать - так и не придумал, поэтому решил в качестве сигнала брать фазу с 2 уровнями квантования (+1 и -1).
В этом случае еще значительно упрощается фильтрация - не нужны умножители, только сумматоры.
2 полосовых фильтра (sin/cos) порядка 3001, полоса пропускания выбрана ~50...250 Гц, тк полезный сигнал ~150Гц (определяется разбросом кварцев приемника и передатчика).
Амплитуда считается по упрощенной формуле |I|+|Q| после фильтров, выводится на светодиоды.
(Потом попробую переделать математику на передачу до ~10Кбит/сек.)

Аналоговая часть очень критична к разводке ПЛИС (у меня DE0-nano, там многослойная плата).
Будет кто пробовать на Марсоходе2/3 (м/б проблемы из-за отсутствия сплошных земляных полигонов, и наличия последовательных резисторов на выводах)?

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Последнее редактирование: от Leka.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6180

Будет кто пробовать на Марсоходе2/3

Я бы попробовал, но хотелось бы иметь или вещательный диапазон,
или хотя бы любительский 14 МГц, где много станций.
И не ясно пока какая цифровая обработка, нужно ли подключение к компьютеру,
или проект автономный? Тогда как производить настройку, какой нужен дисплей?

Николай.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6188

Создал новую тему для своего проекта.
marsohod.org/forum/proekty-polzovatelej/...-na-plate-marsokhod2

Николай.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Радиоприемник на ПЛИС 3 года 7 мес. назад #6189

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54

Ynicky пишет: Создал новую тему для своего проекта.


Это правильно, тк у меня проект переориентирован на радиосвязь между ПЛИС, и в текущем варианте прием вещательных/любительских станций невозможен.

Но м/б общие узлы, например, децимирующие фильтры, работающие на максимально возможной частоте(от 200МГц), а не на частоте АЦП.


Кстати, как насчет такого метода, вместо обычного аппаратного перемножения каждого отсчета АЦП на sin/cos c последующей децимирующей фильтрацией (символ "ж" - свертка):
i = (s * cos) ж h
q = (s * sin) ж h
аппаратно делать только децимирующую фильтрацию:
i = s ж hc
q = s ж hs
где заранее просчитанные фильтры:
hc = h * cos
hs = h * sin
- с последующим поворотом(после децимации) каждой i(n) q(n) пары отсчетов на угол const*n.
В этом случае не нужен отдельный NCO в ПЛИС, тк sin/cos отсчеты гетеродина перемножаются заранее с коэффициентами НЧ КИХ-фильтра в компе или софт-процессоре (при перестройке частоты), и пишутся(пересылаются) в аппаратные таблицы КИХ-фильтров i/q каналов.
?

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Время создания страницы: 2.379 секунд
ВКонтакте  facebook  GitHub  YouTube  Twitter
Вы здесь: Начало Forum Наш форум Вопросы о плате Марсоход Радиоприемник на ПЛИС