Main Content

Recovery Procedure for an 802.11be Packet

This example shows how to detect a packet and decode the payload bits in a received IEEE® 802.11be™ (Wi-Fi 7) waveform. The receiver recovers the packet format parameters from the preamble fields to decode the data field and the MAC frame.

Introduction

In an 802.11be packet, the L-SIG, U-SIG, and EHT-SIG preamble fields signal the transmission parameters to the receiver [1]:

  • The L-SIG field contains the transmission time of the packet.

  • The U-SIG field contains the parameters necessary to interpret an EHT PPDU.

  • The length information in the L-SIG field, in combination with the constellation of the second U-SIG symbol, determines the EHT packet format.

  • The EHT-SIG field provides additional signaling to the U-SIG field for stations (STAs) to interpret an EHT MU PPDU. The EHT-SIG field also contains the U-SIG overflow bits that are common to all users.

This example shows how to recover these transmission parameters from an EHT MU packet within a generated waveform. The example assumes knowledge of only the channel bandwidth. The receiver obtains the other transmission parameters from the decoded L-SIG, U-SIG, and EHT-SIG preamble fields. You then use these parameters to decode the EHT-Data field. You can use this example to perform the following analyses:

  • Recover and display the waveform of the detected packet.

  • Recover and display the spectrum of the detected packet.

  • Display the constellation of the equalized data symbols for all spatial streams.

  • Measure the error vector magnitude (EVM) of each field.

  • Detect an A-MPDU and determine the frame check sequence (FCS) of the MAC frame.

  • Display the EVM per data symbol and spatial stream averaged over subcarriers.

  • Display the EVM per data subcarrier and spatial stream averaged over symbols.

Waveform Generation

This example is capable of decoding both OFDMA and non-OFDMA EHT MU waveforms. For this example, you synthesize a non-OFDMA 802.11be EHT MU waveform. To synthesize an EHT MU waveform you create an EHT MU format configuration object wlanEHTMUConfig.The synthesized waveform is impaired by a 2x2 TGax indoor fading channel, additive white Gaussian noise, and carrier frequency offset.

Note that the wlanEHTMUConfig object is used at the transmitter side only. The receiver uses an EHT recovery configuration object wlanEHTRecoveryConfig. The receiver sets the unknown properties of the EHT recovery configuration object after decoding the information bits in the L-SIG, U-SIG, and EHT-SIG fields. The helperSigRecGenerateWaveform function generates the impaired waveform by:

  • Creating a random payload of MSDUs for the MAC frame, into an EHT MU packet

  • Passing the waveform through a TGax indoor fading channel model

  • Adding carrier frequency offset (CFO) and additive white Gaussian noise (AWGN) to the waveform

Alternatively, you can capture a waveform by using Instrument Control Toolbox(TM) to acquire I/Q data from a wide range of instruments and software-defined radio (SDR) platforms. If you capture an off-the-air waveform using an SDR, see the Recover and Analyze Packets in 802.11 Waveform example.

Define a non-OFDMA MU-MIMO configuration for an EHT MU packet and a channel bandwidth of 320 MHz. The configuration has two users that share a single resource unit (RU). The waveform to process is stored in the variable rxWaveform.

numUsers = 2;
cfgTx = wlanEHTMUConfig('CBW320','NumUsers',numUsers);
cfgTx.NumTransmitAntennas = 2;

userMCS = [4 6]; % MCS per user
for u = 1:numUsers
    cfgTx.User{u}.MCS = userMCS(u);
    cfgTx.User{u}.APEPLength = 10000;
    cfgTx.User{u}.NumSpaceTimeStreams = 1;
end

% Specify propagation channel
numRx = cfgTx.NumTransmitAntennas; % Number of receive antennas
delayProfile = 'Model-D'; % TGax channel delay profile

% Specify impairments
noisePower = -50; % Noise power to apply in dBW
cfo = 62e3; % Carrier frequency offset Hz

% Generate the waveform using a larger IFFT than required for the nominal
% baseband rate, resulting in an oversampled waveform
osf = 1; % Oversampling factor
% Generate waveform
rxWaveform = helperSigRecGenerateWaveform(cfgTx,numRx,delayProfile,noisePower,cfo,osf);

