ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

虚拟电厂多时间尺度调度与储能衰减建模的Matlab实现

虚拟电厂多时间尺度调度与储能衰减建模的Matlab实现 做电力系统优化这两年我最大的感受是可再生能源装机比例一上去调度问题就从传统的“经济负荷分配”变成了“在不确定性里找平衡”。这篇SCI复现项目的核心就是前几天复现的一篇关于虚拟电厂多时间尺度调度的文章标题原文我记不太清了大意是高比例可再生能源并网下怎么平衡灵活性与储能成本作者把虚拟电厂的多时间尺度调度和储能衰减建模放到一起做Matlab代码复现。这篇博文就围绕这个题目展开把框架、模型、代码实现和踩坑记录都摊开来讲希望能给正在做虚拟电厂、储能调度或者多时间尺度优化方向的朋友一些可直接参考的思路。先说结论这套方案的核心并非复杂的智能算法而是一个结构清晰的三层优化框架——日前调度定基调日内滚动做修正实时层兜底处理偏差。储能衰减建模看起来是锦上添花但实际上才是让调度结果具备工程意义的关键忽略衰减的调度策略在仿真里很漂亮放到实际项目里跑几个月就容易把电池搞报废。下面按我的复现过程详细说。1. 为什么要做“多时间尺度”虚拟电厂调度1.1 高比例可再生能源带来的调度困境风电和光伏出力有几个特点波动大、难预测、反调峰。尤其是光伏白天出力猛傍晚骤降正好撞上晚高峰负荷爬升净负荷曲线会形成一个经典的“鸭子曲线”。这种情况下如果还是用传统单时间尺度的日前调度靠晚间一次优化结果硬扛全天那当天内风光出力剧烈波动时系统只能靠火电深度调峰和切负荷来应对既不经济也不安全。我在复现时做过一个对比在同样的风光出力数据和负荷数据下只做日前调度24小时、1小时间隔加上实时不做修正系统在下午光照骤降时段需要调用约12%的额外备用容量而如果预留了这么大的备用日前就必须少报计划出力经济性明显受损。这不是数据特殊而是预测误差的客观存在。日前预测的风速和光照强度到了临近时刻往往偏差很大功率预测误差随预测时长增加几乎是线性扩大。所以多时间尺度调度的本质逻辑是预测精度随时间的临近而提高那么决策也应该是分层的。可以在日前用粗糙一点的预测做长周期计划比如储能的充放电窗口、机组的启停安排等到日内用更新的预测滚动修正调整各资源的出力计划再到实时层用秒级到分钟级的响应去处理残差。1.2 虚拟电厂如何提升系统灵活性虚拟电厂并不是一个物理电厂而是一个聚合管理平台。它把分散的分布式光伏、风电、储能、柔性负荷、电动汽车充电桩等资源聚合成一个“虚拟机组”参与电网调度。对电网调度中心来说VPP就是一个可以下发指令的电源或负荷内部资源怎么协调是VPP自己的事情。这种架构的好处在于单体资源容量小、分布零散、行为随机电网没精力也办法直接调度每一台空调、每一块光伏板。但是聚合起来以后它们的总容量、可调范围、爬坡能力都有了明显的规模效应而且不同类型资源之间还有互补性。比如光伏出力大的中午储能可以充电、柔性负荷可以平移消纳多余电力晚间光伏骤降时储能放电、电动汽车反向送电配合火电快速爬坡正好补上缺口。VPP内部的资源类型越丰富灵活性就越好。我在代码里把资源抽象成了三类可调度电源燃气轮机或柴油机、储能系统、柔性负荷外加不可调度的风光作为净负荷修正项。这样的抽象既保留了主要矛盾又不至于让模型复杂到无法求解。1.3 单时间尺度模型为什么不够用这个问题值得展开说。很多人一开始做VPP调度都是单层优化比如只做日前经济调度把风光预测误差放到约束里预留10%的备用就完事。这个做法简单但有几个毛病。第一备用比例拍脑袋定保守了浪费灵活性资源冒进了又约束不住实时偏差。第二储能日前确定的充放电计划到了日内发现风光实际出力跟预测差很多却要等到明天才能重新优化储能没法在日内响应灵活性就废了。第三柔性负荷、电动汽车这类资源日内响应特性和日前不尽相同单尺度模型很难体现这种时间耦合特性。多时间尺度调度实际上是把“预测—决策—执行—反馈”做成一个闭环预测越准越靠近实时决策也就越精准。用一个不恰当的类比出差前做旅行计划要看天气预报安排行李出发前再看一次实时天气调整穿衣到了现场发现下雨再就近买伞。层层递进合理分工比出发前拍一次板要稳健得多。2. 调度模型与储能衰减建模的核心步骤2.1 目标函数让灵活性和成本在同一框架里对话目标函数的设计直接决定调度策略的“性格”。我复现的模型把总成本拆成了四块从上级电网购电的成本分时电价储能退化折算成本弃风弃光的惩罚成本切负荷/需求响应的惩罚成本。灵活性和储能成本在这里是一对矛盾要灵活性高就需要储能多充多放、机组多调节结果储能循环寿命加速衰减、机组磨损加大要储能成本低就得限制储能出力系统灵活性不足弃风和切负荷风险上升。目标函数就是在这个此消彼长之间找到平衡点。购买电网电力的成本比较直观按各时段电价乘功率累加。弃风弃光的惩罚系数通常设得较高因为可再生能源的边际成本几乎为零弃掉意味着资源浪费。切负荷惩罚就更高了一般不希望出现。储能退化成本是个关键。如果不单独建衰减模型优化器会把储能当免费资源安排它频繁大幅充放电结果就是调度计划非常漂亮但实际运行中电池寿命迅速衰减。这就好比租车随便踩油门油耗和车辆损耗都不用自己管跑得爽是爽回头算总账才发现亏大了。2.2 多时间尺度框架日前—日内—实时三层结构整个调度框架分为三个层级各层的时间分辨率和预测长度不同信息逐层传递、修正日前调度层时间分辨率1小时优化周期24小时。系统根据日前预测负荷、风光、电价确定机组启停、储能充放电长周期策略、可调负荷的启停时段、向上/向下备用安排。这一层不追求实时精度而是保证整体经济性和资源的大方向安排。日内滚动调度层每1~4小时滚动执行一次优化周期4~6小时时间分辨率15分钟。系统读取更新的超短期预测对日前计划进行修正。比如日前安排储能13点充电但12点实际预测光照比预期弱那么日内层就会调整充电功率或者延迟充电时段。实时修正层时间分辨率5分钟甚至1分钟负责弥补短期预测误差和实际执行误差。根据系统频率、联络线功率偏差调用响应速度快的资源储能、柔性负荷、AGC机组进行微调。我在Matlab代码里实现了前两个层级实时层用了一个简化版的功率平衡修正来模拟。三层结构的关键在于层间传递的信息日前层输出各时段计划值作为日内层的基础日内层输出修正量实时层只做偏差的二次调整。2.3 储能衰减建模从寿命曲线到调度约束储能衰减建模是这个项目里最有价值的部分也是大多数复现版本里被省略掉的部分。常见的电池寿命模型分几类循环周期计数法把充放电拆成等效循环、吞吐量法按累计充放电量折算寿命损耗、半经验老化模型考虑温度、SOC、放电深度的影响。考虑到论文复现时的计算规模和控制变量我采用的是基于放电深度DOD和循环寿命的折算方法这是工程上常用的折中方案。锂电池的循环寿命跟放电深度强相关满充满放100% DOD循环次数可能只有2000~3000次如果每次只放20%深度循环次数可以增加到上万次。这个关系可以用厂家数据拟合也可以用常用的近似公式。在调度模型中储能每一次充放电都需要计算对应的等效循环损耗再把损耗折算成成本。实现方式是定义循环寿命与DOD的关系曲线把每次充放电“折成”等效的100% DOD循环次数。电池的总寿命折算成本再按等效循环分配。这里有个数学处理的小技巧分段线性化。原始寿命曲线是高度非线性的直接用非线性规划求解很慢而且容易陷入局部最优。为了嵌入MILP我需要把它做分段线性逼近用几条直线段近似DOD与循环寿命的关系变量增加很多但求解速度依然比非线性求解器快得多。2.4 灵活性指标的量化和约束化灵活性不是个模糊概念在模型里需要变成可计算的数学表达式。常用的灵活性度量指标包括调节容量可上调/下调的空间、爬坡能力、响应时间、持续时间。在多时间尺度调度里不同时间尺度对灵活性的要求不同。我在约束里做了两件事。第一设置向上/向下备用约束备用容量至少覆盖该尺度净负荷预测误差的一定比例。日前尺度因为预测误差大备用系数设得高日内和实时尺度预测误差小了备用系数可以适当调低。第二对机组和储能的爬坡能力进行约束确保每15分钟或每小时的功率变化量在物理限制内。灵活性需求的动态化很重要。净负荷波动大的时段傍晚光伏衰减高峰期备用需求自动调高深夜间负荷平稳时备用需求降低。如果全时段都用同一个备用系数就会在低风险时段过度约束白白损失经济性。3. Matlab代码实现与关键环节解析3.1 数据结构与输入参数准备代码的第一步是构建输入数据。我用的典型场景包括24小时负荷曲线、风光预测出力区分日前和日内两组数据、分时电价、储能参数、可调度机组参数、柔性负荷的可平移区间。关键参数表如下参数数值示例说明储能额定容量2 MWh满充状态可用能量储能最大充/放电功率0.5 MW受PCS限制储能初始SOC0.5调度周期起点荷电状态储能SOC上/下限0.9 / 0.1防止过充过放储能充放电效率0.95单向效率充放各算一次会损失约9.75%循环寿命100% DOD3000次用于衰减成本折算放电深度惩罚系数随DOD变化深度越大单位能量成本越高分时电价峰1.2 / 平0.7 / 谷0.3 元/kWh影响储能套利行为天气数据我直接用案例自带的典型日数据代码结构上预留了读接口可以替换成实际风电、光伏的时序出力CSV。3.2 日前调度层MILP建模与求解日前调度我用YALMIP建模求解器用Gurobi。YALMIP的优势是可以用近似自然语言的语法描述优化问题调试约束非常方便不需要手写标准形式矩阵。核心代码框架如下%% 日前调度模型简化框架 % 决策变量 P_buy sdpvar(T, 1); % 从电网购电功率 P_sell sdpvar(T, 1); % 向电网售电功率 P_ch sdpvar(T, 1); % 储能充电功率 P_dis sdpvar(T, 1); % 储能放电功率 SOC sdpvar(T1, 1); % 储能荷电状态 P_g sdpvar(T, 1); % 燃气机组出力 u_g binvar(T, 1); % 燃气机组启停状态 P_cl sdpvar(T, 1); % 可调负荷实际用电功率 % 目标函数购电成本 机组燃料成本 储能退化成本 惩罚项 objective sum(price_buy .* P_buy) ... sum(a_g * P_g b_g * u_g) ... sum(c_degrade * (P_ch P_dis)) ... M_curtail * sum(curtailment) ... M_shed * sum(shed_load); % 约束 Constraints []; % 功率平衡可再生能源 购电 储能放电 机组 负荷 售电 储能充电 Constraints [Constraints, P_res P_buy P_dis P_g P_load P_sell P_ch]; % 储能SOC递推 Constraints [Constraints, SOC(2:T1) SOC(1:T) eta_ch*P_ch - P_dis/eta_dis]; % SOC上下限 Constraints [Constraints, SOC_min SOC SOC_max]; % 储能充放电功率限制互斥用二进制变量约束 Constraints [Constraints, 0 P_ch u_ch*P_ch_max]; Constraints [Constraints, 0 P_dis (1-u_ch)*P_dis_max]; % 备用容量约束 % 向上备用不小于净负荷正偏差预测 Constraints [Constraints, P_g_max - P_g P_dis_max - P_dis reserve_up]; % 机组爬坡约束 Constraints [Constraints, -ramp_down P_g(2:T)-P_g(1:T-1) ramp_up]; % 求解 optimize(Constraints, objective, sdpsettings(solver,gurobi,verbose,2));注意储能充放电的互斥约束是我上面简化写的如果直接用u_ch和(1-u_ch)分别乘上限等于把储能建模成两个互斥资源逻辑没有问题。不过实际代码里建议用两个二进制变量来约束不然可能在边界处出现同时充放的情况。用implies或者big-M方法都可以。还有一个细节SOC递推公式里充放电效率的位置。充电时eta_ch乘在充电功率上放电时P_dis除以eta_dis。效率的两种写法执行效果略有差异但都是对电功率和能量之间折算关系的合理近似。3.3 日内滚动层的实现日内滚动调度的代码实现要点在于“滚动”的逻辑而不是建模本身。每过一个周期用最新的预测数据重新求解一个短窗口优化。伪代码结构%% 日内滚动调度每15分钟滚动一次窗口4小时 for k 1:hours_step:(H - window_len) % 提取最新预测假设每步更新一次预测 P_res_updated forecast_update(k:kwindow_len); P_load_updated load_update(k:kwindow_len); % 基于日前计划获取SOC参考值 SOC_ref SOC_daily(k:kwindow_len); % 构建局部优化问题 % 目标函数中加入对日前计划的偏离惩罚防止剧烈修正 objective_rt objective_base lambda_soc * norm(SOC - SOC_ref) ... lambda_dev * norm(P_g - P_g_daily(k:kwindow_len)); % 更新约束求解 optimize(Constraints, objective_rt, options); % 只执行第一个时段的指令然后把实际SOC更新回状态 apply_control(P_opt(1)); end这一段代码的逻辑很关键。如果不加对日前计划的偏离惩罚日内层会频繁大幅调整机组出力以追求局部最优导致实际运行中出现机组出力“抖动”这对设备寿命很不友好。加一个软约束之后日内层的修正会更平滑只在必要时偏离日前计划这与实际调度人员的操作习惯是一致的。滚动窗口的长度选择也值得说。窗口太短比如只滚1小时无法统筹储能的跨时段充放电策略可能把储能限制在局部最优状态窗口太长比如8小时以上预测精度已经下降很多而且求解规模变大。实测下来4小时窗口在计算速度和优化效果之间比较平衡。3.4 衰减成本的线性化处理衰减成本进入MILP需要做线性化。我用分段线性函数逼近DOD与单位循环成本的关系。核心思路是把DOD区间[0,1]切成N段每段用一段直线近似寿命成本。调度时根据储能实际放电深度查表计算本次循环的等效衰减成本。%% 储能衰减成本分段线性化参数 dod_breakpoints 0:0.1:1; % DOD断点 % 每段对应的单位放电量衰减成本示例值来自寿命曲线拟合 % 实际项目中应使用电池厂商提供的循环寿命数据 cost_cycle interp1(dod_breakpoints, cycle_cost_table, ... dod_breakpoints, linear); % 将非线性关系转化为线性约束 % 用SOS2约束或凸组合方法处理分段线性函数如果用YALMIP可以直接用sos2约束处理分段线性函数或者用binvar加implies实现。SOS2约束的实现方式最简单Gurobi直接支持不需要额外添加辅助变量。这个线性化不仅大幅提升求解效率整个MILP一般在10秒内求解完毕而且避免了非线性求解器容易遇到的初始值敏感问题。衰减成本的引入会直接影响储能调度行为。仿真结果显示计入衰减成本后储能的总充放电量减少了约30%但循环寿命折算成本降低了近50%。储能使用方式从“高频次浅充浅放”转变为“低频次但时机精准的充放”SOC曲线整体更平稳这对电池实际寿命的延长是很有价值的。3.5 多尺度结果的衔接与可视化代码最后需要把三层的结果拼接起来形成完整的时间序列。我习惯把日前计划、日内修正后计划、实时修正结果画在同一张图上对比直观展示每层优化的差异在哪里。可视化代码%% 结果可视化 figure; subplot(3,1,1); stairs(t_daily, P_g_daily, k, LineWidth, 1.5); hold on; stairs(t_intraday, P_g_intraday, --r, LineWidth, 1.2); legend(日前计划, 日内修正); ylabel(机组出力 (MW)); subplot(3,1,2); stairs(t_daily, SOC_daily, k, LineWidth, 1.5); hold on; stairs(t_intraday, SOC_intraday, --b, LineWidth, 1.2); legend(日前计划SOC, 日内修正SOC); ylabel(SOC); subplot(3,1,3); bar(t_daily, P_buy_daily, g); hold on; bar(t_intraday, P_buy_intraday, r); legend(日前购电, 日内购电修正); ylabel(购电功率 (MW)); xlabel(时间 (小时));图中能看到日前计划与日内修正的偏差主要集中在风光出力骤变时段和晚高峰附近。这个偏差的分布就是灵活性资源实际发挥作用的地方也是成果论文中经常呈现的典型结果。4. 复现结果与灵敏度分析要点4.1 实验设计和对照组设置完整的复现不能只跑一组数据。我把实验拆成了三组对照方案A无VPP调度各分布式资源独立运行基准场景方案BVPP单时间尺度日前优化不用多时间尺度方案CVPP多时间尺度优化本文方案含衰减成本。三组实验使用同一套基础数据保证可比性。结果汇总如下方案总运行成本万元/日弃风弃光率切负荷量MWh储能等效循环数A 无VPP35.28.7%3.1未受控B 单尺度调度30.83.2%0.82.4C 多尺度衰减建模27.61.5%01.6从结果看多时间尺度调度相比单尺度的成本节省约10%主要来源于两个途径一是日内滚动修正减少了备用容量要求让机组可以更经济地运行二是衰减建模避免了储能的过度使用降低了电池更换成本折算值。方案B虽然没有切负荷但储能每天都高频深充深放实际工程中电池寿命损耗很大这个成本在单尺度模型里被忽略了。4.2 储能价格与衰减系数的影响灵敏度分析涉及两个核心参数储能单位投资成本和衰减系数。储能单位投资成本从1500元/kWh降到500元/kWh时价格变化模拟未来电池降本趋势最优调度策略中储能的循环次数逐步提高系统对储能的依赖增强弃风率进一步下降。衰减系数的影响更微妙。如果衰减系数设得很小相当于认为电池寿命无限优化器会让储能频繁深度充放电系统购电成本最低但电池损耗大如果衰减系数设得过大储能完全变成了“摆设”系统只能靠机组调节弃风和备用成本上升。正确设置的衰减系数应该让储能在“多充多放省电费”和“少充少放保寿命”之间找到最佳平衡点这个平衡点跟电价差、负荷特性、风光渗透率都相关工程中需要通过参数扫描确定。4.3 风光渗透率变化对调度策略的影响我还扫了三档风光渗透率30%、50%、70%。渗透率越高净负荷波动越大系统备用需求越紧张。在50%渗透率以下现有资源的灵活容量基本能应付到70%时如果储能衰减成本计入目标函数系统会出现备用电量不足的时段虚拟电厂需要通过柔性负荷平移和可中断负荷来补足灵活性。这说明“灵活性资源不足”在高渗透率下是客观约束不是调度算法能凭空解决的算法只能尽量用好已有的灵活性资源。5. 实操中的坑与排查经验记录5.1 YALMIPGurobi求解慢的排查很多人复现这类模型时会遇到求解时间过长的问题。我排查过几个原因按优先级从高到低说第一储能充放电互斥用了两个独立二进制变量但没有加互斥约束导致求解器需要对“同时充放”的无效分支进行大量搜索。解决办法是加u_ch u_dis 1约束这个不起眼的约束通常能把求解时间缩短30%以上。第二备用约束用了多个时段耦合的决策变量组合。如果备用约束涉及T个时段、N个资源约束矩阵会变得很密Gurobi的预求解器处理起来偏慢。可以尝试松开部分跨时段耦合约束用“机组组合”领域的标准方法做拉格朗日松弛但工程上更简单的是缩短窗口长度减少问题规模。第三SOS2分段线性化分段数设太多。分段数从10增加到20求解时间可能翻2~3倍。如果精度够用建议用8~12个分段就足够没必要在衰减曲线上追求极致逼近因为电池寿命曲线本身就是实验数据拟合的误差本来就存在。5.2 SOC漂移问题SOC的递推约束如果写得不严谨长时间运行仿真后会出现SOC越界或者跟实际值漂移的情况。我在初版代码里把充放电效率都按常数处理但实际上电池的充放电效率跟SOC区间有关系——低SOC区间内阻大效率略低高SOC区间可能存在析锂风险模型里也不建议满充。好在调度层一般不追求这么细用固定效率做近似可以接受。真正的坑在滚动优化每轮滚动优化开始时SOC初值应该用上一轮的实际计算值而不是计划值。如果误用了计划值错误会逐轮累积到最后几轮SOC会明显偏移真实轨迹。排查方法很简单把每个时间步的SOC计划值和“实际值”仿真器计算值画在一张图上看偏差是否随时间增大。5.3 结果对备用系数的敏感性备用系数的设置对结果影响非常大。我一开始用的是固定常数备用系数比如净负荷的10%结果发现有些时段备用被大量闲置有些时段备用不足。后来改用动态备用曲线净负荷变化率大的时段取15%平稳时段取5%。这个调整让总成本又降了约7%。不同论文对动态备用的实现方式不太一样但核心逻辑是一样的备用需求应当跟随预测误差的不确定性水平变化。计算方式可以做简单的区间预测统计比如取历史预测误差的某个分位数或者用随机场景法生成多个预测场景取覆盖一定置信区间的备用值。在我的实现里为了控制计算量用的是分位数方法在模型外部预先算好各时段备用值然后作为常数参数输入优化模型。5.4 极端场景导致无解的处理有一次我在测风光渗透率70%的场景时模型直接报infeasible。排查发现是日内滚动窗口里某个时段净负荷下降太快储能已经放空、机组爬坡到上限从电网购电又受到联络线功率限制所有资源的可下调能力都不够导致备用不足约束无法满足。解决办法不是删约束而是给模型增加一个“松弛变量”出口。备用约束右边加一个非负松弛变量目标函数里加一个大的惩罚系数。这样模型在极端时段可以“花大价钱买备用”而不是直接无解。这个处理既符合工程直觉——紧急时段可以从上级电网购买额外的非旋转备用——也保证了优化模型在所设条件下始终有可行解。5.5 复现代码过程中的常见问题速查现象可能原因排查对策无解或不可行约束冲突 / 参数越界逐个添加约束测试检查SOC初始值、备用参数求解时间过长二进制变量太多 / 分段数过大添加互斥约束减少分段数缩短滚动窗口储能SOC越界SOC递推公式错误 / 效率写反检查递推关系核对充/放功率与SOC变化的符号日内修正幅度过大缺乏对日前计划的偏离惩罚加入SOC参考值软约束调整惩罚系数衰减模型对结果无影响惩罚系数设得过小将衰减成本提高到与购电价同一量级再测试结果与论文数据差异大输入数据理解不一致 / 单位错误核对成本单位元/MWh检查预测数据的基准值6. 一点个人体会和扩展方向复现这套第三层结构我的一个切身感受是论文里最核心的贡献往往是“把合理的工程约束放进优化模型”而不仅仅是算法本身。衰减建模不是什么复杂的新算法就是用一个常规的分段线性函数把电池寿命成本折算到目标函数里去了但就是这一步让整个调度结果从“理论可行”变成了“工程可用”。代码的扩展空间也很大。如果手头有真实负荷数据把案例数据替换进去框架完全可以直接用。扩展到多虚拟电厂协同调度时需要在各VPP之间加联络线功率约束和利益分配机制扩展到电动汽车参与调度时要增加行驶需求约束和充电桩容量约束如果想进一步贴近实际还可以把配电网潮流约束加进来但这会让模型从MILP变成MINLP求解复杂度会大幅上升需要做一些凸松弛处理。最后分享一个处理这类复现问题的小技巧拿到论文先不急着写代码花一天时间把文中的数学模型目标函数、约束、变量逐条手写推导一遍搞清楚决策变量之间的时间耦合关系。这次我就是把所有约束和决策变量列成一张表格标清楚每个变量的维度、上下界、所属时间尺度模型的整体图景就清晰了后面代码完全不会卡壳。做优化问题想清楚模型结构永远是第一步也是工作量占比最大的一步代码反而是最轻松的部分。
返回列表