开发日志
无人机位置优化开发日志:把模拟退火从公式写成程序
记录无人机位置优化课程设计从问题建模到 C++ 实现的过程,以及随机实验、算法验证和代码复盘。
第一步不是写退火,而是把目标说清楚
这个项目的题目看上去很容易让人直接进入编码:随机生成一些用户,然后让无人机不断移动,找到一个看起来更好的位置。但如果没有先定义“更好”是什么,移动就没有意义。
我最后采用的目标是最小化无人机到所有地面用户的最大距离。这个目标比平均距离更严格,因为它关注最差的覆盖用户。只要最远用户仍然离无人机很远,通信范围就很难真正缩小。
用一个结构体保存用户状态
程序使用 jiji 结构体保存每个用户的横坐标、纵坐标、服务容量和中间信道系数。用户数组容量设置为 1005,足以支持课程设计中的 100 个用户实验,也保留了一定扩展空间。
初始化阶段从标准输入读取用户数量,再随机生成坐标和容量。坐标范围设为 [-100, 100],用户统一放在地面平面。所有用户坐标的平均值被用作初始无人机位置,这比完全随机选一个起点更容易让搜索尽快进入有效区域。
把模拟退火拆成三个函数
distcalc() 负责计算两个三维点之间的距离,calc() 遍历所有用户并返回最大距离,SA() 负责真正的随机搜索。这样的拆分让目标函数和优化过程分开,后续更换目标函数时不会重写整个算法。
退火从温度 2000 开始,使用 0.997 的降温系数。新位置由当前坐标叠加随机扰动生成。新解变好就接受,变差时按照 exp(-Delta/t) 决定是否接受。高温阶段允许“走错一步”,是模拟退火和普通贪心搜索最明显的区别。
单次退火结束后,程序又连续调用五次 SA()。这不是严格的随机优化实验设计,但对课程项目来说是一个简单有效的增强手段:不同搜索过程有机会从不同路径接近较优位置。
从源码运行结果看问题
我使用 C++17 编译并运行了当前源码,程序能够完成随机用户生成、无人机坐标输出和总发射功率计算。由于程序使用当前时间作为随机种子,所以不同运行的用户集合和结果会发生变化,这一点和论文中给出的示例数字需要区分开。
运行验证也暴露出几个值得记录的细节。论文假设无人机高度固定为 50,但源码让 z 参与了随机扰动;功率计算的距离函数调用中还把 ansy 传作了高度参数。它们不影响“程序可以运行”这一事实,但会影响模型和结果是否严格一致。
这个项目留下的经验
模拟退火最难的部分不是把概率公式写进代码,而是决定目标函数、邻域扰动、初始解和终止条件是否彼此匹配。数据结构课程设计也不应该只展示一张结果图:随机性从哪里来、结果能否复现、代码和论文是否使用同一模型,这些问题同样属于算法实现的一部分。
当前版本已经完成了从问题建模到算法运行的闭环。下一步如果继续完善,我会先固定输入和随机种子,再修正高度变量和功率计算,最后增加收敛曲线和多组实验对比。这样得到的结果,才更接近可以复用和比较的优化程序。