Packet Recovery

To recover a packet, you process the waveform by following these steps:

  1. Create an EHT recovery configuration object, wlanEHTRecoveryConfig. After decoding the preamble fields in the waveform, the receiver updates the object properties.

  2. Downsample the packet to baseband.

  3. Detect and synchronize the packet.

  4. Extract and demodulate the L-LTF. The demodulated L-LTF symbols do not include tone rotation for each 20 MHz subblock as described in [2], Section 21.3.7.5.

  5. Use the demodulated L-LTF symbols for channel and noise estimates.

  6. For EHT packet format detection, use the time-domain signal containing samples equivalent to the four OFDM symbols immediately following the L-LTF.

  7. Demodulate the L-LTF. The demodulated L-LTF symbols include tone rotation for each 20 MHz subblock as described in [2], Section 21.3.7.5. Use L-LTF channel estimates (with tone rotation) to decode the pre-EHT-LTF fields.

  8. Extract the L-SIG and RL-SIG fields. Estimate the channel on an extra four subcarriers per subchannel in the L-SIG and RL-SIG fields. Update the L-LTF channel estimates to include the channel estimates on the extra subcarriers.

  9. Determine the length of the packet in microseconds from the information bits in the L-SIG field.

  10. Update the recovery configuration object after decoding the U-SIG field. The common transmission parameters in the U-SIG field are necessary to interpret an EHT PPDU.

  11. Update the recovery configuration object after decoding the EHT-SIG common and user field. The EHT-SIG common field provides additional signaling to the U-SIG field which is common to all STAs. The EHT-SIG user field provides user-specific information for each STA.

  12. Create a cell array of wlanEHTRecoveryConfig objects. The wlanEHTRecoveryConfig object for each user in a cell array holds the user-specific information for each STA.

  13. Extract and demodulate the EHT-LTF field. Estimate the channel on the subcarriers allocated to the user of interest. Decode the EHT-Data field using MIMO channel estimates.

  14. Extract the EHT-Data field. Recover the PSDU bits using the wlanEHTRecoveryConfig object for each user.

  15. Detect the A-MPDU within the recovered PSDU and check the FCS for the recovered MAC frame.

Recovery Parameter Setup

To recover the received packet from the waveform, create an EHT recovery configuration object, wlanEHTRecoveryConfig. The recovery object stores the recovered information from the L-SIG, U-SIG, and EHT-SIG preamble fields. After decoding the preamble fields, the receiver updates the unknown properties of the object. The following code configures the object and variables for processing.

chanBW = cfgTx.ChannelBandwidth; % Assume channel bandwidth is known
sr = wlanSampleRate(cfgTx); % Baseband sample rate

% Specify pilot tracking method for recovering the data field. This can be:
%  'Joint' - use joint common phase error and sample rate offset tracking
%  'CPE' - use only common phase error tracking
% When recovering 26-tone RUs only CPE tracking is used as the joint tracking algorithm is susceptible to noise
pilotTracking = 'Joint';

% Create an EHT recovery configuration object and set the channel bandwidth
cfgRx = wlanEHTRecoveryConfig;
cfgRx.ChannelBandwidth = chanBW;

% The recovery configuration object is used to get the start and end indices of the pre-EHT-SIG field.
ind = wlanFieldIndices(cfgRx);

% Plots for the example
[spectrumAnalyzer,timeScope,ConstellationDiagram,EVMPerSubcarrier,EVMPerSymbol] = helperSigRecSetupPlots(sr);

% Minimum packet length is 10 OFDM symbols
lstfLength = double(ind.LSTF(2));
minPktLen = lstfLength*5; % Number of samples in L-STF

rxWaveLen = size(rxWaveform,1);

Downsampling

To process the physical layer of the waveform and take EVM measurements, downsample the oversampled waveform by using the resample function.

if osf>1
    % Resample the waveform to baseband for processing
    disp(['Resampling input waveform from ' num2str(sr*osf/1e6) ' MHz to ' num2str(sr/1e6) ' MHz']);
    rxWaveform = resample(rxWaveform,sr,sr*osf);
end

Front-End Processing

