☰
虚拟电厂日前-日内两时间尺度调度优化Matlab复现解析
2026/10/15 9:04:58 网站建设 项目流程

做电力系统优化的人,最近两年应该会频繁碰到一个词——虚拟电厂。我刚拿到这套“日前调度+日内调度”两时间尺度调度优化的Matlab代码时,第一反应是标题很大,但真正跑通以后发现,这个项目的核心思路其实特别清晰:把虚拟电厂内部的风电、光伏、储能、可控负荷这些资源,放在两个不同的时间尺度上分别做优化,一个管全天的大节奏,一个管接下来几小时的细账,最后整理成两条互补的调度曲线。对于正在做分布式能源、微电网或者储能调度方向的同学来说,这确实是个非常值得花时间吃透的复现工作。这篇文章我就把整个模型的拆解思路、Matlab代码实现细节、以及复现过程中容易踩的坑一起盘一盘。

1. 项目到底在做什么:把标题拆开看调度体系

1.1 虚拟电厂和它要解决的真实问题

虚拟电厂不是什么铁塔电线建出来的物理电厂,而是把分散的分布式资源用通信和算法“拧”成一股绳,对外整体表现为一个可控电源。一个写字楼屋顶的光伏、一个园区的储能柜、一批可以错峰启停的空调负荷,单独拿出来都不够调度部门正眼看一下,但聚合起来可能是几兆瓦的调节能力。虚拟电厂的价值就在于聚合和协同,而协同的关键就是调度。

调度在这里解决的是一个非常现实的问题:明天光伏大发的时候储能要不要充电、充多少;负荷晚高峰的时候是让储能放电还是削减一部分可中断负荷;电价低谷时段要不要从电网多买点电存起来。这些问题必须提前做一个相对合理的安排,不然等到实时运行再反应,就已经来不及了。这套复现项目做的事情,就是把这个“提前安排”的过程用数学优化模型写了下来,并且在两个时间尺度上分别做了一遍。

1.2 为什么非要分两个时间尺度:一锤子买卖不靠谱

刚开始接触这个方向的人最大的疑问往往是:为什么不干脆做一个整体优化,把所有时段和所有设备一把算完,非要分开做“日前”和“日内”两层?

原因很简单,预测精度和决策时机的矛盾。离实际运行时间越远,新能源出力和负荷的预测误差越大。你提前24小时看明天的光伏曲线,基本只能看个大概;但如果提前1小时甚至15分钟再看,准确度就高很多。如果只做日前调度,等于拿一个粗糙的水晶球制定全部计划,实际运行必然对不上;如果只做日内调度,储能和机组启停这种需要提前准备的决策又来不及反应。

所以业界标准的做法就是分层决策,长周期定大方向、短周期做修正。日前调度以小时为颗粒度优化未来24小时,得出一个基准计划;日内调度以15分钟甚至更细的颗粒度滚动优化近几个小时的调整量。两层之间有数据传递、有约束衔接,这就构成了本项目的完整闭环。

2. 日前调度:提前一天的大节奏规划

2.1 日前调度到底在优化什么

日前调度的任务是在“看到”未来24小时负荷预测、新能源出力预测和电价的基础上,决定未来一天虚拟电厂内部各设备的运行计划。目标函数一般有两种写法,一种是运行成本最小化,一种是收益最大化。我这次复现采用的是成本最小化框架,本质上两者等价,只是符号和价格项的位置不同。

成本项通常包含:向上级电网购电的费用、燃气轮机或者柴油机的发电成本、储能充放电的损耗折价、以及调用可中断负荷的补偿费用。收益项则是向电网售电的收入。目标函数的数学形式如下:

min ∑(购电成本 + 机组燃料成本 + 储能老化成本 + 可中断负荷补偿 − 售电收入)

这里有个细节容易被新手忽略:储能本身没有燃料成本,但如果完全不设置充放电的“使用代价”,优化器就会让储能频繁动作,甚至出现为了几分钱来回倒腾的情况。在实际电力系统中这叫“短时往复调度”,对电池寿命很不友好。所以复现时最好在储能项加一个很小的单位成本系数,哪怕只有每千瓦时几厘钱,也能让结果稳定合理得多。

