%% PDCCH Conformance Test
% Example showing how to generate the PDCCH/PCFICH RMCs defined in TS
% 36.101 and use in conformance tests.

% Copyright 2015-2018 The MathWorks, Inc.

%% Introduction
% This example shows the demodulation performance of PDCCH/PCFICH and
% determination of the probability of miss-detection of the downlink
% scheduling grant (Pm-dsg) test as defined in TS 36.101/TS 36.521-1
% Section 8.4. The PDCCH and PCFICH are tested jointly and a miss-detection
% of PCFICH implies a miss-detection of PDCCH. The 1x2 transmit/receive
% antenna port performance test in TS 36.101 Section 8.4.1.1 Table
% 8.4.1.1-1[ <#10 1> ] for R.15 PDCCH/PCFICH reference channel (FDD duplex
% mode) defines a required Pm-dsg of 1% at an SNR of -1.7 dB.
%
% The LTE Toolbox(TM) allows configuration of the downlink waveform
% generator (<matlab:doc('lteRMCDLTool') lteRMCDLTool>) for PDCCH
% conformance tests. Working on a frame by frame basis when simulating at a
% particular SNR, a populated resource grid is generated and OFDM modulated
% to create a transmit waveform. The generated waveform is passed through a
% noisy Extended Typical Urban (ETU) channel. Channel estimation,
% equalization, demodulation and decoding are performed at receiver. The
% average miss-detection probability of the PDCCH/PCFICH is determined
% using the combination of the received CFI and received DCI message.

%% Simulation Setup
% The example is executed for a simulation length of 1 frame to keep the
% simulation time low. SNR values include -1.7 dB specified for the R.15
% RMC single port test. A large number of frames, |NFrames|, should be used
% to produce meaningful results. |SNRIn| can be an array of values or a
% scalar.

nFrames = 1;                      % Number of frames to simulate
snrIn = [-3.1 -2.4 -1.7 -1 -0.3]; % SNR points to simulate