The front-end processing of the downsampled waveform uses a while loop for packet detection, coarse carrier frequency offset correction, timing synchronization, and fine carrier frequency offset correction. To detect a packet, the sample offset, searchOffset, indexes into rxWaveform. If synchronization fails for the first packet, the searchOffset is incremented to move beyond that packet. This process repeats until a packet is successfully synchronized.

searchOffset = 0; % Offset from start of waveform in samples
while (searchOffset + minPktLen) <= rxWaveLen
    % Packet detection
    pktOffset = wlanPacketDetect(rxWaveform,chanBW,searchOffset);

    % Adjust packet offset
    pktOffset = searchOffset + pktOffset;
    if isempty(pktOffset) || (pktOffset + ind.LSIG(2) > rxWaveLen)
        error('** No packet detected **');
    end

    % Coarse frequency offset estimation and correction using L-STF
    rxLSTF = rxWaveform(pktOffset+(ind.LSTF(1):ind.LSTF(2)), :);
    coarseFreqOffset = wlanCoarseCFOEstimate(rxLSTF,chanBW);
    rxWaveform = frequencyOffset(rxWaveform,sr,-coarseFreqOffset);

    % Symbol timing synchronization
    searchBufferLLTF = rxWaveform(pktOffset+(ind.LSTF(1):ind.LSIG(2)),:);
    pktOffset = pktOffset+wlanSymbolTimingEstimate(searchBufferLLTF,chanBW);

    % Fine frequency offset estimation and correction using L-STF
    rxLLTF = rxWaveform(pktOffset+(ind.LLTF(1):ind.LLTF(2)),:);
    fineFreqOffset = wlanFineCFOEstimate(rxLLTF,chanBW);
    rxWaveform = frequencyOffset(rxWaveform,sr,-fineFreqOffset);

    % Timing synchronization complete: packet detected
    disp(['Packet detected at index: ',num2str(pktOffset + 1)]);

    % Display estimated carrier frequency offset
    cfoCorrection = coarseFreqOffset + fineFreqOffset; % Total CFO
    disp(['Estimated CFO: ',num2str(round(cfoCorrection,1)),' Hz']);

    break; % Front-end processing complete, stop searching for a packet
end
Packet detected at index: 6409
Estimated CFO: 61998.4 Hz
% Scale the receive waveform based on L-STF power (AGC)
gain = 1./(sqrt(mean(rxLSTF.*conj(rxLSTF)))); 
rxWaveform = rxWaveform.*gain;

Packet Format Detection

To determine the packet format, the receiver uses the time-domain samples equivalent to the four OFDM symbols immediately following the L-LTF [1], Figure 36-80. Extract and demodulate the L-LTF. For format detection, the demodulated L-LTF symbols must not include tone rotation for each 20 MHz subblock as described in [2], Section 21.3.7.5. Use demodulated L-LTF symbols for channel and noise estimation. Detect the packet format using the L-LTF channel (without tone rotation) and noise power estimates.

rxLLTF = rxWaveform(pktOffset+(ind.LLTF(1):ind.LLTF(2)),:);
lltfDemod = wlanLLTFDemodulate(rxLLTF,chanBW);
lltfChanEst = wlanLLTFChannelEstimate(lltfDemod,chanBW);
noiseVar = wlanLLTFNoiseEstimate(lltfDemod);
disp('Detect packet format...');
Detect packet format...
rxSIG = rxWaveform(pktOffset+(ind.LSIG(1):ind.USIG(2)),:);
pktFormat = wlanFormatDetect(rxSIG,lltfChanEst,noiseVar,chanBW);
disp(['  Detected packet format: ',pktFormat]);
  Detected packet format: EHT-MU

L-LTF Channel Estimate

Demodulate the L-LTF and perform channel estimation. The demodulated L-LTF symbols include tone rotation for each 20 MHz segment as described in [2], Section 21.3.7.5. Use the L-LTF channel estimates (with tone rotation) to equalize and decode the pre-EHT-LTF fields.

lltfDemod = wlanEHTDemodulate(rxLLTF,'L-LTF',cfgRx);
lltfChanEst = wlanLLTFChannelEstimate(lltfDemod,chanBW);

