Matlab Design Ofdm System
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 essential patterns and anti-patterns for building custom OFDM systems in MATLAB. It emphasizes the use of built-in functions like ofdmmod and ofdmdemod over manual FFT/IFFT implementations to avoid common subcarrier mapping errors. It covers critical aspects of OFDM design including subcarrier allocation, pilot insertion, channel estimation, synchronization, and LDPC coding, while highlighting version-specific API differences and proper SNR handling.
What it does
- Specifies correct calling conventions for ofdmmod, ofdmdemod, and related OFDM functions.
- Provides rules for subcarrier allocation, including null and pilot indexing.
- Defines the correct method for computing signal power and adding noise in OFDM simulations.
- Outlines workflows for pilot-based channel estimation and equalization.
- Details the integration of LDPC coding within an OFDM link.
- Provides guidance on configuring fading channels and synchronization pipelines.
When to use it
- When building custom, non-standard OFDM transmitters or receivers.
- When configuring subcarrier grids, guard bands, or pilot patterns.
- When implementing channel estimation, equalization, or synchronization for OFDM links.
- When adding LDPC forward error correction to an OFDM system.
- When simulating OFDM performance over AWGN or fading channels.
Advantages
- Prevents common silent errors caused by manual FFT/IFFT subcarrier mapping.
- Ensures physically accurate noise and SNR handling in OFDM simulations.
- Provides a structured approach to complex tasks like synchronization and channel estimation.
- Clarifies version-specific API usage for modern MATLAB releases.
- Reduces development time by providing clear, tested patterns for OFDM design.
Usage examples
- “How do I correctly modulate a signal for a 64-FFT OFDM system with 12 null subcarriers?”
- The agent will provide the code to define the nullIdx vector, calculate the active subcarrier count, and use ofdmmod with the correct parameters, ensuring proper subcarrier mapping.
- “I need to add AWGN to my OFDM signal. How do I calculate the correct power?”
- The agent will explain that signal power is not 1W and provide the formula 10*log10(nActiveSC / nFFT^2) to be used as the explicit power argument in the awgn function.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/matlab/matlab-design-ofdm-system/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-design-ofdm-system.zip -d .agents/skills
Documentation by MathWorks
OFDM System Design
When To Use
Use this skill when the user wants to build a custom (non-standard) OFDM transmitter/receiver, configure subcarrier allocation, add noise to OFDM signals, equalize OFDM through fading channels, implement synchronization, or add LDPC coding.
When Not To Use
Do NOT use this skill for standards-specific OFDM (use 5G Toolbox for 5G NR, WLAN Toolbox for Wi-Fi, LTE Toolbox for 4G/LTE, Bluetooth Toolbox for Bluetooth, Satellite Communications Toolbox for satellite links).
GATE — Ask Before Coding
If the user's request does not specify or unambiguously imply ALL of the following, STOP and ask before generating any code. Present unclear items as a numbered list and ask whether the user wants to: (a) specify values, (b) have you derive them from other constraints (e.g., CP from delay spread, SCS from Doppler), or (c) use typical defaults. Do not assume defaults. Do not proceed until the user responds.
OFDM parameters — FFT size, CP length, subcarrier spacing, subcarrier allocation
Channel model — AWGN only, fading with perfect CSI, or fading with pilot-based estimation
Pilots — needed for channel estimation or phase tracking?
Coding — uncoded, or coded with a specific rate?
Synchronization — perfect sync, or include timing/CFO estimation?
Must-Follow Rules
ALWAYS use
ofdmmod/ofdmdemod— NEVER implement OFDM by directly callingifft/fft— The functions handle CP insertion/removal,ifftshift/fftshiftfor centered-frequency ordering, and pilot/null subcarrier management. Direct IFFT/FFT gets subcarrier mapping wrong (silent error). Input is[nDataSC × nSym]for SISO. Output is a time-domain column vector. Note: sync preambles (e.g., Schmidl-Cox) that require DFT-order subcarrier mapping may useifftdirectly, sinceofdmmodappliesifftshiftwhich changes the even/odd bin assignment. Windowing:ofdmmoddoes not support windowing. For raised cosine windowing, usecomm.OFDMModulatorfor the transmitter only (always useofdmdemodfunction for demodulation). Seereferences/ofdm-system-guide.mdfor capability comparison.Always use a
symOffsetvariable inofdmdemod— when passingnullidx(5th arg),symOffsetmust be explicitly provided as the 4th arg. The defaultsymOffsetvalue iscpLen(skip entire CP). Note:cpLen/2is more robust when timing synchronization is imperfect.Use explicit signal power in
awgn, NEVER'measured'or0—ofdmmodoutput power is NOT 1W. It equalsnActiveSC / nFFT^2due to MATLAB's 1/N IFFT normalization. Usingawgn(x, snr, 0)adds far too much noise. ComputesigPow = 10*log10(nActiveSC / nFFT^2)once before any loop — it is a constant determined by OFDM parameters.Use
ofdmChannelResponsefor frequency-domain channel response — do NOT computeH = fft(h, nFFT)directly.ofdmmodusesifftshiftinternally, so direct FFT-based channel responses have wrong subcarrier mapping. Pass the result toofdmEqualizefor equalization.When deriving OFDM parameters from physical specs, show the computation with comments — do not just state the values. Show how you calculate subcarrier spacing, FFT size, CP length, sample rate, guard subcarriers, etc. from bandwidth, delay spread, and Doppler spread. Add comments explaining each derivation step.
Check MATLAB version before using version-gated APIs — Functions like
ofdmChannelEstimate,ofdmPilotConfig(R2026a), andldpcPCM(R2025a) are not available on older releases. Unless the user specifically asks for code compatible with a previous version, callversion('-release')to get the current MATLAB release, then choose the appropriate API path.
Key Functions
| Function | Purpose | Since |
|---|---|---|
ofdmmod | OFDM modulation (IFFT + CP insertion) | R2018a |
ofdmdemod | OFDM demodulation (CP removal + FFT) | R2018a |
ofdmChannelResponse | Per-subcarrier channel response from path gains | R2023a |
ofdmEqualize | ZF/MMSE frequency-domain equalization | R2022b |
ofdmPilotConfig | Pilot location and symbol configuration | R2026a |
ofdmChannelEstimate | Pilot-based channel estimation (LS + denoising) | R2026a |
convertSNR | SNR conversion (snrsc, snr, ebno) | R2022a |
awgn | Add white Gaussian noise with explicit signal power | — |
Subcarrier Allocation
Subcarrier indices use centered-frequency ordering: index 1 = most negative frequency, index nFFT/2 + 1 = DC, index nFFT = most positive frequency.
Rules for subcarrier indices:
nullIdxandpilotIdxmust be vectors of 1-based integers in[1, nFFT]They must not overlap
DC subcarrier =
nFFT/2 + 1(always null it)ofdmmodinput X has size[nDataSC x nSym]— null and pilot subcarriers are excludedofdmdemodoutput has size[nDataSC x nSym]— nulls stripped, pilots returned separately
Example (WiFi-like 64-FFT):
nullIdx = [1:6, 33, 60:64].'; % 12 nulls (6 lower guard + DC + 5 upper guard)
pilotIdx = [12; 26; 40; 54]; % 4 pilots
nActiveSC = nFFT - length(nullIdx); % 52 (data + pilots)
nDataSC = nFFT - length(nullIdx) - length(pilotIdx); % 48Basic OFDM Tx/Rx (AWGN)
% Parameters
nFFT = 64; cpLen = 16;
nullIdx = [1:6, 33, 60:64].'; % 12 nulls
nActiveSC = nFFT - length(nullIdx); % 52
nDataSC = nActiveSC; % no pilots
M = 4; % QPSK
nSym = 100;
snr_sc = 10; % dB, per-subcarrier SNR
% Transmit
data = randi([0 M-1], nDataSC, nSym);
modData = pskmod(data, M, InputType="integer");
txSig = ofdmmod(modData, nFFT, cpLen, nullIdx);
% SNR conversion and noise
sigPow = 10*log10(nActiveSC / nFFT^2); % OFDM signal power (dBW)
snr_wb = convertSNR(snr_sc, "snrsc", "snr", ...
FFTLength=nFFT, NumActiveSubcarriers=nActiveSC);
rxSig = awgn(txSig, snr_wb, sigPow);
% Receive
symOffset = cpLen;
rxData = ofdmdemod(rxSig, nFFT, cpLen, symOffset, nullIdx);
demodData = pskdemod(rxData, M, OutputType="integer");
[numErr, ber] = biterr(data(:), demodData(:));SNR Handling for OFDM
SNR per subcarrier (SNR_sc) is the standard noise reference for OFDM simulations. If you need other noise metrics — Eb/No for theoretical BER comparison, or wideband SNR for awgn — use convertSNR to derive them from SNR_sc. See matlab-add-awgn for full convertSNR patterns and awgn usage.
For theoretical BER: convert SNR_sc to Eb/No via convertSNR(snr_sc, "snr", "ebno", BitsPerSymbol=log2(M)), then call berawgn(ebno, 'qam', M). Do NOT pass SNR_sc directly to berawgn or use it as Eb/No in erfc/qfunc closed-form expressions — SNR_sc ≠ Eb/No.
OFDM-specific points (beyond what the AWGN skill covers):
Signal power =
10*log10(nActiveSC / nFFT^2)dBW — due to MATLAB's 1/N IFFT normalizationnActiveSCincludes data AND pilot subcarriersAlways capture noise variance from
awgn's second output:[rxSig, nVar] = awgn(...). Do NOT compute noise variance manually from SNR formula — use the valueawgnreturns to stay in sync with its internal rounding.Noise variance after
ofdmdemodscales by nFFT:nVar_sc = nVar * nFFT(FFT sums N terms)convertSNR"snr" type = per-subcarrier SNR when converting from Eb/No or Es/No (each OFDM subcarrier carries one symbol). To convert per-subcarrier SNR to wideband SNR (forawgn), useconvertSNR(snr_sc, "snrsc", "snr", FFTLength=nFFT, NumActiveSubcarriers=nActiveSC).
Critical Gotchas
awgn(x, snr, 0) is WRONG for OFDM
OFDM signal power depends on nActiveSC and nFFT, not 1W.
% WRONG — assumes unit power (adds ~19 dB too much noise for 64-FFT)
rxSig = awgn(txSig, snr_wb, 0);
% CORRECT — explicit power, capture noise variance
sigPow = 10*log10(nActiveSC / nFFT^2);
[rxSig, nVar] = awgn(txSig, snr_wb, sigPow);symOffset is required in ofdmdemod
symOffset = cpLen; % skip entire CP (or cpLen/2 for imperfect timing)
rxData = ofdmdemod(rxSig, nFFT, cpLen, symOffset, nullIdx);Modulator/demodulator input must be a column vector for single-stream
All Communications Toolbox modulators (qammod, pskmod, etc.) process by columns — each column is an independent channel/stream. For single-stream OFDM, always pass bits or integers as a column vector:
% WRONG — [nSym x k] matrix: each column is treated as a separate stream
txData = reshape(txBits, nBitsPerSym, []).';
txSymbols = qammod(txData, M, InputType="bit", UnitAveragePower=true);
% CORRECT — column vector in, then reshape output to OFDM grid
txSymbols = qammod(txBits, M, InputType="bit", UnitAveragePower=true);
txSymbols = reshape(txSymbols, nActiveSC, nSym);Use multiple columns only when modulating independent MIMO streams or parallel codewords simultaneously.
DC subcarrier index
DC = nFFT/2 + 1. For nFFT=64, DC is index 33. Always include it in nullIdx.
ofdmEqualize hEst dimensions
With default DataFormat="3-D", hEst dimensions are:
[nSC × NS × NR]— static: same estimate applied to all OFDM symbols[(nSC*nSym) × NS × NR]— time-varying: per-symbol estimates collapsed into first dimension
Passing [nSC × nSym] directly is wrong — dim 2 is read as NS, not nSym:
% WRONG — hEst [nSC x nSym] misinterpreted as [nSC x NS=nSym]
eqData = ofdmEqualize(rxData, hEst_per_sym, nVar);
% CORRECT — collapse first dim to (nSC*nSym), keep stream/antenna dims
eqData = ofdmEqualize(rxData, reshape(hEst_per_sym, [], Ns, Nr), nVar);OFDM with Pilots
To insert pilots, pass pilotIdx and pilot symbols as additional arguments to ofdmmod/ofdmdemod. Signal power is based on nActiveSC (data + pilots), not nDataSC alone.
See references/ofdm-pilots-and-estimation.md for the full pilot insertion example.
Pilot-Based Channel Estimation (R2026a)
Use ofdmPilotConfig + ofdmChannelEstimate for pilot-based channel estimation without perfect CSI. If you have not already checked, get the current MATLAB version before deciding between the R2026a workflow and the pre-R2026a manual LS approach.
The ofdmChannelEstimate workflow differs from the legacy pilotIdx approach:
nullIdxcontains only guard bands (NOT DC) — DC becomes an active-grid position that you zero out manually.No
pilotIdxargument toofdmmod/ofdmdemod— build a full[nActiveSC x nSym]grid with data, pilots, and DC=0, then pass it directly.Pilot locations come from
ofdmPilotConfig, not from function arguments.rxSymis 3-D:[nActiveSC x nSym x nRx]— add the receive-antenna dimension even for SISO.
See references/ofdm-pilots-and-estimation.md for complete code examples.
OFDM over Fading Channels
Two approaches for channel equalization:
Perfect CSI (R2023a) — use
ofdmChannelResponsewith path gains fromcomm.RayleighChannel(requiresPathGainsOutputPort=true). GetpathFiltersfrominfo(channel).ChannelFilterCoefficients. PassH(:)toofdmEqualizefor time-varying SISO.Pilot-based estimation (R2026a) — use
ofdmPilotConfig+ofdmChannelEstimate.
Both approaches use ofdmEqualize with Algorithm="mmse" for final equalization. Always use explicit signal power in awgn (not 'measured') — fading changes the instantaneous power.
See references/ofdm-fading-channel.md for channel configuration (Rayleigh/Rician, Doppler, 3GPP profiles, ofdmEqualize dimensions).
Fading Channel Setup
Configure comm.RayleighChannel or comm.RicianChannel with PathGainsOutputPort=true. Key rules:
Always set
SampleRate(default is 1 Hz)Maximum path delay must be < CP duration:
max(PathDelays) < cpLen/SampleRateCompute Doppler from velocity:
fd = (velocity * carrierFreq) / physconst('LightSpeed')
See references/ofdm-fading-channel.md for full setup, 3GPP profiles, and quasi-static fading.
Synchronization
Pipeline: Coarse timing → CFO estimation → CFO correction → Fine timing → OFDM demod → Phase tracking
Key rules:
Use
frequencyOffsetfor CFO application/correction (not manualexp(-1j*2*pi*...))Use
timingEstimatefor cross-correlation timing detectionAlways
unwrappilot phase estimates before applying correction across symbols
See references/ofdm-synchronization.md for Schmidl-Cox, CP-based timing, Zadoff-Chu preambles, and complete Rx example.
LDPC Coding
Key rules:
Use
ldpcEncode/ldpcDecodewith config objects (NOT removedcomm.LDPCEncoder/comm.LDPCDecoder)Create config from parity check matrix only:
H = ldpcPCM(648, 324); encCfg = ldpcEncoderConfig(H); decCfg = ldpcDecoderConfig(H). Do NOT pass scalars or Name-Value pairs —ldpcEncoderConfig(648),ldpcEncoderConfig(648, 1/2), andldpcDecoderConfig(BlockLength=648)all error. If you have not already checked, get the current MATLAB version to decide betweenldpcPCM(R2025a+) andldpcQuasiCyclicMatrix(R2021b+).Include
CodingRateinconvertSNRwhen computing Eb/No for coded systemsPass
NoiseVarianceto demodulators, such asqamdemod, for proper LLR scaling; scale to frequency domain:nVar_sc = nVar * nFFTUse
OutputType="approxllr"for LLR computation
See references/ofdm-ldpc-coding.md for OFDM+LDPC workflow and multi-codeword framing.
Advanced Features
See references/ofdm-system-guide.md for:
Variable CP length — per-symbol CP via row vector
cpLensCommon OFDM configurations — WiFi-like, LTE-like, 5G-like parameter sets
SNR conversion — see
matlab-add-awgnskill for allconvertSNRpatternsNoise variance for soft demodulation — scaling after
ofdmdemod
Cross-References
matlab-add-awgn— when you need to add noise and calculate SNR conversions, use this skill. It covers allconvertSNRpatterns,awgnusage, and noise variance capture.
Reference Loading
Load references/ofdm-pilots-and-estimation.md when the user asks about pilot insertion, pilot-based channel estimation (R2026a ofdmChannelEstimate), or pre-R2026a LS estimation.
Load references/ofdm-fading-channel.md when the user asks about fading channel configuration, Rayleigh/Rician setup, Doppler calculation, 3GPP delay profiles, or ofdmEqualize dimension handling.
Load references/ofdm-synchronization.md when the user asks about timing synchronization, CFO estimation/correction, Schmidl-Cox, preamble design, or pilot-based phase tracking.
Load references/ofdm-ldpc-coding.md when the user asks about LDPC coding, forward error correction, ldpcEncode/ldpcDecode, NoiseVariance for soft decoding, or coded BER simulations.
Load references/ofdm-system-guide.md when the user asks about SNR conversion details, common OFDM configurations, noise variance for soft demodulation, or variable CP length.
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.0 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md15.6 KiB
- manifest.yaml606 B
- references/ofdm-fading-channel.md8.4 KiB
- references/ofdm-ldpc-coding.md7.9 KiB
- references/ofdm-pilots-and-estimation.md8.0 KiB
- references/ofdm-synchronization.md11.8 KiB
- references/ofdm-system-guide.md5.4 KiB
references/ofdm-ldpc-coding.md
LDPC Coding for OFDM — Reference
Must-Follow Rules
Use the modern function API —
ldpcEncode/ldpcDecodewith config objects. The System objectscomm.LDPCEncoderandcomm.LDPCDecoderare removed and error immediately.Pass
NoiseVarianceto the demodulator —qamdemod/pskdemodneedNoiseVarianceto produce correctly scaled LLR. Without it, decoding degrades severely.Include
CodingRateinconvertSNR— omitting it inflates SNR (3 dB too high for rate-1/2). Always pass the actual code rate.Feed LLR (soft bits) to the decoder —
ldpcDecodetakes log-likelihood ratios. Convention: positive LLR = bit 0, negative LLR = bit 1.ldpcEncoderConfigandldpcDecoderConfigeach take exactly one argument: a parity check matrix — there is no scalar, Name-Value, or two-argument shortcut. Always create the PCM first, then pass it:
% CORRECT — two-step: create PCM, then config
H = ldpcPCM(648, 324); % parity check matrix (sparse logical)
encCfg = ldpcEncoderConfig(H); % encoder config
decCfg = ldpcDecoderConfig(H); % decoder config
% WRONG — all of these error immediately:
ldpcEncoderConfig(648, 1/2) % scalar args
ldpcEncoderConfig(648) % scalar block length
ldpcDecoderConfig(BlockLength=648, CodeRate=1/2) % Name-Value pairsKey Functions
| Function | Purpose | Since |
|---|---|---|
ldpcPCM(N, K) | Create rate-1/2 parity check matrix | R2025a |
ldpcQuasiCyclicMatrix(Z, P) | Create any-rate PCM from prototype | R2021b |
ldpcEncoderConfig(H) | Create encoder config | R2021b |
ldpcDecoderConfig(H) | Create decoder config | R2021b |
ldpcEncode(msg, encCfg) | Encode information bits | R2021b |
ldpcDecode(llr, decCfg, maxIter) | Decode from LLR | R2021b |
Removed — do NOT use:
comm.LDPCEncoder/comm.LDPCDecoder— removed, error immediatelydvbs2ldpc— deprecated, warns. UseldpcPCMorldpcQuasiCyclicMatrix
Which Approach to Use
| MATLAB Version | How to Create the Parity Check Matrix |
|---|---|
| R2025a+ | H = ldpcPCM(N, K) — generic, any block length and rate. Preferred. |
| R2021b–R2024b | H = ldpcQuasiCyclicMatrix(blockSize, P) — pass a subblock size and prototype matrix P. See the ldpcQuasiCyclicMatrix doc examples for IEEE 802.11 prototype matrices at various rates. |
Once you have H, the workflow is identical on all versions:
encCfg = ldpcEncoderConfig(H);
decCfg = ldpcDecoderConfig(H);
coded = ldpcEncode(msg, encCfg);
decoded = ldpcDecode(llr, decCfg, maxIter);Example (R2021b+, rate 3/4, block 648, from ldpcQuasiCyclicMatrix doc):
P = [16 17 22 24 9 3 14 -1 4 2 7 -1 26 -1 2 -1 21 -1 1 0 -1 -1 -1 -1
25 12 12 3 3 26 6 21 -1 15 22 -1 15 -1 4 -1 -1 16 -1 0 0 -1 -1 -1
25 18 26 16 22 23 9 -1 0 -1 4 -1 4 -1 8 23 11 -1 -1 -1 0 0 -1 -1
9 7 0 1 17 -1 -1 7 3 -1 3 23 -1 16 -1 -1 21 -1 0 -1 -1 0 0 -1
24 5 26 7 1 -1 -1 15 24 15 -1 8 -1 13 -1 13 -1 11 -1 -1 -1 -1 0 0
2 2 19 14 24 1 15 19 -1 21 -1 2 -1 24 -1 3 -1 2 1 -1 -1 -1 -1 0];
H = ldpcQuasiCyclicMatrix(27, P); % rate 3/4, block 648
encCfg = ldpcEncoderConfig(H);Basic OFDM + LDPC Workflow
%% Parameters
nFFT = 64; cpLen = 16;
nullIdx = [1:6, 33, 60:64].';
nActiveSC = nFFT - length(nullIdx); % 52
M = 16; k = log2(M);
snr_sc = 12; % dB
%% Create LDPC code (rate-1/2)
H = ldpcPCM(648, 324);
encCfg = ldpcEncoderConfig(H);
decCfg = ldpcDecoderConfig(H);
codeRate = decCfg.CodeRate; % 0.5
K = encCfg.NumInformationBits; % 324
N = encCfg.BlockLength; % 648
%% Encode
msg = randi([0 1], K, 1);
encoded = ldpcEncode(msg, encCfg);
%% Map to OFDM symbols
nSymbolsPerCW = ceil(N / (nActiveSC * k)); % QAM symbols needed
% Pad to fill complete OFDM grid
nBitsNeeded = nActiveSC * nSymbolsPerCW * k;
txBits = [encoded; zeros(nBitsNeeded - N, 1)];
%% Modulate (QAM + OFDM)
txQAM = qammod(txBits, M, InputType="bit", UnitAveragePower=true);
txGrid = reshape(txQAM, nActiveSC, nSymbolsPerCW);
txSig = ofdmmod(txGrid, nFFT, cpLen, nullIdx);
%% Add noise
sigPow = 10*log10(nActiveSC / nFFT^2);
snr_wb = convertSNR(snr_sc, "snrsc", "snr", ...
FFTLength=nFFT, NumActiveSubcarriers=nActiveSC);
[rxSig, nVar] = awgn(txSig, snr_wb, sigPow);
%% Demodulate (OFDM + QAM with LLR)
rxGrid = ofdmdemod(rxSig, nFFT, cpLen, cpLen, nullIdx);
nVar_sc = nVar * nFFT; % frequency-domain noise variance
rxLLR = qamdemod(rxGrid(:), M, OutputType="approxllr", ...
UnitAveragePower=true, NoiseVariance=nVar_sc);
%% Decode (take only N bits worth of LLR)
[decoded, numIter, parityChecks] = ldpcDecode(rxLLR(1:N), decCfg, 50);
numErrors = sum(msg ~= decoded);
fprintf("Errors: %d, Iterations: %d\n", numErrors, numIter);CodingRate in convertSNR
Omitting CodingRate inflates SNR:
% WRONG — 3 dB too much SNR for rate-1/2
snr = convertSNR(5, "ebno", "snr", BitsPerSymbol=2); % 8.01 dB
% RIGHT — accounts for code rate
snr = convertSNR(5, "ebno", "snr", BitsPerSymbol=2, CodingRate=1/2); % 5.00 dB| Code rate | SNR penalty if CodingRate omitted |
|---|---|
| 1/2 | 3.01 dB |
| 2/3 | 1.76 dB |
| 3/4 | 1.25 dB |
| 5/6 | 0.79 dB |
NoiseVariance for LLR
For OFDM, noise variance after ofdmdemod scales by nFFT:
% Capture from awgn
[rxSig, nVar] = awgn(txSig, snr_wb, sigPow);
% Scale to frequency domain
nVar_sc = nVar * nFFT;
% Pass to demodulator
rxLLR = qamdemod(rxData, M, OutputType="approxllr", ...
UnitAveragePower=true, NoiseVariance=nVar_sc);Without NoiseVariance: LLR magnitudes are unscaled, decoder needs more iterations or fails.
Decoder Algorithms
| Algorithm | Description | When to use |
|---|---|---|
"bp" | Belief propagation (sum-product) | Default. Best accuracy |
"layered-bp" | Layered belief propagation | Faster convergence for QC-LDPC |
"norm-min-sum" | Normalized min-sum | Lower complexity, hardware models |
"offset-min-sum" | Offset min-sum | Lower complexity, hardware models |
decCfg = ldpcDecoderConfig(H);
decCfg.Algorithm = "layered-bp"; % faster convergence for QC-LDPC (BP=20 ≈ layered=10)Iteration Control and Failure Detection
maxIter = 50;
[decoded, numIter, parityChecks] = ldpcDecode(rxLLR, decCfg, maxIter);
if all(parityChecks == 0)
fprintf("Converged after %d iterations\n", numIter);
else
fprintf("FAILED to converge after %d iterations\n", numIter);
% Check: NoiseVariance correct? LLR sign convention? SNR too low?
endNote: ldpcDecode returns int8. Use double(decoded) if comparing against double arrays.
LLR OutputType
Always use OutputType="approxllr" — negligible accuracy loss vs exact "llr", significantly faster for higher-order QAM.
Multi-Codeword OFDM Frames
When a frame contains multiple LDPC codewords:
numCW = 4;
K = encCfg.NumInformationBits;
N = encCfg.BlockLength;
% Encode all codewords
txBits = zeros(N * numCW, 1);
msgAll = zeros(K * numCW, 1);
for ii = 1:numCW
msg = randi([0 1], K, 1);
msgAll((ii-1)*K+1 : ii*K) = msg;
txBits((ii-1)*N+1 : ii*N) = ldpcEncode(msg, encCfg);
end
% ... modulate, OFDM, channel, demodulate ...
% Decode each codeword — split LLR by codeword length N (not symbols)
for ii = 1:numCW
cwLLR = rxLLR((ii-1)*N+1 : ii*N);
decoded = ldpcDecode(cwLLR, decCfg, 50);
endKey: Split received LLR by codeword length N, not by QAM symbols.
Supported Code Sizes (ldpcPCM)
| N | K | Rate | Expansion factor Z |
|---|---|---|---|
| 648 | 324 | 1/2 | 27 |
| 1296 | 648 | 1/2 | 54 |
| 1944 | 972 | 1/2 | 81 |
For other rates (2/3, 3/4, 5/6), use ldpcQuasiCyclicMatrix(Z, P) with the prototype matrix from the relevant standard (IEEE 802.11, 3GPP TS 38.212).
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-design-ofdm-system · 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-design-ofdm-system.zip