做无人机辅助蜂窝卸载这个方向,最难的不是把NOMA的公式背出来,而是把整个系统在Matlab里"跑通"并且"跑对"。这个项目我前后改了三四版,从最初只做OMA下的卸载仿真,到后来把UAV、NOMA、部分卸载三件事揉在一起做性能分析和优化,中间踩过的坑、试错的经验,值得完整记录下来。这篇博文就围绕"无人机辅助非正交多址蜂窝卸载"这个仿真项目展开,把系统模型怎么搭、Matlab代码怎么组织、优化迭代怎么做、仿真结果怎么解读讲透,适合正在做无线通信方向毕业设计、论文复现或者准备投会议期刊的研究生参考。
1. 项目整体设计与选题背后的逻辑
1.1 为什么无人机、NOMA和蜂窝卸载要放在一起
先理清三个概念各自解决什么问题。蜂窝卸载指的是终端设备把计算任务发送给边缘服务器或者基站处理,以节省本地能量、降低任务处理时延。传统的地面蜂窝网络中,基站位置固定、覆盖范围有限,一旦用户处在小区边缘或者被建筑物遮挡,卸载链路的信道质量就很差,传输速率上不去,任务传不出去,卸载也就失去了意义。
无人机辅助的核心价值在于它能把"基站"或者"中继节点"搬到空中,通过机动性缩短与用户之间的通信距离,构建一条更大概率是视距(Line of Sight,LoS)的传输链路。这样一来,边缘用户的卸载速率显著提升,系统吞吐量和任务处理效率都跟着改善。
那NOMA为什么也要卷进来?正交多址(OMA)方案下,每个时频资源块同一时刻只能服务一个用户,用户多了就得排队或者划分时隙,频谱效率有限。非正交多址(NOMA)在功率域做叠加编码,允许多个用户共享同一个资源块,接收端用串行干扰消除(SIC)分离信号,在用户过载场景下能明显提升频谱利用率和连接数。放到无人机蜂窝卸载的场景里,NOMA可以让无人机同时为多个设备提供卸载服务,一台无人机、一个信道、多个用户任务并行传输,这对任务队列比较密集的场景非常友好。
把三者叠加后,项目要回答的核心问题就很清晰了:在无人机辅助的蜂窝网络中,如何通过NOMA提升多用户的卸载性能?如何联合优化无人机位置、NOMA功率分配和卸载决策,使系统时延或能耗最小化?这个问题既有理论深度,又有工程落地空间,非常适合用Matlab做仿真验证。
1.2 项目方案选型:为什么用部分卸载而非二进制卸载
卸载决策在边缘计算研究中分为两类:二进制卸载和部分卸载。
二进制卸载的模型比较简单粗暴,一个任务要么全部留在本地执行,要么整个卸载到边缘服务器,不存在"一半本地、一半卸载"的状态。这种模型适合任务不可分割的场景,比如一个包含固定依赖关系的完整应用模块。部分卸载则允许将任务按比特或按数据块拆分,本地处理一部分、卸载处理一部分,通过调整卸载比例来权衡本地计算时延与传输时延。
这个项目选定的是部分卸载,原因很实际:整体优化的自由度更高。引入卸载比例因子后,系统多了一个连续优化变量,展示算法收敛曲线和性能随参数变化的规律时更直观,审稿人或者导师看到的结果也更丰满。例如,当本地CPU计算能力较弱但信道条件很好时,卸载比例可以接近1;如果信道质量差、任务数据量又大,完全卸载会导致传输成为瓶颈,此时适当保留一部分在本地算反而是最优策略。
在我给的这套Matlab代码里,卸载比例可以是固定值(用于对照实验),也可以参与联合优化(用于展示算法增益)。建议初学者先把固定比例跑通,理解NOMA和无人机带来的影响,再过渡到变量优化。
1.3 性能指标怎么选:时延与能耗的加权权衡
通信系统研究里,最常见的性能指标是吞吐量、频谱效率、时延、能耗、能效。对于蜂窝卸载这种面向任务处理的场景,时延和能耗更贴近用户的真实体验,所以我把系统的加权和代价函数定义为:
cost = alpha * T_total + (1 - alpha) * E_total
其中T_total是所有用户卸载任务的总时延开销,E_total是总能耗开销,alpha是权重系数,取值0到1。alpha = 1表示纯时延优化,alpha = 0表示纯能耗优化。这个设计的好处是可以通过调节alpha画出Pareto前沿,在文章里展示系统在不同需求偏好下的性能折中。
具体的时延计算,分为本地计算时延和卸载传输时延。本地计算时延 = 任务数据量 * 卸载剩余比例 / 设备CPU频率;卸载传输时延 = 任务数据量 * 卸载比例 / 传输速率。传输速率由香农公式给出,在NOMA场景下还要考虑SIC解码顺序带来的信干噪比差异。
2. 系统模型构建与核心原理拆解
2.1 网络场景:一个无人机、多用户、单基站的卸载架构
先把仿真场景固定下来。考虑一个单小区蜂窝网络,地面基站位于坐标原点,覆盖范围500米。小区内有K个单天线用户,随机分布在基站覆盖区域内,比如在半径300到500米的圆环区域内撒点,模拟边缘用户的处境。一架无人机作为空中边缘节点,悬停在某个高度H,水平坐标可以移动。
用户产生的任务有三种处理路径:
- 路径1:本地直接计算
- 路径2:卸载给无人机处理,无人机配备边缘计算服务器
- 路径3:先卸载给无人机,无人机再做转发给地面基站处理(这条路径在这个项目里作为可选扩展,基础版本通常只用到前两条)
这样设置的原因是要模拟真实蜂窝网络中"无人机补盲"的场景。边缘用户直连地面基站的信道差,但直连无人机的信道可能很好,因为空地信道大概率是视距信道,路径损耗更小、链路更稳定。
Matlab里的参数初始化,建议做成一个独立的脚本或者函数块统一管理,例如:
% 系统基本参数 B = 2e6; % 带宽 2MHz fc = 2e9; % 载频 2GHz N0 = -174 + 10*log10(B); % 噪声功率,单位dBm P_bs = 43; % 基站发射功率 dBm P_uav = 30; % 无人机发射功率 dBm K = 6; % 用户数量 H_uav = 100; % 无人机悬停高度(米) R_cov = 500; % 小区覆盖半径(米) data_size = 500e3; % 任务数据量 500kbit C_local = 1e9; % 本地CPU频率 1GHz C_edge = 10e9; % 边缘服务器CPU频率 10GHz alpha_weight = 0.5; % 时延-能耗权衡系数2.2 空地信道模型:视距概率计算结果
空地信道和地面信道的最大区别,是要显式建模视距和非视距(NLoS)的混合状态。无人机虽然飞得高,但不能假设链路100%是视距,当无人机和用户之间的仰角较小,或者建筑物遮挡严重时,NLoS的路径损耗会明显增大。
常用的概率模型把LoS概率表示为仰角的函数:
p_LoS(theta) = 1 / (1 + a * exp(-b * (theta - a)))
其中a和b是由环境决定的常数,比如密集城区a = 9.61、b = 0.28,郊区a = 4.88、b = 0.43。theta是用户到无人机的仰角。
路径损耗相应分为两类:
- LoS链路:PL_LoS = 20log10(4pifcd/c) + eta_LoS
- NLoS链路:PL_NLoS = 20log10(4pifcd/c) + eta_NLoS
其中eta_LoS和eta_NLoS是额外的环境衰减因子,比如LoS链路取1 dB,NLoS链路取20 dB。信道系数再叠加小尺度衰落,一般建模为莱斯衰落,视距分量占比由K因子控制。
Matlab实现时要注意,每次生成用户位置后都要先计算仰角,再计算LoS概率,然后随机判定该次仿真的链路状态。不能用简单的路径损耗公式一把梭,否则仿出来的结果没有空地链路的特征。
2.3 NOMA功率域叠加与SIC解码机制
NOMA的核心是发送端叠加、接收端串行干扰消除。以两个用户为一组为例,无人机(或基站)在同一个子信道上向用户u1和u2发送叠加信号:
x = sqrt(P1) * x1 + sqrt(P2) * x2
其中P1 + P2 = P_total,信道质量较差的用户分配更高的发射功率,这是NOMA的基本分配原则,因为SIC解码时先解信道好的用户,把信道差的用户信号当作干扰。
接收端u1在解码自己信号时,会把u2的信号视作干扰,此时SINR为:
SINR_1 = P1 * |h1|^2 / (P2 * |h1|^2 + sigma^2)
如果用户1的信道增益大于用户2,那么用户1先解出自己的信号,再从接收信号中减去(SIC),后续用户2解码时已经没有了用户1的干扰,SINR变成:
SINR_2 = P2 * |h2|^2 / sigma^2
这个机制在Matlab里实现时,最关键的步骤是正确排序。我在第一次写代码时,直接把所有用户按信道增益从大到小排列,然后依次做SIC,结果发现某些场景下出现在干扰项里的用户顺序反了,导致SINR算错,误码率完全对不上。后来改用函数封装排序逻辑,并添加了断言,确保每一层SIC都使用正确的信道增益顺序,仿真才算稳定。
2.4 任务卸载模型与总代价函数
假设第k个用户的卸载比例为xita_k,取值范围0到1。任务数据量为D_k,则:
- 本地计算量 = (1 - xita_k) * D_k
- 卸载计算量 = xita_k * D_k
本地计算时延 = (1 - xita_k) * D_k / C_local 卸载传输时延 = xita_k * D_k / R_k
其中R_k是用户到无人机的可达速率,由信道带宽和SINR决定。边缘计算时延 = xita_k * D_k / C_edge,这部分和传输相比通常较小,但严谨起见也加进去。
总代价还是上面说的那套加权公式。Matlab实现时,我建议把代价函数单独写成一个function,后面无论是遍历搜索、梯度下降还是使用CVX求解,都可以直接调用这个函数评估结果,避免重复计算导致的不一致。
3. Matlab仿真架构与代码模块实现
3.1 顶层脚本与模块划分
整个项目我采用"主脚本 + 功能函数"的结构,主脚本负责参数初始化、蒙特卡洛循环和结果绘图,功能函数包括信道生成、NOMA传输、代价计算、优化求解。
%% 主脚本:UAV_NOMA_Offloading_Main.m clear; close all; clc; % 载入参数 initParams; % 蒙特卡洛循环 numIter = 100; resTotal = zeros(numIter, 1); for iter = 1:numIter % 生成用户位置 posUser = generateUsers(K, R_cov); % 生成信道 channelInfo = generateChannel(posUser, posUAV, params); % NOMA功率分配 [pPower, order] = nomaPowerAllocation(channelInfo, P_uav); % 卸载优化 [xitaOpt, costOpt] = optimizeOffloading(channelInfo, pPower, sysPar); resTotal(iter) = costOpt; end % 平均结果 avgCost = mean(resTotal); fprintf('平均代价:%.4f\n', avgCost);3.2 信道生成模块的完整实现
信道生成是UAV仿真里最容易出bug的地方,我把我的实现贴出来重点讲解:
function chanInfo = generateChannel(posUser, posUAV, par) % 输入: % posUser: Kx2 用户平面坐标 % posUAV: 1x2 无人机平面坐标 % par: 参数结构体 % 输出: % chanInfo.h: Kx1 信道系数(复数) % chanInfo.pl: Kx1 路径损耗(dB) % chanInfo.losFlag: Kx1 链路状态 K = size(posUser, 1); chanInfo.h = zeros(K, 1); chanInfo.pl = zeros(K, 1); chanInfo.losFlag = zeros(K, 1); for k = 1:K dist2D = norm(posUser(k, :) - posUAV); dist3D = sqrt(dist2D^2 + par.H_uav^2); theta = atan2(par.H_uav, dist2D) * 180 / pi; % LoS概率(市区模型) pLoS = 1 / (1 + par.a_env * exp(-par.b_env * (theta - par.a_env))); isLoS = rand < pLoS; if isLoS pl = 20*log10(4*pi*par.fc*dist3D/par.c) + par.eta_LoS; chanInfo.losFlag(k) = 1; else pl = 20*log10(4*pi*par.fc*dist3D/par.c) + par.eta_NLoS; chanInfo.losFlag(k) = 0; end % 叠加小尺度衰落:莱斯衰落,视距分量K因子 Kfactor = 10; if isLoS % 莱斯信道:直射分量+散射分量 direct = sqrt(Kfactor/(Kfactor+1)) * exp(1i*2*pi*rand); scatter = sqrt(1/(Kfactor+1)) * (randn + 1i*randn)/sqrt(2); smallFade = direct + scatter; else % Rayleigh衰落 smallFade = (randn + 1i*randn)/sqrt(2); end chanInfo.h(k) = smallFade * sqrt(10^(-pl/10)); chanInfo.pl(k) = pl; end end注意几个要点。第一,theta计算必须用atan2而不是atan,因为用户和无人机的相对位置在四个象限都可能出现,atan2能正确返回[-180, 180]区间的角度。第二,LoS概率是随机性的判断,所以每轮蒙特卡洛仿真的链路状态都不同,这就需要在报告中说明统计次数,一般至少1000次以上才能看到稳定的平均性能。第三,莱斯衰落里的K因子直接影响信道质量,这个参数在代码里应该由环境决定,而不是随便写死,建议把它和LoS/NLoS状态绑定。
3.3 NOMA功率分配模块:从固定分配到注水算法
功率分配模块决定了NOMA叠加信号的功率分布。最简单也最常用的是分数阶功率分配(FTPA):
function [pPower] = nomaPowerAllocation(h, P_total, alpha_f) % 分数阶功率分配 % alpha_f典型值0.2~0.6,越大越偏向信道差的用户 hAbs = abs(h); [~, idx] = sort(hAbs, 'descend'); % 信道好的用户排前面 % 按信道增益从大到小,功率从小到大(逆序分配) K = length(h); pPower = zeros(K, 1); denom = sum((1 ./ hAbs(idx)).^alpha_f); for k = 1:K pPower(idx(k)) = P_total * (1/hAbs(idx(k)))^alpha_f / denom; end end上面这个实现,信道最差的用户会分到最大功率,符合NOMA功率分配原则。这里alpha_f是一个可调参数,当alpha_f = 0时退化为等功率分配,当alpha_f增大时,功率向信道差的用户倾斜,相当于提升了SIC解码过程中最弱链路的可靠性,但代价是信道好的用户受到更强干扰。
3.4 卸载比例优化:一维搜索与二分法
在给定信道和功率分配的条件下,卸载比例的优化是一个一维问题,因为每个用户的卸载代价函数在其定义域内往往是凸的。对于单个用户,代价函数可以写为:
f(x) = alpha * max(T_local(x), T_offload(x)) + (1-alpha) * E(x)
这个max函数会带来非光滑性,所以实际问题里,工程上更常用的是遍历搜索法,因为用户数量不大时计算量完全可以接受。例如把卸载比例从0到1按0.01的步长离散化,对每个用户分别寻找最优比例,100个采样点乘以K个用户,耗时不过几十毫秒。
如果追求严谨,可以在每个区间内用fminbnd做精细搜索:
% 单用户卸载优化 fun = @(x) costFunction(x, hk, Pk, par); xitaOpt = fminbnd(fun, 0, 1);fminbnd用的是黄金分割法,适合单变量有界优化,不需要导数信息。实践下来收敛很快,而且能处理非光滑目标函数。
3.5 蒙特卡洛仿真与结果存储
整个仿真框架我最推荐的方式是:外层跑蒙特卡洛,内层做单次随机场景的优化,最后把所有样本的平均性能存下来。原因在于UAV信道有随机性(LoS状态、小尺度衰落都是随机的),单次仿真的结果波动很大,不取平均就得出"最优方案比OMA方案好50%"的结论是没有统计学意义的。
我在实际项目中,每次随机撒点用户位置,跑完一轮优化之后,会额外把OMA方案在相同信道条件下的代价也算出来,作为对照组。这样做的好处是,两次对比使用完全相同的信道随机种子,排除了信道随机性对对比结果的干扰。Matlab里可以通过rng(iter)控制随机种子,确保公平对比。
4. 性能分析与联合优化
4.1 无人机位置优化:从穷举网格到连续优化
无人机的位置对空地信道质量影响极大。这个项目的第一个优化维度就是无人机水平坐标。
最直接、最稳妥的方法是二维网格搜索。把目标区域划分成10米间隔的网格,在每个候选位置计算系统总代价,选择代价最小的点作为无人机最优位置。这种方法简单、可复现、不需要推导梯度,在目标函数非凸、不光滑的情况下非常实用。缺点是复杂度和网格分辨率相关。
后期如果想要展示更高级的优化能力,可以换成连续优化。比如固定用户位置和功率分配后,用户到无人机的距离是无人机坐标的凸函数,但代价函数涉及对数,整体不是全局凸的。此时常用的做法是连续凸逼近(SCA),把非凸项在每轮迭代中替换成其下界,然后求解凸子问题。SCA的实现相对复杂,但对审稿人和导师而言更有说服力。
我在代码里默认提供网格搜索版本,但接口设计成可替换的优化器形式,后续想升级成SCA或者粒子群算法,只需修改optimizeUavPosition函数的内部实现。
4.2 功率分配优化与用户调度的联合设计
NOMA场景里"哪些用户配上对"和"每对用户怎么分功率"是耦合的。很多论文把用户配对当组合问题处理,先按信道增益排序,再相邻配对,这样可以减少NOMA组内用户信道差异过大的情况。
如果信道差异太大,SIC解码时弱用户的信号会干扰强用户,强用户即使功率小也可能解码失败。如果信道差异太小,NOMA的增益不明显,和OMA相比没有优势。所以配对策略一般遵循"信道好的配信道差的,但差距不能拉得过大"。
功率分配这块,除了FTPA,还可以用迭代注水算法。在NOMA组内,优化各用户的功率使组吞吐量最大化,是一个典型的凸问题,可以用CVX求解:
cvx_begin variable p(K, 1) maximize(sum(log(1 + p .* hVec ./ noiseInter))); subject to sum(p) <= P_total; p >= 0; cvx_end当然,CVX需要额外安装,而且在做蒙特卡洛大循环时速度会明显变慢。我建议在基础仿真阶段先用FTPA,到了做对比实验阶段再用CVX求解作为性能上界。
4.3 NOMA与OMA的对比实验结果解读
仿真结果对比是整篇论文的核心支撑。从项目复现的典型结果来看,有以下几个规律值得注意。
在用户数较多且任务密集的场景下,NOMA比OMA的卸载时延能降低20%到40%。增益来源在于NOMA允许两个用户同时共享同一个子信道,单位时间内能传输更多任务比特,排队时延显著下降。而在用户数少、信道质量都很好的场景下,NOMA和OMA的性能差距缩小,有时甚至接近,这说明NOMA的收益和过载程度正相关。
无人机悬停高度对性能的影响是双面的。高度增加,覆盖范围扩大,但路径损耗增大;高度过低,LoS概率下降,信道波动加剧。仿真结果显示存在一个最优高度,通常在80到120米之间,具体取决于环境参数和小区半径。这个结论在论文里可以作为参数敏感性分析的一部分。
4.4 算法收敛性与运行时间对比
联合优化如果采用交替迭代策略,例如固定无人机位置优化功率分配、固定功率分配优化无人机位置,循环迭代直到收敛,那么需要记录每一轮迭代的代价函数值,绘制收敛曲线。正常情况下,代价函数应该单调不增,迭代次数大约在10到20轮之间,因为无人机位置的网格搜索和功率分配的凸优化都已经各自收敛,交替迭代不会出现明显振荡。
如果发现收敛曲线有振荡,大概率是某个子问题求解没到位,或者离散化网格太粗导致无人机位置在相邻网格间来回跳,解决方法是加密网格或改用连续优化。
5. 常见问题与排查技巧实录
5.1 信道生成模块最容易忽略的细节
很多复现论文的代码,信道模型只写了一个大尺度路径损耗公式,没有区分LoS和NLoS,导致无人机高度对性能的影响完全反映不出来。正确的做法是必须把LoS概率公式、两类路径损耗参数、小尺度衰落类型三者一起建模。
另外,概率型LoS模型每次仿真都会随机判断链路状态,这导致如果只跑几十次仿真,结果方差极大。我建议所有对比实验至少跑500到1000次蒙特卡洛,并且在代码里记录每条链路的LoS比例,如果统计出来的LoS概率和理论值偏离超过5%,说明随机数生成或者角度计算有问题。
5.2 SIC解码顺序引发的"看似正常其实错误"
NOMA仿真的错误很大一部分出在SIC上。常见错误是直接把用户按信道增益排序后,功率分配也按同一顺序,解出来的SINR却是反的。另一个常见问题是,用户分组内有一个用户信道特别差,导致SIC第一层的解码失败率很高,这时应在功率分配上给强用户更小的功率、给弱用户更大的功率,否则系统整体性能反而比OMA更差。
我在仿真里加了一个自检机制:计算完SINR之后,检查每个用户的可达速率是否为正,如果出现负数,则直接终止程序并输出告警。这个简单操作帮助我抓出了好几处排序错误。
5.3 蒙特卡洛仿真的随机种子管理
随机种子管理在项目初期容易被忽略,但在对比实验阶段是保命技能。如果每次仿真的用户位置、信道状态都不一样,OMA和NOMA的对比结果受随机噪声影响,看不出真实性能差距。正确做法是设置全局随机种子,比如rng(2024),或者在外层循环里每轮固定种子再分别调用不同算法。
5.4 CVX安装与求解精度问题
如果做凸优化部分,CVX是绕不开的工具。安装时注意版本兼容性,在Windows上建议使用Matlab R2020b以上的版本,否则容易出现内部求解器无法初始化的问题。CVX默认使用SDPT3求解器,在处理大规模问题时速度偏慢,可以换成SeDuMi或Mosek。实际仿真中,如果变量规模不大,SDPT3足够;如果用户数超过20个,建议直接上Mosek,否则一轮蒙特卡洛要跑好几分钟。
5.5 仿真程序运行速度的优化心得
Matlab跑通信仿真天然比C++慢,但通过几个技巧可以显著提速。一是避免在for循环中使用动态数组,所有矩阵预先分配;二是把蒙特卡洛循环中不依赖随机种子的部分提到循环外;三是使用parfor做并行蒙特卡洛,前提是每次迭代之间要独立。
我实测过,在8核CPU上,用parfor替换for,1000次蒙特卡洛仿真的耗时从约12分钟降到约3分钟。
6. 代码工程化与后续扩展方向
6.1 目录结构与脚本命名规范
代码量上来之后,工程的目录结构就很重要。我建议按以下目录组织:
UAV_NOMA_Offloading/ ├── main/ % 主脚本入口 ├── functions/ % 核心功能函数 ├── optimization/ % 优化算法 ├── plot/ % 绘图脚本 ├── results/ % 结果数据存储 └── README.md % 使用说明6.2 可扩展方向:多无人机协同与动态轨迹
这个项目做完了基础版本之后,扩展空间很大。比如把单无人机扩展成多无人机协同,多个无人机组成空中边缘计算网络,这时需要引入无人机间的任务调度和干扰管理,模型复杂度上一个大台阶,但也更容易出创新点。再比如把悬停无人机扩展成动态轨迹,无人机沿着优化出的轨迹飞行,在移动中完成卸载服务,这在实际巡检和应急场景中很有意义,但仿真量也会成倍增加。
6.3 从仿真到论文的衔接要点
最后分享一点关于出成果的经验。仿真做完只是第一步,要形成一篇像样的论文,建议把结果整理成三类图表:一是系统架构和流程图,二是性能对比曲线(NOMA vs OMA、有无无人机),三是参数敏感性分析表格。这三类内容分别对应了文章的问题阐述、核心贡献和工程指导意义,缺一不可。Matlab代码本身不是成果,代码背后的分析和结论才是。