L-SIG and RL-SIG Decoding

The L-SIG field determines the receive time, or RXTIME, of the packet. The receiver calculates RXTIME by using the length bits of the L-SIG payload. The receiver recovers the L-SIG and RL-SIG fields to estimate the channel at the extra subcarriers in the L-SIG and RL-SIG fields. It then updates the lltfChanEst channel estimates to include the channel estimates at the extra subcarriers in the L-SIG and RL-SIG fields. Using the estimates of the channel and the noise power from the L-LTF field, the receiver decodes the L-SIG payload.

After L-SIG decoding, update the L-SIG length property in the wlanEHTRecoveryConfig object

disp('Decoding L-SIG... ');
Decoding L-SIG... 
% Extract L-SIG and RL-SIG fields
rxLSIG = rxWaveform(pktOffset+(ind.LSIG(1):ind.RLSIG(2)),:);

% OFDM demodulate
lsigDemod = wlanEHTDemodulate(rxLSIG,'L-SIG',cfgRx);

% Estimate CPE and phase correct symbols
lsigDemod = wlanEHTTrackPilotError(lsigDemod,lltfChanEst,cfgRx,'L-SIG');

% Estimate channel on extra 4 subcarriers per subchannel and create full channel estimate
preEHTChanEst = wlanPreEHTChannelEstimate(lsigDemod,lltfChanEst,chanBW);

% Average L-SIG and RL-SIG before equalization
lsigDemod = mean(lsigDemod,2);

% Equalize data carrying subcarriers, merging 20 MHz subchannels
ofdmInfo = wlanEHTOFDMInfo('L-SIG',cfgRx);
[eqLSIGSym,csi] = wlanEHTEqualize(lsigDemod(ofdmInfo.DataIndices,:,:),preEHTChanEst(ofdmInfo.DataIndices,:,:),noiseVar,cfgRx,'L-SIG');

% Decode L-SIG field
[~,failCheck,lsigInfo] = wlanLSIGBitRecover(eqLSIGSym,noiseVar,csi);

if failCheck
    disp('  ** L-SIG check fail **');
else
    disp('  L-SIG check pass');
end
  L-SIG check pass
% Get the length information from the recovered L-SIG bits and update the
% L-SIG length property of the recovery configuration object
lsigLength = lsigInfo.Length;
cfgRx.LSIGLength = lsigLength;

% Measure EVM of L-SIG symbols
EVM = comm.EVM;
EVM.ReferenceSignalSource = 'Estimated from reference constellation';
EVM.Normalization = 'Average constellation power';
EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK');
rmsEVM = EVM(eqLSIGSym);
disp(['  L-SIG EVM: ',num2str(round(20*log10(rmsEVM/100),2)), ' dB']);
  L-SIG EVM: -63.77 dB
% Calculate the receive time and corresponding number of samples in the packet
RXTime = ceil((lsigLength + 3)/3) * 4 + 20; % In microseconds
numRxSamples = round(RXTime * 1e-6 * sr); % Number of samples in time
disp(['  RXTIME: ',num2str(RXTime), ' ',char(956) 's']);
  RXTIME: 188 μs
disp(['  Number of samples in the packet: ',num2str(numRxSamples)]);
  Number of samples in the packet: 60160

Given the RXTIME and corresponding number of samples within rxWaveform, plot and display the waveform and the spectrum of the detected packet.

sampleOffset = max((-lstfLength + pktOffset),1); % First index to plot
sampleSpan = numRxSamples + 2*lstfLength; % Number samples to plot
% Plot as much of the packet (and extra samples) as possible
plotIdx = sampleOffset:min(sampleOffset + sampleSpan,rxWaveLen);

% Configure timeScope to display the packet
timeScope.TimeSpan = sampleSpan/sr;
timeScope.TimeDisplayOffset = sampleOffset/sr;
timeScope.YLimits = [0 max(abs(rxWaveform(:)))];
timeScope(abs(rxWaveform(plotIdx,:)));
release(timeScope);

% Display the spectrum of the detected packet
spectrumAnalyzer(rxWaveform(pktOffset + (1:numRxSamples),:));
release(spectrumAnalyzer);

U-SIG Decoding

