☰
NOMA与OFDMA仿真对比:原理、代码与避坑指南
2026/10/22 3:12:19 网站建设 项目流程

简介:面向无线通信与5G/NOMA研究方向学生、科研人员的MATLAB仿真资源,围绕NOMA(非正交多址接入)与OFDMA(正交频分多址)的对比及融合展开,帮助理解功率域复用、子载波分配、多用户检测与系统误码率评估。压缩包共13个文件,以.m脚本为主体,配合1个.mat数据文件,总体约156KB,涵盖OFDM收发、NOMA/OFDMA编解码、Turbo编译码及BER仿真等模块,代码结构清晰,便于直接运行和调整参数。已有381人学习下载,对入门级到中高级研究人员均有参考意义。通过主仿真脚本可快速复现两种接入方案的误码率对比曲线,结合数据生成与编码模块,深入掌握用户配对、功率分配及干扰管理的关键设计;同时为在OFDMA子载波上叠加NOMA用户的混合方案提供了可扩展的仿真框架,适合作为论文验证或课程设计的起点。

1. 这一包仿真代码,其实是在算一张通信资源的账

拿到「NOMA-OFDMA-SIM」这个压缩包,不用急着解压看代码。先想清楚标题在问什么:同一段频谱,到底按 OFDMA 那种“一个用户一块子载波、互不打扰”的方式分,还是按 NOMA 那种“大家一起发、在功率上做文章”的方式叠?前者是 LTE 时代一路走来的成熟方案,后者是 5G 时代被反复拿出来做对比研究的多址候选。这个 zip 包里的仿真,核心就是让你在同一个无线信道模型下,把两种方案的频谱效率、用户公平性、接收机复杂度放在一组曲线上做对比。适合谁用?一类是正在做无线通信课程设计或者毕设的学生,另一类是想评估 NOMA 值不值得往自己系统里引的工程师。压缩包能回答的不只是“谁快谁慢”,而是“凭什么快、在什么条件下快、快的那部分是从哪里挤出来的”。

2. 正交与功率域:OFDMA 和 NOMA 的底层逻辑

2.1 OFDMA 的“频率独占”思路为什么在密集场景吃亏

OFDMA 的核心是正交。系统把整段带宽切成一堆互相正交的子载波,再把子载波分组分配给不同用户。对接收机来说,每个用户只需要在自己那块频带上做解调,用户之间不存在能量上的互相干扰,所以接收机里的干扰消除模块可以做得非常简单。基站调度器要做的决策也只是“谁在哪个资源块上发”,是个纯粹的二维分配问题:时间维和频率维。

但在用户密集、业务突发明显的场景里,这种正交隔离逻辑会带来隐性浪费。一个用户分到了资源块但实际数据不多,这块频谱就处于半空置状态;另一个用户数据积压严重,却只能等下一个调度周期。更麻烦的是边缘用户,它的信道增益低,要在同样的频段上达到目标速率,就得占用更大比例的功率和带宽,这会把整个小区的频谱效率往下拉。OFDMA 的优势是“可控、干净”,代价是“当信道差异大时,资源做不到充分的共享”。

2.2 NOMA 的叠加与 SIC:近端用户替远端用户多干一道活

NOMA 走的是另一条路,功率域非正交。发射机在同一个子载波上把两个(或多个)用户信号按不同功率系数叠加后一起发出去,对时间、频率资源不做独占,而是让用户在功率维度上共享资源。为什么这样做能成立?关键在接收端做 SIC,也就是串行干扰消除。

用一个两用户的例子来说明。信道质量差的用户,称为远端用户,分配较大的功率;信道质量好的用户,称为近端用户,分配较小的功率。接收端解码顺序按照功率从大到小排,功率越大的信号越容易被先解出来。远端用户功率高,直接把自己信号解出来,把近端信号当成噪声就行;近端用户功率低,但它信道条件好,它先把功率高的远端用户信号解出来、从接收信号中减掉,再解自己的信号。所以说近端用户替远端用户多干了一道“解码再减掉”的活,付出的是接收机复杂度和能耗,换来的是同一块频谱上两个人都在发。这个 SIC 过程的数学表达很简单,远端和近端的信干噪比都能写成一个闭式公式。仿真里只要把公式写对,结果就成功了一大半。

2.3 一张表看清两种方案的本质选择

