☰
MATLAB仿真对比NOMA与OFDMA:从链路搭建到BER曲线分析
2026/10/22 21:13:49 网站建设 项目流程

简介:这份资源面向无线通信方向的学生、研究人员与工程师,聚焦非正交多址接入(NOMA)与正交频分多址(OFDMA)两种多址技术的对比分析,适合具备一定MATLAB基础、希望深入理解5G多用户通信机制的中高级学习者。压缩包共18个文件,约147KB,以11个m脚本为核心,辅以3个png与3个fig图形文件及1个mat数据文件,涵盖NOMA编解码、OFDMA收发链路、数据生成、Turbo编解码与误码率绘图等模块,并针对BPSK、4PSK、8PSK等调制方式给出性能对比图形。已有266人学习下载。通过运行与研读这些脚本,读者可复现NOMA与OFDMA在资源分配、多用户调度、干扰管理及抗噪声衰落等方面的性能差异,获取误码率曲线与调制方式对比结果,为频谱效率评估与系统方案选型提供可参考的仿真依据。

1. 从一份 MATLAB 对比包说起:NOMA 与 OFDMA 到底差在哪

如果你正在做多址接入技术的性能对比,手头大概率绕不开两个名字:NOMA 和 OFDMA。前者是非正交多址接入,靠功率域复用让多个用户在同一个时频资源上叠加传输;后者是正交频分多址,把频谱切成互不重叠的子载波分给不同用户。这份compare NOMA OFDMA.zip就是一套用 MATLAB 写的对比仿真包,里面既有 OFDM 收发链路,也有 NOMA 的编解码,还带了 BPSK、4PSK、8PSK 三种调制下的误码率脚本和现成图。它适合谁?适合已经懂一点通信原理、想亲手跑出两条 BER 曲线做对比的工程师和学生。你不需要从零搭链路,但得能看懂.m文件之间的调用关系,否则打开就是一堆函数名,跑不起来。

2. 拆开压缩包:文件分工与链路结构

2.1 发射端与接收端的文件对应关系

拿到一个仿真包,我习惯先按“发—收—信道—评估”四段把文件归类,而不是急着点运行。这份包的结构其实很清晰:data_gen.m负责生成原始比特流,ofdm_tx.m和ofdm_rx.m构成 OFDMA 的收发链路,noma_enc.m和noma_dec.m构成 NOMA 的编解码,ofdma_enc.m和ofdma_dec.m则是 OFDMA 的编码解码模块。turbo_enc.m和turbo_dec.m是信道编码,main_v2_ber.m是主脚本,plot_ber.m负责画图,ber.mat存的是跑完的结果数据。

这里有个容易忽略的点:OFDMA 的链路里,ofdm_tx.m做的是 IFFT 加循环前缀,ofdm_rx.m做的是去 CP 加 FFT,而ofdma_enc.m和ofdma_dec.m处理的是子载波分配和用户映射。也就是说,OFDMA 的“多址”体现在子载波分配上,OFDM 只是它的传输手段。NOMA 这边,noma_enc.m做的是功率分配和叠加编码,noma_dec.m做的是 SIC(串行干扰消除)。两条链路的入口都是data_gen.m,出口都汇到main_v2_ber.m算误码率。

提示:先别改任何参数,用默认配置跑一遍main_v2_ber.m,确认能出图再动。很多人一上来就调功率分配,结果连基线都跑不通,白白浪费时间。

2.2 调制方式与图文件说明

包里带了三种调制的图:NOMA-BPSK.fig、NOMA-4PSK.fig、NOMA-8PSK.fig,对应的还有.png版本。这些是已经跑好的结果图,你可以直接打开看趋势,也可以自己重跑覆盖。BPSK 每符号 1 比特,4PSK 每符号 2 比特,8PSK 每符号 3 比特。调制阶数越高,频谱效率越高,但抗噪能力越差,BER 曲线会整体右移。

ber.mat里存的是误码率数据,plot_ber.m读这个文件画曲线。如果你想对比 NOMA 和 OFDMA 在不同信噪比下的表现,改main_v2_ber.m里的 SNR 范围就行。常见做法是把 SNR 设成 0:2:20 dB,步长 2 够看出趋势,再细可以设 1。

3. 跑通主脚本:从 data_gen 到 BER 曲线的完整流程

3.1 主脚本的调用顺序与参数入口

main_v2_ber.m是整个包的入口。它一般会先清空环境,然后设参数,再循环 SNR 跑蒙特卡洛。下面是我按常见写法还原的核心结构,你对照自己的文件看,变量名可能略有不同,但逻辑一致。

