做新能源消纳研究的人,十有八九都会撞上同一个问题:风电、光伏出力完全靠天吃饭,深夜的风、正午的太阳不会主动等电网需求。我去年接手了一个Matlab仿真项目,把风电、光伏、电池储能和一座由废弃矿井改造的小型抽水蓄能电站塞进同一个调度框架里跑,验证它们能不能互补运行、能不能把弃风弃光压下去。这篇文章就把这套系统的建模思路、调度策略、Matlab实现过程和踩坑记录完整整理出来,给打算做相关课题的研究生和刚入行的电力系统工程师一个可以直接参考的框架。文章偏重工程实现,不绕理论弯子,尽量把每一步“为什么这么做”讲透。
1. 风光储互补调度的起点:电网调节压力到底来自哪里
1.1 风光出力的波动性和反调峰特性是问题的根源
风电出力随风速变化,可能十几分钟就从额定功率跌到接近零,也可能半夜两点的出力比白天还高;光伏出力则严格跟随太阳,白天有、晚上无,阴雨天还会突然掉一半。这两类电源叠加在一起,会让区域电网的“净负荷”曲线变得非常不友好:白天光伏高峰时段,净负荷被压得很低;傍晚光伏退坡、负荷上扬,净负荷又快速拉升。业内常说的“鸭子曲线”,说的就是这种早高峰、下午深谷、晚高峰反弹的现象。
反调峰更麻烦。很多地区夜间风速反而大,风电出力高,但夜间负荷恰恰处于低谷。一边是过剩的风电,一边是没人用的电,电网调度只能下令弃风。光伏同理,午间出力最大的时候,如果本地负荷消纳不了,也得弃光。我自己在项目里见过最极端的一天,风电弃电率达到35%,光伏弃电接近20%,而同一时刻外部联络线还在从主网购电——因为负荷高峰和新能源出力高峰错开了。
1.2 储能调度的本质:在时间轴上搬移电能
储能解决的就是“错位”问题。把凌晨多余的风电存起来,留到早高峰放;把中午过剩的光伏存起来,留到傍晚放。本质上储能做的事情跟水库调节洪水没有区别,只不过对象从水变成了电,而且搬移的路径多了两条:一条是电池的化学路径,一条是抽水蓄能的水路。
但这里有个关键认知:储能不是万能的。受容量限制,它只能在有限的时间窗口内搬移电量;受功率限制,它只能在有限的速度内吞吐能量。所以调度要做的,是在每个时段决定“储多少、放多少、谁来储、谁来放”,让整个系统的功率平衡、电量平衡和费用平衡同时成立。所谓互补调度,就是利用不同储能形态在响应速度、容量规模、寿命成本上的差异,把它们组合起来,比单用一种储能更贴合真实负荷曲线。
1.3 这类研究最终要回答的问题
往小了说,这个研究要回答的是:给定一个包含风电、光伏、电池储能、废弃矿井小型抽水蓄能和负荷的微网/区域电网,未来24小时里,各机组各时段该发多少出力、储能该充多少放多少,才能让运行成本最低、弃电量最少,同时不违反所有物理约束。往大了说,它是在为新能源高渗透率场景下的调度策略做预演——现在用Matlab做的这个框架,换一套数据、换一个求解器,完全可以推广到更大规模的系统。
我把这个问题拆成了四块:怎么建模、怎么定目标、怎么求解、怎么验证。下面从储能这个容易被低估的环节说起。
2. 废弃矿井抽水蓄能:被低估的“地下电池”
2.1 常规抽水蓄能的地形门槛有多苛刻
常规抽水蓄能电站要求上水库和下水库之间有足够落差,通常需要几百米的水头,还要有合适的地质条件、水源条件和淹没区。这种站址在国内并不算多,而且建设周期长、生态敏感度高。正因为这样,抽水蓄能虽然技术成熟,却很难做到“每个需要的地方都能建一座”。
废弃矿井是另一个思路。煤矿关停后,地下巷道和采空区依然存在,竖井、斜井、平硐都还完好,地面有工业广场可以改造成上水库,井下采空区可以当蓄水容器。落差不需要太大——几十米就够跑一台小型机组。这种电站单机容量从几百千瓦到几兆瓦不等,恰好适合矿区微网、村镇电网这种小规模系统。我调研过几个示范项目,造价和建设周期比同容量常规抽蓄低不少,难点反而在地质稳定性和水质处理上。
2.2 废弃矿井改造机组的运行特点
小型抽水蓄能机组跟传统大机组比,运行逻辑是一样的:抽水工况消耗电能,把地面水库的水打到井下;发电工况放水,驱动水轮机发电。区别在于水头低,因而单位流量对应的发电功率小,但地下空间往往能提供很大的库容——存一趟水的能量可能足够系统用好几个小时。
建模时要注意它的“二元状态”:同一时段只能工作在抽水或发电,或者停机待命。一抽一发转换之间还有最小运行时间和状态切换次数限制,这是机组机械特性决定的。另外效率不能按常数简单处理,低水头小流量工况下,水泵和水轮机的效率会明显偏离额定点。实际建模时,如果取综合效率0.7到0.75,得到的调度结果和真机基本能对上。
2.3 电池储能与抽蓄的分工逻辑
把两种储能放在一个系统里,不是为了显示“我有两个储能”,而是让它们各干各的活。
电池的优势是响应快、能量转换效率高(往返效率普遍80%以上)、位置灵活,但成本高、循环寿命有限。抽蓄的优点是单次储能容量大、寿命长、度电分摊成本低,缺点是响应慢(从停机到满发往往需要几十秒到几分钟)、转换效率低、对地形有要求。互补关系很清楚:短时间的功率波动、秒级到分钟级的快速调节交给电池;跨时段的大规模电量搬移——比如凌晨抽水、晚高峰发电——交给抽蓄。这样电池不用频繁深度充放,寿命压力小;抽蓄不用频繁启停,机械损耗小。
我当时在设计调度模型时,给电池设了更紧的SOC上下限和更小的最大充放电功率,同时限制它一天内循环次数;给抽蓄则没有设循环次数限制,但加了状态切换惩罚,避免它每15分钟就切换一次工况。这样的规则约束,比单纯堆储能容量管用得多。
3. 建模细节:风光出力、电池与抽蓄的数学模型怎么搭
3.1 风电出力:实测序列和威布尔模拟两条路
风电建模可以走两条路。第一条路是用实测风速数据,按风电机组功率曲线折算成出力,再缩放到项目设定的额定容量。这条路最贴近实际,但要求数据时间分辨率和调度步长一致,否则后续会踩坑(后面单讲)。第二条路是假设风速服从威布尔分布,用逆变换采样生成风速序列,再用功率曲线求出力。第二条路适合做蒙特卡洛分析和多场景测试,缺点是没有具体日期的真实波动特征。
功率曲线可以近似写成分段线性函数:切入风速以下出力为零,额定风速以上出力恒等于额定值,切入和额定之间按三次方关系插值。我在Matlab里直接用插值函数处理离散功率曲线表格,避免手写复杂公式。需要注意机组爬坡限制——有的风电场调度模型会忽略这一点,导致仿真里出现“秒级跳变”的出力指令,实际风机会执行不了。
3.2 光伏出力:辐照模型和温度修正
光伏出力建模相对简单,核心公式是:
P_pv(t) = η · S · A · (G(t)/G_ref) · [1 + α·(T_cell(t) - 25)]
其中G_ref通常取1000 W/m²,α是功率温度系数,大约每升高1℃出力下降0.4%到0.5%。如果拿不到组件温度和辐照的详细数据,可以直接用归一化出力系数法:把一天的光伏出力求成0到1之间的归一化曲线,再乘以额定容量。这个方法虽然粗糙,但做调度研究已经够用,而且避免引入过多气象中间量。
我自己习惯把光伏出力按晴天模型生成,再叠加一个云层遮挡系数模拟多云场景。这样做的好处是能控制变量:先验证调度策略在“标准日”下的表现,再考察其在“劣天气”下的鲁棒性。
3.3 电池储能:SOC递推、充放电互斥与循环寿命
电池建模的核心是能量状态SOC的递推关系:
SOC(t+1) = SOC(t) + η_ch · P_ch(t) · Δt / E_rated - P_dis(t) · Δt / (η_dis · E_rated)
有两个容易被忽略的细节。第一,充放电效率不能只用一个值,充电和放电各自的效率不同,如果合并成一个往返效率,SOC递推会出现微小偏差,多日仿真时误差会累积。第二,充电功率和放电功率不能同时为正,必须在约束里加一个0-1变量来互斥,否则求解器会给出“一边充一边放”这种物理上荒诞、数学上却可能“最优”的解。
对于寿命约束,严谨的做法是引入循环次数累计成本,但这样模型会变成非线性。工程上更常用的做法是限制日充放电次数和SOC运行区间,比如要求SOC保持在15%到90%之间,一天内深度充放电不超过2个完整循环。这个简化的效果和精确寿命模型非常接近,计算负担却小得多。
3.4 抽水蓄能机组:双工况、水量平衡与库容约束
抽蓄的离散状态用一个0-1变量表示:1代表抽水,0代表不抽;发电同理。两个变量加一个约束,保证同一时段只能选一个。关键约束来自水量守恒:
V_res(t+1) = V_res(t) - P_gen(t)·Δt / (ρ·g·H·η_gen) + P_pump(t)·Δt·η_pump / (ρ·g·H)
这里V_res是上水库库存水量,H是平均水头。如果我简化模型,采用能量效率法——直接约定“抽水消耗功率P_pump时存入的等效能量为η_pump·P_pump,发电功率P_gen时消耗的等效能量为P_gen/η_gen”,水量守恒就变成等效能量守恒,处理起来非常干净。
还要注意库容边界。抽蓄的等效能量库容不是无穷大,调度必须保证任何时段的蓄能量不超过上下限,这和电池的SOC边界是同一类约束。我在项目里把抽蓄和电池统一成“储能设备”,只是参数不同,这样Matlab代码里可以复用一个储能模块,减少重复代码。
4. 调度策略:目标函数、约束条件和求解路线
4.1 目标函数的三种常见写法
第一步是决定“优化什么”。我见过三种主流目标函数:第一种是运行成本最小,包含向主网购电费用、储能运行损耗、弃风弃光惩罚;第二种是弃风弃光率最小,适合可再生能源消纳分析;第三种是碳排放最低,适合双碳背景课题。实际工程里最常用的是第一种,而且会叠加第二个目标的惩罚项,形成“经济+消纳”的双目标单优化。
我的做法是把弃风弃光量乘以一个惩罚系数,加进总成本。这个系数要调得足够大,让求解器“不愿意”弃电,但又不能大到把正常购电逼成不合理的储能充放。经过多轮试算,弃电惩罚系数取购电价格的1.5到2倍时,结果比较合理——系统会优先消纳新能源,但在极端情况下也不会做出经济性很差的决策。
4.2 约束条件:除了功率平衡,还有哪些容易漏
功率平衡是所有调度的第一约束:各电源出力加储能放电功率,等于负荷加储能充电功率加对外送电功率。但只有这一条远远不够。我整理过一份容易漏掉的约束清单,按重要性排下来是:
- 储能SOC终值约束。优化周期结束时,SOC要回到初值附近,否则多日滚动调度首尾不衔接,前一天把电放光、后一天全从外部买,结果失真。
- 爬坡约束。风电场、光伏逆变器、电池变流器都有出力变化速率上限,忽略爬坡约束会让优化解“过于激进”。
- 抽蓄状态切换次数限制。不加这个限制,求解器可能让机组每15分钟在抽水和发电之间来回切换,机械上根本不现实。
- 联络线传输功率限制和方向互斥。购电和售电不能同时发生,这个和储能充放电互斥是同一类约束。
- 备用容量约束。孤立微网至少要留一定比例旋转备用,否则风光骤降时系统没有缓冲。
4.3 求解方法:为什么我最终选择MILP
把目标函数和约束全部线性化之后,这个调度问题变成一个混合整数线性规划问题——连续变量负责功率和SOC,0-1整数变量负责电池充放电互斥、抽蓄工况选择、购售电方向。用Matlab自带的整数线性规划求解函数就可以处理几百个变量、上千条约束的规模,24时段调度基本秒级求解。
有人会问:为什么不用粒子群、遗传算法这类智能算法?我的看法是:如果问题规模不大、而且可以线性化,混合整数规划本身就能拿到全局最优解,可复现性也强;智能算法的优势在于处理非线性、非凸问题,但结果有随机性,论文审稿也容易被质疑。当前这个项目里,唯一比较强的非线性是抽蓄效率随水头变化,我做了分段线性近似,精度足够。如果后续想更精确,可以先用线性化求解得到调度方案,再代入非线性模型做修正,两步走。
5. Matlab实现:从数据准备到结果输出的完整流水线
5.1 程序框架和模块划分
我习惯把整个仿真分成四个模块:数据准备模块负责读入风电、光伏、负荷序列和储能参数;建模模块负责把目标函数和约束写成矩阵形式;求解模块调用整数规划求解器;后处理模块计算指标并出图。Matlab里用脚本加函数的方式组织,主脚本只负责按顺序调用,每个函数只做一件事,这样改参数和换数据都很快。
一个常见的错误是“所有代码写在一个超级脚本里”。第一轮流改参数要到处翻找,第二求解约束维数一变就报错。我强烈建议把约束建模写成独立的函数,输入是数据和参数,输出是Aeq、beq、A、b、lb、ub和整数变量索引,调试起来非常方便。
5.2 核心调度变量与关键代码片段
决策变量按时段展开,以24时段为例,变量向量包含:风机出力、光伏出力、电池充电、电池放电、抽蓄抽水、抽蓄发电、购电功率、售电功率、电池SOC、抽蓄蓄能状态,以及对应的0-1状态变量。把所有变量串联成一个一维列向量,然后按索引区间操作。
电池SOC递推和充放电互斥的约束可以这样写:
% 假设决策变量 x 的排列为: % [Pw(1:24), Ppv(1:24), Pch(1:24), Pdis(1:24), ... % Ppump(1:24), Pgen(1:24), Pbuy(1:24), Psell(1:24), ... % SOC(1:24), Eps(1:24), u_ch(1:24), u_dis(1:24), ... % u_pump(1:24), u_gen(1:24)] % SOC递推约束 % SOC(t+1) = SOC(t) + eta_ch*Pch(t)*dt - Pdis(t)*dt/eta_dis for t = 1:T-1 Aeq_row = zeros(1, nvars); Aeq_row(soc_idx(t+1)) = 1; Aeq_row(soc_idx(t)) = -1; Aeq_row(pch_idx(t)) = -eta_ch*dt/E_rated; Aeq_row(pdis_idx(t)) = dt/(eta_dis*E_rated); Aeq = [Aeq; Aeq_row]; beq = [beq; 0]; end充放电互斥约束则通过大M法实现:
% Pch(t) <= M * u_ch(t) % Pdis(t) <= M * u_dis(t) % u_ch(t) + u_dis(t) <= 1M取一个比最大功率略大的数即可。取值太大不会导致错误,但会让求解器数值性能下降,所以建议M不要超过最大功率的1.5倍。
5.3 可视化与指标导出
仿真跑完,我会画三组图:第一组是24小时的功率平衡堆叠面积图,风机、光伏、储能放电在零轴上方,负荷、储能充电、购电在零轴下方(或者反着画),一眼看出每个时段谁在供电、谁在耗电;第二组是电池SOC和抽蓄蓄能状态的双坐标图,观察两种储能工作区间是否合理;第三组是弃风弃光率的逐时段柱状图,方便定位“哪个时段消纳压力最大”。
指标计算单独写一个函数:总运行成本、弃风率、弃光率、削峰率、储能循环次数、自发自用率。这些指标直接生成表格输出,方便写报告时直接用。我建议把结果保存成结构体,字段名清晰,后续做多场景对比时批量处理。
6. 典型日仿真结果拆解:调度曲线能说明什么
6.1 无储能和有储能的出力平衡对比
我用一组模拟数据做了对照实验:同一组风光出力序列、同一组负荷曲线,分别跑“无储能”和“含电池+抽蓄”两个算例。无储能情况下,午间光伏高峰大量弃光,凌晨风电高峰大量弃风,傍晚负荷爬坡时全部靠外部购电,联络线功率尖峰非常突出。加入储能后,凌晨把风电存进抽蓄上水库——模拟中是抽水蓄能状态,白天光伏给电池充电,傍晚开始两组储能同时放电,负荷缺口被有效填补。
从数值上看,无储能算例的弃电率接近26%,含储能算例降到4.8%;外部购电峰值从620kW降到410kW。这里不展开所有数字,但一个重要的结论是:储能真正起作用的地方往往不是“平均时段”,而是那几个尖峰和深谷时段。
6.2 电池和抽蓄在时间轴上的分工验证
把两条SOC曲线叠在一起看,分工非常清楚。电池储能在白天光伏出力波动大的时段频繁小幅度充放,平滑出力曲线,近似一个快速调节器;抽蓄则在凌晨2点到5点持续抽水几个小时后,到傍晚18点到21点集中发电,扮演长时能量搬移的角色。抽蓄全天只切换两次工况,电池充放电切换则相对频繁,但每次充放电深度都不大——这正是我最初希望的运行模式。
这个结果说明,混合储能的互补不仅是理论上的“应该”,仿真里也确实能跑出预期效果。如果只用电池,SOC会频繁触顶触底,循环寿命压力大;如果只用抽蓄,晚高峰快速波动的部分它跟不上。两者配合之后,各自的工作点都落在适宜区间。
6.3 关键指标怎么算、怎么看
我习惯把指标分成四类:消纳类(弃风率、弃光率)、经济类(日运行成本、单位度电成本)、调节类(联络线峰值削减率、净负荷方差)、执行类(储能循环次数、抽蓄切换次数)。其中净负荷方差这个指标很多人会忽略,但它是衡量“储能对电网友好度贡献”的直观数字,方差下降30%以上说明平滑效果显著。
多场景对比时,我会固定储能参数不变,只改变风光渗透率,然后输出一个二维表格,横坐标是渗透率,纵坐标是上述四类指标。这种表格放在论文或汇报里比任何图表都直观——别人一眼就能看出,渗透率到哪个水平后,现有储能的调节能力不够了。
7. 实测中踩过的坑:数据、初值与求解器
7.1 风速数据时间分辨率不一致导致出力曲线畸形
第一次跑仿真,我把小时级风速直接线性插值到15分钟,结果风电出力曲线出现了大量“平台化”的假象——原本应有的风速波动全部被插值抹平,调度结果明显偏乐观。后来换成原始15分钟实测序列,曲线立刻变得毛糙,弃风率也上来了,这时候的调度结果才真正可信。所以第一条经验是:数据的时间一致性比数据来源更重要,宁可少用数据,也要保证分辨率统一。
7.2 电池SOC初值设置不当导致首日调度失真
这个问题非常隐蔽。最早我把电池SOC初值设为100%,也没有加SOC终值约束,结果优化结果出现了“先大放后小充”的诡异模式——因为初值满电,算法能白拿这些能量,第一天成本特别低。加上终值和初值相等约束之后,结果立刻正常。再往后我又加了一步:先跑一次不含储能的经济调度,把风光出力均值算出来,把SOC初值和终值都设置在50%附近,这样整个调度窗口首尾都能衔接。这个细节在滚动调度里尤其重要。
7.3 整数变量增多后求解速度骤降的处理
把电池充放电互斥、购售电互斥、抽蓄双工况全部加入后,整数变量从0增加到了上百个,求解时间从不到1秒涨到几十秒,个别边界场景还会报“求解器达到最大节点数”。我的处理办法有三个:一是把无需松弛的大M值尽量缩小;二是调整目标函数的数值量纲,把功率从瓦改成千瓦、成本从元改成百元,减小矩阵条件数;三是设置求解器相对间隙为1%,允许损失极小精度换求解速度。三个措施加在一起,最复杂的算例也能在10秒内稳定求解。
最后再分享一个小经验:跑这类仿真,不要把精力全扑在算法炫酷上,先把数据洗干净、初值设合理、约束条件列全,大部分“结果不合理”的问题其实都出在这三件事上。我做完这个项目最大的感受是——风光储互补调度真正难的,不是数学公式,而是让模型每一步都贴近物理现实。这套Matlab框架现在还在我手上不断改,加入滚动时域修正、多场景随机优化之后,它还能延伸到更复杂的系统里。