Введение
Передача информации в современном мире нас окружает повсюду: мобильная связь, интернет, управление воздушным движением и многое другое. Как правило, в качестве “переносчика” информации выступает высокочастотное колебание: 2.4 ГГц и 5 ГГц для Wi-Fi, 2.6 ГГц и другие для 4G, 1030 МГц и 1090 МГц для обмена данными с воздушными судами и т.д. Эти колебания (частоты) называются несущими. Как, используя несущую частоту, закодировать данные? Как передать или получить “0” или “1”? На эти вопросы мы и постараемся ответить.
Процесс изменения одного или нескольких параметров модулируемого несущего сигнала при помощи модулирующего сигнала называется модуляцией.
В рамках данной лекции мы рассмотрим следующие виды модуляции:
- ASK (Amplitude Shift Keying) — амплитудная манипуляция
- BPSK, QPSK (Binary Phase Shift Keying, Quadrature Phase Shift Keying) — фазовая манипуляция
- QASK (Quadrature Amplitude-Shift Keying) — квадратурная манипуляция
- FSK (Frequency Shift Keying), MSK (Minimum Shift Keying) — частотная манипуляция
Амплитудная манипуляция (ASK)
Амплитудная манипуляция — манипуляция, при которой скачкообразно изменяется амплитуда несущего сигнала в зависимости от закодированного сообщения.
Рассмотрим пример. Создадим сигнал fc, который из себя будет представлять несущую частотой 500 Гц, добавим в неё немного шума и промодулируем кодовой последовательностью (сообщением), заданной в массиве code. Логическому “нулю” будет соответствовать амплитуда 0.1, логической “единице” — 1:
clear, clc, close all
fs = 10000;
ts = -0.1 : 1/fs : 0.1-1/fs;
N = length(ts);
%% несущая частота
fc = cos(2*pi*500*ts);
fc = awgn(fc,30);
%% модулирующий сигнал
% длина одного бита в отсчётах
n_for_bit = 200;
% кодируемая последовательность
code = [1 0.1 0.1 1 1 0.1 1 0.1 1 1];
% формируем модулирующий сигнал
fm = zeros(1,N);
for i=1:length(code)
for j=n_for_bit*(i-1)+1:n_for_bit*i
fm(j) = code(i);
end
end
%% амплитудная модуляция
x = fc.*fm;
plot(ts,x,'LineWidth',0.5), grid on, hold on
plot(ts,fm,'LineWidth',2), grid on
title ('ASK модуляция')
xlabel('Время'), ylabel('Амплитуда')
legend({'Модулированный сигнал';'Модулирующий сигнал'})
Результат выполнения скрипта показан ниже:
Из рисунка видно, что амплитуда несущего (модулированного) сигнала — синий график — повторяет форму модулирующего сигнала — оранжевый график.
Теперь давайте сделаем следующую вещь: на комплексной плоскости отметим точки, соответствующие значениям, которые принимает наш закодированный сигнал. В Matlab это можно сделать с помощью функции scatterplot, указав в качестве входных параметров аналитический сигнал (мы его получим с помощью преобразования Гильберта), количество отсчётов на бит (у нас за это отвечает переменная n_for_bit) и смещение от начала сигнала, с которым будут считываться биты (мы хотим считывать биты в их середине, поэтому смещение зададим n_for_bit/2):
%% сигнальное созвездие scatterplot(hilbert(x),n_for_bit,round(n_for_bit/2)), grid on
Посмотрим результат:
Т.к. мнимая часть равна нулю, мы видим два скопления точек вдоль действительной оси: одно вокруг значения 0.1, второе — вокруг 1. Этот график называется сигнальное созвездие. Он часто используется при анализе характеристик модулированных сигналов, т.к. показывает распределение мгновенного значения сигнала на комплексной плоскости в момент его считывания.
Итак, модулированный сигнал есть — попробуем его обратно демодулировать. Наша задача сводится к нахождению огибающей, а как мы выяснили на прошлой лекции — это легко сделать с помощью преобразования Гильберта. Затем создадим что-то вроде цифрового компаратора, с помощью которого зашумлённую огибающую превратим в прямоугольный цифровой сигнал. Дополним наш код:
%% амплитудная демодуляция
% преобразование Гильберта
h = hilbert(x);
figure
subplot(2,1,1)
plot(ts,x,'LineWidth',0.5), grid on, hold on
plot(ts,abs(h),'LineWidth',2), grid on
title ('ASK демодуляция')
xlabel('Время'), ylabel('Амплитуда')
legend({'Модулированный сигнал';'Демодулированный сигнал'})
% компаратор
dem = zeros(1,length(h));
for i=1:length(h)
if abs(h(i))>=0.5
dem(i) = 1;
else
dem(i) = 0;
end
end
subplot(2,1,2)
plot(ts,dem,'LineWidth',2), grid on
title ('Код демодулированного сигнала')
xlabel('Время'), ylabel('Амплитуда')
Смотрим результат:
Как видим, демодулированный сигнал повторяет битовую последовательность, которую мы закодировали изначально в массиве code, а значит мы всё сделали правильно.
Ещё одним типом амплитудной манипуляции является OOK — On-Off Keying. Основное отличие от ASK — логический “ноль” кодируется амплитудой, равной нулю, “единице” соответствует номинальное значение амплитуды сигнала. Если в листинге “ASK-манипуляция, часть 1” в массиве code вместо всех значений 0.1 запишем 0, то как раз получим OOK-манипуляцию.
Фазовая манипуляция (PSK)
Фазовая манипуляция — манипуляция, при которой скачкообразно изменяется фаза несущего сигнала в зависимости от закодированного сообщения.
Начнём с самого простого вида — BPSK — когда у нас всего два значения фазы —
и
.
Создадим скрипт, реализующий фазовую манипуляцию зашумлённой несущей частоты fc, равной 250 Гц. Кодовую последовательность по аналогии с первым примером будем задавать в массиве code. Перескок фазы будет осуществляться умножением синусоидального сигнала на +1 или -1:
clear, clc, close all
fs = 10000;
ts = 0 : 1/fs : 0.2-1/fs;
N = length(ts);
%% несущая частота
fc = cos(2*pi*250*ts);
fc = awgn(fc,30);
%% модулирующий сигнал
% длина одного бита в отсчётах
n_for_bit = 200;
% кодируемая последовательность
code = [1 -1 -1 1 1 -1 1 -1 1 1];
% формируем модулирующий сигнал
fm = zeros(1,N);
for i=1:length(code)
for j=n_for_bit*(i-1)+1:n_for_bit*i
fm(j) = code(i);
end
end
%% фазовая манипуляция (BPSK)
x = fc.*fm;
plot(ts,x,'LineWidth',0.5), grid on, hold on
plot(ts,fm,'LineWidth',2), grid on
title ('BPSK модуляция')
xlabel('Время'), ylabel('Амплитуда')
legend({'Модулированный сигнал';'Модулирующий сигнал'})
Смотрим, что получилось:
Каждое изменение логического уровня модулирующего сигнала приводит к скачкообразному изменению фазы несущей частоты на
, а это то, что нужно.
Теперь дополним код по аналогии с предыдущим примером и построим сигнальное созвездие:
%% сигнальное созвездие scatterplot(hilbert(x),n_for_bit,round(n_for_bit/2)), grid on
Сигнальное созвездие BPSK-сигнала:
Мы имеем два скопления точек: вокруг (-1,0) и (1,0). Эти точки как раз соответствуют повороту вектора единичной длины на
и
вокруг начала координат. А значит, модуляция работает корректно.
Теперь наша задача — демодулировать сгенерированный сигнал. Для этого умножим его на несущую частоту fc, а затем применим к полученному сигналу ФНЧ с полосой пропускания 100 Гц, сгенерированный с помощью filterDesigner:
%% BPSK демодуляция
% умножаем сигнал на несущую
y = x.*fc;
% применяем ФНЧ, чтобы убрать несущую
fltr = bpsk_fir;
z = filter(fltr.Numerator,1,y);
figure;
subplot(2,1,1)
plot(ts,y), grid on
title('Модулированный сигнал, умноженный на несущую')
xlabel('Время'), ylabel('Амплитуда')
subplot(2,1,2)
plot(ts,z), grid on
title('Тот же сигнал, прошедший через ФНЧ')
xlabel('Время'), ylabel('Амплитуда')
Получаем результаты:
На верхнем графике наблюдаем синусоиды с частотой 2*fc, имеющие разные постоянные составляющие в зависимости от значения фазы модулированного сигнала. Для того, чтобы получить огибающую, мы воспользовались ФНЧ и получили нижний график. Теперь, чтобы преобразовать данный сигнал в цифровой код, разработаем простейший цифровой компаратор с пороговым значением 0.1 и построим результирующие графики:
% компаратор
dem = zeros(1,length(z));
for i=1:length(z)
if z(i)>=0.1
dem(i) = 1;
else
dem(i) = 0;
end
end
figure
plot(ts,x,'LineWidth',0.5), grid on, hold on
plot(ts,dem,'LineWidth',2), grid on
xlabel('Время'), ylabel('Амплитуда')
title ('BPSK демодуляция')
legend({'Модулированный сигнал';'Демодулированный сигнал'})
Демодулированный сигнал на фоне модулированного сигнала представлен ниже:
Как видим, он повторяет форму модулирующего сигнала, заданного в начале листинга, но имеет временную задержку, возникающую в КИХ-ФНЧ.
В рассмотренном примере модулированный сигнал мог принимать два значения фазы:
и
, а значит в один момент времени (такт) можно закодировать только один бит информации — “0” или “1”. Если добавить ещё два изменения фазы (
и
), а затем повернуть полученную диаграмму на
против часовой стрелки, получится QPSK-манипуляция, или квадратурная фазовая манипуляция. В этом случае мы за один такт сможем передавать сразу два бита информации! Посмотрим, как в этом случае будет выглядеть сигнальное созвездие. Разработаем скрипт, который формирует массив случайных данных data, которые затем преобразуем в массив значений PSK-сигнала с помощью функции pskmod, в качестве второго параметра которой будет порядок модуляции (для QPSK это M = 4). В качестве третьего параметра данной функции необходимо задать смещение нулевого значения фазы, в нашем случае, как было сказано выше, это
(тогда, в идеальном случае, в каждом квадранте комплексной плоскости будет по одной точке созвездия). Далее добавим немного шума в этот сигнал, чтобы имитировать реальные условия передачи данных и построим сигнальное созвездие:
clear, clc, close all M = 4; data = randi([0 M-1],1000,1); txSig = pskmod(data, M, pi/M); rxSig = awgn(txSig,20); scatterplot(rxSig), grid on
Получилось вот так:
Мы видим скопление точек вокруг значений
,
,
,
, каждая из которых соответствует положению единичного вектора, начало которого соответствует началу координат, при его повороте с шагом
. Соответствие фазы и передаваемой информации будет иметь следующий вид:
— “11”
— “01”
— “00”
— “10”
Это значит, что при при той же самой символьной скорости сигнал с QPSK передаёт в 2 раза больше информации, чем сигнал с BPSK.
Если присвоить M = 8 и убрать из строки 5 параметр pi/M, получим 8-PSK-манипуляцию. Сигнальное созвездие примет вид:
Здесь мы можем передавать за один такт сразу 3 бита. Однако, с увеличением порядка модуляции M, точки созвездия располагаются всё ближе и ближе друг другу, что может привести к ошибкам декодирования такого сигнала, если он сильно зашумлён. Можете поиграться со значениями M и параметром snr функции awgn, чтобы убедиться в этом на примере.
Квадратурная манипуляция (QASK)
QASK (частный случай QAM — Quadrature Amplitude Modulation) — это вид манипуляции, при которой скачкообразно изменяется как амплитуда, так и фаза несущего сигнала, что позволяет за один такт (отсчёт) передать ещё больше информации, чем в рассмотренных ранее видах манипуляции. Можно сказать, что QASK — это комбинация ASK и PSK.
По традиции, сразу начнём с примера. Создадим несущую с частотой 1кГц, помимо этого создадим массив данных data, который будет содержать случайные числа. Зададим порядок модуляции M=16, это значит, что за один такт будем передавать число от 0 до 15, или 4 бита. Один элемент — один такт передачи, количество элементов — 50. Затем создадим массив отсчётов QASK на базе этих данных с помощью функции qammod и построим сигнальное созвездие из полученного набора данных.
clear, clc, close all fs = 10000; ts = 0 : 1/fs : 0.2-1/fs; N = length(ts); %% несущая частота fc = 1000; %% Модуляция M = 16; % порядок QASK модуляции Nd = 50; % размер данных bit_size = N/Nd; % количество отсчётов на бит data = randi([0 M-1],Nd,1); % случайные данные % формируем массив комплексных чисел qdata = qammod(data, M); % сигнальное созвездие sc = scatterplot(qdata); grid on obj = findobj(sc.Children(1).Children, 'type', 'line'); set(obj, 'MarkerSize', 20)
Результат показан ниже:
Это созвездие состоит из 16 групп точек, а значит сформированный сигнал принимает все возможные значения для QASK-манипуляции 16 порядка.
Теперь “поместим” эти данные на несущую частоту. Растянем массив данных до того же количества отсчётов, что и в сигнале несущей частоты (каждый бит повторим bit_size раз) и получим массив qmod. Поэлементно умножим действительные части данного массива на косинус с частотой fc, а мнимые — на синус той же частоты. Просуммируем полученные сигналы (i и q соответственно), в результате чего получим модулированный сигнал y, который готов для передачи. Добавим в него шум для имитации электромагнитных помех и построим графики.
qmod = repelem(qdata,bit_size).'; % размножаем массив данных до кол-ва отсчётов несущей
% формируем синусный и косинусный сигналы
i = real(qmod).*cos(2*pi*fc*ts);
q = imag(qmod).*sin(2*pi*fc*ts);
% суммируем i и q, получаем сигнал, готовый к передаче
y = i+q;
% добавляем шум
y = awgn(y,20);
figure
subplot(3,1,1)
plot(real(qmod)), grid on
title('Действительная часть сигнала')
xlabel('Время'), ylabel('Real')
subplot(3,1,2)
plot(imag(qmod)), grid on
title('Мнимая часть сигнала')
xlabel('Время'), ylabel('Imag')
subplot(3,1,3)
plot(y), grid on
title('Модулированный сигнал')
xlabel('Время'), ylabel('Амплитуда')
Действительная и мнимая части сигнала, а также сам сигнал y можно увидеть на рисунке ниже:
Видно, что в процессе передачи данных изменяется как амплитуда, так и фаза несущей.
Теперь решим обратную задачу: демодулируем сигнал на нижнем графике. Для этого обратно выделим из него синфазную io и квадратурную qo составляющие умножением на косинус и синус несущей частоты соответственно. Чтобы убрать высокочастотную составляющую, как и в BPSK, применим ФНЧ, в результате чего получим сигналы iof и qof, графики которых затем и построим.
%% Демодуляция
io = 2*y.*cos(2*pi*fc*ts);
qo = 2*y.*sin(2*pi*fc*ts);
% применяем ФНЧ, чтобы убрать несущую и умножаем на 2
fltr = qam_fir;
iof = round(conv(fltr.Numerator,io));
qof = round(conv(fltr.Numerator,qo));
figure
subplot(2,1,1)
plot(iof), grid on
title('Синфазная составляющая демодулированного сигнала после ФНЧ')
subplot(2,1,2)
plot(qof), grid on
title('Квадратурная составляющая демодулированного сигнала после ФНЧ')
А вот и графики:
Следует обратить внимание, что при выделении синфазной и квадратурной составляющей, мы также сделали умножение на два (и получили при этом правильные амплитуды). Давайте разбираться, в чём дело. Как было сказано выше, входной сигнал был умножен на функции
и
. При умножении на косинус получаем сигнал:
(1) 
При умножении на синус:
(2) 
После применения ФНЧ косинусоидальные и синусоидальные составляющие уходят, остаётся только постоянная составляющая:
(3) ![]()
(4) ![]()
Поэтому, чтобы скомпенсировать амплитуду демодулированного сигнала, в строчках 49 и 50 мы и сделали умножение на 2.
Далее преобразуем iof и qof в один комплексный сигнал of, который проредим, взяв из него отсчёты, расположенные в серединах временных отрезков, соответствующих битам данных. Затем воспользуемся функцией qamdemod и сравним результаты: что закодировали, и что в последствии декодировали.
%% Сравнение результатов
% формируем комплесный сигнал после фильтра
of = complex(iof,qof);
% считываем из массива значения с шагом,
% равным периоду следования данных
% и с учётом задержки КИХ-фильтров
fir_delay = round(length(fltr.Numerator)/2);
of_dec = of(fir_delay+round(bit_size/2) : bit_size : length(of)-fir_delay);
% Сравниваем результаты
y = qamdemod(of_dec, M);
figure
plot(data,'b-'), grid on, hold on
plot(y,'x','LineWidth',2)
title('Сравнение закодированных (переданных) и декодированных (принятых) данных')
xlabel('Номер отсчёта'), ylabel('Значение')
legend({'Переданные данные';'Принятые данные'})
Синий график на рисунке отображает входные данные, на основе которых был сформирован модулированный сигнал, красными крестиками — данные, полученные в результате демодуляции этого сигнала:
Как видим, два графика полностью совпадают, а это говорит о том, что реализованный нами алгоритм работает корректно.
Частотная манипуляция (FSK)
Если во всех предыдущих рассмотренных нами видах манипуляции частота несущей была постоянна, то в случае с FSK это не так. FSK — это манипуляция, при которой в зависимости от закодированного сообщения скачкообразно изменяется частота несущего сигнала.
Данный вид манипуляции считается самым помехоустойчивым, т.к. помехи чаще всего влияют на амплитуду, а не на несущую частоту. Частота логического “0” и логической “1” вычисляются по формулам:
(5) ![]()
(6) ![]()
где:
— несущая частота
— коэффициент модуляции
— период передаваемого сообщения
При
манипуляция называется Minimum Shift Keying (MSK) — манипуляция с минимальным сдвигом частоты.
И снова к примеру. Разработаем скрипт, формирующий FSK-модулированный сигнал. Несущую частоту выберем 500 Гц, индекс модуляции
, период следования битов данных 10 мкс. На основе этого рассчитаем значение двух частот: f0 и f1, кодирующие логический “0” и “1” соответственно.
clear, clc, close all fs = 10000; ts = 0 : 1/fs : 0.1-1/fs; N = length(ts); %% параметры несущей fc = 500; % несущая частота h = 4; % индекс модуляции T = 10e-3; % длительность бита f0 = fc+h/(2*T); % частота лог. "0" f1 = fc-h/(2*T); % частота лог. "1"
Далее сформируем модулирующий сигнал по аналогии с тем, как мы это делали в примерах с BPSK и ASK:
%% модулирующий сигнал
% длина одного бита в отсчётах
n_for_bit = T*fs;
% кодируемая последовательность
code = [1 0 0 1 1 0 1 0 1 1];
% формируем модулирующий сигнал
fm = zeros(1,N);
for i=1:length(code)
for j=n_for_bit*(i-1)+1:n_for_bit*i
fm(j) = code(i);
end
end
Теперь создадим два сигнала: x0 с частотой f0 и x1 с частотой f1. На базе этих сигналов и модулирующего сигнала fm сформируем модулированный сигнал x и построим графики.
%% Частотная манипуляция
x0 = cos(2*pi*f0*ts);
x1 = cos(2*pi*f1*ts);
x = zeros(1,N);
for i = 1:N
if fm(i) == 0
x(i) = x0(i);
else
x(i) = x1(i);
end
end
plot(ts,x,'LineWidth',0.5), grid on, hold on
plot(ts,fm,'LineWidth',2), grid on
title ('FSK-модуляция')
xlabel('Время'), ylabel('Амплитуда')
legend({'Модулированный сигнал';'Модулирующий сигнал'})
Результат выполнения данного скрипта:
Из рисунка видно, что в зависимости от значения модулирующего сигнала, меняется частота несущей — это то, что нам нужно. Модулировать научились — теперь попробуем это демодулировать. Для этого умножим наш сигнал на косинусоиды с частотами f0 и f1:
%% FSK-демодуляция
% умножаем сигнал на несущую
y0 = x.*x0;
y1 = x.*x1;
figure;
subplot(2,1,1)
plot(ts,y0), grid on
title('Модулированный сигнал, умноженный на f0')
xlabel('Время'), ylabel('Амплитуда')
subplot(2,1,2)
plot(ts,y1), grid on
title('Модулированный сигнал, умноженный на f1')
xlabel('Время'), ylabel('Амплитуда')
Сигналы y0 и y1 показаны ниже:
Теперь найдём разность этих сигналов и пропустим её через ФНЧ:
y = y1 - y0;
% применяем ФНЧ, чтобы оставить постоянную составляющую
fltr = fsk_fir;
z = filter(fltr.Numerator,1,y);
figure
subplot(2,1,1)
plot(ts,y), grid on
title('Сигнал y=y0-y1')
xlabel('Время'), ylabel('Амплитуда')
subplot(2,1,2)
plot(ts,z), grid on
title('Этот же сигнал после ФНЧ')
xlabel('Время'), ylabel('Амплитуда')
Результат показан ниже:
До финала осталось совсем немного — преобразовать нижний график в цифровой сигнал. Для этого, как и в случае с BPSK, воспользуемся цифровым компаратором и построим результирующий график:
% компаратор
dem = zeros(1,length(z));
for i=1:length(z)
if z(i)>=0.1
dem(i) = 1;
else
dem(i) = 0;
end
end
figure
plot(ts,x,'LineWidth',0.5), grid on, hold on
plot(ts,dem,'LineWidth',2), grid on
xlabel('Время'), ylabel('Амплитуда')
title ('FSK-демодуляция')
legend({'Модулированный сигнал';'Демодулированный сигнал'})
Результат демодуляции показан ниже:
Как видим, оранжевый график имеет ту же форму, что и на первоначальном рисунке, но с уже привычной нам временной задержкой, возникающей в цифровом КИХ-фильтре.
Скачать конспект в pdf: Modulation and Demodulation of Digital Signals Lecture – V.V. Leonidov.pdf
Comments (12)