news 2026/10/10 15:22:13

风-光-储互补调度建模与Matlab实现:含废弃矿井抽蓄

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
风-光-储互补调度建模与Matlab实现:含废弃矿井抽蓄

风电、光伏、储能,这三个词近几年几乎成了新能源领域的标配。但把三者放到同一个优化框架里做“互补调度”,尤其是把电池储能和废弃矿井改造的小型抽水蓄能电站放在一起联合运行,这里面的建模细节和工程约束比想象中要多不少。我最近正好完成了这样一个课题,用Matlab完整搭建了风-光-储(含废弃矿井抽蓄)互补调度模型,跑了典型日和参数灵敏度分析,整个过程踩了不少坑,也沉淀了一些可以直接复用的经验。这篇文章就把整套思路、数学模型、代码落地方式和调试技巧一次讲清楚,适合正在做新能源调度方向研究、或者准备用Matlab做优化模型的同学参考。

1. 为什么要把风电、光伏和两种储能放到同一个调度框架里

1.1 风光出力的时间错位与“反调峰”问题

先说说这个课题的出发点。风电和光伏虽然都是清洁能源,但它们的出力特性天然存在时间错位:风电往往夜间出力大、白天出力小,冬春季节整体偏强;光伏则是中午达到峰值、傍晚快速跌落,夜间完全为零。这种错位听起来像是“互补”,但在实际电网运行中反而制造了麻烦。

举个简单的例子:一个100MW风电场在夜间出力可能达到80MW,但此时负荷可能只有60MW;到了白天,光伏50MW在中午完全满发,风速却普遍偏低,风电可能只剩20MW。如果这两个电源直接并网,电网调度员就得在短时间内频繁调整火电或购买调峰服务,否则要么夜间多余的风电被弃掉,要么白天光伏高峰时段需要大量向下调节。

这就是所谓的“反调峰”特性——新能源出力曲线和负荷曲线并不吻合,而且波动幅度大。解决思路也很直接:引入储能,把多余的电先存起来,等负荷需要的时候再放出来。但储能的选择并不唯一,这也引出了下一节的问题。

1.2 电池与抽水蓄能:快慢搭配、长短结合

储能的类型很多,但适合大规模新能源配建的,主要还是电池储能(BESS)和抽水蓄能。这两类储能的特性差异非常明显,可以这样理解:

电池储能的优势是响应速度快,毫秒级到分钟级就能完成充放电切换,而且能量转换效率高,通常能达到85%到95%,布置灵活、不受地形限制。缺点是单位容量成本高,循环寿命有限(磷酸铁锂一般在6000到8000次),大规模配置时初始投资压力很大。

抽水蓄能正好反过来:启动速度以分钟计,响应速度不如电池,但单机容量可以做很大,寿命长达40到50年,单位千瓦时成本远低于电池。主要的制约是地理条件——要有合适的高低落差和水源,常规抽蓄电站选址非常挑剔。

所以在这个课题里,我选择把两者搭配使用:电池储能负责平抑快速波动、提供短时功率支撑;抽水蓄能负责日内或数小时尺度的大容量能量搬移。类比一下,电池像水杯,抽蓄像水桶,日常喝水用水杯,但真要储水浇地,得靠水桶。

1.3 废弃矿井改造小型抽蓄的工程可行性

常规抽蓄电站选址难,废弃矿井这种“特殊资源”就很有意思了。国内很多矿区开采了几十年后资源枯竭,留下了大量竖井、斜井和巷道。这些地下空间其实有很好的改造潜力:把矿井巷道作为下水库,在地面修建一个小型上水库,利用矿井原有的垂直深度形成水头,就构成了一座小型抽水蓄能电站。

这么做的好处有几个:一是废弃矿井本身已经具备地下空间,省去了新建地下洞室的高昂成本;二是井下结构相对封闭,渗漏问题比地面水库更容易控制;三是很多矿区靠近负荷中心或电网末端,电力接入条件不错。

能量规模也很好估算。假设可利用巷道容积为10万立方米,有效落差80米,综合转换效率0.7,理论储能量就是:

E = ρghVη ≈ 1000 × 9.8 × 80 × 100000 × 0.7 ≈ 5.5×10^10 J ≈ 152 MWh