The U-SIG field contains the common transmission parameters of an EHT packet. Decode the U-SIG field using estimates of the channel and the noise power from the L-LTF field.

disp('Decoding U-SIG...')
Decoding U-SIG...
rxUSIG = rxWaveform(pktOffset+(ind.USIG(1):ind.USIG(2)),:);
usigDemod = wlanEHTDemodulate(rxUSIG,'U-SIG',cfgRx);
usigDemod = wlanEHTTrackPilotError(usigDemod,preEHTChanEst,cfgRx,'U-SIG');
    
% Equalize data-carrying subcarriers, merging 20 MHz subchannels within an
% 80 MHz subblock for diversity
ofdmInfo = wlanEHTOFDMInfo('U-SIG',cfgRx);
[eqUSIGSym,csi] = wlanEHTEqualize(usigDemod(ofdmInfo.DataIndices,:,:),preEHTChanEst(ofdmInfo.DataIndices,:,:),noiseVar,cfgRx,'U-SIG');
% Recover U-SIG bits
[rxUSIGBits,failCRC] = wlanUSIGBitRecover(eqUSIGSym,noiseVar,csi);

% Perform the CRC on U-SIG bits. It only fails if every 80 MHz subblock fails.
if all(failCRC)
    disp('  ** U-SIG CRC fail **');
else
    disp('   U-SIG CRC pass');
end
   U-SIG CRC pass

Measure the EVM of the U-SIG symbols.

release(EVM);
EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK');
rmsEVM = EVM(eqUSIGSym);
disp(['   U-SIG EVM: ',num2str(round(20*log10(mean(rmsEVM)/100),2)),' dB']);
   U-SIG EVM: -54.81 dB

Interpret the recovered U-SIG bits and update the wlanEHTRecoveryConfig object with them.

[cfgRx,failInterpretation] = interpretUSIGBits(cfgRx,rxUSIGBits,failCRC);
if failInterpretation
    disp('   ** U-SIG bit interpretation failure **');
    return
end

Display the common transmission configuration obtained from the U-SIG field for an EHT MU packet. The properties with value -1 are unknown or undefined. After successfully decoding the EHT-SIG field, the receiver updates the unknown user-related properties.

disp(cfgRx)
  wlanEHTRecoveryConfig with properties:

                ChannelBandwidth: 'CBW320'
                      LSIGLength: 123
                 CompressionMode: 2
                       EHTSIGMCS: 0
        NumEHTSIGSymbolsSignaled: 2
                 LDPCExtraSymbol: -1
             PreFECPaddingFactor: -1
                  PEDisambiguity: -1
                   GuardInterval: -1
                      EHTLTFType: -1
                NumEHTLTFSymbols: -1
                UplinkIndication: 0
                        BSSColor: 0
                    SpatialReuse: -1
                    TXOPDuration: -1
                NumNonOFDMAUsers: -1
       NumUsersPerContentChannel: -1
         RUTotalSpaceTimeStreams: -1
                          RUSize: -1
                         RUIndex: -1
      PuncturedChannelFieldValue: 0
                           STAID: -1
                             MCS: -1
                   ChannelCoding: unknown
             NumSpaceTimeStreams: -1
    SpaceTimeStreamStartingIndex: -1
                  Channelization: 1

   Read-only properties:
                        PPDUType: dl_mumimo
                      EHTDUPMode: 0

EHT-SIG Decoding

In an 802.11be packet, the EHT-SIG preamble fields signal the common and user parameters to the receiver. The receiver infers the user transmission parameters for both non-MU-MIMO and MU-MIMO transmission from the EHT-SIG user field as defined in [1], Tables 36-40 and 36-41.

Decode the EHT-SIG field using estimates of the channel and the noise power from the L-LTF field.

ind = wlanFieldIndices(cfgRx); % Update field indices
rxEHTSIG = rxWaveform(pktOffset+(double(ind.EHTSIG(1):ind.EHTSIG(2))),:);
ehtSigDemod = wlanEHTDemodulate(rxEHTSIG,'EHT-SIG',cfgRx);
ehtSigDemod = wlanEHTTrackPilotError(ehtSigDemod,preEHTChanEst,cfgRx,'EHT-SIG');
ofdmInfo = wlanEHTOFDMInfo('EHT-SIG',cfgRx);
    
