NR PDSCH Throughput

This example measures the physical downlink shared channel (PDSCH) throughput of a 5G New Radio (NR) link, as defined by the 3GPP NR standard. It implements the transport and physical channels (DL-SCH and PDSCH). The transmitter model includes PDSCH demodulation reference symbols (DM-RS) and synchronization signal (SS) bursts. This example supports clustered delay line (CDL) and tapped delay line (TDL) propagation channels and assumes perfect synchronization and channel estimation.

Introduction

This example measures the PDSCH throughput of a 5G link, as defined by the 3GPP NR standard [ 1 ], [ 2 ], [ 3 ], [ 4 ].

The following 5G NR features are modeled:

  • DL-SCH transport channel coding

  • PDSCH and PDSCH DM-RS generation

  • SS burst generation (PSS/SSS/PBCH/PBCH DM-RS)

  • Variable subcarrier spacing and frame numerologies (2^n * 15kHz) for normal and extended cyclic prefix

  • TDL and CDL propagation channel models

Other features of the simulation are:

  • PDSCH precoding using SVD

  • CP-OFDM modulation, with the option of W-OFDM (WOLA-OFDM) and F-OFDM (Filtered OFDM)

  • Slot wise and non slot wise PDSCH and DM-RS mapping

  • SS burst generation (cases A-E, SS/PBCH block bitmap control)

  • Perfect synchronization and channel estimation

  • HARQ operation with 16 processes

  • The example uses a single bandwidth part across the whole carrier

The figure below shows the processing chain implemented. For clarity, the DM-RS and SS burst generation have been omitted.

This example supports operation with one codeword. Note that perfect synchronization and perfect channel knowledge are assumed, i.e. SS/PBCH block and PDSCH DM-RS signals are not used at the receiver. A single precoding matrix for the whole PDSCH allocation is determined using SVD by averaging the channel estimate across all allocated PDSCH PRBs. Therefore, for large PDSCH allocations, i.e. occupying a wide bandwidth, the single precoding matrix may not be well matched to the channel across all frequencies, resulting in performance degradation. There is no beamforming on the SS/PBCH blocks in the SS burst.

Simulation Length and SNR Points

Set the length of the simulation in terms of the number of 10ms frames. A large number of NFrames should be used to produce meaningful throughput results. Set the SNR points to simulate. The SNR for each layer is defined per RE, and it includes the effect of signal and noise across all antennas.

simParameters = [];             % Clear simParameters variable
simParameters.NFrames = 2;      % Number of 10ms frames
simParameters.SNRIn = [-5 0 5]; % SNR range

gNodeB and PDSCH Configuration

Set the key parameters of the simulation. These include:

  • The bandwidth in resource blocks (12 subcarriers per resource block).

  • Subcarrier spacing: 15, 30, 60, 120, 240, 480 (kHz)

  • Cyclic prefix length: normal or extended

  • Cell ID

  • Number of transmit and receive antennas

A substructure containing the DL-SCH and PDSCH parameters is also specified. This includes:

  • Target code rate

  • Allocated resource blocks (PRBSet)

  • Modulation scheme: 'QPSK', '16QAM', '64QAM', '256QAM'

  • Number of layers

  • PDSCH mapping type

  • DM-RS configuration parameters

Other simulation wide parameters are:

  • Propagation channel model: 'TDL' or 'CDL'

  • SS burst configuration parameters. Note that the SS burst generation can be disabled by setting the SSBTransmitted field to [0 0 0 0].

% Set waveform type and PDSCH numerology (SCS and CP type)
simParameters.NDLRB = 51;                % Bandwidth in number of resource blocks (51RBs at 30kHz SCS for 20MHz BW)
simParameters.SubcarrierSpacing = 30;    % 15, 30, 60, 120, 240, 480 (kHz)
simParameters.CyclicPrefix = 'Normal';   % 'Normal' or 'Extended'
simParameters.NCellID = 1;               % Cell identity
simParameters.NTxAnts = 8;               % Number of PDSCH transmission antennas
simParameters.NRxAnts = 2;               % Number of UE receive antennas

% DL-SCH/PDSCH parameters
simParameters.PDSCH.TargetCodeRate = 0.4785;  % Code rate used to calculate transport block sizes
simParameters.PDSCH.PRBSet = 0:simParameters.NDLRB-1; % PDSCH PRB allocation
simParameters.PDSCH.SymbolSet = 0:13;           % PDSCH symbol allocation in each slot
simParameters.PDSCH.Modulation = '16QAM';       % 'QPSK', '16QAM', '64QAM', '256QAM'
simParameters.PDSCH.NLayers = 2;                % Number of PDSCH layers
simParameters.PDSCH.EnableHARQ = true;          % Enable/disable HARQ, if disabled, single transmission with RV=0, i.e. no retransmissions
% DM-RS configuration (TS 38.211 section 7.4.1.1)
simParameters.PDSCH.PortSet = 0:simParameters.PDSCH.NLayers-1; % DM-RS ports to use for the layers
simParameters.PDSCH.PDSCHMappingType = 'A';     % PDSCH mapping type ('A'(slot-wise),'B'(non slot-wise))
simParameters.PDSCH.DL_DMRS_typeA_pos = 2;      % Mapping type A only. First DM-RS symbol position (2,3)
simParameters.PDSCH.DL_DMRS_max_len = 1;        % Number of front-loaded DM-RS symbols (1(single symbol),2(double symbol))
simParameters.PDSCH.DL_DMRS_add_pos = 0;        % Additional DM-RS symbol positions (max range 0...3)
simParameters.PDSCH.DL_DMRS_config_type = 2;    % DM-RS configuration type (1,2)
simParameters.PDSCH.NIDNSCID = 1;               % Scrambling identity (0...65535)
simParameters.PDSCH.NSCID = 0;                  % Scrambling initialization (0,1)
% Reserved PRB patterns (for CORESETs, forward compatibility etc)
simParameters.PDSCH.Reserved.Symbols = [];      % Reserved PDSCH symbols
simParameters.PDSCH.Reserved.PRB = [];          % Reserved PDSCH PRBs
simParameters.PDSCH.Reserved.Period = [];       % Periodicity of reserved resources