150MWh的储能容量,已经相当于一个几十兆瓦时的电池储能站的规模,但单位成本低得多。当然,这只是理论值,实际还要考虑巷道渗水、岩体稳定性、泥沙淤积等一系列工程问题,但在调度建模层面,把它当作一个容量和功率受限的储能单元来刻画是成立的。

2. 各设备数学建模与关键参数

2.1 风电与光伏出力的简化建模

调度模型的精度取决于各设备模型的合理性,但也没必要过度复杂。在小时级调度里,风电可以用风速-功率曲线来描述。标准的风电功率曲线是分段函数:

P_w(v) = 0, v < v_cut_in 或 v ≥ v_cut_out

P_w(v) = P_r × (v - v_cut_in) / (v_r - v_cut_in), v_cut_in ≤ v < v_r

P_w(v) = P_r, v_r ≤ v < v_cut_out

其中v_r是额定风速,v_cut_in和v_cut_out分别是切入和切出风速。实际代码里可以用向量化计算,把风速数据一次处理成出力序列,速度很快。

光伏出力模型相对更直接,标准公式是:

P_pv = P_stc × (G_t / G_stc) × [1 + k × (T_cell - T_stc)]

其中G_t是实际辐照度,G_stc是标准测试条件辐照度(1000W/m²),T_cell是电池板温度,T_stc是标准测试温度(25°C),k是温度系数(通常为负值,约-0.004/°C)。电池板温度可以由环境温度推算,也可以直接用历史数据。

为什么要用这么简化的模型?因为调度模型的决策变量很多,如果每个时刻的光伏出力都依赖复杂的物理方程,求解时间会成倍增加。简化模型的误差在小时级调度可接受范围内,重点是捕捉出力的时序特征。

2.2 电池储能SOC与老化模型

电池储能建模的核心是SOC(荷电状态)的递推关系。设电池额定容量为E_bat,充电功率为P_ch(t),放电功率为P_dis(t),充放电效率分别为η_ch和η_dis,时间步长为Δt,则:

SOC(t+1) = SOC(t) + (η_ch × P_ch(t) - P_dis(t) / η_dis) × Δt / E_bat

这个公式体现了两个关键点:充电时实际存入电量是输入功率乘以效率(存进去比用掉的少);放电时消耗的电量要除以效率(放出来的功率折算成SOC的减少量要大一些)。效率不对称是电池真实特性的反映,建模时一定要区分。

SOC的上下限要留余量,频繁的过充过放对电池寿命损伤很大。我一般设置SOC下限0.1、上限0.9,这样30MW/60MWh的电池实际可用容量是48MWh。

另外一个容易忽略的问题是电池老化成本。在目标函数里如果不考虑电池循环损耗,优化器会倾向于频繁充放电,这不现实。做法很简单,给每次充放电加一个单位折旧成本,比如每MWh充放对应几十元的老化费用,数值根据电池价格和循环寿命折算。

2.3 矿井抽蓄的水量平衡与能量约束

抽水蓄能的建模比电池复杂一些,核心是水量平衡方程。设抽蓄储能量为S(t)(与水库水量成正比),发电功率为P_gen(t),抽水功率为P_pump(t),发电效率η_gen和抽水效率η_pump,则:

S(t+1) = S(t) - P_gen(t) × Δt / η_gen + η_pump × P_pump(t) × Δt

功率和流量的关系通过水头连接:

P = ρgQh

实际建模时不需要直接处理流量,把功率作为决策变量,储能量作为状态变量就够用。

矿井抽蓄有两个特殊约束需要注意。第一,上水库和下水库的容量通常不对称——下水库利用巷道空间,往往比上水库大。所以储能量上下限要分别设定,我常用S_min和S_max表示,其中S_max取决于上水库库容(因为上水库通常是瓶颈)。第二,抽蓄需要维持日循环,即每天调度周期结束时储能量要回到起始值,否则第二天就没法继续循环运行了。这个约束在数学上直接写成S(24) = S(0)即可。

还有一个容易出问题的地方:抽蓄机组的发电和抽水不能同时进行,这是一个互斥约束。后面在3.2节里我会讲怎么用整数变量处理。

