Симуляция частоты появления ошибочных блоков NB-IoT NPDSCH

Этот пример показывает, как LTE Toolbox™ может использоваться, чтобы создать Узкополосную связь NB-IoT Физический Нисходящий Разделяемый Канал (NPDSCH) Частота появления ошибочных блоков (BLER) симуляция при выборочном частотой исчезновении и канале Аддитивного белого гауссова шума (AWGN).

Введение

3GPP Релиз 13 LTE начал добавлять поддержку Узкополосной связи приложения IoT. Релиз 13 задает одну Категорию NB-IoT UE, а именно, Cat-NB1, и Релиз 14 добавляет Cat-NB2, который допускает большие транспортные размеры блока. Этот пример фокусируется на Релизе 13 NB-IoT.

Пример генерирует кривую BLER NB-IoT NPDSCH для многих точек ОСШ и параметров передачи. NPBCH, NPSS, NSSS и разрывы передачи NPDSCH не рассматриваются в этом примере и NPDSCH, и NRS (и CRS если применимо) передаются во всех подкадрах.

Настройка симуляции

Продолжительность симуляции является 50 транспортными блоками DL-SCH для многих точек ОСШ. Большее число numTrBlks должно использоваться, чтобы привести к значимым результатам пропускной способности. SNR может быть массивом значений или скаляра. Симуляция выполняется по различным значениям повторения, чтобы сравнить повышение производительности с повторениями.

numTrBlks = 4;        % Number of simulated transport blocks
SNRdB = -32:4:0;      % SNR range in dB
ireps = [0 5 9];      % Range of reps simulated

Setup более высокие параметры слоя

Setup следующие более высокие параметры слоя, которые используются, чтобы сконфигурировать NPDSCH в следующем разделе:

  • Переменная NPDSCHDataType указывает, несет ли NPDSCH SystemInformationBlockType1-NB (SIB1-NB) или нет, и несет ли NPDSCH широковещательный канал управления (BCCH) или нет. Позволенными значениями NPDSCHDataType является 'SIB1NB', 'BCCHNotSIB1NB' и 'NotBCCH'. Обратите внимание на то, что SIB1-NB принадлежит BCCH.

  • Количество повторений NPDSCH и транспортного размера блока (TBS) затронуто тем, несет ли NPDSCH SIB1-NB или не (см. 3GPP TS 36.213 16.4.1.3 и 16.4.1.5 [2]). набор NPDSCHDataType к 'SIB1NB' указывает, что NPDSCH несет SIB1-NB; набор NPDSCHDataType или к 'BCCHNotSIB1NB' или к 'NotBCCH' указывает, что NPDSCH не несет SIB1-NB.

  • Шаблон повторения NPDSCH и борющаяся генерация последовательности затронуты тем, несет ли NPDSCH BCCH или не (см. 3GPP TS 36.211 10.2.3 [1]). набор NPDSCHDataType или к 'SIB1NB' или к 'BCCHNotSIB1NB' указывает, что NPDSCH несет BCCH; набор NPDSCHDataType к 'NotBCCH' указывает, что NPDSCH не несет BCCH.

NPDSCHDataType = 'NotBCCH';  % The allowed values are 'SIB1NB', 'BCCHNotSIB1NB' or 'NotBCCH'
  • Переменная ISF конфигурирует количество подкадров для NPDSCH согласно 3GPP таблица 16.4.1.3-1 [2] TS 36.213. Допустимые значения для ISF 0... 7.

Когда NPDSCH несет SIB1-NB:

  • Переменная SchedulingInfoSIB1 конфигурирует количество повторений NPDSCH согласно 3GPP таблица 16.4.1.3-3 TS 36.213 и TBS согласно Таблице 16.4.1.5.2-1 [2]. Допустимые значения для SchedulingInfoSIB1 0... 11.

Когда NPDSCH не несет SIB1-NB:

  • Переменная IRep конфигурирует количество повторений NPDSCH согласно 3GPP таблица 16.4.1.3-2 [2] TS 36.213. Допустимые значения для IRep 0... 15.

  • Переменная IMCS вместе с IRep конфигурирует TBS согласно 3GPP таблица 16.4.1.5.1-1 [2] TS 36.213. Допустимые значения для IMCS 0... 12.

