Моделирование данной системы будет заключаться в передаче сообщения трафика в соответствии с алгоритмом, изображённым на рисунке 17 предыдущей статьи [1]. Структуры пакетов уровней и OFDM-символов изображены на рисунке 1.
 
Рисунок 1. Структура пакетов уровней и OFDM-символов.
При QPSK модуляции каждый OFDM символ, включающий 18 информационных поднесущих, способен переносить 36 битов данных.
Размер структуры пакетов имеет фиксированную длину - 328 бит, поэтому необходимо предусмотреть добавление незначащих нулей. Сообщение будет передаваться с первой конфигурацией физического уровня, то есть, будет использоваться циклический кодер со скоростью 3/4.
В качестве данных, передаваемых по каналу трафика, у нас служит текстовый файл. Сперва преобразуем его к двоичному виду, зададим некоторые параметры системы и сформируем сообщение, поступающее с канального уровня.
close all;
clc;
err=0;
% Выбор файла для передачи
FileName = 'test.txt';
% Кодировка символа текста: 2 байта на символ
sym_size = 2;
% Длина однократно считываемого текстового сообщения
Str_size = 14;
% Смещение указателя чтения символа из файла на заданную величину
byte_off = 0;

% параметры модели
% позиционность модуляции - QPSK

mPos = 4;
R_message = '';

% Параметры CRC
poly=[1 0 0 0 1 0 1 1 0 1 0 0 0]; %CRC-16-CCIT
[x y]=size(poly); %размерность полинома

% Открытие на чтение и получение идентификатора текстового файла
[fid, message] = fopen(FileName, 'r');
%Проверка на доступность указанного файла
if (fid < 0)
    disp('Файл с передаваемым сообщением не найден. Завершение работы.');
    return
end;
 
% Организуется цикл чтения данных размером Str_size байт
% из файла до тех пор, пока не будет достугнут конец файла

while ~feof(fid)

   msg = fscanf(fid, '%c', Str_size);
   
   % ================== Канальный  уровень ================================
   %% Подготовка к передаче сообщения
   % текстовое сообщение переводится в двоичный вид

   str_bin = strtobin(msg)';
   % получение адреса терминала в двоичном 6-и разрядном виде (Address=5)
   addr_bin = my_de2bi(5,'left_msb',6);
   % добавление адреса и выравнивание сообщения до фиксированной
   % длины пакета нулями

   number_of_zeros=224-length(str_bin);
   equaler=zeros(1,number_of_zeros);
   if number_of_zeros>0
          msg = [addr_bin  str_bin equaler];
   else
       msg = [addr_bin  str_bin];
   end;    
   
   % получение CRC кода
   m=[msg zeros(1,y-1)]; %вставка нулей в поле CRC
   [q r] = deconv(m,poly); % поиск частного и остатка от деления
   %информационной части на порождающий полином CRC кода
   r = mod(abs(r),2);
   CRC = r(length(msg)+1:end);%расчет CRC
   % сборка сообщения
   msg_Lev1 = [msg CRC];
   % добавление хвостовых битов для сброса свёрточного кодера
   tail=[0 0 0 0];
   trx = [msg_Lev1 tail];
 
