Сообщество Engee

Модуляция OFDM

Автор
avatar-yurevyurev
Notebook

Модуляция OFDM: принципы работы и практическая реализация

Мультиплексирование с ортогональным частотным разделением (OFDM) – это современная технология модуляции, ставшая основой для множества стандартов беспроводной связи, включая Wi-Fi, LTE и цифровое телевидение DVB. Её ключевая идея состоит в преобразовании высокоскоростного последовательного потока данных в набор параллельных низкоскоростных потоков, каждый из которых передаётся на отдельной ортогональной поднесущей частоте. Такой подход кардинально решает проблему межсимвольной интерференции (ISI) и устойчивости к частотно-селективным замираниям, которые особенно выражены в многолучевых каналах распространения сигнала, характерных для современных беспроводных систем.

В данной статье рассматривается полный цикл обработки сигнала в системе OFDM – от теоретических основ до практической реализации на языке программирования Julia. Мы поэтапно разберём весь процесс: начиная с генерации символов квадратурной амплитудной модуляции (QAM), через формирование OFDM-сигнала и моделирование его прохождения через искажающий канал, и заканчивая приёмом, выравниванием и демодуляцией, позволяющей восстановить исходные данные.

Проблема, которую призван решить OFDM, особенно актуальна для систем с одной несущей и высокой скоростью передачи. В них требуются короткие символьные интервалы и, как следствие, широкая полоса пропускания. Когда такой широкополосный сигнал проходит через многолучевой канал с частотно-селективными свойствами, импульсная характеристика канала может растягиваться во времени и накладываться на несколько последующих символов. Это и есть межсимвольная интерференция, которая приводит к ошибкам при приёме.

OFDM предлагает элегантное решение: вместо передачи одного быстрого потока в широкой полосе используется множество медленных потоков в узких ортогональных подполосах. Поскольку каждый такой подканал имеет гораздо меньшую скорость символов, длительность каждого символа значительно увеличивается относительно времени задержки в канале. В результате каждый символ "видит" почти плоскую (неискажённую) частотную характеристику канала в пределах своей узкой полосы, что практически устраняет межсимвольную интерференцию.

С математической точки зрения, OFDM-сигнал представляет собой сумму N ортогональных поднесущих, модулированных независимыми символами данных. Дискретный выход модулятора может быть записан как обратное дискретное преобразование Фурье (IDFT) от вектора комплексных модуляционных символов. На практике для эффективного вычисления этого преобразования применяется алгоритм обратного быстрого преобразования Фурье (IFFT), что делает реализацию OFDM вычислительно эффективной даже при большом числе поднесущих, исчисляемых сотнями или тысячами.

Перейдём к реализации, код ниже содержит две демонстрационные функции, которые визуализируют фундаментальные концепции технологии OFDM. По миом основных функций, есть вспомогательные rectpulse и rectpuls используемые для формирования прямоугольных импульсов необходимой формы.

Первая функция, helperPlotMultipath(), наглядно демонстрирует основную проблему, которую призван решить OFDM — межсимвольную интерференцию в частотно-селективном канале. Она генерирует два сигнала: высокоскоростной с короткой длительностью символа и низкоскоростной с увеличенной длительностью символа. Функция моделирует их прохождение через многолучевой канал и строит графики как во временной, так и в частотной областях. На графике временной области видно, как импульсная характеристика канала накладывается на несколько символов высокоскоростного сигнала, вызывая их интерференцию, в то время как низкоскоростной сигнал благодаря более длинному символу остаётся неискажённым. В частотной области становится очевидным, что полоса пропускания низкоскоростного сигнала лежит в пределах почти плоского участка частотной характеристики канала, тогда как широкополосный сигнал испытывает значительные искажения по всей своей полосе.

Вторая функция, helperPlotOFDM(), иллюстрирует ключевой принцип OFDM — ортогональность поднесущих. Она создаёт четыре прямоугольных импульса во временной области, сдвинутых по частоте на величину, равную символьной скорости. Функция строит графики как временной формы этих импульсов, так и их спектральных характеристик. Особенно важен график в частотной области, который показывает, что спектры этих импульсов расположены таким образом, что пик каждого спектра приходится на нулевые значения всех остальных. Именно эта ортогональность позволяет поднесущим не мешать друг другу, несмотря на перекрытие их спектров, что обеспечивает эффективное использование полосы частот.

In [ ]:
include("Helperplot.jl")
include("HeplerplotOFDM.jl")
display(helperPlotMultipath())
display(helperPlotOFDM())
(nothing, nothing)
(nothing, nothing)