ISF = 0;                % Resource assignment field in DCI (DCI format N1 or N2)
SchedulingInfoSIB1 = 0; % Scheduling information field in MasterInformationBlock-NB (MIB-NB)
IMCS = 4;               % Modulation and coding scheme field in DCI (DCI format N1 or N2)

Настройка eNB

Сконфигурируйте стартовый кадр и числа подкадра (enb.NFrame и enb.NSubframe) в симуляции для каждой точки ОСШ, узкополосной физической ячейки ID enb.NNCellID, количества портов антенны NRS (enb.NBRefP, один порт антенны указывает, что порт 2000 используется, два порта антенны указывает, что порт 2000 и порт 2001 используются), режим работы NB-IoT enb.OperationMode, который может быть любым значением можно следующим образом:

  • 'Standalone': поставщик услуг NB-IoT, развернутый вне спектра LTE, например, спектра, используемого для GSM или спутниковой связи

  • 'Guardband': поставщик услуг NB-IoT, развернутый в защитной полосе между двумя поставщиками услуг LTE

  • 'Inband-SamePCI': поставщик услуг NB-IoT, развернутый в блоках ресурса поставщика услуг LTE, с enb.NBRefP то же самое как количество портов CRS enb.CellRefP

  • 'Inband-DifferentPCI': поставщик услуг NB-IoT, развернутый в блоках ресурса поставщика услуг LTE, с enb.NBRefP, отличающимся как enb.CellRefP

enb.CellRefP сконфигурирован, когда режимом работы является 'Inband-DifferentPCI'. Начальный индекс символа OFDM в подкадре для NPDSCH сконфигурирован с помощью enb.ControlRegionSize, когда значения NPDSCHDataType и enb.OperationMode удовлетворяют следующие условия:

  • NPDSCHDataType является или 'BCCHNotSIB1NB' или 'NotBCCH'

  • enb.OperationMode является или 'Inband-SamePCI' или 'Inband-DifferentPCI'

enb.NFrame = 0;     % Simulation starting frame number
enb.NSubframe = 0;  % Simulation starting subframe number
enb.NNCellID = 0;   % NB-IoT physical cell ID
enb.NBRefP = 2;     % Number of NRS antenna ports, should be either 1 or 2
enb.OperationMode = 'Inband-DifferentPCI';  % The allowed values are 'Inband-SamePCI', 'Inband-DifferentPCI', 'Guardband' or 'Standalone'
if strcmpi(enb.OperationMode,'Inband-SamePCI')
    enb.CellRefP = enb.NBRefP;     % The allowed values are NBRefP or 4
    enb.NCellID = enb.NNCellID;
elseif strcmpi(enb.OperationMode,'Inband-DifferentPCI')
    enb.CellRefP = 4; % Number of Cell RS antenna ports (Must be equal to NBRefP or 4)
    enb.NCellID = 1;
end
if (strcmpi(NPDSCHDataType,'BCCHNotSIB1NB') || strcmpi(NPDSCHDataType,'NotBCCH')) && ...
        (strcmpi(enb.OperationMode,'Inband-SamePCI') || strcmpi(enb.OperationMode,'Inband-DifferentPCI'))
    enb.ControlRegionSize = 3;     % The allowed values are 0...13
end

Настройка модели канала распространения

Структура channel содержит параметры конфигурации модели канала.

channel = struct;                    % Initialize channel config structure
channel.Seed = 6;                    % Channel seed
channel.NRxAnts = 1;                 % 1 receive antenna
channel.DelayProfile ='EPA';         % Delay profile
channel.DopplerFreq = 5;             % Doppler frequency in Hz
channel.MIMOCorrelation = 'Low';     % Multi-antenna correlation
channel.NTerms = 16;                 % Oscillators used in fading model
channel.ModelType = 'GMEDS';         % Rayleigh fading model type
channel.InitPhase = 'Random';        % Random initial phases
channel.NormalizePathGains = 'On';   % Normalize delay profile power
channel.NormalizeTxAnts = 'On';      % Normalize for transmit antennas

Настройка средства оценки канала

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

Настройка NPDSCH

