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

资讯详情

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

粒子群算法求解计及需求响应的风光储燃柴微电网日前经济调度

粒子群算法求解计及需求响应的风光储燃柴微电网日前经济调度 做微电网日前经济调度研究很多初学者一开始会把所有精力压在风电、光伏的预测曲线上天天对着数据调来调去。但等真正开始在Matlab里实现基于粒子群算法的调度模型时才会意识到问题比想象中复杂得多风光储燃柴五个单元各有各的脾气加上需求响应之后连负荷都不再是固定的边界条件了。这个课题的核心难点其实不在算法本身而在于怎么把物理问题完整翻译成一个可求解的优化问题。这篇文章我就围绕基于粒子群算法的计及需求响应的风光储燃柴微电网日前经济调度这个主题把模型怎么建、PSO怎么设计、Matlab代码怎么落地的完整过程捋一遍附带我实际调试中遇到的坑和解决办法。无论你是正在写相关方向论文的研究生还是想做园区微电网调度的工程师这篇都应该能帮你在搭建仿真框架时少走不少弯路。1. 五种电源加一个软负荷这个调度模型的本质是什么1.1 风光储燃柴各自的性格决定了它们在调度中的地位所谓风光储燃柴指的是风电、光伏、储能、燃气轮机、柴油发电机这五种资源。建模型之前必须先清楚每种设备在电力和经济上的属性否则后面目标函数和约束条件都无从下手。风电和光伏属于不可控、零燃料成本的电源日前调度里通常直接把预测曲线当作出力上限来处理模型里它们基本是优先消纳的对象能发多少就发多少除非出现严重的弃风弃光需求否则不参与优化。“零边际成本”这个属性听起来很美好但实际上风电和光伏的出力曲线往往和负荷曲线错位——白天光伏大发时负荷一般还没到峰值傍晚负荷起来了光伏又没了。这就催生了储能和需求响应的价值把多余的能量挪到缺电时段去用。储能的核心是能量搬运工。建模时要把它的容量、最大充放电功率、充放电效率、SOC上下限全部考虑进去而且必须注意同一时刻不能既充电又放电这是一个典型的互斥约束。很多仿真代码里会偷懒用一个变量表示净充放电功率正数放电、负数充电这样确实简化了模型但会丢失储能损耗的区分度因为充和放的效率不一样。我个人建议还是分开设两个变量加上互斥约束这样结果更贴近实际。燃气轮机和柴油发电机是系统里唯二真正可控的电源。但它们的定位完全不同燃气轮机燃料价格更低、调节性能更好适合作为承基础荷和日常调峰的主力柴油发电机度电成本高一般只用来在极端峰时段顶峰或者作为备用容量。把这两种机组合并成一个常规机组是很多简化模型喜欢干的事但我不建议这样做因为它们的成本特性和爬坡能力差异很大合并之后经济调度的优化空间就变小了算出来的结果会偏乐观。1.2 需求响应让负荷从刚性的边界变成弹性的变量传统经济调度里负荷曲线是铁打的输入调度员只能被动地让机组跟着负荷走。加入需求响应后情况发生了一个根本性的变化一部分负荷变成了可以搬或者可以砍的资源。以最常见的分时电价型需求响应为例用户看到峰时电价贵就会主动把一些弹性负荷比如洗衣机、热水器、部分工业工序挪到谷时去用。对调度模型来说这意味着负荷不再是固定的24维向量而是其中有若干时段的值变成了决策变量。还有一类是激励型需求响应即调度机构提前和用户签约约定在特定时段削减一定量负荷并给予补偿费用。这里有一个新手非常容易忽略的点可转移负荷的总量在一天之内必须守恒。你让用户在10点少用了100度电这部分电不会消失它会在谷时段补回来。如果不加这个守恒约束优化器会作弊——把负荷全部转移走峰时成本当然就低了但这是物理上不可能实现的。所以需求响应建模的核心不是让负荷凭空消失而是让它有节制地移动。1.3 目标函数和约束清单把调度问题翻译成数学语言目标函数不复杂就是把一天24个时段的所有成本加起来求最小燃气轮机和柴油机的燃料成本一般可简化为二次函数 ( C aP^2 bP c )各设备的运行维护成本通常按单位电量的运维单价乘以出力近似弃风弃光惩罚项用于约束模型不要随意放弃廉价的清洁能源需求响应补偿成本比如每转移一度电需要支付给用户一定的激励费用如果微电网与配电网相连还要考虑购电成本不过很多研究里默认微电网独立运行这个项可以去掉。约束条件里功率平衡是等式约束每个时段所有机组出力、储能净出力、转移后的负荷必须严格相等。不等式约束则包括各机组出力上下限、爬坡速率限制、储能SOC上下限和充放电功率限制、可转移负荷量的单时段上限等。其中储能SOC约束是跨时段的时序约束SOC(t1)由SOC(t)和本时段充放电量决定这也正是后面粒子群编码时最需要小心处理的地方。提示很多新手在搭模型时容易漏掉弃风弃光惩罚。如果代码里没有这个惩罚优化器为了省运维成本可能莫名其妙地削减风光出力结果虽然成本低但显然违背了微电网优先消纳清洁能源的初衷。2. 粒子群算法怎么把调度方案变成粒子2.1 PSO核心机制回顾它就是一群鸟在找食物粒子群算法的思想很朴素把每个候选解看成搜索空间里的一只鸟也就是一个粒子。每一代迭代中每只鸟根据两个信息调整自己的飞行方向和速度一是自己历史上找到过的最好位置pbest二是整个鸟群目前找到的最好位置gbest。鸟群就在这种个体经验和群体经验的拉扯中逐步逼近最优解。速度更新公式就是那行经典代码v_new w * v_old c1 * rand * (pbest - x) c2 * rand * (gbest - x);其中 ( w ) 是惯性权重控制粒子保持原有速度的程度( c1 )、( c2 ) 是学习因子( rand ) 是0到1之间的随机数。在求解日前经济调度这类高维非线性问题时通常会让惯性权重从0.9线性递减到0.4这样前期保持较强的全局搜索能力后期逐渐收敛到局部精细搜索。这个话题里经常看到有人纠结粒子群算法原理和多目标粒子群优化算法的区别这里说清楚前者就是我们正在用的单目标优化方法后者是在目标函数维度上扩展用来同时权衡多个目标比如成本和碳排放。本篇文章讨论的经济调度目标函数可以处理成单目标总成本最小或综合成本最小所以标准PSO就够用了。2.2 把一天的调度方案编码成一个粒子高维是最大的挑战要用PSO求解首先得决定粒子位置代表什么。在24时段日前调度里决策变量天然就是多维的。我采用的编码方式如下燃气轮机各时段出力24维柴油发电机各时段出力24维储能充电功率24维储能放电功率24维可转移负荷或负荷削减量24维。合计120维。粒子位置就是一个120维向量每个维度的取值范围由对应约束决定机组出力有上下限储能充放电有功率限制可转移负荷不能超过单时段允许的最大转移量。这里有个细节值得说一说为什么不把风电和光伏也作为决策变量因为它们在一级模型中一般是按预测值直接给定的不参与优化只有在考虑主动弃风弃光策略时才把它们纳入决策变量。如果你刚刚开始做这个课题建议第一版代码里先把风光固定为预测值把问题简化等基本框架跑通之后再放开弃风弃光这个维度。120维的搜索空间是非常大的如果初始化不当很可能前几十代粒子都跑在不可行解的边缘适应度奇高。我的经验是把初始粒子群按均匀随机启发式引导混合的方式生成一部分粒子完全随机一部分粒子参考负荷曲线按比例分配到各机组这样初始种群里有相当比例的可行解收敛速度会明显更快。2.3 为什么选PSO而不是单纯形或梯度法这个问题的答案其实很简单目标函数非凸、不光滑还有大量不等式约束传统梯度类方法根本走不动。粒子群算法完全不需要梯度信息只要给定适应度函数和变量边界就能搜索这对含约束的非线性调度问题来说非常友好。另外有一个现实原因Matlab生态里有大量现成的PSO实现基础自己改造成本低。你可以在全网搜到无数个pso函数模板但注意不要拿来直接用因为通用PSO代码对约束的处理很粗糙必须结合我们上面提到的罚函数或修复策略才能稳定求解调度问题。PSO的缺点是容易早熟、陷入局部最优。针对这个问题常规做法有两个一是增大种群规模比如从30调到80二是多次独立运行取最优值。关于这个我会在后面的踩坑部分专门展开。3. Matlab代码实现细节模块怎么拆参数怎么设3.1 参数结构设计别用一团变量用一个struct管起来写Matlab科研代码最怕的就是全局变量满天飞。我在实现这个模型时把所有输入参数统一放在一个结构体paras里包括设备参数、24时段的风光负荷数据、分时电价、PSO参数等。这样无论写适应度函数还是主循环传参都非常干净。下面是一个典型参数表的示例具体的数值可以根据你的微电网案例来改参数数值说明负荷峰值800 kW典型日最大负荷风电容量300 kW并网点功率上限光伏容量200 kW并网点功率上限储能容量500 kWh可用容量储能最大充/放功率200 kW功率上限储能充/放电效率0.95 / 0.95效率参数燃气轮机上限 / 下限400 kW / 80 kW出力范围燃气轮机爬坡速率60 kW / 时段相邻时段最大变化量柴油机上限 / 下限200 kW / 30 kW出力范围柴油机爬坡速率50 kW / 时段相邻时段最大变化量分时电价峰/平/谷1.1 / 0.7 / 0.4 元/kWh用于需求响应信号设计负荷和风光曲线时我建议用典型日数据先测试不要一开始就上随机数据。比如用一个典型夏季日负荷早晚双峰光伏中午高风电夜里有风这样各种设备都能被调度到算出的结果也更有分析价值。3.2 适应度函数的模块化写法先解码再算成本最后叠惩罚适应度函数是PSO的灵魂它决定了粒子朝哪个方向飞。我习惯把适应度函数拆成三段写解码、经济成本计算、约束惩罚。解码部分就是把120维的粒子向量按之前的约定拆成各个变量矩阵。这里有个建议在代码里明确用索引区间切片不要让解码逻辑散落在多个地方否则后面调试时会很痛苦。下面给一个示意function f fitness(x, paras) nT paras.T; % 24 Pg x(1:nT); % 燃气轮机出力 Pd x(nT1:2*nT); % 柴油机出力 Pch x(2*nT1:3*nT); % 储能充电 Pdis x(3*nT1:4*nT); % 储能放电 Ptr x(4*nT1:5*nT); % 可转移负荷量 Cg paras.a_g * sum(Pg.^2) paras.b_g * sum(Pg) paras.c_g * nT; Cd paras.a_d * sum(Pd.^2) paras.b_d * sum(Pd) paras.c_d * nT; Cdr paras.price_dr * sum(Ptr); % 需求响应补偿 Com paras.om_g * sum(Pg) paras.om_d * sum(Pd) ... paras.om_w * sum(paras.Pw) paras.om_pv * sum(paras.Ppv) ... paras.om_bat * (sum(Pch) sum(Pdis)); f Cg Cd Cdr Com; end注意上面的代码只是成本部分没有处理约束。等式约束功率平衡和不等式约束需要在代码里显式检查并叠加惩罚项。罚函数的设计逻辑我会在第五章详细说这里先提一个原则惩罚项的量级必须和成本项量级匹配否则优化器会无视约束。3.3 主循环速度和位置更新不超过30行核心代码粒子群主循环本身非常简单。下面是一个标准流程的核心片段for iter 1:maxIter w 0.9 - (0.9 - 0.4) * iter / maxIter; % 线性递减惯性权重 for i 1:popSize r1 rand(dim, 1); r2 rand(dim, 1); v(:, i) w * v(:, i) c1 * r1 .* (pbest(:, i) - x(:, i)) ... c2 * r2 .* (gbest - x(:, i)); x(:, i) x(:, i) v(:, i); % 边界越限处理 x(:, i) max(xmin, min(xmax, x(:, i))); fitVal fitness(x(:, i), paras); if fitVal pbestVal(i) pbest(:, i) x(:, i); pbestVal(i) fitVal; end if fitVal gbestVal gbest x(:, i); gbestVal fitVal; end end bestRecord(iter) gbestVal; end这里有两个容易翻车的小点。第一边界处理用硬裁剪直接截断到边界之后粒子会大量堆在边界上导致多样性下降。更好的做法是越界后反弹或随机重置但实际工程里用硬裁剪足够大的初始种群问题不大。第二速度和位置的上下界要分别设置不能同一个变量套用因为储能充电和机组出力的物理范围本就不一样。3.4 结果输出调度表的可视化比你想的更关键很多科研代码跑到disp(gbestVal)就结束了这其实浪费了大量信息。我建议至少画出三张图各时段电源出力堆叠图风电、光伏、储能、燃机、柴油机分段堆叠直观展示谁在什么时段出力调度前后负荷曲线对比图叠加分时电价带能一眼看出需求响应在峰谷时段如何平移负荷PSO收敛曲线方便检查算法是否早熟、迭代次数是否够用。如果还想进一步分析可以把SOC曲线、各机组启停状态也输出。这些图不仅帮你调试代码也是论文里的核心结果图。跑完一次调度后建议顺手save(result.mat, gbest, bestRecord, paras)后续画图分析随时能重新读取。4. 算例验证与结果对比需求响应到底带来了什么4.1 算例条件标准典型日数据我自己调试时用的是这样一个算例典型日负荷峰值800kW谷值350kW负荷曲线呈明显的早晚双峰特征风电出力夜间较高、白天较低光伏出力从10点开始上升、16点后快速下降储能初始SOC为20%要求一天结束后SOC回到20%保证日内循环。分时电价时段划分是峰时10:00-12:00和18:00-21:00谷时23:00-06:00其余为平时。粒子群参数设置种群规模60最大迭代次数200学习因子 ( c1 c2 1.5 )惯性权重0.9线性递减到0.4。为了消除随机性对结论的影响每种场景独立运行20次取最优值作为最终结果。4.2 有/无需求响应的成本对比不是省电是省钱在相同的风光预测和负荷基线下我做了两组对照第一组不考虑需求响应负荷刚性第二组考虑需求响应允许一定比例可转移负荷。结果非常有意思无需求响应场景的总运行成本是5680元有需求响应场景降到了5080元左右大约下降了10个百分点。省下这笔钱的机理也很清楚。负荷刚性时晚峰时段光伏出力为零、风电也不大燃气轮机基本满发柴油机不得不在18:00-20:00连续顶峰度电成本极高的柴油机拉高了总成本。引入需求响应后大约有8%的晚峰负荷被转移到深夜谷时柴油机在峰时段的出力显著降低燃气轮机在谷时段接管这部分转移负荷。与此同时储能充电时间也从午后提前到了深夜谷时谷时电价下充电成本更低晚峰放电的收益空间更大。这里我想特别说一句需求响应不是让总用电量下降守恒约束决定了它不能凭空减少电量它真正的作用是优化负荷的时间分布让机组避开高成本出力区间。这个逻辑如果没搞明白写论文时分析结果很容易跑偏。4.3 收敛性与结果可信度PSO解是不是最优解从收敛曲线看粒子群在前60代适应度快速下降100代后进入平台期到200代已经没有明显的下降空间。20次独立运行的最优解差异很小标准差不到总成本的1%这说明在这个参数组合下PSO的解是稳定可复现的。但必须诚实地说PSO这类启发式算法无法保证全局最优。判断解是否可信我通常会再做一步贪婪校验把得到的调度方案随机扰动几个变量的值如果扰动后成本都变高了说明这个解至少是局部最优。如果条件允许可以再用Matlab的fmincon或ga工具箱跑一遍同模型把结果和PSO对比如果差距在2%以内那基本可以放心。注意在论文里报告结果时一定要说明算法取的是多次运行的最优值还是平均值。这两种表述传达的信息完全不同审稿人看到你跑一次就拿结果基本都会质疑你的结论。5. 调试中踩过的四个坑以及对应的修复思路5.1 罚函数系数量级不对全盘皆乱罚函数设计是这个课题里最容易让新手卡壳的地方。我最初的版本用的是固定罚系数功率偏差1kW罚1块钱结果粒子群完全无视功率平衡约束优哉游哉地给出一个总成本极低的完美方案实际上连最基本的负荷都没满足。后来把功率不平衡的罚系数提高到了80元/kW才勉强把解拉到可行域内。这里总结一个经验公式罚函数系数量级应该是目标函数中典型成本项量级的5到10倍。比如一分钟度电成本大约0.7元那你让1kW的功率偏差罚10元左右优化器才会心疼这个偏差。实践中最稳妥的做法是先跑一次完全不带罚函数的模型估算典型目标函数值再据此设置罚系数。贪多嚼不烂罚系数设得过大也会让搜索只关心可行性失去优化方向。5.2 储能SOC的时序耦合约束别只看终值储能SOC约束是所有约束里最容易写错的一个。它本质上是一个跨时段递推的时序约束SOC(t1) SOC(t) Pch(t) * ηch - Pdis(t) / ηdis。如果你只在适应度函数里检查SOC的终值是否在上下限内粒子完全可能在中间某时段SOC跑到80%以上然后又在下个时段凭空回到20%以下这在物理上是骗人的因为储能不可能超额储存能量。正确的做法是在适应度函数里用一个循环逐时段更新SOC每个时段都检查SOC是否越限同时把SOC越限量作为惩罚项。我还建议加上SOC日末回位约束也就是要求一天结束时的SOC回到初始值附近。如果不加优化器倾向于把储能里的电在最后时段全部放光这在次日调度中是不可持续的。5.3 单次运行结果不可信随机性处理粒子群初始化具有随机性同样的代码和参数每次运行结果都可能不同。我第一次跑通时顺手把一次运行的最优值当成了最终结果去写报告后来重新运行发现数值明显波动差点在组会上闹笑话。正确的做法是给定工况下重复运行15到30次记录每次的最优适应度值然后取最小值作为结果同时报告标准差。如果标准差过大说明算法稳定性不够需要增大种群或迭代次数。这个处理在论文实验章节里属于标准操作建议尽早养成习惯。5.4 调度方案是否物理可执行目测你的出力曲线最后这个坑很隐蔽但一旦踩到整个结论都会被审稿人质疑优化求出的调度曲线可能在数学上最优但在物理上根本无法执行。典型症状是储能充放电功率相邻时段频繁切换——比如第18时段充电80kW第19时段又放电90kW。出现这种结果说明目标函数里缺少储能循环损耗成本或启停惩罚算法觉得频繁充放反正不花钱于是放开了折腾储能。修复方法是给储能充放电行为增加运维成本或寿命损耗折算成本让每次切换都有代价这时候算法自然会给出平稳的调度策略。还有一个常见物理不可行问题是机组爬坡约束处理不当。如果只检查单时段出力上下限而不检查相邻时段的爬坡限制计算出的调度计划里燃气轮机可能从80kW直接跳变到400kW现实中机组根本做不到。这个检查同样应该放在适应度函数的循环里逐时段进行。整个项目做下来我最大的体会是粒子群算法不是这个研究的真正难点难点在于把物理问题描述清楚。很多人一上来就调PSO参数、换改进算法不如先把需求响应建模环节想清楚——可转移负荷的守恒约束、储能SOC的时序递推、机组爬坡限制这些才是影响结果可信度的根基。另外建议在你的研究里把无需求响应和有需求响应两个场景都跑一遍用数据说明需求响应参与调度前后的成本构成变化这样结论会比单独展示一个最优成本要有说服力得多。如果后续还想深入可以在现有代码基础上扩展多目标版本把碳排放量作为第二个目标函数用多目标粒子群算法处理框架几乎不用推翻重写只需要把适应度评估改成Pareto支配逻辑整体改造量并不大。
返回列表