% main_v2_ber.m 核心流程还原 clear; close all; clc; % ---- 系统参数 ---- N = 64; % 子载波数 cp_len = 16; % 循环前缀长度 M = 4; % 调制阶数,4 对应 4PSK num_users = 2; % NOMA 用户数 snr_db = 0:2:20; % 信噪比范围 num_bits = 1e5; % 每轮仿真比特数 ber_noma = zeros(1, length(snr_db)); ber_ofdma = zeros(1, length(snr_db)); for idx = 1:length(snr_db) % 生成数据 tx_bits = data_gen(num_bits); % ---- NOMA 链路 ---- [noma_sym, power_alloc] = noma_enc(tx_bits, M, num_users); noma_rx = ofdm_tx(noma_sym, N, cp_len); % 走 OFDM 传输 noma_rx = awgn(noma_rx, snr_db(idx), 'measured'); noma_rx = ofdm_rx(noma_rx, N, cp_len); noma_bits = noma_dec(noma_rx, M, num_users, power_alloc); % ---- OFDMA 链路 ---- [ofdma_sym, subcarrier_map] = ofdma_enc(tx_bits, M, N, num_users); ofdma_rx = ofdm_tx(ofdma_sym, N, cp_len); ofdma_rx = awgn(ofdma_rx, snr_db(idx), 'measured'); ofdma_rx = ofdm_rx(ofdma_rx, N, cp_len); ofdma_bits = ofdma_dec(ofdma_rx, M, N, num_users, subcarrier_map); % ---- 误码率统计 ---- [~, ber_noma(idx)] = biterr(tx_bits, noma_bits); [~, ber_ofdma(idx)] = biterr(tx_bits, ofdma_bits); end % 保存并画图 save('ber.mat', 'ber_noma', 'ber_ofdma', 'snr_db'); plot_ber(snr_db, ber_noma, ber_ofdma);

这段代码的逻辑说明:data_gen产生随机比特,noma_enc按功率分配把多个用户的符号叠加,ofdm_tx做 IFFT 和加 CP,awgn加高斯白噪声,ofdm_rx做去 CP 和 FFT,noma_dec用 SIC 逐用户解码。OFDMA 那边,ofdma_enc把不同用户的符号映射到不同子载波上,接收端按子载波解映射。最后biterr统计误码数,除以总比特数得到 BER。

参数说明:N=64是子载波数,改大能提高频谱分辨率但增加计算量;cp_len=16是循环前缀长度,一般取 N 的 1/4 到 1/8;M=4对应 4PSK,改成 2 就是 BPSK,改成 8 就是 8PSK;num_users=2是 NOMA 叠加的用户数,改大对 SIC 要求更高;num_bits=1e5是每轮仿真比特数,太小 BER 曲线会抖,太大跑得慢,1e5 到 1e6 之间比较合适。

3.2 功率分配对 NOMA 性能的影响

NOMA 的核心参数是功率分配。noma_enc.m里一般会有一个功率分配向量,比如power_alloc = [0.8, 0.2]表示近用户分 80% 功率,远用户分 20%。这个比例直接决定 SIC 能不能正确解出远用户。如果远用户功率太低,SIC 第一步就解错了,后面全错。

% noma_enc.m 中功率分配与叠加编码的常见写法 function [tx_sym, power_alloc] = noma_enc(bits, M, num_users) % 默认功率分配:近用户高功率,远用户低功率 power_alloc = linspace(0.8, 0.2, num_users); power_alloc = power_alloc / sum(power_alloc); % 归一化 tx_sym = 0; for u = 1:num_users % 每个用户独立调制 user_bits = bits((u-1)*length(bits)/num_users + 1 : u*length(bits)/num_users); mod_sym = pskmod(user_bits, M); % 按功率叠加 tx_sym = tx_sym + sqrt(power_alloc(u)) * mod_sym; end end

逻辑说明:linspace(0.8, 0.2, num_users)生成从 0.8 到 0.2 的等间隔功率系数,两个用户时就是 [0.8, 0.2]。归一化保证总功率为 1。每个用户的比特独立调制后乘以功率系数的平方根再叠加。接收端 SIC 先解高功率用户,解出来后重构信号减掉,再解低功率用户。

参数怎么改:如果远用户信道条件很差,可以把功率分配改成 [0.7, 0.3] 甚至 [0.6, 0.4],让远用户多一点功率。但近用户的 BER 会变差,需要折中。常见做法是跑几组不同功率分配,看两条 BER 曲线的交叉点。

注意:pskmod默认输出是列向量,如果你的data_gen产生的是行向量,记得转置,否则biterr会报维度不匹配。这个坑我踩过不止一次。

4. 避坑与排查:跑不出曲线时先查这五处

4.1 现象:BER 曲线一直是 0.5,完全不下降

