风电、光伏与储能的互补调度,这事听起来像是标准的电力系统优化问题,但真正上手做过的人都知道,难点从来不在于某个单一电源的建模,而在于怎么把风、光、电池、抽水蓄能这几种“脾气”完全不同的对象,塞进同一个调度框架里还能跑得动、跑得稳。我这次做了一套基于Matlab的仿真研究,模型里不仅包含常规的风电和光伏,还同时纳入了电池储能和基于废弃矿井改造的小型抽水蓄能,目标是让这四类电源在日内调度中形成真正的互补关系。整个过程走下来,踩了不少坑,也总结出一些值得分享的经验。这篇就把完整的研究思路、模型细节、Matlab实现过程和调试心得一次说清楚。
1. 项目背景与核心问题
1.1 为什么风电、光伏必须做互补调度
风电和光伏的出力特性,用一句话概括就是“靠天吃饭”。风电在夜间往往出力更大,因为夜间大气层结更稳定、风速变化相对平缓,而白天随着地表受热加剧,湍流增强,风速反而可能出现下降;光伏则完全跟随光照强度,只在白天有出力,中午达到峰值,傍晚迅速归零。这两者的时间错配,直接导致了一个现实问题:如果只靠单一电源供电,要么夜间缺电,要么午间电力过剩,始终无法和负荷曲线对齐。
更麻烦的是,风电和光伏的波动并不仅仅是“白天有、晚上没有”这种粗颗粒度的规律。分钟级和小时级的随机波动才是调度员真正头疼的地方。一片云飘过光伏电站,出力能在几十秒内下降30%以上;一个局部风切变过程,能让风电场输出功率在10分钟内剧烈摆动。这种高频波动如果直接注入电网,频率稳定和电压稳定都会受到冲击。
所以,互补调度的第一层意义,就是利用风电和光伏在时间分布上的差异性做初步的平滑。风大光弱的时候让风电多出力,光强风弱的时候让光伏顶上,彼此填补对方的出力低谷。但仅靠风、光之间的互补远远不够,因为二者都存在“同时为零”的可能——比如阴雨天加静风天气,或者夜间无风的日子。这时候就必须有储能介入,把之前富余的电能存起来,在双低谷时段放出来,才能真正实现让负荷曲线“有求必应”。
1.2 储能的双重身份:调节电源与能量时移
在互补调度体系里,储能扮演的角色不是单一的“备用电源”,而是两个层面的功能叠加。第一层是功率调节,即利用储能毫秒级到分钟级的响应能力,平抑风电和光伏的高频波动。风电场的爬坡事件、光伏的云遮效应,都可以通过储能系统的快速充放电来抵消。第二层是能量时移,也就是把午间光伏大发时的富余电量存起来,挪到晚间负荷高峰时使用,或者把夜间风电的多余电量存起来,补充次日清晨的负荷爬坡。
这两个功能在调度模型中的数学表达完全不同。功率调节对应的是对储能出力变化率的约束,本质上是限制其在单位时间内的功率调整幅度;能量时移对应的则是储能SOC(荷电状态)在时间维度上的转移,核心是能量平衡约束。把这两层功能同时塞进调度模型,是很多人第一次做多源互补调度时容易忽略的点——如果只把储能当成一个“大号电池”来建模,不考虑它的爬坡能力约束,仿真结果会过于乐观,工程上根本不可行。
我在模型里对电池储能和抽水蓄能做了差异化处理。电池储能的响应速度按分钟级考虑,具备双向快速调节能力;抽水蓄能则按小时级考虑,启停时间和工况转换时间更长,但胜在单机容量大、持续放电时间长。这两种储能的时间常数差异,恰好构成了互补调度的第二层互补——快慢结合,兼顾波动平抑与能量的长时间转移。
1.3 废弃矿井抽水蓄能:被低估的储能形式
提到抽水蓄能,大多数人第一反应是大型水电站式的工程,比如某个装机上百万千瓦的抽蓄电站。但实际上,抽水蓄能的形态可以远小于此。利用废弃矿井建设小型抽水蓄能电站,是近年来在资源枯竭型地区颇受关注的技术路线。废弃矿井通常具备现成的地下巷道空间和竖井结构,上下两个不同标高的采空区或巷道可以作为天然的上水库和下水库,只需要安装水泵水轮机组和相应的电气设备,就能以远低于地面新建电站的成本,获得一个可用的储能单元。
这种小型抽水蓄能的优势,首先体现在容量和功率的“中型化”——单站装机通常在几兆瓦到几十兆瓦之间,正好填补电池储能(兆瓦级以下到十兆瓦级)和大型抽蓄(百兆瓦级以上)之间的空白。其次是响应特性,虽然无法和电池比毫秒级响应,但作为小时级能量时移的主力绰绰有余。第三是选址灵活性,废弃矿井往往分布在负荷中心附近或电网末端,可以作为分布式储能节点接入配网。
当然,废弃矿井抽水蓄能也有自己的约束。地下空间的水文地质条件直接决定可行性,巷道围岩的稳定性、地下水的补给与渗漏特性、竖井的防腐与设备安装条件,每一项都需要专门论证。在调度模型层面,我重点关注的是它的运行约束——包括上下水库的库容限制、抽水和发电工况的转换时间、水头变化对出力效率的影响等。这些约束和电池储能差异很大,建模时必须单独处理。
2. 调度模型构建与数学描述
2.1 目标函数:经济性优先还是可靠性优先
调度模型的目标函数,决定了整个优化问题的走向。做风电、光伏、储能互补调度时,常见的思路有两种。第一种是经济性最优,即把系统总运行成本最小化作为目标,包括常规机组的燃料成本、储能设备的充放电损耗成本、弃风弃光惩罚成本等。第二种是可靠性最优,以系统供电不足的概率或电量最小化为目标,优先保证负荷的满足率。
我在这套模型里采用的是经济性优先、可靠性以约束形式保证的思路。原因很实际:纯可靠性优化的结果往往是“不计代价保供电”,储能会被频繁深度充放,设备寿命损耗严重,运行成本高到不具备工程可行性。而纯经济性优化又有风险,可能为了省钱而牺牲必要的备用容量。把可靠性要求写成约束条件(比如旋转备用容量不低于最大负荷的一定比例、系统供电不足概率低于某个阈值),再在满足约束的前提下做经济性优化,这才是工程上最常见、也最容易被决策者接受的做法。
具体的目标函数可以写成:
% 目标函数:系统总运行成本最小 % 包含:储能充放电损耗成本 + 弃风弃光惩罚 + 负荷缺电惩罚 + 抽水蓄能运行维护成本 f = sum(c_bat_loss .* (P_bat_ch + P_bat_dis)) ... % 电池损耗成本 + sum(c_psh_loss .* (P_psh_pump + P_psh_gen)) ... % 抽蓄运行成本 + sum(c_curtail_w .* P_curtail_w) ... % 弃风惩罚 + sum(c_curtail_pv .* P_curtail_pv) ... % 弃光惩罚 + sum(c_lps .* P_lps); % 失负荷惩罚这里每个成本项的系数都不是随便拍的。电池损耗成本与循环次数、放电深度直接相关,通常折算为每千瓦时充放电量的等效成本;弃风弃光惩罚的取值则参考当地的上网电价和绿电溢价,设置太低会导致模型宁可弃电也不用储能,设置太高又会让储能过度调用、增加不必要的损耗。
2.2 关键约束条件
调度模型的约束条件,是整篇代码里最庞大也最容易出错的部分。我按功能把它们分成四个组,每个组的物理意义都必须想清楚才能写进代码。
第一组是功率平衡约束,也就是任意时刻系统内所有电源出力、储能充放电功率和负荷功率必须严格相等。这个约束是硬性的,偏差哪怕只有1kW也会导致模型结果失真。第二组是电源出力约束,包括风电和光伏的可用出力上限(由预测曲线决定)以及最小技术出力。风电机组和光伏逆变器都有最小技术出力限制,不是想发多少就发多少。第三组是储能运行约束,包括功率上下限、SOC上下限、充放电爬坡约束以及充放电状态互斥约束——这里最容易出问题的是状态互斥,很多新手会忘记电池不能同时充放电,导致模型在极端条件下出现“一边充一边放”的荒唐结果。第四组是抽水蓄能特有约束,包括上下水库库容约束、抽水/发电工况转换时间约束、单位时间内的工况启停次数限制。
功率平衡约束的Matlab表达如下:
% 功率平衡约束:发电=负荷+储能充电(或-储能放电)+弃电+失负荷 % P_w为风电出力,P_pv为光伏出力,P_bat_ch/P_bat_dis为电池充放电功率 % P_psh_pump/P_psh_gen为抽蓄抽水/发电功率 % P_curtail为弃电功率,P_lps为失负荷功率 P_w + P_pv + P_bat_dis + P_psh_gen + P_lps == ... P_load + P_bat_ch + P_psh_pump + P_curtail;这个等式是调度模型的核心骨架,所有其他约束都是从不同侧面限制这个等式两侧的变量。每次修改模型,我第一件事就是检查这个等式在代码里是否被正确传递,变量数量是否和约束矩阵的列数对应。出错的概率极高,但排查方法也很直接——先跑一个不含储能的简化版本,确认功率平衡能满足,再逐步加上储能模型。
2.3 电池与抽水蓄能的差异化建模
电池和抽水蓄能虽然都能“充电放电”,但在数学模型上的差异巨大。电池储能建模的核心变量是SOC,其递推关系是:
% 电池SOC递推方程 % SOC(k+1) = SOC(k) + (P_bat_ch * eta_ch - P_bat_dis / eta_dis) * dt / E_bat for k = 1:T-1 SOC(k+1) == SOC(k) + (P_bat_ch(k) * eta_ch - P_bat_dis(k) / eta_dis) * dt / E_bat; end这里eta_ch和eta_dis分别是充电效率和放电效率。很多人建模时会简化成一个综合效率系数,这种做法在小规模仿真里还行,但要模拟电池的实际损耗,就必须区分充放电两个方向——铅酸电池、锂电池、液流电池的充放电效率差异很大,统一的效率系数会掩盖这种差异。
抽水蓄能的建模则完全不同。它的“SOC”是上下水库的水量,递推关系受水头影响,但阶跃式的、以固定小时数为周期的调度更贴合实际。
3. 基于Matlab的求解实现
3.1 整体流程与代码结构
Matlab代码的整体结构可以分为五个模块:数据输入模块、模型构建模块、求解模块、结果输出模块和可视化模块。数据输入模块负责读取风电、光伏、负荷的历史数据或预测数据,以及储能参数;模型构建模块把第2节描述的数学模型写成优化问题的具体形式;求解模块调用求解器完成计算;结果输出模块把最优解解码为各电源的出力计划;可视化模块把调度结果画成曲线,便于分析。
整个代码框架是这样的:
%% 主程序框架 clc; clear; close all; % 1. 数据输入 [data_wind, data_pv, data_load, param] = load_input_data(); % 2. 模型构建 [problem, x0] = build_optimization_model(data_wind, data_pv, data_load, param); % 3. 求解 [solution, fval, exitflag] = solve_optimization(problem, x0); % 4. 结果解码 [schedule_w, schedule_pv, schedule_bat, schedule_psh] = decode_solution(solution, param); % 5. 可视化 plot_schedule(schedule_w, schedule_pv, schedule_bat, schedule_psh, data_load);这里的关键设计是把模型构建和求解分离。原因很简单:在调试阶段,你需要频繁修改约束条件,如果模型构建和求解耦合在一起,每改一次约束都要重新跑一遍完整流程,效率极低。分离之后,你可以单独测试约束矩阵的有效性,发现问题只修改对应的模块。
3.2 核心算法选择
调度优化问题的求解方法,直接影响计算速度和结果质量。我实验过几种不同的算法。
第一种是线性规划,如果目标函数和约束都是线性的,直接调用linprog即可,速度快、结果稳定。但线性模型的问题在于无法精确表达储能充放电效率随功率变化的非线性关系,也无法处理电池寿命与放电深度的非线性耦合。
第二种是混合整数线性规划,引入二进制变量处理充放电状态互斥、抽水蓄能工况切换这类逻辑约束。这是当前工程上最实用的选择,能够精确表达状态切换的离散特性,求解速度在合理规模下完全可以接受。我的模型最终采用的就是这种方法。
第三种是启发式算法,包括遗传算法、粒子群等。这类算法适合处理高度非线性的问题,但缺点是结果具有随机性,每次运行可能得到不同的解,而且计算时间相对较长。针对确定性较强的调度问题,我并不偏好这类方法,除非模型里加入了大量非线性设备特性。
MILP模型的二元变量部分是这样的:
% 电池充放电状态互斥约束 % u_bat为二进制变量:1表示充电,0表示放电(或待机) P_bat_ch(k) <= M * u_bat(k); P_bat_dis(k) <= M * (1 - u_bat(k));这个约束用一个大数M来实现——当u为1时,充电功率可以大于0,放电功率被强制为0;当u为0时,放电功率可以大于0,充电功率被强制为0。M的取值不能太大也不能太小,太大会导致数值稳定性问题,太小会错误地限制功率上限。我的经验是取储能额定功率的1.2倍左右比较稳妥。
3.3 关键参数设置
参数设置这件事,看起来不起眼,实际却是决定模型是否跑得通、结果是否合理的关键。
风电和光伏的出力数据,我建议使用典型日的实测数据,而不是理想化的正弦曲线。实测数据的特性是带有真实的波动模式——比如午间光伏出力会因云量变化出现锯齿形波动,风电出力在早晚时段会有明显的爬坡过程——这些波动正是调度模型要处理的“麻烦”,仿真价值远高于平滑的理想数据。
储能的SOC上下限设置需要特别小心。锂电池的实际可用容量一般只有标称容量的20%~90%(取决于保护策略),超过这个范围会严重缩短寿命。抽水蓄能的库容利用率也类似,上下水库都有限死水位,不能全库容放水。这些限制都要转化为SOC约束。
时间分辨率的选择同样值得关注。我采用的是15分钟一个调度时段、共96个时段。15分钟能捕捉到大多数新能源波动的细节,又不至于让变量数量爆炸。如果采用5分钟分辨率,变量数量变成6倍,求解时间可能从几秒增加到几分钟,而精度提升相对有限。对于日调度来说,15分钟是性价比最好的折中选择。
4. 典型场景仿真与结果分析
4.1 场景设计
为了验证互补调度模型的适应性,我设计了三个典型场景进行仿真。
场景一:大风无光日。风电出力较大,光伏出力接近零,全天负荷从早到晚逐级爬升。这个场景考验的是风电如何在夜间与储能配合,把夜间低负荷时段的多余电量存储起来,支撑早高峰和晚高峰的负荷需求。
场景二:强光弱风日。光伏大发,风电出力不足。午间光伏出力远超负荷需求,电网面临严重的弃光压力;傍晚光伏快速切出后,系统可能进入晚高峰缺电状态。这个场景考验储能系统的“午充晚放”能力,以及抽水蓄能能否在有限的几个小时内完成大量能量转移。
场景三:闷热无风阴天。风电、光伏同时处于低出力状态,全天负荷却比较高。这个场景是压力最大的测试——考验的是混合储能在极端情况下的兜底能力,以及电池与抽水蓄能是否能把前一日存储的能量在关键时刻全部释放。
4.2 结果分析
仿真结果有几个数据值得拿出来单独说。
第一个是弃风弃光率的变化。场景一中,无储能的情况下弃风率大约在18%左右(夜间风电大发、负荷低谷,电网接纳不了一部分风电);加入电池储能后,弃风率降到了8%左右;再加入抽水蓄能后,进一步降到4%以下。原因不难理解:夜间风电大发持续的时间长达8~10小时,电池储能的容量如果只有2小时左右,只能平移部分风电;而抽水蓄能的能量容量可以达到6小时以上,能够更完整地把夜间大风期的多余电量搬运到白天。
第二个是负荷峰值削减量。场景二中,午间光伏大发时段系统出现大量过剩电力,如果没有储能,要么弃光、要么让常规机组深度压低出力——两者代价都很高。加入互补调度后,电池储能负责吸纳午间前2小时的光伏盈余,抽水蓄能负责吸纳后4小时的盈余,晚高峰再依次释放。实测效果是系统最大净负荷下降了约21%,这直接意味着可以推迟对输电线路和变压器的扩容投资。
第三个是电池循环次数与放电深度。在只有电池储能的情况下,为了满足晚高峰的负荷需求,电池需要每日一次深度放电,SOC从90%跌到20%甚至更低,长期运行的寿命衰减非常明显。加入抽水蓄能后,电池的日循环次数和平均放电深度都显著下降——电池更多承担短时功率调节和高频波动平抑,能量时移的重担主要交给抽蓄。这个分工模式在实际工程中非常关键。
5. 常见问题与排查技巧实录
5.1 问题排查实录
整套Matlab模型从搭框架到跑通,我至少遇到了四个值得记录的坑。
第一个坑是求解器“无解”报告,但怎么查都找不到约束明显矛盾的地方。后来排查发现,是功率平衡约束和失负荷变量的边界条件设置不当——失负荷功率被限制为非负变量,但在个别时段、备用约束和功率平衡联合作用下,这个非负变量被逼到了负值,求解器自然报错。解决方法是放宽备用约束的上下限,或者给失负荷变量加一个足够大的惩罚系数,让它永远只在万不得已时才被激活。
第二个坑是SOC初值不匹配。调度周期从SOC=50%开始,但模型要求调度结束时的SOC也回到50%,否则就变成“占系统便宜”了——开始有电和结束有电,日内的净放电量就被人为放大了。这个问题不解决,调度结果会出现“假性最优”:系统靠消耗储能的初始电量来降低成本,长期看根本不可持续。我采用的办法是把SOC初值和末值一起纳入约束变量,让模型自行适配最合理的起始荷电状态。
第三个坑是抽水蓄能工况转换时间被忽略。抽水蓄能从抽水工况切换到发电工况,物理上需要几分钟到十几分钟,期间机组既不能抽水也不能发电。如果模型忽略这个时间窗口,就会在仿真中出现“抽水2小时、停机5分钟、再发电3小时”这种实际操作做不出来的计划。处理方式是引入工况转换的二进制变量,强制两次工况变更之间至少间隔一个调度时段。
第四个坑是可视化结果和优化结果对不上。有一段时间我发现,画出来的调度曲线在个别时段明显违反功率平衡——发电、储能和负荷的数值加起来对不上。排查后发现是时间索引错位:Matlab中数组索引从1开始,而时间序列从0点开始,导致跨零点时出现了数据错位。这个问题不难解决,但排查过程相当耗时,最终靠逐时段打印功率平衡校验值才定位。
5.2 经验技巧与心得
除了问题排查,再分享几组我认为最有价值的实操经验。
关于模型调试,我强烈建议“从小到大、分步验证”。先用一个3时段的简化模型跑通整个逻辑链,再扩展为96时段。这样任何逻辑错误都能在小规模问题上快速暴露,而不是在96×N的大矩阵里大海捞针。我通常是先在简化模型里手算几组期望结果,再对照优化输出,确认每个约束确实被模型正确接收。
关于参数敏感性,做完整套模型之后,一定要做一轮关键参数的敏感性扫描——特别是电池容量、抽蓄功率、备用比例这三个参数。我曾经发现一个现象:当电池容量从2小时增加到4小时时,弃风率下降幅度明显;但从4小时增加到6小时时,边际收益骤降。这说明在给定场景下电池容量存在一个“甜蜜点”,继续增大容量只会增加投资成本,不会带来等比例的效益提升。这种信息对工程方案设计来说非常关键。
关于数据格式统一,风电、光伏、负荷数据的单位、分辨率、时间基准必须严格一致。我见过很多初学者把风电数据用MW、光伏数据用kW、负荷数据用MWh来输入,结果模型结果完全失真。建议在数据输入模块里统一单位换算,并增加一轮数据合理性校验,比如检查是否存在负值、是否出现明显的跳变异常值。
关于求解器选择,Matlab自带的intlinprog对于中等规模的MILP问题(比如96时段、几十个变量的调度问题)完全够用。但当问题规模扩展到多个典型日、多台储能设备同时优化时,intlinprog的求解时间会明显上升。这时候可以考虑两条路:一是用YALMIP框架封装模型、然后调用Gurobi或CPLEX等商用求解器,二是把问题按典型日拆分、用滚动优化的思路分批求解。两条路我都试过,前者适合追求最优解的科研场景,后者更适合工程落地。
5.3 从仿真到工程落地的经验总结
关于这套模型的扩展方向,我最大的体会是:模型再精良,也只是“预演”。从仿真结果到实际工程落地,中间还隔着设备响应延时、通信带宽限制、预测误差波动等一系列现实问题。在Matlab里跑通互补调度,只是拿到了“理论上的最优调度计划”,要让这个计划可执行,还需要加上滚动修正环节——每15分钟滚动一次,用最新的风电光伏预测数据重新求解一次调度问题,只执行下一时段的内容。这样做下来,系统的稳定性表现要远好于一次性生成次日全天计划的做法。
对于想在这个方向深入做的读者,我建议下一步关注两件事:一是把预测的不确定性显式纳入调度模型,比如用鲁棒优化或随机优化的方法处理风电光伏预测误差;二是把设备寿命模型做细,电池的循环老化、抽水蓄能机组的磨损都值得精细化建模。这两个方向补上之后,互补调度模型离真正的工业级应用就又近了一步。