资讯详情

QPSK/8PSK/16PSK/16QAM信道容量曲线:蒙特卡洛仿真与MATLAB实现

📅 2026/10/14 5:10:44 | 华诺云谱 👁 阅读
QPSK/8PSK/16PSK/16QAM信道容量曲线:蒙特卡洛仿真与MATLAB实现
简介这是一份面向通信工程专业学生与MATLAB仿真学习者的技术文档系统整理了QPSK、8PSK、16PSK和16QAM四种调制方式在高斯白噪声信道下的信道容量曲线推导与计算过程。文档以《Channel Codes: Classical and Modern》为参考从二维M元信号集合的复数表示和星座图出发结合复高斯噪声概率密度函数逐步推导出M进制调制容量公式并详细解释了容量公式中期望项的计算方法。随后给出了从信噪比到Eb/N0的转换思路以及在MATLAB中通过遍历-10~35 dB信噪比范围、使用大样本采样来估计容量值的完整程序段包含四种调制方式的星座图设置可直接运行或二次修改。包内共1个doc文件大小约345KB既有理论推导也有可复现的源代码适合用于通信原理课程设计、毕业设计或调制理论自学。目前已有1352人学习下载是一份兼顾理论深度与工程实践的实用参考资料。1. 不只有香农公式这份资源把 QPSK、8PSK、16PSK、16QAM 的信道容量曲线一次算清信道容量曲线是通信系统设计里绕不开的参照系给定信噪比一个调制方式到底能撑起多少 bit/s/Hz 的可靠传输直接决定编码方案和调制阶数的选择。很多人上手就写C 0.5*log2(1SNR)但那是连续高斯输入下的极限值换成 QPSK、8PSK、16PSK、16QAM 这些离散星座容量公式要基于互信息重新推一遍。这份课程设计资源把推导过程和 MATLAB 实现都打包了核心是用蒙特卡洛采样估计二维复高斯信道下的互信息然后画出容量与 Eb/N0 的关系曲线。适合正在做数字调制课程设计的学生、需要估算系统编码余量的通信工程师以及任何想把星座图长什么样和容量上限是多少对应起来的人。2. 高斯信道下 M 元调制的容量从连续互信息到可计算的蒙特卡洛形式2.1 为什么离散星座不能直接套香农公式香农容量公式给出的 AWGN 信道容量是假设输入信号服从连续高斯分布时取得的理论上限。实际系统里输入信号取自有限集合比如 QPSK 只有四个复平面上的点携带的信息量受限于星座点数也受限于这些点之间的距离。在高信噪比下M 元调制的容量上限趋近 log2(M) bit/符号而不是像高斯输入那样随 SNR 无界增长。这就是为什么需要重新推导针对离散输入集合的容量表达式。二维 M 元信号集合 {s_m} 中的每个符号都可以用两个归一化正交函数的线性组合表示在基带等价于一个复数。高斯信道中二维 M 进制调制的容量公式可以看成二进制情况的直接推广。核心关系是互信息I(X;Y) h(Y) - h(Z)其中 h(Y) 是接收信号 y 的微分熵h(Z) 是复高斯噪声的微分熵。因为噪声是二维复高斯方差为 N0其微分熵是固定的h(Z) log2(pi * e * N0)所以容量计算的关键落到了 h(Y) 上。接收信号 y 的概率密度不是简单的高斯分布而是 M 个高斯分量的混合每个分量对应一个星座点 s_m。这个混合密度直接决定了互信息的大小。2.2 容量公式的分步推导p(y) 的混合高斯结构在等概率发送的前提下接收信号的概率密度是 M 个复高斯密度的平均p(y) (1/M) * sum_{m1}^M p(y|s_m) p(y|s_m) (1/(pi*N0)) * exp(-|y - s_m|^2 / N0)噪声每一维的方差是 N0/2所以复噪声总的方差是 N0这解释了密度函数中系数是 pi*N0 而不是 sqrt 形式。把 h(Y) 写成期望形式h(Y) -E[log2 p(y)]这个期望没有闭式解但可以用蒙特卡洛估计。生成 L 个带噪样本 y_l每个样本都独立地从一个随机选中的星座点加复高斯噪声得到然后用样本均值近似期望C ≈ - (1/L) * sum_{l1}^L log2( (1/M) * sum_{m1}^M (1/(pi*N0)) * exp(-|y_l - s_m|^2 / N0) ) - log2(pi * e * N0)这个形式就是代码里log2py和Capacity两行表达式的来源。公式4里的第一项是 log2(p(y)) 的均值用样本平均计算第二项是噪声熵直接带入 pieN0。2.3 蒙特卡洛估计的三个关键参数样本数、信噪比范围和能量归一化蒙特卡洛估计的精度取决于样本数 L。代码里sample66666是一个偏大的取值理论上每个信噪比点都有六万多个随机样本均值估计的方差足够小曲线会很光滑。但代价是计算量每个样本都要遍历 M 个星座点计算 exp四层循环信噪比 × 样本 × 星座点 × 四种调制方式跑起来很慢这一点在后面的避坑章节展开。信噪比范围设为snr-10:1:35覆盖了从容量几乎为零的低信噪区到容量接近 log2(M) 的高信噪区。注意这个 snr 是 Es/N0 意义上的信噪比不是 Eb/N0。代码里通过PsPn10.^(0.1*snr)得到功率比然后用NoEs/PsPn(i)算出每个符号对应的噪声方差。Es 是调制信号的平均能量由星座点的模值平方均值求得。这个过程成立的前提是功率比等于能量比因为符号周期相同功率和能量只差一个常数因子。能量归一化是这里最容易被忽略的点。四种调制的 Es 必须一致画出来的曲线才有可比性。代码里 QPSK、8PSK、16PSK 的星座点都落在单位圆上Es1但 16QAM 用的是坐标 1 和 3 的网格Es(428104*18)/1610。这导致 16QAM 曲线和三种 PSK 曲线不在同一个能量基准上比较后面会专门讨论这个问题。3. MATLAB 代码逐段拆解星座初始化、噪声叠加与三层循环3.1 信号空间与四种星座的定义方式代码先定义信噪比范围和样本数然后按调制阶数依次生成星座点。QPSK 的四个点直接落在复平面的 (±1, ±1) 上8PSK 和 16PSK 都在单位圆上按等角度分布。8PSK 的坐标用手写的三角函数值给出16PSK 也类似都是角度从 0 开始、每次增加 pi/4 或 pi/8 的圆周点。16QAM 则是 1 和 3 组成的 4×4 网格。% QPSK 星座四个点落在 (±1, ±1) signal_space(1) complex(1, 1); signal_space(2) complex(-1, 1); signal_space(3) complex(-1, -1); signal_space(4) complex(1, -1); % 8PSK 星座单位圆上 8 等分Es1 signal_space(1) complex(1, 0); signal_space(2) complex(cos(pi/4), sin(pi/4)); signal_space(3) complex(0, 1); signal_space(4) complex(cos(3*pi/4), sin(3*pi/4)); signal_space(5) complex(-1, 0); signal_space(6) complex(cos(5*pi/4), sin(5*pi/4)); signal_space(7) complex(0, -1); signal_space(8) complex(cos(-pi/4), sin(-pi/4));这段代码的特点是手写而非循环生成。对于 QPSK 和 8PSK手写可读性好但 16PSK 的 16 个点手写就很容易写错角度符号。对比 16PSK 代码里第 10 到第 16 个点角度从 7*pi/8 开始取负值是沿着单位圆从第一象限顺时针绕回。更稳妥的写法是用exp(j*theta)循环生成theta 取(0:M-1)*2*pi/M既减少笔误又方便扩展到 32PSK。16QAM 的坐标也有规律是 {-3,-1,1,3} 两两组合用两层 for 循环加一个索引映射表可以取代 16 行手写赋值。三种 PSK 的星座点都在单位圆上所以 Es 都是 1这也让三种 PSK 曲线可以直接用同一个 No 计算公式。16QAM 就不同了它的 Es 是 10代码里单独算了一次Essum(abs(signal_space).^2)/M这一步没有错但埋下了和 PSK 曲线对比时能量基准不一致的问题。3.2 蒙特卡洛主循环随机信号生成、复高斯噪声叠加与 pysm 累加主循环结构分为三层外层遍历信噪比中层生成 sample 个输入符号并叠加噪声内层对每个接收样本计算 log2(p(y)) 的贡献。以下是核心循环代码for i1:1:length(snr) No Es / PsPn(i); % 噪声方差由能量比等于功率比得到 for j1:1:sample x(j) signal_space(floor(rand*M)1); % 等概率随机选取星座点 end y x sqrt(No./2) * complex(randn(1,sample), randn(1,sample)); for j1:1:sample pysm 0; for b1:1:M pysm pysm exp(-(abs(y(j)-signal_space(b))).^2 / No); end log2py(j) log2(1/M/(pi*No) * pysm); end Capacity(i) -mean(log2py) - log2(pi*exp(1)*No); endx(j) signal_space(floor(rand*M)1)用rand生成 [0,1) 均匀随机数乘 M 后取整得到 1 到 M 的索引。这个写法对但每次调用rand都有函数开销后面会提到换成randi更干净。噪声叠加行是关键sqrt(No./2) * complex(randn, randn)。复噪声的实部和虚部各占 N0/2 方差合起来的复噪声方差是 N0和公式 (3) 中的密度函数系数一致。这里容易犯的错是直接用sqrt(No) * randn只加实噪声那相当于把二维问题退化成一维容量结果会和正确值差一截。内层pysm累加的是 exp(-|y-s_m|^2/No)也就是公式里高斯分量的非归一化部分。除以1/M/(pi*No)后取 log2得到 log2(p(y)) 的单样本估计。最后Capacity -mean(log2py) - log2(pi*exp(1)*No)mean直接给出期望的样本均值减去噪声熵就是互信息。这一段逻辑和公式 (4) 完全对应没有多余的技巧但执行效率是最差的——每算一个 y_j 都要循环 M 次 expsample 取 66666 时这一层循环要跑约三十万次乘加全程序跑完需要等待较长时间。3.3 从 SNR 到 Eb/N0 的坐标变换容量单位与换算公式画图时横轴用 Eb/N0 而不是 SNR因为不同调制阶数每符号携带的比特数不同只有换算到每比特能量才能公平比较。换算公式是Eb/N0 (Ps/Pn) / CC 的单位是 bit/符号所以 (Ps/Pn)/C 就是每比特能量与噪声谱密度之比取 10*log10 后得到 dB 值。代码里写作EbNo 10*log10(PsPn./Capacity);这个式子成立的前提是 Capacity 严格为正。在低信噪比区域蒙特卡洛估计的容量可能因为样本噪声变成很小的负数直接除会出现负的 Eb/N0导致曲线出现不合理的急剧下降。这个问题在后面避坑章有具体处理办法。画图部分用四种线型区分调制方式axis([-2,20,0,5])把横轴限制在 -2 到 20 dB纵轴限制在 0 到 5 bit/符号。QPSK 理论极限是 2 bit/符号16QAM 是 4 bit/符号所以纵轴取 5 够用。text函数在 x18 的位置放置图例文字避免了 legend 在不同 MATLAB 版本下的兼容性问题。4. 四种调制的曲线对比与公平性能量归一化的关键细节4.1 同一 Es 下三种 PSK 的容量排序与直觉解释QPSK、8PSK、16PSK 在单位圆上等间隔分布Es 都等于 1它们的容量曲线可以直接对比。直观规律是调制阶数越高高信噪比下的容量上限越高但达到上限所需的 Eb/N0 也越高。QPSK 曲线从大约 0 dB 开始快速爬升在 10 dB 左右就接近 2 bit/符号的渐近线8PSK 需要更高的 Es/N0 才能拉开和 QPSK 的差距但上限是 3 bit/符号16PSK 的 16 个点挤在单位圆上相邻点距离最小低信噪比下误码概率更高容量曲线在三种 PSK 里爬得最慢但最终趋近 4 bit/符号。这个排序的物理意义在于星座点数越多每个符号携带的信息量越大但星座点之间的欧氏距离随之减小抗噪声能力下降。容量曲线反映的是这个折中的定量结果——在某个 Eb/N0 以下用低阶调制反而能获得更高的可靠速率。4.2 16QAM 的 Es10 问题与 PSK 对比前必须归一化16QAM 的星座点坐标是 ±1 和 ±3 的组合平均能量是 10而三种 PSK 的 Es 是 1。代码里 16QAM 部分重新算了 Es所以它自己的曲线是自洽的但和 PSK 曲线放在同一张图里对比时能量基准不一样。16QAM 的曲线整体会比它在 Es1 情况下右移 10*log10(10)10 dB也就是说如果不做归一化16QAM 看起来在低信噪比下容量明显低于 QPSK但这其实是能量没对齐造成的假象。常见做法是把 16QAM 的星座点除以 sqrt(10) 再做仿真让所有调制方式的 Es 都等于 1这样四条曲线就在同一个能量基准上比较。坐标缩放不影响容量曲线的形状只影响横轴位置。如果你用这份代码做课程设计或系统级仿真建议把 16QAM 星座点统一除以 sqrt(Es)既方便对比也符合大多数通信教材里星座图归一化的习惯。4.3 从曲线读取设计结论编码门限与调制阶数选择容量曲线的用途不只是展示上限更重要的是为编码方案选择提供依据。一个实用的读法是给定目标频谱效率比如 2 bit/s/Hz看哪种调制在更低的 Eb/N0 下能达到这个容量那个调制就是能量效率更优的选择。QPSK 在 2 bit/s/Hz 附近所需的 Eb/N0 明显低于 16QAM 在同一频谱效率下的需求这意味着用 QPSK 加码率 1/2 的编码可能比用 16QAM 加高码率编码更容易逼近容量。另一个读法是看曲线拐点。容量曲线在低信噪比区域缓慢爬升接近渐近线时明显变平拐点大致对应星座点间距与噪声标准差相当的临界区域。在实际系统设计中工作点一般选在容量曲线下方 1~2 dB 处预留编码调制余量。这份资源的曲线可以作为这种预算分析的参照。5. 复现避坑指南样本数、负容量、循环提速与曲线截断5.1 sample66666 跑一次要等几分钟现象程序在for j1:1:sample和for b1:1:M两层循环里反复算 exp46 个信噪比点、四种调制16QAM 还要单跑一遍总计约 46×4×66666×16 次 exp 运算普通笔记本跑一次要十几分钟信噪比点再多一点就直接失去耐心。原因蒙特卡洛估计确实需要足够多样本才能让曲线平滑但 66666 这个数字没有理论依据。容量估计的均方误差与样本数成反比样本数到 1 万左右时曲线的抖动已经在可接受范围。解决把sample降到 20000或用parfor替换外层信噪比循环。更彻底的办法是向量化内层循环一次性算出 sample×M 的指数矩阵后面章节给出具体代码。改完参数后先用sample5000验证曲线形状确认稳定后再放大样本数画正式图。5.2 低信噪比下容量出现负值现象snr-10 dB 附近Capacity(i)算出负数有时候小到 -0.3画图时纵轴出现负值曲线穿到横轴下方。原因蒙特卡洛估计本身有方差。真实容量在极低信噪比下趋近于 0理论上不可能为负但样本均值估计 h(Y) 时某些样本的 log2(p(y)) 波动会把均值推到噪声熵以下产生轻微负数。sample 越小、信噪比越低这种现象越明显。解决把负容量截断为 0Capacity(i)max(0, Capacity(i))。这个处理不影响有效区域的曲线形状因为负值只出现在容量接近 0 的低信噪区。另一个补充手段是增大样本数但截断更简单直接且符合容量非负的物理约束。5.3 16QAM 曲线比其他调制低一大截怎么调都对不上现象同样在 15 dB Eb/N0 处QPSK 容量约 2 bit/符号16QAM 算出来只有 3 左右甚至更低曲线整体右移约 10 dB。原因16QAM 的 Es10而三种 PSK 的 Es1。代码里 16QAM 部分单独计算了 Es所以它的 NoEs/PsPn 和 PSK 路径不统一等于在比 PSK 高 10 dB 的 Es/N0 点上做仿真曲线自然右移。解决在 16QAM 星座初始化之后、进入信噪比循环之前加一行归一化signal_space signal_space / sqrt(Es);再重新计算Es1。这样四种调制就在同一能量基准上画图对比才有意义。这是复现这份代码时最容易踩的坑强烈建议先固定 Es 再跑仿真。5.4 从 SNR 转 Eb/N0 时曲线出现剧烈抖动或断点现象EbNo10*log10(PsPn./Capacity)这行执行后某些点的 Eb/N0 变成很大的正数或负数曲线出现尖刺。原因当 Capacity 接近 0 时除法结果接近无穷取对数后数值不稳定。特别是低信噪比区容量估计的微小波动会被除法放大产生极端值。另外如果容量为负log10会得到 NaN曲线直接断裂。解决先做容量截断第 5.2 条再做 Eb/N0 转换。转换后对超出axis([-2,20,0,5])范围的数据点可以不处理因为 MATLAB 画图时会自动裁剪但要确认没有 NaN 点否则整条曲线都会消失。5.5 画图时曲线在边界被切断图例文字被截现象axis([-2,20,0,5])设定后snr 范围是 -10 到 35对应 Eb/N0 范围可能超过 20 dB曲线在 x20 处被垂直切断看上去像容量饱和后又突然掉下来。原因坐标轴范围写死而不同调制方式在低信噪比下的 Eb/N0 可以远大于 20。特别在容量趋近 0 的区间Eb/N0 会飙升到几十甚至上百 dB超出横轴范围。解决把横轴范围放宽到 [-2, 25] 或者干脆不设 x 轴上限用xlim([-2 25])配合ylim([0 5])让曲线完整显示。图例文字放在 x18 处也可能和曲线重叠改成text的位置按各曲线在右上角的实际走势微调或者直接用legend在 MATLAB 2019 之后的版本里有自动防重叠功能。6. 让曲线更快更稳三个小改动与一条验证技巧第一个改动是向量化内层循环。原来的三层循环可以压缩成两层用 MATLAB 的矩阵运算一次算出所有样本对所有星座点的距离for i1:1:length(snr) No Es / PsPn(i); x_idx randi(M, 1, sample); % 直接生成整数索引 x signal_space(x_idx); % 抽取随机星座点 y x sqrt(No/2) * complex(randn(1,sample), randn(1,sample)); dist2 abs(bsxfun(minus, y., signal_space(:).)).^2; % sample×M 距离矩阵 py sum(exp(-dist2/No), 2) / M / (pi*No); % 每个样本的 p(y) 估计 log2py log2(py); Capacity(i) -mean(log2py) - log2(pi*exp(1)*No); endbsxfun在旧版本 MATLAB 里可用新版本直接支持y. - signal_space(:).的隐式扩展。距离矩阵一次性算出来避免逐样本逐星座点的 exp 循环速度提升通常在十倍以上。randi(M,1,sample)比floor(rand*M)1更简洁也避免每次调用 rand 的冗余开销。第二个改动是给容量加截断保护在Capacity(i)计算后加一行Capacity(i) max(0, Capacity(i));防止低信噪比下的负值影响 Eb/N0 转换。这是让曲线在低信噪区看起来干净的唯一必要处理。第三个改动是固定随机种子。在程序开头加rng(42);这样每次跑出来的曲线完全一致方便调参数时对比差异。调优阶段用rng(shuffle)观察不同种子下的波动范围确认曲线形状的稳健性。验证技巧是画一张对照图把 QPSK 的仿真容量曲线和 AWGN 容量公式C log2(1snr)画在同一张图上QPSK 在高信噪比区应该贴着这条理论上限走因为四个点可以等效近似连续高斯输入。如果 QPSK 曲线明显低于理论线说明样本数不够或噪声方差算错了如果曲线在高信噪比区超过 log2(M)说明容量估计出了问题需要回头检查星座点坐标。另外可以验证 8PSK 在 Eb/N0-1.59 dB 处容量不超过 0因为 -1.59 dB 是整个 AWGN 信道的香农极限任何离散调制在该点都不可能取得正速率。我从那以后每次复现容量仿真都强制先做一遍能量归一化和随机种子固定再开始调参。这个方法帮我少走了不少弯路数据也对得上教材曲线。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