news 2026/9/30 5:18:16

无蜂窝大规模MIMO与无人机辅助通信:基于DQN的调度策略实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无蜂窝大规模MIMO与无人机辅助通信:基于DQN的调度策略实战

简介:这份资源是一篇面向通信工程、无线网络与人工智能交叉方向研究者的技术文档,聚焦无蜂窝大规模MIMO场景下无人机辅助通信与资源调度难题,适合具备一定强化学习与通信理论基础的研究生、科研人员及工程技术人员参考。压缩包内仅含1个docx文档,约409KB,内容围绕分布式MIMO与大规模MIMO融合架构展开,系统梳理了无人机轨迹设计、AP功率分配、用户调度等核心问题。文档深入探讨了双动作马尔可夫决策过程、有限状态马尔可夫信道、深度Q网络、深度确定性策略梯度及多智能体强化学习等算法在无线资源管理中的具体应用,并给出两跳协作机制下的建模与求解思路。目前已有226人学习,读者可从中获取偏远地区、灾区、沙漠海洋及高速公路等场景的通信覆盖方案设计参考,理解如何利用深度强化学习最大化用户可达速率与总吞吐量,为相关课题研究或工程实践提供可借鉴的算法框架与问题建模方法。

1. 无蜂窝大规模MIMO遇上无人机:这套组合到底在解决什么问题

地面基站越建越密,边缘用户的速率却始终上不去,这是很多人做无蜂窝大规模MIMO时最先撞上的墙。无蜂窝大规模MIMO的核心思路是把一堆接入点(AP)通过回传链路连到中央处理单元,让多个AP同时服务同一个用户,用协作增益换掉传统蜂窝的小区间干扰。理论上很美,但真到部署阶段,热点区域流量潮汐效应明显,固定AP在低峰期闲置、高峰期又不够用,这时候无人机辅助通信就成了一个很自然的补充手段——把空中节点当成可移动的AP,按需飞到流量密集区顶上补容量。

问题随之而来:无人机往哪飞、飞多高、和哪些地面AP协作用户、功率怎么分配,这些决策互相耦合,用传统凸优化做,每换一个场景就要重新推导一遍,而且信道状态和用户位置一变,离线算好的解直接失效。深度强化学习,尤其是DQN这类值函数方法,恰好适合这种「状态连续变化、动作离散可选、奖励延迟反馈」的调度问题。这套方案适合已经懂一点MIMO预编码、又想把手里的调度问题从「离线优化」升级到「在线决策」的工程师,也适合做无人机通信仿真、想找一个能跑通的最小闭环的研究生。下面我按自己实际搭仿真的顺序,把这条链路拆开讲清楚。

2. 无蜂窝大规模MIMO与无人机辅助通信的建模要点:先想清楚状态、动作、奖励

2.1 为什么无蜂窝架构下无人机不能当成普通移动基站

传统蜂窝里,无人机基站服务自己小区内的用户,其他小区干扰它,建模时把干扰项一减就完事。无蜂窝架构不一样,所有AP共享同一套导频和同一块时频资源,用户接收到的信号是多个AP的叠加,无人机作为其中一个AP加入后,它的位置直接改变了整个协作簇的信道矩阵结构。换句话说,无人机的动作不只是「服务谁」,而是「以什么几何位置参与联合传输」。

我一般会把上行导频传输和下行数据传输分开建模。上行阶段,所有AP接收导频,中央单元做信道估计;下行阶段,CPU根据估计结果算预编码,再分发给各AP。无人机在这个流程里贡献的是它到用户的那条视距(LoS)分量,这条分量随无人机位置变化非常剧烈,所以状态里必须包含无人机三维坐标和用户分布,否则DQN学出来的策略会退化成「悬停不动」。

另一个容易忽略的点是回传容量。无蜂窝架构依赖AP到CPU的回传链路,无人机走无线回传时,带宽是有限的。如果状态里不体现回传负载,智能体会倾向于把所有用户都塞给无人机,导致回传拥塞,仿真里表现为吞吐量不升反降。常见做法是在奖励函数里加一个回传惩罚项,或者把回传队列长度放进状态向量。

2.2 状态、动作、奖励的具体设计