把两个方案放在同一张表里看,逻辑会更清楚。

对比项OFDMA功率域 NOMA
资源分配维度时间 + 频率(正交隔离)频率为底 + 功率叠加非正交
每资源块服务用户数通常 1 个多个(常见 2 个)
接收机复杂度低,只需传统解调高,需要 SIC 迭代
反馈与调度开销需要精确信道质量反馈需要的是用户排序和功率分配信息
对信道差异的偏好不希望差异太大(边缘难调度)差异越大功率区分越容易,越有利
性能瓶颈资源闲置和调度时延功率分配是否合理、SIC 误差传播

这张表能解释为什么仿真标题里 NOMA 总是和 OFDMA 放一起对比:两者不是简单的替代关系,而是两种资源使用哲学的差异。OFDMA 用正交换取简单,NOMA 用干扰换取频谱复用。当你的仿真场景是信道差异大的多用户小区,NOMA 往往能压过 OFDMA;反过来在信道对称、用户公平性要求苛刻的场景,OFDMA 仍然更稳妥。仿真真正要做的事,就是把这种边界条件摸清楚。

3. 跑通 NOMA-OFDMA 对比仿真:代码结构与第一次运行

3.1 拿到压缩包后,先按功能把手里的文件归类

这类仿真包解压之后通常不会只有一个孤零零的脚本,而是若干个文件互相调用。别急着双击其中一个运行,先把文件按职责分类:第一类叫主脚本,负责设置仿真参数、循环扫描信噪比、调用子函数、最后画图;第二类是信道生成部分,一般是一个函数,输入用户数和信道类型,输出信道系数数组;第三类是发射机处理逻辑,做符号映射、功率分配、叠加编码;第四类就是接收机设计,实现 SIC 解码流程,并计算误比特率或吞吐量;第五类是 OFDMA 对照组,它的地位经常被低估,但恰恰是这个对照组设置了性能比较的基准线。

动代码之前,我建议先打开主脚本,把里面几个关键变量的赋值找出来:SNR 扫描范围、蒙特卡洛次数、用户数、子载波数、功率分配系数。这几个数决定了整个仿真的工作点。特别是蒙特卡洛次数,如果写的是 100 这种量级,跑出来的曲线会抖得像心电图,后面所有对比结论都站不住脚。先把这些参数记下来,再去看实现细节。

3.2 一个最小可运行的 NOMA 仿真脚本与逐行说明

与其去猜包里的代码怎么写的,不如先照着下面这段最小脚本建立一个自己的“试验台”。这个脚本是我常用的两用户 NOMA 与 OFDMA 对比框架,删掉了所有不必要的绘图细节,只保留容量计算逻辑。

% 主仿真参数 SNRdB = 0:2:20; % 信噪比扫描范围,单位 dB nTrial = 5000; % 蒙特卡洛次数,想曲线平滑就至少 5000 P = 1; % 归一化发射总功率 a = [0.8, 0.2]; % NOMA 功率分配系数:远端 0.8,近端 0.2 % 预分配结果数组 rateNoma = zeros(size(SNRdB)); rateOfdma = zeros(size(SNRdB)); for i = 1:length(SNRdB) sumN = 0; sumO = 0; for t = 1:nTrial % 生成两用户瑞利衰落信道,独立同分布 h = (randn(1,2) + 1i*randn(1,2)) / sqrt(2); % 按信道增益升序排列:h(1) 是远端弱用户,h(2) 是近端强用户 [h] = sort(abs(h), 'ascend'); % 噪声功率,由目标 SNR 换算得到 N0 = P * 10^(-SNRdB(i)/10); % NOMA:远端用户直接把近端信号当噪声 sinr1 = (abs(h(1))^2 * P * a(1)) / (abs(h(1))^2 * P * a(2) + N0); % NOMA:近端用户 SIC 后只剩自己的信号和噪声 sinr2 = (abs(h(2))^2 * P * a(2)) / N0; sumN = sumN + log2(1 + sinr1) + log2(1 + sinr2); % OFDMA 对照:带宽、功率都均分给两个用户 sumO = sumO + 0.5*log2(1 + (abs(h(1))^2 * P/2) / N0) ... + 0.5*log2(1 + (abs(h(2))^2 * P/2) / N0); end rateNoma(i) = sumN / nTrial; rateOfdma(i) = sumO / nTrial; end % 绘图部分:横轴 SNRdB,纵轴归一化频谱效率 plot(SNRdB, rateNoma, 'r-o', SNRdB, rateOfdma, 'b-s'); legend('NOMA', 'OFDMA'); xlabel('SNR (dB)'); ylabel('Sum Rate (bps/Hz)'); grid on;

