融合非支配排序与拥挤度距离:NSDBO求解微电网多目标优化调度

发布时间:2026/10/20 5:49:21
融合非支配排序与拥挤度距离:NSDBO求解微电网多目标优化调度 微电网调度这个题做了这几年最直观的感受是它天生就是个多目标优化问题而不是一个单目标问题。经济性要成本最低环保要看排放最少运行层面还希望出力平缓、储能SOC别动不动触及边界这些目标互相打架。以前常用的做法是加权求和图省事但Pareto前沿这种东西不是靠一次加权能求全的——权重一变最优解跟着变你很难一次算完。后来我接触到蜣螂优化算法Dung Beetle OptimizerDBO它在单目标连续优化上表现不错但在多目标场景里直接套用DBO解集退化非常快会集中在某个目标占优的区域多样性很差。所以就有了这套方案把多目标进化算法里最经典的非支配排序与拥挤度距离机制引到DBO中做成多目标版本的NSDBO用Matlab实现求解微电网多目标优化调度。整体跑下来相比原始DBO、NSGA-II和MOPSO前沿质量、收敛速度和解集均匀度都有明显提升。这篇文章把从问题建模、算法改造、代码实现到对比实验的完整过程复盘一遍尤其把调试过程中踩过的坑都写出来希望能帮到正在做微电网调度或者多目标优化的朋友。1. 项目背景与设计思路1.1 微电网调度到底在解什么微电网可以看作一个小型电力系统里面有光伏、风电、微型燃气轮机、储能电池可能还有柴油发电机组负荷是辖区内的用户。调度问题的核心就是在满足负荷需求的前提下决定未来一个时段内各台机组的出力计划。常见调度周期是24小时时间步长1小时。决策对象通俗说就是“每台机组在每个小时发多少电储能充多少、放多少”。约束有功率平衡、机组出力上下限、爬坡约束、储能SOC上下限目标则通常是运行成本和污染物排放。如果只是要求“把电发出来”那不难难的是在多个目标同时存在时找到一个合理的折中方案。比如燃气轮机提一点功率单位固定成本会摊薄但燃料费用和排放一定上升储能多放电可以削峰填谷但放多了SOC耗尽后期面对高峰负荷时撑不住。这就是多目标优化的典型特征。这里我要强调一点微电网调度不是在山寨一个优化理论玩具它背后有真实的经济和安全需求。多目标优化的结果要么是找到一组Pareto最优解供调度员根据实际情况选择要么是提取出一个最优折中解用于自动控制。论文里通常两者都要给。1.2 为什么多目标问题不能用单纯加权很多刚接触这个方向的同学第一反应是加权求和——把成本和排放乘上权重相加变成一个标量然后用粒子群、遗传算法去解。这个方法工作上没错但有个致命问题加权法通常只能拿到Pareto前沿上某些凸部的点对于非凸前沿的中间凹区段无论怎么调权重都调不出来。更重要的是权重本身缺乏物理意义你很难向运营方解释“0.7对应的环保权重”有什么依据也不容易说明最终结果为什么是这样一个折中点。我用一个具体例子说明这个问题当成本和排放两个目标数量级差很大的时候比如成本是几千块钱排放是几百千克如果直接加权而不做归一化结果实际上等于只优化成本排放目标基本被淹没。加权法想转Pareto前沿你得反复试权重每次运行都要从头算一遍计算量成倍增加而且每轮只得到一个点无法让决策者同时看到多种候选方案。所以从工程需求角度讲真多目标算法比加权更有价值。NSGA-II之所以经典核心在于它的精英保留和多样性保持机制非支配排序把种群分成若干层前沿同一前沿内拥挤度大的个体优先级更高。这套机制是几十年来多目标进化算法里最稳定的框架之一。但我没有直接上NSGA-II原因是它的遗传算子模拟二进制交叉、多项式变异在连续数值优化问题上搜索效率一般收敛速度不算快。而DBO这一类新的群体智能算法在单目标连续优化上往往表现更好。两者结合正好互补非支配排序负责筛“好解”维持Pareto前沿DBO的更新公式负责生“新解”保证搜索效率。1.3 为什么选择DBO作为“生新解”的引擎DBO是近几年提出的一种仿生元启发式算法模拟蜣螂滚粪球、舞蹈定向、产卵繁殖、觅食和偷窃等行为。相比粒子群和差分进化它最大的特点是不同个体承担不同角色有明确的分工一部分个体做全局探索一部分做局部开发还有一部分负责跳出局部最优。这种分工机制在微电网调度这种高维连续优化问题上很有优势因为决策变量动辄几十上百维如果所有个体都同质化地更新很容易陷入局部收敛。但DBO本身是为单目标设计的。它更新位置时依赖一个“全局最优”和“最差个体”的概念而在多目标问题里不存在单一最优——只有一堆互相之间不支配的解组成的Pareto前沿。强行把多目标压成单目标再用DBO解集就会退化。所以我做的工作很明确把非支配排序思想和拥挤度距离机制嵌入DBO的迭代框架里替代之前单一最优的引导方式让每个蜣螂个体都以Pareto前沿上的信息为参照来更新位置。2. NSDBO核心原理拆解2.1 DBO底层的四种行为和两类更新策略DBO好玩的地方在于它把蜣螂的生活习性搬进了优化算法里。我在实现时把种群分成四个角色滚球蜣螂、产卵蜣螂、觅食蜣螂和偷窃蜣螂每个角色负责不同的搜索行为。滚球蜣螂是最主要的全局探索角色。它一边推着粪球前进一边通过太阳或者风向来判断方向。在算法里滚球行为的位置更新大致可以写成这样的逻辑如果当前环境有光源蜣螂沿着一个与历史最优相关的方向滚动并参考种群最差个体来制造扰动如果没有光源蜣螂就跳一支“舞蹈”来重新定向角度随机更新公式里会带一个正切函数项。这个正切项很有意思当角度接近正负90度时步长会变得非常大本质上是在做长距离跳跃增强了跳出局部最优的能力。产卵蜣螂对应局部开发。雌性蜣螂会选择一个安全区域产卵简单说就是把卵下在目前已知较优解的附近并通过动态边界限制定位范围保证卵不会离最优区域太远。觅食蜣螂则是从当前种群最优和全局最优附近寻找食物同样用小范围搜索来增强局部收敛。偷窃蜣螂就比较“皮”了它会去偷别的蜣螂的粪球在算法里表现为从全局最优附近随机扰动生成新位置等于在最优解邻域做再搜索。这四个角色在每一代中按一定比例分配比如我习惯设置滚球个体占一半产卵和觅食各占两成偷窃占一成当然比例是可调的参数。比例直接决定探索和开发之间的平衡滚球占比太高收敛慢偷窃和产卵占比太高容易早熟。2.2 非支配排序怎么判定解的“好”与“坏”多目标里没有“绝对最好”只有“谁支配谁”。如果个体a在所有目标上都优于或等于个体b而且至少在某个目标上严格优于b就说a支配bb被支配。所有不被任何其他解支配的个体构成第一层Pareto前沿去除这一层后剩下的解里再找一组不被支配的就是第二层依此类推。非支配排序干的事就是把整个种群按支配关系分层。分层之后光有层级还不够。在第一层前沿上可能有几十个个体它们互相都不支配得选哪些留下来遗传给下一代这时候就用到拥挤度距离。拥挤度的思想很直观某个个体在目标空间里离它最近的两个邻居有多远。距离越大说明它周围的解越稀疏也就越值得保留这样才能让Pareto前沿分布均匀不会挤成一团。我在算法里的选择顺序是这样的先按非支配层级从小到大选层级小的个体全部优先进入下一代当某一层个体太多、剩余席位不足时再按拥挤度距离从大到小截断。这其实就是NSGA-II的做法我把它原样搬进DBO的迭代框架里用在环境选择和外部档案更新两个环节。2.3 NSDBO的整体流程整个NSDBO的流程可以归纳成下面几步。第一步初始化随机生成N个个体每个个体是一组微电网调度方案对应一个决策变量向量。第二步计算所有个体的多个目标函数值。第三步对种群做非支配排序得到各层前沿编号并计算拥挤度。第四步执行DBO的四种角色更新公式生成N个新个体。第五步把父代和子代合并成一个大小为2N的临时种群对这个临时种群做非支配排序和拥挤度计算从中选出前N个优秀个体进入下一代。第六步判断是否达到最大迭代次数如果没到就回到第二步循环往复。注意第五步这一步很关键很多刚改算法的同学会在这里犯错如果只对子代替换父代容易丢掉上一代最优秀的解。把父子代合并后再统一选优才叫真正的精英保留。我在写代码时也遵循了这条策略效果比直接覆盖要好很多。3. 微电网多目标调度模型的建立3.1 目标函数设计微电网调度目标函数可以根据实际系统灵活设计我这次做的是最典型的双目标总运行成本和污染物排放量。总运行成本包括四块内容。第一是燃料成本主要由微型燃气轮机和柴油发电机的出力决定我采用了二次函数近似也就是每个机组有一个二次项、一次项和常数项系数这样更接近实际热力机组的效率曲线。第二是运行维护成本通常和出力成正比用一个运维系数乘以出力来算。第三是设备启停成本如果机组从停机变成开机会有一笔固定费用。第四是储能退化成本这是我后来加上去的因为储能每充放一次都有寿命损耗这项成本会让算法主动减少不必要的储能动作防止调度结果里电池一直处于大功率充放状态解析结果和实际工程更贴近。排放目标主要算各机组排放的污染物总量。气体污染物可以折算成等效二氧化碳每个机组带的排放系数不一样燃气轮机比柴油机干净光伏、风电和储能基本是零排放。这样排放目标和成本目标之间就形成明显冲突Pareto前沿有很好的延伸性。如果你有额外的运行需求也可以加第三个目标比如系统出力波动最小化、电压偏差最小化。我当时没有加第三个目标是考虑到三目标会大幅增加算法计算量而且Pareto前沿在三维空间里可视化对比效果不如二维直观。作为创新点实验先把双目标做扎实更重要。3.2 约束条件模型里的约束条件每一条都有实际物理含义不能随便删。功率平衡约束是整个调度问题的底线任意时刻所有机组出力加储能放电功率再加网购电功率必须等于负荷加上储能充电功率和网售电功率。这一条如果不满足调度方案就是不可行的。机组出力约束限制了各台机组的最小和最大出力对燃气轮机和柴油机来说还额外有一个爬坡约束任意相邻两个时间段之间的出力变化量不能超过限值否则物理上机组跟不上。储能约束要更仔细一点。储能电池的SOC要始终保持在上下限之间比如下限0.1、上限0.9充电和放电功率分别有上限而且充放电不能同时进行。SOC递推公式是调度模型里最容易写错的地方效率系数、时间步长和容量单位不统一就会出大问题。并网模式下还会和主网进行功率交换购电价和售电价一般不同这块我做成了分时电价峰时段贵、谷时段便宜。这样算法在电价低谷时倾向于买电给储能充电高峰时放出来自动形成差价套利的合理调度行为。3.3 决策变量与编码方式我用的编码方式比较朴素但也比较实用把每个时间段所有可控单元的出力拼成一个一维向量。假设系统里有1台燃气轮机、1台柴油机和1台储能24个时间段决策变量维度就是3乘以24等于72维。光伏和风电是预测值不作为决策变量它们相当于已知输入。变量范围就是各机组的出力上下限和储能充放电上下限生成初始种群时在这个超矩形空间里随机取点。约束处理上主要采用惩罚函数法对功率平衡和SOC越限的个体在目标函数值上加一个很大的惩罚项。这里有个经验惩罚系数不能一上来就给得太大太小也不行。太大会让算法只顾着找满足约束的解忽略了目标本身的优化太小又会让大量不可行解混进Pareto前沿。我调试时是从一个中等量级开始逐步调整直到最终解集合里可行解占比超过95%为止。4. Matlab实现全流程4.1 工程目录结构与初始化项目的Matlab工程我习惯分成三大块主运行脚本、模型函数文件夹和算法函数文件夹。主脚本负责设置参数、调用算法、输出结果和绘图模型函数文件夹里放着目标函数、约束检验和储能SOC递推的计算函数算法函数文件夹里放非支配排序、拥挤度计算、外部档案更新和DBO四种角色的位置更新函数。初始化阶段必须把随机数种子选好不然后面做不同算法的对比实验时每次结果都不一样无法公平比较。我在对比实验里统一用同一个随机数种子来初始化种群保证每个算法都在同一批初始解上起步这样后面画收敛曲线的比较才有意义。初始化还包含生产光伏、风电和负荷的24小时预测数据这些数据如果自己拍脑袋定做出来的调度结果可能非常诡异我最后用的是公开数据集里某典型日的曲线再把负荷峰值和风机出力的量纲统一到千瓦级。4.2 非支配排序与拥挤度距离的Matlab实现非支配排序的写法有很多种初学者最容易写出三重循环但跑得奇慢的版本。我的建议是先用清晰版的O(N^2)代码把功能跑通再去考虑优化。核心逻辑是维护两个信息每个个体被多少个个体支配的计数以及每个个体支配的个体列表。被支配计数为0的个体属于第一层前沿然后把它们从支配列表里去掉谁的被支配计数减到0谁就进入下一层。拥挤度距离的代码相对简单按每个目标分别排序。排序后首尾两个个体距离设为无穷大中间个体的拥挤度是这个目标方向上前后两个邻居目标值之差除以整个前沿在该目标上的跨度。所有目标方向的拥挤度累加就得到最终的拥挤度距离。需要注意的是不同目标的量纲差异很大成本可能是几千排放是几百如果不归一化直接累加大数值的目标会主导拥挤度。因此我在实现里用了按跨度归一化的方式效果更合理。4.3 DBO更新算子的实现要点DBO的四种角色更新公式各有一套参数。滚球蜣螂的更新我把方向系数做了一个自适应的调整迭代初期偏向大步长探索迭代后期逐步缩小步长去精细搜索。产卵蜣螂的动态边界我直接复用了当前局部最优和全局最优的信息同时加了一个随机扰动防止所有新卵都挤在同一个点上。偷窃蜣螂我设置为以一定概率更新到全局最优附近这个概率随着迭代逐渐降低避免后期震荡。实际写代码的时候有一个细节很容易出错所有个体的更新必须基于上一代的旧个体位置不能边更新边覆盖。如果顺手写成x(i1)更新时用了x(i)刚更新过的值算法整体就乱套了。我在每个角色更新之前先把当前代种群的全部位置保存一份副本更新过程中全部从副本里读旧位置。另外生成的新个体还要做边界处理把超出变量上下限的分量拉回边界附近。我试过截断到边界也试过反射回边界内结果差别不大最终统一用截断简单省事。4.4 参数设置与调优参数设置可以分为两类微电网模型参数和算法参数。模型参数方面储能容量我设成200千瓦时充放电功率上限50千瓦SOC范围0.1到0.9充放电效率都取0.95。燃气轮机的最大出力设为200千瓦最小出力30千瓦爬坡限值40千瓦每小时。柴油机组最大出力150千瓦最小出力20千瓦爬坡限值30千瓦每小时。负荷曲线峰值约250千瓦光伏峰值约80千瓦风电出力在20到50千瓦之间波动。分时电价峰时段1.2元每千瓦时谷时段0.4元每千瓦时平时0.8元每千瓦时。算法参数方面种群规模我设了200最大迭代次数500。这两个参数不是越大越好种群太大每一代都要做一次完整的目标函数计算调度模型的目标函数里包含储能递推和爬坡检验计算量不小200个体跑500代在普通电脑上大概需要十几分钟再往上翻倍就不太划算了。DBO角色比例我用的是滚球50%、产卵20%、觅食20%、偷窃10%。外部档案容量我设成100保存历代的Pareto最优解防止最优解在迭代中丢失。调参有个土办法先固定种群和迭代数逐次改角色比例对比三个指标——收敛曲线是否平顺、Pareto前沿是否连续、运行时间是否可控。反复调几轮就能找到一组适合手头问题的参数。4.5 结果可视化与Pareto前沿绘制Matlab画Pareto前沿我用的是scatter函数把成本和排放分别作为横纵坐标种群中第一层非支配解用一个颜色标出来。为了对比效果我还会把每种算法最终得到的Pareto前沿用不同颜色画在一张图里横轴成本、纵轴排放一眼就能看出哪个算法更贴近左下方区域。迭代收敛曲线方面我采用的指标是每一代外部档案中非支配解的平均目标值或者直接用最后一代的最优折中解来追踪。这里有个容易踩的坑如果直接用档案里所有解的目标平均值画曲线曲线可能会震荡得很厉害因为外层解和折中解的差异很大。后来我只追踪档案中与理想点距离最小的那个解曲线就平滑多了也更能反映算法整体的收敛趋势。另外我还会画一张24小时调度结果堆叠图横轴是时刻纵轴是功率把光伏、风电、燃气轮机、柴油机、储能的充放电叠加起来和负荷曲线对比。这张图对验证调度方案的合理性非常有用如果画出来购电功率在峰值时段反而很高或者储能SOC曲线剧烈波动那大概率是目标函数或约束写错了。5. 算例结果与算法对比分析5.1 四种算法的对比设置我把对比对象定成四个原始DBO单目标版本加权法处理、NSGA-II、MOPSO多目标粒子群以及本文的NSDBO。为了保证公平种群规模、迭代次数和外部档案容量四个算法全部一致初始种群使用同一个随机种子生成。评价指标用三个常用的世代距离GD衡量算法得到的Pareto前沿与真实前沿之间的距离空间评价SP衡量解集分布均匀程度以及反世代距离IGD它同时考虑收敛性和多样性是目前多目标优化里最常被审稿人看的指标。真实Pareto前沿怎么来最笨但也最可信的办法把所有算法迭代过程中产生的非支配解全部收集起来放在一个大池子里再去掉被支配的解得到一个近似真实前沿。虽然理论上的真实前沿难以求得但这种近似前沿在对比实验里已经足够评估相对优劣了。5.2 结果数据与指标分析从最终的数据看NSDBO的IGD值比原始DBO降低了约三成左右比NSGA-II降低了约两成比MOPSO也略有优势。这说明NSDBO在收敛性和多样性两方面都占优。原始DBO由于采用加权策略只能得到单一折中解画在Pareto前沿图上就是孤零零几个点多样性指标完全没法看。NSGA-II能够形成连续前沿但在前沿两端的延展性不够好极端低成本或者极端低排放的区域经常覆盖不到。运行时间上NSDBO和NSGA-II差不多都是十几分钟级别MOPSO略快一点原始DBO因为只需要跑单目标速度最快但那是以牺牲多目标信息为代价的。如果只追求时间而不在乎解的多样性DBO加权法完全够用但要做一套能实际供调度决策使用的前沿方案集NSDBO明显更有优势。从24小时调度结果看NSDBO找到的优化方案在峰时段储能放电、谷时段充电规律非常明显燃气轮机出力曲线平滑没有出现频繁启停的抖动态。这让我很确定目标函数和约束的建模是合理的算法不仅找到了低成本的方案而且方案具备工程可执行性。5.3 灵敏度与鲁棒性小实验我还做了一组小实验测试算法对不同负荷峰值的敏感性分别把负荷峰值抬高和降低10%重新跑完整个流程。一个有意思的现象是NSDBO对不同负荷水平都能保持前后沿分布稳定但角色比例里偷窃蜣螂占比如果超过15%在高负荷场景下解的多样性会下降。这说明偷窃行为的随机扰动偏强负荷高时功率平衡约束更容易被破坏过多偷窃个体会加重惩罚项的负担。储能容量也是一项敏感参数。容量从200千瓦时降低到100千瓦时之后成本目标的整体上升并不明显但SOC约束更容易触顶算法要花更多迭代才能让所有解满足约束。如果哪天有人想把这个模型扩展到更大规模储能容量建模方面值得给足耐心。6. 踩坑实录与常见问题排查6.1 解集退化成一个点我最早跑DBO多目标版本时把非支配排序加进去之后前几十代还能看到一条弧线到后面整个种群几乎全部收敛到Pareto前沿中央那一片区域两端完全丢失。排查来排查去问题出在选择压环境选择时只侧重了非支配层级忽略了拥挤度。种群中第一层前沿如果个体数量已经超过名额我没做拥挤度截断等于所有个体都往中心区域挤。解决办法是在选择环节严格按“层级优先、同层按拥挤度排序”来执行并且外部档案容量不要设得太小。外部档案如果太小比如只有20个库存位放进来的解很快就会把彼此挤掉前沿照样没法均匀扩展。档案容量设到100之后两端解终于能活下来了。6.2 初始幂次和量纲问题有一次我跑出来的Pareto前沿是一条竖线排放几乎不变成本在变。查了半天才发现排放目标函数里单位的系数差了一千倍某台机组的排放系数用了克量级的数值而成本单位是元两者完全不成比例结果排放目标在目标空间里被压成了一条窄带非支配排序两个目标几乎退化成单目标。这类问题特别隐蔽文字上看不出错画图就能一眼看出异常。后续我所有目标函数值都先做一次粗略量纲归算再喂给算法虽然不影响最终调度方案的物理意义但能显著改善Pareto前沿的表现。6.3 储能递推公式时间步长不一致这是我写代码时实实在在踩过的一个坑。SOC递推公式里功率乘时间步长除以容量时间步长是1小时容量是200千瓦时功率是50千瓦单位换算照理没问题。但我第一次写的时候把时间步长写成了分钟制算出来的SOC变化量瞬间超限约束惩罚项直接把所有个体都判成不可行算法跑了好几代都找不到可行解看起来像完全不收敛。排查方法很简单单独写一个测试脚本固定一个调度序列手算SOC期望值再把程序输出和手算结果对比。这种单步验证脚本后来被我保留下来了每次改动模型都会重新跑一遍防止改错。6.4 运行时间从几分钟膨胀到两小时初学者最容易把非支配排序写成三层循环而且每代都对新种群重新算一次复杂度和种群规模的平方成正比200个个体勉强能忍500个个体就很痛苦了。我后来把整个流程检查了一遍把两个问题修掉了。第一个是目标函数做了批量计算原来是一个个体一个个体地调模型函数改成整个种群的决策矩阵一次性传入Matlab里用向量化写法速度提升了将近十倍。第二个是非支配排序逻辑里用列表记录支配关系避免每代重复计算两两比较结果虽然空间占用大了点但时间快得多。如果你的模型规模很大还可以考虑把目标函数改成并行计算这个对多核机器提升非常明显。7. 一点扩展思考做了这轮NSDBO之后我个人体会最深的一点是改算法的价值不在算法本身多炫而在于它是否真的解决了原方法在具体问题上的短板。微电网调度场景里分布式新能源出力随机性很强单纯用历史预测数据做确定性调度其实已经不太够下一步可以把场景生成与NSDBO结合做成鲁棒优化或者机会约束规划版本让调度结果在光伏、风电出力波动时依然可靠。在代码层面我的建议是新人在看这个项目代码时先不要急着读DBO更新公式先把非支配排序和拥挤度计算这两个基础函数读透再回到主循环理解它们如何衔接。只要理解了“筛选解”和“生成解”这条双线结构NSDBO的思想就掌握了后面换成其他新型算法比如秃鹰搜索、海鸥优化都能用同样的套路改造出多目标版本。这套框架的迁移能力比某一个算法本身更值钱。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询