
简介面向通信工程与电子信息类专业学生的NOMA非正交多址接入系统Matlab仿真代码包。系统通过信号叠加与串行干扰消除实现多用户共享时频资源是5G及未来通信的关键技术之一特别适合用作课程设计、期末大作业或毕业设计的起点。压缩包共3个文件包含2个m格式仿真脚本与1张png结果示意图整体大小仅32KB轻量易部署脚本采用参数化编程关键参数可灵活调整代码注释清晰便于阅读和二次开发。已有45人学习下载借助附赠案例数据可快速运行验证直观观察NOMA在多用户场景下的频谱效率提升效果。包内代码兼容Matlab2014、Matlab2019a及Matlab2024a等多个版本使用者可调整用户功率分配、叠加编码等参数拓展评估不同设计方案帮助将理论模型转化为具体工程实践兼顾学习与科研扩展需求。1. NOMA与正交多址的频谱效率差距为什么拿Matlab做仿真传统LTE把用户分到不同资源块干扰虽然干净但频谱效率被白白浪费了。NOMA故意让多个用户共享同一时频资源在发送端用不同功率叠加信号在接收端靠串行干扰消除把别人的信号剥掉。这个反直觉的做法能换来比OMA更高的系统和速率也是5G新空口里对它重新重视的原因。Matlab之所以是验证NOMA最顺手的工具是因为矩阵运算天然匹配叠加编码通信工具箱直接提供调制、信道与误码率函数这份代码又采用参数化编程用户数、功率分配因子、调制阶数、SNR范围全部集中在脚本头部改一个变量就能重复跑出一组性能曲线适合课程设计、期末大作业和毕业设计。下面从功率域复用的原理开始再逐步把这份仿真代码拆开。2. 叠加编码与SIC检测NOMA系统模型在Matlab中的落地2.1 功率域NOMA的系统模型与关键假设NOMA最核心的假设是多个用户共享同一子载波通过不同的发射功率区分用户。基站发送的信号可以写成x sqrt(P*α1)s1 sqrt(Pα2)*s2其中P是总发射功率α1和α2是功率分配系数且α1α21s1和s2分别是用户1和用户2的调制符号。用户1和用户2的信道增益分别记为h1和h2。注意NOMA中有一个看起来反直觉的约定信道条件较差的远端用户分配较大的功率信道条件较好的近端用户分配较小的功率。这样做的目的是保证远端用户能直接解出自己的信号而近端用户由于SIC的存在也能在消除强信号后拿到自己的数据。功率分配系数的设计直接影响系统公平性和总吞吐量所以仿真时一定要把它作为参数放在配置区。下面的表格对比了OMA和NOMA在关键维度上的差异这也是为什么很多5G仿真选NOMA作为研究对象。对比维度OMA正交多址NOMA非正交多址用户资源占用时频资源正交划分同一时频资源叠加频谱效率受限于资源块划分可超过1资源利用率更高接收机复杂度简单只需解调自己的资源需要SIC串行干扰消除对功率分配的依赖低高分配策略直接影响性能适合场景LTE传统宏基站5G密集场景、上行免调度这张表说明了NOMA在性能上的优势是靠接收机复杂度换来的。在Matlab仿真中SIC解码顺序和功率分配系数就是两个最容易出错的地方后面会专门说。2.2 发射端叠加编码的Matlab实现这份NOMA仿真代码发射端的核心不是复杂的函数而是几行矩阵运算。我一般会建议学生先写一个独立的叠加编码片段验证星座点是否符合预期。下面是一个典型的BPSK调制下NOMA叠加过程% 叠加编码两个用户共享同一子载波 N 1000; % 符号数决定仿真点数 P 1; % 归一化总发射功率通常设为1 alpha [0.8, 0.2]; % 功率分配系数远端用户1分配0.8近端用户2分配0.2 % BPSK调制0映射为-11映射为1 s1 2 * randi([0 1], 1, N) - 1; s2 2 * randi([0 1], 1, N) - 1; % 叠加发射信号 x sqrt(P * alpha(1)) * s1 sqrt(P * alpha(2)) * s2;这段代码把两个用户的比特流各自映射成BPSK符号然后按照功率分配系数加权叠加。sqrt(P*alpha(1))是用户1的幅度增益sqrt(P*alpha(2))是用户2的幅度增益。注意这里功率分配系数必须满足sum(alpha)1否则发射功率会变仿真结果会和理论不一致。如果后续要扩展到QPSK或16QAM只需要把调制部分换成qammod函数并把M作为参数写在配置区。2.3 信道与接收端SIC解码顺序信号经过无线信道后接收端收到的是带噪声和衰落版本的叠加信号。以一个两用户下行场景为例用户1和用户2的接收信号可以写为y1 h1 * x n1y2 h2 * x n2其中h1、h2是信道衰落系数n1、n2是复高斯白噪声。在SIC检测中用户1作为远端用户直接对y1做检测因为自己的信号功率大所以能够直接解调。用户2作为近端用户需要先解调用户1的符号然后重构用户1的贡献从自己的接收信号中减去再解调自己的符号。下面是用户2执行SIC的核心代码% 用户2 接收信号假设h2是已知信道系数 y2 h2 * x sqrt(N0 / 2) * (randn(1, N) 1j * randn(1, N)); % 第一步解调用户1信号远端用户功率大 s1_hat real(y2 / (sqrt(P * alpha(1)) * h2)) 0; s1_hat 2 * s1_hat - 1; % 恢复为1/-1符号 % 第二步重构用户1信号并从y2中减去 y_cancel y2 - sqrt(P * alpha(1)) * h2 * s1_hat; % 第三步解调用户2自身信号 s2_hat real(y_cancel / (sqrt(P * alpha(2)) * h2)) 0;这里最关键的是顺序必须先解调功率分配大的用户。如果反过来的话近端用户会把另一个用户强信号当成噪声误码率会非常差。另外SIC对信道估计误差非常敏感代码里通常假设接收端已知信道系数这是理想情况实际仿真中如果需要评估准真实场景应该加入信道估计模块。这段代码里的sqrt(N0/2)是复高斯噪声的标准差N0由SNR计算得到后面会看到如何关联。3. 参数化仿真代码的结构解析从发射机到接收机的完整链路3.1 参数化配置区改一处即可切换场景拿到这份Matlab代码时第一件事不是从头看懂每一行而是打开脚本头部的参数配置区。参数化编程的意思就是把所有会影响仿真结果的变量都集中到一起用清晰的注释标明物理含义。例如% 参数配置区 numUsers 2; % 接入用户数当前支持2用户功率域NOMA modOrder 2; % 调制阶数2表示BPSK4表示QPSK numSymbols 10000; % 每个SNR点仿真符号数 snrRange 0:2:20; % 信噪比扫描范围单位dB alpha [0.8, 0.2]; % 功率分配系数建议保持和为1 channelType rayleigh; % 信道类型awgn 或 rayleigh numTrials 10; % 蒙特卡洛次数越大曲线越平滑 % 这些参数直接决定仿真场景和耗时。比如把numSymbols从10000改成1000误码率曲线会抖动变大但运行时间会缩短把channelType改成awgn可以快速验证SIC逻辑是否正确。将这类参数放在同一个区块能让课程设计或毕设的实验部分直接引用“参数表”也方便给答辩老师演示。下表列出几个关键参数的建议范围和影响参数名建议范围对仿真的影响numUsers2 ~ 4大于2时SIC级数增加解码顺序逻辑更复杂modOrder2/4/16直接影响符号错误率高阶调制曲线更陡alpha0.5~0.9功率差越大SIC越稳定但弱用户性能下降snrRange0~30 dB范围太宽则耗时长太窄则看不到误码率拐点numTrials5~20增加后曲线平滑但仿真时间近似线性增长3.2 完整链路的主循环与函数拆分我比较推荐把链路仿真拆成三个子函数发射、信道、接收统计。这样代码可读性比一个长脚本好得多答辩时也容易讲。下面是一个主函数的调度伪代码实际代码里可以直接替换成你自己的函数名function [berUser1, berUser2] noma_link_sim(snr_dB, alpha, N) % 单次链路仿真返回两个用户的误码率 % 输入 % snr_dB - 信噪比单位dB % alpha - 功率分配系数向量 % N - 符号数 P 1; N0 P / (10^(snr_dB / 10)); % 由SNR计算噪声功率密度 % 发射端叠加编码 x noma_transmit(N, alpha, P); % 信道两用户独立瑞利衰落 h1 (randn 1j*randn) / sqrt(2); h2 (randn 1j*randn) / sqrt(2); % 接收端加入噪声做SIC [berUser1, berUser2] noma_receive(x, h1, h2, N0, alpha); end注意N0 P / (10^(snr_dB/10))这行的含义归一化发射功率P除以线性信噪比得到噪声功率密度。这样写能保证所有用户共享同一个SNR定义不会出现每个用户噪声不统一的问题。这里的randn生成的是复高斯随机变量除以sqrt(2)是为了让信道增益的功率归一化为1否则误码率曲线会整体偏移。noma_receive函数内部就是前面章节提到的SIC过程不过要加上误码统计。误码统计通常使用sum(xor)比如errUser1 sum(s1_hat ~ s1); berUser1 errUser1 / N;3.3 运行步骤与验证方法直接在Matlab命令行执行主脚本即可前提是matlab2014/2019a/2024a都能运行这套代码。建议运行顺序是先保持参数区默认值运行一遍确认无报错。将channelType改为awgn对比瑞利信道下的曲线观察差异。调整alpha为[0.7,0.3]和[0.9,0.1]记录两个用户的误码率变化。若需要输出图形在脚本末尾添加semilogy(snr_dB, berUser1)命令纵轴用对数坐标才能看清误码率下降趋势。这里要说明的是如果运行时报“未定义函数或变量”先检查是否把子函数写在同一个noma_main.m文件里。Matlab的脚本与函数文件格式要求严格子函数不能直接放在脚本中除非使用function定义在脚本末尾。多数学生遇到的问题不是算法而是文件结构这点在下面的排错章节专门讲。4. 误码率与用户速率对比仿真结果分析与参数调整方法4.1 蒙特卡洛循环与误码率统计单次链路仿真的误码率有随机性尤其是瑞利信道一次仿真的结果可能波动非常大。常见做法是在每个SNR点上重复多次蒙特卡洛仿真取平均。下面是循环计算两个用户误码率的典型代码snr_dB 0:2:20; ber1 zeros(size(snr_dB)); ber2 zeros(size(snr_dB)); numTrials 10; N 10000; for k 1:length(snr_dB) err1 0; err2 0; for trial 1:numTrials [berUser1, berUser2] noma_link_sim(snr_dB(k), alpha, N); err1 err1 berUser1 * N; err2 err2 berUser2 * N; end ber1(k) err1 / (numTrials * N); ber2(k) err2 / (numTrials * N); end这段代码的循环逻辑是外层遍历SNR内层重复蒙特卡洛。把berUser1 * N换算成错误比特数相加最后再除以总比特数这样比直接对误码率求平均更准确能避免小样本下误码率被零次错误拉低。如果使用Matlab的并行计算可以把内层for改成parfor但要注意随机数种子问题否则每次运行结果无法复现。4.2 功率分配系数对误码率的影响在NOMA仿真里一上来就看总误码率没有意义一定要分开统计每个用户的误码率。通常远端用户1由于功率分配更大误码率会明显低于近端用户2。但随着SNR提高近端用户通过SIC消除强干扰后性能会逐渐赶上来。下面是一组在典型仿真参数下得到的趋势这里不指定具体版本因为不同Matlab版本和随机数种子会有差异但趋势是一致的SNR (dB)用户1误码率alpha0.8用户2误码率alpha0.20约 1e-2 量级约 0.2 左右6约 1e-3 量级约 5e-2 左右12约 1e-4 量级约 1e-2 左右18更低趋于平台约 1e-3 量级这张表的重点不是数值本身而是观察两个用户之间的性能差。如果把alpha改成[0.95,0.05]用户1误码率会更低但用户2会因为自身功率太小噪声影响被放大误码率反而恶化。这说明功率分配因子不能盲目拉大它是一个在用户公平性和系统容量之间的折中参数。在论文或报告中画曲线时应该以SNR为横轴、误码率为纵轴用semilogy绘图并把两个用户画在一张图上。4.3 系统吞吐量对比与OMA基准除了误码率NOMA仿真的另一个常用指标是和速率或系统吞吐量。两用户下行NOMA的和速率可以用香农公式近似表达。在Matlab里我会在同一个脚本里计算OMA场景下的基线吞吐量用来做对照% 计算NOMA和速率单位为 bit/s/Hz rate_noma log2(1 P * alpha(1) * abs(h1)^2 / N0) ... log2(1 P * alpha(2) * abs(h2)^2 / (P * alpha(1) * abs(h2)^2 N0)); % OMA基线两个用户各分一半时频资源 rate_oma 0.5 * log2(1 P * abs(h1)^2 / N0) ... 0.5 * log2(1 P * abs(h2)^2 / N0);注意这里的NOMA和速率第二项里面分母包含了用户1的残余干扰P*alpha(1)*abs(h2)^2这对应的是用户2在SIC之后仍然受用户1干扰的极限情况。如果SIC完美干扰项会被消除但实际仿真中很难完全不留下误差。这个表达式可以直接用于画“NOMA vs OMA”的容量柱状图答辩时非常直观。5. 调参、排错与扩展把基础NOMA仿真改造成自己的毕设5.1 最常见的三个坑先说要避开的坑。SIC解码顺序颠倒必须先解功率分配大的用户后解功率分配小的用户。如果顺序反了近端用户误码率会接近0.5也就是完全解不出来。检查时可以在接收端打印两个用户解调前后的幅度值。功率分配系数没有归一化如果alpha之和不为1发射信号总功率就不是P误码率曲线会整体左右移动看起来像是SNR变了。建议在参数配置区用alpha alpha / sum(alpha);做一次归一化。复高斯噪声的方差用错Matlab中randn生成的是实高斯分布复噪声需要分别生成实部和虚部再乘以sqrt(N0/2)。很多同学只乘了sqrt(N0)导致实际噪声功率翻倍仿真曲线比理论差大约3dB。5.2 验证仿真结果是否正确的技巧验证思路很简单把NOMA退化成OMA。具体做法是将alpha设置为[1,0]此时两个用户不再叠加系统退化为单用户传输误码率应该与BPSK在AWGN或瑞利信道下的理论曲线一致。如果退化场景能和理论值对得上说明发射机和接收机链路基本正确如果对不上问题通常出在噪声功率或者符号映射上。另一个快速验证方法是把numUsers改成1直接运行单用户链路检查输出误码率是否在10^-3量级附近。5.3 扩展方向多用户、高阶调制与MIMO-NOMA如果做毕业设计不建议只停留在两用户BPSK。可以把代码扩展到四个用户这时候功率分配需要按信道增益降序排列SIC的级数也变为3次但整体流程不变。更实用的是把BPSK换成QPSK或16QAM调制阶数提升后SIC的符号重构要使用qammod/qamdemod误码率统计也要按比特而不是符号计算。下面是扩展多用户功率分配的一种常见策略% 按信道增益从低到高分配功率信道差的用户功率大 [~, idx] sort(abs(h), ascend); alpha zeros(1, numUsers); rho 0.2; % 步长控制因子 for m 1:numUsers alpha(idx(m)) rho * (numUsers - m 1); end alpha alpha / sum(alpha);这段代码先对信道增益排序然后给信道差的用户分配更大的功率系数最后归一化。步长因子rho可以控制功率差异的剧烈程度。这样的扩展不仅保留原代码的可读性也能让你在答辩时讲清楚“参数化编程如何适应多用户场景”。用户数增加后SIC的错误传播效应会累积近端用户误码率会比两用户场景更难压下去这时可以把理想信道估计换成带导频的LS估计进一步贴近真实系统。本文还有配套的精品资源点击获取