% Define the propagation channel type
simParameters.ChannelType = 'CDL'; % 'CDL' or 'TDL'

% SS burst configuration
simParameters.SSBurst.BlockPattern = 'Case B';    % 30kHz subcarrier spacing
simParameters.SSBurst.SSBTransmitted = [0 1 0 1]; % Bitmap indicating blocks transmitted in the burst
simParameters.SSBurst.SSBPeriodicity = 20;        % SS burst set periodicity in ms (5, 10, 20, 40, 80, 160)

validateNLayers(simParameters);

Additional parameters can be set depending on the type of modulation waveform used. For W-OFDM you can specify:

  • The window roll-off factor

  • The windowing function samples. This parameter is optional and defaults to root raised cosine if unspecified

For F-OFDM you can specify:

  • The filter length

  • The tone offset

For more information on how to parameterize the different waveforms see the help for hOFDMModulate and [ 5 ].

Create gNodeB configuration structure 'gnb' and PDSCH configuration structure 'pdsch'

gnb = simParameters;
pdsch = simParameters.PDSCH;

% Specify additional required fields for PDSCH
pdsch.RNTI = 1;

Xoh_PDSCH = 0;     % The Xoh-PDSCH overhead value is taken to be 0 here

Propagation Channel Model Configuration

Create the channel model object. Both CDL and TDL channel models are supported [ 6 ].

nTxAnts = simParameters.NTxAnts;
nRxAnts = simParameters.NRxAnts;

if strcmpi(simParameters.ChannelType,'CDL')
    channel = nrCDLChannel; % CDL channel object

    % Use CDL-C model (Urban macrocell model)
    channel.DelayProfile = 'CDL-C';
    channel.DelaySpread = 300e-9;

    % Turn the overall number of antennas into a specific antenna panel
    % array geometry
    [channel.TransmitAntennaArray.Size, channel.ReceiveAntennaArray.Size] = ...
        arrayGeometry(nTxAnts,nRxAnts);

elseif strcmpi(simParameters.ChannelType,'TDL')
    channel = nrTDLChannel; % TDL channel object
    % Set the channel geometry
    channel.DelayProfile = 'TDL-C';
    channel.DelaySpread = 300e-9;
    channel.NumTransmitAntennas = nTxAnts;
    channel.NumReceiveAntennas = nRxAnts;
else
    error('ChannelType parameter field must be either CDL or TDL.');
end

The sampling rate for the channel model is set using the value returned from hOFDMInfo.

waveformInfo = hOFDMInfo(gnb);
channel.SampleRate = waveformInfo.SamplingRate;

Get the maximum number of delayed samples by a channel multipath component. This is calculated from the channel path with the largest delay and the implementation delay of the channel filter. This is required later to flush the channel filter to obtain the received signal.

chInfo = info(channel);
maxChDelay = ceil(max(chInfo.PathDelays*channel.SampleRate)) + chInfo.ChannelFilterDelay;

Reserve PDSCH Resources Corresponding to SS burst

This section shows how to reserve resources for the transmission of the SS burst.

% Create SS burst information structure
ssburst = simParameters.SSBurst;
ssburst.NCellID = gnb.NCellID;
ssburst.SampleRate = waveformInfo.SamplingRate;

ssbInfo = hSSBurstInfo(ssburst);

% Map the occupied subcarriers and transmitted symbols of the SS burst
% (defined in the SS burst numerology) to PDSCH PRBs and symbols in the
% data numerology
[mappedPRB,mappedSymbols] = mapNumerology(ssbInfo.OccupiedSubcarriers,ssbInfo.OccupiedSymbols,ssbInfo.SubcarrierSpacing,gnb.SubcarrierSpacing);

% Configure the PDSCH to reserve these resources so that the PDSCH
% transmission does not overlap the SS burst
reservation.Symbols = mappedSymbols;
reservation.PRB = mappedPRB;
reservation.Period = ssburst.SSBPeriodicity * (gnb.SubcarrierSpacing/15); % Period in slots
pdsch.Reserved(end+1) = reservation;

Processing Loop

To determine the throughput at each SNR point, the PDSCH data is analyzed per transmission instance using the following steps:

  • Update current HARQ process. Check the CRC of the previous transmission for the given HARQ process. Determine whether a retransmission is required. If that is not the case generate new data.

  • Resource grid generation. Channel coding is performed by encodeDLSCH. It operates on the input transport block provided. Internally, it keeps a copy of the transport block in case a retransmission is required. The coded bits are modulated on the PDSCH by nrPDSCH. The precoding operation is applied to the resulting signal.

  • Waveform generation. The generated grid is then OFDM modulated.

  • Noisy channel modeling. The waveform is passed through a CDL or TDL fading channel. AWGN is added. The SNR for each layer is defined per RE, and it includes the effect of signal and noise across all antennas.

  • Perform synchronization and OFDM demodulation. Information returned by the channel is used for perfect synchronization. The synchronized signal is then OFDM demodulated.

  • Perform perfect channel estimation. Perfect channel estimation is used.

  • Precoding matrix calculation. The precoding matrix W for the next transmission is calculated using singular value decomposition (SVD). A single matrix is obtained for the full allocation by averaging the channel conditions. Therefore, for a channel with frequency selectivity, W could be less accurate for larger allocated bandwidths.

  • Decode the PDSCH. The recovered PDSCH symbols for all transmit and receive antenna pairs, along with a noise estimate, are demodulated and descrambled by nrPDSCHDecode to obtain an estimate of the received codewords.

  • Decode the Downlink Shared Channel (DL-SCH) and store the block CRC error for a HARQ process. The vector of decoded soft bits is passed to hDLSCHDecode which decodes the codeword and returns the block CRC error used to determine the throughput of the system.

