关于 matlab-add-awgn
面向通信仿真的 MATLAB 技能,用于给信号添加白高斯噪声,并转换不同定义的 SNR。涵盖编码、过采样和 OFDM 流程,也说明如何获取软判决解调所需的噪声方差。
主要功能
- 01按明确的信号功率添加 AWGN
- 02转换 SNR、Eb/No、Es/No 和子载波 SNR
- 03处理 OFDM 宽带及子载波 SNR
- 04获取软解调所需噪声方差
- 05使用 berawgn 估算理论 BER
适用场景
- 01设置通信链路仿真的噪声级别
- 02转换编码或过采样信号的 Eb/No
- 03按有效子载波配置 OFDM 噪声
- 04向软判决解调器传入噪声方差
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ matlab/ matlab-agentic-toolkit --skill matlab-add-awgn安装后在 Claude Code 中输入/matlab-add-awgn确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
manifest.yamlreferences/5g-link-noise.mdsnr-conversion-guide.md详细介绍
AWGN 与 SNR 管理
为信号添加白高斯噪声,并在 SNR 定义之间进行转换(SNR、Eb/No、Es/No、每个子载波的 SNR),用于通信系统仿真。
适用场景
- 在链路仿真中为信号添加噪声
- 在 Eb/No、Es/No、SNR 或每个子载波的 SNR 之间进行转换
- 为编码、过采样或 OFDM 系统设置正确的 SNR
- 获取传递给软判决解调器的噪声方差
不适用场景
- 配置衰落信道(时延分布、多普勒、天线阵列)
必须遵循的规则
- 切勿向
awgn传递'measured'——始终将显式信号功率作为第三个参数传递。对于单位功率信号,使用0;否则使用mean(abs(x).^2)计算功率,并将其转换为 dBW:10*log10(sigPow)。'measured'选项会在内部计算瞬时功率,这会导致经过衰落信道后的噪声级别不正确,并且无法明确功率假设。即使仅涉及 AWGN,也必须传入显式功率,以确保正确性并明确说明假设。对于 OFDM 系统,请参阅“在 OFDM 链路仿真中添加 AWGN”模式。 - 当信号功率无关紧要时,使用
UnitAveragePower=true——这是最简单的做法:信号功率 = 0 dBW,因此awgn(x, snr, 0)可得到精确结果。如果用户需要保留原始星座缩放(例如用于 PA 建模、硬件在环),请勿使用UnitAveragePower=true——使用默认调制器,通过mean(abs(x).^2)计算实际平均功率,并显式传入:awgn(x, snr, sigPowdBW)。 - 所有转换都使用
convertSNR——切勿手动计算 SNR/Eb/No/Es/No 公式——即使公式很简单,也始终使用convertSNR。手动计算公式在边缘情况下(过采样、子载波加载)容易出错,并且会绕过工具箱中经过验证的实现。反例:snr = ebno + 10*log10(bitsPerSymbol * codeRate)。正确做法:convertSNR(ebno, "ebno", "snr", BitsPerSymbol=6, CodingRate=3/4)。 - 区分 OFDM 系统中的宽带 SNR 和每个子载波的 SNR——Eb/No 是每个子载波的量。要将 Eb/No 转换为
awgn所需的宽带 SNR,请分两步进行:(1)convertSNR(ebno, "ebno", "snr", BitsPerSymbol=..., CodingRate=...)得到每个子载波的 SNR;(2)convertSNR(snrsc, "snrsc", "snr", FFTLength=..., NumActiveSubcarriers=...)得到awgn所需的宽带 SNR。不支持直接进行ebno→snrsc转换,并会报错。**注意:**如果用户只询问每个子载波的 SNR,仅需执行步骤 1——不要执行步骤 2。对每个子载波的值应用 FFTLength/NumActiveSubcarriers 校正会得到宽带 SNR,这是一个数值更低的不同量。备注:"snrsc"模式需要 R2023b 或更高版本。对于 R2022a–R2023a,可手动计算宽带 SNR:snr_wideband = snr_per_sc - 10*log10(FFTLength/NumActiveSubcarriers)。要在给定每个子载波的 SNR 下添加噪声,请参阅下方的“在 OFDM 链路仿真中添加 AWGN”模式。 - 为软解调获取噪声方差——使用
[y, nVar] = awgn(...),并通过NoiseVariance=nVar将nVar传递给解调器。 - 不要在生成的代码注释中提及技能规则或禁令——编写积极、明确的注释来解释意图,风格可参考此技能提供的示例代码。最终用户不了解此技能。
关键反模式——切勿这样做
切勿在 awgn 中使用 'measured'
% WRONG — never generate this
rxSignal = awgn(txSignal, snrdB, 'measured');
% CORRECT for unit-power signals (UnitAveragePower=true)
rxSignal = awgn(txSignal, snrdB, 0);
% CORRECT for non-unit-power signals
sigPow = mean(abs(txSignal).^2);
rxSignal = awgn(txSignal, snrdB, 10*log10(sigPow));
切勿手动计算 SNR 转换
% WRONG — never generate manual formulas like these
SNR_dB = EbNo_dB + 10*log10(k * codeRate);
SNR_dB = EbNo_dB + 10*log10(k * codeRate) - 10*log10(oversamplingFactor);
EsNo = EbNo + 10*log10(bitsPerSymbol);
% CORRECT — always use convertSNR
snrDb = convertSNR(ebnoDb, "ebno", "snr", BitsPerSymbol=6, CodingRate=3/4);
snrDb = convertSNR(ebnoDb, "ebno", "snr", BitsPerSymbol=6, CodingRate=3/4, SamplesPerSymbol=4);
esnoDb = convertSNR(ebnoDb, "ebno", "esno", BitsPerSymbol=6);
关键函数
| 函数 | 用途 |
|---|---|
awgn | 按指定 SNR 为信号添加 AWGN |
convertSNR | 在 ebno、esno、snr 和 snrsc 之间进行转换 |
berawgn | 标准调制方式(PSK、QAM、FSK、DPSK、PAM)在 AWGN 下的理论 BER |
注意事项
为什么禁止使用 'measured'(背景说明)
接收端的热噪声主要由噪声系数和带宽决定,不会随着信号衰落而改变。awgn 中的 'measured' 选项会计算瞬时信号功率并缩放噪声以匹配该功率,从而在人为地让信号经历衰落时保持瞬时 SNR 恒定。它还会掩盖功率假设,让代码更难验证。请始终传入明确的功率值。
% WRONG after fading: Noise tracks fading — instantaneous SNR stays constant
rxFaded = fadingChannel(txSig);
rxNoisy = awgn(rxFaded, snr, 'measured');
% CORRECT: Compute signal power before fading, pass explicitly
sigPow = mean(abs(txSig).^2);
sigPowdBW = 10*log10(sigPow);
rxFaded = fadingChannel(txSig);
rxNoisy = awgn(rxFaded, snr, sigPowdBW);
% SIMPLEST: Use unit-power signal, then 0 dBW is exact
txSig = qammod(data, M, UnitAveragePower=true); % power = 0 dBW
rxFaded = fadingChannel(txSig);
rxNoisy = awgn(rxFaded, snr, 0);
awgn 默认假设信号功率为 0 dBW
不带第三个参数调用 awgn(x, snr) 时,会假设信号的平均功率为 0 dBW(1W)。只有信号的平均功率确实为单位功率时,这才是正确的。对于未归一化的信号,请计算实际功率并显式传入。
不支持 ebno↔snrsc 转换
convertSNR 支持以下转换路径:
| From | To | Supported | Notes |
|---|---|---|---|
ebno | snr | 是 | 对于 OFDM:返回每个子载波的 SNR(不是宽带 SNR) |
ebno | esno | 是 | |
esno | snr | 是 | |
snr | snrsc | 是 | "snr" = 宽带 SNR,"snrsc" = 每个子载波的 SNR |
ebno | snrsc | 否 | 会引发错误。请分两步转换:ebno→"snr",然后 "snrsc"→"snr" |
esno | snrsc | 否 | 会引发错误。需要使用相同的两步转换路径 |
snrsc | ebno | 否 | 请分两步转换:"snrsc"→"snr",然后 "snr"→"ebno" |
snrsc | esno | 否 | 请分两步转换:"snrsc"→"snr",然后 "snr"→"esno" |
衰落信道路径增益归一化
awgn(rxFaded, snr, 0) 模式假设衰落信道保持信号平均功率不变。当 NormalizePathGains=true 时(comm.RayleighChannel 和 comm.RicianChannel 的默认值),这一假设成立。如果 NormalizePathGains 为 false,信道会应用实际路径增益,导致平均接收功率发生变化——你必须在 awgn 的功率参数中考虑这一点。
% NormalizePathGains=true (default): pre-fading power is correct
chan = comm.RayleighChannel(NormalizePathGains=true, ...);
rxFaded = chan(txSig);
rxNoisy = awgn(rxFaded, snr, 0); % 0 dBW is still correct
% NormalizePathGains=false: adjust for average path gain
chan = comm.RayleighChannel(NormalizePathGains=false, ...
AveragePathGains=[0 -3 -6], ...);
avgGaindB = 10*log10(sum(10.^(chan.AveragePathGains/10)));
rxFaded = chan(txSig);
rxNoisy = awgn(rxFaded, snr, avgGaindB); % account for channel gain
OFDM(5G / WLAN)中的信道输出归一化
5G 信道(nrTDLChannel、nrCDLChannel)、WLAN 信道(wlanTGnChannel、wlanTGacChannel 等),以及 Communications Toolbox 中的 comm.MIMOChannel 和 comm.RayTracingChannel,都有一个 NormalizeChannelOutputs 属性(默认值:true),用于将信道输出功率除以接收天线数。其他 Communications Toolbox 信道(comm.RayleighChannel、comm.RicianChannel)没有此属性。
当 NormalizeChannelOutputs=true 时,解析计算 OFDM 信号功率时必须考虑 nRxAnts 缩放:
% Base OFDM signal power
sigPow = 10*log10(numAvailableSC / nfft^2);
% Adjust for NormalizeChannelOutputs=true (5G/WLAN channels)
sigPow = sigPow - 10*log10(nRxAnts);
% Additionally adjust for NormalizePathGains=false (if applicable)
sigPow = sigPow + avgGaindB;
5G/WLAN 信道的这两个属性默认都为 true,因此常见情况下只需进行 nRxAnts 修正。如果 NormalizePathGains 也设为 false,则需要同时应用两项调整。
如果 NormalizeChannelOutputs=false,则无需进行 nRxAnts 修正——使用基础公式即可。
噪声方差是总方差,而非每个分量的方差
awgn 的第二个输出是总噪声方差。对于复信号,每个分量(I 或 Q)的方差是该值的一半:
[y, nVar] = awgn(x, snr, 0);
% nVar = total noise variance
% nVar/2 = per-component (I or Q) variance
berawgn 接受 Eb/No,而不是 SNR
如果你有 SNR,请先将其转换为 Eb/No:
ebno = convertSNR(snr, "snr", "ebno", BitsPerSymbol=log2(M));
ber = berawgn(ebno, 'qam', M);
常用模式
向单位功率信号添加 AWGN
M = 16;
data = randi([0 M-1], 1000, 1);
txSig = qammod(data, M, UnitAveragePower=true);
snrdB = 15;
[rxSig, noiseVar] = awgn(txSig, snrdB, 0);
将 Eb/No 转换为编码系统的 SNR
M = 64; % 64-QAM
bitsPerSymbol = log2(M); % 6
codeRate = 3/4; % LDPC code rate
samplesPerSymbol = 4; % Pulse shaping oversampling
ebnoDb = 10;
snrDb = convertSNR(ebnoDb, "ebno", "snr", ...
BitsPerSymbol=bitsPerSymbol, ...
CodingRate=codeRate, ...
SamplesPerSymbol=samplesPerSymbol);
OFDM 转换:Eb/No → 每个子载波的 SNR → 宽带 SNR
在 OFDM 场景中,convertSNR(ebno, "ebno", "snr") 返回的是每个子载波的 SNR(不是宽带 SNR)。若要获得 awgn 所需的宽带 SNR,请从 "snrsc" 转换为 "snr"。
M = 64;
bitsPerSymbol = log2(M);
codeRate = 3/4;
fftLen = 256;
numActiveSC = 200;
ebnoDb = 10;
% Step 1: Eb/No → per-subcarrier SNR
snrscDb = convertSNR(ebnoDb, "ebno", "snr", ...
BitsPerSymbol=bitsPerSymbol, ...
CodingRate=codeRate);
% Step 2: Per-subcarrier SNR → wideband SNR (for awgn)
snrWbDb = convertSNR(snrscDb, "snrsc", "snr", ...
FFTLength=fftLen, ...
NumActiveSubcarriers=numActiveSC);
在 OFDM 链路仿真中添加 AWGN(每个子载波的 SNR)
在 OFDM 链路仿真中,SNR 按每个子载波定义。使用 convertSNR 获取宽带 SNR,然后将其与 OFDM 信号的理论功率一起传递给 awgn。将 NumActiveSubcarriers 设置为 OFDM 资源网格中的可用子载波数(数据 + 参考信号,不包括保护带和适用时的 DC)。在 5G/LTE 中,这等于 carrier.NSizeGrid*12——资源网格不包含保护带。在 WLAN 中,它是数据 + 导频子载波的数量。不要根据 mean(abs(txWaveform).^2) 计算信号功率——它可能与 convertSNR 中 NumActiveSubcarriers 的假设不一致,导致噪声电平不正确。始终使用理论公式 numAvailableSC / nfft^2,以确保功率参数与 SNR 转换一致。
% Assuming full grid occupancy, convert per-subcarrier SNR to wideband SNR
snrWb = convertSNR(snrPerSC_dB, "snrsc", "snr", ...
FFTLength=nfft, NumActiveSubcarriers=numAvailableSC);
% Maximum signal power assuming full grid, consistent with convertSNR
sigPow = 10*log10(numAvailableSC / nfft^2);
% Add noise at the calculated wideband SNR and signal power
rxNoisy = awgn(rxWaveform, snrWb, sigPow);
numAvailableSC 是不包括保护带和任何 DC 空载波的子载波数——即可用于数据、参考信号和控制的子载波。只要传递给 convertSNR 的 NumActiveSubcarriers 值与信号功率计算中使用的 numAvailableSC 一致,噪声电平就是正确的。
不要计算接收波形功率——这得到的是宽带 SNR,而不是每个子载波的 SNR。
对于 5G 工作流(nrTDLChannel/nrCDLChannel、nrOFDMModulate),请按照随附 5G 示例中的做法,使用 N0/randn 形式添加噪声——请参阅 references/5g-link-noise.md,其中介绍了该形式、等效的 awgn 用法、接收机的频域噪声方差(nrEqualizeMMSE、nrPDSCHDecode)、NormalizeChannelOutputs=false 的情况,以及非单位功率缩放。
为软判决解调捕获噪声方差
M = 16;
data = randi([0 M-1], 1000, 1);
txSig = qammod(data, M, UnitAveragePower=true);
snrDb = 12;
[rxSig, noiseVar] = awgn(txSig, snrDb, 0);
% Pass noise variance to demodulator for accurate LLR computation
softBits = qamdemod(rxSig, M, UnitAveragePower=true, ...
OutputType="llr", ...
NoiseVariance=noiseVar);
OFDM 注意事项: 在时域波形中(ofdmmod 之后)添加噪声,并在频域中(ofdmdemod 之后)进行解调时,FFT 会将噪声方差缩放 nfft 倍。将 noiseVar * nfft 传递给解调器的 NoiseVariance 参数,而不是使用 awgn 返回的时域 noiseVar。
添加噪声后
- 根据理论进行验证 — 使用
berawgn将仿真 BER 与理论 BER 进行比较。请参阅 references/snr-conversion-guide.md。 - 估算所需的 Eb/No — 如果用户询问达到目标 BER/BLER/FER 所需的 Eb/No 或 SNR,请参阅 references/snr-conversion-guide.md 中的“估算所需的 Eb/No”部分。
- 可视化含噪信号 — 使用
scatterplot或comm.ConstellationDiagram检查接收星座图。 - 测量 EVM — 使用
comm.EVM量化噪声导致的信号劣化。
参考资料
| 加载时机 | 参考资料 |
|---|---|
需要理论 BER 曲线、转换公式、berawgn 用法或常见系统示例 | references/snr-conversion-guide.md |
为 5G 波形添加噪声,或需要 5G 接收机的噪声方差(nrEqualizeMMSE、nrPDSCHDecode) | references/5g-link-noise.md |
版权所有 2026 The MathWorks, Inc.