虚拟电厂多时间尺度调度建模:储能衰减成本与Matlab实现
发布时间:2026/10/1 18:55:48来源:尧图网络
我是在帮课题组复现一篇虚拟电厂调度的SCI论文时才真正理解“高比例可再生能源并网”和“储能成本”之间的那笔账。白天光伏出力冲到峰值下午四五点又直线跌落净负荷曲线被挤成一只张着大嘴的鸭子。储能是该拿来填谷、压峰还是留着应对更严重的爬坡每次充放电都在消耗电池寿命优化器如果看不见这笔折旧最后算出来的调度方案就是空中楼阁。这篇博客把我在Matlab里复现多时间尺度调度模型的过程、公式和踩过的坑完整铺开涉及虚拟电厂的核心逻辑、储能衰减建模的处理以及Gurobi/Yalmip求解的实现细节。1. 净负荷曲线的“鸭型”困境与虚拟电厂的角色1.1 净负荷曲线可再生能源并网的第一道坎在传统电网里调度员只需要盯着负荷曲线火电、水电跟着负荷走就行。可再生能源一上来情况就变了。电网真正需要平衡的对象不再是负荷而是“净负荷”也就是负荷减去风电、光伏出力之后剩下的那个值。一个简单算例就能说明问题。假设某区域日负荷峰值40MW夜间低谷25MW光伏在中午12点到14点出力冲到20MW此时净负荷被压到5MW以下傍晚18点光伏出力归零而负荷正值晚高峰净负荷瞬间反弹到40MW。整个曲线在午间塌下去傍晚又陡峭抬升就是电网人常说的“鸭子曲线”。这条曲线给调度带来的麻烦集中在两点一是午间净负荷太低常规机组不能随便停机停了晚高峰就爬不上来只能压着最低出力硬扛二是傍晚爬坡速率极快传统机组从低出力往上爬的速度有限一旦跟不上就需要别的资源顶上。高比例可再生能源并网之后这个爬坡缺口会被急剧放大单纯依靠火电调峰已经不够用了。1.2 虚拟电厂如何“组装”分散资源虚拟电厂VPP解决的正是“分散资源难以直接参与调度”的问题。它把分布式光伏、用户侧储能、可控负荷、电动汽车充电桩这类小散资源聚合起来通过统一的协调控制对外呈现出一个可控电源的特性。打个比方一堆散户手里的散钱凑不成一笔能参与大额投资的资金虚拟电厂就是那个“资金池”它负责把零钱归集、风控、分配最后以一个大额投资人的身份进场。在调度模型里虚拟电厂对外只需提供一条聚合后的净出力曲线对内则要拆解到每台储能、每个负荷节点。这个“对外一个接口、对内多种资源”的结构正是建模的关键。聚合资源越多虚拟电厂的调节能力越强但协调复杂度也指数上升。1.3 灵活性需求的三副面孔说到灵活性很多人第一反应是“能多发电”其实电力系统调度语境下的灵活性有三个完全不同的维度经常被混为一谈灵活性类型对应问题典型时间尺度主要资源爬坡灵活性净负荷快速上升/下降分钟到小时储能、燃气机组、可中断负荷调峰灵活性净负荷谷底/峰顶的调节幅度小时到日储能、水火电机组、需求响应备用灵活性预测误差导致的功率缺口秒到分钟储能、旋转备用、AGC高比例可再生能源并网之后最稀缺的不再是电量而是“在特定时间段内快速改变出力”的能力。储能之所以在虚拟电厂中占据核心位置就是因为它同时具备三个维度的调节能力爬坡快、调节幅度大、响应速度快。但储能是贵资产不能不计成本地用。2. 多时间尺度调度框架日前-日内-实时如何分工2.1 为什么单一时间尺度不够如果把调度问题简化成“一个24小时的优化模型”直接求解理论上也能得到结果但实际运行中一定会出问题。原因在于预测精度光伏和风电出力预测是分层的提前24小时的预测误差通常在15%到25%提前4小时的超短期预测能压到5%到10%而分钟级实时预测的误差基本可以控制在3%以内。如果只用日前预测做决策一旦实际光伏比预测少发聚合出力就会和电网需求产生偏差如果只做实时调度又看不到未来几个小时的趋势容易做出“只救眼前火、不顾身后洪水”的短视决策。多时间尺度调度的本质是“用不同精度的信息在不同决策时间点上做不同程度的承诺”。前一天先定基调日内不断修正实时最后一公里兜底。2.2 日前调度先把基调定下来日前调度通常以15分钟为一个时段全天96个时段。输入数据包括新能源出力预测、负荷预测、分时电价、储能初始SOC、机组技术参数。决策内容主要包括储能各时段充放电计划、虚拟电厂聚合后的对外出力曲线、购电计划、以及是否需要弃风弃光。这个层面的模型追求的是全局经济性计算规模不算大用混合整数线性规划MILP就能处理Gurobi或Cplex求解通常几秒到几十秒内完成。日前调度的输出不会完全执行它更像是一个“契约”告诉电网调度员这个虚拟电厂明天打算怎么出力让电网有底气安排其他机组。2.3 日内滚动用新数据修正旧方案日内滚动优化的核心操作是“滚动时域”。普遍做法是每隔15分钟触发一次重新优化每次优化只对未来4小时做计划但只执行下一个15分钟的决策。到了下一个触发点用最新的超短期预测数据再重新算一遍。这个“滚动-执行-再滚动”的模式目的是把预测误差的影响控制在最小。即便日前预测说下午光伏有20MW出力实际到下午发现云层很厚日内层就会重新调整储能和购电计划让虚拟电厂的实际出力尽量贴近电网需求。在代码实现上日内层和日前层用的是同一套模型只是预测数据更新了、优化时域缩短了。差别最大的一点在于SOC基准日内优化不能完全无视日前计划里的SOC轨迹否则会出现“日内拼命放电、夜里无电可用”的短视行为。2.4 实时层最后一公里修正实时层通常对应秒级到分钟级的自动发电控制AGC或实时经济调度。这一层不需要做复杂的预测也不需要重新优化未来几个时段它的职责是“盯着实际值和计划值的偏差随时微调”。虚拟电厂的实时控制逻辑可以设定为跟踪日内层给出的聚合出力指令储能承担高频波动可控负荷承担低频调节。偏差大了才调整策略偏差小就保持不动避免设备频繁动作。2.5 时间尺度衔接的关键状态变量传递三个时间尺度之间的衔接不是简单的“接力跑”而是要通过状态变量把前后方案“缝”起来。最重要的状态变量就是储能SOC。我在复现时发现一个典型问题日内层如果不参考日前层的SOC计划完全自由优化结果往往是凌晨把电池充满白天再全部放光因为实时电价信号驱动它这么做。但这和日前安排的大相径庭储能循环次数明显增加衰减成本飙升。解决办法是在日内优化中加入“SOC轨迹走廊”约束日内决策的SOC可以偏离日前计划但不能超过预设的上下界比如允许偏离5个百分点。这样既保留了日内修正空间又不至于让长期计划完全失效。这个处理方式在后来的多组算例里都验证可行强烈建议复现时加上。3. 储能衰减建模从“损耗”到“成本”的关键一跃3.1 不建模的代价优化器会把储能往死里用很多初版模型在处理储能时只写一个SOC递推方程和充放电功率约束目标函数里完全没有电池老化成本。这样优化器眼中的储能就是一个“免费的调节工具”——不用白不用白天充、晚上放遇到爬坡需求更是疯狂出力。但现实中锂电池是有寿命的。容量衰减到80%左右就认为寿命终止需要更换电池这笔更换成本动辄千万甚至上亿。如果不把衰减成本量化进目标函数优化结果必然是“储能过劳死”从全生命周期看反而是亏本运营。3.2 衰减模型选型从简单到复杂储能衰减建模有三条路线可选模型类型原理适合场景计算复杂度固定损耗模型每次充放电按固定系数扣成本教学演示、粗略估算低基于DOD的半经验模型循环寿命与放电深度呈幂函数关系调度优化主选中电化学模型如SEI膜生长从机理上描述老化过程电池设计、寿命预测高不适合在线优化调度优化里最实用的就是半经验模型核心公式是一条幂函数N(DOD) a × DOD^(-b)其中N(DOD)表示在放电深度DOD下能完成的循环次数a和b是由电池实测数据拟合出的系数。以某磷酸铁锂电池为例100% DOD对应循环寿命3000次50% DOD对应8000次20% DOD对应20000次。拟合出的b通常在0.8到1.2之间。这个公式的含义很直观浅充浅放的损耗远小于深充深放。优化器如果能感知到这条曲线就会自动倾向于浅充浅放的策略而不是每次都把电池榨干。3.3 雨流计数法把SOC曲线折算成等效循环优化模型里每次计算得到的是一条SOC时间曲线怎么把这条曲线转换成“多少次循环、多深的DOD”工程实践里最常用的方法是雨流计数法。雨流计数法原本用于材料疲劳寿命分析后来被直接搬到了电池SOC曲线分析里。它的基本步骤可以概括为取SOC序列的极值点把相邻的“充电半循环”和“放电半循环”配对成一个完整循环统计每个循环的深度和次数。举个例子某储能在一天内的SOC序列是50%→85%→40%→75%→30%。雨流计数会把85%→40%和50%→85%配成深度45%和35%的两个半循环再把75%→30%和40%→75%配成另一个完整循环。最终折算成若干个深度不同的循环再按寿命曲线换算成等效满循环次数。在Matlab复现中不需要自己从零实现完整的雨流计数算法可以直接调用第三方函数或者用一个简化的替代方案按充放电切换点划分循环并把深度折算到统一基准。我的经验是如果优化的目标是运行成本而非电池寿命精确预测简化折算完全够用。3.4 衰减成本怎么写进目标函数把衰减成本写入目标函数最直接的化简方式是“按放电电量折算”C_deg K_deg × E_dis其中E_dis是储能放电量K_deg是单位放电量的衰减成本计算公式为K_deg C_replace / (E_cap × N_full)以一套100MWh储能系统为例更换成本1亿元满循环寿命3000次那么K_deg 100000000 / (100 × 3000) 333元/MWh也就是0.333元/kWh。这个值非常关键。峰谷电价差若是0.6元/kWh扣除充放电效率损失后储能套利空间还剩约0.35元/kWh再扣衰减成本就几乎不剩利润。如果把衰减成本写进模型优化器会明显减少不必要的深度循环而如果不写优化器会得出“疯狂充放”的乐观方案。在实际建模中我遇到一个细节问题按放电电量乘以固定系数本质上假设衰减和DOD无关这和半经验模型的结论矛盾。更精细的做法是在目标函数里对充放电循环深度做分段线性惩罚DOD越深单位惩罚越大。这样优化器会在重惩罚下自动避免深循环。但这种做法会让模型从线性变成混合整数求解难度上升不少需要根据项目需求权衡。4. 灵活性与储能成本的平衡机制目标函数里的博弈4.1 目标函数里的四笔账虚拟电厂调度模型的完整目标函数通常包含四部分min F F_buy F_curtail F_om F_deg其中F_buy是向电网购电的费用按分时电价结算F_curtail是弃风弃光惩罚代表新能源浪费带来的损失F_om是储能运行维护成本通常按充放电量线性计费F_deg就是上一节提到的衰减成本。在Matlab里用Yalmip表达这四笔账非常自然前三笔是线性项第四笔如果是按放电电量线性折算依然可以保持线性模型。整个目标函数就是一个线性规划LP或混合整数线性规划MILP求解速度快完全满足日前调度的时效要求。4.2 约束条件怎么把灵活性“钉”进模型灵活性不是一句口号最终要落成具体约束。我在代码里最核心的约束有四类一是功率平衡约束虚拟电厂对外出力加上购电功率等于负荷减去新能源出力再减去弃电二是储能动态约束SOC递推方程必须严格成立三是爬坡约束虚拟电厂聚合出力在两个相邻时段之间的变化量不能超过设定的爬坡上限四是备用约束要求储能保留一定可用容量以应对突发预测偏差。爬坡约束是体现“灵活性”的最直接约束。如果虚拟电厂向电网承诺了每分钟2MW的爬坡能力那么优化结果就必须保证每15分钟内出力变化不超过30MW。这个约束会给储能分配“爬坡任务”让它为整个聚合体兜底。4.3 一个具体决策场景充还是弃灵活性和储能成本的博弈在“午间光伏大发、净负荷极低”的场景中体现得最典型。此时有两个选择给储能充电以消纳多余光伏或者直接弃掉一部分光伏。怎么选假设午间弃电惩罚为0.5元/kWh储能放电的衰减成本是0.333元/kWh充电本身不直接产生衰减成本。如果光伏电价折算下来只有0.25元/kWh那么把电量存下来留到晚间释放晚间省下的购电成本是0.8元/kWh。从全时段看放电收益0.8元减去衰减成本0.333元减去充电时的机会成本依然有利润所以应该充。反过来如果储能衰减成本上升到0.6元/kWh放电边际收益变成0.8元减0.6元等于0.2元还要考虑能量损失很可能不如直接弃电划算。这就是模型里“充还是弃”的天然开关一切由成本和惩罚的数值比较决定而不是人工拍脑袋定策略。4.4 不同权重下的行为变化我在复现时做了两组对照实验一组目标函数里不含衰减成本另一组包含衰减成本。结果显示无衰减成本时储能全年等效满循环次数达到450次左右储能利用率看着很高加上衰减成本后等效循环次数降到260次左右但系统总成本反而下降了约9%。原因很简单多了电池更换成本这层约束后优化器大幅减少了低收益的浅循环套利只保留真正划算的峰谷转移和爬坡支撑整体经济性反而更好。这个结果充分说明衰减建模不是让储能“少干活”而是让储能“干有价值的活”。5. Matlab复现代码架构与关键实现5.1 YalmipGurobi的选型逻辑Matlab里做优化建模我首推Yalmip工具箱加Gurobi求解器的组合。Yalmip负责建模Gurobi负责求解两者接合流畅支持LP、QP、MILP、MIQP等多种问题类型。相比直接用linprog或者intlinprog一个矩阵一个矩阵地手写约束Yalmip的代码可读性和修改效率都高出好几个量级。Gurobi的学术许可是免费申请的个人复现完全够用。如果拿不到GurobiCplex也是同级别的替代方案两者在Yalmip里的调用方式几乎一致只需要改一行求解器设置。5.2 数据与参数准备建模之前先把下面的参数表准备好能省很多调试时间参数数值说明N96日前调度时段数15分钟一个时段E_cap100 MWh储能容量SOC_min / SOC_max0.2 / 0.9荷电状态上下限P_ch_max / P_dis_max20 MW充放电功率上限eta_ch / eta_dis0.95 / 0.95充放电效率C_replace1×10^8 元电池更换成本N_full3000满循环寿命Price分时电价序列(96)购电价P_load / P_re负荷/新能源预测序列长度为N的向量这些数据可以直接用Matlab脚本生成一组模拟值也可以读入实际系统数据。推荐先用模拟数据把代码跑通再接真实数据验证。5.3 核心代码目标函数、约束与求解下面是我复现日前调度层的核心代码骨架可以直接拿去做对照修改%% 参数定义 N 96; E_cap 100; P_ch_max 20; P_dis_max 20; eta_ch 0.95; eta_dis 0.95; SOC_min 0.2; SOC_max 0.9; SOC_init 0.5; C_curtail 500; % 弃电惩罚元/MWh C_om 10; % 运行维护成本元/MWh C_replace 1e8; N_full 3000; K_deg C_replace / (E_cap * N_full); % 元/MWh % 模拟数据负荷、新能源出力、分时电价 P_load 20 15 * sin(linspace(0, 2*pi, N)).^2 randn(1, N) * 2; P_re 12 * max(0, sin(linspace(0, 2*pi, N) - pi/2)).^3 randn(1, N) * 0.5; Price 200 300 * (P_load 28) - 100 * (P_load 22); %% 决策变量 P_ch sdpvar(1, N, full); % 储能充电功率 P_dis sdpvar(1, N, full); % 储能放电功率 SOC sdpvar(1, N 1, full); % SOC轨迹 P_grid sdpvar(1, N, full); % 购电功率 P_curtail sdpvar(1, N, full);% 弃电功率 %% 目标函数 obj sum(Price .* P_grid) / 1000 ... C_curtail * sum(P_curtail) / 1000 ... C_om * sum(P_ch P_dis) / 1000 ... K_deg * sum(P_dis) / 1000; %% 约束条件 Constraints []; % 功率平衡负荷 新能源 储能净出力 购电 - 弃电 Constraints [Constraints, P_load - P_re - P_dis P_ch - P_grid P_curtail 0]; % 储能动态 SOC(1) SOC_init; for t 1:N Constraints [Constraints, SOC(t 1) SOC(t) eta_ch * P_ch(t) / E_cap - P_dis(t) / (eta_dis * E_cap)]; Constraints [Constraints, 0 P_ch(t) P_ch_max]; Constraints [Constraints, 0 P_dis(t) P_dis_max]; Constraints [Constraints, SOC_min SOC(t 1) SOC_max]; end % 充放电互斥可选通过二进制变量或直接放宽 % 本模型允许同时充放电但由于目标函数成本项优化器不会无意义地同时充放 %% 求解 ops sdpsettings(solver, gurobi, verbose, 0); sol optimize(Constraints, obj, ops);这段代码里的目标函数最后一项K_deg乘的是放电功率代表储能衰减成本只按放电电量折算。这个处理方式抓住了衰减和吞吐量之间的主线性关系又能保持模型为线性规划求解效率很高。如果要让模型更精细可以把SOC(t1)-SOC(t)的差分解构出DOD和循环次数再写入惩罚项但那样就需要引入整数变量来表示循环配对模型复杂度会急剧上升。我的建议是主程序用线性近似论文需要精细曲线时再用雨流计数后处理校准。5.4 结果可视化的几个模板调度结果出来后可视化是判断模型是否合理的最快方式。推荐画三张图聚合功率平衡图、储能SOC曲线图、分时电价与购电功率对比图。示例代码figure; subplot(3, 1, 1); plot(value(P_load), k-, LineWidth, 1.2); hold on; plot(value(P_re), b--); plot(value(P_grid), r-); legend(负荷, 新能源出力, 购电功率); grid on; subplot(3, 1, 2); stairs(0:N, value(SOC), g-); ylabel(SOC); ylim([0 1]); grid on; subplot(3, 1, 3); stairs(Price, m-); ylabel(电价); grid on;脱硫而不是脱负荷。看到SOC曲线如果出现频繁的满充满放说明衰减成本权重不够如果SOC几乎不动说明成本权重过大需要检查K_deg的数值是否偏离实际。6. 复现路上踩过的坑和我的一点心得6.1 衰减系数调不出来储能要么罢工要么过劳第一次加入衰减成本时我把K_deg直接设成0.5元/kWh结果优化器让储能几乎完全闲置。原因很简单这个成本接近甚至超过了峰谷套利空间储能每次动作都在亏钱最好的策略自然是不动作。后来换了一个思路先用不含衰减成本的模型跑一遍统计储能的充放电量和等效循环次数再用更换成本反推平均单位放电成本得到一个“让储能保持合理使用强度”的系数。这个系数比拍脑袋设出来的值更贴合实际也更让人信服。6.2 日前/日内SOC衔接导致无解日内滚动优化中我最初没有给SOC轨迹加走廊约束运行到下午时段经常出现“储能SOC无可行解”的情况。原因是日前计划预计午间充了大量光伏电量但日内实际光伏比预期少SOC达不到日前计划的水平可日内目标又执着地要求维持原有SOC轨迹于是模型直接无解。解决办法是以日前计划SOC为基点设置±5个百分点的缓冲范围允许日内决策在这个走廊里自由调整而不是钉死在某条轨迹上。加了这条约束之后连续滚动720个时段3天没有再出现无解情况。6.3 求解器版本与非线性约束的坑Yalmip对Gurobi版本很敏感。我在一台老机器上用的是Gurobi 9.5后来换到Gurobi 10Yalmip自动识别没问题但一些老脚本里的求解器参数设置会报warnings。建议复现之前先确认Yalmip和Gurobi版本匹配直接用最新版的Yalmip是最稳妥的选择。另外要特别提醒目标函数里如果写了数组和数组相乘Yalmip有时会自动引入非线性项导致模型变成二次规划甚至更复杂的问题。我在调试时遇到过一次求解时间从3秒暴增到200秒的情况最后发现是Price和P_grid的维度对不上Matlab自动进行了隐式扩展引入了本不该存在的二次项。处理方法是严格保持所有变量维度一致或者在关键位置加size检查。6.4 这个模型的真正价值在哪跑完整个复现后我的体会是虚拟电厂多时间尺度调度模型的最大价值不是给出某一天的最佳充放电计划而是提供了一个“定量讨论权衡”的框架。比如电网公司想知道“如果储能衰减成本是X虚拟电厂愿意提供多快的爬坡能力”不再需要拍脑袋调整一下衰减惩罚系数重新求解就能得到答案。新能源场站想知道“弃电惩罚提高到多少储能才愿意消纳这部分电量”同样可以通过灵敏度分析直接算出来。这套框架把“灵活性”从定性口号变成了可优化、可折现、可比较的量化指标这也是它在工程和学术两端都能站住脚的根本原因。如果让我再做一次我会把电价预测的不确定性也建模进日内层用场景法或者鲁棒优化的思路处理。目前的模型里电价是确定性输入这在现货市场环境下还不够真实。不过那是下一步的扩展方向了把眼前这套复现跑通、把关键参数吃透已经够在项目里稳稳立足。
网站建设高端定制企业官网