2.2 决策变量和约束条件的实际含义

日前调度的决策变量包括:各时段向电网购电功率、售电功率、储能充电功率、储能放电功率、可中断负荷的削减量。如果虚拟电厂里还有燃气轮机,那么机组的启停状态、出力大小也是决策变量,这就引入了0-1整数变量,模型也从线性规划升级成混合整数规划。

约束条件里最重要的几条,我按实际建模顺序列一下:

  • 功率平衡约束:任何时候总发电加上购电,必须等于总负荷加售电加储能充电。这个约束把整个虚拟电厂内部的电能流动串成一条线。
  • 储能SOC递推约束:剩余电量等于上一时段加充电减放电,还要乘上充放电效率。充放电效率的取值很敏感,一般充电取0.9到0.95,放电同样。如果这个参数写错,整个调度结果的SOC曲线会出现明显的物理不守恒现象。
  • 充电和放电互斥约束:模型必须限制同一时段不能既充电又放电。这个在建模时用两个0-1变量就能实现。虽然在理论上充放互斥属于常识,但如果不显式建模,求解器真的会让你看到电同时流进流出这种滑稽结果。
  • 爬坡约束:机组出力和储能功率在相邻时段的调整量不能超过上限,否则设备实际跟不上计划的调整速度。
  • 可中断负荷约束:削减量不能超过合同约定的上限,也不能让总削减量超过当天可用的总量。

2.3 一个典型的24小时算例

为了让模型落地,我在复现时自己构造了一份接近真实特征的测试数据。负荷曲线取了典型的双峰形状,早高峰出现在9点到11点,晚高峰出现在18点到21点。光伏出力做了个钟形曲线,中午12点到14点达到峰值。风电设成一个相对稳定的基荷加上一点随机波动。分时电价采用峰平谷三段结构,低谷时段电价大约只有高峰的40%。这个典型日设置非常关键,因为只有把峰谷差和新能源波动做得明显,日前调度才能看出有意安排的“谷充峰放”响应行为。

跑完日前优化以后,你会得到一条全天24小时的购电计划曲线,以及储能各时段是充还是放的序列。比如光伏大发的中午时段,如果光伏出力超过负荷,储能大概率会进入充电状态;晚高峰电价高的时候,储能就会放电替电网分忧。这个结果虽然看上去“理所应当”,但它背后是上千个约束条件同时满足后得到的最优解,而不是靠规则拍脑袋拍出来的。

3. 日内调度:滚动优化的误差修正机制

3.1 日内调度为什么必须滚动着算

日内调度的核心机制是滚动优化,工业界叫模型预测控制。基本思路是:每15分钟触发一次优化,但并不是一下子把后面96个时段全部定死,而是只看未来4个小时的窗口,算出结果后只执行下一个15分钟的动作,等到下一个触发时刻,用最新的超短期预测数据重新优化一遍窗口。

这个过程有点像导航软件,每次重新规划路线,但只看着下一个路口怎么走。因为超短期预测(未来4小时)明显比中期预测(未来24小时)准,所以每次重新规划都能把最新的误差信息吸收进来,主动修正偏差,而不是等着偏差累积到最后爆发。

3.2 日内调度目标和约束与日前有什么不同

日内调度不是简单地把日前模型的时间分辨率改细再算一遍,它的核心逻辑从“全局最优”变成了“跟踪和修正”。目标函数通常由两部分组成:一是运行成本项,二是偏差惩罚项。偏差惩罚项衡量的是日内出力计划与日前计划之间的偏离程度,偏离越大惩罚越重。

这样设计的原因很直白:日前计划已经对电网做过申报,日内如果大幅度偏离,相当于违约,会产生考核费用。所以日内调度是在“尽量守住日前承诺”和“尽量少花新成本”之间做权衡。

约束上与日前的差异在于:日内时段粒度更细,比如15分钟一个断面,一个4小时的滚动窗口就有16个时段;储能设备的物理约束不变,但SOC初值必须取当前实际量测值,而不是理论推算值。这个“初值取真实值”的细节是系统能否闭环的关键,如果还是用日前的SOC计算值做初值,误差就会在一天内不断滚动累积,最终日内调度完全失控。