%% PDCCH/PCFICH Configuration
% The downlink waveform generator <matlab:doc('lteRMCDLTool') lteRMCDLTool>
% generates the PDSCH, PDCCH, PCFICH and other physical channels and
% signals. Here we perform the conformance testing for the R.15 FDD RMC by
% configuring the PCFICH and PDCCH channels and generating the waveform.
% The parameters for the generator are specified via a structure |rmc|. The
% <matlab:doc('lteRMCDL') lteRMCDL> function generates PDSCH RMC
% configurations including associated PDCCH/PCFICH and we can update the
% PDCCH/PCFICH parameters to generate the PDCCH/PCFICH RMCs. Here we start
% by using a PDSCH RMC that closely matches the PDSCH setup mentioned in TS
% 36.521-1 Section 8.4.1.1.4 [ <#10 2> ] for the R.15 FDD RMC and then
% setting the DCI and PDCCH parameters. No data and control is transmitted
% on subframe 5. Therefore it is not decoded and does not count towards the
% missed detection calculation.

% Setup the PDSCH according to TS 36.521-1 Table A.3.5.1-2 for single port
% which corresponds to R.2 FDD PDSCH RMC
rmc = lteRMCDL('R.2','FDD');

% Setup DCI and PDCCH according to TS 36.101 Section 8.4.1.1 for R.15 FDD
% RMC which requires the CFI, DCI format, HICH group multiplier,
% aggregation level and power to be set as defined for the test
rmc.CFI = 2;                     % OFDM symbols for PDCCH
rmc.Ng = 'One';                  % HICH group multiplier
rmc.PDSCH.DCIFormat = 'Format1'; % Set the DCI Format
rmc.PDSCH.PDCCHFormat = 3;       % Set the aggregation level to be 8
rmc.PDSCH.PDCCHPower = 0;        % Relative power is 0dB for single port 

% Setup the OCNG to fill all unused data and control region REs
rmc.OCNGPDSCHEnable = 'On';
rmc.OCNGPDSCHPower = 0;
rmc.OCNGPDCCHEnable = 'On';
rmc.OCNGPDCCHPower = 0;

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

%% Channel Estimator Configuration
% The variable |perfectChannelEstimator| controls channel estimator
% behavior. Valid values are |true| or |false|. When set to |true| a
% perfect channel estimate is used otherwise an imperfect estimate is used,
% based on the values of received pilot signals.

% Channel estimator behavior
perfectChannelEstimator = false;

%%
% The imperfect channel estimator is configured with a structure |cec|. An
% ETU delay profile causes the channel to change quickly over time.
% Therefore only time averaging is performed over pilot estimates by
% setting the frequency window to 1 Resource Element (RE). A Doppler
% frequency of 70 Hz causes the channel fading to be slow enough to allow a
% large time averaging window. Pilots in the whole frame are included in
% the average by setting the time window to 31 REs.

% Configure channel estimator
cec.PilotAverage = 'UserDefined';   % Type of pilot symbol averaging
cec.FreqWindow = 1;                 % Frequency window size in REs
cec.TimeWindow = 31;                % Time window size in REs
cec.InterpType = 'Cubic';           % 2D interpolation type
cec.InterpWindow = 'Centered';      % Interpolation window type
cec.InterpWinSize = 3;              % Interpolation window size


%% Processing 
% For each SNR point the following operations are performed for each frame:
% 
% * _RMC Generation and OFDM Modulation_: Generate the OFDM modulated
% waveform as defined for the PDCCH/PCFICH RMC.
% * _Propagation Channel Model_: The OFDM modulated waveform is transmitted
% through the propagation channel. The output of the channel |rxWaveform|
% has two columns, one per receive antenna.
% * _Add Channel Noise_: The channel noise is modeled by AWGN.
% * _Receiver Synchronization and OFDM Demodulation_: Determine the delay
% suffered during propagation. This is calculated by calling
% <matlab:doc('lteDLFrameOffset') lteDLFrameOffset>, which uses the primary
% and secondary synchronization signals. OFDM demodulation is performed
% after synchronization.
% * _Channel Estimation_: Provides an estimate of the channel response at
% each element of the resource grid for a transmit/receive antenna pair.
% This estimate is then used to remove the effect of the channel on the
% transmitted signal. The channel estimation also aims to reduce the
% channel noise experienced during transmission by averaging the reference
% signals (pilot symbols).
% * _Miss-Detection Measurement_: PCFICH and PDCCH data is analyzed on a
% subframe by subframe basis. A specific frame worth of data for all
% receive antennas is extracted from the array of received grids, the same
% defined frame worth of information is extracted from the estimate of
% channel response for all transmit and receive antenna pairs. These, along
% with the noise estimate, are input into the function
% <matlab:doc('ltePCFICHDecode') ltePCFICHDecode>, which decodes the CFI
% data. If the CFI is correctly detected, the PCFICH reception is
% successful and the next stage is to receive the DCI. Using the channel
% estimate and noise estimate, the PDCCH message is recovered using the
% <matlab:doc('ltePDCCHDecode') ltePDCCHDecode> function; blind search is
% then performed on this decoded bits to recover the DCI. If the DCI
% message is also correctly received, the transmission is successful and
% used to determine the detection of the system.

% dims is a three element vector [K L P]: where K = no of subcarriers,
% L = no of OFDM symbols and P = no of transmit antennas
dims = lteDLResourceGridSize(rmc);  % Determine resource grid dimensions
L = dims(2);                        % Number of OFDM symbols per subframe
P = dims(3);                        % Number of transmit antennas

% Initialize the variables used in the simulation and analysis
resultIndex = 1;                    % Initialize SNR index
initOffsets = 0;                    % Initialize frame offset 

% Set the random number generator to default value
rng('default');

% Number of subframes carrying transport blocks with data and control
% within a frame. For RMC R.15 this should be 9, as out of the 10 subframes
% in a frame subframe 5 does not carry any data or control
nDataTBSPerFrame = sum(rmc.PDSCH.TrBlkSizes(:) ~= 0);

% Total Pmdsg vector
totalPmdsg = zeros(numel(snrIn),nDataTBSPerFrame*nFrames); 

for snrdb = snrIn
    fprintf('\nSimulating at %gdB SNR for a total %d Frame(s)\n',...
    snrdb,nFrames);

    % Initialize result vector for each SNR point
    totalPmdsgSNR = zeros(nFrames,nDataTBSPerFrame);% Total block CRC 
    
    % Initialize offset vector for each frame
    offsets = initOffsets;
    
    for FrameNo = 1:nFrames
        
        % Set the subframe number
        rmc.NSubframe = 0;
        
        % Generate the waveform
        [txWaveform,txGrid,info] = lteRMCDLTool(rmc,[1 0 0 1]);
        
        % Initialize result store for frame
        pmdsg = zeros(nDataTBSPerFrame,1);   
        dataSubframeIndex = 1;

        % Set sampling rate of channel to that of OFDM modulation     
        cfg.SamplingRate = info.SamplingRate;

        % Set channel offset to current frame (1 frame = 10ms)
        cfg.InitTime = (FrameNo-1)*(rmc.TotSubframes)/1000;

        % Pass data through the fading channel model. 
        % An additional 25 samples are added to the end of the waveform.
        % These are to cover the range of delays expected from the channel
        % modeling (a combination of implementation delay and channel
        % delay spread).
        rxWaveform = lteFadingChannel(cfg,[txWaveform ; zeros(25,P)]);

        % Noise setup
        SNR = 10^((snrdb-rmc.PDSCH.PDCCHPower)/20);    % Linear SNR

        % 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*rmc.CellRefP*double(info.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;

        % Perform receiver synchronization 
        offset = lteDLFrameOffset(rmc,rxWaveform);

        % Determine if frame synchronization was successful
        if (offset > 25)
            offset = offsets(end);
        else
            offsets = [offsets offset]; %#ok
        end
        if (offset>0)
            rxWaveform = rxWaveform(1+offset:end,:);
        end

        % Perform OFDM demodulation on the received data to recreate the
        % resource grid
        rxGrid = lteOFDMDemodulate(rmc,rxWaveform);
        
        % Channel estimation
        if(perfectChannelEstimator)
            estChannelGrid = lteDLPerfectChannelEstimate(rmc, cfg, offset);  %#ok<UNRCH>
            n = lteOFDMDemodulate(rmc, noise(1+offset:end ,:));
            noiseest = var(n(:));
        else
            [estChannelGrid, noiseest] = lteDLChannelEstimate( ...
                rmc, cec, rxGrid);
        end

        % Process subframes 0 to 9 within received frame. Test for PCFICH
        % and if successful, test for PDCCH. If both PCFICH and PDCCH are
        % successfully received, the transmission is successful
        for sf = 0:rmc.TotSubframes-1

            % Increment subframe number for correct decoding of data
            rmc.NSubframe = mod(sf,10);
            
            % No data is transmitted in subframe 5, so skip this
            if(rmc.NSubframe ~= 5) 
            
                % Extract one subframe for analyzing at a time from the
                % received grid        
                rxSubframe = rxGrid(:,L*sf+1:L*(sf+1),:);

                % Extract the estimated channel response for the subframe
                % being analyzed
                chSubframe = estChannelGrid(:,L*sf+1:L*(sf+1),:,:);

                % Perform PCFICH decoding of received data using the estimate
                % of the channel
                pcfichIndices = ltePCFICHIndices(rmc);
                [rxPcfichSym,pcfichHestSym] = lteExtractResources(pcfichIndices,rxSubframe,chSubframe);
                rxPcfich = ltePCFICHDecode(rmc,rxPcfichSym,pcfichHestSym,noiseest);
                rxCFI = lteCFIDecode(rxPcfich);

                if rxCFI ~= rmc.CFI
                    rxFail = 1;
                else
                   % CFI decoded fine, now check if DCI can be decoded

                   % Extract and decode PDCCH bits
                   pdcchIndices = ltePDCCHIndices(rmc);
                   [rxPdcchSym,pdcchHestSym] = lteExtractResources(pdcchIndices,rxSubframe,chSubframe);
                   rxPdcchBits = ltePDCCHDecode(rmc,rxPdcchSym,pdcchHestSym,noiseest); 

                   % PDCCH blind search, demask PDCCH candidate using RNTI
                   ueConfig.RNTI = rmc.PDSCH.RNTI;
                   ueConfig.ControlChannelType = 'PDCCH';
                   ueConfig.EnableCarrierIndication = 'Off';
                   ueConfig.SearchSpace = 'UESpecific';
                   ueConfig.EnableMultipleCSIRequest = 'Off';
                   ueConfig.EnableSRSRequest = 'Off';
                   ueConfig.NTxAnts = 1;
                   [rxDCI,rxDCIBits] = ltePDCCHSearch(rmc,ueConfig,rxPdcchBits);

                   if ~isempty(rxDCI) && isfield(rxDCI{1},'DCIFormat') && strcmpi(rxDCI{1}.DCIFormat,rmc.PDSCH.DCIFormat)
                       rxFail = 0;
                   else
                       rxFail = 1;
                   end
            
                end
                % Store the values and increment the subframe index
                pmdsg(dataSubframeIndex, :) = rxFail;
                dataSubframeIndex = dataSubframeIndex + 1;
            end
        end
        % Store resulting pmdsg results 
        totalPmdsgSNR(FrameNo,:) = pmdsg(:);

    end
    % Record the missed detection for the total number of frames simulated
    % at a particular SNR
    totalPmdsg(resultIndex,:) = totalPmdsgSNR(:); % CRC 
    resultIndex = resultIndex + 1;
    
end

%% Plot Results

% Pm-dsg should be less than 1% at -1.7 dB SNR for single port
pmdsgVal = 100*mean(totalPmdsg,2);
figure
plot(snrIn,pmdsgVal,'-*')
title(['Pm-dsg for ', num2str(nFrames) ' frame(s)'] )
xlabel('SNR(dB)'); ylabel('Pm-dsg (%)');
grid on;
hold on;
plot(snrIn, ones(1,numel(snrIn)),'--rs');
legend('Simulation Result','Target 1% Pm-dsg','Location',...
       'NorthEast');
ylim([fix(min(pmdsgVal)-2) fix(max(pmdsgVal)+2)]);

%% Further Exploration
% You can modify parts of this example to generate other PDCCH/PCFICH RMCs
% (as per TS 36.101 Section 8.4 [ <#10 1> ] and 36.521-1 Section 8.4 [ <#10
% 2> ]). For example, to generate the R.16 FDD RMC from TS 36.101 Section
% 8.4.2.2.1 [ <#10 1> ] which is defined for transmit diversity performance
% with 2x2 transmit/receive antenna configuration, update the |rmc|
% structure as below:

rmc.CellRefP = 2;                   % Number of transmit antenna ports
rmc.CFI = 2;                        % OFDM symbols for PDCCH
rmc.Ng = 'One';                     % HICH group multiplier
rmc.PDSCH.DCIFormat = 'Format2';    % Set the DCI Format
rmc.PDSCH.PDCCHFormat = 2;          % Set the aggregation level to be 4
rmc.PDSCH.PDCCHPower = -3;          % Relative power is -3dB 
rmc.PDSCH.TxScheme = 'TxDiversity'; % PDSCH transmission scheme
rmc.PDSCH.NLayers = 2;              % Number of transmission layers
rmc.OCNGPDSCH.TxScheme = 'TxDiversity'; % PDSCH OCNG transmission scheme
rmc.OCNGPDCCHPower = -3;            % Relative power is -3dB for PDCCH OCNG   

%% Selected Bibliography
% # 3GPP TS 36.101 "User Equipment (UE) radio transmission and reception"
% # 3GPP TS 36.521-1 "User Equipment (UE) conformance specification; Radio
% transmission and reception; Part 1: Conformance testing"