状态设计我通常用四组量拼成一个向量:无人机当前位置(3维)、无人机剩余电量(1维)、各用户的位置和速率需求(假设K个用户,每个用户4维,共4K维)、以及当前各AP的负载(M个AP,M维)。如果用户数超过10个,状态维度会迅速膨胀,这时候要么做用户分簇,要么用CNN提取空间特征,DQN直接吃原始状态会很难收敛。

动作空间要离散化。连续的位置控制对DQN不友好,我一般把无人机的可移动范围切成网格,比如水平方向7个档、垂直方向3个档,加上「保持悬停」,总共22个动作。功率分配如果也要学,可以再乘一个功率档位,但动作数会爆炸,建议第一版先固定功率,只学位置和调度。

奖励函数是整套方案里最需要反复调的地方。我用的形式是:

# reward 计算示例 # rate_k: 第k个用户的瞬时速率 # backhaul_load: 无人机回传链路当前负载比例 # energy: 无人机剩余电量比例 # collision: 是否与地面AP覆盖冲突(0/1) def compute_reward(rate_k, backhaul_load, energy, collision): # 速率项:取对数平滑,避免个别用户速率过高主导奖励 rate_term = sum([np.log2(1 + r) for r in rate_k]) # 回传惩罚:负载超过0.8后惩罚急剧上升 backhaul_penalty = 5.0 * max(0, backhaul_load - 0.8) # 电量惩罚:低于20%时开始扣分 energy_penalty = 3.0 * max(0, 0.2 - energy) # 冲突惩罚:与地面AP覆盖重叠严重时扣分 collision_penalty = 2.0 * collision return rate_term - backhaul_penalty - energy_penalty - collision_penalty

这段奖励的逻辑是:速率项用对数而不是线性,是因为线性速率会让智能体只盯着信道最好的那个用户,其他用户被饿死;回传惩罚设0.8的阈值,是留出20%的余量应对突发;电量惩罚放在0.2以下,是避免智能体过早返航导致服务中断。参数不是拍脑袋定的,我一般会先跑几组不同权重,看训练曲线里速率和惩罚项的比值,再微调。

提示:奖励函数里的惩罚项系数不要一开始就设得很大,否则智能体会学出「什么都不做」的保守策略,因为任何动作都可能触发惩罚。先用小系数跑通,再逐步加大。

2.3 信道模型与仿真参数怎么设才不脱离实际

信道模型我建议用概率视距模型,而不是纯LoS或纯瑞利。无人机到地面用户的LoS概率是仰角的函数,仰角越高,LoS概率越大。具体形式常见做法是:

# 视距概率计算 # theta: 仰角(度) # a, b: 环境参数,城区一般取 a=9.61, b=0.16 def los_probability(theta, a=9.61, b=0.16): return 1.0 / (1.0 + a * np.exp(-b * (theta - a)))

这个公式里,a和b决定了LoS概率随仰角变化的陡峭程度。城区环境a取9.61、b取0.16是比较常用的值,郊区可以适当调小a。仰角theta由无人机高度和水平距离算出来,所以无人机飞得越高,LoS概率越大,但路径损耗也越大,这里存在一个最优高度,DQN要学的就是这个权衡。

仿真参数方面,载波频率我一般用2GHz,带宽20MHz,地面AP数量设16个,用户数设8到12个,无人机发射功率设0.1W到1W可调。噪声功率谱密度取-174dBm/Hz。这些数值不是标准答案,但能保证仿真结果在合理范围内,不会出现速率高得离谱或者低得没法看的情况。

3. 用DQN跑通无人机调度:从环境封装到训练收敛的完整步骤

3.1 环境封装:把通信仿真写成gym风格接口

DQN需要和环境的交互接口,我习惯把通信仿真封装成gym风格的类,核心是reset()和step()两个方法。reset()初始化无人机位置、用户分布和信道状态,返回初始状态;step(action)执行动作,更新无人机位置和信道,计算奖励,返回(next_state, reward, done, info)。