Далее выполняются задачи физического уровня:
%% Помехоустойчивое кодирование
  
   % первый профиль - кодер со скоростью 3/4

   profile1 = poly2trellis([5 5 5],[23 27 0 0; 0 24 25 0; 0 0 26 31]);
  
 Далее по алгоритму поток битов поступает на блочный перемежитель, который записывает этот поток в матрицу построчно, а затем считывает из неё по столбцам:
   % Блочное перемежение
   interleaved_bits=matintrlv(code_word, 4, length(code_word)/4);

   
   Далее следует модуляция QPSK и формирование OFDM символов:
   %% Модуляция и формирование OFDM сигнала
   Ngr = 2; % количество неиспользуемых поднесущих и приходящихся на защитные интервалы 


   % номера пилотных поднесущих в OFDM-символе
   pilotIndexes = [1 8 15 22];
   %Размерность OFDM-символа
   Nc=22;
   msg_length = length(interleaved_bits);% длина передаваемого сообщения, битов
   % количество поднесущих с данными
   Ndata = Nc - length(pilotIndexes); % 18 поднесущих для передачи 18 QPSK символов

   % количество битов, передаваемых в одном OFDM-символе
   s_length = Ndata * log2(mPos);

   ns = floor(msg_length/s_length)+1; % сколько потребуется OFDM-символов

   % сколько потребуется добавить незначащих битов - как разница между тем
   % количеством битов, что обеспечивает расчетное количество OFDM-символов, и
   % количеством блоком в передаваемом сообщении

   fil_zero = zeros(1, ns*s_length - msg_length);
  
   h = modem.pskmod(mPos);
   % h - модем PSK с позиционностью mPos
   % Требуется настроить остальные его параметры:
   % Параметры модуляции

   h.inputtype = 'bit';
   h.SymbolOrder = 'gray';
   h.PhaseOffset = pi/4;
   ss_signal = [interleaved_bits fil_zero]';
   % собственно модуляция
   IQ_signal = modulate(h, ss_signal);
   plot(IQ_signal,'.');
 

 Рисунок 1. Сигнальное созвездие получившегося сигнала после QPSK модуляции.
%формирование OFDM-символов
   ofdmFrame = makeOfdmFrame(IQ_signal, ns);
Формирование OFDM символов ведётся с помощью функции makeOfdmFrame, которая, если несущая информационная, ставит ей в соответствие информационный QPSK-символ. Если несущая представляет собой пилот сигнал, то функция вставляет туда значение из кода Баркера. Также функция добавляет циклический префикс, имеющий размер половины длины символа:
function ofdmFrame = makeOfdmFrame(dataMod, Nofdm)

global pilotIndexes;
global Nc;

%символы пилотных поднесущих промодулированы псевдослучайным кодом (для
%примера, код Баркера), как результат - BPSK

seqBarker = [-1 -1 -1 1 1 1 -1 1 1 -1 1]*4/3;
ofdmSymbol = [];
ofdmFrame = [];
indexOfPilot = 1;
indexOfData = 1;
for i=1:Nofdm
    for j=1:Nc % собираются IQ-символы будущего OFDM-символа
        if (j==pilotIndexes(indexOfPilot))
            ofdmSymbol(j)=seqBarker(indexOfPilot);
            indexOfPilot=indexOfPilot+1;
        else
            ofdmSymbol(j) = dataMod(indexOfData);
            indexOfData=indexOfData+1;
        end
    end
    indexOfPilot=1;
    ofdmSymbol = ifft(ofdmSymbol);
    %формирование циклического префикса, как часть OFDM-символа,
   

    cp = ofdmSymbol(Nc-Nc/2+1:Nc);
    % добавление ЦП в начало OFDM-символа (11 IQ-символа)
    ofdmSymbol=[cp ofdmSymbol];
    % Сборка информационных OFDM-символов пакета физического уровня
    ofdmFrame=[ofdmFrame ofdmSymbol];
    ofdmSymbol=[];
end
end
Далее идёт формирование символов преамбулы:
   %формирование символов преамбулы
   %Идея построения заимствована из 802.11а (модуль tx_gen_preamble
   %соответствующей лабораторной работы)
   %Короткие символы - для подстройки частоты (синхронизация по частоте)

   ShortTrainingSymbols = sqrt(13/6)*[0 0 1+j 0 0 0 -1-j 0 0 0 1+j 0 0 0 -1-j 0 0 0 -1-j 0 0 0 1+j 0 0 0 0 0 0 -1-j 0 0 0 -1-j 0 0 0 ...
      1+j 0 0 0 1+j 0 0 0 1+j 0 0 0 1+j 0 0];

   short_symbols = ifft(ShortTrainingSymbols);
   % выделение первых 6 отсчетов
   Strs = short_symbols(1:6);
   % Формирование 10 кототких символов преамбулы на основе выбранного набора
   short_trs=[Strs Strs Strs Strs Strs Strs Strs Strs Strs Strs];
 
   %длинный символ преамбулы
   LongTrainingSymbols=[0 0 0 0 0 0 1 1 -1 -1 1 1 -1 1 -1 1 1 1 1 1 1 -1 -1 1 1 -1 1 -1 1 1 1 1 ...
      1 -1 -1 1 1 -1 1 -1 1 -1 -1 -1 -1 -1 1 1 -1 -1 1 -1 1 -1 1 1 1 1 0 0 0 0 0 0];
   long_symbol = ifft(LongTrainingSymbols);
   long_trs = [long_symbol(22-2*6+1:22) long_symbol long_symbol];

 
   % Пакет физического уровня (символы преамбулы и OFDM-символы)
   phy_frame = [short_trs long_trs ofdmFrame];  
   figure(3);
   plot(abs(phy_frame));
 
 Рисунок 2. Получившийся OFDM-кадр.
