Сворганил BPSK приемо-передатчик с петлей Костаса на базе VCO.
Основной код петли заимствовал на просторах сети.
%% Петля Костаса на базе VCO
%% Модуляция
clear;
% Битовая картика профиля pacman
image = [ 1, 1, 1, 0, 0, 1, 1, 1;
1, 1, 0, 0, 0, 0, 1, 1;
1, 0, 0, 0, 1, 0, 0, 1;
0, 0, 0, 0, 0, 0, 1, 1;
0, 0, 0, 0, 0, 1, 1, 1;
1, 0, 0, 0, 0, 0, 0, 1;
1, 1, 0, 0, 0, 0, 1, 1;
1, 1, 1, 0, 0, 1, 1, 1 ];
% Начальный символ приема
sync_symbol = [ 1 ];
% Битовый поток с начальным символом
bit_stream = [ sync_symbol ];
% Генерация битового потока из матрицы профиля pacman
for j = 1:8
bit_stream = [bit_stream image(j,

];
end
%bit_stream = (rand(1, 6) > 0.5);
%bit_stream = [1 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0];
bit_stream = [1 1 0 1 0];
N = length(bit_stream);
fprintf('bit_stream %d\n', bit_stream);
% Частота семплирования 288 кГц
fs = 288000;
% Несущая частота относительно частоты выборок 36 кГц
f = 0.125;
% Частота доплера 300 Гц
fdop = f/1200;
% Символьная частота 100 Гц
fsim = 100;
% Количество выборок на период несущей 8
ns = 1/f;
% Количество выборок необх. для одного символа (360*8 периодов нес. f)
% Символьная скорость 100 Гц
tsymbol = fs*f*ns/fsim;
fprintf('tsymbol %d\n', tsymbol);
% Счетчик выборок в 0
t = 0;
% Количество символов переданных с нулевой фазой
nDummySymbols = 4;
% Общее количество выборок
%ttotal = N*tsymbol + nDummySymbols * tsymbol + tsymbol*3;
ttotal = N*tsymbol + nDummySymbols * tsymbol;
fprintf('ttotal %d\n', ttotal);
% Создать пустой сигнал
BPSK_signal = zeros(ttotal,1);
% Символы с нулевой фазой
for i = 1:nDummySymbols
for j = 1:tsymbol
BPSK_signal(t+1) = cos( 2*pi*(f+fdop)*t );
BPSK_signal_nomod(t+1) = cos(2*pi*(f+fdop)*t);
t = t + 1;
end
end
fprintf('t %d\n', t);
% BPSK сигнал
for i = 1:length(bit_stream)
phase = pi * bit_stream(i);
for j = 1:tsymbol
BPSK_signal(t+1) = cos(2*pi*(f+fdop)*t + phase);
BPSK_signal_mod(t+1) = cos(2*pi*(f+fdop)*t + phase);
BPSK_signal_nomod(t+1) = 0;
t = t + 1;
end
end
fprintf('length BPSK_signal %d\n', length(BPSK_signal));
fprintf('t %d\n', t);
%% AWGN (аддитивный белый гауссов шум) канал передачи данных
% отношение сигнал/шум в децибелах
SNR = 20;
% мощность сигнала в децибелах
SIGPOWER = 10;
% смесь мод.сигнала с шумом
BPSK_signal = awgn( BPSK_signal, SNR, SIGPOWER);
%% Демодуляция
% полученная картинка в 0
rec_image = zeros(8,8);
% Координаты картинки
x = 1;
y = 1;
% начальный шаг в 0
t = 0;
% Все матрицы в 0
carrier_inph = zeros(ttotal,1);
mixer_inph = zeros(ttotal,1);
demod_thr_inph = zeros(ttotal,1);
% Фильтр демодулятора
b = fir1(100, 0.1);
% Память состояния демодулятора
stateLowpassInph = zeros(numel(

-1,1);
% переменные для PLL осциллятора
% cosine output
c = 1;
% delayed cosine by one timestep
c_delay = 0;
% sine output
s = 0;
% delayed sine by one timestep
s_delay = 0;
% Данные из VCO для целей отладки
sine = zeros(ttotal,1);
cosine =zeros(ttotal,1);
vco = zeros(ttotal,1);
% PLL loop фильтр
bPLL = fir1(40, 0.1);
% and the state memory
zfPLLa = zeros(numel(bPLL)-1,1);
zfPLLc = zeros(numel(bPLL)-1,1);
zfPLLs = zeros(numel(bPLL)-1,1);
% Обратный отсчет. При нулевом значении отбирается символ.
% Начальный обратный отсчет учитывает задержку
% fir lowpass и пропускает начальный символ
sampleMoment = tsymbol/2+tsymbol;
% Это время необходимое PLL для стабилизации на несущей
nPLLsettle = (nDummySymbols/2) * tsymbol;
% Игнорировать данные, пока не получен символ "1"
ignoreData = 1;
% VCO шаг
VCOgain = 0.005;
% VCO, которое управляет частотой. при v = 0 он точно равен f.
v = 0;
% Основной цикл
for step = 1:ttotal
% Получить значение BPSK_signal
sample = BPSK_signal(step);
% PLL - "voltage" управляемый осциллятор с +/- v входом
% w0 частота VCO
w0 = 2*pi*(f+v*VCOgain);
% Cохранить предыдущее состояние
c_delay = c;
s_delay = s;
% Подсчет нового состояния
c = c_delay * cos(w0) - s_delay * sin(w0);
s = s_delay * cos(w0) + c_delay * sin(w0);
% Cохраним все в удобных векторах для графики
sine(step) = s;
cosine(step) = c;
vco(step) = v;
% конец VCO
% Сохраняем sine/cosine. Обратите внимание, что инфазная волна
% теперь является синусоидальной волной, потому что PLL с мультипликацией
% в качестве фазового детектора имеет сдвиг фазы на 90 градусов между
% входом и выходом
carrier_inph(step) = c;
% Это решает, находимся ли мы в режиме синхронизации PLL или режима замораживания
% Примечание: это должно быть заменено блокировкой PLL в реальном приеме,
% потому что мы не знаем, когда передача фактически
% начинается. Здесь мы просто предполагаем, что она начинается с самого начала
% PLL in action: изменение частоты через v
% Фазовый детектор
pc = sample*c;
ps = sample*-s;
% filtering out the 2f term
% Фильтрация pc
[vc,zfPLLc] = filter(bPLL,1,pc,zfPLLc);
% filtering out the 2f term
% Фильтрация ps
[vs,zfPLLs] = filter(bPLL,1,ps,zfPLLs);
[v,zfPLLa] = filter(bPLL,1,vc*vs,zfPLLa);
% we sneak here a -1 in because this is ambigous
% шаг на -1
mixer_inph(step) = -sample*carrier_inph(step);
[lp_demod_inph(step),stateLowpassInph] = filter(b,1,mixer_inph(step),stateLowpassInph);
demod_thr_inph(step) = lp_demod_inph(step);
if (ignoreData)
% Ждем стартового символа 1
if ( lp_demod_inph(step) > 0.25 )
% got it!
% Стартовый символ прошел
ignoreData = 0;
end
else
% Ожидание середины символа для выборки демодулятора
sampleMoment = sampleMoment - 1;
if (sampleMoment == 0)
sampleMoment = tsymbol;
if ( demod_thr_inph(step) > 0.2 )
lsb = 1;
else
lsb = 0;
end
fprintf('lsb %d\n', lsb);
% debug samples: add small spikes
% отладка: добавка небольших пиков
lp_demod_inph(step) = lp_demod_inph(step) + 0.1;
% Сохранить результат в картинку
if (((x<9) && (y<9)) && (ignoreData == 0))
rec_image(y,x) = lsb;
x = x + 1;
if (x > 8)
x = 1;
y = y + 1;
end % if (x > 8)
end % x>9 && y>9
end % sampleMoment == 0
end % ignore data
% Следующий шаг в выборке
t = t + 1;
end
%% Графика
% Немодулированный сигнал
figure;
plot(BPSK_signal_nomod, 'b-', 'LineWidth', 2);
hold on;
grid on;
title('Немодулированный сигнал');
% Модулированный сигнал
figure;
plot(BPSK_signal_mod, 'b-', 'LineWidth', 2);
hold on;
grid on;
title('Модулированный сигнал');
% Полный BPSK_signal
figure;
plot(BPSK_signal, 'b-', 'LineWidth', 2);
hold on;
grid on;
title('BPSK сигнал');
% Демодулированный сигнал
figure;
subplot(2,1,1);
plot(lp_demod_inph,'LineWidth',2);
xlabel('Samples');
ylabel('Amplitude');
title('demod / lowpass filtered');
grid on;
% Картинка
subplot(2,1,2);
imshow(rec_image);
% Напряжение VCO
figure;
subplot(1,1,1);
plot(vco);
Работает при соотнощении сигнал-шум 20 на 10 децибел, доплере 30 Гц при несущей в 36 кГц и символьной скорости 100 Гц
Напрягает то, что при соотношении сигнал шум 1 приемник перестает работать. Все разваливается, даже при нулевом доплере.
Получается что для нормальной работы BPSK приемника необходим хороший приемный усилитель с узкой полосой (определяется удвоенной символьной скоростью) и коэффициентом усиления достаточным, чтобы при минимально возможном сигнале на его входе он мог обеспечить необходимый уровень сигнала на входе BPSK приемника.
Но с другой стороны при максимально возможном уровне сигнала на входе приемного усилителя он не должен входить в ограничение выхода.