主要内容

Wi-Fi 8 Downlink Packet Error Rate Simulation Using Unequal Modulation

This example shows how to measure the packet error rate (PER) of a beamformed IEEE® 802.11bn™ ultra high reliability (UHR) single-user MIMO (SU-MIMO) link that uses unequal modulation (UEQM).

Introduction

Unequal modulation (UEQM) is a new feature introduced in Wi-Fi® 8, also referred to as 802.11bn UHR [1]. In a PPDU that uses UEQM, the uncoded bits sent across all spatial streams for a given user in the data field of the PPDU are jointly encoded. The resulting coded bits are then distributed among the spatial streams, with at least one stream using a different modulation order than the first spatial stream. Since higher modulation orders perform better at higher signal-to-noise ratios (SNRs) and beamforming causes different spatial streams to have different SNRs, UEQM is particularly well suited for use in beamforming scenarios [2]. The diagram below illustrates the default setup for simulating beamforming together with UEQM in this example.

This diagram illustrates the two-stage process of wireless data transmission using beamforming. First, the system sends a training sequence and analyzes it to determine the optimal transmission parameters (beamforming matrix). Next, the system uses these parameters for spatial mapping and efficiently transmission of actual data through the wireless channel, maximizing signal quality at the receiver.

Waveform Configuration

This example evaluates the PER of a beamformed Wi-Fi 8 SU-MIMO link that uses UEQM. To sound all subcarriers and estimate the channel without interpolation for this transmission configuration, use the 4x UHR-LTF compression mode. This example does not model subcarrier beamforming smoothing. This example also uses a doubled LDPC code length of 3888 to enhance the reliability. Additionally, you can configure this example to disable beamforming or UEQM.

useBeamforming = true;

NumTxAnts = 4;                                      % Number of transmit antennas
NumSTS = 2;                                         % Number of space-time streams
NumRxAnts = 2;                                      % Number of receive antennas

if useBeamforming
    spatialMapping = 'Custom';                      % Custom for beamforming
    Ng = 16;                                        % Subcarrier grouping for beamforming. Ng must be 1 (no grouping), 4, or 16.
else
    spatialMapping = 'Fourier'; %#ok<UNRCH>         % Fourier mapping for non-beamforming
end

chanBW = 'CBW20';                                   % Channel bandwidth
cfgUHRBase = uhrMUConfig(chanBW);
cfgUHRBase.NumTransmitAntennas = NumTxAnts;         % Number of transmit antennas
cfgUHRBase.GuardInterval = 3.2;                     % Guard interval duration
cfgUHRBase.UHRLTFType = 4;                          % UHR-LTF compression mode
cfgUHRBase.User{1}.NumSpaceTimeStreams = NumSTS;    % Number of space-time streams
cfgUHRBase.User{1}.APEPLength = 1e4;                % Payload length in bytes
cfgUHRBase.User{1}.ChannelCoding = 'ldpc2x';        % 2xLDPC Channel coding
cfgUHRBase.RU{1}.SpatialMapping = spatialMapping;   % Spatial mapping

To enable UEQM, you must set different modulation and coding scheme (MCS) values for each spatial stream and ensure that the coding rate is the same for all streams. For the example below, the first spatial stream uses 4096-QAM (MCS 13), while the second uses 1024-QAM (MCS 11). Both MCS 13 and MCS 11 have a coding rate of 5/6. The standard [1] specifies certain allowed combinations of modulation schemes, referred to as UEQMPattern. You can check the UEQM relevant information using the read-only properties of the uhrUser object. For equal modulation (EQM), since the same MCS applies to all spatial streams, specify the MCS as a scalar.

useUEQM = true;
if useUEQM
    % 1st SS - 4096 QAM
    % 2nd SS - 1024 QAM
    mcs = [13 11];
else
    mcs = 13; %#ok<UNRCH> 
end
cfgUHRBase.User{1}.MCS = mcs;                       % Modulation and coding scheme
disp(cfgUHRBase.User{1})
  uhrUser with properties:

              APEPLength: 10000
                     MCS: [13 11]
     NumSpaceTimeStreams: 2
           ChannelCoding: ldpc2x
                   STAID: 0
    NominalPacketPadding: 0
    PostFECPaddingSource: mt19937arwithseed
      PostFECPaddingSeed: 1

   Read-only properties:
                RUNumber: 1
                    UEQM: 1
              Modulation: ["4096QAM"    "1024QAM"]
              CodingRate: ["5/6"    "5/6"]
             UEQMPattern: 0

Beamforming Configuration