Код ниже представляет собой практическую реализацию базового OFDM-модулятора. В нём последовательно выполняются ключевые этапы формирования OFDM-сигнала. Сначала инициализируются компоненты для работы с преобразованием Фурье и задаются основные параметры системы: используется модуляция 16-QAM, где каждый символ кодирует 4 бита информации, а размер преобразования Фурье установлен в 128 точек. Затем создаётся генератор случайных целых чисел, который формирует поток из 128 символов для передачи. Эти символы поступают на модулятор 16-QAM, где каждый из них отображается в соответствующую точку на комплексной плоскости. Созвездие модуляции предварительно нормируется, чтобы обеспечить единичную среднюю мощность сигнала. Следующий шаг — это ядро формирования OFDM-сигнала. Полученный вектор комплексных символов txgrid подаётся на вход операции обратного быстрого преобразования Фурье (IFFT). Выполняемые операции conj (комплексное сопряжение) до и после преобразования являются технической особенностью реализации, обеспечивающей соответствие математическому определению IFFT. Результат также масштабируется делением на длину преобразования. На выходе получается временной OFDM-сигнал txout, который представляет собой сумму всех 128 ортогональных поднесущих, модулированных соответствующими символами QAM.

Визуализация результата осуществляется построением графика реальной части сформированного OFDM-сигнала во временной области, где каждый отсчёт отображается в виде вертикального столбца. Этот график позволяет наблюдать характерную многокомпонентную структуру OFDM-символа, являющуюся результатом интерференции множества синусоидальных поднесущих с разными амплитудами и фазами, заданными модуляционными символами.

In [ ]:
using EngeeComms
using EngeeDSP

var_fft = EngeeFFT();
var_fftshift = EngeeFFTshift();   
bps = 4;    # Кол-во бит на символ
M = 2^bps;  # 16QAM
nFFT = 128; # Число ячеек FFT

var_rand = RandomIntegerGenerator(SetSize=M,InitialSeed=1234,SampleTime=1.0,SamplesPerFrame=nFFT);
var_qam = GeneralQAMModulatorBaseband(Constellation=[-3+3im,-3+1im,-3-3im,-3-1im,-1+3im,-1+1im,-1-3im,-1-1im,3+3im,3+1im,3-3im,3-1im,1+3im,1+1im,1-3im,1-1im]./sqrt(10));
txsymbols = step!(var_rand,0.0);
txgrid = step!(var_qam,vec(txsymbols));
txout = conj(step!(var_fft,conj(txgrid)))/length(txgrid);
pl = plot([1:nFFT...],real(txout),linecolor = :blue, line=:stem,marker=:dot,)
Out[0]:

Следующий фрагмент кода моделирует упрощённый процесс приёма и демодуляции OFDM-сигнала в идеальных условиях. После формирования OFDM-сигнала txout он поступает в канал связи. Сначала создаётся модель канала с аддитивным белым гауссовским шумом (AWGN). Параметр EbNo=100 устанавливает очень высокое отношение сигнал/шум, что практически соответствует условиям отсутствия шума и позволяет изолировать работу алгоритма от его влияния. Сгенерированный OFDM-сигнал пропускается через этот канал, и на выходе получается принятый сигнал rxin. Затем выполняется ключевой шаг демодуляции OFDM — преобразование принятого временного сигнала обратно в частотную область с помощью прямого быстрого преобразования Фурье (FFT). Эта операция, обратная IFFT на стороне передатчика, разделяет ортогональные поднесущие и позволяет извлечь модуляционные символы, которые были на них поданы. Результат rxgrid представляет собой вектор принятых комплексных символов в частотных ячейках. Далее создаётся демодулятор 16-QAM, настроенный на то же самое созвездие, что использовалось при модуляции. Этот демодулятор принимает решение о том, какой символ был передан, сравнивая каждый принятый комплексный отсчёт из rxgrid с ближайшей точкой эталонного созвездия. Выходом демодулятора является поток целых чисел rxsymbols. Наконец, выполняется проверка корректности всей цепочки обработки. Исходные переданные символы txsymbols сравниваются с демодулированными принятыми символами rxsymbols. Поскольку моделирование проводится в практически бесшумном канале и без учёта таких реалистичных эффектов, как многолучевое распространение или смещение по частоте, результат демодуляции должен быть идеальным. Сообщение "Восстановленные символы соответствуют переданным символам" подтверждает, что базовые алгоритмы модуляции (QAM), преобразования (IFFT/FFT) и демодуляции работают корректно в этой упрощённой схеме. Это служит основой для последующего усложнения модели добавлением эффектов реального канала, таких как частотно-селективные замирания, что потребует введения дополнительных этапов обработки, в частности, выравнивания сигнала.

