虚拟电厂多时间尺度调度中的储能衰减建模与Matlab实现
1. 复现这篇SCI之前先把灵活性vs成本这笔账算清楚先说个经历我一直觉得虚拟电厂VPP这块的调度论文尤其是带储能衰减建模的属于看着高端、复现起来全是坑的类型。但前阵子为了研究高比例可再生能源并网下的灵活性供需平衡问题我硬着头皮把这篇顶级SCI的Matlab实现完整复现了一遍。复现完最大的感受是——这篇论文真正的价值不在于数学模型多漂亮而在于它把灵活性和储能成本这对矛盾放到不同时间尺度下去解耦思路非常清晰。高比例可再生能源并网带来的问题做电力的人这几年应该深有体会光伏和风电出力波动大日前预测误差动辄百分之二三十到日内可能又来个气象突变实时运行阶段频率和电压波动更是家常便饭。这时候系统的灵活性指的是什么说白了就是能不能在需要的时间、以需要的速率、提供需要的功率调整量。灵活性不足弃风弃光就来了甚至可能触发切负荷灵活性过度储能装一堆却利用率低下成本全摊在电价里。论文的核心出发点就是用VPP把分布式光伏、风电、储能、柔性负荷聚合起来通过多时间尺度调度去协调谁在什么时间提供灵活性。这里要特别强调一点灵活性不是单时间尺度的概念。日前需要一个小时的调节步长日内需要15分钟的滚动修正实时控制甚至要到分钟级。每个时间尺度的预测精度不一样、决策变量不一样、求解速度要求也不一样。把它们揉到一个模型里去优化要么求解慢得没法用要么精度被平均化。所以这篇论文的第一大亮点就是分层调度架构第二亮点就是把储能衰减成本量化后放进了目标函数——这两件事合起来才真正回答标题里平衡这两个字。我在复现之前把论文读了三四遍又把附录里的参数表反复对照最后才动手写代码。后面我会按模型拆解、衰减建模、调度框架、Matlab实现、仿真验证的顺序把我踩过的坑和最终跑通的做法完整写出来。如果你也是做电力系统优化方向的或者正在复现类似论文这篇文章应该能帮你省下至少两个星期。2. 储能衰减建模为什么一个常数损耗系数带不过去2.1 储能放在VPP里的角色和代价在传统调度模型里储能往往被简化成充放电功率约束 SOC状态转移 容量约束最多再在目标函数里加一个很小的单位充放电成本。这种做法在火电为主体的系统里问题不大因为储能用的少损耗占比小。但在高比例可再生能源并网场景下储能几乎每天都在深度充放电循环次数多、放电深度大衰减速度快得惊人。用一个常数损耗系数去近似会让调度结果严重偏向频繁使用储能——因为模型里储能是零边际成本的调度器当然拼命用它来平抑波动实际运行中电池很快就衰减到需要更换的程度。这篇SCI在这一点上处理得非常聪明它把储能衰减成本和充放电行为直接挂钩核心思想是DOD越大、循环次数越多电池寿命损耗越大。具体实现上用了一个经过实验数据拟合的等效循环寿命模型循环次数与放电深度的关系常见表达式N N_ref × (DOD / DOD_ref)^(-k)其中N是当前放电深度DOD下的最大循环次数N_ref是参考放电深度DOD_ref下的额定循环次数比如电池厂家给的5000次80% DODk是经验指数一般在1.0到2.0之间取决于电池化学体系。锂离子电池通常取1.1~1.5铅酸电池更高。我一开始以为这个公式直接用就行结果发现一个大坑调度模型里的决策变量是每个时段的充放电功率SOC是状态变量而循环次数和放电深度是SOC曲线的统计特征不是单时段决策变量根本没法直接写进优化模型里。论文里用的是等效循环数逼近法把每一次非完整的充放电过程按照电荷吞吐量折算成参考DOD下的等效循环数。2.2 等效循环折算的具体做法逐时段累加的思想可以这么理解假设一个调度周期比如24小时内储能完成了多次不完整的充放电。我们不去精确识别每一次循环而是用累计电荷吞吐量近似等效循环数 总充电能量或放电能量 / 额定容量 × 参考DOD更精细的做法是分段统计检测SOC轨迹中的谷值到峰值为一次充电半循环峰到谷为一次放电半循环然后用雨流计数法提取完整循环。但我用雨流计数法试过放进优化模型里做约束非常困难因为负荷和可再生出力的预测值一更新SOC轨迹就变了雨流结果也跟着变调度循环里根本没法做梯度。所以我最后采用的方式和论文一致用能量吞吐量法近似把衰减成本表示成充放电功率的二次函数或线性函数。具体公式如下C_degrade c_degrade × (P_ch P_dis) × Δt其中c_degrade是等效损耗成本系数单位是元/MWh物理含义是每吞吐单位电量储能寿命折损对应的价值量。这样做的好处是模型线性化MILP可以直接求解。为了得到c_degrade需要先把全生命周期成本折算c_degrade 电池投资成本含更换成本 / 全生命周期等效吞吐量举个例子一套100MWh容量的储能系统投资成本按800元/kWh算总投入8000万元。假设参考DOD80%循环次数5000次则全生命周期等效吞吐量为 100MWh × 0.8 × 5000 400,000 MWh。那么c_degrade 8000万元 / 40万MWh 200元/MWh。这个数字相当可观——但在许多论文里储能的单位充放电成本只给10~20元/MWh两者差了十倍。这就是为什么论文要把衰减成本单独建模它直接影响储能参与调度的意愿。2.3 温度与倍率的修正项要不要加论文里还提到了温度修正系数和充放电倍率修正系数。温度修正用Arrhenius公式近似温度每升高10℃老化速率翻倍锂电在高温段确实如此。倍率修正则是高倍率充放会增加极化损耗加速老化。这两个修正项在理论模型里很完善但复现时我建议先不加——原因是修正系数需要大量实测数据标定不同电池品牌差异极大硬套论文参数只会让结果失真。我的做法是基础衰减成本用吞吐量模型然后在灵敏度分析里单独测试衰减系数±50%变化对调度结果的影响这样既保证了模型可解性又证明了结论对衰减参数不敏感审稿人关心的稳健性问题也覆盖了。这个思路直接用就行不用额外写一堆非线性函数。3. 多时间尺度调度框架日前、日内、实时如何各司其职3.1 为什么非要拆成三个尺度而不是一个超大规模优化这个问题我复现前就想了很久既然计算机够强为什么不用全信息做一次一体化优化理论上完全可以实际操作不行原因有三预测精度的时间不对称性、求解规模的爆炸、运行约束的时效性。先说预测精度。可再生出力的预测误差随预测时长的增加而显著上升。日前预测提前24小时误差可能达到20%以上日内滚动预测提前1小时可以压到10%以内实时超短期预测提前5~15分钟能做到5%以下。一体化模型只能用日前预测数据但日前预测根本没法捕捉下午突然起来的一阵风或一片云结果就是计划跑出来只是纸面最优。再说求解规模。如果把24小时、逐15分钟、考虑上百个分布式单元的完整模型放在一起决策变量轻松超过十万级带整数变量机组启停、储能开关的MILP求解时间可能以小时计。调度系统对计算时间的要求是分钟级甚至秒级。所以论文的分层策略本质上是把时间维度拆开逐层消解不确定性。第三点运行约束的时效性。实时阶段需要对频率偏差、电压波动做快速响应这种秒级-分钟级的控制不可能靠24小时的优化结果直接下发。3.2 日前调度确定基准运行点日前调度的时间分辨率通常是1小时主要任务是在光伏/风电/负荷的日前预测基础上安排各分布式电源的启停计划、储能的充放电计划、VPP与大电网的交换功率计划以及可中断负荷柔性负荷的预签约量。优化目标覆盖运行成本、启停成本、购售电成本、储能衰减成本和弃能惩罚成本。这一层的输出很关键它定下了明天大致怎么运行的基调但不追求执行层面的精确。比如汽车里的导航提前规划好路径和预计到达时间但不会精确到每一秒踩油门还是踩刹车。日前调度的约束主要包括每个时段的功率平衡、机组出力上下限及爬坡约束、储能SOC逐时段递推及上下限、与主网的功率交换上限、备用容量约束。特别注意爬坡约束高比例可再生场景下净负荷负荷减去可再生出力的爬坡率可能非常大如果不约束分布式机组的爬坡能力调度计划在实时执行时根本追不上。3.3 日内滚动修正吃掉中间层的不确定性日内滚动调度的时间窗口一般为未来1~4小时分辨率15分钟每15分钟或30分钟滚动更新一次。它做的事情是利用最新的超短期预测对日前计划进行修正重点调整储能出力、柔性负荷响应量和主网交互功率同时尽量不改变已经敲定的机组启停状态——因为机组启停时间常数大日内改启停代价极高。我在复现时最头疼的是日内模型中如何引入对日前计划的跟踪约束。论文的做法很实用给储能SOC加了一个计划走廊约束即日内SOC不能偏离日前计划的SOC轨迹太远比如±10%这样既保留了储能调节的灵活性又不会让结果跑飞。这个约束在Matlab里写起来很简单就是一个上下限约束但对求解稳定性的帮助极大。3.4 实时优化最后一道防线实时优化阶段分辨率可以到5分钟甚至1分钟覆盖未来15分钟至1小时。由于时间窗短模型可以做适当的线性化甚至把非线性约束简化。这一层主要处理超短期的功率平衡问题储能、需求响应、以及快速启停的小机组是主要调节手段。我自己复现时把实时层做得比较简化——直接用一个经济模型预测控制Economic MPC实现目标函数只关注储能的衰减成本、主网交互成本、弃能惩罚和平衡偏差惩罚。控制周期5分钟预测时域1小时求解速度完全够用。如果你在论文复现阶段实时层不用做太复杂重点是把三层的信息传递和反馈闭环建立起来。下面是三层调度的对比我做了一张表方便你对照搭建模型时间尺度分辨率滚动周期主要决策变量主要预测输入求解频率日前调度1小时24小时窗机组启停、储能计划、购售电计划日前风电/光伏/负荷预测每日一次日内滚动15分钟1~4小时窗储能出力修正、柔性负荷响应、主网修正超短期预测1~4h每15~30分钟实时优化1~5分钟15分钟~1小时储能快速调节、平衡偏差纠正实时量测和超短期预测每1~5分钟三层之间不是孤立运行的而是接力关系。日内层必须把日前计划作为基准实时层必须跟踪日内层的修正结果。用一句话概括就是日前定框架日内纠偏差实时保平衡。这条逻辑线捋顺了代码层面的数据结构就不会乱。4. Matlab代码实现从目标函数到求解器的完整落地方案4.1 整体架构用面向过程的方式先跑通再谈优化很多初学者一上来就想用面向对象把VPP抽象得漂漂亮亮——聚合商是一个类储能是一个类光伏是一个类再搞个调度器类。想法很好但复现一篇SCI时别这么干。论文的算法逻辑是线性的先定义场景数据再建立模型矩阵最后调求解器。用面向过程的方式写能随时对照论文公式排查错误等结果验证通过了再重构也不迟。我最终的Matlab工程包含几个文件main_vpp_sched.m主程序、load_data.m读取场景参数、model_dayahead.m日前模型、model_intraday.m日内模型、model_realtime.m实时模型、battery_model.m储能衰减计算、plot_results.m结果可视化。主程序的逻辑骨架如下%% 主程序: 三阶段协同调度 clear; clc; close all; rng(42); % 固定随机数种子保证结果可复现 % 1. 读入基础数据和预测场景 [grid, pv, wt, load, BESS, DR] load_data(case_study.xlsx); % 2. 日前调度求解 [DAd, DA_result] solve_dayahead(grid, pv, wt, load, BESS, DR); % 3. 日内滚动修正循环 ID_result {}; for t 1:96 % 每隔15分钟一次滚动 [ID_result{t}, BESS] solve_intraday(grid, pv, wt, load, ... BESS, DA_result, t); end % 4. 实时优化15分钟窗口内分钟级 RT_result solve_realtime(grid, pv, wt, load, BESS, ID_result); % 5. 汇总与可视化 plot_results(DA_result, ID_result, RT_result);用Yalmip写模型是最顺的它把优化建模和求解器解耦支持LP、QP、MILP、SDP接口统一。没有Yalmip的先去装一个推荐配Cplex或Gurobi免费的可以用intlinprog代替但大规模整数问题会慢很多。4.2 日前调度的核心代码解析日前模型里最核心的是目标函数构造。下面是简化版的Yalmip代码function result solve_dayahead(grid, pv, wt, load, BESS, DR) % 决策变量 N 24; % 24小时 Pgrid sdpvar(1, N); % 与主网交换功率正买负卖 Pch sdpvar(1, N); % 储能充电功率 Pdis sdpvar(1, N); % 储能放电功率 SOC sdpvar(1, N1); % 储能荷电状态 u_ch binvar(1, N); % 充电状态标志 u_dis binvar(1, N); % 放电状态标志 % 目标函数: 购电成本 运行成本 储能衰减成本 弃能惩罚 Objective 0; for t 1:N % 主网购售电费用购电价与售电价不对称 Objective Objective grid.buy_price(t) * max(Pgrid(t), 0) ... - grid.sell_price(t) * min(Pgrid(t), 0); % 储能衰减成本用放电电量折算 Objective Objective BESS.c_degrade * (Pch(t) Pdis(t)) * grid.dt; % 弃光弃风惩罚 Objective Objective grid.penalty_curtail * ... (pv.avail(t) - pv.use(t) wt.avail(t) - wt.use(t)); end % 约束条件 Constraints []; for t 1:N % 功率平衡 Constraints [Constraints, Pgrid(t) pv.use(t) wt.use(t) Pdis(t) ... load.demand(t) Pch(t) DR.use(t)]; % 储能充放电互斥约束 Constraints [Constraints, Pch(t) 0, Pdis(t) 0]; Constraints [Constraints, Pch(t) BESS.Pmax * u_ch(t)]; Constraints [Constraints, Pdis(t) BESS.Pmax * u_dis(t)]; Constraints [Constraints, u_ch(t) u_dis(t) 1]; % SOC递推: SOC(t1) SOC(t) eta_ch*Pch*dt/Cap - Pdis*dt/(eta_dis*Cap) Constraints [Constraints, SOC(t1) SOC(t) ... BESS.eta_ch * Pch(t) * grid.dt / BESS.cap - ... Pdis(t) * grid.dt / (BESS.eta_dis * BESS.cap)]; end % SOC边界和起止约束 Constraints [Constraints, SOC(1) 0.5]; % 初始SOC Constraints [Constraints, SOC(N1) 0.5]; % 周期末回到初始便于日内/实时复用 Constraints [Constraints, BESS.SOC_min SOC(2:end) BESS.SOC_max]; % 备用约束: 向上/向下备用这里以储能为主 Constraints [Constraints, sum(BESS.Pmax - Pdis) grid.reserve_up]; Constraints [Constraints, sum(Pch BESS.Pmax - BESS.Pmax) grid.reserve_down]; % 简化示意 % 求解 ops sdpsettings(solver, cplex, verbose, 1, showprogress, 0); sol optimize(Constraints, Objective, ops); % 提取结果 result.Pgrid value(Pgrid); result.Pch value(Pch); result.Pdis value(Pdis); result.SOC value(SOC); result.Objective value(Objective); end代码里有两个细节值得特别说明。第一个是max(Pgrid,0)和min(Pgrid,0)这种写法在Yalmip里是非线性的会造成求解器不兼容。正确做法是引入两个非负辅助变量Pbuy和Psell加上约束Pgrid Pbuy - Psell。上面代码是为了展示目标函数逻辑实际建模时一定要拆开。第二个是SOC的终值约束。我一开始没加SOC(N1)0.5结果储能调度倾向在最后一个时段把SOC榨干因为剩下的能量没有价值了。加上这个约束之后结果才跟论文里的趋势对得上。4.3 日内滚动收敛阈值和边界条件处理日内模型跟日前模型的代码结构几乎相同区别在于时间窗和SOC走廊约束。一个容易踩的坑是滚动窗口每次更新时SOC的初始值必须用上一轮求解得到的当前时刻SOC实际值而不是重新给个0.5。这个热启动处理不好滚动修正的效果直接少一半。做法很简单% 滚动窗口更新时传入当前实际SOC if t 1 SOC_init 0.5; % 第一个周期从日前结果或设定值来 else SOC_init SOC_actual(t); % 取上一周期实时反馈值 end另外滚动预测窗内的可再生出力序列是不断更新的每15分钟需要读一次最新的预测接口或预测文件。我在复现时做了一个简化预测误差用高斯噪声模拟从日前预测的20%误差逐步收敛到实时预测的5%。这样既符合论文场景又避开了真实预测系统接口对接的复杂度。4.4 求解器选型和计算时长实测数据我用一个包含30台分布式电源、5套储能、10组柔性负荷的测试系统在笔记本上i7-12700H16GB内存跑完24小时的完整三阶段仿真耗时对比如下求解器日前调度24h整型日内滚动96轮×1h窗实时优化288轮×15min窗总计Cplex MILP8秒约90秒约30秒约2分钟Gurobi MILP5秒约70秒约25秒约1分40秒intlinprog30秒约300秒约80秒约7分钟实测下来intlinprog也能跑但规模一旦扩大比如100个节点速度差距会非常明显。建议学生党至少安装一个Gurobi的学术许可证免费且安装简单。5. 仿真结果怎么看不只看成本下降了多少5.1 三个关键结果的对比维度论文复现完成后仿真结果需要从三个维度去验证成本构成变化、SOC运行轨迹、灵活性指标备用容量和爬坡能力。成本构成是最直观的。我在相同可再生渗透率下对比了含衰减建模与不含衰减建模两组实验发现一个有意思的现象包含衰减成本后系统总运行成本反而可能上升但全生命周期成本加上储能更换费用会显著下降。这正是平衡灵活性与储能成本的含义——牺牲一点短期运行经济性换来系统长期投资的降本。图表上体现为储能的充放电循环次数大幅减少深度充放电DOD80%的占比明显下降。SOC轨迹方面含衰减建模的调度结果中SOC很少冲到0.9以上或跌到0.2以下因为深度充放电会被惩罚成本抑制。这个特征非常容易在图上看到也是论文对比仿真中最有说服力的那一幕。灵活性指标方面要关注系统在面对预测误差时的调节能力。我算了一个灵活性不足期望指标在实时阶段如果系统无法平衡净负荷偏差就记一次灵活性不足事件。结果证实多时间尺度协调能明显降低灵活性缺额尤其在爬坡需求大的清晨和傍晚时段。5.2 参数敏感性衰减系数、储能容量、预测误差哪个影响最大做灵敏度分析是论文复现的必备环节。我用控制变量法逐个测试了以下参数变化对总成本和灵活性缺额的影响储能衰减成本系数从150元/MWh到400元/MWh步长50储能容量配置从额定容量的0.5倍到2倍可再生预测误差标准差从5%到25%储能充放电效率从85%到95%结果表明衰减系数影响最大的是储能出力曲线形状和循环次数预测误差影响最大的是日内和实时阶段的平衡偏差以及由此产生的惩罚成本储能容量则直接影响系统灵活性的上限。有意思的是当衰减系数增大到一定程度后总成本增速放缓——说明系统已经通过调整运行策略来规避衰减损失。我把典型实验结果整理成一张小表场景储能循环次数日均总运行成本万元/日灵活性缺额事件次/日不含衰减建模2.8次25.62含衰减建模基准参数1.4次27.11衰减系数×1.50.9次28.31预测误差≤10%1.2次26.20储能容量×1.50.8次25.80这张表基本复现了论文的核心结论衰减建模促使储能少而精地参与调节预测误差压缩则直接减少灵活性缺额。复现到这个程度这篇SCI的数学内核就算是真正吃透了。6. 写在最后的实操建议哪些坑值得绕开哪些简化可以大胆做这篇论文复现下来我的总体评价是数学不复杂工程细节多非常适合作为电力系统多时间尺度调度的入门级复现对象。但以下几个坑我必须单独拎出来说每一个我都栽过跟头。第一SOC终值约束不要漏。不加这个约束调度结果会利用优化漏洞把储能能量在周期末清空仿真出来的成本虚低灵活性指标也失真。更稳的做法是加入循环周期之间的SOC连续性衔接。第二衰减成本的线性化要提前做。论文里如果用的是非线性衰减模型你要想清楚是改用吞吐量线性模型还是用分段线性近似。千万别直接在Yalmip里写N N_ref * (DOD/DOD_ref)^(-k)这种式子因为DOD是SOC变量的函数这里既有非线性又有非凸性求解器根本啃不动。第三日内滚动仿真的时间同步问题。很多人跑滚动调度时把窗口平移做得不对导致同一个预测数据被重复使用或者时间索引错位。建议先用一个确定性场景无预测误差验证滚动结果与日前结果一致再引入不确定性。这个验证手段能快速定位代码逻辑bug。第四可视化的价值被低估了。至少要画三张图日前SOC计划轨迹、日内滚动修正后的实际SOC轨迹、实时阶段的功率平衡堆叠图。这三张图画出来论文里的调度逻辑一目了然答辩或写报告时也省去大量解释工作。第五也是我对所有复现论文的人的建议不要只复现代码跑通一定要复现论文图表。每张图、每张表都试着自己从结果里画出来跟原文对比。那些看起来无足轻重的对比实验其实是理解作者建模动机的最佳方式。这篇论文的图表不算多但每一张都对应一个明确的结论值得逐一还原。如果你打算用这篇论文的思路做进一步扩展我建议往这两个方向试一是把衰减模型从能量吞吐量升级到电化学状态估计用更细的SOC区间分段统计循环深度二是把多时间尺度调度和电力市场出清模型对接让VPP参与到现货市场的日前、日内交易中。这两个方向都有期刊论文在探索从复现到改进的路径相对平滑。我自己的下一步计划是把这个模型移植到实测数据上用某工业园区微网的负荷和屋顶光伏数据做实例验证到时候再整理一篇实操笔记分享。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →