这几年做空对地通信仿真我和团队接触最多的一个组合就是无人机当空中基站地面终端散落在楼宇、山体、树冠之间非视距遮挡严重固定基站要么够不着要么容量不够。常规做法是让无人机沿着预设航点巡航但用户一挪、场景一变航线就基本作废需要重新手动规划。后来我们把问题拆成两层来解决物理层用NOMA非正交多址接入把同一个频谱资源切给多用户提升系统容量控制层用去中心化Q-Learning让每架无人机根据自身局部观测独立学习路径策略。整套思路最后在Matlab里落了地今天这篇就是完整的项目拆解包括系统建模、算法设计、仿真代码框架和调参踩坑记录。适合正在做无人机通信、NOMA资源调度、强化学习路径规划的硕博生和工程开发人员参考。1. 项目背景与问题拆解双无人机为什么要和NOMA、Q-Learning绑在一起1.1 场景痛点与设计动机先还原一下原始问题。某个园区做应急通信演练地面基站断电需要临时恢复覆盖。现场有十几个终端分布在几栋建筑之间有一部分终端处在严重遮挡区域地面基站临时架设难度大、周期长。这时候无人机作为空中接入点的价值就体现出来了它飞得高视距链路概率大部署快而且可以通过优化航迹主动逼近用户。但真正落地时发现三层问题。第一层是频谱资源紧张。一片区域内用户一多频带就分不过来。如果每用户独占一个时频资源块容量天花板很低。第二层是路径规划。双无人机各自服务一组用户但用户分布不均匀有的区域用户密集、有的区域稀疏无人机如果飞得不对距离一远信道质量就断崖式下跌。第三层是控制架构。最直观的想法是地面中心统一管控收集所有状态、下发所有动作但实际场景链路易断、时延不可控一旦中心失效全盘瘫痪。NOMA解决第一层问题。它允许同一个资源块通过功率域或码域区分用户接收端用串行干扰消除SIC把混叠信号拆开频谱效率直接翻倍。Q-Learning解决第二和第三层问题。每个无人机被建模成独立智能体根据自己的位置、用户分布和信道观测决定下一步往哪飞、用多大功率不依赖统一中心。1.2 技术选型逻辑NOMA解决什么去中心化强化学习解决什么先说NOMA。传统正交多址OMA给每个用户分配正交资源缺点是资源利用率上限低。NOMA的思路很直接在发送端用不同功率叠加多个用户的信号在接收端按信号强度排序依次解码。功率分配是核心——强用户信道条件好的分配较小功率弱用户信道条件差的分配较大功率这样弱用户可以直接把强用户信号当噪声解出自己的信号强用户则通过SIC先解出并消掉弱用户信号再解自己的。放在双无人机场景里两架无人机可以选择同一时频资源、分别服务一对“近强远弱”的用户通过功率域NOMA叠加在一个资源块上同时传两路数据。系统吞吐量、边缘用户速率、频谱效率三项指标都能得到改善。再说Q-Learning。很多人会问路径规划用A*、人工势场、凸优化不是更成熟这些方法的问题在于当环境是动态的、用户分布不可预知、目标是长期累计吞吐量而非单步最短路径时无模型的强化学习更有优势。Q-Learning不需要信道模型精确已知只需要定义好状态、动作、奖励然后通过试错迭代学出一个策略表。而且它天然适合做成去中心化——每个智能体维护自己的Q表自己探索、自己利用单机决策复杂度低符合无人机集群没有地面中心节点或链路经常中断的约束条件。这里需要说清楚去中心化不等于完全孤立。它指的是不依赖全局状态和中央调度器但无人机之间仍然可以通过机间链路交换少量必要信息比如避免飞入同一区域、避免信号互干扰。在设计Q表的奖励函数时可以把碰撞惩罚和干扰惩罚嵌进去实现“局部决策、全局协调”的效果。2. 系统模型与数学基础信道、NOMA配对、无人机运动模型2.1 三维空对地信道模型仿真里信道模型不能随便拿一个自由空间损耗公式糊弄过去。空地信道和地面信道最大的区别在于仰角会显著影响视距概率。建筑、树木、地形遮挡会随仰角变化典型工程做法是采用概率视距模型把路径损耗写成视距分量和非视距分量的加权平均。上行和下行场景不同但我这里只说下行传输。无人机到地面用户的路径损耗表达式为L 20log10(4πf d / c) P_LOS * η_LOS P_NLOS * η_NLOS其中d是三维距离d sqrt((x_u - x_g)^2 (y_u - y_g)^2 h^2)。h是无人机飞行高度f是载波频率c是光速。η_LOS和η_NLOS是额外损耗因子视距条件下取小一些非视距条件下取大一些。P_LOS和P_NLOS是视距和非视距概率随仰角提升P_LOS单调上升。还有一个细节是信道增益h_ch 10^(-L/10)。后续算SINR时直接就归一化到1毫瓦参考功率上。2.2 功率域NOMA的SINR建模假设一个时隙内无人机A以功率P1服务弱用户无人机B以功率P2服务强用户两个信号在同一个子载波上叠加发射。弱用户信道增益记为g_weak强用户信道增益记为g_strong噪声功率N0。弱用户直接被服务解码时把强用户信号视为干扰SINR_weak P1 * g_weak / (P2 * g_strong N0)强用户采取SIC先解弱用户信号并从混合信号中消除再解自己的信号SINR_strong P2 * g_strong / N0从公式能看出来几个关键点。第一弱用户的干扰项里含P2 * g_strong如果两架无人机把功率都加到最大弱用户反而容易被干扰吞掉。第二SIC的前提是强用户能正确解出弱用户信号这要求弱用户功率足够强否则SIC会失效。第三两架无人机各自服务不同用户但它们共享同一个频段所以彼此之间的功率分配变成了一个联合优化问题这也是后面奖励函数要重点考虑的部分。配套还要考虑用户到哪个无人机的配对。实际工程中先在每个时隙根据信道增益做配对信道好的用户和信道差的用户配成一组再决定哪架无人机给哪个用户发。仿真时我用的原则是每架无人机只服务离自己最近的几个用户两个无人机选取的配对用户保证不重复。2.3 无人机运动与能耗模型无人机运行高度固定时可以简化成二维平面运动。我仿真时把高度设为100米速度上限12m/s每个时隙长度1秒也就是无人机每步最多移动12米。动作空间包含8个方向移动一步、原地悬停、以及3个功率档位。能耗模型是算奖励时绕不开的。悬停、水平飞行、加速都有不同功耗。简化但不失一般性的做法是飞行状态时功率功耗取常值P_hover加上与速度平方成正比的增量移动越远耗能越高。剩余能量作为一个状态分量进入Q表让无人机学会在电量低时减少不必要的绕飞优先飞到高价值用户区域。这里提一个容易踩的坑如果能量消耗只作为惩罚项放进奖励而不进入状态无人机永远学不会“想着电量做规划”。因为Q-learning本身是马尔可夫决策过程如果状态里没有剩余能量这个决策问题就不是马尔可夫的策略会受历史影响而抖动。所以剩余能量等级必须放进状态哪怕只离散成3到5档。3. 去中心化Q-Learning算法设计状态、动作、奖励与决策流程3.1 为什么必须去中心化中心化方案看起来更“标准”一个地面控制中心收集所有无人机的位置、能量、用户信道状态求解全局最优路径逐时隙下发动作。但真实场景里有一个致命问题——控制链路开销。无人机数量一多控制中心需要处理的联合状态空间会随无人机数量指数增长而且每次决策还要等链路往返时延高、可靠性差。更重要的是控制中心一旦被干扰或链路断裂所有无人机都会变成“无头苍蝇”。去中心化的本质是“每个智能体只根据局部观测做决策”。双无人机场景里每架无人机知道自己相对用户的位置、自己的剩余能量、自己当前对目标用户信道的估计以及另一个无人机的大致方位。它不需要知道另一位智能体完整的Q表也不需要中央节点做仲裁。我这样类比中心化像剧场导演指挥每个演员走位导演一离开演出就乱套去中心化像即兴表演每个演员只遵循基本规则、根据对手动作即兴反应。性能可能略低于全局最优但鲁棒性完全不在一个量级。3.2 状态与动作空间设计Q表的大小取决于状态离散化。状态空间如果直接放原始坐标比如1000米乘1000米区域、5米一格那就是4万个状态乘8个动作两个无人机各搞一张6位数的Q表训练量直接爆炸。我的处理方法是用相对信息做状态压缩而不是用绝对坐标。具体来说把无人机周围360度分成8个扇区每个扇区统计服务用户的个数。最近用户的距离等级分成近200米、中200到500米、远500米3档。剩余能量等级分成高、中、低3档。另一架无人机的相对方位分成同扇区或不同扇区2种状态。这样单机状态数量大约是8个扇区用户数的组合数实际按每个扇区0/1/2个用户量化乘以3乘以3乘以2可以控制在几千量级这是表格型Q-Learning可以处理的范围。动作空间更简洁8个移动方向 原地悬停 3档发射功率一共11个动作。这里把位置决策和功率决策放在同一个动作里是因为功率和位置对信道增益的影响是耦合的远距离悬停配大功率效果可能不如贴近用户配小功率。分两步决策会增加状态设计复杂度合在一起虽然动作空间变大但Q表规模还在可控范围。如果觉得动作数过多可以先跑简化版本9个动作8方向悬停、功率固定。路径收敛后再放开功率维度。3.3 奖励函数设计与参数权衡奖励函数是整个算法设计里最影响收敛效果的部分。我最终用的是这样一个综合奖励r w1 * ΔR_sum w2 * R_min - w3 * E_step - C_collision - C_boundary其中ΔR_sum是本时隙相对上一时隙系统总吞吐量的增量R_min是当前时隙两用户中最小的可达速率E_step是本步移动消耗的能量C_collision是两架无人机距离过近时的惩罚C_boundary是飞出预定区域的惩罚。为什么要用吞吐量增量而不是绝对吞吐量因为Q-Learning的Q值是通过累加折扣奖励来拟合长期回报的。如果奖励里带一个很大的常数基准项Q值会变得很大且变化不敏感训练曲线看起来像是“已经收敛”实际策略没有发生任何优化。用增量奖励可以让Q值对策略变化更敏感。R_min那一项是保证公平性的。如果只优化总吞吐量无人机很快会发现“喂饱离得近的强用户”是最高效策略边缘弱用户直接被放弃这既不符合通信公平性原则也浪费了NOMA弱用户链路的价值。折中方案是给最小速率乘以权重w2倒逼无人机在飞行过程中兼顾弱势用户。再说惩罚项。C_collision我设置的是两架无人机欧氏距离小于安全距离50米时给-5这个数值不能太小否则无人机倾向于贴着飞信号互相干扰严重但也不能太大否则两架无人机过度回避、各自往区域两边跑导致覆盖产生空洞。C_boundary设成-3因为仿真区域外围通常存在未知地形或禁飞区步进过程中一旦越界就回退并惩罚。3.4 训练流程与超参选择具体训练流程按标准Q-Learning走每个episode开始时随机撒用户位置无人机从固定起点起飞。每个时刻根据当前状态用epsilon-greedy策略选动作。执行动作后计算奖励、得到下一状态、更新Q表。当无人机电量耗尽或到达最大步数时结束episode重置场景继续下一轮。超参数我建议这样设置学习率alpha初始0.1每500个episode乘以0.9衰减最低不低于0.01折扣因子gamma取0.9到0.95之间gamma越大越看重长期收益但收敛越慢epsilon初始0.9随着训练推进衰减到0.05让智能体前期多探索、后期多利用。每个episode最大步数设为200保证训练不会无休止跑下去。还有一个容易被忽略的点状态初始化要覆盖多样场景。如果把用户位置撒点限制在一个小区内部学出来的策略只适用于那种均匀分布很脆弱。我在随机撒用户时会让位置分布混合模式一部分均匀分布、一部分集中成簇这样无人机学到的是更泛化的规则而不是对某一种分布的过拟合。4. Matlab仿真框架实现从信道函数到Q学习主循环4.1 工程目录与模块划分Matlab工程我按功能拆成几个脚本别全都塞进一个主文件里否则调试起来寸步难行。常见的目录结构如下drone_noma_qlearning/ main_run.m config_params.m init_scenario.m compute_channel.m compute_noma_rate.m compute_reward.m select_action.m update_qtable.m plot_results.mmain_run.m是入口负责加载参数、初始化环境、执行训练循环、保存结果。config_params.m集中存放所有超参数和系统参数每次跑新实验只用改这一个文件。compute_channel.m算空地信道增益compute_noma_rate.m算两个用户的SINR和可达速率compute_reward.m按公式计算奖励select_action.m实现epsilon-greedy选择update_qtable.m做Q表更新。4.2 核心函数实现与讲解先看信道函数。这一块要注意输入输出向量化避免后面循环里反复算重复量时性能拉胯。function [g_los, g_nlos, pl_prob] compute_channel(pos_drone, pos_user, fc, h_drone, env) c 3e8; d_3d sqrt((pos_drone(1)-pos_user(1))^2 ... (pos_drone(2)-pos_user(2))^2 h_drone^2); theta asin(h_drone / d_3d) * 180 / pi; A env.A; % 环境相关常量密集城区取较大值 B env.B; p_los 1 / (1 A * exp(-B * (theta - A))); p_nlos 1 - p_los; pl_free 20*log10(4*pi*fc*d_3d/c); pl_los pl_free env.eta_los; pl_nlos pl_free env.eta_nlos; g_los 10^(-pl_los / 10); g_nlos 10^(-pl_nlos / 10); pl_prob p_los; end注意我返回的是视距和非视距两套信道增益主循环里按概率p_los抽样决定实际使用哪一套。有的简化仿真直接用了期望信道增益g p_losg_los p_nlosg_nlos这样做训练更平稳但丢失了信道随机性学出来的策略可能对瞬时衰落过于乐观。我推荐至少保留概率抽样版本这样策略天然带有鲁棒性。NOMA速率计算是所有调参工作的核心。下面这个函数输入是两架无人机功率、信道增益、噪声功率输出是强用户和弱用户各自的可达速率function [rate_strong, rate_weak, sinr_strong, sinr_weak] compute_noma_rate(p_strong, p_weak, g_strong, g_weak, bw, p_noise) sinr_weak p_weak * g_weak / (p_strong * g_strong p_noise); sinr_strong p_strong * g_strong / p_noise; rate_weak bw * log2(1 sinr_weak); rate_strong bw * log2(1 sinr_strong); end这里有一个分量容易出错p_strong和p_weak指的是无人机发射功率还是信号在接收端的功率仿真里如果信道增益g已经包含路径损耗那么接收功率就是p * g所以SINR公式里直接用发射功率乘以信道增益没问题。但要注意单位的统一我用的是毫瓦级别噪声功率N0用接收机热噪声功率折算过来常见值约-104dBm转换为毫瓦是10^(-104/10)。4.3 主仿真循环与训练过程主循环伪代码级别如下for episode 1 : max_episodes scenario init_scenario(); state1 get_state(drone1, scenario); state2 get_state(drone2, scenario); for step 1 : max_steps action1 select_action(Q1, state1, epsilon); action2 select_action(Q2, state2, epsilon); [next_state1, next_state2, reward, done] env_step(scenario, action1, action2); Q1(state1, action1) Q1(state1, action1) ... alpha * (reward1 gamma * max(Q1(next_state1, :)) - Q1(state1, action1)); Q2(state2, action2) Q2(state2, action2) ... alpha * (reward2 gamma * max(Q2(next_state2, :)) - Q2(state2, action2)); state1 next_state1; state2 next_state2; if done, break; end end epsilon max(epsilon * epsilon_decay, 0.05); alpha max(alpha * alpha_decay, 0.01); end两个细节值得特别说明。一个是reward1和reward2怎么分。双无人机共享系统总奖励但各自更新自己的Q表时用的是同一个总奖励值。如果各用各的局部速率两架无人机会各顾各的最后互相干扰反而总吞吐量下降。所以这里我让reward1 reward2 总奖励值共享全局奖励是去中心化前提下最简单也最有效的协同协作方式。另一个是环境函数env_step里的碰撞处理。两架无人机如果同一时隙移动到同一点附近动作需要回退到上一位置。回退动作会导致Q表里出现一条“这个状态向那个方向走会撞车”的经验这正是我们希望智能体学到的。但回退本身也会改变用户距离导致奖励跳变所以碰撞惩罚不能只加在一个时隙建议让碰撞后的3个时隙持续减分这样无人机才不会反复往碰撞区域试探。完整Matlab源码的拼装逻辑就是config_params定义参数init_scenario生成用户分布和初始状态env_step调用compute_channel和compute_noma_rate计算通信速率再调用compute_reward计算奖励主循环里反复执行select_action和update_qtable最后调用plot_results出图。代码量不大整个工程也就400到500行。5. 仿真参数配置与结果分析5.1 关键参数配置表这是我调试下来比较稳定的一组参数直接贴出来供参考参数名取值说明区域范围1000m x 1000m无人机不允许出界无人机高度100m固定高度最大速度12m/s每时隙最大位移12m时隙长度1s决策周期用户数量8双无人机各服务1个NOMA配对载波频率2GHz常用空对地频段带宽5MHzNOMA共享带宽噪声功率-104dBm接收机底噪无人机发射功率0.1W/1W/2W 三档动作空间里的功率维度学习率alpha0.1衰减至0.01每500个episode衰减折扣因子gamma0.95偏向长期累计收益epsilon0.9衰减至0.05前期探索后期利用最大episode数3000训练总轮数最大步数200单轮最大飞行时隙5.2 路径优化效果与Q值收敛分析训练到约800个episode时总奖励曲线开始出现明显的上升趋势到1500个episode后基本进入平台期。这里要说一下如何判断收敛不能只看总奖励曲线还要看每个状态下的Q值是否稳定。我在调试中发现一个现象总奖励曲线在600到900个episode之间反复波动看起来像没收敛实际上是因为epsilon从0.9衰减到0.3左右无人机还在大量探索频繁进入低奖励状态。这个阶段属于正常现象不要因为中间震荡就急着调小alpha否则后面探索不足会陷入局部最优。路径可视化脚本里叠加了无人机轨迹和用户位置。训练完成后可以看到一个明显模式无人机先飞向用户分布最密集的区域在靠近弱势用户的距离悬停然后根据信道状态微调位置而不是简单地在区域中心转圈。两架无人机的轨迹在空间上自然错开没有撞到一起说明碰撞惩罚项起到了作用。5.3 与中心化方案/固定航线的对比为了验证算法价值我跑了几组对照实验。第一组是固定航线无人机按预定的圆形航线匀速巡航不决策、不变速、不变功率。结果是总吞吐量低因为部分时隙无人机离服务用户太远信道增益太低NOMA弱用户速率几乎为零。第二组是中心化Q学习一个中心Q表同时管理两架无人机的联合动作。效果是收敛后半数的单步吞吐量比去中心化方案高8%到12%这个提升来自全局状态下的精准协同但代价是状态空间膨胀了几倍训练时间增加约3倍而且一旦模拟链路中断性能立刻崩溃。第三组是去中心化但无NOMA双无人机用正交频段各自服务用户。去中心化方案加NOMA后频谱效率大约提升了35%到40%代价是SINR计算多了一层干扰建模调试难度有所增加。对比结论很明确去中心化Q-Learning方案牺牲了一部分最优性换来了更强的鲁棒性和更低的决策复杂度在链路不稳定、中心节点不可依赖的应急场景里意义更大。如果你所在场景有可靠的中心控制链路又不缺算力中心化方案确实更香如果你的需求是抗毁和分布式部署那去中心化是取舍之后的正确方向。6. 常见问题与调试心得6.1 训练不收敛奖励一直震荡这是我遇到最多的问题。几个排查顺序供参考先看奖励尺度是否合理。如果奖励值域跨度过大比如移动能耗是0.0001量级吞吐量增量是10量级能耗项在Q值更新里被完全淹没无人机根本不学“节省能量”这件事。把奖励各分量归一化到差不多的量级再跑收敛速度会明显改善。再看状态空间是否包含关键历史信息。正如前面提的剩余能量、上一时隙是否碰撞这类信息如果不进状态环境对智能体来说就不是马尔可夫的Q表会一直抖动。这类问题排查方式是把奖励和状态打印出来肉眼核对“相似状态”是否对应“相似奖励”。最后看探索策略。epsilon衰减太快无人机可能还没充分探索所有动作就已经开始利用最后卡在局部最优。把exploration的衰减速度放缓比如每1000个episode衰减到原来的0.9多试几次。6.2 NOMA配对失效两用户都解不出信号仿真中常见的一个错误是SIC链路失效。前面公式里弱用户以强用户信号为干扰完成解码前提是弱用户自身的SINR高于解调门限。如果两架无人机功率分配颠倒强用户功率远大于弱用户弱用户速率为零强用户即使SIC解出弱用户信号也毫无意义。建议在compute_reward函数里加一个约束当弱用户SINR小于解调门限时本时隙无效不给任何正奖励。否则智能体会学到一种“骗奖励”的策略——只提升强用户速率、假装弱用户存在但弱用户实际并没有通信成功。这个细节是我调试中最容易忽略的地方。6.3 双无人机总是往同一侧飞协同失效如果奖励设计里没有明确的空间约束两架无人机会倾向于同时飞向用户最密集的区域导致另一侧用户无人服务。解决办法有三种一是把覆盖均匀性加入奖励。比如计算每个无人机服务用户的平均距离距离差距过大时给负奖励。二是设置半区偏好。初始阶段强制一架无人机偏向区域左侧、一架偏向右侧等策略成熟后取消偏好。三是我前面提到的共享全局奖励让每架无人机知道“整体吞吐量上去了自己才有奖励”这样即便局部看起来“吃亏”也能学会配合。6.4 可复现性建议Matlab仿真存在两个天然陷阱随机数种子和并行工具箱的随机流。如果实验跑一半发现结果对不上先检查rng设置。我的做法是在config_params里固定rng(20240601)用户撒点、信道抽样都用这个种子。启用parfor并行训练时每个worker要单独设置随机流否则多个worker之间共享随机序列会导致训练数据被重复使用。另一个提示是保存中间Q表。每500个episode存一次Q1.mat和Q2.mat。这样即使后面训练跑飞了还能回退到之前的状态继续调参不用从头再来。整个调参周期里这个习惯帮我省了大量时间。最后再多说两句我自己的体会是这类算法题目最难的从来不是某个公式或某段代码而是把通信系统的物理约束和强化学习的模型假设对齐起来。信道模型太粗糙策略学了也和实际对不上Q表状态设计太细训练慢到怀疑人生奖励函数权重没配好无人机学出来的行为完全不符合直觉。建议你拿到这个课题后先跑一个“单无人机、固定功率、只看位置”的最简版本确认Q学习框架正常再逐步加入功率维度和第二架无人机。每一步都验证了再叠加调试成本会低很多。后续可以继续扩展的方向包括连续动作空间的DQN替代表格Q-Learning、多无人机超过两架时的邻居通信拓扑设计、以及把NOMA的功率分配从离散动作改为连续优化并用神经网路拟合。希望这篇拆解对你有实际帮助哪怕只是让你少踩一个我在仿真里踩过的坑。