
做新能源并网研究的朋友十个里有八个在跟“波动性”较劲。风电出力随风速变化上蹿下跳光伏更“任性”——白天出力拉满傍晚直接归零遇到阴雨天简直形同虚设。我之前跑过一个不含储能的并网仿真风电渗透率一上去弃风率直接飙到20%以上那画面看得我头疼。后来下决心研究“风电光伏储能”的互补调度问题这才发现突破口不在于加多少储能而在于怎么调度储能。这套基于MATLAB的多能互补调度仿真源码15174期就是我这段折腾的成果里面同时考虑了电池储能和废弃矿井改造的小型抽水蓄能。这两类储能形态的性格完全不同——一个反应快但容量贵一个容量大但响应慢——把它们放在同一个优化框架里互补配合是最有意思的部分。这篇文章就从模型设计、代码实现到结果分析把我踩过的坑和经验完整复盘一遍适合正在做新能源消纳、微电网调度、储能容量配置相关课题的研究生和工程师参考。1. 为什么要做多能互补调度新能源出力波动到底有多“不讲理”在做模型之前先得把这个问题想清楚我们到底在解决什么问题。很多人觉得加储能就完事了但实际上储能怎么加、加多少、怎么控制完全取决于你对风光出力特性的理解深度。1.1 风光出力特性的实测体感风电出力主要受风速影响而风速在时间和空间上的波动极大。我用威布尔分布生成风速序列时能明显感受到这种随机性同一组参数下前一小时还是接近额定风速的满发状态后一小时风速掉到切入风速以下风机直接停机。爬坡率这个指标更能说明问题——所谓爬坡率就是单位时间内出力变化的大小风电的分钟级爬坡率可以达到装机容量的10%以上这对系统的调频和备用提出了很高要求。光伏出力则是另一种规律。白天出力曲线呈现典型的钟形正午达到峰值但云层遮光会导致出力在几分钟内暴跌到峰值的30%左右。最麻烦的是光伏在傍晚出力迅速归零而这时正好是负荷晚高峰的开始如果不提前安排储能或其它电源顶上系统就很容易出现电力缺口。这两个特性决定了互补调度的第一个逻辑风电和光伏本身就有天然的互补性把两者叠加之后总出力曲线的波动程度比单独任何一种都小。但仅仅靠风光互补远远不够因为两者都受天气影响一旦遇到“有风无光”或“有光无风”的日子互补效果就会大打折扣。1.2 没有储能时系统会发生什么我在仿真中做了一个对照实验系统里只有火电、风电和光伏不配置任何储能。风电场装机200MW光伏电站装机100MW负荷曲线取自某地区典型日的实测数据。结果非常直观在某些时段风光出力总和超过负荷需求系统被迫弃风弃光在另一些时段风光出力骤降火电不得不快速爬坡甚至触发爬坡率越限。更关键的是弃风弃光电量的统计。那组仿真里全天弃风弃光电量占总新能源发电量的17.8%。也就是说将近五分之一的“免费绿电”因为系统调节能力不足而浪费掉了。这个数字在模型参数调整后还会更高——比如光伏渗透率提高或者负荷曲线变得平缓时。1.3 互补调度的价值到底在哪儿互补调度不是一个概念装饰它的核心价值有两层。第一层是时间维度的能量搬移储能系统在新能源出力大于负荷时充电把多余的电能存起来在新能源出力不足时放电填补缺口。这个过程本质上就是把“不听话”的新能源出力曲线改造成一个相对可控的电源。第二层是空间维度的容量替代通过合理的调度策略储能可以替代一部分火电调峰容量或者在电网允许的范围内减少对旋转备用的依赖。我在模型里用火电的调峰成本对比来量化这个价值——接入储能之后火电的出力波动幅度明显降低煤耗成本也相应下降。所以这篇文章里的调度模型目标不是简单地“把储能用起来”而是要让储能和新能源配合得恰到好处在满足负荷需求的前提下最大化消纳新能源、最小化系统运行成本。2. 电池储能与废弃矿井小型抽蓄两种储能形态的互补逻辑储能技术路线很多但在这个项目里我特意选了电池储能和废弃矿井小型抽蓄的组合。很多人第一反应是为什么不干脆多上一些电池答案藏在储能的技术经济特性里。2.1 电池储能反应快但容量贵电池储能的核心优势是响应速度。电化学反应的时标在毫秒到秒级非常适合做功率波动平抑、一次调频、AGC调频这些需要快速响应的场景。在调度模型里电池储能通常被建模为功率型储能重点关注SOC荷电状态的递推关系。但电池储能的短板也很明显单位容量的成本高而且循环寿命有限。磷酸铁锂电池的度电成本虽然一直在下降但考虑到每天一次甚至多次的充放电循环寿命损耗是不可忽视的。我在模型里给电池储能加了循环损耗成本项每充放一次电按一定的成本系数折算进目标函数这样优化器就不会“拼命滥用”电池。容量配置上本项目的电池储能按20MW/40MWh设置也就是可以支撑2小时的额定功率输出。这个配置足以应对分钟级到小时级的功率波动场景。2.2 废弃矿井抽蓄把废弃空间变成能量银行废弃矿井小型抽水蓄能是这套模型里最有特色的部分。原理其实不复杂利用废弃矿井的巷道空间作为下水库在地面修建小型蓄水池作为上水库两个水库之间通过已有的竖井或斜井连接安装小型水泵水轮机组。抽水时把水从下水库打到上水库发电时水流反向冲击水轮机发电。为什么选废弃矿井首先是成本优势。不用拦河筑坝不用淹没大片土地上水库可以利用矿井工业广场的现有设施改造下水库的直接利用矿井巷道容积土建成本比常规抽蓄低很多。其次是选址优势很多废弃矿区就在负荷中心附近既解决了矿区转型问题又不需要新建长距离输电线路。当然废弃矿井抽蓄也有自己的约束。机组容量受巷道空间和水头限制通常属于小型抽蓄单机容量从几百千瓦到几兆瓦不等。响应速度也比电池慢从抽水工况切换到发电工况需要几分钟时间。但在能量型储能这个定位上它的优势是电池无法比拟的——蓄水容量大储能时长可以达到6到8小时甚至可以做到跨日调度。2.3 储能互补组合的物理逻辑把电池储能和废弃矿井抽蓄放在同一个系统里不是简单叠加而是基于性格差异的协同分工。我把这两类储能的工作定位整理成一张对照表对比维度电池储能废弃矿井小型抽蓄响应速度秒级分钟级储能时长2小时以内4-8小时适用场景功率平抑、调频、短时填谷削峰填谷、跨时段搬移、黑启动备用能量损耗自放电率低循环效率90%以上抽发转换效率70%-75%有水头损失寿命特征循环次数有限数千次设备寿命长但需定期维护建设成本单位容量成本高利用废弃空间单位容量成本低这张表直接决定了调度策略的设计方向电池储能承担“快速响应、精确补偿”的任务比如在风光出力突变时快速填补功率缺口抽水蓄能承担“大容量、长时间”的任务比如在光伏大发的中午抽水蓄能在晚高峰发电放水。优化模型不会人为指定谁干什么而是通过目标函数中的成本系数和约束条件让系统自动选择最优的储能使用方式。提示如果只配电池储能系统的短时波动问题能解决但跨时段调峰能力不足如果只配抽蓄响应速度跟不上分钟级波动。两者互补结合才能在模型里同时覆盖两个时间尺度的问题。3. 调度优化模型的数学骨架目标函数与约束条件模型是调度策略的核心载体。这套MATLAB源码里的优化模型本质是一个混合整数线性规划MILP问题——电池储能和抽蓄的运行状态需要0-1整数变量来描述其余部分则是线性约束。3.1 目标函数经济性与消纳率的权衡我把目标函数定义为实现系统日运行成本最小化具体包括四个部分第一是火电的运行成本用煤耗成本函数近似通常写成出力的一次函数或二次函数在MILP框架下做分段线性化处理。第二是电池储能的循环损耗成本按充放电电量乘以损耗系数计入。这相当于给电池“每一次动作”都贴上价格标签避免优化器做出过度频繁的充放电决策。第三是抽水蓄能的运维成本包括抽水耗电成本和设备维护成本分摊这部分相对固定按发电量和抽水量线性折算。第四是弃风弃光惩罚成本。这个项很关键——如果弃风弃光不产生成本优化器为了省钱可能会选择少发绿电加上一个足够高的惩罚系数之后模型会优先想尽办法消纳新能源。但系数不能盲目设高否则优化器会不惜代价地使用储能造成储能寿命损耗和运行成本的隐性上升。目标函数的写法如下% 目标函数min 火电成本电池损耗抽蓄运维弃风弃光惩罚 objective sum(sum(C_coal .* P_tg)) ... % 火电煤耗成本 sum(sum(C_bat .* (P_bat_ch P_bat_dis))) ... % 电池循环损耗 sum(sum(C_phs .* (P_phs_pump P_phs_gen))) ... % 抽蓄运维 sum(sum(C_curtail .* (P_w_cur P_pv_cur))); % 弃风弃光惩罚3.2 关键约束条件逐一拆解约束条件是这个模型的真正难点。我在建模时把约束分成四大类每一类都有具体的物理意义。第一类是系统功率平衡约束。任意时段内所有电源出力加储能净放电量必须等于负荷需求。这个约束是整个调度模型的中枢联结了所有设备变量。第二类是机组运行约束。火电机组有出力上下限和爬坡约束风电场和光伏电站的出力上限取决于预测值储能设备有充放电功率限制。其中爬坡约束特别容易写错——它不只是限制相邻时段出力差还要考虑火电从启动到额定出力的过程需要额外加启停状态变量。第三类是储能运行约束。电池储能要满足SOC递推关系即当前时段SOC等于上一时段SOC加上充电电量减去放电电量再除以容量。充放电互斥也需要约束避免优化器同时充电和放电来“刷数据”。这个互斥约束在MILP框架下通过0-1变量实现也是模型求解规模变大的主要原因。抽水蓄能的建模比电池复杂一个层级。它有三个运行状态发电、抽水、停机。我引入两个0-1变量来区分状态发电时水流从上部水库流向底部抽水时反向。同时要满足上下水库水量平衡关系即任一时刻上下水库总水量守恒且水库水量有上下限不能抽干也不能溢出。第四类是备用约束。系统需要预留一定比例的旋转备用容量防止风电光伏实际出力低于预测值或负荷突然升高。这个约束在调度模型里经常被忽略但忽略了就意味着模型“过于乐观”——实际运行时会面临很大的失负荷风险。3.3 时间尺度的选择日前调度还是日内滚动调度模型的时间尺度直接决定了对风光出力预测精度的依赖程度。我在源码中实现的是日前调度模型以1小时为时间间隔对全天24小时进行统一优化。这种模式的好处是全局最优性有保障——优化器可以看到一整天的负荷和出力曲线合理安排储能在低谷时段充电、高峰时段放电。但实际运行中风光预测误差是不可避免的。所以这个模型更适合作为“计划层”使用在日内还需要配合滚动修正或实时调整环节。我在源码里预留了修改接口如果想把它改造成日内滚动调度只需要把时间窗从24小时缩短到未来4到6小时并保留当前实际出力作为初始状态即可。4. MATLAB仿真的实现路径从数据生成到求解输出这一部分讲代码实现。网上有很多调度模型源码但大多数要么逻辑复杂看不懂要么没有考虑工程细节。我把自己的实现思路拆开讲重点说清楚每个模块解决什么问题。4.1 仿真数据的获取与生成做调度仿真第一步是搞定输入数据。我用的方法分两部分一部分是直接读取外部Excel数据文件里面存放了负荷的实测历史数据另一部分是用随机模型生成风速和光照强度时间序列。风速序列我用威布尔分布 自回归模型来生成保证风速在时间上有相关性而不是完全独立的随机数。光照强度则用晴空模型乘以随机云量系数模拟这样生成的光伏出力曲线既符合日出日落规律又有随机的波动特征。风电出力和光伏出力的计算公式比较标准风电功率根据风速和风机功率曲线插值得到光伏功率根据光照强度和光伏板效率计算。我把这些函数都封装成了独立的function模块方便替换成真实的风光出力数据。4.2 优化模型在MATLAB中的落地方式模型求解我选用了Yalmip工具箱 外部求解器的方案。Yalmip是一个建模层工具用起来比直接写矩阵约束直观得多。求解器方面CPLEX和Gurobi是商业求解器求解速度快但需要授权开源方案可以用GLPK或SCIP对于本项目的小规模问题也足够用。Yalmip的关键用法是定义决策变量、目标函数和约束集合然后调用求解器求解。以电池SOC递推为例% 电池SOC状态变量 SOC sdpvar(1, T); E_bat sdpvar(1, T); % 电池存储能量 % SOC递推关系 constraints [constraints, E_bat(:, t1) E_bat(:, t) eta_ch * P_bat_ch(:, t) - P_bat_dis(:, t) / eta_dis]; constraints [constraints, SOC(:, t) E_bat(:, t) / E_bat_max];抽蓄的三状态建模多一些步骤% 引入两个0-1变量u_pump抽水状态、u_gen发电状态 u_pump binvar(1, T); u_gen binvar(1, T); % 同一时刻只能处于一种状态停机、抽水或发电 constraints [constraints, u_pump(:, t) u_gen(:, t) 1]; % 抽水功率受状态变量约束 constraints [constraints, P_phs_pump(:, t) u_pump(:, t) * P_phs_pump_max]; constraints [constraints, P_phs_gen(:, t) u_gen(:, t) * P_phs_gen_max];4.3 主程序逻辑与核心代码片段整个仿真主程序的执行流程是设置系统参数 → 生成或读取负荷与新能源数据 → 构建决策变量 → 建立目标函数与约束集合 → 调用求解器求解 → 提取结果并绘图。核心代码片段里有一个容易被忽略的细节结果提取时不能直接使用求解器返回的变量值因为有些变量是松弛变量或辅助变量需要做一次映射处理。绘图部分我习惯用四个子图展示结果第一幅是各电源出力构成的堆叠面积图直观看到不同时段谁在顶出力第二幅是储能系统的充放电功率曲线和SOC曲线第三幅是负荷供需平衡情况包括是否存在失负荷或弃电时段第四幅是火电出力与爬坡情况。这四张图放在一起基本就能把一个调度日的运行情况讲清楚了。5. 典型日仿真结果分析与指标对比模型建好、代码跑通之后仿真分析才能真正体现研究的价值。我拿两个典型日做了对比分析一个是春秋季的大风多云日另一个是夏季的高温晴热日场景差异很能说明问题。5.1 场景设置两个典型日第一个场景代表“风大光弱”的情况。全天风速偏高风电出力充足中午时段光伏出力受云层影响波动明显。负荷曲线相对平稳全天负荷峰值出现在晚间。这个场景对储能的需求主要体现在中午的光伏波动平抑和傍晚的风电突然下降补偿。第二个场景代表“光强风弱”的情况。全天光照充足光伏在中午形成明显的出力高峰但风速偏低导致风电出力很少。负荷由于高温制冷需求全天水平较高晚高峰负荷尤其严峻。这个场景考验储能的“削峰填谷”能力——中午光伏高峰时储存多余电能晚高峰时释放。5.2 调度结果曲线怎么读第一场景的仿真结果非常有启发性。中午时段光伏出力波动剧烈电池储能快速响应SOC曲线呈现密集的小幅波动——这就是功率型储能在发挥平抑作用。到了下午到傍晚风电出力逐渐下降废弃矿井抽蓄开始接手在下午时段抽水蓄能晚间时段发电放水SOC曲线呈明显的“V”型走势。第二场景的结果则体现了另一种互补逻辑。光伏在10点到14点之间出力远大于负荷需求此时电池储能率先达到充电上限剩余的电量全部用于抽水蓄能。14点以后光伏出力衰减抽蓄开始放水发电配合火电共同满足晚高峰负荷。如果没有这个抽蓄晚高峰时段必须有大量火电快速爬坡甚至启动备用机组。5.3 几个核心指标的对比我把两种场景下的关键指标做了汇总优先看这几个维度弃风弃光率、储能利用率、系统运行成本和火电出力标准差。指标场景一大风多云日场景二高温晴热日弃风弃光率3.2%1.8%电池储能循环次数8次含部分浅充浅放5次抽蓄发电量占比22.5%34.7%火电出力标准差降低41% vs 无储能降低28% vs 无储能对比下来有几个明显结论。第一储能系统的加入显著降低了弃风弃光率尤其在光伏大发日弃电率从无储能时的15%以上降到2%以内。第二电池储能主要做“高频小幅”的调整抽蓄做“低频大幅”的搬移两者不存在明显冲突——这说明目标函数里的成本引导策略是有效的。第三火电出力标准差大幅下降说明储能在一定程度上替代了火电调峰这是系统经济性的主要来源。6. 复现这套源码时最容易踩的坑最后这部分的经验是我在不同数据集和参数下反复跑仿真后攒下来的。如果你打算直接拿这套源码修改使用下面几个坑值得提前注意。6.1 参数敏感性惩罚系数别乱调弃风弃光惩罚系数是整套模型里最容易“出戏”的参数。系数设置太低优化器会选择弃掉一部分新能源以节省储能损耗成本系数设置太高则会诱导优化器过度使用储能甚至让火电压出力来“保消纳”。我调试时的经验是先设定火电边际成本的两到三倍作为基准惩罚系数然后扫描10倍范围观察结果变化找到转折点后再微调。6.2 求解器与计算效率问题MILP问题求解时间是最大不确定因素。初始版本我用开源求解器跑一天24小时的模型在最坏情况下耗时超过半小时。后来做了两处优化一是把抽蓄的水量递推约束做了线性化处理减少了非线性约束的数量二是给电池储能设置了“禁止同时充电和放电”的约束时用了big-M方法效果明显但要注意M取值不能太大否则数值稳定性会恶化。如果还是觉得慢可以尝试把时间粒度从1小时放宽到2小时计算量可以压缩近一半。6.3 抽蓄三态建模的细节抽水蓄能的建模是整个项目里最容易出bug的地方。用两个0-1变量表示三状态时最常见的错误是忘了加“同一时刻只能处于一种状态”的互斥约束导致优化器同时让机组抽水和发电——这在物理上是荒谬的却等效于凭空多出一台“充放电设备”。还有个隐性问题抽蓄的发电效率和抽水效率都是指数级的折算关系在MILP框架下直接写乘除法会把问题变成非线性的需要预先用线性近似或分段线性化处理。6.4 值得继续扩展的方向这套源码的模型框架本身是开放的我总结了几条顺手就能做的扩展方向。一是把日前调度升级为“日前日内滚动”应对风光预测误差问题二是在目标函数中加入碳排放约束设置碳配额或碳价参数评估多能互补系统的减排价值三是加入储能容量优化变量让模型同时给出“配多少电池、建多大抽蓄”的最优方案作为规划工具使用。我在实际复现中发现对初学者来说最容易上手的方式不是从零改模型而是先把源码在默认参数下跑通一次把目标函数里每一项都注释清楚、理解透彻再逐步调整参数观察结果变化。当年我调参时踩过不少弯路最深刻的一条体会是储能调度问题里模型结构往往决定了可能性的边界参数只是在这个边界内寻找最优解所以建模阶段多想清楚每种储能在系统中的角色定位比后面花大量时间调参更重要。