Recovery Procedure for an 802.11ac Packet
This example shows how to detect a packet and decode payload bits in a received IEEE® 802.11ac™ (Wi-Fi® 5) VHT waveform. The receiver recovers the packet format parameters from the preamble fields to decode the data.
Introduction
In a single-user 802.11ac packet, the L-SIG and VHT-SIG-A preamble fields signal the transmission parameters to the receiver [1]:
The L-SIG field contains information that allows the receiver to determine the transmission time of a packet.
The VHT-SIG-A field contains the transmission parameters, including the modulation and coding scheme, number of space-time streams, and channel coding.
This example generates a waveform, then detects and decodes a packet within it. The waveform contains a valid MAC frame with frame check sequence (FCS). Except for the channel bandwidth, the receiver does not know any of the transmission parameters. The receiver obtains the parameters by decoding the L-SIG and VHT-SIG-A preamble fields in the packet. The receiver then uses the retrieved transmission configuration to decode the VHT-SIG-B and VHT Data fields. Additionally, the example performs the following analysis:
Display the waveform of the received packet.
Display the spectrum of the detected packet.
Display the constellation of the equalized data symbols per spatial stream.
Measure the error vector magnitude (EVM) of each field.
Waveform Transmission
This example generates an 802.11ac VHT single-user waveform locally, but you can use a captured waveform. You can acquire I/Q data from a wide range of instruments using Instrument Control Toolbox™ and software-defined radio platforms.
The example impairs the locally generated waveform using a 3x3 TGac fading channel, additive white Gaussian noise, and carrier frequency offset. To generate a waveform locally, configure a wlanVHTConfig
object. Only the transmitter side uses this VHT configuration object. The receiver creates another VHT configuration object when it decodes the packet. The vhtSigRecGenerateWaveform helper function generates the impaired waveform locally. The processing steps within the helper function are:
Generate and encode a valid MAC frame into a VHT waveform.
Pass the waveform through a TGac fading channel model.
Add carrier frequency offset to the waveform.
Add additive white Gaussian noise to the waveform.
% VHT link parameters cfgVHTTx = wlanVHTConfig( ... ChannelBandwidth='CBW80', ... NumTransmitAntennas=3, ... NumSpaceTimeStreams=2, ... SpatialMapping='Hadamard', ... STBC=true, ... MCS=5, ... GuardInterval='Long', ... APEPLength=1052); % Propagation channel numRx = 3; % Number of receive antennas delayProfile = 'Model-C'; % TGac channel delay profile % Impairments noisePower = -30; % Noise power to apply in dBW cfo = 62e3; % Carrier frequency offset (Hz) % Generated waveform parameters numTxPkt = 1; % Number of transmitted packets idleTime = 20e-6; % Idle time before and after each packet % Generate waveform rx = vhtSigRecGenerateWaveform(cfgVHTTx, numRx, ... delayProfile, noisePower, cfo, numTxPkt, idleTime);
Packet Recovery
The examples stores the signal in the variable rx
. The processing steps to recover a packet are:
Detect and synchronize the packet.
Detect the packet format.
Extract the L-SIG field and recover its information bits to determine the length of the packet in microseconds.
Extract the VHT-SIG-A field and recover its information bits.
Retrieve the packet format parameters from the decoded L-SIG and VHT-SIG-A bits.
Extract the VHT-LTF field to perform MIMO channel estimation for decoding the VHT-SIG-B and VHT Data fields.
Extract the VHT-SIG-B field and recover its information bits.
Extract the VHT-Data field and recover the PSDU and VHT-SIG-B cyclic redundancy check (CRC) bits using the retrieved packet parameters.
The start and end indices for some preamble fields depend on the channel bandwidth, but are independent of all other transmission parameters. To calculate these indices, use a default transmission configuration object with the channel bandwidth you originally specified.
cfgVHTRx = wlanVHTConfig(ChannelBandwidth=cfgVHTTx.ChannelBandwidth); idxLSTF = wlanFieldIndices(cfgVHTRx,'L-STF'); idxLLTF = wlanFieldIndices(cfgVHTRx,'L-LTF'); idxLSIG = wlanFieldIndices(cfgVHTRx,'L-SIG'); idxSIGA = wlanFieldIndices(cfgVHTRx,'VHT-SIG-A');
Configure objects and variables for processing.
chanBW = cfgVHTTx.ChannelBandwidth; sr = wlanSampleRate(cfgVHTTx); % Set up plots for example [spectrumAnalyzer, timeScope, constellationDiagram] = vhtSigRecSetupPlots(sr); % Minimum packet length is 10 OFDM symbols lstfLen = double(idxLSTF(2)); % Number of samples in L-STF minPktLen = lstfLen*5; rxWaveLen = size(rx, 1);
Front-End Processing
The front-end processing consists of packet detection, coarse carrier frequency offset correction, timing synchronization and fine carrier frequency offset correction. The example uses a while loop to detect and synchronize a packet within the received waveform. To detect a packet, use the sample offset searchOffset
to index elements within the array rx
. Detect and process the first packet within rx
. If the synchronization fails for the detected packet, the example increments the sample index offset searchOffset
to move beyond the processed packet in rx
. This process repeats until the example successfully detects and synchronizes a packet.
searchOffset = 0; % Offset from start of waveform in samples while (searchOffset + minPktLen) <= rxWaveLen % Packet detection pktOffset = wlanPacketDetect(rx, chanBW, searchOffset); % Adjust packet offset pktOffset = searchOffset + pktOffset; if isempty(pktOffset) || (pktOffset + idxLSIG(2) > rxWaveLen) error('** No packet detected **'); end % Coarse frequency offset estimation using L-STF LSTF = rx(pktOffset + (idxLSTF(1):idxLSTF(2)), :); coarseFreqOffset = wlanCoarseCFOEstimate(LSTF, chanBW); % Coarse frequency offset compensation rx = frequencyOffset(rx,sr,-coarseFreqOffset); % Symbol timing synchronization LLTFSearchBuffer = rx(pktOffset+(idxLSTF(1):idxLSIG(2)),:); pktOffset = pktOffset+wlanSymbolTimingEstimate(LLTFSearchBuffer,chanBW); if (pktOffset + minPktLen) > rxWaveLen fprintf('** Not enough samples to recover packet **\n\n'); break; end % Timing synchronization complete: packet detected fprintf('Packet detected at index %d\n\n', pktOffset + 1); % Fine frequency offset estimation using L-LTF LLTF = rx(pktOffset + (idxLLTF(1):idxLLTF(2)), :); fineFreqOffset = wlanFineCFOEstimate(LLTF, chanBW); % Fine frequency offset compensation rx = frequencyOffset(rx, sr, -fineFreqOffset); % Display estimated carrier frequency offset cfoCorrection = coarseFreqOffset + fineFreqOffset; % Total CFO fprintf('Estimated CFO: %5.1f Hz\n\n', cfoCorrection); break; % Front-end processing complete, stop searching for a packet end
Packet detected at index 1600
Estimated CFO: 61954.3 Hz
Format Detection
To detect the format of the packet, use the three OFDM symbols that immediately follow the L-LTF. This requires estimates of the channel and noise power from the L-LTF.
% Channel estimation using L-LTF LLTF = rx(pktOffset + (idxLLTF(1):idxLLTF(2)), :); demodLLTF = wlanLLTFDemodulate(LLTF, chanBW); chanEstLLTF = wlanLLTFChannelEstimate(demodLLTF, chanBW); % Estimate noise power in non-HT fields noiseVarNonHT = wlanLLTFNoiseEstimate(demodLLTF); % Detect the format of the packet fmt = wlanFormatDetect(rx(pktOffset + (idxLSIG(1):idxSIGA(2)), :), ... chanEstLLTF, noiseVarNonHT, chanBW); disp([fmt ' format detected']);
VHT format detected
if ~strcmp(fmt,'VHT') error('** A format other than VHT has been detected **'); end
L-SIG Decoding
VHT transmissions use the L-SIG field to determine the receive time, or RXTIME, of the packet. The field bits of the L-SIG payload determine RXTIME via Equation 22-105 in [1]. The receiver uses RXTIME to calculate the number of samples that contain the packet within rx
. The example decodes the L-SIG payload using the estimates of the channel and noise power you obtained from the L-LTF.
% Recover L-SIG field bits disp('Decoding L-SIG... ');
Decoding L-SIG...
[rxLSIGBits, failCheck, eqLSIGSym] = wlanLSIGRecover(rx(pktOffset + (idxLSIG(1):idxLSIG(2)), :), ... chanEstLLTF, noiseVarNonHT, chanBW); if failCheck % Skip L-STF length of samples and continue searching disp('** L-SIG check fail **'); else disp('L-SIG check pass'); end
L-SIG check pass
% Measure EVM of L-SIG symbol EVM = comm.EVM; EVM.ReferenceSignalSource = 'Estimated from reference constellation'; EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK'); rmsEVM = EVM(eqLSIGSym); fprintf('L-SIG EVM: %2.2f%% RMS\n', rmsEVM);
L-SIG EVM: 1.83% RMS
% Calculate the receive time and corresponding number of samples in the % packet lengthBits = rxLSIGBits(6:17); RXTime = ceil((bit2int(double(lengthBits),12,false) + 3)/3) * 4 + 20; % us numRxSamples = RXTime * 1e-6 * sr; % Number of samples in receive time fprintf('RXTIME: %dus\n', RXTime);
RXTIME: 84us
fprintf('Number of samples in packet: %d\n\n', numRxSamples);
Number of samples in packet: 6720
Display the waveform and spectrum of the detected packet within rx
for the calculated RXTIME and corresponding number of samples.
sampleOffset = max((-lstfLen + pktOffset), 1); % First index to plot sampleSpan = numRxSamples + 2*lstfLen; % Number of 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(rx(:)))]; timeScope(abs(rx(plotIdx ,:)));
% Display the spectrum of the detected packet
spectrumAnalyzer(rx(pktOffset + (1:numRxSamples), :));
VHT-SIG-A Decoding
The VHT-SIG-A field contains the transmission configuration of the packet. To recover the VHT-SIG-A bits, use the channel and noise power estimates you obtained from the L-LTF.
% Recover VHT-SIG-A field bits disp('Decoding VHT-SIG-A... ');
Decoding VHT-SIG-A...
[rxSIGABits, failCRC, eqSIGASym] = wlanVHTSIGARecover(rx(pktOffset + (idxSIGA(1):idxSIGA(2)), :), ... chanEstLLTF, noiseVarNonHT, chanBW); if failCRC disp('** VHT-SIG-A CRC fail **'); else disp('VHT-SIG-A CRC pass'); end
VHT-SIG-A CRC pass
% Measure EVM of VHT-SIG-A symbols for BPSK and QBPSK modulation schemes release(EVM); EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK'); rmsEVMSym1 = EVM(eqSIGASym(:,1)); release(EVM); EVM.ReferenceConstellation = wlanReferenceSymbols('QBPSK'); rmsEVMSym2 = EVM(eqSIGASym(:,2)); fprintf('VHT-SIG-A EVM: %2.2f%% RMS\n', mean([rmsEVMSym1 rmsEVMSym2]));
VHT-SIG-A EVM: 2.06% RMS
The helperVHTConfigRecover helper function returns a VHT format configuration object, cfgVHTRx
, based on the recovered VHT-SIG-A and L-SIG bits. The helper function sets properties that are not required to decode the waveform to their default values for a wlanVHTConfig
object. Therefore, these property values may differ from the corresponding values in cfgVHTTx
. Examples of such properties include NumTransmitAntennas
and SpatialMapping
.
% Create a VHT format configuration object by retrieving packet parameters % from the decoded L-SIG and VHT-SIG-A bits cfgVHTRx = helperVHTConfigRecover(rxLSIGBits, rxSIGABits); % Display the transmission configuration obtained from VHT-SIG-A vhtSigRecDisplaySIGAInfo(cfgVHTRx);
Decoded VHT-SIG-A contents: ChannelBandwidth: 'CBW80' NumSpaceTimeStreams: 2 STBC: 1 MCS: 5 ChannelCoding: {'BCC'} GuardInterval: 'Long' GroupID: 63 PartialAID: 275 Beamforming: 0 PSDULength: 1167
The information in the VHT-SIG-A field enables the receiver to calculate the location of subsequent fields within the received waveform.
% Obtain starting and ending indices for VHT-LTF and VHT-Data fields % using retrieved packet parameters idxVHTLTF = wlanFieldIndices(cfgVHTRx, 'VHT-LTF'); idxVHTSIGB = wlanFieldIndices(cfgVHTRx, 'VHT-SIG-B'); idxVHTData = wlanFieldIndices(cfgVHTRx, 'VHT-Data'); % Warn if waveform does not contain whole packet if (pktOffset + double(idxVHTData(2))) > rxWaveLen fprintf('** Not enough samples to recover entire packet **\n\n'); end
VHT-SIG-B Decoding
The primary use of the VHT-SIG-B field is signaling user information in a multi-user packet. In a single-user packet, the VHT-SIG-B field carries the length of the packet. As this example has shown, the receiver can also calculate the length of the packet using the L-SIG and VHT-SIG-A fields. Despite not being required to decode a single-user packet, the example recovers the VHT-SIG-B field and interprets its bits. The example demodulates the VHT-SIG-B symbols using a MIMO channel estimate it obtains from the VHT-LTF. Note the CRC for the VHT-SIG-B field is carried in the VHT Data field.
% Estimate MIMO channel using VHT-LTF and retrieved packet parameters
demodVHTLTF = wlanVHTLTFDemodulate(rx(pktOffset + (idxVHTLTF(1):idxVHTLTF(2)), :), cfgVHTRx);
[chanEstVHTLTF, chanEstSSPilots] = wlanVHTLTFChannelEstimate(demodVHTLTF, cfgVHTRx);
The L-LTF OFDM demodulator normalizes the output by the number of subcarriers. The VHT-SIG-B OFDM demodulator normalizes the output by the number of subcarriers and space-time streams. Therefore, estimate the noise power in VHT-SIG-B by scaling the L-LTF noise estimate by the ratio of the number of subcarriers in both fields, and the number of space-time streams.
numSTSTotal = sum(cfgVHTRx.NumSpaceTimeStreams, 1); scalingFactor = (height(demodVHTLTF)/size(demodLLTF, 1))*numSTSTotal; noiseVarVHT = noiseVarNonHT*scalingFactor; % VHT-SIG-B Recover disp('Decoding VHT-SIG-B...');
Decoding VHT-SIG-B...
[rxSIGBBits, eqSIGBSym] = wlanVHTSIGBRecover(rx(pktOffset + (idxVHTSIGB(1):idxVHTSIGB(2)),:), ... chanEstVHTLTF, noiseVarVHT, chanBW); % Measure EVM of VHT-SIG-B symbol release(EVM); EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK'); rmsEVM = EVM(eqSIGBSym); fprintf('VHT-SIG-B EVM: %2.2f%% RMS\n', rmsEVM);
VHT-SIG-B EVM: 5.21% RMS
% Interpret VHT-SIG-B bits to recover the APEP length (rounded up to a % multiple of four bytes) and generate reference CRC bits [refSIGBCRC, sigbAPEPLength] = helperInterpretSIGB(rxSIGBBits, chanBW, true); disp('Decoded VHT-SIG-B contents: ');
Decoded VHT-SIG-B contents:
fprintf(' APEP Length (rounded up to 4 byte multiple): %d bytes\n\n', sigbAPEPLength);
APEP Length (rounded up to 4 byte multiple): 1052 bytes
VHT Data Decoding
Use the reconstructed VHT configuration object can to recover the VHT Data field. This includes the VHT-SIG-B CRC bits and PSDU.
Then, analyze the recovered VHT data symbols as required. This example displays the equalized constellation of the recovered VHT data symbols per spatial stream.
% Extract VHT Data samples from the waveform vhtdata = rx(pktOffset + (idxVHTData(1):idxVHTData(2)), :); % Estimate the noise power in VHT data field noiseVarVHT = vhtNoiseEstimate(vhtdata, chanEstSSPilots, cfgVHTRx); % Recover PSDU bits using retrieved packet parameters and channel % estimates from VHT-LTF disp('Decoding VHT Data field...');
Decoding VHT Data field...
[rxPSDU, rxSIGBCRC, eqDataSym] = wlanVHTDataRecover(vhtdata, chanEstVHTLTF, noiseVarVHT, cfgVHTRx, ... LDPCDecodingMethod='norm-min-sum', EarlyTermination=true); % Plot equalized constellation for each spatial stream refConst = wlanReferenceSymbols(cfgVHTRx); [Nsd, Nsym, Nss] = size(eqDataSym); eqDataSymPerSS = reshape(eqDataSym, Nsd*Nsym, Nss); for iss = 1:Nss constellationDiagram{iss}.ReferenceConstellation = refConst; constellationDiagram{iss}(eqDataSymPerSS(:, iss)); end
% Measure EVM of VHT-Data symbols release(EVM); EVM.ReferenceConstellation = refConst; rmsEVM = EVM(eqDataSym(:)); fprintf('VHT-Data EVM: %2.2f%% RMS\n', rmsEVM);
VHT-Data EVM: 4.68% RMS
To determine whether the VHT-SIG-B and VHT data service bits have been recovered successfully, compare the CRC bits for the VHT-SIG-B field to the locally generated reference .
% Test VHT-SIG-B CRC from service bits within VHT Data against % reference calculated with VHT-SIG-B bits if ~isequal(refSIGBCRC, rxSIGBCRC) disp('** VHT-SIG-B CRC fail **'); else disp('VHT-SIG-B CRC pass'); end
VHT-SIG-B CRC pass
The recovered PSDU contains an A-MPDU. Extract the MPDUs from the A-MPDU.
mpduList = wlanAMPDUDeaggregate(rxPSDU, cfgVHTRx);
fprintf('Number of MPDUs present in the A-MPDU: %d\n', numel(mpduList));
Number of MPDUs present in the A-MPDU: 1
The mpduList
contains the deaggregated list of MPDUs. Decode the MPDU and validate the FCS of each MPDU.
for i = 1:numel(mpduList) [macCfg, payload, decodeStatus] = wlanMPDUDecode(mpduList{i}, cfgVHTRx, ... DataFormat='octets'); if strcmp(decodeStatus, 'FCSFailed') fprintf('** FCS failed for MPDU-%d **\n', i); else fprintf('FCS passed for MPDU-%d\n', i); end end
FCS passed for MPDU-1
Selected Bibliography
IEEE Std 802.11™-2020. 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
wlanVHTConfig
| wlanVHTLTFDemodulate
| wlanVHTLTFChannelEstimate