3. Matlab调度模型实现:目标、约束与求解器选型

3.1 目标函数设计:三个指标怎么组合

调度模型的目标函数通常不是单一的,常见的有三个维度:系统运行成本最小化、可再生能源消纳最大化和负荷缺电率最小化。这三个目标在数学上可以通过加权组合成一个标量目标函数。

我采用的目标函数形式是:

min Σ C_grid(t) × P_buy(t) + C_bat_degrade × (P_ch(t) + P_dis(t)) + λ_curtail × Σ P_curtail(t) + λ_loss × Σ P_loss(t)

其中第一项是从电网购电的成本(如果允许向电网售电,则加上售电收益的负项),第二项是电池老化成本,第三项是弃风弃光惩罚,第四项是失负荷惩罚。λ_curtail和λ_loss是惩罚系数,取值不能太小,否则优化器会优先弃电而不是调度储能;也不能太大,否则会导致数值问题。我习惯把弃电惩罚设为购电价格的2到3倍,失负荷惩罚设为购电价格的10倍以上,这样储能资源会被充分调用。

这个目标函数已经覆盖了经济效益和消纳指标,在实际课题里比较容易出结果。如果想做更精细的多目标分析,可以用帕累托前沿的方法,但入门阶段加权法更实用。

3.2 关键约束条件的线性化处理

调度模型是一个混合整数线性规划(MILP)问题,原因在于充放电互斥、抽蓄两种工况互斥这类逻辑需要通过二进制变量来表达。这里重点讲几个典型约束的处理。

功率平衡约束是模型的主约束,表达式为:

P_w(t) + P_pv(t) + P_dis(t) + P_gen(t) + P_buy(t) = P_load(t) + P_ch(t) + P_pump(t) + P_sell(t)

左侧是各类电源出力,右侧是负荷和储能充电消耗。这里P_w(t)和P_pv(t)可以是预测值,但实际调度中为了考虑弃风弃光,我把它们拆分成“实际出力 + 弃电量”的形式,即实际出力P_w_actual(t) = P_w_forecast(t) - P_curtail(t),这样弃电量作为一个非负变量被引入目标函数。

充放电互斥约束需要引入二进制变量,典型做法是大M法:

P_ch(t) ≤ M × u_ch(t)

P_dis(t) ≤ M × u_dis(t)

u_ch(t) + u_dis(t) ≤ 1

其中u_ch和u_dis是二进制变量,M是一个足够大的常数。这里有个实操经验:M不宜过大,取该设备最大功率的1.1倍即可,否则会带来数值求解困难。

抽蓄工况互斥约束完全类似,只是把充放电换成了发电和抽水。此外还有SOC上下限、抽蓄储能量上下限、购售电功率上限、日循环水量平衡约束等,这些直接写成不等式或者等式即可。

3.3 Yalmip建模与求解器选择

Matlab里做优化建模,我首选Yalmip工具箱。Yalmip的语法非常简洁,特别适合把大型优化问题快速原型化。下面是调度模型核心部分的建模框架示例:

%% 定义决策变量 P_ch = sdpvar(T, 1); % 电池充电功率 P_dis = sdpvar(T, 1); % 电池放电功率 u_ch = binvar(T, 1); % 电池充电状态 u_dis = binvar(T, 1); % 电池放电状态 S_bat = sdpvar(T+1, 1); % 电池SOC P_pump = sdpvar(T, 1); % 抽蓄抽水功率 P_gen = sdpvar(T, 1); % 抽蓄发电功率 u_pump = binvar(T, 1); % 抽蓄抽水状态 u_gen = binvar(T, 1); % 抽蓄发电状态 S_psh = sdpvar(T+1, 1); % 抽蓄储能量 P_buy = sdpvar(T, 1); % 电网购电 P_curt = sdpvar(T, 1); % 弃电功率 %% 约束条件 Constraints = []; % 功率平衡 Constraints = [Constraints, P_w + P_pv - P_curt + P_dis + P_gen + P_buy == ... P_load + P_ch + P_pump]; % 电池SOC递推 Constraints = [Constraints, S_bat(2:end) == S_bat(1:end-1) + ... (eta_ch * P_ch - P_dis / eta_dis) * dt / E_bat]; % 电池充放电互斥 M = 30; % 电池最大功率 Constraints = [Constraints, P_ch <= M * u_ch, P_dis <= M * u_dis, ... u_ch + u_dis <= 1]; % 抽蓄工况互斥 Mp = 10; % 抽蓄最大功率 Constraints = [Constraints, P_pump <= Mp * u_pump, P_gen <= Mp * u_gen, ... u_pump + u_gen <= 1]; % 日循环约束 Constraints = [Constraints, S_psh(end) == S_psh(1)]; %% 目标函数(省略各变量定义细节) obj = sum(P_buy) + lambda_curt * sum(P_curt); %% 求解 ops = sdpsettings('solver', 'gurobi', 'verbose', 0); optimize(Constraints, obj, ops);