这段代码里最容易绕晕的是sort那一步。信道系数生成后,我取模值再做升序排列,确认索引 1 是弱用户、索引 2 是强用户。为什么必须做这一步?因为 NOMA 的功率分配与 SIC 解码顺序都依赖于信道排序,排反了整个系统就失去意义。NOMA 的吞吐量计算上面,远端用户的信干噪比分母里有近端用户的功率项,因为对远端来说近端信号就是干扰;近端用户信干噪比的分母只有噪声,对应它在 SIC 成功后把干扰完全消除的理想状态。OFDMA 对照那两行,带宽减半所以谱效率乘了 0.5,功率均分所以每用户发射功率是 P/2,这个必须和 NOMA 保持相同的总功率预算,否则对比就不公平。

3.3 对照组 OFDMA 的仿真设计有三种常见口径

OFDMA 对照有很多写法,不同写法直接影响结论方向。第一种最常见,就是我上面用的带宽均分、功率均分,这是“等资源池”口径,大家总功耗一样,NOMA 额外付出的复杂度换来的收益一目了然。第二种是带宽均分、功率按信道倒置分配,也就是好的信道少给功率、差的信道多给功率,这其实是在帮 OFDMA 做公平性优化,对比对象变成了“功率分配更优的 OFDMA”。第三种是 OFDMA 也实现频率选择性调度,把每个子载波分配给当前信道最好的用户,这在多用户场景里会让 OFDMA 的频谱效率大幅提升。

我一般会把第一种作为默认口径,因为它是中性的比较基准。做敏感性分析时再跑第二种和第三种,看 NOMA 的相对增益会不会被调度算法吃掉。如果你拿到的 zip 包里 OFDMA 对照组写的是全体用户挤在一起但各自解调互不干扰,那就有问题——这不是 OFDMA,是把 NOMA 的叠加信号直接当正交信号解,性能会差到离谱,属于明显的实现错误。

4. 仿真参数怎么定:信道模型与工作点选择

4.1 瑞利信道与归一化功率:仿真里最容易虚高的两个设置

信道模型是整个仿真的地基,也是最容易被低估的参数。包里的仿真绝大多数默认用瑞利衰落,因为它是无线多径传播最经典的统计模型,括号里的系数(randn + 1i*randn)/sqrt(2)保证了信道增益的平均功率为 1,这种归一化让后面所有功率计算都能在“相对功率”的基础上进行。

但瑞利模型默认所有用户经历相同的大尺度衰落,这在某些场景下会掩盖真实差异。如果目标是评估“用户距离基站不同远近”的 NOMA 场景,就需要在大尺度上做手脚:给远端用户乘一个更小的路径损耗系数,让两个用户的接收功率拉开差距。我见过不少翻车案例,信道全部用小尺度瑞利、不加大尺度差异,跑出来的结果里 NOMA 的增益很小甚至看不出来,然后作者硬是把功率分配系数调到 0.95 去补。这种调参方式本质上是掩盖模型缺陷。正确做法是先在信道模型里把差异建出来,再让功率分配器去适应这个模型;而不是反过来,用极端功率分配系数硬撑出优势。

归一化功率这里也有个经典坑。仿真里总功率 P 取 1,但功率分配系数 a 的维度必须和 P 协调。a 是比例,两个用户的功率是P*a(1)和P*a(2),所以必须满足 a(1)+a(2)=1,含义是“对总功率的切分”。如果代码里写成了P*a(1)和P*a(2)但a(2)=0.3而a(1)=0.8,两个功率加起来是 1.1P,总功率预算悄悄多了 10%,曲线整体上移。这种错误特别隐蔽,因为人眼很难从曲线上判断 10% 的偏差,还是靠代码审查才能抓住。我建议在初始化阶段就写一行断言:if sum(a) ~= 1, error('功率分配系数必须归一化'); end,一劳永逸。

4.2 用“和速率 vs SNR”作为试验台的工作参数

