Matlab Generate 5g Waveform
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Software development
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to generating standard-compliant 5G New Radio (NR) baseband waveforms using the nrWaveformGenerator function. It covers the configuration of both downlink and uplink channels, including PDSCH, PUSCH, PDCCH, and various reference signals. The workflow emphasizes using simplified constructors for standard configurations while providing guidance for manual adjustments in complex scenarios like multi-bandwidth-part or multi-numerology layouts. It is designed for engineers performing conformance testing, RF instrument playback, or IQ baseband synthesis.
What it does
- Generates 3GPP-compliant 5G NR downlink and uplink waveforms.
- Configures data, control, and broadcast channels including PDSCH, PUSCH, PDCCH, and PUCCH.
- Supports complex setups like multi-bandwidth-part and multi-numerology configurations.
- Provides methods for creating standard test models (TM) and fixed reference channels (FRC).
- Handles channel multiplexing, power scaling, and OFDM modulation automatically.
- Enables visualization of resource grids for verification.
When to use it
- When you need to generate 5G NR signals for test and measurement or simulation.
- When creating test vectors for conformance testing.
- When you need to configure specific bandwidth, subcarrier spacing, or modulation parameters.
- When you need to generate standard-compliant test model (TM) or fixed reference channel (FRC) waveforms.
Advantages
- Ensures 3GPP compliance through standardized configuration objects.
- Simplifies complex waveform generation with automated constructor defaults.
- Provides a consistent API for both simple and advanced multi-carrier layouts.
- Reduces configuration errors by separating primitive signal processing from waveform construction.
Usage examples
- “Generate a default 5G NR downlink waveform for a 20 MHz channel with 30 kHz subcarrier spacing.”
- The agent creates a configuration object using nrDLCarrierConfig('FR1', 20, 30), generates the waveform with nrWaveformGenerator, and displays the resource grid.
- “Create a 5G NR test model TM1.1 waveform.”
- The agent uses the hNRReferenceWaveformGenerator helper to set up the TM1.1 configuration, generates the waveform, and provides the resource grid information.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/matlab/matlab-generate-5g-waveform/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-generate-5g-waveform.zip -d .agents/skills
Documentation by MathWorks
Generate 5G NR Waveforms
Generate standard-compliant 5G NR downlink and uplink waveforms for test and
measurement, simulation, and verification using nrWaveformGenerator.
When to Use
Generate a 5G, NR, or New Radio waveform (DL: PDSCH, PDCCH, SSBurst, CSI-RS; UL: PUSCH, PUCCH, SRS)
Generate NR test model (TM) or fixed reference channel (FRC) waveforms
Configure bandwidth, SCS, modulation, power, or multi-bandwidth-part layouts
When Not to Use
Channel modeling or propagation — use
nrCDLChannel,nrTDLChannelReceiver processing or decoding — use
nrPDSCHDecode,nrDLSCHDecoderLink-level simulation end-to-end
API Choice
| Need | API |
|---|---|
| Custom DL waveform | nrDLCarrierConfig + nrWaveformGenerator |
| Custom UL waveform | nrULCarrierConfig + nrWaveformGenerator |
| Standard test model (TM) or FRC | hNRReferenceWaveformGenerator |
Do not use primitive-level functions (nrCarrierConfig + nrPDSCH +
nrOFDMModulate) for waveform generation, and do not mix primitive config
objects (nrPDSCHConfig, nrPUSCHConfig, nrCarrierConfig) with
nrWaveformGenerator — use the nrWavegen* objects. nrWaveformGenerator
handles channel multiplexing, power scaling, and OFDM modulation correctly.
Full function catalog, property names, and the incompatible-object table:
references/api-reference.md.
Core Workflow (custom DL/UL)
Create the carrier config with the simplified constructor (R2026a+), which auto-sizes SCSCarriers, BandwidthParts, SSBurst/CORESET (DL), and a default PDSCH/PUSCH to the bandwidth:
cfg = nrDLCarrierConfig('FR1', 20, 30); % DL: FR1, 20 MHz, 30 kHz SCS
cfg = nrULCarrierConfig('FR1', 20, 15); % UL: FR1, 20 MHz, 15 kHz SCSFor DL, if the requested SCS differs from the default SSB numerology the
constructor adds a dedicated SSB SCS carrier (e.g. nrDLCarrierConfig('FR1', 5, 30)
adds a hidden 15 kHz carrier). Pre-R2026a, or to control the SCS-carrier count
exactly, build manually with nrDLCarrierConfig (no args).
Customize only what the task requires (see the rule below). Set non-defaults such as
cfg.PDSCH{1}.Modulation = '64QAM';. Never overwrite a constructor-placed value with a different one (e.g. forcingNStartBWP = 0when the constructor centered it) — that breaks the validated layout.Generate —
validateConfigchecks structural rules but does not catch channel conflicts (overlapping PDSCH/CSI-RS, CSI-RS/SSBurst); always run the generator, which returns the waveform and the resource-grid info:
[waveform, info] = nrWaveformGenerator(cfg);What the simplified constructor builds is generation-ready as-is — an
unedited nrDLCarrierConfig(fr, bw, scs) or nrULCarrierConfig(fr, bw, scs)
generates for every FR1/FR2 bandwidth/SCS combination, so do not re-check what
it set. This does not apply to the no-argument nrDLCarrierConfig /
nrULCarrierConfig, whose defaults (15 kHz, Case A SSB, 52-RB PRBSet) must be
resized by hand. One silent caveat: at 3 MHz / 15 kHz the SSB is wider than
the 15-RB carrier, so the PBCH is punctured — this is expected; keep the SSB
(details in Critical Rules). Check the Critical Rules for
whatever you change or build by hand: a no-argument (manual) carrier, an
edited NSizeGrid/BWP/CORESET/PRBSet, a BlockPattern override, an added SCS
carrier or BWP (Point A centering), CSI-RS or PDCCH across BWPs, or 2 codewords
(layers/DM-RS). Those edits cause the most generation failures.
Set Only What the Task Requires
Set every property the task requires — including parameters forced by a
requested feature, even when the prompt never names them — and nothing else. For
example, 2 codewords → NumLayers 5–8 → a DM-RS that supports more than 4 ports
(see Critical Rules); a requested CSI-RS →
CSIRS{1}.Enable = true (off by default). These are required, not over-config.
SSBurst is already enabled by default, so a requested SS burst needs no
Enable line.
Recipes and References
Open the reference that matches the task; each has copy-ready, verified code:
Common single-carrier waveforms (Basic DL with dual-grid plot, Basic UL, power spectrum): references/patterns.md
Narrow-band 11-RB carriers, manual build only (5 MHz/30 kHz, 10 MHz/60 kHz). The simplified constructor already handles these — skip this reference when you use it. Open it only for a no-argument build (pre-R2026a, or to avoid the auto-added SSB carrier), where the defaults fail and need
NSizeGrid = 11, a disabled/rehomed SSB, a shrunk CORESET, AL1, and an explicitPRBSet: references/narrow-band-manual-config.mdMulti-BWP / multi-numerology layouts: references/multi-bwp-guidance.md
Test models (TM) and fixed reference channels (FRC) — use the example helper
hNRReferenceWaveformGenerator(RC, BW, SCS)(e.g.'DL-FRC-FR1-64QAM','NR-FR1-TM1.1'), thengenerateWaveform+displayResourceGrid. It is not on the path by default: first make it available with a portable setup (setupExample('5g/NRTestModelWaveformGenerationExample', ...)+copyfile+cd, oropenExample) — never a hardcoded path, never a made-up namespaced name. Valid names, portable-setup block, andmakeConfigWritableedits: references/test-models-and-frc.mdFull API catalog + output structure (fields of
info, correct property names): references/api-reference.mdOnline documentation links: references/documentation-links.md
Conventions
After generating a waveform, unless the user asks for something specific:
Tell the user the waveform variable name and that it is in the workspace
Plot the resource grid from
info.ResourceGrids(k).ResourceGridBWP(BWP-sized, one per BWP); useResourceGridInCarrieronly for a full-carrier view. The SS burst is a separate grid — whenSSBurst.Enableis true and the SS burst is asked for, also plotinfo.ResourceGridSSBurst.ResourceGrid(it is not part ofResourceGridBWP)Save the generation code as a
.mscript and open it in the MATLAB editor withedit('scriptName.m')
Start with the simplified constructor
nrDLCarrierConfig('FR1', bw, scs)when possibleCorrect property names:
DMRSPower(not PowerDMRS),PTRSPower(not PowerPTRS),NSizeGrid(not NRB),ChannelBandwidth(not Bandwidth)SCSCarriers,BandwidthParts,CORESET,PDSCH,PUSCHare cell arrays — use{};SSBurstis a direct object — use.not{}Use
tiledlayout/nexttilefor multi-panel figures; always label axes with units and include figure titlesComment non-obvious, interdependent choices (why a given
NSizeGrid, why SSBurst is disabled, why a specificAggregationLevel) so the code explains itself
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.1 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md7.9 KiB
- manifest.yaml440 B
- references/api-reference.md3.4 KiB
- references/critical-rules.md8.0 KiB
- references/documentation-links.md2.4 KiB
- references/multi-bwp-guidance.md17.7 KiB
- references/narrow-band-manual-config.md4.5 KiB
- references/patterns.md1.8 KiB
- references/test-models-and-frc.md5.0 KiB
references/critical-rules.md
Critical Rules
These parameter constraints cause the most errors. An unedited
simplified-constructor config (nrDLCarrierConfig(fr, bw, scs) /
nrULCarrierConfig(fr, bw, scs)) already satisfies them; check the ones that
apply to anything you change, or to a no-argument (manual) build, before calling
nrWaveformGenerator. Apply only the fixes your layout needs, and follow
Set Only What the Task Requires in SKILL.md for everything else.
NSizeGrid Must Match Channel Bandwidth
Look up NSizeGrid from the bandwidth tables. The simplified constructor
(R2026a+) handles this automatically. To look up values programmatically:
nrDLCarrierConfig.FR1BandwidthTable
nrDLCarrierConfig.FR2BandwidthTableBWP Must Fit Within SCS Carrier
NStartBWP >= NStartGrid
NStartBWP + NSizeBWP <= NStartGrid + NSizeGridThe BWP SubcarrierSpacing must exactly match one SCS carrier's
SubcarrierSpacing.
CORESET Must Fit Within BWP
Each bit set to 1 in FrequencyResources allocates 6 RBs. Total must
not exceed NSizeBWP:
6 * sum(FrequencyResources) <= NSizeBWPMax bits to set: floor(NSizeBWP / 6). Trailing zeros are implied, so a short
vector is enough. For narrow bandwidths:
| NSizeBWP | Max bits | Example FrequencyResources |
|---|---|---|
| 11 | 1 | 1 |
| 24 | 4 | [1 1 1 1] |
| 51 | 8 | ones(1,8) |
SSB Carrier Must Be at Least 20 RBs (Except at 3 MHz)
The SCS carrier at the SSB numerology must have NSizeGrid >= 20, except at
ChannelBandwidth = 3 (below). Otherwise generation errors ("SCS carrier
associated with the SSB must be 20 resource blocks or wider").
3 MHz exception: the PBCH is punctured. At 3 MHz the 15 kHz carrier is only
15 RBs, yet the Case A SSB is accepted and generation succeeds silently: the
20-RB (240-subcarrier) SSB is cut to the carrier, so
PSS and SSS stay intact but about half the PBCH REs (including PBCH DM-RS) are
punctured. This is 3GPP-sanctioned (Rel-17 3 MHz channel), not a bug — keep the
SSB; do not disable it or move it to a wider carrier (the puncture affects PBCH
decoding margin and SSB power measurements). The same 15-RB carrier at any wider ChannelBandwidth
errors.
| BlockPattern | SSB SCS |
|---|---|
| Case A | 15 kHz |
| Case B | 30 kHz |
| Case C | 30 kHz |
| Case D | 120 kHz |
| Case E | 240 kHz |
When the user does not specify SSB parameters, choose a BlockPattern that matches the user's SCS carrier so no extra carrier is needed: 15 kHz → Case A, 30 kHz → Case B, 60 kHz → Case B (FR1; add a 30 kHz carrier if none exists), 120 kHz → Case D.
When the user explicitly requests SSB parameters that require a different SCS than the main carrier, add a dedicated SCS carrier for the SSB:
% Example: user wants Case A (15 kHz SSB) on a 30 kHz carrier
scsSSB = nrSCSCarrierConfig;
scsSSB.SubcarrierSpacing = 15;
scsSSB.NSizeGrid = 20; % Minimum for SSB
cfg.SCSCarriers{end+1} = scsSSB;
cfg.SSBurst.BlockPattern = 'Case A';An 11-RB data carrier (5 MHz / 30 kHz, 10 MHz / 60 kHz) cannot host the SSB
itself, but a separate 20-RB SSB carrier still fits the channel — that is what
the simplified constructor builds (see
narrow-band-manual-config.md). Disable
SSBurst (cfg.SSBurst.Enable = false) only when the task wants a
single-carrier layout or no SSB.
Point A Centering Constrains Multi-Carrier Layouts
When multiple SCS carriers coexist, Point A centers the highest-SCS carrier, so a
lower-SCS carrier may need fewer RBs than the bandwidth-table maximum (e.g. at 40 MHz a
full 106-RB 30 kHz carrier leaves room for only 214 RBs at 15 kHz, not the table's 216).
Call validateConfig(cfg) and reduce NSizeGrid if needed.
CSI-RS Must Not Conflict With Other Channels
Within the same BWP, nrWaveformGenerator reserves CSI-RS REs automatically, so
conflicts only arise between DM-RS and CSI-RS. Across different BWPs that overlap in
frequency, CSI-RS defaults span the full BWP and can collide with PDSCH, PDCCH, or
SSBurst. Fix with NumRB and RBOffset:
% Start from the constructor's CSI-RS: its SymbolLocations clears PDCCH
% (a new nrWavegenCSIRSConfig defaults to symbol 0, on the CORESET).
csirs1 = cfg.CSIRS{1}; % BWP 1 (BandwidthPartID default 1 — don't restate it)
csirs1.Enable = true; % the constructor ships CSI-RS disabled
csirs1.NumRB = 106; % confine to PDSCH1's region (RBOffset default 0 — don't restate it)
csirs2 = csirs1;
csirs2.BandwidthPartID = 2; % set only where it differs from the default 1
csirs2.NumRB = 53;
csirs2.RBOffset = 53; % non-default offset — genuinely needed to clear PDSCH1
cfg.CSIRS = {csirs1, csirs2};The CSI-RS/SSBurst clash is wider than it looks: across different SCS (SSBurst
Case A 15 kHz vs CSI-RS on a 30 kHz BWP) one SSB symbol maps to several on the CSI-RS
grid, so a small SSB footprint forbids a broad band and a mid-slot guess (e.g. 8) lands
inside it. Check every CSI-RS on any BWP; resolve in order, then re-run
nrWaveformGenerator to confirm clean: (1) CSIRSPeriod (most robust) — steer
CSI-RS to a slot the SSBurst skips (CSIRSPeriod = [10 1]), any numerology; (2)
NumRB/RBOffset — a region clear of the SSBurst carrier; (3) SymbolLocations
(last resort) — place at the slot end (13/12), never mid-slot. Keep CSI-RS
off the CORESET symbols (0–1 by default) so the same placement also clears PDCCH — no
need to touch the unrequested PDCCH. A new nrWavegenCSIRSConfig defaults to
SymbolLocations = 0, which lands on the CORESET and conflicts with PDCCH. The
simplified constructor's (disabled) CSIRS{1} instead holds a layout-specific symbol
(3, 4, or 6) that clears both PDCCH and SSBurst, so just enabling it generates cleanly.
Resizing it (NumRB/RBOffset) can reopen the SSBurst clash, so re-run.
PDCCH Conflicts With PDSCH Across BWPs or RNTIs
Within the same BWP and RNTI, nrWaveformGenerator automatically reserves
REs for PDCCH (via the CORESET region). PDCCH conflicts with PDSCH when:
They are on different overlapping BWPs
They have different RNTIs on the same BWP
To resolve, separate them in time (SymbolAllocation, SlotAllocation) or
frequency (PRBSet).
PDSCH/PUSCH PRBSet Must Fit Within BWP
Every RB in PRBSet must lie inside the BWP:
max(PRBSet) < NSizeBWPAlways set PRBSet explicitly to fit the BWP — PRBSet = 0:NSizeBWP-1 for
full-band. An over-range PRBSet is invalid, and the reaction is
release-dependent (through R2026a it errors; R2026b silently clips), so rely on
neither. The default 0:51 overflows any BWP under 52 RBs (e.g. an 11-RB 5 MHz /
30 kHz carrier). PRBSet sets frequency allocation only — waveform length is
fixed by bandwidth, SCS, and NumSubframes.
Two Codewords Need 5–8 Layers and a Matching DM-RS
A PDSCH or PUSCH carries 2 codewords only when NumLayers is 5–8 (TS 38.211
Table 7.3.1.3-1; 8-layer PUSCH is Rel-18 UL MIMO). The default DM-RS (type 1,
single-symbol) supports only 4 ports, so NumLayers > 4 errors unless the DM-RS
is also changed:
DMRSConfigurationType | DMRSLength | Max layers |
|---|---|---|
| 1 (default) | 1 (default) | 4 |
| 1 | 2 | 8 |
| 2 | 1 | 6 |
| 2 | 2 | 8 (max) |
cfg.PDSCH{1}.NumLayers = 8; % 2 codewords need 5–8 layers
cfg.PDSCH{1}.DMRS.DMRSLength = 2; % default DM-RS caps at 4 portsThe same two lines apply to cfg.PUSCH{1} in an nrULCarrierConfig. A 2-codeword
PUSCH also needs TransformPrecoding = false (the default); transform precoding
supports only one codeword.
The DM-RS change is task-required, not over-config. nrWaveformGenerator
sizes the antenna count to NumLayers automatically.
PDCCH Links Through SearchSpace to CORESET
PDCCH.SearchSpaceID must reference a valid SearchSpace, which must
reference a valid CORESET via CORESETID. All IDs must exist.
Copyright 2026 The MathWorks, Inc.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/wireless-communications/matlab-generate-5g-waveform · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-generate-5g-waveform.zip