求解器方面,Gurobi是学术界和工业界都非常认可的MILP求解器,性能出色。学生或科研用户可以申请学术免费license。如果暂时没有Gurobi,Matlab自带的intlinprog也能处理中小规模问题,只是求解速度会慢不少。我在课题里同时测试了两种方案,小规模算例(24小时、节点数不多)两者差异不大,但参数灵敏度分析时要做几十次求解,Gurobi的速度优势就很明显了。

4. 仿真算例:一个典型日内的完整调度过程

4.1 算例参数与数据准备

为了让模型跑起来并验证效果,我设计了一个小型算例系统。基本参数如下表:

设备参数数值
风电场额定容量100 MW
光伏电站额定容量50 MW
电池储能功率/容量20 MW / 40 MWh
矿井抽蓄功率/储能量10 MW / 150 MWh
抽蓄水头—80 m
负荷峰值/谷值120 MW / 60 MW
调度周期时间分辨率24 h / 1 h

风速数据我用了一组典型夏季日数据:凌晨风速较高(7-9m/s),午后下降(4-5m/s),夜间回升。辐照度数据符合钟形曲线,中午12点达到峰值约900W/m²,傍晚18点降为0。负荷曲线早晚双峰,中午有短暂的午休低谷。这些数据虽然简化,但能体现风电、光伏和负荷错位的主要矛盾。

数据准备阶段有一个常见问题:风速、辐照度、负荷数据来自不同数据源,时间戳往往不同步。我建议进入模型前统一转化为同样的时间序列格式,缺失值用线性插值补齐,异常值(比如辐照度超过1200W/m²)直接剔除或者限幅。

4.2 典型日调度结果解读

调度结果很能说明问题。我把一天分成四个时段来分析:

凌晨0点到6点:负荷处于低谷(60-80MW),风电出力反而最高(70-90MW)。模型选择让电池从1点开始以20MW功率充电约2小时,抽蓄从3点开始以10MW功率抽水约4小时,把多余的风电储存起来。这个时段基本不需要从电网购电,弃电率被压到很低。

上午6点到12点:负荷逐步攀升到110MW,光伏出力从0逐渐升到45MW,风电下降。电池在7-9点开始放电,支撑早高峰;抽蓄在上午保持蓄水状态,等待下午的更大负荷。

中午12点到18点:光伏进入大发时段,12-15点之间光伏出力接近满发,负荷却因为午休出现小幅回落。此时模型选择给电池充电(约13-15点),同时抽蓄在16点后开始发电,配合光伏余量和电池补足晚高峰的负荷缺口。

傍晚18点到24点:光伏快速下降,负荷迎来晚高峰(120MW)。此时电池放电、抽蓄发电同时进行,加上风电夜间的回升,共同满足负荷。24点前后负荷回落到80MW,抽蓄在泵工况下抽水回蓄,为第二天做准备。

从结果数据看,无储能方案下弃电率约15%,纯电池方案弃电率降到6%左右,而混合储能方案弃电率可以压到3%以内。这验证了“多种储能配合”的优势——电池负责灵活快速响应,抽蓄承担大容量搬移,二者互补后系统调节能力明显增强。

4.3 参数灵敏度:电池容量和矿井水头的影响

参数灵敏度分析是这个课题里比较有说服力的部分。我重点考察了两个参数。

