关于 matlab-design-ofdm-system
面向 MATLAB 的非标准 OFDM 收发系统设计技能,涵盖子载波分配、信道仿真、同步与均衡,并要求先确认关键参数,避免常见实现错误。
主要功能
- 01设计自定义 OFDM 收发系统
- 02配置子载波与导频
- 03仿真 AWGN 和衰落信道
- 04实现同步与信道均衡
- 05编码前核对关键参数
适用场景
- 01在 MATLAB 中构建自定义 OFDM 链路
- 02仿真噪声或衰落影响
- 03添加导频并进行信道估计
- 04规划同步与编码参数
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ matlab/ matlab-agentic-toolkit --skill matlab-design-ofdm-system安装后在 Claude Code 中输入/matlab-design-ofdm-system确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
manifest.yamlreferences/ofdm-fading-channel.mdofdm-ldpc-coding.mdofdm-pilots-and-estimation.mdofdm-synchronization.mdofdm-system-guide.md详细介绍
OFDM 系统设计
适用场景
当用户想要构建自定义(非标准)OFDM 发射机/接收机、配置子载波分配、向 OFDM 信号添加噪声、对经过衰落信道的 OFDM 信号进行均衡、实现同步或添加 LDPC 编码时,请使用此技能。
不适用场景
对于特定标准的 OFDM,请勿使用此技能(5G NR 使用 5G Toolbox,Wi-Fi 使用 WLAN Toolbox,4G/LTE 使用 LTE Toolbox,Bluetooth 使用 Bluetooth Toolbox,卫星链路使用 Satellite Communications Toolbox)。
GATE — 编码前先询问
如果用户的请求未明确指定或无法明确推断以下所有内容,请停下来,在生成任何代码前先询问。将不明确的项目列为编号清单,并询问用户希望:(a)指定具体值;(b)让你根据其他约束推导(例如,根据时延扩展确定 CP,根据多普勒确定 SCS);或(c)使用典型默认值。不要自行假设默认值。用户回复前不要继续。
- OFDM 参数 — FFT 大小、CP 长度、子载波间隔、子载波分配
- 信道模型 — 仅 AWGN、具有完美 CSI 的衰落,或基于导频估计的衰落
- 导频 — 是否需要用于信道估计或相位跟踪?
- 编码 — 不编码,或采用特定码率进行编码?
- 同步 — 完美同步,或包含定时/CFO 估计?
必须遵守的规则
-
始终使用
ofdmmod/ofdmdemod——绝不直接调用ifft/fft实现 OFDM — 这些函数会处理 CP 的插入/移除、用于居中频率排序的ifftshift/fftshift,以及导频/空子载波管理。直接使用 IFFT/FFT 会导致子载波映射错误(且错误不会显现)。SISO 的输入为[nDataSC × nSym]。输出为时域列向量。注意: 需要 DFT 顺序子载波映射的同步前导码(例如 Schmidl-Cox)可以直接使用ifft,因为ofdmmod会应用ifftshift,从而改变偶数/奇数频点的分配。加窗:ofdmmod不支持加窗。要使用升余弦加窗,仅在发射机端使用comm.OFDMModulator(解调时始终使用ofdmdemod函数)。有关功能对比,请参阅references/ofdm-system-guide.md。 -
在
ofdmdemod中始终使用symOffset变量 — 传入nullidx(第 5 个参数)时,必须将symOffset显式设为第 4 个参数。默认的symOffset值为cpLen(跳过整个 CP)。注意:当定时同步不完美时,cpLen/2更稳健。 -
在
awgn中使用明确的信号功率,绝不使用'measured'或0—ofdmmod的输出功率不等于 1W。由于 MATLAB 的 1/N IFFT 归一化,其功率等于nActiveSC / nFFT^2。使用awgn(x, snr, 0)会加入过多噪声。在任何循环之前计算一次sigPow = 10*log10(nActiveSC / nFFT^2)——这是由 OFDM 参数决定的常量。 -
使用
ofdmChannelResponse获取频域信道响应 — 不要直接计算H = fft(h, nFFT)。ofdmmod内部使用ifftshift,因此直接通过 FFT 计算的信道响应会导致子载波映射错误。将结果传递给ofdmEqualize进行均衡。 -
根据物理规格推导 OFDM 参数时,用注释展示计算过程 — 不要只给出数值。应展示如何根据带宽、时延扩展和多普勒扩展计算子载波间隔、FFT 大小、CP 长度、采样率、保护子载波等。添加注释,解释每个推导步骤。
-
使用受版本限制的 API 前,先检查 MATLAB 版本 —
ofdmChannelEstimate、ofdmPilotConfig(R2026a)和ldpcPCM(R2025a)等函数在较旧版本中不可用。除非用户明确要求代码兼容旧版本,否则调用version('-release')获取当前 MATLAB 版本,然后选择合适的 API 路径。
主要功能
| 功能 | 用途 | 起始版本 |
|---|---|---|
ofdmmod | OFDM 调制(IFFT + 插入 CP) | R2018a |
ofdmdemod | OFDM 解调(移除 CP + FFT) | R2018a |
ofdmChannelResponse | 根据路径增益计算每个子载波的信道响应 | R2023a |
ofdmEqualize | ZF/MMSE 频域均衡 | R2022b |
ofdmPilotConfig | 导频位置和符号配置 | R2026a |
ofdmChannelEstimate | 基于导频的信道估计(LS + 降噪) | R2026a |
convertSNR | SNR 转换(snrsc、snr、ebno) | R2022a |
awgn | 根据明确指定的信号功率添加白高斯噪声 | — |
子载波分配
子载波索引使用中心频率顺序:索引 1 = 最负频率,索引 nFFT/2 + 1 = DC,索引 nFFT = 最正频率。
子载波索引规则:
nullIdx和pilotIdx必须是[1, nFFT]范围内由 1 开始的整数向量- 两者不能重叠
- DC 子载波 =
nFFT/2 + 1(始终将其设为 null) ofdmmod输入 X 的大小为[nDataSC x nSym]— 不包含 null 和导频子载波ofdmdemod输出的大小为[nDataSC x nSym]— 已剔除 null 子载波,导频会单独返回
示例(类似 WiFi 的 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); % 48
基本 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(:));
OFDM 的 SNR 处理
每个子载波的 SNR(SNR_sc)是 OFDM 仿真中标准的噪声参考值。 如果需要其他噪声指标,例如用于理论 BER 对比的 Eb/No,或用于 awgn 的宽带 SNR,请使用 convertSNR 从 SNR_sc 推导。有关 convertSNR 的完整用法模式和 awgn 用法,请参阅 matlab-add-awgn。
对于理论 BER: 使用 convertSNR(snr_sc, "snr", "ebno", BitsPerSymbol=log2(M)) 将 SNR_sc 转换为 Eb/No,然后调用 berawgn(ebno, 'qam', M)。切勿将 SNR_sc 直接传给 berawgn,也不要在 erfc/qfunc 闭式表达式中将其用作 Eb/No — SNR_sc ≠ Eb/No。
OFDM 特有注意事项(AWGN 技能中未涉及):
- 信号功率 =
10*log10(nActiveSC / nFFT^2)dBW — 这是由于 MATLAB 的 1/N IFFT 归一化 nActiveSC包含数据和导频子载波- 始终从
awgn的第二个输出中获取噪声方差:[rxSig, nVar] = awgn(...)。切勿根据 SNR 公式手动计算噪声方差 — 使用awgn返回的值,以确保与其内部舍入保持一致。 ofdmdemod后的噪声方差 会按 nFFT 缩放:nVar_sc = nVar * nFFT(FFT 会累加 N 项)convertSNR的 "snr" 类型 = 从 Eb/No 或 Es/No 转换时的每子载波 SNR(每个 OFDM 子载波承载一个符号)。若要将每子载波 SNR 转换为宽带 SNR(用于awgn),请使用convertSNR(snr_sc, "snrsc", "snr", FFTLength=nFFT, NumActiveSubcarriers=nActiveSC)。
关键注意事项
awgn(x, snr, 0) 不适用于 OFDM
OFDM 信号功率取决于 nActiveSC 和 nFFT,而不是 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);
ofdmdemod 必须指定 symOffset
symOffset = cpLen; % skip entire CP (or cpLen/2 for imperfect timing)
rxData = ofdmdemod(rxSig, nFFT, cpLen, symOffset, nullIdx);
单流时,调制器/解调器的输入必须是列向量
所有 Communications Toolbox 调制器(qammod、pskmod 等)都按列处理数据 — 每列是一个独立的信道/数据流。对于单流 OFDM,始终将比特或整数作为列向量传入:
% 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);
只有在同时调制相互独立的 MIMO 数据流或并行码字时,才使用多列。
DC 子载波索引
DC = nFFT/2 + 1。对于 nFFT=64,DC 的索引为 33。始终将其包含在 nullIdx 中。
ofdmEqualize 的 hEst 维度
使用默认的 DataFormat="3-D" 时,hEst 的维度为:
[nSC × NS × NR]— 静态:将相同的估计应用于所有 OFDM 符号[(nSC*nSym) × NS × NR]— 时变:将每个符号的估计折叠到第一维中
直接传入 [nSC × nSym] 是错误的 — 第 2 维会被视为 NS,而不是 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
要插入导频,请将 pilotIdx 和导频符号作为额外参数传递给 ofdmmod/ofdmdemod。信号功率基于 nActiveSC(数据 + 导频),而非仅基于 nDataSC。
完整的导频插入示例见 references/ofdm-pilots-and-estimation.md。
基于导频的信道估计(R2026a)
使用 ofdmPilotConfig + ofdmChannelEstimate 进行基于导频的信道估计,无需完美 CSI。如果尚未检查,请先获取当前 MATLAB 版本,再决定使用 R2026a 工作流还是 R2026a 之前的手动 LS 方法。
ofdmChannelEstimate 工作流与旧版 pilotIdx 方法不同:
nullIdx仅包含保护带(不包含 DC) —— DC 会成为活动网格位置,需要手动将其置零。ofdmmod/ofdmdemod不需要pilotIdx参数 —— 构建包含数据、导频和 DC=0 的完整[nActiveSC x nSym]网格,然后直接传入。- 导频位置由
ofdmPilotConfig指定,而非通过函数参数传入。 rxSym是 3-D 数组:[nActiveSC x nSym x nRx]—— 即使是 SISO,也要添加接收天线维度。
完整代码示例见 references/ofdm-pilots-and-estimation.md。
衰落信道中的 OFDM
信道均衡有两种方法:
-
完美 CSI(R2023a)——使用
ofdmChannelResponse和来自comm.RayleighChannel的路径增益(需要设置PathGainsOutputPort=true)。从info(channel).ChannelFilterCoefficients获取pathFilters。对于时变 SISO,将H(:)传递给ofdmEqualize。 -
基于导频的估计(R2026a)——使用
ofdmPilotConfig+ofdmChannelEstimate。
两种方法都使用 ofdmEqualize 并设置 Algorithm="mmse" 进行最终均衡。在 awgn 中始终使用显式信号功率(而非 'measured')——衰落会改变瞬时功率。
信道配置(Rayleigh/Rician、多普勒、3GPP 配置文件、ofdmEqualize 维度)见 references/ofdm-fading-channel.md。
衰落信道设置
配置 comm.RayleighChannel 或 comm.RicianChannel 时,将 PathGainsOutputPort=true。关键规则:
- 始终设置
SampleRate(默认值为 1 Hz) - 最大路径时延必须小于 CP 时长:
max(PathDelays) < cpLen/SampleRate - 根据速度计算多普勒频移:
fd = (velocity * carrierFreq) / physconst('LightSpeed')
完整设置说明、3GPP 配置文件和准静态衰落见 references/ofdm-fading-channel.md。
同步
处理流程:粗定时 → CFO 估计 → CFO 校正 → 精细定时 → OFDM 解调 → 相位跟踪
关键规则:
- 使用
frequencyOffset应用/校正 CFO(不要手动使用exp(-1j*2*pi*...)) - 使用
timingEstimate进行互相关定时检测 - 在跨符号应用校正前,始终对导频相位估计使用
unwrap
Schmidl-Cox、基于 CP 的定时、Zadoff-Chu 前导码和完整的 Rx 示例见 references/ofdm-synchronization.md。
LDPC 编码
关键规则:
- 使用配置对象搭配
ldpcEncode/ldpcDecode(不要使用已移除的comm.LDPCEncoder/comm.LDPCDecoder) - 仅从奇偶校验矩阵创建配置:
H = ldpcPCM(648, 324); encCfg = ldpcEncoderConfig(H); decCfg = ldpcDecoderConfig(H)。不要传入标量或名称-值对——ldpcEncoderConfig(648)、ldpcEncoderConfig(648, 1/2)和ldpcDecoderConfig(BlockLength=648)都会报错。如果尚未检查,请先获取当前 MATLAB 版本,以决定使用ldpcPCM(R2025a+)还是ldpcQuasiCyclicMatrix(R2021b+)。 - 为编码系统计算 Eb/No 时,在
convertSNR中包含CodingRate - 将
NoiseVariance传递给解调器(如qamdemod),以正确缩放 LLR;换算到频域:nVar_sc = nVar * nFFT - 使用
OutputType="approxllr"计算 LLR
OFDM + LDPC 工作流和多码字成帧见 references/ofdm-ldpc-coding.md。
高级功能
请参阅 references/ofdm-system-guide.md,了解:
- 可变 CP 长度 — 通过行向量
cpLens设置每个符号的 CP - 常见 OFDM 配置 — 类似 WiFi、LTE 和 5G 的参数集
- SNR 转换 — 有关所有
convertSNR用法模式,请参阅matlab-add-awgn技能 - 软解调的噪声方差 —
ofdmdemod后的缩放
交叉引用
matlab-add-awgn— 需要添加噪声并计算 SNR 转换时,请使用此技能。它涵盖所有convertSNR用法模式、awgn的用法,以及噪声方差的捕获。
参考资料加载
当用户询问导频插入、基于导频的信道估计(R2026a ofdmChannelEstimate)或 R2026a 之前的 LS 估计时,加载 references/ofdm-pilots-and-estimation.md。
当用户询问衰落信道配置、Rayleigh/Rician 设置、多普勒计算、3GPP 延迟配置文件或 ofdmEqualize 的维度处理时,加载 references/ofdm-fading-channel.md。
当用户询问定时同步、CFO 估计/校正、Schmidl-Cox、前导码设计或基于导频的相位跟踪时,加载 references/ofdm-synchronization.md。
当用户询问 LDPC 编码、前向纠错、ldpcEncode/ldpcDecode、软解码的 NoiseVariance 或编码 BER 仿真时,加载 references/ofdm-ldpc-coding.md。
当用户询问 SNR 转换详情、常见 OFDM 配置、软解调的噪声方差或可变 CP 长度时,加载 references/ofdm-system-guide.md。
版权所有 2026 The MathWorks, Inc.