In [ ]:
st = AWGN( EbNo=100, BitsPerSymbol=M, SignalPower=1);
rxin =  step!(st, txout);
rxgrid =step!(var_fft, rxin);
var_demod = GeneralQAMDemodulatorBaseband(Constellation=[-3+3im,-3+1im,-3-3im,-3-1im,-1+3im,-1+1im,-1-3im,-1-1im,3+3im,3+1im,3-3im,3-1im,1+3im,1+1im,1-3im,1-1im]./sqrt(10),OutType="Integer");
rxsymbols = step!(var_demod, vec(rxgrid));
if isequal(vec(txsymbols),vec(rxsymbols))
    display("Восстановленные символы соответствуют переданным символам.")
else
    display("Восстановленные символы не соответствуют переданным символам.")
end
"Восстановленные символы соответствуют переданным символам."

Код ниже задаёт тестовый входной сигнал u1 и импульсную характеристику канала h, а затем визуализирует их. Эта подготовка необходима для наглядной демонстрации ключевой проблемы: линейная свертка сигнала с каналом в системах без циклического префикса приводит к межсимвольной интерференции, так как "хвост" импульсной характеристики накладывается на последующие символы. Понимание этого эффекта является основой для введения циклического префикса в OFDM, который преобразует линейную свертку в циклическую, что, в свою очередь, позволяет применять простое выравнивание в частотной области.

In [ ]:
using EngeeDSP.Functions

u1 = [1:8...]; 
h = [0.4,1,0.4];

p1 = plot(u1,linecolor = :blue, line=:stem,marker=:dot, title = "Входной сигнал");
ylims!(0,10);
xlims!(0,10);

p2 = plot(h,linecolor = :blue, line=:stem,marker=:dot,title ="Импульсная характеристика канала");
ylims!(0,2);
xlims!(0,10);
plots1 = plot(p1,p2,layout=(2,1),legend = false)
WARNING: using Functions.cos in module Main conflicts with an existing identifier.
WARNING: using Functions.sin in module Main conflicts with an existing identifier.
WARNING: using Functions.rectpuls in module Main conflicts with an existing identifier.
Out[0]:

Следующий код наглядно демонстрирует различие между линейной и циклической сверткой — фундаментальную проблему, которую решает OFDM. Сначала вычисляется линейная свертка yl1 сигнала u1 с каналом h, моделируя реальное искажение в канале связи. Затем, чтобы получить циклическую свертку yc1, векторы дополняются нулями до одинаковой длины и перемножаются в частотной области через БПФ, после чего результат преобразуется обратно во временную область. График с двумя наложенными друг на друга последовательностями чётко показывает, что результаты линейной и циклической свертки не совпадают. Именно это несовпадение является причиной межсимвольной интерференции и объясняет, зачем в OFDM добавляют циклический префикс: он искусственно делает свёртку циклической, что является необходимым условием для последующего простого выравнивания в частотной области.

In [ ]:
yl1 = conv(u1,h);
yc1 = ifft(fft(u1).*fft([h;zeros(length(u1)-length(h))];));

p3 = plot(yl1,linecolor = :blue, line=:stem,marker=:dot, label = "Линейная");
p4 = plot!(yc1,linecolor = :red, line=:stem,marker=:cross, label = "Циклическая");
p3
Out[0]:

Далее демонстрируется решение проблемы, показанной ранее, с помощью метода, лежащего в основе OFDM — добавления циклического префикса (CP). Последние L отсчётов исходного сигнала u1 копируются и добавляются в его начало, формируя расширенный сигнал u2. Когда этот сигнал, уже имеющий циклический префикс, проходит через канал, его линейная свёртка с импульсной характеристикой h, вычисленная через БПФ, даёт результат yl2. После удаления префикса из начала yl2 получается последовательность, которая полностью совпадает с ранее вычисленной циклической свёрткой yc1. График подтверждает это совпадение. Таким образом, код наглядно показывает, как циклический префикс магическим образом превращает линейную свёртку реального канала в циклическую, что является краеугольным камнем технологии OFDM, позволяющим затем просто и эффективно компенсировать искажения канала в частотной области.