% Loop variables initialization
% Array to store the maximum throughput for all SNR points
maxThroughput = zeros(length(simParameters.SNRIn),1);
% Array to store the simulation throughput for all SNR points
simThroughput = zeros(length(simParameters.SNRIn),1);

% Set up Redundancy Version (RV) sequence, number of HARQ processes and
% the sequence in which the HARQ processes are used
if pdsch.EnableHARQ
    % In the final report of RAN WG1 meeting #91 (R1-1719301), it was
    % observed in R1-1717405 that if performance is the priority, [0 2 3 1]
    % should be used. If self-decodability is the priority, it should be
    % taken into account that the upper limit of the code rate at which
    % each RV is self-decodable is in the following order: 0>3>>2>1
    rvSeq = [0 2 3 1];
else
    % HARQ disabled - single transmission with RV=0, no retransmissions
    rvSeq = 0;
end
% Specify the order in which we cycle through the HARQ processes
NHARQProcesses = 16;
harqSequence = 1:NHARQProcesses;

% Create DLSCH encoder system object
encodeDLSCH = hDLSCH;
encodeDLSCH.NumLayers = pdsch.NLayers;
encodeDLSCH.TargetCodeRate = pdsch.TargetCodeRate;

% Create DLSCH decoder system object
decodeDLSCH = hDLSCHDecode;
decodeDLSCH.NumLayers = pdsch.NLayers;
decodeDLSCH.TargetCodeRate = pdsch.TargetCodeRate;
decodeDLSCH.EnableCodewordCombining = pdsch.EnableHARQ;