Transmit beamforming focuses energy toward a receiver to improve the SNR of a link. In this scheme, the transmitter is called a beamformer and the receiver is called a beamformee. The beamformer uses a steering matrix to direct the energy to the beamformee. The beamformer calculates the steering matrix using channel state information (CSI) obtained through channel measurements. These measurements are obtained by sounding the channel between beamformer and beamformee. To sound the channel, the beamformer sends a null data packet (NDP) to the beamformee. The beamformee measures the channel information during sounding to calculate a feedback matrix [3]. The process of forming the steering matrix is shown in the 802.11ac Transmit Beamforming example. This example uses a subcarrier grouping of 16 and assumes no CSI feedback compression. For more information on subcarrier grouping and CSI feedback compression, see the 802.11ax Compressed Beamforming Packet Error Rate Simulation example.

Configure the NDP transmission to have a data length of zero. Since the NDP is used to obtain the channel state information, set the number of space-time streams equal to the number of transmit antennas and directly map each space-time stream to a transmit antenna.

if useBeamforming
    cfgNDP = cfgUHRBase;
    cfgNDP.User{1}.APEPLength = 0;                     % NDP has no data
    cfgNDP.User{1}.NumSpaceTimeStreams = NumTxAnts;    % For feedback matrix calculation
    cfgNDP.User{1}.MCS = 0;                            % Set MCS to 0 to skip UEQM validation
    cfgNDP.RU{1}.SpatialMapping = 'Direct';            % Each TxAnt carries an STS

    if Ng>1
        % Subcarrier grouping
        indicesGrouping = helperCompressedBeamformingSubcarrierIndices(cfgNDP,Ng);
    end

    % Transmit null data packet and add trailing zeros to allow for channel delay
    ndpTxWaveform = [uhrWaveformGenerator([],cfgNDP); zeros(50,cfgNDP.NumTransmitAntennas)];

    indSound = uhrFieldIndices(cfgNDP);
end

Channel Configuration

This example uses a TGax NLOS indoor channel model with delay profile Model-B. For more information, see wlanTGaxChannel.

% Create and configure the TGax channel
tgaxChannel = wlanTGaxChannel;
tgaxChannel.DelayProfile = 'Model-B';
tgaxChannel.NumTransmitAntennas = NumTxAnts;
tgaxChannel.NumReceiveAntennas = NumRxAnts;
tgaxChannel.TransmitReceiveDistance = 5; % Distance in meters for NLOS
tgaxChannel.ChannelBandwidth = chanBW;
tgaxChannel.LargeScaleFadingEffect = 'None';
tgaxChannel.NormalizeChannelOutputs = false;
fs = wlanSampleRate(chanBW);
tgaxChannel.SampleRate = fs;

Simulation Parameters

Set the SNRs to simulate in dB.

if useBeamforming
    snr = 31:3:43;
else
    snr = 39:6:63; %#ok<UNRCH> 
end

if useUEQM
    snr = snr-3;     % Shift SNR values for UEQM scenarios
end

Limit the number of packets tested at each SNR point to maxNumErrors or maxNumPackets, where:

  • maxNumErrors is the maximum number of packet errors simulated at each SNR point. When the number of packet errors reaches this limit, the simulation at this SNR point is complete.

  • maxNumPackets is the maximum number of packets simulated at each SNR point and limits the length of the simulation if the packet error limit is not reached.

The numbers in this example result in a very short simulation. For statistically meaningful results, increase these numbers.

maxNumErrors = 10;   % The maximum number of packet errors at an SNR point
maxNumPackets = 100; % The maximum number of packets at an SNR point

SNR Point Processing

For each SNR point, test packets and calculate the PER. For each packet, perform these steps:

Obtain Steering Matrix to create Feedback Matrix

  1. Transmit an NDP waveform through an indoor TGax channel model. Model different channel realizations for different packets.

  2. Add AWGN to the received waveform to create the desired average SNR per active subcarrier after OFDM demodulation.

  3. Detect the packet at the beamformee.

  4. Estimate and correct for coarse carrier frequency offset (CFO).

  5. Establish fine timing synchronization.

  6. Estimate and correct for fine CFO.

  7. Extract the UHR-LTF from the synchronized received waveform. OFDM-demodulate the UHR-LTF and perform channel estimation.

  8. Perform singular value decomposition on the estimated channel at grouped subcarriers and calculate the beamforming feedback matrix, V.

Transmit Data Packet using Recovered Steering Matrix

  1. Use the V matrix calculated by the beamformee. Assume no beamforming feedback delay.

  2. Create and encode a PSDU to create a single-packet waveform with the steering matrix set to the beamforming feedback matrix, V.

  3. Pass the waveform through the same indoor TGax channel realization as the NDP transmission.

  4. Add AWGN to the received waveform.