仿真工作点的选择,也就是扫哪些参数、参数范围取多少,取决于你手头要回答的问题。如果目的是复现文献结论或者验证 NOMA 的基本性质,最常见的工作台是“和速率对 SNR”,横轴 0 到 30 dB,步长 1 或 2 dB。在低 SNR 区,噪声占主导,SIC 能把干扰消掉但消不掉噪声,NOMA 不如 OFDMA 的现象属于正常;随着 SNR 升高,NOMA 的和速率会逐渐超过 OFDMA,这个交点大概在哪个 dB 数出现,往往是评审人最喜欢问的问题。

蒙特卡洛次数对标曲线的稳定性。5000 次是及格线,10000 次能让曲线平滑到不用额外滤波。低于 1000 次时,单次信道实现的随机性还没被平均掉,曲线毛刺会让人误判趋势。如果你时间紧只能跑 1000 次,至少要在代码里把随机数种子固定下来,保证两次跑的结果一致,否则改一个参数重新跑一遍,曲线形状大变,没法做对比。

子载波数与用户数的关系也要注意。NOMA 的叠加增益来自每资源块上的多用户复用,所以典型设置是“64 个子载波、每 2 个用户一组、共 32 组”;用户数固定为 2 的仿真只能证明双用户场景的结论,4 用户时 SIC 顺序变长,误差传播影响会被放大,这时候再看孙景频谱效率,NOMA 的收益曲线会往下弯。这本身是个有价值的结论,但它需要单独一组仿真来说明,不要试图用双用户结果外推。

4.3 仿真里常用的性能指标不止和速率一个维度

做对比仿真时,除了横纵轴直接画和速率,我建议至少再补两个维度的评估。第一个是公平性指标,最常用的是 Jain 指数,它反映系统里各用户速率的均衡程度,取值在 0 到 1 之间。NOMA 的和速率高,但近端用户可能吃得盆满钵满,远端用户只分到一点残羹,Jain 指数就会显著低于 OFDMA。只报和速率、不报公平性,评审人一眼就能看出这是在用系统级指标掩盖用户级矛盾。第二个是中断概率,定义是用户速率低于某个门限的概率,它比平均速率更能反映用户在真实业务下的感知。

这两个指标不用每次仿真都跑,而是作为“全面评估”的补充。我在做这类对比时,固定下来的一套习惯动作是:先扫和速率找到性能交点,再在交点的 SNR 处画 Jain 指数,最后对功率分配系数扫一遍。三张图放在一起,系统的全貌就出来了。第 6 章里会具体展开功率系数扫描这个技巧,这里先记住一个原则:单条曲线只是结论的起点,三条曲线才是可信的论据。

5. 避坑:NOMA-OFDMA 仿真的五个高频翻车点

5.1 现象:功率分配系数之和大于 1,和速率曲线整体虚高

第一次跑通两用户 NOMA 仿真,我看到 20 dB 处和速率比 OFDMA 高了快一倍,当时觉得这个方案简直无敌。后来逐行审查代码才发现,两个功率系数加起来等于 1.15,总功率预算超了 15%。这个问题在公式推导里几乎不可能出现,但在脚本实现里极其常见,因为矩阵赋值时 a(2) 被反复修改过,最早的归一化约束在修改中失效了。解决方法是把功率分配写成一个独立的函数,每次调用内部重新归一化,禁止在外部直接修改系数值。

function a = normalizePowerCoeffs(aRaw) a = aRaw / sum(aRaw); % 强制归一化,确保总功率等于 P if any(a < 0) error('功率分配系数不能为负'); end end

这段代码虽然只有三行,但能挡住两类最隐蔽的错误:一是系数没有归一化,二是某个系数被写成负数。负功率在物理上不存在,但脚本里如果前面的计算出了负的中间变量,很容易带进来。加上这个函数之后,所有功率分配入口统一从这里走,问题从根源上被切断。

5.2 现象:SIC 解码顺序写反,近端用户误码率反而高于远端

SIC 解码顺序由信道增益排序决定,功率分配顺序由同一个排序决定。两者必须保持一致,近端用户先解出远端用户的信号并减去,再解自己的。如果你的代码里排序用了降序,把强信号当成了高功率用户,那近端的 SIC 第一步就会失败——它试图先解一个功率比自己低但干扰更强的信号,信干噪比根本达不到解码门限,减不掉,然后带着一个强干扰去解自己的信号,误码率直接崩溃。最迷惑的是系统级误码率曲线看起来只是稍微变差,不会出现明显报错,让人怀疑是信道模型的问题。排查方法很简单:在仿真循环里打印出两次解码后的星座图或者信干噪比,如果近端解码的信干噪比低于远端,排序几乎可以肯定是反的。