原因:收发两端的数据维度或调制阶数不一致。比如发射端用 4PSK,接收端noma_dec里写的是 2PSK 的解调,解出来的比特和原始比特完全对不上。或者data_gen产生的是行向量,pskmod按列处理,导致符号数对不上。

解决:在main_v2_ber.m里加一行size(tx_bits)和size(noma_bits)打印,确认维度一致。再检查M参数在收发两端是否传的是同一个值。常见做法是把M定义在主脚本开头,所有函数都从这个变量读,不要在各函数里硬编码。

4.2 现象:NOMA 的 BER 比 OFDMA 还差,和理论相反

原因:功率分配不合理,或者 SIC 解码顺序错了。NOMA 理论上在特定功率分配下能比 OFDMA 有更好的边缘用户性能,但前提是 SIC 先解高功率用户。如果noma_dec.m里先解低功率用户,信干噪比太低,第一步就错,后面全崩。

解决:打开noma_dec.m,确认解码顺序是按功率从大到小。如果是两个用户,先解power_alloc大的那个。解完后用pskmod重构再减掉,再解第二个。这个顺序不能反。

4.3 现象:awgn报错“信号功率测量失败”

原因:awgn函数用'measured'模式时会先测信号功率,如果输入信号是全零或者功率极低,测量会失败。常见于 SNR 设得很高、信号被衰减到接近零的情况。

解决:把awgn的调用改成手动指定功率,比如awgn(sig, snr_db, 10*log10(mean(abs(sig).^2)))。或者检查ofdm_tx输出是不是全零,有时候 IFFT 之后没做归一化,功率小到测量不出来。

4.4 现象:跑完main_v2_ber.m后ber.mat是空的

原因:save语句在循环里被覆盖,或者变量名写错。常见的是save('ber.mat', 'ber_noma')只存了一个变量,plot_ber.m读的时候找不到ber_ofdma。

解决:在循环结束后统一save,把snr_db、ber_noma、ber_ofdma都存进去。plot_ber.m里用load('ber.mat')后检查whos确认变量都在。

4.5 现象:8PSK 的图跑不出来,报“调制阶数不支持”

原因:pskmod对 8PSK 要求输入比特是 3 的整数倍。如果num_bits设的是 1e5,不是 3 的倍数,最后一组符号会缺比特,导致报错或结果错位。

解决:把num_bits改成 3 的倍数,比如 99999 或 100002。或者用floor(num_bits/3)*3截断。4PSK 要求 2 的倍数,BPSK 任意。这个细节在换调制方式时特别容易忘。

5. 进阶技巧:用 BER 数据做公平对比与曲线拟合

跑出两条曲线只是第一步,真正要做对比,得保证仿真条件公平。我一般会在main_v2_ber.m里加一段控制变量逻辑:NOMA 和 OFDMA 用同一个data_gen种子、同一个 SNR 向量、同一个信道实例。如果awgn每次调用都重新生成噪声,两条链路的噪声不一样,对比就不公平。常见做法是在循环内先rng(seed)固定随机数,再分别跑两条链路。

% 公平对比:固定随机种子,保证两条链路经历相同噪声 for idx = 1:length(snr_db) rng(42); % 固定种子 tx_bits = data_gen(num_bits); rng(42); % 重置种子,NOMA 和 OFDMA 用相同噪声 noma_rx = awgn(ofdm_tx(noma_enc(tx_bits, M, num_users), N, cp_len), snr_db(idx), 'measured'); rng(42); % 再次重置 ofdma_rx = awgn(ofdm_tx(ofdma_enc(tx_bits, M, N, num_users), N, cp_len), snr_db(idx), 'measured'); % ... 后续解码和 BER 统计 end

逻辑说明:rng(42)把随机数生成器重置到固定状态,这样awgn产生的噪声序列在两条链路里完全一致。参数 42 是任意选的,换成别的整数也行,关键是三次调用用同一个种子。这样 NOMA 和 OFDMA 的 BER 差异就只来自多址方式本身,而不是噪声随机性。

另一个技巧是曲线拟合。ber.mat里的数据点有限,画出来是折线。如果想看平滑趋势,可以用semilogy加interp1插值。但注意插值只是视觉平滑,不能改变数据本身。我一般直接用semilogy(snr_db, ber_noma, 'o-'),标记点加连线,既看出趋势又保留原始数据点。

提示:如果你要写报告或论文,记得把num_bits加大到 1e6 以上,否则高 SNR 段 BER 可能统计不到足够的误码数,曲线尾部会断。常见做法是设一个最小误码数阈值,比如 100 个误码就停,没到就继续加比特。

从那以后我每次跑对比仿真,都强制先固定随机种子再跑两条链路,不然两条曲线的差异里混着噪声随机性,根本说不清是谁的功劳。希望帮到你。

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

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

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

立即咨询