Получите следующие параметры NPDSCH из более высоких настроек слоя, заданных выше:

  • Количество повторений (NRep)

  • Количество подкадров использовало для NPDSCH, когда нет никакого повторения (NSF)

  • Транспортный размер блока (TBS)

Эти параметры могут быть получены при помощи класса hNPDSCHInfo. hNPDSCHInfo также предоставляет методу displaySubframePattern, чтобы отобразить шаблон повторения NPDSCH, который показывают в следующем разделе.

Обратите внимание на то, что, когда NPDSCH не несет SIB1-NB, ошибка инициирована, если сконфигурированный IRep и значения IMCS приводят к пустому TBS. Дело обстоит так, когда TBS не задан для конкретного IRep и пары IMCS в таблице 16.4.1.5.1-1 [2] 3GPP TS 36.213.

for repIdx = 1:numel(ireps)
    npdschInfo = hNPDSCHInfo;
    npdschInfo.NPDSCHDataType = NPDSCHDataType;
    npdschInfo.ISF = ISF;
    if strcmpi(NPDSCHDataType,'SIB1NB')  % NPDSCH carrying SIB1-NB
        npdschInfo.SchedulingInfoSIB1 = SchedulingInfoSIB1;
    else % NPDSCH not carrying SIB1-NB
        npdschInfo.IRep = ireps(repIdx); % Repetition number field in DCI (DCI format N1 or N2)
        npdschInfo.IMCS = IMCS;          % Modulation and coding scheme field in DCI (DCI format N1 or N2)
        % Verify the inputs of IRep and IMCS
        if isempty(npdschInfo.TBS)
            npdschInfo.TBSTable
            error(['Invalid [ITBS,ISF] (where ITBS=IMCS=' num2str(IMCS)...
                ', ISF=' num2str(ISF)  ') pair, empty TBS is returned, check valid pairs in the above table or 3GPP TS 36.213 table 16.4.1.5.1-1']);
        end
    end

Создайте структуру npdsch с помощью полученного количества повторений (npdschInfo.NRep), количество подкадров NPDSCH (npdschInfo.NSF) от экземпляра класса npdschInfo, введите параметр NPDSCHDataType и Радиосеть Временный Идентификатор RNTI. Обратите внимание на то, что NSF = 8 используется, когда NPDSCHDataType является 'SIB1NB'.

    npdsch.NSF = npdschInfo.NSF;
    npdsch.NRep = npdschInfo.NRep;
    npdsch.NPDSCHDataType = NPDSCHDataType;
    npdsch.RNTI = 1;

Проверьте сконфигурированные более высокие параметры слоя с помощью уровня кода DL-SCH. Уровень кода является отношением между количеством битов после кодирования CRC и количеством битов после соответствия уровня. Для случая, когда SIB1NB установлен в true, уровень кода, R может быть больше, чем или равняться 1, который не является допустимым сценарием. Например, такой случай происходит, когда ISF установлен в 0, и SchedulingInfoSIB1 установлен в 3.

    [~,info] = lteNPDSCHIndices(enb,npdsch);
    rmoutlen = info.G;           % Bit length after rate matching, i.e. codeword length
    trblklen = npdschInfo.TBS;   % Transport block size
    R = (trblklen+24)/rmoutlen;  % DL-SCH channel coding rate, 24 denotes the number of CRC bits
    if R >= 1
        error(['DL-SCH coding rate (' num2str(R) ') larger than or equal to 1 for the configured parameters.']);
    end

Отобразите шаблон повторения подкадра

Переменная displayPattern управляет отображением шаблона повторения подкадра NPDSCH. Пример показывают в следующей фигуре для случая, когда NPDSCH несет BCCH, NPDSCH состоит из npdschInfo.NSF = 3 различные подкадры, каждый цвет представляет подкадр, который представляет 1 мс. Каждый подкадр является повторенными временами npdschInfo.NRep = 4, таким образом в общей сложности 12 подкадров требуются, чтобы передавать NPDSCH.

    %  The NPDSCH repetition pattern for the current configuration is
    %  displayed below
    displayPattern = true;
    % Display NPDSCH repetition pattern
    if displayPattern == true
        npdschInfo.displaySubframePattern;
    end