for snrIdx = 1:numel(simParameters.SNRIn)

    % Set the random number generator settings to default values
    rng('default');
    reset(decodeDLSCH);

    SNRdB = simParameters.SNRIn(snrIdx);
    fprintf('\nSimulating transmission scheme 1 (%dx%d) and SCS=%dkHz with %s channel at %gdB SNR for %d 10ms frame(s)\n',...
        nTxAnts,nRxAnts,gnb.SubcarrierSpacing, ...
        simParameters.ChannelType,SNRdB,gnb.NFrames);

    % Initialize variables used in the simulation and analysis
    blkCRC = [];            % Block CRC for all active PDSCH transmissions
    bitTput = [];           % Number of successfully received bits per transmission
    txedTrBlkSizes = [];    % Number of transmitted info bits per transmission

    % Initialize the state of all HARQ processes
    harqProcesses = newHARQProcess(NHARQProcesses,rvSeq);

    % Reset the channel so that each SNR point will experience the same
    % channel realization
    reset(channel);

    % Total number of OFDM symbols in the simulation period
    NSymbols = gnb.NFrames * 10 * waveformInfo.SymbolsPerSubframe;

    % OFDM symbol number associated with start of each PDSCH transmission
    gnb.NSymbol = 0;

    % Running counter of the number of PDSCH transmission instances
    % The simulation will use this counter as the slot number for each
    % PDSCH
    pdsch.NSlot = 0;

    % Index to the start of the current set of SS burst samples to be
    % transmitted
    ssbSampleIndex = 1;

    % Obtain a precoding matrix (wtx) to be used in the transmission of the
    % first transport block
    estChannelGrid = getInitialChannelEstimate(gnb,nTxAnts,channel);
    newWtx = getPrecodingMatrix(pdsch.PRBSet,pdsch.NLayers,estChannelGrid);

    while  gnb.NSymbol < NSymbols  % Move to next slot, gnb.NSymbol increased in steps of one slot

        % Generate a new SS burst when necessary
        if (ssbSampleIndex==1)
            nSubframe = gnb.NSymbol / waveformInfo.SymbolsPerSubframe;
            ssburst.NFrame = floor(nSubframe / 10);
            ssburst.NHalfFrame = mod(nSubframe / 5,2);
            [ssbWaveform,~,ssbInfo] = hSSBurst(ssburst);
        end

        % Get HARQ process index for the current PDSCH from HARQ index table
        harqProcIdx = harqSequence(mod(pdsch.NSlot,length(harqSequence))+1);

        % Update current HARQ process information (this updates the RV
        % depending on CRC pass or fail in the previous transmission for
        % this HARQ process)
        harqProcesses(harqProcIdx) = updateHARQProcess(harqProcesses(harqProcIdx));

        % Calculate the transport block sizes for the codewords in the slot
        [pdschIndices,dmrsIndices,dmrsSymbols,pdschIndicesInfo] = hPDSCHResources(gnb,pdsch);
        trBlkSizes = hPDSCHTBS(pdsch,pdschIndicesInfo.NREPerPRB-Xoh_PDSCH);
        encodeDLSCH.OutputCodewordLength = pdschIndicesInfo.G; % cw length can change per slot

        % HARQ: check CRC from previous transmission, i.e. is a
        % retransmission required?
        if harqProcesses(harqProcIdx).blkerr
            newTrBlkRequired = false; % Retransmit old data ...
            % Unless we are at end of retransmission schedule
            if (harqProcesses(harqProcIdx).RVIdx==1)
                newTrBlkRequired = true;
                resetHarqProcess(decodeDLSCH,harqProcIdx);
            end
        else % Get new data
            newTrBlkRequired = true;
        end

        % Generate data bits if new transport block is required
        if newTrBlkRequired
            trdata = randi([0 1],trBlkSizes,1);
            setTransportBlock(encodeDLSCH,trdata,harqProcIdx);
            encodeDLSCH.Modulation = pdsch.Modulation;
        end

        codedTrBlock = encodeDLSCH(harqProcIdx,harqProcesses(harqProcIdx).RV);

        % Get wtx (precoding matrix) calculated in previous slot
        wtx = newWtx;

        % PDSCH modulation and precoding
        pdschSymbols = nrPDSCH(codedTrBlock,pdsch.Modulation,pdsch.NLayers,gnb.NCellID,pdsch.RNTI);
        pdschSymbols = pdschSymbols*wtx;

        % PDSCH mapping in grid associated with PDSCH transmission period
        pdschGrid = zeros(waveformInfo.NSubcarriers,waveformInfo.SymbolsPerSlot,nTxAnts);
        [~,pdschAntIndices] = nrExtractResources(pdschIndices,pdschGrid);
        pdschGrid(pdschAntIndices) = pdschSymbols;

        % PDSCH DM-RS precoding and mapping
        for p = 1:size(dmrsSymbols,2)
            [~,dmrsAntIndices] = nrExtractResources(dmrsIndices(:,p),pdschGrid);
            pdschGrid(dmrsAntIndices) = pdschGrid(dmrsAntIndices) + dmrsSymbols(:,p)*wtx(p,:);
        end

        % OFDM modulation of associated resource elements
        txWaveform = hOFDMModulate(gnb, pdschGrid);

        % Add the appropriate portion of SS burst waveform to the
        % transmitted waveform
        Nt = size(txWaveform,1);
        txWaveform = txWaveform + ssbWaveform(ssbSampleIndex + (0:Nt-1),:);
        ssbSampleIndex = mod(ssbSampleIndex + Nt,size(ssbWaveform,1));

        % Pass data through channel model. Append zeros at the end of the
        % transmitted waveform to flush channel content. These zeros take
        % into account any delay introduced in the channel. This is a mix
        % of multipath delay and implementation delay. This value may
        % change depending on the sampling rate, delay profile and delay
        % spread
        txWaveform = [txWaveform; zeros(maxChDelay, size(txWaveform,2))];
        [rxWaveform,pathGains,sampleTimes] = channel(txWaveform);

        % Add AWGN to the received time domain waveform
        % Normalize noise power to take account of sampling rate, which is
        % a function of the IFFT size used in OFDM modulation
        SNR = 10^(SNRdB/20);    % Calculate linear noise gain
        N0 = 1/(sqrt(2.0*double(waveformInfo.Nfft))*SNR);
        noise = N0*complex(randn(size(rxWaveform)),randn(size(rxWaveform)));
        rxWaveform = rxWaveform + noise;

        % Perfect synchronization. Use information provided by the channel
        % to find the strongest multipath component
        pathFilters = getPathFilters(channel); % get path filters for perfect channel estimation
        [offset,mag] = nrPerfectTimingEstimate(pathGains,pathFilters);
        rxWaveform = rxWaveform(1+offset:end, :);

        % Perform OFDM demodulation on the received data to recreate the
        % resource grid
        rxGrid = hOFDMDemodulate(gnb, rxWaveform);

        % Perfect channel estimation, use the value of the path gains
        % provided by the channel
        estChannelGrid = nrPerfectChannelEstimate(pathGains,pathFilters,gnb.NDLRB,gnb.SubcarrierSpacing,pdsch.NSlot,offset,sampleTimes,gnb.CyclicPrefix);

        % Get perfect noise estimate (from the noise realization)
        noiseGrid = hOFDMDemodulate(gnb,noise(1+offset:end ,:));
        noiseEst = var(noiseGrid(:));

        % Get precoding matrix for next slot
        newWtx = getPrecodingMatrix(pdsch.PRBSet,pdsch.NLayers,estChannelGrid);

        % Apply precoding to Hest
        % Linearize 4D matrix and reshape after multiplication
        K = size(estChannelGrid,1);
        estChannelGrid = reshape(estChannelGrid,K*waveformInfo.SymbolsPerSlot*nRxAnts,nTxAnts);
        estChannelGrid = estChannelGrid*wtx.';
        estChannelGrid = reshape(estChannelGrid,K,waveformInfo.SymbolsPerSlot,nRxAnts,pdsch.NLayers);

        % Get PDSCH resource elements from the received grid
        [pdschRx,pdschHest] = nrExtractResources(pdschIndices,rxGrid,estChannelGrid);

        % Equalization
        [pdschEq,csi] = nrEqualizeMMSE(pdschRx,pdschHest,noiseEst);

        % Decode PDSCH physical channel
        [dlschBits,rxSymbols] = nrPDSCHDecode(pdschEq,pdsch.Modulation,gnb.NCellID,pdsch.RNTI,noiseEst);

        % Decode the DL-SCH transport channel
        decodeDLSCH.TransportBlockLength = trBlkSizes;
        decodeDLSCH.Modulation = pdsch.Modulation;
        [decbits,harqProcesses(harqProcIdx).blkerr] = decodeDLSCH(dlschBits,harqProcIdx,harqProcesses(harqProcIdx).RV);

        % Store values to calculate throughput (only for active PDSCH instances)
        if(any(trBlkSizes) ~= 0)
            blkCRC = [blkCRC harqProcesses(harqProcIdx).blkerr];
            bitTput = [bitTput trBlkSizes.*(1-harqProcesses(harqProcIdx).blkerr)];
            txedTrBlkSizes = [txedTrBlkSizes trBlkSizes];
        end

        % Update starting symbol number of next PDSCH transmission
        gnb.NSymbol = gnb.NSymbol + size(pdschGrid,2);
        % Update count of overall number of PDSCH transmissions
        pdsch.NSlot = pdsch.NSlot+1;

        % Display transport block error information per codeword managed by current HARQ process
        fprintf('\n(%3.2f%%) HARQ Proc %d: ',100*gnb.NSymbol/NSymbols,harqProcIdx);
        estrings = {'passed','failed'};
        rvi = harqProcesses(harqProcIdx).RVIdx;
        for cw=1:length(rvi)
            cwrvi = rvi(cw);
            % Create a report on the RV state given position in RV sequence and decoding error
            if cwrvi == 1
                ts = sprintf('Initial transmission (RV=%d)',rvSeq(cw,cwrvi));
            else
                ts = sprintf('Retransmission #%d (RV=%d)',cwrvi-1,rvSeq(cw,cwrvi));
            end
            fprintf('CW%d - %s %s. ',cw-1,ts,estrings{1+harqProcesses(harqProcIdx).blkerr(cw)});
        end

     end

    % Calculate maximum and simulated throughput
    maxThroughput(snrIdx) = sum(txedTrBlkSizes); % Max possible throughput
    simThroughput(snrIdx) = sum(bitTput,2);      % Simulated throughput

    % Display the results dynamically in the command window
    fprintf([['\n\nThroughput(Mbps) for ', num2str(gnb.NFrames) ' frame(s) '],...
        '= %.4f\n'], 1e-6*simThroughput(snrIdx)/(gnb.NFrames*10e-3));
    fprintf(['Throughput(%%) for ', num2str(gnb.NFrames) ' frame(s) = %.4f\n'],...
        simThroughput(snrIdx)*100/maxThroughput(snrIdx));