Decode Beamformed Data Transmission to Recover PSDU

  1. As with NDP, perform synchronization and UHR channel estimation.

  2. Extract the data field from the synchronized received waveform and OFDM-demodulate.

  3. Perform common phase error pilot tracking to track any residual carrier frequency offset.

  4. Estimate the noise power using the demodulated data field pilots and single-stream channel estimate at pilot subcarriers.

  5. Equalize the phase-corrected OFDM symbols with the channel estimate.

  6. Demodulate and decode the equalized symbols to recover the PSDU.

To parallelize processing of SNR points, you can use a parfor loop. To enable the use of parallel computing for increased speed comment out the for statement and uncomment the parfor statement below.

numSNR = numel(snr); % Number of SNR points
packetErrorRate = zeros(1,numSNR);

% Get occupied subcarrier indices and OFDM parameters
ofdmInfo = uhrOFDMInfo('UHR-Data',cfgUHRBase);

% Indices to extract fields from the PPDU
ind = uhrFieldIndices(cfgUHRBase);

% PSDU length in bytes
psduLengthInBytes = psduLength(cfgUHRBase);

%parfor isnr = 1:numSNR % Use 'parfor' to speed up the simulation
for isnr = 1:numSNR
    % Set random substream index per iteration to ensure that each
    % iteration uses a repeatable set of random numbers
    stream = RandStream('combRecursive','Seed',99);
    stream.Substream = isnr;
    RandStream.setGlobalStream(stream);

    % Convert the SNR per active subcarrier to total SNR to account for
    % noise energy in null subcarriers
    snrValue = convertSNR(snr(isnr),"snrsc","snr",...
        FFTLength=ofdmInfo.FFTLength,...
        NumActiveSubcarriers=ofdmInfo.NumTones);

    % Create an instance of the UHR configuration object per SNR point
    % simulated. This enables you to use parfor.
    cfgUHR = cfgUHRBase;

    % Loop to simulate multiple packets
    numPacketErrors = 0;
    numPkt = 1; % Index of packet transmitted
    while numPacketErrors<=maxNumErrors && numPkt<=maxNumPackets
        % Pass through a TGax indoor fading channel
        reset(tgaxChannel); % Reset channel for different realization

        if useBeamforming
            % NDP transmission
            rx = tgaxChannel(ndpTxWaveform);

            % Pass the waveform through AWGN channel
            rx = awgn(rx,snrValue);

            % Calculate the steering matrix at the beamformee
            V = helperUserBeamformingFeedback(rx,cfgNDP,indSound,Ng);

            if isempty(V)
                % User feedback failed, packet error
                numPacketErrors = numPacketErrors+1;
                numPkt = numPkt+1;
                continue; % Go to next loop iteration
            end

            % Subcarrier interpolation
            if Ng>1
                steeringMat = interpolateSteeringMatrix(V,ofdmInfo.NumTones,indicesGrouping);
            else
                steeringMat = V; % No grouping
            end

            cfgUHR.RU{1}.SpatialMappingMatrix = steeringMat;
        end

        % Data packet transmission
        txPSDU = randi([0 1],psduLengthInBytes*8,1); % Generate random PSDU
        tx = uhrWaveformGenerator(txPSDU,cfgUHR);

        % Add trailing zeros to allow for channel delay
        txPad = [tx; zeros(50,cfgUHR.NumTransmitAntennas)];

        % Pass through a fading indoor TGax channel
        rx = tgaxChannel(txPad);

        % Pass the waveform through AWGN channel
        rx = awgn(rx,snrValue);

        % Packet detect and determine coarse packet offset
        coarsePktOffset = wlanPacketDetect(rx,chanBW);
        if isempty(coarsePktOffset) % If empty no L-STF detected; packet error
            numPacketErrors = numPacketErrors+1;
            numPkt = numPkt+1;
            continue; % Go to next loop iteration
        end

        % Extract L-STF and perform coarse frequency offset correction
        lstf = rx(coarsePktOffset+(ind.LSTF(1):ind.LSTF(2)),:);
        coarseFreqOff = wlanCoarseCFOEstimate(lstf,chanBW);
        rx = frequencyOffset(rx,fs,-coarseFreqOff);

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

        % Determine final packet offset
        pktOffset = coarsePktOffset+finePktOffset;

        % Register a packet error if packet detected outside
        % the range of expected delays from the channel modeling
        if pktOffset>50
            numPacketErrors = numPacketErrors+1;
            numPkt = numPkt+1;
            continue; % Go to next loop iteration
        end

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

        % UHR-LTF demodulation and channel estimation
        rxUHRLTF = rx(pktOffset+(ind.UHRLTF(1):ind.UHRLTF(2)),:);
        uhrltfDemod = uhrDemodulate(rxUHRLTF,'UHR-LTF',cfgUHR);
        [chanEst,pilotEst] = uhrLTFChannelEstimate(uhrltfDemod,cfgUHR);

        % Data demodulate
        rxData = rx(pktOffset+(ind.UHRData(1):ind.UHRData(2)),:);
        demodSym = uhrDemodulate(rxData,'UHR-Data',cfgUHR);

        % Pilot phase tracking
        % Average single-stream pilot estimates over symbols (2nd dimension)
        pilotEstTrack = mean(pilotEst,2);
        demodSym = uhrTrackPilotError(demodSym,pilotEstTrack,cfgUHR,'UHR-Data');

        % Estimate noise power in UHR fields
        nVarEst = uhrDataNoiseEstimate(demodSym(ofdmInfo.PilotIndices,:,:),pilotEstTrack,cfgUHR);

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

        % Equalization
        [eqDataSym,csi] = uhrEqualize(demodDataSym,chanEstData,nVarEst,cfgUHR,'UHR-Data');

        % Recover data
        rxPSDU = uhrDataBitRecover(eqDataSym,nVarEst,csi,cfgUHR);

        % Determine if any bits are in error, i.e. a packet error
        packetError = ~isequal(txPSDU,rxPSDU);
        numPacketErrors = numPacketErrors+packetError;
        numPkt = numPkt+1;
    end

    % Calculate packet error rate (PER) at SNR point
    packetErrorRate(:,isnr) = numPacketErrors/(numPkt-1);
    disp(['MCS ' num2str(cfgUHR.User{1}.MCS) ','...
        ' SNR ' num2str(snr(isnr)) ' dB'...
        ' completed after ' num2str(numPkt-1) ' packets,'...
        ' PER:' num2str(packetErrorRate(:,isnr))]);