Цикл симуляции частоты появления ошибочных блоков

Эта часть примера показывает, как выполнить симуляцию уровня ссылки NB-IoT NPDSCH и результаты BLER графика. Передача и получает цепочку, изображен в следующей фигуре.

Случайный поток битов с размером желаемого транспортного блока подвергается кодированию CRC, сверточному кодированию и уровню, соответствующему, чтобы получить биты NPDSCH, которые повторяются согласно определенному шаблону повторения подкадра. Скремблирование, модуляция, отображение слоя и предварительное кодирование затем применяются, чтобы сформировать комплексные символы NPDSCH. Эти символы наряду с сигналами NRS сопоставлены с сеткой и OFDM, модулируемым, чтобы создать форму волны области времени. Это затем передается через исчезающий канал, и AWGN добавляется. Шумная форма волны затем синхронизируется и демодулируется. Оценка канала и коррекция выполняются на восстановленных символах NPDSCH, после которых декодирование канала и демодуляция выполняются, чтобы восстановить транспортный блок. После дескремблирования мягко объединены повторяющиеся подкадры перед уровнем восстанавливаются. Транспортная частота появления ошибочных блоков вычисляется для каждой точки ОСШ. Оценка частоты появления ошибочных блоков основана на предположении, что все подкадры в пакете используются, чтобы декодировать транспортный блок в UE. Пакет задан в слое MAC (см. 3GPP TS 36.321 5.3.2.1 [3]), когда подкадры npdsch.NRep npdsch.NSF раньше несли транспортный блок.

    NSubframe = enb.NFrame*10+enb.NSubframe;      % Absolute subframe number at the starting point of the simulation
    % Get total number of subframes to simulate
    if strcmpi(NPDSCHDataType,'SIB1NB')
        TotSubframes = npdsch.NRep*8*numTrBlks;
    else
        TotSubframes = npdsch.NRep*npdsch.NSF*numTrBlks;
    end

    % Initialize BLER and throughput result
    maxThroughput = zeros(length(SNRdB),1);
    simThroughput = zeros(length(SNRdB),1);
    bler = zeros(1,numel(SNRdB));

    % The temporary variables 'enb_init' and 'channel_init' are used to create
    % the temporary variable 'enb' and 'channel' within the SNR loop to create
    % independent simulation loops for the 'parfor' loop
    enb_init = enb;
    channel_init = channel;

    for snrIdx = 1:numel(SNRdB)
    % parfor snrIdx = 1:numel(SNRdB)
    % To enable the use of parallel computing for increased speed comment out
    % the 'for' statement above and uncomment the 'parfor' statement below.
    % This needs the Parallel Computing Toolbox. If this is not installed
    % 'parfor' will default to the normal 'for' statement.

        % Set the random number generator seed depending to the loop variable
        % to ensure independent random streams
        rng(snrIdx,'combRecursive');

        fprintf('\nSimulating %d subframes at %gdB SNR\n',TotSubframes,SNRdB(snrIdx));

        enb = enb_init;         % Initialize eNodeB configuration
        channel = channel_init; % Initialize fading channel configuration
        txcw = [];              % Initialize the transmitted codeword
        numBlkErrors = 0;       % Number of transport blocks with errors
        estate = [];            % Initialize NPDSCH encoder state
        dstate = [];            % Initialize NPDSCH decoder state
        lastOffset = 0;         % Initialize overall frame timing offset
        offset = 0;             % Initialize frame timing offset
        subframeGrid = zeros(12,14,enb.NBRefP); % Initialize the slot grid

        for subframeIdx=NSubframe:(NSubframe+TotSubframes)-1

            % Set current absolute subframe and frame numbers
            enb.NSubframe = mod(subframeIdx,10);
            enb.NFrame = floor((subframeIdx)/10);

            % Update transport block when the transmitted codeword is empty
            if isempty(txcw)
                txTrBlk = randi([0 1],trblklen,1);
                txcw = lteNDLSCH(rmoutlen,txTrBlk);
            end

            % Generate NPDSCH symbols and indices for a subframe
            [txNpdschSymbols,estate] = lteNPDSCH(enb,npdsch,txcw,estate);
            npdschIndices = lteNPDSCHIndices(enb,npdsch);
            % Map the symbols to the subframe grid
            subframeGrid(npdschIndices) = txNpdschSymbols;

            % Generate the NRS symbols and indices
            nrsSymbols = lteNRS(enb);
            nrsIndices = lteNRSIndices(enb);
            % Map the symbols to the subframe grid
            subframeGrid(nrsIndices) = nrsSymbols;

            % Perform OFDM modulation to generate the time domain waveform
            [txWaveform,ofdmInfo] = nbOFDMModulate(enb,subframeGrid);

            % Add 25 sample padding. This is to cover the range of delays
            % expected from channel modeling (a combination of
            % implementation delay and channel delay spread)
            txWaveform =  [txWaveform; zeros(25, enb.NBRefP)]; %#ok<AGROW>

            % Initialize channel time for each subframe
            channel.InitTime = subframeIdx/1000;

            % Pass data through channel model
            channel.SamplingRate = ofdmInfo.SamplingRate;
            [rxWaveform,fadingInfo] = lteFadingChannel(channel, txWaveform);

            % Calculate noise gain including compensation for downlink power
            % allocation
            SNR = 10^(SNRdB(snrIdx)/20);

            % Normalize noise power to take account of sampling rate, which is
            % a function of the IFFT size used in OFDM modulation, and the
            % number of antennas
            N0 = 1/(sqrt(2.0*enb.NBRefP*double(ofdmInfo.Nfft))*SNR);

            % Create additive white Gaussian noise
            noise = N0*complex(randn(size(rxWaveform)), ...
                                randn(size(rxWaveform)));

            % Add AWGN to the received time domain waveform
            rxWaveform = rxWaveform + noise;

            %------------------------------------------------------------------
            %            Receiver
            %------------------------------------------------------------------

            % Perform timing synchronization, extract the appropriate
            % subframe of the received waveform, and perform OFDM
            % demodulation
            offset  = hPerfectTimingEstimate(fadingInfo);

            % Synchronize the received waveform
            rxWaveform = rxWaveform(1+offset:end, :);

            % Perform OFDM demodulation on the received data to recreate the
            % resource grid
            rxSubframe = nbOFDMDemodulate(enb,rxWaveform);

            % Perfect channel estimation
            estChannelGrid = nbDLPerfectChannelEstimate(enb, channel, offset);
            noiseGrid = nbOFDMDemodulate(enb, noise(1+offset:end ,:));
            noiseEst = var(noiseGrid(:));

            % Get NPDSCH indices
            npdschIndices = lteNPDSCHIndices(enb, npdsch);

            % Get PDSCH resource elements from the received subframe. Scale the
            % received subframe by the PDSCH power factor Rho. The PDSCH is
            % scaled by this amount, while the cell reference symbols used for
            % channel estimation (used in the PDSCH decoding stage) are not.
            [rxNpdschSymbols, npdschHest] = lteExtractResources(npdschIndices, ...
                rxSubframe, estChannelGrid);

            % Decode NPDSCH
            [rxcw,dstate,symbols] = lteNPDSCHDecode(...
                                 enb, npdsch, rxNpdschSymbols, npdschHest, noiseEst,dstate);

            % Decode the transport block when all the subframes in a bundle
            % have been received
            if dstate.EndOfTx
               [trblkout,blkerr] = lteNDLSCHDecode(trblklen,rxcw);
               numBlkErrors = numBlkErrors + blkerr;
               % Re-initialize to enable the transmission of a new transport
               % block
               txcw = [];
            end

        end

        % Calculate the block error rate
        bler(snrIdx) = numBlkErrors/numTrBlks;
        fprintf('NPDSCH BLER = %.4f \n',bler(snrIdx));
        % Calculate the maximum and simulated throughput
        maxThroughput(snrIdx) = trblklen*numTrBlks; % Max possible throughput
        simThroughput(snrIdx) = trblklen*(numTrBlks-numBlkErrors);  % Simulated throughput
        fprintf('NPDSCH Throughput(%%) = %.4f %%\n',simThroughput(snrIdx)*100/maxThroughput(snrIdx));

    end