% Equalize and merge subchannel within an 80 MHz subchannels
[eqSIGSym,csi] = wlanEHTEqualize(ehtSigDemod(ofdmInfo.DataIndices,:,:),preEHTChanEst(ofdmInfo.DataIndices,:,:),noiseVar,cfgRx,'EHT-SIG');

% Recover EHT-SIG common encoding block
[commonBits,failCRC,cfgRx] = wlanEHTSIGCommonBitRecover(eqSIGSym,noiseVar,csi,cfgRx);

disp('EHT-SIG decoding:')
EHT-SIG decoding:
disp('  Decoding EHT-SIG common field...');
  Decoding EHT-SIG common field...
if all(failCRC,'All')
    error('    CRC fails for all encoding blocks');
else
    if cfgRx.PPDUType==wlan.type.EHTPPDUType.ndp
        disp('    EHT sounding NDP, common encoding block CRC pass');
        disp(cfgRx)
        return
    elseif cfgRx.PPDUType==wlan.type.EHTPPDUType.dl_ofdma && any(failCRC,'All')
        error('    CRC fails for a content channel in an 80 MHz subblock');
    end
end
disp('    EHT-SIG (common field) CRC pass');
    EHT-SIG (common field) CRC pass
[userBits,failCRC,cfgUsers] = wlanEHTSIGUserBitRecover(eqSIGSym,noiseVar,csi,cfgRx);
disp('  Decoding EHT-SIG user field...');
  Decoding EHT-SIG user field...
if ~any(failCRC)
    disp('    EHT-SIG (user field) CRC pass');
    numUsers = numel(cfgUsers);
elseif all(failCRC)
    % Discard the packet if all users fail the CRC
    error('     ** EHT-SIG CRC fail for all users **');
else
    disp('   ** EHT-SIG CRC fail for at least one user **');
    % Only process users with valid CRC
    numUsers = numel(cfgUsers);
end
    EHT-SIG (user field) CRC pass
disp('  Recovered user parameters:')
  Recovered user parameters:
disp('  Display first user''s decoded parameters:')
  Display first user's decoded parameters:
disp(cfgUsers{1})
  wlanEHTRecoveryConfig with properties:

                ChannelBandwidth: 'CBW320'
                      LSIGLength: 123
                 CompressionMode: 2
                       EHTSIGMCS: 0
        NumEHTSIGSymbolsSignaled: 2
                 LDPCExtraSymbol: 0
             PreFECPaddingFactor: 4
                  PEDisambiguity: 0
                   GuardInterval: 3.2000
                      EHTLTFType: 4
                NumEHTLTFSymbols: 2
                UplinkIndication: 0
                        BSSColor: 0
                    SpatialReuse: 0
                    TXOPDuration: -1
                NumNonOFDMAUsers: 2
       NumUsersPerContentChannel: [1 1]
         RUTotalSpaceTimeStreams: 2
                          RUSize: 3984
                         RUIndex: 1
      PuncturedChannelFieldValue: 0
                           STAID: 0
                             MCS: 4
                   ChannelCoding: ldpc
             NumSpaceTimeStreams: 1
    SpaceTimeStreamStartingIndex: 1
                  Channelization: 1

   Read-only properties:
                        PPDUType: dl_mumimo
                      EHTDUPMode: 0

Data Decoding

Recover the PSDU bits for each user in the EHT-Data field with the updated wlanEHTRecoveryConfig object.

% The index for EHT-Data field is the same for all users
ind = wlanFieldIndices(cfgUsers{1});

disp('Decoding EHT-Data...');
Decoding EHT-Data...
cfgDataRec = trackingRecoveryConfig;
cfgDataRec.PilotTracking = pilotTracking;