import numpy as np class UAVSchedulingEnv: def __init__(self, num_users=10, num_aps=16, grid_size=7): self.num_users = num_users self.num_aps = num_aps self.grid_size = grid_size self.action_space = grid_size * 3 + 1 # 水平7档 x 垂直3档 + 悬停 self.state_dim = 3 + 1 + 4 * num_users + num_aps def reset(self): # 无人机初始位置:区域中心,高度100m self.uav_pos = np.array([0.0, 0.0, 100.0]) # 用户随机分布 self.user_pos = np.random.uniform(-500, 500, (self.num_users, 2)) self.user_pos = np.hstack([self.user_pos, np.zeros((self.num_users, 1))]) # 电量初始100% self.energy = 1.0 # AP负载初始为0 self.ap_load = np.zeros(self.num_aps) return self._get_state() def step(self, action): # 解析动作:水平档位、垂直档位、是否悬停 if action == self.action_space - 1: pass # 悬停,位置不变 else: h_idx = action // 3 v_idx = action % 3 # 水平移动步长50m,垂直移动步长20m self.uav_pos[0] += (h_idx - 3) * 50.0 self.uav_pos[1] += (v_idx - 1) * 20.0 self.uav_pos[2] = np.clip(self.uav_pos[2] + (v_idx - 1) * 20.0, 50.0, 300.0) # 计算信道和速率 rate_k = self._compute_rates() # 更新电量:悬停耗电少,移动耗电多 move_dist = np.linalg.norm(self.uav_pos - self._last_pos) self.energy -= 0.001 * move_dist + 0.0005 self._last_pos = self.uav_pos.copy() # 计算奖励 reward = self._compute_reward(rate_k) done = self.energy <= 0.05 return self._get_state(), reward, done, {}

这段代码的关键在于动作解析和电量更新。动作空间设计成水平7档、垂直3档加悬停,总共22个动作,DQN的输出层维度就是22。电量消耗和移动距离挂钩,这样智能体会学到「少动多悬停」的策略,但悬停太久用户速率会下降,形成权衡。_compute_rates()里做的是无蜂窝协作传输的速率计算,需要用到预编码矩阵,这部分我单独封装,避免和环境逻辑混在一起。

注意:step()里一定要做边界裁剪,无人机飞出区域或者高度超出范围时,要么clip要么给惩罚,否则训练初期智能体会疯狂撞墙,浪费大量样本。

3.2 DQN网络结构与关键超参数

DQN的网络结构不用太深,我一般用三层全连接:输入层维度等于state_dim,两个隐藏层各256个神经元,激活函数用ReLU,输出层维度等于动作数。经验回放池大小设10000,batch size设64,目标网络更新频率设每200步一次。

import torch import torch.nn as nn class DQN(nn.Module): def __init__(self, state_dim, action_dim, hidden_dim=256): super(DQN, self).__init__() self.net = nn.Sequential( nn.Linear(state_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, action_dim) ) def forward(self, x): return self.net(x) # 超参数 GAMMA = 0.95 # 折扣因子 LR = 1e-4 # 学习率 EPSILON_START = 1.0 # 初始探索率 EPSILON_END = 0.05 # 最终探索率 EPSILON_DECAY = 5000 # 探索率衰减步数 TARGET_UPDATE = 200 # 目标网络更新频率 MEMORY_SIZE = 10000 # 经验回放池大小 BATCH_SIZE = 64 # 批大小

折扣因子GAMMA取0.95而不是0.99,是因为无人机调度问题里,当前动作对未来的影响衰减较快,取太大智能体会过度关注远期奖励,收敛变慢。学习率1e-4是DQN的常用值,如果训练曲线震荡厉害,可以降到5e-5。探索率从1.0线性衰减到0.05,衰减步数5000,这个值要根据总训练步数调整,总步数10万的话,5000步衰减完有点快,可以设成20000。

目标网络更新频率200步,这个值影响训练稳定性。更新太频繁,目标网络和在线网络太接近,容易发散;更新太慢,目标滞后严重,学习效率低。我一般先在200附近试,看loss曲线,如果loss震荡就加大到500。

3.3 训练循环与收敛判断

训练循环的核心是:采样动作、执行、存经验、抽batch、算loss、反向传播、定期更新目标网络。

import random from collections import deque memory = deque(maxlen=MEMORY_SIZE) policy_net = DQN(state_dim, action_dim) target_net = DQN(state_dim, action_dim) target_net.load_state_dict(policy_net.state_dict()) optimizer = torch.optim.Adam(policy_net.parameters(), lr=LR) def select_action(state, epsilon): if random.random() < epsilon: return random.randrange(action_dim) with torch.no_grad(): return policy_net(state).argmax().item() def train_step(): if len(memory) < BATCH_SIZE: return batch = random.sample(memory, BATCH_SIZE) states, actions, rewards, next_states, dones = zip(*batch) states = torch.stack(states) actions = torch.tensor(actions) rewards = torch.tensor(rewards, dtype=torch.float32) next_states = torch.stack(next_states) dones = torch.tensor(dones, dtype=torch.float32) q_values = policy_net(states).gather(1, actions.unsqueeze(1)).squeeze() with torch.no_grad(): next_q = target_net(next_states).max(1)[0] target = rewards + GAMMA * next_q * (1 - dones) loss = nn.MSELoss()(q_values, target) optimizer.zero_grad() loss.backward() optimizer.step()