end
Simulating transmission scheme 1 (8x2) and SCS=30kHz with CDL channel at -5dB SNR for 2 10ms frame(s)

(2.50%) HARQ Proc 1: CW0 - Initial transmission (RV=0) failed. 
(5.00%) HARQ Proc 2: CW0 - Initial transmission (RV=0) failed. 
(7.50%) HARQ Proc 3: CW0 - Initial transmission (RV=0) failed. 
(10.00%) HARQ Proc 4: CW0 - Initial transmission (RV=0) failed. 
(12.50%) HARQ Proc 5: CW0 - Initial transmission (RV=0) failed. 
(15.00%) HARQ Proc 6: CW0 - Initial transmission (RV=0) failed. 
(17.50%) HARQ Proc 7: CW0 - Initial transmission (RV=0) failed. 
(20.00%) HARQ Proc 8: CW0 - Initial transmission (RV=0) failed. 
(22.50%) HARQ Proc 9: CW0 - Initial transmission (RV=0) failed. 
(25.00%) HARQ Proc 10: CW0 - Initial transmission (RV=0) failed. 
(27.50%) HARQ Proc 11: CW0 - Initial transmission (RV=0) failed. 
(30.00%) HARQ Proc 12: CW0 - Initial transmission (RV=0) failed. 
(32.50%) HARQ Proc 13: CW0 - Initial transmission (RV=0) failed. 
(35.00%) HARQ Proc 14: CW0 - Initial transmission (RV=0) failed. 
(37.50%) HARQ Proc 15: CW0 - Initial transmission (RV=0) failed. 
(40.00%) HARQ Proc 16: CW0 - Initial transmission (RV=0) failed. 
(42.50%) HARQ Proc 1: CW0 - Retransmission #1 (RV=2) failed. 
(45.00%) HARQ Proc 2: CW0 - Retransmission #1 (RV=2) failed. 
(47.50%) HARQ Proc 3: CW0 - Retransmission #1 (RV=2) failed. 
(50.00%) HARQ Proc 4: CW0 - Retransmission #1 (RV=2) failed. 
(52.50%) HARQ Proc 5: CW0 - Retransmission #1 (RV=2) failed. 
(55.00%) HARQ Proc 6: CW0 - Retransmission #1 (RV=2) failed. 
(57.50%) HARQ Proc 7: CW0 - Retransmission #1 (RV=2) failed. 
(60.00%) HARQ Proc 8: CW0 - Retransmission #1 (RV=2) failed. 
(62.50%) HARQ Proc 9: CW0 - Retransmission #1 (RV=2) failed. 
(65.00%) HARQ Proc 10: CW0 - Retransmission #1 (RV=2) failed. 
(67.50%) HARQ Proc 11: CW0 - Retransmission #1 (RV=2) failed. 
(70.00%) HARQ Proc 12: CW0 - Retransmission #1 (RV=2) failed. 
(72.50%) HARQ Proc 13: CW0 - Retransmission #1 (RV=2) failed. 
(75.00%) HARQ Proc 14: CW0 - Retransmission #1 (RV=2) failed. 
(77.50%) HARQ Proc 15: CW0 - Retransmission #1 (RV=2) failed. 
(80.00%) HARQ Proc 16: CW0 - Retransmission #1 (RV=2) failed. 
(82.50%) HARQ Proc 1: CW0 - Retransmission #2 (RV=3) failed. 
(85.00%) HARQ Proc 2: CW0 - Retransmission #2 (RV=3) failed. 
(87.50%) HARQ Proc 3: CW0 - Retransmission #2 (RV=3) failed. 
(90.00%) HARQ Proc 4: CW0 - Retransmission #2 (RV=3) failed. 
(92.50%) HARQ Proc 5: CW0 - Retransmission #2 (RV=3) failed. 
(95.00%) HARQ Proc 6: CW0 - Retransmission #2 (RV=3) failed. 
(97.50%) HARQ Proc 7: CW0 - Retransmission #2 (RV=3) failed. 
(100.00%) HARQ Proc 8: CW0 - Retransmission #2 (RV=3) failed. 