for iu=1:numUsers
    % Get recovery configuration object for each user
    user = cfgUsers{iu};
    disp([' Decoding User: ',num2str(iu), ', STAID: ', num2str(user.STAID),', RUSize: ',num2str(user.RUSize)]);
    ofdmInfo = wlanEHTOFDMInfo('EHT-LTF',user);

    % Demodulate EHT-LTF and estimate channel
    rxEHTLTF = rxWaveform(pktOffset+(ind.EHTLTF(1):ind.EHTLTF(2)),:);
    ltfDemod = wlanEHTDemodulate(rxEHTLTF,'EHT-LTF',user);
    [chanEst,pilotEst] = wlanEHTLTFChannelEstimate(ltfDemod,user);

    % Number of expected data OFDM symbols
    symLen = ofdmInfo.FFTLength+ofdmInfo.CPLength;
    numOFDMSym = double((ind.EHTData(2)-ind.EHTData(1)+1))/symLen;

    % EHT-Data demodulation with pilot phase and timing tracking
    % Account for extra samples when extracting data field from the packet
    % for sample rate offset tracking. Extra samples may be required if the
    % receiver clock is significantly faster than the transmitter.
    maxSRO = 120; % Parts per million
    Ne = ceil(numRxSamples*maxSRO*1e-6); % Number of extra samples
    Ne = min(Ne,rxWaveLen-numRxSamples); % Limited to length of waveform
    numRxSamplesProcess = numRxSamples+Ne;
    rxData = rxWaveform(pktOffset+(ind.EHTData(1):numRxSamplesProcess),:);
    if user.RUSize==26
        % Force CPE only tracking for 26-tone RU as algorithm susceptible to noise
        cfgDataRec.PilotTracking = 'CPE';
    else
        cfgDataRec.PilotTracking = pilotTracking;
    end
    demodSym = helperTrackingOFDMDemodulate(rxData,chanEst,numOFDMSym,user,cfgDataRec);

    % Estimate noise power in EHT fields
    nVarEst = wlanEHTDataNoiseEstimate(demodSym(ofdmInfo.PilotIndices,:,:),pilotEst,user);

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

    % Equalize
    [eqSym,csi] = wlanEHTEqualize(demodDataSym,chanEstData,nVarEst,user,'EHT-Data');

    % Recover data field bits
    rxBits = wlanEHTDataBitRecover(eqSym,nVarEst,csi,user);

    % Decode MAC frames
    helperDecodeMACFrame(rxBits)

    % Plot equalized constellation of the recovered EHT data symbols for all spatial streams per user
    helperPlotEQConstellation(eqSym,user,ConstellationDiagram,iu,numUsers);

    % Measure EVM of EHT-Data symbols
    release(EVM);
    EVM.ReferenceConstellation = wlanReferenceSymbols(user);
    rmsEVM = EVM(eqSym(:));
    disp(['    EHT-Data EVM: ',num2str(round(20*log10(rmsEVM/100),2)),' dB']);
    
    % Plot EVM per symbol of the recovered EHT data symbols
    helperPlotEVMPerSymbol(eqSym,user,EVMPerSymbol,iu,numUsers);
    
    % Plot EVM per subcarrier of the recovered EHT data symbols
    helperPlotEVMPerSubcarrier(eqSym,user,EVMPerSubcarrier,iu,numUsers);
end
 Decoding User: 1, STAID: 0, RUSize: 3984
    A-MPDU deaggregation successful 
    Packet contents: A-MPDU
    FCS pass for MPDU:1
    FCS pass for MPDU:2
    FCS pass for MPDU:3
    FCS pass for MPDU:4
    FCS pass for MPDU:5
    EHT-Data EVM: -32.47 dB
 Decoding User: 2, STAID: 1, RUSize: 3984
    A-MPDU deaggregation successful 
    Packet contents: A-MPDU
    FCS pass for MPDU:1
    FCS pass for MPDU:2
    FCS pass for MPDU:3
    FCS pass for MPDU:4
    FCS pass for MPDU:5

    EHT-Data EVM: -33.2 dB

Related Topics

References

  1. IEEE P802.11be™/D4.0. Draft Standard for Information technology — Telecommunications and information exchange between systems Local and metropolitan area networks — Specific requirements. Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications. Amendment 8: Enhancements for extremely high throughput (EHT).

  2. IEEE Std 802.11™-2020 Standard for Information Technology — Telecommunications and Information Exchange between Systems — Local and Metropolitan Area Networks — Specific Requirements — Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications.