> Generate standard-compliant IEEE 802.11 waveforms using MATLAB WLAN Toolbox. Use when creating WLAN waveforms, PPDU packets, or the transmit side of a VHT (802.11ac), HE-SU/HE-MU/HE-TB (802.11ax), EHT-MU/EHT-TB (802.11be), UHR-MU/UHR-TB/UHR-ELR (802.11bn). Handles single-user, MU-MIMO, OFDMA, trigger-based uplink, extended range, preamble puncturing, UEQM, and DRU. Use when asked to generate test waveforms, create packets with MAC frames, configure OFDMA resource units, build trigger-based uplink transmissions, target a specific transmit duration, or build multi-packet waveforms.
npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-generate-wlan-waveform
Generate standard-compliant IEEE 802.11 waveforms for device testing, link-level
simulation, or signal analysis. This skill covers the transmit chain: configure
the PHY format, size the payload, generate the time-domain IQ waveform, and plot.
UHR (802.11bn) requires R2026a or later. If the user requests a UHR waveform
and their release is older, inform them that UHR support was introduced in R2026a
and recommend upgrading.
Every waveform generation follows this pipeline:
wlanMACFramewlanWaveformGenerator(bits, cfg)showAllocation for HE/EHT/UHR configs| Standard | Marketing | Config Object | Users |
|----------|-----------|---------------|-------|
| 802.11b | Wi-Fi 1 | wlanNonHTConfig (DSSS) | SU only |
| 802.11a/g | Wi-Fi 1/3 | wlanNonHTConfig | SU only |
| 802.11n | Wi-Fi 4 | wlanHTConfig | SU only |
| 802.11ac | Wi-Fi 5 | wlanVHTConfig | SU or MU-MIMO |
| 802.11ax | Wi-Fi 6 | wlanHESUConfig | SU only |
| 802.11ax | Wi-Fi 6 | wlanHESUConfig (ExtendedRange) | SU — extended range |
| 802.11ax | Wi-Fi 6 | wlanHEMUConfig(allocIdx) | OFDMA and/or MU-MIMO |
| 802.11ax | Wi-Fi 6 | wlanHETBConfig | SU uplink (trigger-based) |
| 802.11be | Wi-Fi 7 | wlanEHTMUConfig(allocIdx) | OFDMA and/or MU-MIMO / MRU |
| 802.11be | Wi-Fi 7 | wlanEHTMUConfig("CBW...") | Non-OFDMA MU-MIMO (full-band RU) |
| 802.11be | Wi-Fi 7 | wlanEHTMUConfig("CBW...", EHTDUPMode=true) | SU — DUP mode (MCS 14 only) |
| 802.11be | Wi-Fi 7 | wlanEHTTBConfig | SU uplink (trigger-based) |
| 802.11bn | Wi-Fi 8 | uhrMUConfig(allocIdx) | OFDMA / MU-MIMO / UEQM (example helpers) |
| 802.11bn | Wi-Fi 8 | uhrMUConfig("CBW...") | Non-OFDMA MU-MIMO (example helpers) |
| 802.11bn | Wi-Fi 8 | uhrTBConfig | SU uplink / DRU (example helpers) |
| 802.11bn | Wi-Fi 8 | uhrELRConfig | SU enhanced long range (example helpers) |
For OFDMA formats (HE-MU, EHT-MU), the constructor takes allocation indices,
not RU sizes. See references/he-allocation-indices.md
and references/eht-allocation-indices.md.
UHR (802.11bn / Wi-Fi 8) uses example helper files, not built-in toolbox objects.
Copy helpers into the script's working folder with
setupExample("wlan/UHRParameterizationExample", scriptFolder). UHR supports
UEQM (per-stream MCS), DRU, LDPC2x, ELR (enhanced long range), and new MCS
values (15-23). Same allocation indices as EHT. See
references/uhr-waveform-generation.md.
See Critical Rules for format-specific constraints (allocation index schemes,
HT MCS encoding, DSSS properties).
EHT DUP mode duplicates the signal across subchannels for robust coverage.
Set at construction: wlanEHTMUConfig("CBW80", EHTDUPMode=true). Constraints:
MCS 14 (BPSK-DCM) only, single user, 1 spatial stream, no puncturing,
80/160/320 MHz. EHTDUPMode is read-only after construction.
Calculate payload size from target duration. All values are integer microseconds.
| Config | Function | Example |
|--------|----------|---------|
| wlanNonHTConfig | wlanPSDULength(cfg, 'TxTime', us) | cfg.PSDULength = wlanPSDULength(cfg, 'TxTime', 500); |
| wlanHTConfig | wlanPSDULength(cfg, 'TxTime', us) | cfg.PSDULength = wlanPSDULength(cfg, 'TxTime', 1000); |
| wlanVHTConfig (SU only) | wlanAPEPLength(cfg, 'TxTime', us) | cfg.APEPLength = wlanAPEPLength(cfg, 'TxTime', 2000); |
| wlanHESUConfig | wlanAPEPLength(cfg, 'TxTime', us) | cfg.APEPLength = wlanAPEPLength(cfg, 'TxTime', 3000); |
| wlanEHTMUConfig (SU non-OFDMA) | wlanAPEPLength(cfg, 'TxTime', us) | cfg.User{1}.APEPLength = wlanAPEPLength(cfg, 'TxTime', 1000); |
| Any MU/OFDMA config | Iterative transmitTime loop | See below — wlanAPEPLength errors on MU/OFDMA |
Duration argument is integer microseconds, not seconds. Pass 2000, not 2e-3.
For any MU config (homogeneous users — same MCS, RU size, and spatial streams):
targetDuration = 1e-3; apepLen = 2000; % initial guess
for iter = 1:10
for u = 1:numUsers, cfg.User{u}.APEPLength = apepLen; end
txTime = transmitTime(cfg);
if abs(txTime - targetDuration)/targetDuration < 0.01, break; end
apepLen = round(apepLen * targetDuration / txTime);
end
Heterogeneous users (different MCS/RU/STS): Lowest-capacity user sets duration.
Set per-user APEPLength based on traffic demand; use transmitTime(cfg).
The way to get PSDU length varies by format. Using the wrong pattern throws errors.
| Config | How to get PSDU length | Notes |
|--------|----------------------|-------|
| wlanNonHTConfig | cfg.PSDULength | Settable property |
| wlanHTConfig | cfg.PSDULength | Settable property |
| wlanVHTConfig | cfg.PSDULength | Read-only property (derived from APEPLength). Vector for MU. |
| wlanHESUConfig | getPSDULength(cfg) | Method call. Not a property. |
| wlanHEMUConfig | getPSDULength(cfg) | Method call. Returns vector (one per user). |
| wlanHETBConfig | getPSDULength(cfg) | Method call. Same as HE-SU/HE-MU. |
| wlanEHTMUConfig | psduLength(cfg) | Different method name from HE. Returns vector. |
| wlanEHTTBConfig | psduLength(cfg) | Same method name as EHT-MU. |
getPSDULength and psduLength are not interchangeable. HE uses
getPSDULength. EHT uses psduLength.
| Function | Purpose |
|----------|---------|
| wlanWaveformGenerator(bits, cfg) | Generate time-domain IQ waveform |
| wlanSampleRate(cfg) | Get sample rate for the configuration — always use this |
| wlanHETBConfig | Configure HE trigger-based uplink (single STA) |
| wlanEHTTBConfig | Configure EHT trigger-based uplink (single STA) |
| wlanMACFrame(payload, cfgMAC) | Generate MAC frame bits (see references/mac-frame-properties.md) |
| wlanAPEPLength(cfg, 'TxTime', us) | APEP length for target duration (VHT-SU, HE-SU, EHT-MU single-user) |
| wlanPSDULength(cfg, 'TxTime', us) | PSDU length for target duration (NonHT/HT) |
| transmitTime(cfg) or transmitTime(cfg, 'microseconds') | Get transmit time — use unit argument instead of * 1e6 |
| showAllocation(cfg) or showAllocation(cfg, ax) | Plot RU allocation — pass axes handle to embed in tiledlayout |
| ruInfo(cfg) | Query RU sizes, indices, user counts |
If you need to verify property names, check valid values for a config
object, or look up parameters not covered in this skill, consult the online
documentation links in references/documentation-links.md.
cfg = wlanVHTConfig;
cfg.ChannelBandwidth = 'CBW80';
cfg.MCS = 9;
cfg.NumTransmitAntennas = 4;
cfg.NumSpaceTimeStreams = 4;
cfg.SpatialMapping = 'Fourier';
% Size payload for 2 ms transmit time
cfg.APEPLength = wlanAPEPLength(cfg, 'TxTime', 2000);
% Generate waveform: 3 packets, 20 us idle
psduBits = randi([0 1], cfg.PSDULength * 8, 1);
waveform = wlanWaveformGenerator(psduBits, cfg, ...
'NumPackets', 3, 'IdleTime', 20e-6);
fs = wlanSampleRate(cfg);
cfg = wlanNonHTConfig;
cfg.Modulation = 'DSSS';
cfg.DataRate = '11Mbps'; % '1Mbps', '2Mbps', '5.5Mbps', or '11Mbps'
cfg.PSDULength = 1000;
psduBits = randi([0 1], cfg.PSDULength * 8, 1);
waveform = wlanWaveformGenerator(psduBits, cfg);
fs = wlanSampleRate(cfg); % 11 MHz (chip rate)
For OFDMA, the constructor takes allocation indices per 20 MHz subchannel.
Read references/he-allocation-indices.md for
the full index-to-RU mapping.
% 80 MHz, four 242-tone RUs (index 192 = one 242-tone RU per subchannel)
cfg = wlanHEMUConfig([192 192 192 192]);
cfg.NumTransmitAntennas = 4;
% Configure per-user parameters
for u = 1:4
cfg.User{u}.MCS = u + 6; % MCS 7, 8, 9, 10
cfg.User{u}.NumSpaceTimeStreams = 1;
cfg.User{u}.APEPLength = 4000;
cfg.User{u}.ChannelCoding = 'LDPC';
end
% Use Fourier spatial mapping when NumSTS < NumTransmitAntennas per RU
for r = 1:numel(cfg.RU)
cfg.RU{r}.SpatialMapping = 'Fourier';
end
% Generate PSDU bits per user
psduLen = getPSDULength(cfg);
txData = cell(1, numel(psduLen));
for u = 1:numel(psduLen)
txData{u} = randi([0 1], psduLen(u) * 8, 1);
end
waveform = wlanWaveformGenerator(txData, cfg);
showAllocation(cfg);
Common HE allocation indices (per 20 MHz subchannel):
| Index | RU Layout | Users |
|-------|-----------|-------|
| 0 | Nine 26-tone | 9 |
| 96 | Two 106-tone | 2 |
| 112 | Four 52-tone | 4 |
| 192 | One 242-tone | 1 |
| 193 | One 242-tone | 2 (MU-MIMO) |
| 200 | One 484-tone (40 MHz pair) | 1 |
| 208 | One 996-tone (80 MHz quad) | 1 |
For 40 MHz, provide 2 indices. For 80 MHz, provide 4. For 160 MHz, provide 8.
EHT allocation indices support Multi-Resource Units (MRU) — non-contiguous tone
blocks assigned to a single user. Read
references/eht-allocation-indices.md for
the full mapping.
% 80 MHz: 484+242 MRU on subchannels 1-3, 106+26+106 on subchannel 4
% Index 120 = 484+242 MRU (1 MU-MIMO user), 29/28 = continuation, 25 = 106+26+106
cfg = wlanEHTMUConfig([120 29 28 25]);
cfg.NumTransmitAntennas = 2;
% Set APEPLength appropriate to RU size (26-tone RUs have low throughput)
apepPerUser = [2000, 500, 100, 500]; % MRU, 106-tone, 26-tone, 106-tone
mcsPerUser = [7, 4, 2, 4];
for u = 1:numel(cfg.User)
cfg.User{u}.APEPLength = apepPerUser(u);
cfg.User{u}.MCS = mcsPerUser(u);
cfg.User{u}.NumSpaceTimeStreams = 1;
cfg.User{u}.ChannelCoding = 'LDPC';
end
for r = 1:numel(cfg.RU)
cfg.RU{r}.SpatialMapping = 'Fourier';
end
% EHT uses psduLength(), NOT getPSDULength()
psduLens = psduLength(cfg);
txData = cell(1, numel(psduLens));
for u = 1:numel(psduLens)
txData{u} = randi([0 1], psduLens(u) * 8, 1);
end
waveform = wlanWaveformGenerator(txData, cfg);
showAllocation(cfg);
EHT continuation indices: When an RU spans multiple 20 MHz subchannels, use
continuation indices for the additional subchannels:
cfg = wlanVHTConfig;
cfg.ChannelBandwidth = 'CBW80';
cfg.NumUsers = 2;
cfg.NumTransmitAntennas = 4;
cfg.NumSpaceTimeStreams = [2 2];
cfg.MCS = [8 8];
cfg.APEPLength = [1024 1024];
cfg.GroupID = 2; % MU-MIMO: must be 1-62
cfg.SpatialMapping = 'Fourier'; % Required when total STS < NumTxAntennas
psduLen = cfg.PSDULength; % Read-only vector for MU
txData = cell(1, cfg.NumUsers);
for u = 1:cfg.NumUsers
txData{u} = randi([0 1], psduLen(u) * 8, 1);
end
waveform = wlanWaveformGenerator(txData, cfg);
When the user requests MU-MIMO without OFDMA (all users share a single
full-bandwidth RU), use these patterns. **If the user says "MU-MIMO" without
mentioning OFDMA or multiple RUs, default to non-OFDMA.**
EHT — use the string constructor (no allocation indices needed):
% 80 MHz, 2 MU-MIMO users on a single 996-tone RU (non-OFDMA)
cfg = wlanEHTMUConfig("CBW80", NumUsers=2);
cfg.NumTransmitAntennas = 4;
cfg.User{1}.NumSpaceTimeStreams = 2;
cfg.User{1}.MCS = 9;
cfg.User{1}.APEPLength = 4000;
cfg.User{1}.ChannelCoding = 'LDPC';
cfg.User{2}.NumSpaceTimeStreams = 2;
cfg.User{2}.MCS = 7;
cfg.User{2}.APEPLength = 4000;
cfg.User{2}.ChannelCoding = 'LDPC';
cfg.RU{1}.SpatialMapping = 'Fourier';
psduLens = psduLength(cfg);
txData = cell(1, numel(psduLens));
for u = 1:numel(psduLens)
txData{u} = randi([0 1], psduLens(u) * 8, 1);
end
waveform = wlanWaveformGenerator(txData, cfg);
Valid bandwidths: "CBW20", "CBW40", "CBW80", "CBW160", "CBW320".
Up to 8 users. Supports puncturing via PuncturedChannelFieldValue.
HE — no string constructor; use full-band allocation indices:
| Bandwidth | Index for N users | Zero-user index |
|-----------|-------------------|-----------------|
| 20 MHz | 192 + N - 1 | N/A |
| 40 MHz | [200 + N - 1, 114] | 114 |
| 80 MHz | [208 + N - 1, 115, 115, 115] | 115 |
| 160 MHz | [216 + N - 1, 115, 115, 115, 115, 115, 115, 115] | 115 |
Follow the same per-user/per-RU pattern as EHT above, using getPSDULength(cfg)
instead of psduLength(cfg). Example: cfg = wlanHEMUConfig([209 115 115 115])
for 80 MHz with 2 users.
See references/mac-frame-properties.md for:
See references/multi-packet-waveforms.md for:
wlanMSDULengths (cell array of uint8 MSDUs)NumPackets, IdleTime) or mixed-formatconcatenation with SIFS/DIFS/PIFS spacing
Quick reference — inter-frame spacing: SIFS=16 μs, DIFS=34 μs, PIFS=25 μs.
See references/trigger-based-uplink.md for:
wlanHETBConfig), EHT TB (wlanEHTTBConfig), UHR TB (uhrTBConfig)RUSize/RUIndex from ruInfo(cfgMU), LTF symbols, OversamplingFactorshowAllocation(cfg).m file using thematlab-create-live-script skill format (%[text] markup, %% sections,
required appendix). Open it in the editor with edit('scriptName.m').
the script with setupExample. See
references/uhr-waveform-generation.md.
multi-user. wlanWaveformGenerator(bits, cfg) not wlanWaveformGenerator({bits}, cfg).
wlanSampleRate(cfg) — never hardcode. For UHR configs usewlanSampleRate(cfg.ChannelBandwidth) (UHR objects are not yet supported).
length (1→20, 2→40, 4→80, 8→160 MHz).
IdleTime in seconds (20e-6). Duration functions in integermicroseconds (2000). OversamplingFactor multiplies wlanSampleRate.
transmitTime(cfg, 'microseconds') — use the unit argument for display,
not * 1e6. Valid units: 'seconds', 'milliseconds', 'microseconds',
'nanoseconds'.
ruInfo(cfg) — after constructing anyOFDMA or MU-MIMO config, call ruInfo and check NumUsers, NumUsersPerRU,
and RUSizes match what was requested. Wrong allocation indices silently
produce wrong user counts.
tiledlayout/nexttile (not subplot).showAllocation(cfg, ax) embeds in existing layout.
These constraints cause the most errors. Check them before calling
wlanWaveformGenerator.
Using the wrong accessor throws "Undefined function" or silent wrong results.
| Format | How to get PSDU length | Wrong approach |
|--------|----------------------|---------------|
| Non-HT, HT | cfg.PSDULength (property) | getPSDULength(cfg) — errors |
| VHT | cfg.PSDULength (read-only) | Setting it — errors |
| HE-SU, HE-MU, HE-TB | getPSDULength(cfg) | psduLength(cfg) — errors |
| EHT-MU, EHT-TB | psduLength(cfg) | getPSDULength(cfg) — errors |
wlanHEMUConfig(242) is invalid. Use wlanHEMUConfig(192) for a
242-tone RU. wlanEHTMUConfig(242) is also invalid — use
wlanEHTMUConfig(64). Always consult the allocation index reference tables.
HE and EHT use completely different index schemes. A 242-tone RU is
index 192 for HE but index 64 for EHT. Never mix them.
HE-MU multi-subchannel RU indices signal users per content channel — see
references/he-allocation-indices.md.
| Goal | HE | EHT (OFDMA) | EHT (non-OFDMA) |
|------|-----|-------------|-----------------|
| Fully puncture subchannel | Allocation index 113 | Allocation index 26 | PuncturedChannelFieldValue at construction |
| Disable user data only | STAID=2046 | STAID=2046 | — |
STAID=2046 does not puncture — it only disables one user's data.
Non-OFDMA puncturing uses PuncturedChannelFieldValue (1–4 for 80 MHz,
mapping to subchannels 1–4). Must be set at construction:
wlanEHTMUConfig("CBW80", NumUsers=2, PuncturedChannelFieldValue=3)
NumSpaceTimeStreams < NumTransmitAntennas per RU → SpatialMapping = 'Fourier'
NumSpaceTimeStreams == NumTransmitAntennas → SpatialMapping = 'Direct'
Using 'Direct' when STS < antennas causes a dimension mismatch error.
When the user says "MU-MIMO" without mentioning OFDMA or multiple RUs,
default to non-OFDMA (single full-bandwidth RU shared by all users):
wlanEHTMUConfig("CBW80", NumUsers=N)TB config RUIndex values are **subcarrier-based positions from
ruInfo(cfgMU).RUIndices**, not sequential RU numbers. Using wrong
indices causes subcarrier overlap errors.
EHTDUPMode, PuncturedChannelFieldValue, and NumUsers on wlanEHTMUConfig
are read-only after construction — pass them as name-value pairs in the
constructor. See references/eht-allocation-indices.md
for the full list and examples.
| Constraint | Details |
|-----------|---------|
| HT MCS encodes streams | MCS 0-7 = 1 SS, 8-15 = 2 SS, 16-23 = 3 SS, 24-31 = 4 SS. Set NumSpaceTimeStreams = floor(MCS/8) + 1. |
| DSSS has no OFDM properties | Use DataRate ('1Mbps'...'11Mbps'). No ChannelBandwidth, MCS, NumTransmitAntennas, or NumSpaceTimeStreams. |
| HE ER + Upper106ToneRU | Restricts MCS to 0. The 242-tone ER variant allows MCS 0-2. |
| VHT GroupID | 0/63 = SU. 1-62 = MU-MIMO. Silently accepts wrong values. |
| wlanAPEPLength is SU-only | Works for VHT-SU, HE-SU, and EHT-MU single-user (non-OFDMA). Errors on any MU/OFDMA config — use iterative transmitTime loop. |
| Do not fabricate IEEE versions | Direct the user to the WLAN Toolbox Release Notes. |
----
Copyright 2026 The MathWorks, Inc.
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Use when implementing any feature or bugfix, before writing implementation code
Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
Expert guidance for systematic backtesting of trading strategies. Use when developing, testing, stress-testing, or validating quantitative trading strategies. Covers "beating ideas to death" methodology, parameter robustness testing, slippage modeling, bias prevention, and interpreting backtest results. Applicable when user asks about backtesting, strategy validation, robustness testing, avoiding overfitting, or systematic trading development.
Cloud laboratory platform for automated protein testing and validation. Use when designing proteins and needing experimental validation including binding assays, expression testing, thermostability measurements, enzyme activity assays, or protein sequence optimization. Also use for submitting experiments via API, tracking experiment status, downloading results, optimizing protein sequences for better expression using computational tools (NetSolP, SoluProt, SolubleMPNN, ESM), or managing protein design workflows with wet-lab validation.
This skill should be used for time series machine learning tasks including classification, regression, clustering, forecasting, anomaly detection, segmentation, and similarity search. Use when working with temporal data, sequential patterns, or time-indexed observations requiring specialized algorithms beyond standard ML approaches. Particularly suited for univariate and multivariate time series analysis with scikit-learn compatible APIs.
Take matlab/matlab-generate-wlan-waveform from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.