资讯动态

4QAM/16QAM调制解调Matlab仿真:从星座图到误码率曲线

发布时间:2026/10/13 22:47:14 来源:尧图企业网站定制
简介这是一份面向通信工程专业学生及MATLAB初学者的调制解调仿真资源围绕4QAM与16QAM两种调制方式完整实现从调制、加噪、解调到误码性能分析的全流程并配有系统框图与各点波形观察可用于课程设计、毕业设计或通信原理实验。压缩包内含16个M文件体积仅11KB代码结构清晰按调制、解调、误码率计算、星座图绘制等功能拆分方便读者对照学习各模块原理并自行修改参数。目前已有5232人学习该资源适合需要快速掌握QAM仿真实现、理解星座图与误码率曲线含义的读者。通过运行自带脚本可直观获得两种调制方式的星座图、误码率曲线以及各关键节点波形帮助理解系统设计中的因果逻辑与性能差异节省从零搭建仿真环境的时间。1. 4QAM、16QAM 调制与解调仿真电路从星座图看到误码率曲线的一次完整跑通做通信物理层仿真的人早晚会卡在同一道坎上教材里把 4QAM、16QAM 调制与解调仿真电路画得干干净净星座图上几个点一目了然可轮到自己用 Matlab 搭链路时出来的星座图要么旋转了 45 度要么误码率曲线比理论值差出一个数量级。这篇文章要解决的就是把这套仿真电路从「看着懂」变成「跑得通」——从 QAM 的星座图映射规则开始到加噪、判决、误码率统计的每一行代码再到最容易翻车的参数设置和噪声归一化。适合正在做移动通信课程设计、准备复试或刚接触调制解调仿真的同学也适合想快速搭一条 BER 验证链路、后续扩展到 64QAM 的工程师。全部代码不依赖通信工具箱之外的任何东西复制到 Matlab 里就能跑。2. QAM 的星座图与映射规则为什么 4QAM 和 16QAM 的判决边界完全不同2.1 从 4QAM 到 16QAM每符号多携带两个比特代价是什么4QAM 本质上就是 QPSK一个符号携带 2 个比特星座点位于 (±1, ±1) 的四个角上。16QAM 把每符号比特数提升到 4 个星座图变成 4×4 的方阵幅度从 ±1 扩展到 ±1 和 ±3 的组合。看起来只是点数变多实际上判决边界从「过零轴」变成了「每隔 2 个单位一条分界线」相邻星座点之间的欧氏距离从 2√2 缩短到 2抗噪声能力明显下降。这就是 QAM 的核心权衡带宽效率随星座点数对数增长但同一信噪比下的误码率也在恶化。仿真时你会直观看到16QAM 的 BER 曲线比 4QAM 的曲线向右平移约 4~5 dB——想达到同样的误码率16QAM 需要更高的发射功率。这个代价在星座图上表现为「点更密」在误码率曲线上表现为「曲线更靠右」。功率归一化是这里最容易忽略的一步。4QAM 四个点的平均能量是 216QAM 十六个点的平均能量是 10。如果直接把星座点送进 AWGN 信道不对星座做能量归一化那么同样一个 SNR 值下16QAM 收到的信号幅度比 4QAM 大误码率统计自然失真。常见的做法是把整个星座除以其均方根能量让平均符号能量 Es 1这样噪声方差和 SNR 的换算就干净了。2.2 Gray 映射 vs 自然映射相邻点差几位直接决定 BER 曲线形状QAM 星座图的每个点都要绑定一组比特。自然映射下星座点按二进制顺序排列相邻点之间可能差 2 个甚至更多比特Gray 映射则保证欧氏距离最近的两个点只差 1 个比特。在 AWGN 信道里绝大多数判决错误发生在相邻星座点之间Gray 映射能把一个符号错误对应到 1 个比特错误而不是 2 个这让高信噪比下的误码率曲线明显更陡。4QAM 的 Gray 映射很直观水平方向看 I 路垂直方向看 Q 路每个维度都是 2-PAM比特 0 对应 -1比特 1 对应 1。16QAM 稍微复杂每个维度是 4-PAM需要 2 个比特决定幅度这个映射不能用普通的二进制顺序而要按二进制反射 Gray 码排列。表格如下。维度比特对应幅度00-301-1111103注意表格里 10 排在 11 后面这是 Gray 码的典型特征按幅度从负到正看对应的比特序列是 00、01、11、10任何相邻幅度只差 1 个比特。16QAM 的每个符号由 I、Q 两路各取 2 比特组合而成比如比特 0101 表示 I 路 01幅度 -1、Q 路 01幅度 -1对应星座点 -1-1j。2.3 仿真电路的模块划分发射、信道、接收三段各管什么一套完整的 QAM 调制解调仿真电路在 Matlab 里通常拆成三块发射端把随机比特映射成星座点并做能量归一化信道加入高斯白噪声噪声功率由设定的 Eb/N0 换算得到接收端根据接收符号到所有星座点的欧氏距离做最近邻判决再把判决出的星座点索引还原成比特。用脚本实现时这三块分别对应「比特到星座点查表」「复噪声叠加」「距离判决与比特还原」。用 Simulink 实现时对应的是 Bernoulli Generator、Rectangular QAM Modulator Baseband、AWGN Channel、Rectangular QAM Demodulator Baseband 和 Error Rate Calculation 这几个模块的连线。脚本方式的好处是每个中间变量都能停下来看星座图和 BER 曲线的产生过程完全透明Simulink 的好处是模块连好后改参数方便适合做课程要求的电路级框图演示。下面章节的代码以脚本为主最后会补充 Simulink 对应的参数设置。3. 用 Matlab 搭建 QAM 仿真链路从星座图到误码率曲线的完整脚本3.1 先画星座图用最小脚本验证映射表是否正确在跑误码率之前建议先做一件事把星座图画出来肉眼确认每个点的位置和标签。这一步能挡住后面一半的坑比如 I/Q 接反、Gray 映射顺序写错、归一化因子漏掉。% 4QAM 星座图行序对应比特值 00,01,10,11 constel_4 [-1-1j; -11j; 1-1j; 11j]; % 16QAM 星座图按比特值 0000~1111 顺序排列 % 每维度幅度映射00--3, 01--1, 10-3, 11-1 constel_16 [-3-3j; -3-1j; -33j; -31j; ... -1-3j; -1-1j; -13j; -11j; ... 3-3j; 3-1j; 33j; 31j; ... 1-3j; 1-1j; 13j; 11j]; figure; subplot(1,2,1); plot(real(constel_4), imag(constel_4), o, MarkerSize, 8); grid on; axis equal; title(4QAM 星座图); subplot(1,2,2); plot(real(constel_16), imag(constel_16), o, MarkerSize, 6); grid on; axis equal; title(16QAM 星座图);这套代码用查表方式定义星座点constel_4 的第 i 行就是比特值 i-1 对应的复数符号。16QAM 的每维度映射采用 Gray 序00、01、10、11 对应 -3、-1、3、1这个顺序确保相邻幅度只差 1 比特。画出来之后16QAM 的十六个点应该均匀分布在 [-3,-1,1,3]×[-3,-1,1,3] 的网格上不会有斜线或重叠。运行这段脚本时注意 axis equal否则纵轴横轴比例不一致星座图会看起来像被压扁了。画完后可以把constel_16的值打印出来对照上一章的表格逐行核对这一步花两分钟能省掉后面解码时查半天标签对应关系的麻烦。3.2 主仿真脚本加噪、判决、统计误码率的完整循环下面的脚本是整条仿真链路的核心包含了发射、AWGN 信道、最近邻判决和误码率统计。为了减少对通信工具箱的依赖判决部分用手写的最小距离法实现这样即使没有 qammod/qamdemod 也能跑。% QAM 调制解调仿真主脚本 % 参数设置 M 16; % 4 或 16 k log2(M); % 每符号比特数 nSym 2e4; % 每个信噪比点仿真的符号数 EbN0dB 0:2:14; % 扫描的 Eb/N0 范围单位 dB % 选择星座图 if M 4 constel [-1-1j; -11j; 1-1j; 11j]; else constel [-3-3j; -3-1j; -33j; -31j; ... -1-3j; -1-1j; -13j; -11j; ... 3-3j; 3-1j; 33j; 31j; ... 1-3j; 1-1j; 13j; 11j]; end % 能量归一化让平均符号能量 Es 1 Es mean(abs(constel).^2); constel_n constel / sqrt(Es); % 生成随机比特流并映射为星座点 rng(0); % 固定随机种子保证结果可复现 bits randi([0 1], nSym, k); idx bits * (2.^(k-1:-1:0)).; % 二进制转十进制行向量尺寸 nSym×1 tx constel_n(idx 1).; % 发射符号序列转成行向量 ber zeros(size(EbN0dB)); for i 1:length(EbN0dB) % Eb/N0 转 Es/N0再计算复噪声标准方差 EbN0lin 10^(EbN0dB(i)/10); N0 1 / (k * EbN0lin); % 因为 Es1 noise sqrt(N0/2) * (randn(1, nSym) 1j*randn(1, nSym)); rx tx noise; % 最近邻判决逐符号计算到所有星座点的距离 rxIdx zeros(1, nSym); for n 1:nSym dist2 abs(rx(n) - constel_n.).^2; [~, rxIdx(n)] min(dist2); end % 判决索引还原比特逐位比对统计误码率 rxBits zeros(nSym, k); for n 1:nSym val rxIdx(n) - 1; % 索引转十进制值 for b 1:k % 十进制转回比特向量 rxBits(n, k-b1) mod(val, 2); val floor(val / 2); end end ber(i) sum(sum(rxBits ~ bits)) / (nSym * k); end % 画星座图和误码率曲线 figure; subplot(1,2,1); scatter(real(rx), imag(rx), 6, filled); hold on; plot(real(constel_n), imag(constel_n), ro, MarkerSize, 8); grid on; axis equal; title(接收星座图含噪声); subplot(1,2,2); semilogy(EbN0dB, ber, bo-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER); title(QAM 误码率曲线);主循环里最关键的是噪声方差计算。因为星座图已经归一化到 Es1所以单边噪声功率谱密度 N0 1 / (k × EbN0lin)复噪声的每个维度实部和虚部各分配 N0/2。这个换算关系如果写错整条 BER 曲线会整体向左或向右偏移几个 dB而且偏移量随 M 不同而变化看起来像「不知哪里出了 bug」。最近邻判决部分遍历每个符号和每个星座点当 nSym2e4、M16 时内层运算量约 32 万次距离计算Matlab 几秒内能跑完作为教学演示足够。3.3 叠加上理论曲线验证仿真结果是否可信仿真跑出来的误码率曲线需要和理论值对照否则你无法判断是链路写对了还是错得正好对称。对 Gray 映射的方形 M-QAM高信噪比下有一个常见的近似公式可以直接用% 理论 BER 近似公式Gray 映射、AWGN 信道 EbN0lin 10.^(EbN0dB/10); thBer (2/k) * (1 - 1/sqrt(M)) .* erfc(sqrt(3 * k * EbN0lin / (2*(M-1)))); % 叠加到之前的误码率图上 semilogy(EbN0dB, thBer, r-, LineWidth, 1.5); legend(仿真, 理论近似);这个近似公式的本质是把 M-QAM 的符号错误率除以每符号比特数 k。对于 4QAMM4、k2 代入后恰好得到 QPSK 的理论误码率 0.5×erfc(sqrt(Eb/N0))对于 16QAM系数是 0.375erfc 的参数里包含 3k/(2(M-1)) 这个因子对应常见教材里 16QAM 的 BER 表达式。需要说明的是这是一个近似式在中低信噪比下和精确值有细微偏差但工程上用来验证仿真链路已经足够。仿真曲线和理论曲线重合到同一量级说明噪声添加、判决、误码统计都没问题。如果仿真曲线比理论值差一截优先检查能量归一化和 Gray 映射如果仿真曲线比理论还好那基本可以断定判决时用了发射端信息属于典型的「作弊」bug。4. 仿真参数怎么定Gray 映射、Eb/N0 换算与蒙特卡洛次数4.1 为什么必须用 Gray 映射自然映射会让 BER 曲线变平如果不加 Gray 映射直接按二进制顺序给 16QAM 星座点标号那么相邻星座点之间平均差 2 个比特左右。判决错误发生在相邻星座点时一个符号错误会带来两个比特错误BER 大约是 Gray 映射的两倍。在 BER 曲线上看自然映射的曲线整体抬升而且 slope 在高信噪比段明显变缓。Matlab 的通信工具箱里qammod(data, M, gray) 和 qamdemod 能直接帮你做 Gray 映射但要注意它们内部的星座点顺序和手写查表不一定一致。我在 3.2 节脚本里用的是手写查表判决索引到比特的还原也是自洽的这两种方式不要混用。如果改用 qammod/qamdemod发射、接收两端都换成工具箱函数否则发射端按你的表映射、接收端按工具箱的表解映射解出来的比特会整体错乱。4.2 符号能量和比特能量的换算曲线偏移的常见根源仿真中设定的是 Eb/N0但加噪时实际需要知道每个符号的 Es/N0。两者的关系是 Es/N0 k × Eb/N0k log2(M)。4QAM 时 k2Es/N0 比 Eb/N0 高约 3 dB16QAM 时 k4高约 6 dB。很多第一次写 QAM 仿真的同学直接把 Eb/N0 当 Es/N0 用导致 16QAM 的 BER 曲线实际是在比预期低 6 dB 的信噪比下跑出来的曲线整体右移。我在代码里用N0 1 / (k * EbN0lin)一步完成了这个换算它的前提是星座图已经归一化到 Es1。如果你不想归一化星座图也可以保留原来的星座点然后用N0 Es / (k * EbN0lin)两套写法等价。关键是想清楚噪声方差和信号能量必须用同一个参考系。4.3 蒙特卡洛符号数曲线末端抖动的根源误码率统计本质上是一个随机实验BER 曲线末端的抖动来自有限样本的方差。如果你每个信噪比点只跑 1000 个符号16QAM 一共 4000 个比特在 Eb/N012 dB 时真实误码率约 1e-4理论上 4000 个比特里一个误码都碰不到的概率很高曲线就会突然掉到 0画在对数坐标上表现为「断崖下坠」。常见做法是让每个信噪比点的误码数至少达到 100 个或者限制最少的比特数。% 动态停止版本统计到足够误码才进入下一个信噪比点 minErr 100; % 最少误码数 minBits 1e6; % 最少比特数兜底 errCnt 0; bitCnt 0; while errCnt minErr bitCnt minBits % 取一批符号加入噪声并判决 % 累计 errCnt 和 bitCnt end ber errCnt / bitCnt;这个动态停止方式比固定符号数更科学高信噪比时自动跑更多符号低信噪比时几百个符号就够。代价是总仿真时间不可控适合晚上挂机跑。如果只是验证链路正确性固定 nSym2e4、Eb/N0 扫描到 14 dB 就已经能看到完整曲线形态了。5. QAM 仿真避坑指南星座图旋转、曲线右移和抖动问题5.1 星座图整体旋转了 45 度现象画出来的接收星座图还是四四方方的网格但整体绕着原点转了 45 度判决后误码率奇高。原因发射端和接收端用的不是同一套坐标系最常见的是把复信号的实部虚部对调了或者在某一步把符号取了共轭。另一个可能是判决时把实部当虚部、虚部当实部相当于对星座做了镜像变换。解决先不要加噪声把发射符号直接送进判决模块如果 BER 不为 0说明收发映射不自洽。检查 constel 的定义和接收端距离计算的复数格式是否一致。在 3.1 节先画星座图的习惯能在这里省下大量时间。5.2 误码率曲线整体右移 3~6 dB现象仿真曲线形状和理论曲线几乎一样但整体向右偏了几个 dB4QAM 偏 3 dB、16QAM 偏 6 dB 左右。原因这就是 4.2 节说的 Eb/N0 和 Es/N0 换算漏掉了 k 因子。如果你发现 4QAM 偏 3 dB、16QAM 偏 6 dB基本可以确定是直接把 Eb/N0 当 Es/N0 用了。解决检查噪声方差处是否乘了 1/k。改成N0 1/(k*EbN0lin)后两条曲线应当重合。还有一类特殊情况是星座图做了归一化但理论公式里没除理论曲线会偏低或偏高注意保持「理论和仿真用同一个 Es 定义」。5.3 高信噪比段曲线抖动剧烈甚至掉到 0现象BER 曲线在低信噪比段很平滑到了 10 dB 以上开始剧烈抖动某几个点突然为 0对数坐标上直接断掉。原因固定符号数仿真时高信噪比下误码数太少。比如 nSym2e4、16QAM 在 Eb/N014 dB 时理论上只有几个误码样本方差极大甚至一个误码都没有。解决改用 4.3 节的动态停止准则或者降低扫描范围到 0~12 dB。如果必须看到更低误码率就提高符号数并接受更长的运行时间。另一个技巧是固定随机种子让每次跑出来的抖动位置一致方便前后对比。5.4 16QAM 解调出来的比特整体错位现象低信噪比下误码率接近 50%高信噪比下也不下降星座图看着是好的。原因判决索引到比特的还原逻辑和发射端的映射表不一致。比如发射端用十进制索引 idx 对应 constel 的第 idx1 行接收端却把距离最小的星座点位置直接当成了索引两者差了一位或者十进制转比特时位序写反低位高位对调。解决先用无噪声信号做自测发射几个已知比特序列打印发射前和判决后的比特逐位比对。最容易出错的是bits * (2.^(k-1:-1:0))这一行的位权方向改成2.^(0:k-1)会导致 bit 顺序整体反转。5.5 Simulink 仿真曲线和脚本结果对不上现象同一份参数Simulink 模型跑出来的 BER 和脚本仿真的结果差 1 dB 左右查了半天不知道哪里不对。原因Simulink 的 AWGN Channel 模块里SNR 的单位设置和 Eb/N0 换算方式跟脚本不一定一致。模块默认可以用 SNR(dB)、Es/N0(dB) 或 Eb/N0(dB) 三种模式很多人选 Eb/N0 模式却忘了填「每符号比特数」这个参数模块内部换算就会出错。解决在 AWGN Channel 模块的参数里把 SNR mode 选为 Eb/N0并正确填写 Number of bits per symbol4QAM 填 2、16QAM 填 4。仿真时间也要设置得足够长Error Rate Calculation 模块里勾选「Stop simulation」并设置目标误码数避免在曲线末端抖动。6. 结果验证的一个硬习惯先固定随机种子再谈曲线平滑验证整套仿真链路我的习惯是固定三样东西随机种子、星座图定义、理论公式。随机种子用rng(0)固定后每次跑出来的误码曲线完全一致改一个参数就能看出它对曲线的真实影响而不是被随机抖动掩盖。星座图定义固定后发射和接收端共用一个 constel 变量从根上杜绝映射表不一致。理论公式固定后每次改动链路都能立刻判断改动方向是否正确。进一步验证时可以把 4QAM 和 16QAM 的曲线画在同一张图上横轴用归一化的 Es/N0。此时 4QAM 和 16QAM 的理论曲线间隔会缩小能更清楚地看到高阶调制在带宽效率和功率效率之间的取舍。想扩展成 64QAM 也很简单把 4-PAM 换成 8-PAM星座点数从 16 扩到 64k 从 4 变成 6其余逻辑一行不用动。唯一的注意点是 64QAM 需要更高的信噪比才能跑出可看的曲线Eb/N0 扫描范围建议从 4 dB 开始并且把 nSym 提到 1e5。这套仿真做过几次最深的教训是调制解调仿真里 90% 的翻车都不是原理不懂而是能量归一化、索引对应、位序方向这类小地方错了还看不出来。所以每次写完链路我都会先跑一个无噪声自测再叠理论曲线最后才放开信噪比扫描。希望这个流程对你也有用祝一次跑通。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