Simulating 4 subframes at -32dB SNR
Simulating 128 subframes at -32dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 128 subframes at -28dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 128 subframes at -24dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 128 subframes at -20dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 128 subframes at -16dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 128 subframes at -12dB SNR
NPDSCH BLER = 0.2500 
NPDSCH Throughput(%) = 75.0000 %

Simulating 128 subframes at -8dB SNR
NPDSCH BLER = 0.2500 
NPDSCH Throughput(%) = 75.0000 %

Simulating 128 subframes at -4dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %

Simulating 128 subframes at 0dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %
Simulating 1024 subframes at -32dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 1024 subframes at -28dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 1024 subframes at -24dB SNR
NPDSCH BLER = 0.2500 
NPDSCH Throughput(%) = 75.0000 %

Simulating 1024 subframes at -20dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %

Simulating 1024 subframes at -16dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %

Simulating 1024 subframes at -12dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %

Simulating 1024 subframes at -8dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %

Simulating 1024 subframes at -4dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %

Simulating 1024 subframes at 0dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %

Постройте Частоту появления ошибочных блоков по сравнению с результатами ОСШ

    if repIdx == 1
        fh = figure;
        grid on;
        hold on;
        xlabel('SNR (dB)');
        ylabel('BLER');
        legendstr = {['NRep = ' num2str(npdsch.NRep)]};
    else
        legendstr = [legendstr ['NRep = ' num2str(npdsch.NRep)]]; %#ok<AGROW>
    end
    figure(fh);
    plot(SNRdB, bler, '-o');

