尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

智能电网调度优化算法实战:从粒子群到多目标优化

智能电网调度优化算法实战:从粒子群到多目标优化 开头部分约300字搞智能电网的朋友应该都有体会调度问题从来不是一个“把负荷分下去”那么简单的事。以前电网结构相对固定负荷曲线也比较好预测靠传统调度经验和经典优化算法基本够用。但这两年新能源装机比例一路走高风电、光伏的出力波动大加上电动汽车充电、储能装置这些新型负荷不断接入电网运行的不确定性一下子拉满。这时候“智能调度”和“优化算法”这两个词几乎成了行业里躲不开的话题。这篇东西算是我自己在一线做智能电网调度算法研究的一些经验总结主要聊三件事一是智能调度到底要解决什么问题二是怎么把调度问题建造成一个可求解的数学模型三是目前主流的优化算法包括粒子群、多目标优化这些在实际工程里怎么选、怎么用、怎么落地。内容会穿插一些Python代码和实际踩坑记录适合刚接触智能电网调度、准备做电力系统优化方向的工程师或研究生参考。已经写了多年调度程序的老手也可以看看第三部分关于算法工程化的经验也许能少走点弯路。1. 智能电网为什么需要智能调度1.1 传统调度模式面临的真实困境电力系统的调度说白了就是要在每一时刻让发电侧的总出力等于用电侧的总负荷同时满足电压、频率、线路潮流等一系列安全约束。过去火电、水电为主力机组调节能力强、出力可控调度员做的是“预测负荷然后安排机组出力”一天做一次机组组合几个小时做一次经济调度基本就能稳住大局。但现在不行了。以我一个实际接触过的项目为例一个区域电网里风电装机占比超过30%之后出力曲线基本是“看天吃饭”。晴天有风的时候风电场瞬间满发无风的时候又几乎零出力。光伏更夸张早高峰和晚高峰之间的出力曲线跟抛物线一样中午可能高负荷、傍晚突然断崖式跌落。这个时候如果还按原来的静态调度模型去做要么出现弃风弃光要么出现备用容量不足严重的时候甚至可能触发低频减载。所以智能调度这个概念被反复强调本质是调度系统必须能够感知更多信息包括新能源预测、实时量测、市场信号并且在更短的时间尺度内做出优化决策。它不是一个单一算法能解决的问题而是一整套“感知—预测—优化—控制”的闭环。1.2 智能调度的核心目标与约束体系智能调度的目标不是单一个它通常包含多个相互矛盾的子目标经济性目标发电成本最小、购电费用最小、网损最小。环保性目标碳排放最小化、污染物排放最小化。安全性目标电压偏移最小、线路负载率均衡、备用容量充足。这几个目标在大多数场景下是打架的。比如便宜的煤电机组污染高昂贵的气电机组响应快但成本高你要压缩成本就不可能不牺牲一点排放指标。更麻烦的是约束条件功率平衡约束所有电源出力之和加上网损等于总负荷。机组出力上下限约束每台机组都有最小技术出力和最大出力。爬坡速率约束机组在相邻时段之间的出力变化不能超过一定速率。最小启停时间约束机组开起来之后不能马上停机停了也不能马上启动。网络安全约束线路潮流、节点电压需要保持在安全范围内。这些约束堆在一起再叠加新能源出力的不确定性整个问题就变成一个大规模、非线性、多约束、多目标的优化问题。经典数学规划方法处理起来相当吃力因为问题规模一大计算时间可能指数级增长。这也就是为什么智能优化算法在智能电网调度领域被大量引入的根本原因。1.3 时间尺度上的调度体系分层还有一个容易被忽略的点智能调度不是一个单点问题而是分时间尺度的。我一开始做研究的时候犯过这个错误以为把模型建大了、约束全放进去就行结果程序跑一天都出不来结果。实际工程里调度体系通常分三层日前调度提前一天做时间分辨率一般是1小时或15分钟需要做机组组合和经济调度安排第二天的开机方式和出力计划。日内滚动调度每15分钟或1小时滚动一次基于最新的超短期负荷预测和新能源功率预测修正日前计划。实时调度/自动发电控制AGC秒级到分钟级由调度自动化系统自动调节机组出力跟踪实时负荷波动。不同时间尺度对算法的要求完全不同。日前调度可以接受几分钟甚至十几分钟的计算时间日内滚动调度需要在几十秒内给出结果实时AGC则要求毫秒级响应。所以选算法之前先搞清楚你的问题属于哪个层级这比纠结用粒子群还是遗传算法重要得多。2. 智能调度问题的数学建模与核心难点2.1 经济调度问题的典型数学表达先看最经典的电力系统经济调度问题。假设系统里有N台发电机组每台机组的发电成本通常用一个二次函数来近似C_i(P_i) a_i * P_i² b_i * P_i c_i其中P_i是第i台机组的出力a_i、b_i、c_i是成本系数。目标函数是让总成本最小min ∑ C_i(P_i)约束条件包括∑ P_i P_D P_loss功率平衡P_D为总负荷P_loss为网损P_i,min ≤ P_i ≤ P_i,max出力上下限还有爬坡约束、备用约束等如果考虑机组启停还要加入二进制变量表示启停状态问题就变成了混合整数规划。这个模型看着简单但真正做起来有几个坑。第一个坑是网损P_loss怎么算。稍微精确一点的做法是用B系数法即P_loss ∑∑ B_ij * P_i * P_j但这会把约束变成二次约束求解难度直接上一个台阶。如果只做简化考虑可以忽略网损或者用上一次迭代的结果来近似网损工程上常见做法是迭代修正。第二个坑是成本函数的非凸性。实际中有些机组存在阀点效应成本函数不是简单的光滑二次曲线而是带有波纹的曲线。这种情况下一阶最优条件可能会找到局部最优经典拉格朗日乘子法容易失效。这也是为什么很多研究开始转向智能算法——它们对函数形态的要求比较宽松。2.2 不确定性因素的建模思路新能源接入之后调度问题最头疼的数学上的难点就是不确定性怎么建模。目前主流的三条路线随机规划认为风电出力、光伏出力、负荷都是服从某种概率分布的随机变量通过生成大量场景来逼近真实分布然后对场景集求期望最优。这条路线的问题是计算量大场景一多问题规模直接爆炸。我之前试过用蒙特卡洛抽样生成500个场景跑日前调度单次求解时间从几秒直接飙到十几分钟。鲁棒优化不确定参数只会落在一个给定的集合内目标是让方案在最坏情况下也不违约。优点是方案保守性强缺点也是太保守经济性差。实际项目中如果用户对经济性特别敏感鲁棒优化的结果往往很难被接受。分布鲁棒优化介于两者之间假设不确定参数的真实分布在一个以经验分布为中心的集合内优化最坏情况下的期望目标。这是最近几年的学术热点但在工程落地中还不算成熟。我个人在实际工程中比较推荐的做法是“场景生成缩减”的组合拳。先用拉丁超立方抽样生成大量初始场景再用同步回代缩减k-means聚类也可以把场景数量减到几十个既保留了不确定性信息又把计算量控制在可接受范围内。2.3 为什么说它是个棘手的组合优化难题如果只是纯经济调度变量全是连续的那用线性规划或者二次规划就能解决。真正让问题变难的是机组组合Unit Commitment里的整数变量——每台机组某个时段开还是不开这是一个0-1决策问题。假设系统里有50台机组调度周期是24个时段那光是决策变量就是50×241200个二进制变量。组合爆炸的意味很浓穷举法想都别想。即便用商业求解器比如Gurobi、CPLEX配合分支定界法在约束特别复杂的时候也可能需要很长时间。这就是为什么粒子群算法、遗传算法、差分进化算法这些“启发式”方法在电力系统研究中有那么大的受众。它们不保证找到全局最优解但能在合理时间内找到一个工程上可用的“足够好”的解。这个“工程上可用”很重要——在调度运行里你花两小时找到一个只便宜0.3%的方案远不如花两分钟找到一个接近最优、但能应付突发状况的方案。3. 优化算法选型经典算法与智能优化算法怎么选3.1 经典数学规划算法在什么场景下仍然不可替代有一段时间学术界有一种倾向觉得智能算法就是万能钥匙什么问题拿过来套一个粒子群就行了。我对此持不同意见。经典算法在两类场景下依然不可替代第一类是求解精度要求极高的小规模问题。比如一个区域配电网里只有十几台分布式电源用内点法求解二次规划求解速度快、结果稳定而且能拿到理论上的最优性证明。这个时候硬用粒子群属于大炮打蚊子还得担心收敛精度问题。第二类是作为“精确算法”的底层引擎。很多智能算法在迭代过程中需要反复求解子问题这时候内点法、单纯形法这些经典算法作为子问题求解器反而比纯启发式搜索更高效。比如我在一个配电网重构项目里外层用遗传算法搜索开关组合内层用线性规划计算潮流分布和网损这个组合比纯遗传算法快了三倍不止。所以我的建议是不要把经典算法和智能算法放在对立面它们是互补的关系。经典算法擅长处理“结构好”的问题智能算法擅长处理“结构差”的问题而真实工程问题往往是“部分结构好、部分结构差”。3.2 粒子群优化算法的原理与适用边界粒子群算法PSO应该是搞智能优化的人接触最多的算法之一。它的思想来源是鸟群觅食行为——每只鸟粒子在搜索空间里飞行既参考自己历史上找到的最好位置个体经验也参考整个群体找到的最好位置社会经验通过不断更新速度和位置来逼近最优解。核心更新公式就两个v_i(t1) w * v_i(t) c_1 * r_1 * (pBest_i - x_i(t)) c_2 * r_2 * (gBest - x_i(t))x_i(t1) x_i(t) v_i(t1)其中w是惯性权重控制粒子保持原来速度的程度c_1和c_2是学习因子控制粒子向个体极值和全局极值学习的强度r_1和r_2是[0,1]之间的随机数。这个算法最大的优点就是实现简单参数少不需要求梯度适合处理非凸、不可导的调度问题。我经常跟人说一个写代码的新手花一个下午就能把基础PSO跑起来。但它的缺点也明显容易早熟收敛陷入局部最优。特别是多峰函数问题粒子群经常集中在一个局部极值附近“自嗨”。参数太敏感。w、c_1、c_2的取值对结果影响很大而且不同问题上最优参数还不一样。约束处理能力弱。PSO本身是无约束优化算法处理电力系统这种强约束问题必须配合惩罚函数法或者约束修复策略。给一个经验性的参数建议惯性权重w从0.9线性递减到0.4前40%迭代用0.9附近后期到0.4附近c_1和c_2通常取2.0粒子数取问题维度的10到20倍。这些参数不一定是最优的但作为起点跑一轮通常能得到一个合理结果。3.3 多目标优化为什么值得重点关注实际电网调度几乎从来不是单目标问题。成本、碳排放、网损、电压质量这些目标往往是互相冲突的。如果强行加权重合成单目标最大的问题是权重怎么定而且一次运行只能给出一组权重对应的一个解无法看到帕累托前沿的完整结构。多目标优化算法要解决的就是这个问题。NSGA-II是这类算法中最经典的一个核心思路是用非支配排序把种群分成不同层级第一层是最优秀的解第二层次之再通过拥挤度距离保持解的多样性保证最终得到的一组解能均匀分布在帕累托前沿上。我在实际项目中用过NSGA-II来做“成本碳排放”双目标的经济调度效果相当不错。跑完之后把帕累托前沿画出来决策者可以从曲线上直观看到如果碳排放降低10%成本大概要增加多少如果不想增加太多成本碳排放在哪个区间内是合理的。这种决策支持能力单目标优化是怎么也给不出来的。对于多目标算法还有几个细节值得注意种群规模不能太小我一般设100以上否则帕累托前沿会很难看。变异率不要设太大否则收敛不了也不要太小否则种群很快就同质化了一般取0.1左右。迭代次数要留够多目标问题的收敛速度通常比单目标慢300代以下基本不要期望有好结果。3.4 其他常用智能算法与混合策略除了PSO工程上常用的还有遗传算法GA全局搜索能力强于PSO但收敛速度慢。适合机组组合这种离散变量占比高的问题。差分进化算法DE整体鲁棒性比GA好尤其是连续优化问题在我的测试里DE的收敛精度通常优于标准PSO。灰狼优化GWO结构简单、收敛速度快近年在电力系统里也很流行但同样有早熟收敛问题。野马优化算法WHO这是相对新颖的算法模拟野马群的社会行为在部分测试函数上表现亮眼但工程验证还比较少建议在小规模问题上先试用。我的实践结论是没有哪个算法全面碾压其他算法关键在于用对地方。比如同样是配电网重构问题如果开关个数不多少于50个遗传算法配合枚举局部搜索效果很好如果是连续变量为主的经济调度差分进化往往比PSO更稳。还有一个很实用的策略是混合算法。比如“PSO 局部搜索”粒子群先全局粗搜每一步迭代完了对当前最优解做一次局部精细搜索比如用模式搜索法这样既能保持全局搜索能力又提升了收敛精度。我在多个项目里用这个策略效果比单用PSO好很多。4. 实操过程用Python实现一个智能调度优化示例4.1 问题定义与数据准备纸上谈兵没什么意思我直接用Python写一个完整的调度优化示例让大家直观感受整个流程。这里以经典的6机组经济调度问题为例目标是在满足负荷需求的前提下最小化发电总成本。机组参数用IEEE标准测试系统里常用的数据每台机组有出力上下限、成本系数机组P_min (MW)P_max (MW)a (元/MW²h)b (元/MWh)c (元/h)G11005000.0077240G2502000.009510200G3803000.0098.5220G4501500.00911200G5502000.00810.5220G6501200.007512190总负荷假设是850 MW。先忽略网损和机组爬坡约束把问题简化为纯经济调度方便大家看懂核心逻辑。4.2 粒子群算法实现经济调度的完整代码我先写一个标准的PSO来求解这个问题注意点在代码注释里标出来。import numpy as np # 机组参数 P_min np.array([100, 50, 80, 50, 50, 50]) P_max np.array([500, 200, 300, 150, 200, 120]) a np.array([0.007, 0.0095, 0.009, 0.009, 0.008, 0.0075]) b np.array([7, 10, 8.5, 11, 10.5, 12]) c np.array([240, 200, 220, 200, 220, 190]) P_D 850 # 总负荷(MW) n_gen len(P_min) def cost_func(P): 计算总发电成本 return np.sum(a * P**2 b * P c) def constraint_penalty(P): 约束处理功率平衡惩罚项 出力越限惩罚项 penalty 0.0 # 功率平衡惩罚偏差越大惩罚越大 balance_violation np.abs(np.sum(P) - P_D) penalty 1000 * balance_violation # 出力上下限惩罚 penalty 1000 * np.sum(np.maximum(0, P_min - P)**2) penalty 1000 * np.sum(np.maximum(0, P - P_max)**2) return penalty def fitness(P): return cost_func(P) constraint_penalty(P) # PSO 参数 n_particles 60 n_iter 200 w_max, w_min 0.9, 0.4 c1, c2 2.0, 2.0 # 初始化粒子位置在上下限之间随机初始化 X np.random.uniform(P_min, P_max, size(n_particles, n_gen)) # 修正初始解使总和接近负荷 for i in range(n_particles): X[i] P_min (P_max - P_min) * np.random.rand(n_gen) X[i] * P_D / np.sum(X[i]) # 缩放使总和等于 P_D V np.zeros_like(X) pBest X.copy() pBest_fitness np.array([fitness(p) for p in pBest]) gBest_idx np.argmin(pBest_fitness) gBest pBest[gBest_idx].copy() gBest_fitness pBest_fitness[gBest_idx] for t in range(n_iter): w w_max - (w_max - w_min) * t / n_iter r1, r2 np.random.rand(n_gen), np.random.rand(n_gen) V w * V c1 * r1 * (pBest - X) c2 * r2 * (gBest - X) X X V # 反射处理越界把粒子拉回边界内 X np.clip(X, P_min, P_max) for i in range(n_particles): # 每次迭代后做一次简单修正让总和靠近P_D X[i] (P_D - np.sum(X[i])) / n_gen X[i] np.clip(X[i], P_min, P_max) fit fitness(X[i]) if fit pBest_fitness[i]: pBest[i] X[i].copy() pBest_fitness[i] fit gBest_idx np.argmin(pBest_fitness) if pBest_fitness[gBest_idx] gBest_fitness: gBest pBest[gBest_idx].copy() gBest_fitness pBest_fitness[gBest_idx] print(最优出力方案(MW):, np.round(gBest, 2)) print(总出力(MW):, round(np.sum(gBest), 2)) print(总成本(元/h):, round(cost_func(gBest), 2))这段代码跑完之后你会看到每台机组的出力分配结果。正常情况下PSO能找到总出力正好等于850 MW的解成本大约在8700到8900元/h之间。4.3 代码背后的关键设计思路这一段代码虽然短但里面藏了几个我踩坑之后总结出来的工程技巧第一个是初始解构造。很多人初始化粒子时习惯直接在范围内随机撒点但这样得到的初始种群很多都不满足功率平衡约束罚函数值巨大粒子群初期会浪费大量迭代在“纠正方向”而不是“优化成本”。我在这里做了一个缩放修正先随机生成然后按比例缩放让初始解的总和正好等于负荷。这个操作能让初始种群一开始就在可行的超平面附近收敛速度会快非常非常多。第二个是爬坡约束的替代处理。上面代码没有显式考虑爬坡约束但实际工程里这个约束会极大影响可行域形状。如果你要加入爬坡约束需要把决策变量从一个时刻扩展到多个时刻比如24时段这时每个粒子就是一个24×N的矩阵速度更新要相应改成三维操作。我建议新手先跑通单时段的再加多时段。第三个是惩罚系数的掌握。约束惩罚系数设太大粒子会只顾着满足约束而失去优化动力设太小惩罚项根本起不了作用。我的经验是先从1000开始试如果看到粒子群在迭代中频繁违反约束就加大如果看到粒子群稳定在可行域内但成本下不去就减小。4.4 扩展到多目标优化NSGA-II实战要点如果你做的是多目标调度比如成本和排放同时优化NSGA-II会比PSO更合适。这里不贴完整NSGA-II代码网上现成库很多比如pymoo但讲一下用pymoo实现的几个关键点from pymoo.algorithms.moo.nsga2 import NSGA2 from pymoo.core.problem import Problem from pymoo.optimize import minimize from pymoo.operators.crossover.sbx import SBX from pymoo.operators.mutation.pm import PM from pymoo.operators.sampling.rnd import FloatRandomSampling class DispatchProblem(Problem): def __init__(self): super().__init__(n_var6, n_obj2, xlP_min, xuP_max) def _evaluate(self, X, out, *args, **kwargs): # 第一个目标成本 f1 np.sum(a * X**2 b * X c, axis1) # 第二个目标碳排放排放系数简化为线性 emission_factor np.array([0.9, 0.6, 0.7, 0.5, 0.7, 0.4]) f2 np.sum(emission_factor * X, axis1) # 约束功率平衡 g1 np.abs(np.sum(X, axis1) - P_D) - 5 out[F] np.column_stack([f1, f2]) out[G] g1.reshape(-1, 1) problem DispatchProblem() algorithm NSGA2( pop_size100, samplingFloatRandomSampling(), crossoverSBX(prob0.9, eta15), mutationPM(prob1.0/6, eta20), ) res minimize(problem, algorithm, (n_gen, 300), verboseTrue)用pymoo跑多目标优化的好处是非支配排序、拥挤度计算这些底层逻辑都封装好了你只需要定义目标和约束。跑完之后res.F就是一组帕累托前沿上的解。画成散点图你会看到一条从“低成本高排放”到“高成本低排放”的曲线这个图直接能给决策者看非常直观。5. 常见问题与排查技巧实录5.1 收敛精度差或收敛到不可行解这是我被问得最多的问题。粒子群跑完了结果里有一台机组的出力还在上下限边界附近震荡或者总出力跟设定负荷差了十几MW怎么看怎么不对劲。排查思路先从“问题出在算法还是出在模型”入手。我建议先做一个检测把用PSO找到的解代入到约束条件里逐条检查看看是哪个约束被违反了被违反了多少。如果违反的是功率平衡约束大概率是惩罚系数不够大或者边界修正逻辑有问题。比如有些新手会在每次迭代结束时不加“X[i] (P_D - np.sum(X[i])) / n_gen”这个修正步骤那功率平衡只能靠惩罚项拉很难精确到位。如果粒子群早熟收敛在某个局部最优解上试试下面几个方向增大种群规模从40增加到80或100。调整惯性权重不要线性递减改成自适应比如用当前种群多样性来衡量多样性低就加大w。引入变异机制随机让一部分粒子重新初始化模拟遗传算法里的变异操作。5.2 多目标优化中帕累托前沿分布不均用NSGA-II跑多目标调度经常出现帕累托前沿“两头密、中间空”的问题。这通常意味着解的多样性保持出了问题。一个常见原因是拥挤度距离的计算逻辑在你用的框架里没有覆盖所有个体导致中间区域的解被错误删掉了。我的建议是迭代结束后把得到的非支配解重新做一次拥挤度计算手动筛选出分布均匀的子集而不是直接信任算法输出的最后一代表。另外一个技巧是可以在每次迭代后把当前代的非支配解记录下来整个运行结束后合并所有非支配解再做一次筛选。这种做法虽然会多消耗一点内存但能有效避免中间优秀解的丢失。我做过实验同样的配置下记录历史非支配解的方案比只用最后一代的结果帕累托前沿的覆盖范围能提升15%到20%。5.3 求解速度太慢如何加速调度问题上了规模之后最头疼的就是运算时间。下面几个加速手段是我实际验证过有效的第一降维。把建模粒度从1小时改成15分钟决策变量数量直接缩小4倍速度提升非常明显。当然时间分辨率变粗会损失一些调度精度要根据工况权衡。第二并行化。粒子群和遗传算法这类群体智能算法天然适合并行。每个粒子的适应度计算是相互独立的可以用Python的multiprocessing或者joblib做并行。我有一次把一个72机的算例用8核并行把计算时间从20分钟压缩到4分钟效果极好。第三用混合算法做“粗精结合”。简单来说先用智能算法快速找到一个可行解附近再用内点法做二次规划精细收敛。因为内点法在用智能算法给出的初始点附近能快速收敛到局部最优两者结合往往能比纯智能算法快好几倍精度也不差。5.4 工程落地中容易被忽视的三个问题最后分享几个纯数据层面的教训都是做项目时踩过坑才意识到的数据质量问题。智能调度的效果上限取决于输入数据的质量。风机出力预测误差太大再好的优化算法也白搭。所以实际项目里我会花大量时间做数据清洗和预测模型调优有时候算法优化带来的收益反而不如把预测误差降低2个百分点来得明显。边界条件意识。调度系统最终是给调度员用的不是给算法研究者自嗨的。算法跑出来的方案必须能解释清楚“为什么是这个方案”。有一次我优化出来的方案建议一台大机组在凌晨低谷时段保持运行从成本上看是优化了但调度员直接否掉了——因为那个时段该机组所在区域的电网有线路检修不能运行。从那以后我养成了把约束条件整理成清单、和业务方逐条确认的习惯。系统鲁棒性。算法不是跑一次就完事的实际调度系统是全天候运行的。如果某个时刻数据异常导致算法不收敛系统必须有fallback机制。我现在做调度算法一定跑两层第一层是优化算法第二层是事后校验模块在算法输出结果之后重新校验一遍所有约束是否满足如果不满足自动切换到预设的安全预案。这套机制看起来笨拙但在生产环境里能避免大量的故障。我在实际项目中还有个习惯每次跑完优化之后会把解和目标值都存下来做历史对比。过了几个月回看能很清楚地发现算法参数是否需要调整负荷结构是否有变化。这种事后的复盘往往比调参本身更有价值。如果你正准备做智能电网调度方向的研究或者项目我的建议是先把基础模型吃透再玩花活儿。不要一上来就追求复杂的深度强化学习或者分布式优化把经济调度、机组组合、粒子群这些地基打好后面遇到真实问题才能举一反三。
返回列表