5.3 现象:蒙特卡洛次数不足,曲线毛刺让性能交点判断产生偏差

和速率曲线在交点附近的斜率往往很缓,两三条曲线缠在一起。这种场景下,如果蒙特卡洛次数只有 200,随机起伏会掩盖真实的性能交点,你看到的可能是 NOMA 交叉点偏左 1 dB 或者偏右 1 dB,结论就完全不同。更麻烦的是,在交点附近跑两遍结果不一样,一旦有人复现,就对结果失去信心。处理方案不是简单地加大次数,而是先用较小次数找出交点大致位置,然后在交点附近加密扫描并用 10000 次数重跑,把原来的粗扫曲线替换成局部精确曲线。这个做法节省时间,也能让结论更扎实。

5.4 现象:只画和速率,不提用户公平性,仿真结论被评审一票否决

NOMA 的和速率优势很大,尤其是信道差异被拉得很开的时候。但看细节就会发现,远端用户速率可能被压到 OFDMA 下的一半,近端用户速率高出两倍,平均值好看不代表每个用户都好。只报和速率的仿真报告,在评审环节几乎必被问到一个问题:用户间的公平性是否符合要求?如果你的功率分配策略里没有对远端用户速率做最低门限保护,NOMA 的“优势”在实际系统中可能不可接受。对应的做法是画一条公平性曲线,或者直接设定“远端用户速率不低于 OFDMA 下的速率”作为约束条件,在这个约束下再做功率分配。

5.5 现象:信道模型没做路径损耗,NOMA 增益被完全淹没

上面 2.1 节提到过,NOMA 的功率区分能力依赖于用户间信道差异。如果仿真里所有用户都用同样的瑞利分布且不加大尺度衰落,两个用户的平均功率差异接近零,SIC 能依赖的只有小尺度衰落的瞬时差异。这种模型下跑出来的结果,NOMA 的和速率增益常常只有 5% 左右,很难说明问题。验证方法很直接:算一下远端用户和近端用户的平均接收功率比值,如果比值接近 1,说明信道差异不够,需要加入距离相关的路径损耗项。

6. 进阶:扫一遍功率分配系数,找到公平与效率的平衡点

两用户 NOMA 的功率分配系数只有一个自由度:设定 a(1) 后,a(2) 自动等于 1-a(1)。这个自由度看起来简单,却是系统真正的调节旋钮。a(1) 偏大,远端用户舒服了,近端用户 SIC 后残留的干扰也小,但近端自己的功率被压缩,近端速率下降;a(1) 偏小,远端用户速率撑不住,系统公平性崩掉。扫系数就是在效率与公平之间描出一条曲线,然后用这条曲线去对应你的系统目标。

具体做法是在固定 SNR 下,让 a(1) 从 0.51 到 0.95 按 0.01 步进扫描,每次重跑蒙特卡洛循环,记录两个关键值:和速率与远端用户速率。然后把两条曲线画在同一个图上,横轴是 a(1)。你会看到一个典型形态:和速率曲线有一个峰,通常落在 0.7 到 0.85 之间,具体位置取决于信道差异程度;远端用户速率则随 a(1) 单调上升。二者的交点,也就是“和速率下降前远端用户速率已经足够高”的折中位置,就是实际系统里推荐的功率分配工作点。

我习惯在这个扫描基础上再叠一层约束:如果项目目标是保证边缘用户体验,就先把远端速率不能低于某个绝对门限写入代码,在满足门限的系数区间内选和速率最大的那一个点。如果没有明确目标函数,就选和速率峰右侧刚进入缓降区的位置,这样系统对信道估计误差的敏感度最低。仿真不是找数学最优解,而是找工程上最稳的工作点,这个经验我在好几个项目里都验证过。功率系数扫描虽然要多跑几十轮蒙特卡洛,但换来的是对这个系统行为习惯的完整认知——手上有这张曲线图,后续无论评审问什么,你都能直接从图上指一个点给结论。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询