Throughput(Mbps) for 2 frame(s) = 0.0000
Throughput(%) for 2 frame(s) = 0.0000

Simulating transmission scheme 1 (8x2) and SCS=30kHz with CDL channel at 0dB SNR for 2 10ms frame(s)

(2.50%) HARQ Proc 1: CW0 - Initial transmission (RV=0) failed. 
(5.00%) HARQ Proc 2: CW0 - Initial transmission (RV=0) failed. 
(7.50%) HARQ Proc 3: CW0 - Initial transmission (RV=0) failed. 
(10.00%) HARQ Proc 4: CW0 - Initial transmission (RV=0) failed. 
(12.50%) HARQ Proc 5: CW0 - Initial transmission (RV=0) failed. 
(15.00%) HARQ Proc 6: CW0 - Initial transmission (RV=0) failed. 
(17.50%) HARQ Proc 7: CW0 - Initial transmission (RV=0) failed. 
(20.00%) HARQ Proc 8: CW0 - Initial transmission (RV=0) failed. 
(22.50%) HARQ Proc 9: CW0 - Initial transmission (RV=0) failed. 
(25.00%) HARQ Proc 10: CW0 - Initial transmission (RV=0) failed. 
(27.50%) HARQ Proc 11: CW0 - Initial transmission (RV=0) failed. 
(30.00%) HARQ Proc 12: CW0 - Initial transmission (RV=0) failed. 
(32.50%) HARQ Proc 13: CW0 - Initial transmission (RV=0) failed. 
(35.00%) HARQ Proc 14: CW0 - Initial transmission (RV=0) failed. 
(37.50%) HARQ Proc 15: CW0 - Initial transmission (RV=0) failed. 
(40.00%) HARQ Proc 16: CW0 - Initial transmission (RV=0) failed. 
(42.50%) HARQ Proc 1: CW0 - Retransmission #1 (RV=2) failed. 
(45.00%) HARQ Proc 2: CW0 - Retransmission #1 (RV=2) failed. 
(47.50%) HARQ Proc 3: CW0 - Retransmission #1 (RV=2) failed. 
(50.00%) HARQ Proc 4: CW0 - Retransmission #1 (RV=2) failed. 
(52.50%) HARQ Proc 5: CW0 - Retransmission #1 (RV=2) failed. 
(55.00%) HARQ Proc 6: CW0 - Retransmission #1 (RV=2) failed. 
(57.50%) HARQ Proc 7: CW0 - Retransmission #1 (RV=2) failed. 
(60.00%) HARQ Proc 8: CW0 - Retransmission #1 (RV=2) failed. 
(62.50%) HARQ Proc 9: CW0 - Retransmission #1 (RV=2) failed. 
(65.00%) HARQ Proc 10: CW0 - Retransmission #1 (RV=2) failed. 
(67.50%) HARQ Proc 11: CW0 - Retransmission #1 (RV=2) failed. 
(70.00%) HARQ Proc 12: CW0 - Retransmission #1 (RV=2) failed. 
(72.50%) HARQ Proc 13: CW0 - Retransmission #1 (RV=2) failed. 
(75.00%) HARQ Proc 14: CW0 - Retransmission #1 (RV=2) failed. 
(77.50%) HARQ Proc 15: CW0 - Retransmission #1 (RV=2) failed. 
(80.00%) HARQ Proc 16: CW0 - Retransmission #1 (RV=2) failed. 
(82.50%) HARQ Proc 1: CW0 - Retransmission #2 (RV=3) passed. 
(85.00%) HARQ Proc 2: CW0 - Retransmission #2 (RV=3) passed. 
(87.50%) HARQ Proc 3: CW0 - Retransmission #2 (RV=3) passed. 
(90.00%) HARQ Proc 4: CW0 - Retransmission #2 (RV=3) passed. 
(92.50%) HARQ Proc 5: CW0 - Retransmission #2 (RV=3) passed. 
(95.00%) HARQ Proc 6: CW0 - Retransmission #2 (RV=3) passed. 
(97.50%) HARQ Proc 7: CW0 - Retransmission #2 (RV=3) passed. 
(100.00%) HARQ Proc 8: CW0 - Retransmission #2 (RV=3) passed. 

Throughput(Mbps) for 2 frame(s) = 12.0864
Throughput(%) for 2 frame(s) = 20.0000

Simulating transmission scheme 1 (8x2) and SCS=30kHz with CDL channel at 5dB SNR for 2 10ms frame(s)