收敛判断不能只看reward曲线,我一般同时看三个指标:平均reward是否稳定上升并趋于平台、平均Q值是否发散、以及实际调度指标(用户平均速率、回传负载)是否改善。如果reward上升但用户速率没变,说明智能体在钻奖励函数的空子,比如一直悬停拿电量惩罚的低分但避免了大动作的惩罚,这时候要回去改奖励。

训练步数方面,状态维度在50左右、动作22个的情况下,我一般跑5万到10万步能看到明显收敛。如果跑20万步还在震荡,大概率是状态设计有问题,或者奖励函数里有相互矛盾的项。

4. 避坑与排查:无人机辅助无蜂窝MIMO调度里最容易翻车的5个地方

4.1 现象:训练初期reward直接崩到负无穷

原因:奖励函数里的惩罚项系数设得太大,智能体第一次探索时触发了回传或电量惩罚,Q值被拉到一个极大的负值,后续所有动作的Q值都被这个负值主导,网络输出饱和。

解决:把惩罚项系数先设成0.1倍,跑通后再逐步加到目标值。另外检查状态归一化,如果状态里有的维度是几百、有的是0.1,网络第一层权重会被大数值维度主导,建议所有状态维度都归一化到[-1, 1]或[0, 1]。

4.2 现象:智能体学会「悬停不动」拿保底奖励

原因:移动的惩罚(电量消耗)大于移动带来的速率增益,智能体发现悬停能拿一个稳定的中等奖励,移动反而可能触发惩罚。这是奖励函数设计里典型的「保守策略陷阱」。

解决:在奖励里加一个「速率增益」项,只有速率超过基线时才给正奖励,或者把电量惩罚改成只在电量低于阈值时才生效。另一个办法是给悬停动作加一个小的负奖励,逼智能体动起来。

4.3 现象:仿真里速率很高,但回传负载爆了

原因:状态里没有回传负载信息,或者回传惩罚项系数太小,智能体把所有用户都调度到无人机上,地面AP闲置。无蜂窝架构的回传容量是硬约束,忽略它会导致仿真结果不可信。

解决:把回传队列长度放进状态向量,并在奖励里加一个硬约束:回传负载超过0.9时,直接给一个大的负奖励(比如-10),而不是线性惩罚。硬约束比软惩罚更能让智能体学会避开。

4.4 现象:换一组用户分布,策略完全失效

原因:DQN过拟合到了训练时的用户分布,状态里用户位置是绝对坐标,网络学到的是「在某个坐标附近悬停」,而不是「往用户密集区飞」。这是泛化能力不足的典型表现。

解决:状态里不要用绝对坐标,改用相对坐标——无人机到用户质心的偏移量、用户分布的方差等统计量。另外训练时每轮reset都随机化用户分布,不要用固定分布。

4.5 现象:训练loss震荡,Q值越来越大

原因:目标网络更新太慢,或者GAMMA设得太大,导致目标Q值不断累积,网络输出越来越大。DQN里Q值发散是常见问题,尤其是奖励尺度没有归一化的时候。

解决:先把奖励归一化到[-1, 1]区间,再检查GAMMA是否超过0.99。如果还震荡,把目标网络更新频率从200降到100,或者用软更新(每次只更新目标网络参数的0.01倍)。另外检查经验回放池里是否有大量高奖励样本,导致batch内方差过大。

5. 进阶技巧:用优先经验回放和动作掩码把收敛速度提上来

基础DQN跑通之后,如果觉得收敛慢或者策略不够精细,有两个改动性价比最高。第一个是优先经验回放(Prioritized Experience Replay),核心思想是让TD误差大的样本被采样概率更高,因为那些样本包含更多「意外」信息。实现上不用改网络结构,只改采样逻辑:

# 优先经验回放采样 # priorities: 每个样本的TD误差绝对值 # alpha: 优先级指数,0表示均匀采样,1表示完全按优先级 def sample_prioritized(memory, priorities, batch_size, alpha=0.6): probs = np.array(priorities) ** alpha probs /= probs.sum() indices = np.random.choice(len(memory), batch_size, p=probs) return [memory[i] for i in indices], indices

alpha取0.6是常用值,兼顾探索和利用。采样后要更新对应样本的优先级,新样本的优先级设成当前最大优先级,保证每个样本至少被采样一次。这个改动一般能让收敛步数减少20%到30%,代价是多了优先级维护的开销。

第二个改动是动作掩码。无人机调度里有些动作是物理上不可行的,比如电量低于10%时不能再往远处飞,或者回传负载已满时不能再接入新用户。与其让智能体通过惩罚慢慢学,不如直接在动作选择时把这些动作的Q值设成负无穷:

# 动作掩码:不可行动作的Q值设为 -inf def masked_action_selection(q_values, feasible_mask): q_values = q_values.clone() q_values[~feasible_mask] = float('-inf') return q_values.argmax().item()

feasible_mask是一个布尔向量,根据当前电量和回传负载算出来。这个改动几乎不增加计算量,但能显著减少无效探索,训练初期尤其明显。

验证策略是否真的学到了东西,我一般用两个方法。一是固定一组用户分布,看无人机最终悬停位置是否在用户质心附近,如果偏得很远,说明状态或奖励有问题。二是画速率累积分布曲线,对比DQN策略和「随机悬停」「固定位置悬停」两个基线的CDF,如果DQN的曲线明显靠右,说明策略有效。我自己的习惯是每次改完奖励函数或状态设计,都先跑5000步看趋势,趋势不对就停下来改,不要硬跑到10万步再看,那样太费时间。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 5:17:50

Windows整盘换Ubuntu 20.04单系统:分区引导与驱动实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 5:17:43

基于TensorFlow的LSTM短期电力负荷预测:从论文复现到工程避坑

简介&#xff1a;这份PDF面向电力系统从业者、深度学习入门者与时间序列预测研究者&#xff0c;聚焦短期电力负荷预测这一典型场景&#xff0c;讲解如何借助TensorFlow搭建LSTM循环神经网络完成高精度预测。资源为单文件PDF&#xff0c;约2.27MB&#xff0c;内容源自正式期刊论…

作者头像 李华
网站建设 2026/9/30 5:14:56

深入理解pkill命令:进程匹配机制、信号处理与实战避坑指南

只要在命令行下工作过&#xff0c;就一定遇到过这样的场景&#xff1a;某个进程疯了&#xff0c;CPU被它吃到100%&#xff0c;但一时半会儿你就是不知道它的PID是多少。打开另一个终端去ps抓&#xff0c;多敲两条命令的时间里&#xff0c;那个进程可能又变得更不可控。此时大部…

作者头像 李华
网站建设 2026/9/30 5:14:42

C语言基础——指针

指针是C语言中的一个重要概念&#xff0c;也是C语言的一个重要特色。正确而灵活地运用它&#xff0c;可以有效地表示复杂的数据结构&#xff0c;能动态分配内存&#xff0c;指针 提供了一个能力 --直接使用内存&#xff0c;方便地使用字符串&#xff0c;有效而方便地使用数组&a…

作者头像 李华
网站建设 2026/9/30 5:14:26

Spring Cloud Gateway生产级配置与Nacos服务发现实战指南

1. Gateway配置不是写个yml就完事&#xff1a;它本质是微服务流量的“交通指挥中心”你有没有遇到过这样的场景&#xff1a;前端调用一个接口&#xff0c;返回502 Bad Gateway&#xff0c;但后端服务明明在跑&#xff1b;或者改了Nacos里的路由规则&#xff0c;重启服务后才生效…

作者头像 李华
网站建设 2026/9/30 5:14:17

猫情绪检测数据集:3200张YOLO格式细粒度标注

1. 项目概述&#xff1a;为什么3200张猫脸图能撑起一个情绪检测数据集&#xff1f;“猫情绪检测数据集 | 3200张YOLO宠物行为数据集”——这个标题乍看像两个拼凑的关键词&#xff0c;但实际藏着一个非常具体、可落地、且长期被低估的工程痛点&#xff1a;宠物AI产品落地卡在“…

作者头像 李华