第一个是电池容量对系统性能的影响。把电池从20MW/40MWh增加到40MW/80MWh,弃电率从3.1%降到2.4%,继续增加到60MW/120MWh时,弃电率只降到2.2%。也就是说,电池容量翻倍带来的边际收益递减非常明显。这个结果提醒我们,储能配比不是越大越好,要结合弃电率、投资成本和运行效益综合确定。

第二个是矿井抽蓄水头的影响。在储能量公式里,E与h成正比,所以水头从80米提高到100米,同样的巷道容积储能量提升25%。但水头提高意味着机组需要的扬程增加,水泵和发电机的选型成本也会上升。灵敏度分析的结果是:水头每提升20米,系统弃电率大约下降0.5-0.8个百分点,效果存在但不算巨大。如果想继续提升消纳率,更有效的手段是扩大上水库库容或者优化电池容量配比。

5. Matlab编程中的常见坑与排查方法

5.1 求解器调用与license问题

Matlab里使用Yalmip+Gurobi的组合,最常见的坑就是Gurobi的license配置。安装完Gurobi后,需要把gurobi的matlab接口路径添加到Matlab搜索路径中,同时设置环境变量GRB_LICENSE_FILE指向license文件。很多人在第一步就卡住,报错信息往往是“Unable to locate Gurobi library”或者“License not found”。

我的建议是先运行gurobi_setup函数(Gurobi自带脚本),确认命令行能求解一个简单的lp模型,再到Yalmip里测试。如果Yalmip报错提示找不到求解器,可以用sdpsettings('solver','gurobi')强制指定,并检查yalmiptest是否通过。

如果没有Gurobi license,也不要用盗版破解,直接用intlinprog完全能跑。Yalmip只需把求解器参数改成sdpsettings('solver','intlinprog')即可,模型代码不需要任何改动。实际测试中,24小时、单节点的小算例,intlinprog跑几十秒也能出结果,完全够用。

5.2 模型求解慢的优化技巧

调度模型一旦加了二进制变量,求解时间就可能指数级增长。我遇到的典型问题是做72小时长周期调度时,变量量达到数千个,Gurobi默认参数求解要一两分钟,灵敏度分析做几十次就很痛苦。这里分享几个亲测有效的提速方法。

第一,合理设置MIPGap参数。Gurobi默认的MIPGap绝对值配置有时过于严格,工程上1%的相对gap通常已经足够。用sdpsettings('solver','gurobi','gurobi.MIPGap',0.01)可以显著加快求解收敛。

第二,避免过大的Big-M。有些同学习惯用1e6这样的值,结果不仅引入了数值病态,还让求解器在分支定界时大量试探。M取设备最大功率的1.1倍,既不影响可行性,又能让LP松弛更紧。

第三,尽量聚合约束。比如SOC的上下限约束,写成区间形式而不是拆成两个节点约束,变量规模可以压缩。Yalmip支持约束向量化,像0.1 <= S_bat <= 0.9这种写法就可以。

我还有一个经验是先把模型在24小时尺度上调通,确认约束无冲突、结果合理,再扩展到更长时间尺度。直接一上来就跑72小时,一旦约束写错很难定位。

5.3 结果可视化与数据对齐经验

Matlab做结果可视化其实很灵活,但调度结果有一点需要特别注意:堆叠图(stacked area plot)的显示顺序。功率平衡里各个电源有正有负,如果直接用area函数,容易出现负值覆盖正值的问题。我习惯把负荷和各个电源出力分别画,再单独画储能SOC曲线,这样信息更清晰。

还有一个细节是时间轴对齐。很多数据源用的是UTC时间,本地时间需要转换。气象数据尤其如此——风速和辐照度如果按照UTC导入,而负荷数据是本地时间,两者错位一两个小时就会导致调度结果失真。我建议在读取数据时统一转换为Matlab的datetime格式,并显式指定时区。

可视化输出方面,导出EPS或PDF时要注意字体设置,Matlab默认画图导出的中文字体经常乱码。简单方案是在绘图前统一设置字体:

set(groot, 'DefaultAxesFontName', 'Times New Roman'); set(groot, 'DefaultTextFontName', 'Times New Roman');

这样在学术论文里插图效果会好很多。