end
% Set figure title
if strcmpi(NPDSCHDataType,'SIB1NB')
    npdsch.NSF = 8;
end
title([' ' char(npdsch.NPDSCHDataType) ': TBS=' num2str(trblklen)...
    '; NSF=' num2str(npdsch.NSF) '; ' num2str(enb_init.NBRefP) ' NRS port(s)' ]);
legend(legendstr);

Следующий график показывает симуляцию, запущенную с набором numTrBlks к 5 000.

Приложение

Этот пример использует функции помощника:

Выбранная библиография

  1. 3GPP TS 36.211 "Физические каналы и модуляция"

  2. 3GPP TS 36.213 "Процедуры физического уровня"

  3. 3GPP TS 36.321 "Спецификация протокола Среднего управления доступом (MAC)"

  4. 3GPP TS 36.101 "Передача радио оборудования пользователя (UE) и прием"

Localfunctions

% NB-IoT DL OFDM Modulator
function [waveform,info] = nbOFDMModulate(enb,grid)
    % Apply default window size according to TS 36.104 Table E.5.1-1a
    if(~isfield(enb,'Windowing'))
        enb.Windowing = 6;
    end
    % Use NB-IoT SC-FDMA to get the 1/2 subcarrier shift on the OFDM modulation
    enb.NBULSubcarrierSpacing = '15kHz';
    [waveform,info] = lteSCFDMAModulate(enb,grid);
end

% NB-IoT DL OFDM Demodulator
function grid = nbOFDMDemodulate(enb,rxWaveform)
    % Use NB-IoT SC-FDMA to get the 1/2 subcarrier shift on the OFDM modulation
    enb.NBULSubcarrierSpacing = '15kHz';
    grid = lteSCFDMADemodulate(enb,rxWaveform,0.55); % CP fraction of 0.55
end

% NB-IoT DL Perfect Channel Estimator
function H = nbDLPerfectChannelEstimate(enb,channel,timefreqoffset)
    % Reconfigure NB-IoT UL perfect channel estimator to perform DL perfect
    % channel estimation
    enb.NBULSubcarrierSpacing = '15kHz';
    enb.NTxAnts = enb.NBRefP;
    enb.TotSlots = 2;
    H = lteULPerfectChannelEstimate(enb, channel,timefreqoffset);
end
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at -28dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at -24dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at -20dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at -16dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at -12dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at -8dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at -4dB SNR
NPDSCH BLER = 1.0000 
NPDSCH Throughput(%) = 0.0000 %

Simulating 4 subframes at 0dB SNR
NPDSCH BLER = 0.0000 
NPDSCH Throughput(%) = 100.0000 %