%heDecodeWaveform Waveform decoding and EVM calculation
%   [EVM,DATASYM,RXPSDU] = heDecodeWaveform(RXWAVEFORM,COUNT) decodes the
%   received HE waveform, RXWAVEFORM. It returns the decoded symbols
%   DATASYM, the average EVM and the decoded bits, RXPSDU. It considers
%   COUNT to set up the EVM plots at the beginning of the simulation.

%   Copyright 2020-2021 The MathWorks, Inc.

function [EVM,dataSym,rxPSDU] = heDecodeWaveform(rxWaveform,count)

    % Create EVM plot instances as persistent so that the same plot is updated
    % when new data is available during simulation
    persistent EVMSymbolPlot;
    persistent EVMSubcarrierPlot;
    persistent EVMCalculator;
    
    % Get waveform information from workspace
    cfgHE = evalin('base', 'HEInfo.WaveformConfig');
    chanBW = cfgHE.ChannelBandwidth;
    fs = wlanSampleRate(cfgHE);
    
    % Get subcarrier indices and OFDM parameters
    ofdmInfo = wlanHEOFDMInfo('HE-Data',cfgHE);
   
    % Indices to extract fields from the PPDU
    ind = wlanFieldIndices(cfgHE);
    
    % Obtain coarse packet offset
    coarsePktOffset = wlanPacketDetect(rxWaveform,chanBW);
    if isempty(coarsePktOffset)
        coarsePktOffset = 0;
    end 
    
    % Extract L-STF and perform fine frequency offset correction
    lstf = rxWaveform(coarsePktOffset+(ind.LSTF(1):ind.LSTF(2)),:);
    coarseFreqOff = wlanCoarseCFOEstimate(lstf,chanBW);
    rxWaveform = helperFrequencyOffset(rxWaveform,fs,-coarseFreqOff);

    % Extract the non-HT fields and determine fine packet offset
    nonhtfields = rxWaveform(coarsePktOffset+(ind.LSTF(1):ind.LSIG(2)),:);
    finePktOffset = wlanSymbolTimingEstimate(nonhtfields,chanBW);

    % Determine final packet offset
    pktOffset = coarsePktOffset+finePktOffset; 

    % Extract L-LTF and perform fine frequency offset correction
    rxLLTF = rxWaveform(pktOffset+(ind.LLTF(1):ind.LLTF(2)),:);
    fineFreqOff = wlanFineCFOEstimate(rxLLTF,chanBW);
    rxWaveform = helperFrequencyOffset(rxWaveform,fs,-fineFreqOff);

    % HE-LTF demodulation and channel estimation
    rxHELTF = rxWaveform(pktOffset+(ind.HELTF(1):ind.HELTF(2)),:);
    heltfDemod = wlanHEDemodulate(rxHELTF,'HE-LTF',cfgHE);
    [chanEst,pilotEst] = heLTFChannelEstimate(heltfDemod,cfgHE);
                
    % Data demodulate
    rxData = rxWaveform(pktOffset+(ind.HEData(1):ind.HEData(2)),:);
    demodSym = wlanHEDemodulate(rxData,'HE-Data',cfgHE);

    % Pilot phase tracking
    demodSym = heCommonPhaseErrorTracking(demodSym,chanEst,cfgHE);

    % Estimate noise power in HE fields
    nVarEst = heNoiseEstimate(demodSym(ofdmInfo.PilotIndices,:,:),pilotEst,cfgHE);

    % Extract data subcarriers from demodulated symbols and channel estimate
    demodDataSym = demodSym(ofdmInfo.DataIndices,:,:);
    chanEstData = chanEst(ofdmInfo.DataIndices,:,:);

    % Equalization and STBC combining
    [eqDataSym,csi] = heEqualizeCombine(demodDataSym,chanEstData,nVarEst,cfgHE);

    % Set up the EVM plots and the EVM calculator at the beginning of the simulation
    if count == 1
        [~,~,~,EVMPerSubcarrier,EVMPerSymbol] = heSigRecSetupPlots(fs);
        EVMSymbolPlot = EVMPerSymbol;
        EVMSubcarrierPlot = EVMPerSubcarrier;
        EVMSymbolPlot.AxesScaling = 'Manual';
        EVMSubcarrierPlot.AxesScaling = 'Manual';
        EVMCalculator = comm.EVM;
        EVMCalculator.ReferenceSignalSource = 'Estimated from reference constellation';
        EVMCalculator.Normalization = 'Average constellation power';
        assignin('base','EVMPerSymbol',EVMSymbolPlot);
        assignin('base','EVMPerSubcarrier',EVMSubcarrierPlot); 
    end

    % Measure EVM of HE-Data symbols
    release(EVMCalculator);
    EVMCalculator.ReferenceConstellation = wlanReferenceSymbols(cfgHE);
    rmsEVMOverall = EVMCalculator(eqDataSym(:));

    % Plot EVM per symbol of the recovered HE data symbols
    EVMPerSymbol = hePlotEVMPerSymbol(eqDataSym,cfgHE,EVMSymbolPlot);
    
    % Set vertical limits so that the scope shows the range where the EVM
    % per symbol is plotted
    if length(EVMPerSymbol) > 1
        EVMSymbolPlot.YLimits = [min(EVMPerSymbol) max(EVMPerSymbol)];
    end

    % Plot EVM per subcarrier of the recovered HE data symbols
    EVMPerSUbcarrier = hePlotEVMPerSubcarrier(eqDataSym,cfgHE,EVMSubcarrierPlot);
    
    % Set vertical limits so that the scope shows the range where the EVM
    % per subcarrier is plotted
    EVMSubcarrierPlot.YLimits = [min(EVMPerSUbcarrier) max(EVMPerSUbcarrier)];
           
    % EVM measurements
    EVM = rmsEVMOverall;
    assignin('base','EVMrms',EVM);
    
    % Initialize the PDSCH symbols array
    dataSym = eqDataSym(:);
    
    % Recover data
    rxPSDU = wlanHEDataBitRecover(eqDataSym,nVarEst,csi,cfgHE,'LDPCDecodingMethod','layered-bp');

end