6. 一些个人经验和后续扩展方向

调度模型的输出质量很大程度上取决于输入数据的质量和约束设置的合理性。我建议各位拿到一个真实系统时,先不要急着把所有设备都加进去,先把风、光、负荷三条曲线画出来,肉眼判断负荷缺电时段和新能源盈余时段,再设计储能容量和调度策略——往往一眼就能看出储能该配多大、该怎么充放。

做这个课题时我自己最大的体会是,互补调度的核心价值不是“多发电”,而是“在正确的时间用正确的储能资源去填正确的缺口”。电池和抽蓄的组合,一个管灵活、一个管容量,协调好了,弃电率能压下去,高峰供电可靠性也能提上来。

后续想扩展的话,可以考虑这些方向:一是在模型里加入机组组合和火电备用,做多能源系统的联合优化;二是把风电和光伏的不确定性用场景法处理,做两阶段随机规划;三是引入强化学习做一个实时调度智能体,让它在历史数据中学习优化策略。每一块都是很好的延展课题。如果这篇分享对你有帮助,后面我可以再写一篇关于废弃矿井抽蓄经济性评估和容量优化配置的详细拆解,欢迎继续交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 15:21:53

Scala case class与模式匹配:从解构数据到优雅工程实践

Scala这门语言&#xff0c;最初抓住我的就是case class和模式匹配这套组合拳。在很多语言里&#xff0c;把一个嵌套的数据结构拆开&#xff0c;需要写一大堆样板代码——判断类型、强转、逐字段取值&#xff0c;稍不留神就会NPE。而在Scala里&#xff0c;通常一行模式匹配就结束…

作者头像 李华
网站建设 2026/10/10 15:19:39

从绘制三角形开始,吃透图形管线与Render Pass核心原理

绘制三角形这件事&#xff0c;听起来像是图形学入门的“Hello World”&#xff0c;但等我真的把一个三角形从顶点数据一路“画”到屏幕上&#xff0c;我才意识到自己对 Graphics pipeline&#xff08;图形管线&#xff09;和 Render Pass 的理解有多浅。前两年我在做一个跨平台…

作者头像 李华
网站建设 2026/10/10 15:16:03

dumptar实战:解析tar文件头与校验和,精准定位归档损坏

简介&#xff1a;《安安dumptar》是一份面向IT运维与开发者的数据备份工具资源&#xff0c;将Unix/Linux中tar的打包能力与dump的系统镜像能力结合&#xff0c;并针对“anan 三星”场景做了适配&#xff0c;可应用于设备数据保护、系统快照与日志收集等场景。资源整体为一个完整…

作者头像 李华
网站建设 2026/10/10 15:15:33

Surface Studio 1代换固态硬盘全记录:拆机步骤、系统迁移与性能实测

1. 一台老一体机凭什么还值得折腾Surface Studio 1代这台机器&#xff0c;放在今天看参数确实不算亮眼&#xff1a;第六代低压处理器、DDR4内存、一块 28 英寸 3:2 比例的触摸屏。但真正用过它的人都知道&#xff0c;那块屏幕的素质放到现在依然能打&#xff0c;45003000 的分辨…

作者头像 李华
网站建设 2026/10/10 15:13:00

Jakarta NoSQL Template API:Java NoSQL持久化的统一抽象与实践

说实话&#xff0c;Java 生态里做 NoSQL 持久化一直是件挺尴尬的事。关系型数据库有 JDBC 这个统一标准&#xff0c;换数据库只需要换驱动&#xff1b;但到了 NoSQL 这边&#xff0c;每个数据库都有自己的客户端 API&#xff0c;API 风格、异常模型、数据映射方式完全不一样。今…

作者头像 李华
网站建设 2026/10/10 15:11:53

Java异常处理从入门到实战:受检异常、自定义异常与资源关闭核心解析

1. 异常处理练习题的设计思路&#xff1a;为什么初学者总在这里栽跟头我带过的初学者里&#xff0c;十个有九个在学到异常处理这一章的时候开始怀疑人生。前面的语法、循环、数组都还好好的&#xff0c;一碰到try-catch-finally、受检异常和非受检异常这些概念&#xff0c;整个…

作者头像 李华