% Наложение шума на сигнал
   noise_sgn = awgn(phy_frame,10); 
   % отображение сигнально-кодового созвездия
   figure(2);
   plot(noise_sgn,'.');
 
Рисунок 3. Сигнальное созвездие зашумлённого OFDM-кадра.
На приёмной стороне осуществляются обратные действия:
Поскольку задачи синхронизации в модели не рассматриваются, пропускаем короткую и длинную части преамбулы:
%% демодуляция
 
   rx_signal=noise_sgn(60+140+1:length(noise_sgn));
   rx_ofdmsymbol=[];
   rx_ofdmFrame=[];
   
   for i=1:ns
       % удаление циклического префикса
       rx_ofdmsymbol=rx_signal((length(rx_signal)/ns)*i-21:(length(rx_signal)/ns)*i);
       % переход в частотную область
       rx_ofdmsymbol=fft(rx_ofdmsymbol);
       % удаление пилотов
       rx_ofdmsymbol=[rx_ofdmsymbol(2:7) rx_ofdmsymbol(9:14) rx_ofdmsymbol(16:21)];
       % формирование принятого OFDM кадра
       rx_ofdmFrame=[rx_ofdmFrame rx_ofdmsymbol];
   end;   
  
  
   % Параметры демодуляции
   h = modem.pskdemod(mPos);
   h.SymbolOrder = 'gray';
   h.PhaseOffset = pi/4;
   h.OutputType = 'bit';

   % собственно демодуляция
   s = demodulate(h,rx_ofdmFrame);
  
   % деперемежение
   deinterleaved_bits=matdeintrlv(interleaved_bits, 4, length(code_word)/4); 
Далее следует декодирование:
%% Помехоустойчивое декодирование
   received_mes_L1 = vitdec(deinterleaved_bits,profile1,2,'trunc','hard'); 
 
Далее следуют задачи канального уровня:
%% декодирование L2-сообщения
   % Подготовка к проверке CRC

   [q r]=deconv(received_mes_L1,poly);
   %проверка остатка
   r=mod(abs(r),2);
   if r == zeros(1,length(received_mes_L1))
        detect=0;% ошибок нет
   else
         err=err+1;
        detect=1;% обнаружены ошибки
      
   end;
 
  received_mes_L2=[];
   % Собственно принятое сообщение
   received_mes_L2 = received_mes_L1(1:length(received_mes_L1)+1-length(poly));


   % Преобразование в текстовый формат
   % адрес получателя

   addr =  my_bi2de(received_mes_L2(1:6)','left_msb');
  
   % Извлечение принимаемого сообщения (в двоичном виде)с учётом хвостовых
   % битов

   txt_mesage = received_mes_L2(7:length(received_mes_L2)-4)';
   % перевод в текстовый формат
   txt = bintostr(txt_mesage);
   % накопление частей принятого сообщения в переменной R_message
   R_message = [R_message txt];

   % отображение в виде html-ссылки участков текста, принятых с ошибкой 
   if detect==0
       fprintf('%s', txt);
   else
       fprintf('%s', [' <a href =  ' '" "' '> ' txt '    </a> ']);
    end;
%pos = ftell(fid)
end; % признак завершения цикла

% закрытие файла

fclose (fid); 
 
В результате выполнения был безошибочно передан текстовый файл и воспроизведён на приёмной стороне.  
Список использованной литературы
1. http://omoled.ru/publications/view/335 
2. А. В. Бакке, конспект лекций по курсу СССПО,  РГРТУ, Рязань, 2012.