In [ ]:
L = length(h);                          # Length of channel
N = length(u1);                         # Length of input signal
ucp = u1[N-L+1:N];                      # Use last samples of input signal as the CP
u2 = vcat(ucp,u1);                      # Prepend the CP to the input signal
yl2 = real(ifft(fft(u2).*fft([h;zeros(length(u2)-length(h))];)));   # Convolution of input+CP and channel
yl2 = yl2[L+1:end];                     # Remove CP to compare signals

p5 = plot(yl2,linecolor = :blue, line=:stem,marker=:dot, label = "Линейная");
p6 = plot!(yc1,linecolor = :red, line=:stem,marker=:plus, label = "Циклическая");
p5
Out[0]:

Код ниже представляет собой законченную реализацию передающей части (модулятора) системы OFDM, включающую все практические элементы, необходимые для работы в реальном канале. Задаются ключевые параметры: 16-QAM модуляция, 128 поднесущих (точек БПФ) и циклический префикс длиной 8 отсчётов. Процесс начинается с генерации случайных символов и их модуляции в комплексные точки созвездия 16-QAM. Затем, в отличие от предыдущего упрощённого примера, здесь выполняется критически важный шаг — формирование OFDM-символа во временной области с помощью обратного БПФ и последующее добавление циклического префикса. Циклический префикс создаётся путём копирования последних nCP отсчётов сформированного OFDM-символа и добавления этой копии в его начало. В результате получается готовый к передаче сигнал txout, который уже содержит защитный интервал, позволяющий противостоять межсимвольной интерференции в многолучевом канале. Этот этап завершает подготовку сигнала к передаче через искажающую среду.

In [ ]:
using EngeeComms
using EngeeDSP.Functions

var_fft = EngeeFFT();
var_fftshift = EngeeFFTshift();

bps = 4;    # Число бит на символ
M = 2^bps;  # Порядок модуляции
nFFT = 128; # число ячеек БПФ
nCP = 8;    # Длина циклического префикса
var_rand = RandomIntegerGenerator(SetSize=M,InitialSeed=1234,SampleTime=1.0,SamplesPerFrame=nFFT);
var_qam = GeneralQAMModulatorBaseband(Constellation=[-3+3im,-3+1im,-3-3im,-3-1im,-1+3im,-1+1im,-1-3im,-1-1im,3+3im,3+1im,3-3im,3-1im,1+3im,1+1im,1-3im,1-1im]./sqrt(10));
  
txsymbols = vec(step!(var_rand,0.0));
txgrid = step!(var_qam, txsymbols);
txout = conj(step!(var_fft,conj(txgrid)))/length(txgrid);
# Чтобы обработать несколько символов, векторизуем матрицу txout
txout = txout[:];
txcp = txout[nFFT-nCP+1:nFFT];
txout = vcat(txcp,txout);

Ниже моделируется реалистичный канал связи для передачи подготовленного OFDM-сигнала

In [ ]:
hchan = [0.4 1 0.4]'[:,1];
st = AWGN( EbNo=100, BitsPerSymbol=M, SignalPower=1);

rxin = step!(st,txout)                    # Добавление шума
rxin = conv(rxin,hchan);          # Добавление частотной зависимости
Out[0]:
138×1 Matrix{ComplexF64}:
 -0.004613386424821975 + 0.01018410397582413im
  0.013652038144603758 + 0.043197035894136454im
    0.0492270347950972 + 0.06620316556688652im
  0.001454364935108754 + 0.07097230525150806im
  -0.05289394861331751 + 0.05033647217286611im
  -0.10623842534926266 + 0.007631835760060518im
  -0.07220724444152067 + 0.0793883297034132im
  -0.08507639447568857 + 0.058457945333152114im
 -0.059006500236081214 + 0.02197075541671166im
 -0.027234998054386908 + 0.08887937404769576im
  -0.07888122025262403 + 0.18952011862455057im
 -0.008990523559159254 + 0.1256668429507964im
   0.11094712063193093 + 0.00907828481820107im
                       ⋮
   0.09460731132990707 - 0.0004812715748047959im
   0.07015399117915509 + 0.008909309963818066im
   -0.0371498347875724 + 0.02023774785437928im
 -0.013717251481083662 + 0.04775861884404914im
   0.04922799919124048 + 0.06620289608421998im
  0.001458269015173954 + 0.07096986997488722im
 -0.052889984395700716 + 0.050335079514633896im
  -0.10623688395213834 + 0.007637221385099306im
  -0.07220640713224899 + 0.07939103226752264im
  -0.08507420603847964 + 0.05846119723940281im
  -0.06888399812904436 + 0.012094766301959506im
 -0.016912783242377258 + 0.0017110779803630666im