3.3 偏差惩罚系数怎么调

偏差惩罚系数是整个日内调度模型里最敏感的系数。设得太小,日内结果可能和日前计划完全脱节,失去跟踪意义;设得太大,日内模型又几乎不敢做任何调整,一旦实际光伏和日前预测差别很大,系统就硬扛着,反而浪费了日内预测精度高的优势。

实际操作中我习惯先看量级。先把成本项里的电价放进去,再把偏差惩罚设为电价的2到5倍,做一个基准版本跑一遍。然后检查日内调度给出的出力曲线和功率平衡情况:如果曲线频繁剧烈波动,说明惩罚系数偏小;如果曲线几乎和日前计划重合,但实际负荷预测发生了明显变化,说明惩罚系数偏大。做两三次敏感性测试基本就能定下来。这个调参过程不是玄学,本质上是你对模型“胆子”和“稳定性”的主动控制。

4. Matlab复现的工程细节与代码逻辑

4.1 工具链选型:YALMIP还是intlinprog

Matlab做优化调度,首先面对的是建模工具选择。这个项目我推荐直接使用YALMIP,理由很实际:它可以用人类能读懂的方式写约束和目标,而不是把所有约束手动塞进矩阵A和向量b里。模型复杂的时候,矩阵方式非常容易写错行列号,而且错了极难排查。YALMIP的底层再调用具体求解器,既可以用Gurobi,也可以用Cplex,没有商业授权的话用开源的SCIP或者Matlab自带的intlinprog也能顶一阵。

我在本地用的是YALMIP加Gurobi的组合,Gurobi在求解混合整数规划问题上速度确实快,尤其是日内调度要滚动跑几十次优化,每轮都要在几百毫秒内出结果,求解器性能非常影响体验。

4.2 核心代码结构拆解

整个Matlab代码建议按功能拆成四大块,而不是一个主脚本从头写到尾:

第一块是数据准备模块。所有负荷、新能源出力、电价、设备参数都放在结构体或者表格里,集中管理。这样后面无论是改数据还是做敏感性分析都很方便。第二块是模型搭建模块,定义决策变量、约束和目标函数。第三块是求解模块,调用求解器并处理返回结果。第四块是结果后处理和出图模块。

日前调度模型搭建的核心代码框架大致如下:

%% 日前调度模型框架(示意) % 24时段决策变量 Pbuy = sdpvar(1, 24, 'full'); % 购电功率 Psell = sdpvar(1, 24, 'full'); % 售电功率 Pch = sdpvar(1, 24, 'full'); % 储能充电 Pdis = sdpvar(1, 24, 'full'); % 储能放电 u_ch = binvar(1, 24); % 充电状态 u_dis = binvar(1, 24); % 放电状态 Constraints = []; % 功率平衡、储能SOC、上下限、互斥等约束依次添加 Constraints = [Constraints, Pbuy >= 0, Pbuy <= Pbuy_max]; % ... 省略中间大量约束写法 Objective = sum(price .* Pbuy) - sum(price_sell .* Psell) ... + sum(C_fuel * Pg) + sum(C_load * Pcut); sol = optimize(Constraints, Objective, sdpsettings('solver','gurobi'));

日内调度则是在这个基础上套了一层循环,外层每15分钟推进一次,内层做当前窗口的优化模型,优化完取第一个时段的决策结果存下来,然后更新SOC状态,进入下一轮。这个滚动循环是整套代码的枢纽,看似简单,但状态变量的传递和初值更新非常容易出bug,我后面会专门讲。

4.3 结果分析:不是画出图就完事了

优化跑完,用Matlab的plot函数画出购电曲线、储能SOC曲线、新能源出力和负荷曲线是基本操作。但作为复现,更重要的是验证结果是否符合物理直觉和预期规律。我的检查顺序一般是这样:先看功率平衡残差,确认每个时段发电、购电、用电都是严格守恒的;然后看储能SOC初值和末值,一个完整日内调度周期SOC首尾偏差不能太大,否则说明存在能量的“凭空产生”;最后看充放电状态序列,确认没有同段充放、没有跨越上下限的功率越界。