end
MCS 13  11, SNR 28 dB completed after 11 packets, PER:1
MCS 13  11, SNR 31 dB completed after 12 packets, PER:0.91667
MCS 13  11, SNR 34 dB completed after 25 packets, PER:0.44
MCS 13  11, SNR 37 dB completed after 100 packets, PER:0.09
MCS 13  11, SNR 40 dB completed after 100 packets, PER:0

Packet Error Rate vs Signal to Noise Ratio

markers = 'ox*sd^v><ph+ox*sd^v><ph+';
figure;
semilogy(snr,packetErrorRate.',['-' markers(1)]);
hold on;
grid on;
xlabel('SNR (dB)');
ylabel('PER');
if isscalar(mcs)
    dataStr = sprintf('MCS %d',mcs);
else
    mcsStr = cell(1,NumSTS);
    for iNumSTSs = 1:NumSTS
        mcsStr{iNumSTSs} = sprintf('%d ',mcs(iNumSTSs));
    end
    dataStr = strjoin(['MCS', mcsStr]);
end
legend(dataStr,'Location','NorthEastOutside');
title(['PER (UHR MU), ' num2str(cfgUHRBase.ChannelBandwidth) ', Model-B, ' num2str(NumTxAnts) '-by-' num2str(NumRxAnts)]);

Figure contains an axes object. The axes object with title PER (UHR MU), CBW20, Model-B, 4-by-2, xlabel SNR (dB), ylabel PER contains an object of type line. This object represents MCS 13 11 .

Further Exploration

The number of packets tested at each SNR point is controlled by two parameters: maxNumErrors and maxNumPackets. For more meaningful results, increase the values that you used.

By running a longer simulation with maxNumErrors:1e2 and maxNumPackets:1e3, you can generate the figure below. It shows the PER performance of UEQM and EQM with different MCS combinations. Though the PER performance of UEQM is slightly worse than that of EQM for MCS 11, the overall system throughput can be higher because the high-SNR spatial stream can utilize a higher-order modulation scheme.

Using 4x UHR-LTF compression mode for NDP and data packet transmissions allows all subcarriers to be sounded and the channel to be estimated. When using 2x UHR-LTF compression mode, linear interpolation is performed during channel estimation. This example does not perform subcarrier beamforming smoothing. Therefore, if you configure the simulation to use 2x UHR-LTF compression, the interpolation performed during channel estimation not correctly estimate the beamforming matrix for all subcarriers and the PER increases.

Selected Bibliography

[1] IEEE P802.11bn™/D1.0. IEEE 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 6: Enhancements for ultra high reliability (UHR).

[2] Ron Porat etc, "Improved Tx Beamforming with UEQM," Accessed Aug 14th, 2025, https://mentor.ieee.org/802.11/dcn/24/11-24-0117-01-00bn-improved-tx-beamforming-with-ueqm.pptx.

[3] IEEE Std 802.11™-2024. IEEE 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.

See Also

Topics