(2.50%) HARQ Proc 1: CW0 - Initial transmission (RV=0) passed. 
(5.00%) HARQ Proc 2: CW0 - Initial transmission (RV=0) passed. 
(7.50%) HARQ Proc 3: CW0 - Initial transmission (RV=0) passed. 
(10.00%) HARQ Proc 4: CW0 - Initial transmission (RV=0) passed. 
(12.50%) HARQ Proc 5: CW0 - Initial transmission (RV=0) passed. 
(15.00%) HARQ Proc 6: CW0 - Initial transmission (RV=0) passed. 
(17.50%) HARQ Proc 7: CW0 - Initial transmission (RV=0) passed. 
(20.00%) HARQ Proc 8: CW0 - Initial transmission (RV=0) passed. 
(22.50%) HARQ Proc 9: CW0 - Initial transmission (RV=0) passed. 
(25.00%) HARQ Proc 10: CW0 - Initial transmission (RV=0) passed. 
(27.50%) HARQ Proc 11: CW0 - Initial transmission (RV=0) passed. 
(30.00%) HARQ Proc 12: CW0 - Initial transmission (RV=0) passed. 
(32.50%) HARQ Proc 13: CW0 - Initial transmission (RV=0) passed. 
(35.00%) HARQ Proc 14: CW0 - Initial transmission (RV=0) passed. 
(37.50%) HARQ Proc 15: CW0 - Initial transmission (RV=0) passed. 
(40.00%) HARQ Proc 16: CW0 - Initial transmission (RV=0) passed. 
(42.50%) HARQ Proc 1: CW0 - Initial transmission (RV=0) passed. 
(45.00%) HARQ Proc 2: CW0 - Initial transmission (RV=0) passed. 
(47.50%) HARQ Proc 3: CW0 - Initial transmission (RV=0) passed. 
(50.00%) HARQ Proc 4: CW0 - Initial transmission (RV=0) passed. 
(52.50%) HARQ Proc 5: CW0 - Initial transmission (RV=0) passed. 
(55.00%) HARQ Proc 6: CW0 - Initial transmission (RV=0) passed. 
(57.50%) HARQ Proc 7: CW0 - Initial transmission (RV=0) passed. 
(60.00%) HARQ Proc 8: CW0 - Initial transmission (RV=0) passed. 
(62.50%) HARQ Proc 9: CW0 - Initial transmission (RV=0) passed. 
(65.00%) HARQ Proc 10: CW0 - Initial transmission (RV=0) passed. 
(67.50%) HARQ Proc 11: CW0 - Initial transmission (RV=0) passed. 
(70.00%) HARQ Proc 12: CW0 - Initial transmission (RV=0) passed. 
(72.50%) HARQ Proc 13: CW0 - Initial transmission (RV=0) passed. 
(75.00%) HARQ Proc 14: CW0 - Initial transmission (RV=0) passed. 
(77.50%) HARQ Proc 15: CW0 - Initial transmission (RV=0) passed. 
(80.00%) HARQ Proc 16: CW0 - Initial transmission (RV=0) passed. 
(82.50%) HARQ Proc 1: CW0 - Initial transmission (RV=0) passed. 
(85.00%) HARQ Proc 2: CW0 - Initial transmission (RV=0) passed. 
(87.50%) HARQ Proc 3: CW0 - Initial transmission (RV=0) passed. 
(90.00%) HARQ Proc 4: CW0 - Initial transmission (RV=0) passed. 
(92.50%) HARQ Proc 5: CW0 - Initial transmission (RV=0) passed. 
(95.00%) HARQ Proc 6: CW0 - Initial transmission (RV=0) passed. 
(97.50%) HARQ Proc 7: CW0 - Initial transmission (RV=0) passed. 
(100.00%) HARQ Proc 8: CW0 - Initial transmission (RV=0) passed. 

Throughput(Mbps) for 2 frame(s) = 60.4320
Throughput(%) for 2 frame(s) = 100.0000

Results

Display the measured throughput. This is calculated as the percentage of the maximum possible throughput of the link given the available resources for data transmission.

figure;
plot(simParameters.SNRIn,simThroughput*100./maxThroughput,'o-.')
xlabel('SNR (dB)'); ylabel('Throughput (%)'); grid on;
title(sprintf('(%dx%d) / NDLRB=%d / SCS=%dkHz',...
              nTxAnts,nRxAnts,gnb.NDLRB,gnb.SubcarrierSpacing));

% Bundle key parameters and results into a combined structure for recording
simResults.simParameters = simParameters;
simResults.simThroughput = simThroughput;

The figure below shows throughput results obtained simulating 10000 subframes.

Appendix

This example uses the following helper functions:

Selected Bibliography

  1. 3GPP TS 38.211. "NR; Physical channels and modulation (Release 15)." 3rd Generation Partnership Project; Technical Specification Group Radio Access Network.

  2. 3GPP TS 38.212. "NR; Multiplexing and channel coding (Release 15)." 3rd Generation Partnership Project; Technical Specification Group Radio Access Network.

  3. 3GPP TS 38.213. "NR; Physical layer procedures for control (Release 15)." 3rd Generation Partnership Project; Technical Specification Group Radio Access Network.

  4. 3GPP TS 38.214. "NR; Physical layer procedures for data (Release 15)." 3rd Generation Partnership Project; Technical Specification Group Radio Access Network.

  5. R1-166999. "Detailed configuration of F-OFDM and W-OFDM for LLS evaluation", 3GPP RAN WG1 #86, Spreadtrum Communications, August 2016.

  6. 3GPP TR 38.901. "Study on channel model for frequencies from 0.5 to 100 GHz (Release 15)." 3rd Generation Partnership Project; Technical Specification Group Radio Access Network.

Local Functions

function validateNLayers(simParameters)
% Validate the number of layers
    if length(simParameters.PDSCH.PortSet)~= simParameters.PDSCH.NLayers
        error('The number of elements of PortSet (%d) must be the same as the number of layers (%d)',...
            length(simParameters.PDSCH.PortSet), simParameters.PDSCH.NLayers);
    end

    if simParameters.PDSCH.NLayers > min(simParameters.NTxAnts,simParameters.NRxAnts)
        error('The number of layers (%d) must satisfy NLayers <= min(NTxAnts,NRxAnts) = min(%d,%d) = (%d)',...
            simParameters.PDSCH.NLayers,simParameters.NTxAnts,simParameters.NRxAnts,min(simParameters.NTxAnts,simParameters.NRxAnts));
    end
end

function estChannelGrid = getInitialChannelEstimate(gnb,nTxAnts,channel)
% Obtain channel estimate before first transmission. This can be used to
% obtain a precoding matrix for the first slot.

    ofdmInfo = hOFDMInfo(gnb);

    chInfo = info(channel);
    maxChDelay = ceil(max(chInfo.PathDelays*channel.SampleRate)) + chInfo.ChannelFilterDelay;

    % Temporary waveform (only needed for the sizes)
    tmpWaveform = zeros((ofdmInfo.SamplesPerSubframe/ofdmInfo.SlotsPerSubframe)+maxChDelay,nTxAnts);

    % Filter through channel
    [~,pathGains,sampleTimes] = channel(tmpWaveform);

    % Perfect timing synch
    pathFilters = getPathFilters(channel);
    offset = nrPerfectTimingEstimate(pathGains,pathFilters);

    nslot = gnb.NSymbol/ofdmInfo.SymbolsPerSlot;

    % Perfect channel estimate
    estChannelGrid = nrPerfectChannelEstimate(pathGains,pathFilters,gnb.NDLRB,gnb.SubcarrierSpacing,nslot,offset,sampleTimes);

end

function wtx = getPrecodingMatrix(PRBSet,NLayers,hestGrid)
% Calculate precoding matrix given an allocation and a channel estimate

    % Allocated subcarrier indices
    allocSc = (1:12)' + 12*PRBSet(:).';
    allocSc = allocSc(:);

    % Average channel estimate
    [~,~,R,P] = size(hestGrid);
    estAllocGrid = hestGrid(allocSc,:,:,:);
    Hest = permute(mean(reshape(estAllocGrid,[],R,P)),[2 3 1]);

    % SVD decomposition
    [~,~,V] = svd(Hest);
    wtx = V(:,1:NLayers).';

end

function [mappedPRB,mappedSymbols] = mapNumerology(subcarriers,symbols,fs,ft)

    mappedPRB = unique(fix(subcarriers*fs/(ft*12)),'stable');

    if (ft < fs)
        % If ft/fs < 1, reduction
        mappedSymbols = unique(fix(symbols*ft/fs),'stable');
    else
        % Else, repetition by ft/fs
        mappedSymbols = reshape((0:(ft/fs-1))' + symbols(:)'*ft/fs,1,[]);
    end

end

function harqProcesses = newHARQProcess(NHARQProcesses,rvsequence)
% Generates an array of NHARQProcesses new HARQ processes with the provided
% modulation and RV sequence values

    ncw = 1; % one codeword
    harqProcess.RVSequence = rvsequence;
    harqProcess.blkerr = zeros(1,ncw);         % Initialize block errors
    harqProcess.ncw = ncw;                     % Set number of codewords

    harqProcess.RVIdx = ones(1,ncw); % Add RVIdx to config
    harqProcess.RV = rvsequence(ones(1,ncw));

    % Create HARQ processes as indicated by NHARQProcesses
    harqProcesses(1:NHARQProcesses) = harqProcess;

end

function [harqProcess] = updateHARQProcess(harqProcess)
% Update HARQ process redundancy version (RV)

	blkpass = ~(harqProcess.blkerr);

    % Advance to next RV and generate new data
    harqProcess.RVIdx = mod(harqProcess.RVIdx + 1, ...
        length(harqProcess.RVSequence)+1); % RvIdx == 0 means no more retransmit
    blkpass(harqProcess.RVIdx == 0) = true;

    % Update the RV for new transmission
    harqProcess.RVIdx(blkpass) = 1;

    % Update RVSeq for transmit side
    harqProcess.RV = harqProcess.RVSequence(1, ...
        harqProcess.RVIdx(1)).';

end

function [txArrayGeometry, rxArrayGeometry] = arrayGeometry(nTxAnts,nRxAnts)

    % Setup the transmit antenna geometry
    % Table of antenna panel array configurations
    % M:  no. of rows in each antenna panel
    % N:  no. of columns in each antenna panel
    % P:  no. of polarizations (1 or 2)
    % Mg: no. of rows in the array of panels
    % Ng: no. of columns in the array of panels
    % Row format: [M  N   P   Mg  Ng]
    antarrays = ...
        [1   1   1   1   1;   % 1 ants
        1   1   2   1   1;   % 2 ants
        2   1   2   1   1;   % 4 ants
        2   2   2   1   1;   % 8 ants
        2   4   2   1   1;   % 16 ants
        4   4   2   1   1;   % 32 ants
        4   4   2   1   2;   % 64 ants
        4   8   2   1   2;   % 128 ants
        4   8   2   2   2;   % 256 ants
        8   8   2   2   2;   % 512 ants
        8  16   2   2   2];  % 1024 ants
    antselected = 1+fix(log2(nTxAnts));
    txArrayGeometry = antarrays(antselected,:);

    % Setup the receive antenna geometry
    if nRxAnts == 1
        % In the following settings, the number of rows in antenna array,
        % columns in antenna array, polarizations, row array panels and the
        % columns array panels are all 1
        rxArrayGeometry = ones(1,5);
    else
        % In the following settings, the no. of rows in antenna array is
        % nRxAntennas/2, the no. of columns in antenna array is 1, the no.
        % of polarizations is 2, the no. of row array panels is 1 and the
        % no. of column array panels is 1. The values can be changed to
        % create alternative antenna setups
        rxArrayGeometry = [fix(nRxAnts/2),1,2,1,1];
    end

end

See Also

System Objects

Functions