如果这三项都通过,复现结果基本可信。如果发现SOC曲线在某个时段突然跳变,别急着调参数,先回去查约束定义是不是漏掉了一行SOC递推。

5. 复现过程中常见的坑与解决实录

5.1 求解器层面的坑

我复现这套代码时踩的第一个坑是YALMIP报出“No suitable solver”错误。原因很简单,机器里装了YALMIP但没装任何求解器,或者装有Gurobi但Matlab找不到它的路径。解决办法是把Gurobi安装目录下的mex文件路径添加到Matlab搜索路径,并在YALMIP里执行yalmiptest验证求解器是否可用。

还有一个很容易踩的坑是求解器性能设置。默认参数下Gurobi求解混合整数规划有时会很慢,原因不是模型太大,而是求解器默认开启了很多冗余策略。实际用的时候可以把求解器输出关掉,设置合理的MIP gap,比如0.05%到1%之间,对大多数调度应用来说已经足够精确,速度却能快一个数量级。

5.2 模型层面的坑

模型层面最经典的bug之一就是储能SOC递推公式里的时间步长系数乘错。日前调度步长是1小时,日内调度步长是0.25小时,如果从日前代码复制到日内时忘记把Δt从1改成0.25,整个日内优化的结果会平庸到让你怀疑人生——储能几乎不动,因为模型认为充一小时才增加一点电量,收益远低于实际预期。

另一个常见问题是约束里变量的维度没对齐。YALMIP对维度不一致通常只是警告,不会直接报错,但你调用求解器后会发现结果莫名其妙,可能某个约束里变量全被赋予了0。遇到这种问题,最直接的办法是逐个约束检查size是否一致。

我还遇到过可中断负荷约束漏写上界,结果优化器为了省成本直接把所有负荷都“中断”掉了,出现全天负荷大幅削减。这种结果在数据上可能严格满足所有约束,但物理上完全不合理。所以运行完一定要检查关键决策变量的上下限有没有被结构性突破。

5.3 问题速查表

现象可能原因排查与解决
求解器报No suitable solverYALMIP未找到Gurobi/Cplex添加求解器路径,执行yalmiptest
求解时间长MIP gap设置过紧调大到0.1%到1%
储能SOC反复跳变SOC递推约束缺失或Δt错误检查递推式,核对日内Δt=0.25
充电放电同时发生缺少互斥约束添加u_ch+u_dis<=1
功率不平衡约束内变量维度不匹配逐个检查size一致
全为0的解目标函数或约束未关联变量检查目标表达式是否引用sdpvar
日前日内曲线严重脱节偏差惩罚系数过小增大惩罚系数或做敏感性分析
日内滚动结果发散SOC初值未用实际值滚动循环内更新SOC初值

5.4 几个值得试一试的扩展方向

如果基础版本已经跑通,我建议可以往两个方向扩展,让这个项目更有深度。一个是把不确定性建模加进去,用场景法或者机会约束替代目前的确定性预测,这样能对比出确定性模型在光伏预测误差大时的局限性。另一个是把需求响应更精细化,比如给可中断负荷添加响应时间约束,模拟工业用户和商业用户不同的响应特性。这些扩展方向每加一个,模型复杂度上一个台阶,但可解释性和工程价值也会明显提升。

我个人在实际操作中的体会是,这种多时间尺度调度模型的复现,最大的收获不在模型本身,而在跑通全流程后对“预测、决策、执行、修正”这个闭环的理解。调度不是算一次就完事,而是动态跟踪和滚动修正的连续过程。如果你只把代码跑通画个图就收手,那这套复现的功力只发挥了三成。真正值得花时间的是把滚动窗口的每一步掰开看,理解每个时段的决策为什么在变、变化是数据驱动的还是模型结构导致的。这套思路吃透以后,不管后面是继续搞微电网优化、储能调度还是参与市场出清,底层逻辑都是通的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询