Ниже выполняется обработка принятого сигнала — временная синхронизация и преобразование в частотную область. Сначала генерируется случайное временное смещение, имитирующее неидеальность синхронизации между передатчиком и приёмником. Затем из искажённого сигнала rxin удаляется циклический префикс, и оставшаяся полезная часть OFDM-символа выделяется в rxsync. Ключевой шаг — применение прямого БПФ к этому синхронизированному фрагменту, что преобразует сигнал из временного представления обратно в частотное, разделяя ортогональные поднесущие и подготавливая данные для последующего выравнивания и демодуляции.

In [ ]:
var_rand1 = RandomIntegerGenerator(SetSize=nCP,InitialSeed=1234,SampleTime=1.0,SamplesPerFrame=1);
offset = Int64(step!(var_rand1,0.0)[1])      # случайное смещение меньше длины циклического префикса
# Удаление циклического префикса и синхронизация принятого сигнала
#rxsync = rxin[nCP+1+1-offset:end];
rxsync = rxin[nCP+1:end];
rxgrid = step!(var_fft,rxsync[1:nFFT]);

Следующий блок кода завершает приёмную цепочку, выполняя ключевую операцию выравнивания (эквализации) и демодуляции. Если эквалайзер включён, то сначала вычисляется частотный отклик канала hfchan с помощью БПФ. Затем принятые символы в частотной области rxgrid делятся на этот отклик, что компенсирует амплитудные и фазовые искажения, вносимые каналом. Полученные выровненные символы rxgrideq подаются на демодулятор 16-QAM, который преобразует их обратно в поток целых чисел. Финальная проверка сравнивает демодулированные символы с исходными переданными. При корректной работе системы с включённым выравниванием они должны полностью совпасть, что подтверждает эффективность OFDM в сочетании с циклическим префиксом для борьбы с искажениями в частотно-селективном канале.

In [ ]:
useEqualizer = true;                #       Включение и выключение эквализации
if useEqualizer
    hfchan = step!(var_fft,vcat(hchan,zeros(128-length(hchan))))
    # Линейный фазовый сдвиг, связанный со смещением по времени
    offsetf = exp.(-1im * 2*pi*offset * (0:nFFT-1)/nFFT);
    #rxgrideq = rxgrid ./ (hfchan .* offsetf);
    rxgrideq = rxgrid ./ (hfchan);
else # Без эквализации возникают ошибки
    rxgrideq = rxgrid;
end
var_demod = GeneralQAMDemodulatorBaseband(Constellation=[-3+3im,-3+1im,-3-3im,-3-1im,-1+3im,-1+1im,-1-3im,-1-1im,3+3im,3+1im,3-3im,3-1im,1+3im,1+1im,1-3im,1-1im]./sqrt(10),OutType="Integer");
rxsymbols = step!(var_demod, rxgrideq[:,1]);
if maximum(txsymbols - rxsymbols) < 1e-8
    display("Восстановленные символы соответствуют переданным символам.");
else
    display("Восстановленные символы не соответствуют переданным символам.")
end
"Восстановленные символы соответствуют переданным символам."

Вывод

Данная работа представляет собой комплексную демонстрацию принципов работы и практической реализации системы OFDM, охватывая все ключевые аспекты технологии: от теоретического обоснования ортогональности поднесущих до решения практических задач синхронизации и выравнивания в условиях реального канала связи. Особое внимание было уделено фундаментальной роли циклического префикса — элемента, который преобразует линейную свёртку сигнала с импульсной характеристикой канала в циклическую. Это преобразование является необходимым условием для применения простого и эффективного выравнивания в частотной области. Экспериментально подтверждено, что даже при наличии частотно-селективных замираний и временных задержек, не превышающих длину циклического префикса, система OFDM способна обеспечить надёжное восстановление переданных данных.

Представленная реализация на платформе Engee с использованием Julia наглядно демонстрирует не только корректную работу алгоритмов OFDM, но и практические преимущества современных вычислительных сред для моделирования в области связи. Подобные инструменты позволяют исследователям и инженерам быстро прототипировать, тестировать и визуализировать сложные алгоритмы обработки сигналов, углубляя понимание их работы. Данная модель служит прочной основой для дальнейшего изучения более сложных аспектов современных систем связи, таких как адаптивная модуляция, методы множественного доступа (OFDMA) или алгоритмы оценки и отслеживания параметров канала.