ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

微网多目标优化调度:基于MATLAB的改进粒子群算法实践

微网多目标优化调度:基于MATLAB的改进粒子群算法实践 做微网调度优化的人应该都有同感真正让人挠头的从来不是把模型搭起来而是怎么在“多目标”这三个字里找到一个能真正落地的解。经济成本要压到最低、碳排放要尽量少、新能源消纳还得最大化这三个目标放在同一个问题里互相打架谁都不能简单牺牲谁。我在做这个基于MATLAB仿真的微网多目标优化调度项目时最初直接用标准粒子群算法PSO跑结果Pareto前沿一团糟解的质量和稳定性都远达不到预期。后来改成改进粒子群算法把自适应惯性权重、Pareto支配关系、外部档案维护和模糊决策结合起来仿真效果才真正有了对比和说服力。这篇文章就把我整个实践过程拆开来写模型怎么搭、标准PSO为什么不行、改进算法每一处改动背后的考虑、MATLAB代码骨架怎么组织以及仿真结果到底好在哪里。最后会聊几个我在实际运行中踩过的坑这些细节在论文和文档里通常不会写但对复现项目的人来说往往最关键。1. 微网多目标调度问题的数学模型是怎么搭出来的很多人一上来就写算法但算法再花哨目标函数和约束条件没建明白算出来的结果也没有实际意义。微网调度的本质是在满足系统安全运行和用户用电需求的前提下决定未来24小时或更短周期内各分布式电源、储能和主网交互功率的出力计划。我的做法是先列出全部目标再写清楚所有约束最后才考虑用什么样的智能算法去求解。1.1 三个目标函数的平衡逻辑成本、排放与消纳微网里的分布式电源大致包括微型燃气轮机MT、燃料电池FC、储能系统ESS、光伏和风电。目标函数我取了三个这也是目前微网调度文献里最主流的三元组合第一个目标是经济性成本最小化包括微型燃气轮机和燃料电池的燃料成本、设备的运行维护成本、以及与主网交互的购电成本。单位时段t的总运行成本可以写成C_total(t) C_fuel_MT(t) C_OM_MT(t) C_fuel_FC(t) C_OM_FC(t) C_grid(t)其中燃料成本用二次函数拟合机组出力C_fuel a·P² b·P ca、b、c是不同机组的热耗参数。购电成本C_grid(t)的正负取决于微网是买电还是卖电电价用分时电价峰时段和谷时段差别很大。第二个目标是碳排放最小化。微网虽然强调清洁但微型燃气轮机和燃料电池仍然是化石能源碳排放不可忽略。我以系统调度周期内所有化石机组的碳排放总量为目标E_total (MT排放强度 × P_MT FC排放强度 × P_FC) × Δt第三个目标是新能源消纳最大化我用弃风弃光惩罚来间接表达。光伏和风电的出力带有不确定性调度时没有消纳掉的功率会被切除这部分用惩罚成本计入优化目标C_curtail λ_curtail × (P_PV_avail - P_PV_used P_WT_avail - P_WT_used)理论上这三个目标彼此矛盾想让成本最低就得让便宜的化石机组多出但碳排放跟着上去了想多消纳新能源就要减少化石机组出力可系统调节能力和稳定性会受影响。多目标优化的核心价值就在这里——不是找到唯一最优解而是找到一组在三个目标之间平衡的Pareto最优解。1.2 约束条件功率平衡之外的现实边界目标函数确定了约束条件是让解“可落地”的关键。我整理了一下主要约束分四类约束类型具体表达式说明功率平衡约束ΣP_gen P_load P_grid P_ESS每个时段发电与负荷严格平衡这是等式约束必须精确满足机组出力上下限P_min ≤ P_i ≤ P_max每台机组都有最小稳定出力和最大出力爬坡约束-R_down ≤ P(t)-P(t-1) ≤ R_up微型燃气轮机响应不是瞬时的爬坡率必须限制储能SOC约束SOC_min ≤ SOC ≤ SOC_max且充放电功率限幅储能SOC通常限制在0.20.9之间避免过充过放这里特别要说一下储能约束。很多初做微网调度的人会忽略SOC的时序递推关系SOC(t1) SOC(t) η_ch·P_ch·Δt - P_dis·Δt/η_dis。这个公式让储能成为跨时段耦合的变量上一时刻的充放电决策会直接影响下一时刻的可用容量所以储能时段之间不能独立优化。功率平衡约束我用等式约束方式加入适应度函数因为储能和主网交换功率本身就是决策变量的一部分只要总功率代数和不等于零就说明解不满足物理规律应该给予强惩罚。2. 标准粒子群在多目标调度场景下的三个瓶颈模型搭好之后我第一版直接用标准PSO去跑。粒子群算法的思想很简单——每个解是一个粒子粒子根据个体历史最优pbest和全局最优gbest更新自己的速度和位置。这个算法在单目标连续优化问题上表现很好收敛快、参数少、实现容易。但放到微网多目标调度这个具体场景里标准PSO很快就暴露了三个核心问题。2.1 全局最优的选择困境单目标思维在多目标问题上的失效标准PSO只有一个全局最优gbest但多目标问题里不存在一个能让所有目标同时达到最优的单一解。那么迭代过程中gbest到底该指向哪个解如果草率地把三个目标加权求和成单目标就会面临权重怎么取的问题而且一旦权重固定搜索方向就被锁死得到的结果只是某一个特定偏好下的解无法获得完整的Pareto前沿。我当时试过最直观的做法把三个目标线性加权后作为粒子的适应度值。结果确实跑得快但每次运行得到的解都只偏向某一两个目标换一组权重结果完全不一样。更麻烦的是微网调度问题中三个目标的量纲差得很远成本是几百到几千元排放是几十千克消纳惩罚又可能是另一个量级加权系数稍有问题优化过程就被大数值的目标主导了。2.2 惯性权重与学习因子的固定设置导致早熟收敛标准PSO中惯性权重w通常固定取0.8左右学习因子c1和c2固定取2。在微网调度这种高维约束优化问题里这种固定参数策略存在明显问题迭代前期需要较强的全局探索能力粒子应该尽量在整个解空间里搜索迭代后期则需要局部精细开发粒子应该在小范围内深挖。固定w的结果就是前后期行为一模一样。前期探索不充分粒子群可能从一开始就集中在某个可行域附近多样性不足后期w又不够小粒子在最优解附近反复振荡很难收敛到更优的位置。我第一版跑出来的结果很不稳定相同的参数不同的随机种子最后得到的成本和排放差异能到15%以上。2.3 约束处理的粗放让粒子频繁越界微网调度是强约束优化问题。PSO本身是无约束优化算法粒子更新位置时并不自动满足功率平衡、机组上下限等约束。我当时第一版用的处理方式是简单的“越界截断罚函数”但罚函数惩罚系数取不好问题就来了系数太小大量粒子滞留在不可行域里算法把不满足物理约束的解当作优秀个体保留下来系数太大适应度函数被罚函数主导粒子之间的目标函数差异被掩盖选择压力失真种群多样性急剧下降。我后来统计过第一版的粒子群在迭代中期竟然有超过40%的粒子不满足功率平衡约束基本等于白跑。这也说明标准PSO直接套到微网多目标调度上不是改两行代码就能解决的必须在算法结构上做针对性的改进。3. 改进粒子群算法的具体设计从单目标思维转向Pareto前沿搜索针对上面三个瓶颈我的总体思路是保留PSO“个体学习群体协作”的骨架把单目标驱动机制改成Pareto多目标驱动机制把固定参数改成自适应参数把粗糙的约束惩罚改成可行性优先的约束处理。下面是我实际采用的四个关键改进每个都有明确的动机和对应的仿真效果。3.1 自适应惯性权重让粒子“前期开阔搜索后期精细挖掘”惯性权重w决定粒子对上一时刻速度的继承程度。我采用的策略是随迭代次数非线性递减w(t) w_max - (w_max - w_min) × (t/T_max)²w_max取0.9w_min取0.4。之所以用平方递减而不是线性递减是因为微网调度问题维度高前期需要更多迭代次数去遍历可行域平方曲线让w在前期下降得更慢给足探索时间。迭代后期w快速降到0.4附近粒子速度变化趋缓在小范围内精细搜索最优解。需要注意的是w并不是越小越好。w过低意味着粒子几乎只靠当前速度滑行一旦陷入局部Pareto前沿几乎没有办法跳出来。实测下来0.4这个下限对24维决策变量24个时段基础调度变量的算例是比较合适的如果决策变量维度更高建议把w_min适当调大到0.45。学习因子我也做了调整c1从2.6线性递减到1.6c2从1.6线性递增到2.6。前期的c1大鼓励粒子向自己的历史最优学习保持个体多样性后期c2大强化向全局最优收敛的趋势。这个“一大一小、前后互补”的设置让粒子群在后期有更强的收敛动力。3.2 Pareto支配、拥挤距离与外部档案维护这是整个改进算法最核心的部分。我的方案是多目标粒子群优化MOPSO的标准框架但结合微网调度的特点做了调整维护一个外部档案Archive内部存放当前找到的非支配解每次迭代将当前种群所有粒子的非支配解并入档案用拥挤距离评估Pareto前沿上解的分布密度档案规模超过上限我设为100时优先删除拥挤距离小的解保留分布更均匀的个体。Pareto支配关系的定义是解A支配解B当且仅当A在所有目标上都不劣于B且至少在一个目标上严格优于B。在微网调度场景里这对应的是解A的成本不高于B排放不高于B弃风弃光惩罚不高于B并且至少一项严格小于——那么A就可以淘汰B不用人为给三个目标分配权重。外部档案更新时我还有一个特殊处理新加入的解如果与档案中现有解的决策变量欧氏距离过近并且目标值也相近则视为重复解不放入档案。这个“去重”逻辑能有效防止粒子群在某个局部区域密集堆积保持Pareto前沿在目标空间里的覆盖范围。gbest的选取不能再是单一的全局最优。我的做法是在每次迭代时从外部档案中随机选一个非支配解作为粒子群的gbest。为什么随机选而不是选拥挤距离最大的解因为所有粒子共享同一个gbest容易导致种群迅速向档案的某个区域收缩丧失多样性。随机选择虽然每次方向不固定但保证了粒子群在整个Pareto前沿方向上都有探索可能。3.3 约束可行性优先的适应度评价策略罚函数不是不能用但必须设计得合理。我采用的策略是“可行性优先动态惩罚”适应度值 目标函数值 Penalty × 最大违规量具体分两种情况如果粒子满足所有约束直接用目标函数值作为适应度如果粒子违反约束则用目标函数值加上惩罚项并且罚函数系数不是固定值而是随着迭代次数增加逐渐增大。这样做的理由很直接迭代前期允许粒子在可行域边缘试探通过较小的惩罚保留一些接近可行域的解有利于维持种群多样性迭代后期惩罚系数变大迫使粒子收敛到严格可行的区域。我把功率平衡约束的违规量除以基础负荷得到一个相对偏差率再乘以一个自适应系数。这样处理的好处是惩罚项与目标函数量纲可比避免了因为成本数值大、排放数值小导致的罚函数掩盖真实目标值的问题。这个细节在后面第6章还要专门展开因为量纲问题是我实际踩过的最深的坑之一。3.4 模糊隶属度函数从Pareto解集中挑出最优折中方案算法跑完外部档案里有几十上百个Pareto非支配解怎么给决策者一个最终答案项目调度人员不可能自己去翻Pareto前沿挑解所以我用模糊隶属度函数做最后的折中决策。对每个Pareto解k计算其在第i个目标上的隶属度u_i(k) (f_i_max - f_i(k)) / (f_i_max - f_i_min)f_i_max和f_i_min分别是第i个目标在Pareto前沿上的最大值和最小值。每个解的标准化隶属度之和U(k) Σu_i(k)U(k)越大说明这个解在所有目标上的综合表现越均衡。调度人员如果更看重经济性可以选择靠近成本最小端的解如果更看重环保可以选择靠近排放最小端的解如果无偏好就选U(k)最大的解作为推荐方案。这是把多目标决策交给人的一种折中方式实际操作中非常实用——因为不同时期微网的运营偏好本来就不一样比如电价高峰时段更偏向省钱环保压力大的时候更偏向减排模糊隶属度方案保留了这种选择空间。4. MATLAB仿真实现的关键细节与代码骨架算法设计清楚了接下来是落地。MATLAB做微网调度仿真的有两点很合适一是矩阵运算和向量化方便能处理多维决策变量二是可视化工具完善画Pareto前沿、收敛曲线、设备出力曲线都很顺手。4.1 算例参数、决策变量编码与初始化我的算例是典型日24小时调度时间间隔Δt取1小时。微网内包含2台微型燃气轮机、1台燃料电池、1套储能、光伏和风电与配电网的联络线功率也有约束。主要参数如下单元出力上限出力下限关键参数MT1100 kW15 kW燃料成本系数a0.045, b28, c1.5MT280 kW10 kW燃料成本系数a0.062, b25, c2.0FC60 kW5 kW燃料成本系数a0.085, b18, c3.2ESS30 kW-30 kW容量100 kWhSOC范围0.2~0.9η0.95联络线100 kW-100 kW分时电价购电峰时段1.2元/kWh决策变量的编码方式如下每个时段包含MT1出力、MT2出力、FC出力、储能充放电功率充电为正、放电为负、联络线交换功率购电为正、售电为负再加SOC初始值总共变量数是24×51121维。每个粒子是一个121维的行向量。种群规模我设为200迭代次数设300。这个规模在普通桌面电脑上运行一次大约需要2~3分钟。种群初始化不是全空间随机而是确保每个粒子初始就在机组出力范围内随机取值避免粒子一诞生就严重越界这会显著提高前期收敛效率。4.2 粒子群主循环的代码架构核心主循环骨架如下%% 参数设置 nPop 200; % 种群规模 Tmax 300; % 最大迭代次数 nDim 121; % 决策变量维度 nObj 3; % 目标函数个数 % 档案初始化 Archive []; ArchiveCost []; for iter 1:Tmax % 1. 自适应惯性权重和学习因子 w 0.9 - (0.9 - 0.4) * (iter / Tmax)^2; c1 2.6 - (2.6 - 1.6) * (iter / Tmax); c2 1.6 (2.6 - 1.6) * (iter / Tmax); % 2. 更新每个粒子的速度和位置 for i 1:nPop % 从外部档案中随机选择一个作为全局最优 if ~isempty(Archive) gbest_idx randi(size(Archive, 1)); gbest Archive(gbest_idx, :); else gbest particle(i).Position; end particle(i).Velocity w * particle(i).Velocity ... c1 * rand(1, nDim) .* (particle(i).pbest - particle(i).Position) ... c2 * rand(1, nDim) .* (gbest - particle(i).Position); % 速度限幅防止粒子飞出界限 particle(i).Velocity max(min(particle(i).Velocity, Vmax), -Vmax); particle(i).Position particle(i).Position particle(i).Velocity; % 位置边界处理越界边界处带随机扰动弹回 particle(i).Position max(min(particle(i).Position, Xmax), Xmin); % 3. 计算目标函数和约束违规量 [cost, emission, curtail, viol] ... EvaluateFitness(particle(i).Position, data); % 4. 更新个体历史最优Pareto支配判断 if ParetoDominates(particle(i).Position, particle(i).pbest) particle(i).pbest particle(i).Position; end end % 5. 更新外部档案合并本轮非支配解 [Archive, ArchiveCost] UpdateArchive(Archive, ArchiveCost, ... particle, data, ArchiveMaxSize); end速度限幅Vmax这里需要特别说明。我设置为( Xmax - Xmin ) × 0.2也就是粒子单次位置变化最大不超过整个搜索区间宽度的20%。这是防止粒子在迭代后期因速度积累过大而在可行域内来回横跳保证收敛稳定性。4.3 适应度函数与约束罚函数的具体写法EvaluateFitness是整个算法里最容易出错的部分。我的写法是把目标函数值和约束违规量分开计算约束违规量再单独返回给主循环处理而不是混在目标值里function [cost, emission, curtail, viol] EvaluateFitness(x, data) % 将所有决策变量拆成各时段的调度值 P_MT1 x(1:24); P_MT2 x(25:48); P_FC x(49:72); P_ESS x(73:96); % 正为充电负为放电 P_grid x(97:120); % 正为购电负为售电 SOC_ini x(121); % 目标1总运行成本 cost sum(MT1_fuel(P_MT1) MT2_fuel(P_MT2) FC_fuel(P_FC) ... OM_cost(P_MT1 P_MT2 P_FC abs(P_ESS)) ... grid_cost(P_grid, price)); % 目标2碳排放总量 emission sum(emis_MT1 * P_MT1 emis_MT2 * P_MT2 emis_FC * P_FC); % 目标3弃风弃光惩罚 curtail sum(lambda_curtail * ... (PV_avail - PV_used WT_avail - WT_used)); % 约束违规量返回标量表示所有约束的总违规程度 viol 0; % 1) 功率平衡强制等式约束违规量大 balance_res sum(P_MT1 P_MT2 P_FC P_ESS P_grid ... PV_used WT_used - P_load); viol viol abs(balance_res) / sum(P_load); % 2) 机组上下限 viol viol sum(max(0, Xmin_MT1 - P_MT1) max(0, P_MT1 - Xmax_MT1)); % ... 其他机组类似 % 3) 储能SOC递推约束跨时段 SOC SOC_ini; % 初始化SOC SOC_history zeros(1, 24); for t 1:24 if P_ESS(t) 0 SOC SOC data.eta_ch * P_ESS(t) * 1 / data.ESS_cap; else SOC SOC P_ESS(t) / data.eta_dis / data.ESS_cap; end % SOC越限惩罚 viol viol max(0, SOC - 0.9) max(0, 0.2 - SOC); SOC_history(t) SOC; end end这里有个容易忽略的细节SOC递推用的是上一时段结束后的SOC而不是当前时刻出力对应的瞬时值。如果不按顺序递推只是简单把所有时段的SOC都当作独立变量储能的时间耦合特性就丢了调度结果在物理上不可行。我在前期版本里踩过这个坑优化出来的SOC曲线在连续时段之间突变一看就是不合理的。5. 仿真结果解读改进方案到底赢在哪里算法写完最关心的就是把改进PSO和标准PSO放在同一算例下做对比。我的对比方式是固定相同的微网参数、负荷曲线、风光出力曲线分别运行标准PSO、改进PSO各30次统计结果的均值、最值和Pareto前沿分布避免单次运行的随机性影响结论。5.1 收敛曲线与稳定性对比先看单目标化处理后的收敛曲线。为了公平比较我把多目标问题暂时用等权重加权成单目标观察两种算法在同一目标空间下的收敛速度。标准PSO大概在80代左右收敛但最终适应度明显偏高改进PSO虽然前期收敛略慢但能持续下探到更低的目标值代际间的波动也小很多。30次独立运行的统计结果如下指标标准PSO改进PSO运行成本最优值元5846.35462.8运行成本平均值元6017.55521.4成本标准差元198.646.2排放最优值kg162.5148.3排放标准差kg9.73.1标准差从198元降到46元说明自适应权重和档案维护机制确实提升了算法的稳定性。对调度人员来说稳定性有时比最优性更重要——你不可能为了一个理论上最优但极不稳定的方案去反复调参。5.2 Pareto前沿分布的改善标准PSO因为缺少外部档案和拥挤距离机制最终只收敛到Pareto前沿的一小段区域而且解在目标空间的分布很稀疏。改进PSO的Pareto前沿覆盖了从“低成本高排放”到“高成本低排放”的完整区间解分布也更均匀。这一点直接决定了解的可选择性。如果微网在某段时间面临环保指标压力调度员可以直接从改进PSO给出的Pareto前沿里挑选排放更低的解而标准PSO给出的狭窄前沿几乎不提供这种灵活度。5.3 典型日调度方案的效果拆解用模糊隶属度函数选取最优折中解后我把各设备的24小时出力曲线画出来看。改进PSO给出的调度方案有几个明显的合理特征在电价低谷时段储能充电、微型燃气轮机低负荷运行尽量从主网购电便宜的电在电价高峰时段储能放电、燃气轮机提高出力减少从主网购电显著压低成本在光伏出力高峰时段微网主动降低燃气轮机出力优先消纳光伏弃光量明显减少碳排放目标与成本目标产生矛盾时模糊隶属度能自动寻找平衡点而不是一边倒。标准PSO给出的方案则明显“僵硬”——储能充放电切换频繁甚至出现相邻时段储能先充满电又立刻放光的非理性动作燃气轮机的出力也普遍偏高说明算法没有充分搜索到更优的调度组合。6. 实际运行中的“坑”与调优心得最后这部分是我觉得最有价值的内容。整个项目做下来真正耗费时间最多的不是算法设计本身而是各种各样的“工程细节坑”。我把印象最深的几个写出来给后来者一个提示。6.1 罚函数系数的量纲问题成本和排放根本不是同一个世界我前面提到排放目标的数值通常只有成本数值的几十分之一。如果用统一罚函数系数会出现在罚函数中排放在数值上几乎不起作用的现象——罚函数的值被成本项主导。我的解决办法是分目标归一化后再求和也就是罚函数里每个约束违规量的数值先除以该目标在整个种群中的最大-最小范围再乘统一系数。这样各目标在罚函数中的贡献是等量级的算法才不会偏心。6.2 三种随机性叠加结果不稳定是必然的微网调度这个场景天然有多个随机源初始种群是随机的、PSO本身的速度更新是随机的、光伏和风电的预测误差也是随机的。如果不加控制地进行对比实验很容易得出错误结论——比如误把某次随机种子的好运当成算法改进的效果。我在项目里强制所有对比实验用相同的随机种子初始化种群并且每个算法独立运行30次取统计指标。论文里报告结果时仅报告单次运行的最佳值不仅不严谨也没有参考价值。如果你要做算法对比一定不要省这一步。6.3 决策变量维度升高后代码性能从循环优化转向向量化121维决策变量、200个粒子、300次迭代如果在适应度函数里用嵌套循环逐时段逐机组计算MATLAB跑一次要接近10分钟。我后来做了两处优化第一把适应度计算中的时段循环改成矩阵运算一次计算所有24个时段的目标值运行时间降到约2分钟。第二在Pareto支配判断时用一个矩阵同时比较多个粒子的支配关系而不是逐个粒子嵌套比较效率提升非常明显。这个经验对所有基于MATLAB的智能优化算法都适用——尽量用矩阵思维代替循环思维尤其当你的目标函数需要反复计算数千次时这个优化直接决定项目能不能在可接受的时间内跑完。做这个项目的整体感受是改进粒子群算法本身不算什么神奇发明但它放到微网多目标调度这个具体问题上确实解决了标准PSO在Pareto搜索、稳定性、约束处理方面的核心短板。仿真结果验证下来改进PSO在收敛性、Pareto前沿分布和解的稳定性上都明显优于标准PSO给出的折中调度方案在物理上也合理。如果后续想继续深入可以考虑把光伏和风电的出力不确定建模成多场景或者鲁棒优化框架在现有算法基础上加入场景削减和分布鲁棒约束进一步贴近真实运行条件——但那就是另一个层面的项目了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进