ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

计及氢能的综合能源优化调度Matlab实现与建模详解

计及氢能的综合能源优化调度Matlab实现与建模详解

最近因为一个模拟园区的项目,我把一套计及氢能的综合能源优化调度模型从论文里搬到了Matlab里,跑到能出结果、能出图、能复现的程度。说实话,这种题目看着“高大上”,拆开其实就是三件事:把设备建好模、把约束写对、把求解器喂饱。如果你也在碰综合能源优化调度,或者导师给了一个“氢能+多能互补”的题目,这篇内容应该能让你少走很多弯路。

这个研究的名字叫计及氢能的综合能源优化调度研究,翻译成大白话是:在一个同时有电、热、气(氢)等多种能源形式的园区或区域系统里,把氢能这条“电—氢—电”的链条考虑进来,用优化算法决定每个设备每个时刻的出力,在满足用能需求的前提下,让运行成本最低或者碳排放最少。适用人群很明确:能源方向的研究生、做园区/微网/区域综合能源的工程师、以及需要复现类似论文算法的人。这篇文章我就按建模、约束、编码、调参这条主线走,尽量讲人话,Matlab代码骨架也会直接放出来。

1. 为什么要研究“计及氢能”的综合能源系统

1.1 综合能源系统到底是个什么“系统”

你可以把一个综合能源系统想象成一个小区里的多能管家。它同时管理电网、热网、气网,谁便宜用谁、谁效率高用谁、谁污染小优先用谁。光伏和风电的预测出力会波动,电负荷和热负荷有峰谷,管家要做的就是在每个时刻决定:买多少电、烧多少气、蓄多少热、放多少电、制不制氢。

如果只看单一电网,那调度问题相对简单:负荷有多少,发电端就跟着补多少。可一旦把热负荷、冷负荷、天然气负荷都拉进来,问题就复杂了——热电联产机组发电的同时会产生热,电解槽耗电的但同时能产氢,燃料电池耗氢的但同时能发电。设备之间的出力不再是独立的,而是相互耦合的。综合能源优化调度,本质上就是在这些耦合约束下找一个让系统总运行费用最小的运行方案。

1.2 氢能在这盘棋里的特殊位置

氢能最特别的地方在于它同时具备“储能介质”和“燃料”两种身份。风大光电多的时候,电价便宜甚至可能过剩,这时让电解槽把多余的电变成氢,储存在储氢罐里;等到晚高峰电价贵、电负荷顶不住的时候,再把储氢罐里的氢拿出来给燃料电池发电,或者供给氢负荷、掺入天然气锅炉燃烧。这个链条相当于给可再生能源配了一个“可充电的燃气罐”,既解决了弃风弃光问题,又给系统增加了调节灵活性。

很多论文里提到的“电转氢”(Power-to-Hydrogen,P2H)就是这个思路。氢能链路的加入,让原本只能在“电—热”之间耦合的系统,多了一条“电—氢—热(电)”的深度耦合路径。它对调度结果的影响是实实在在的:谷时段可能因为制氢而抬高用电负荷,峰时段又因为燃料电池发电而降低购电压力,整个系统的负荷曲线会变得平缓很多。

1.3 这类课题适合谁,怎么选切入点

从我的经验看,这类题目特别适合两类人。一类是在校研究生,需要做毕业设计或者发小论文,题目既有工程背景又有算法深度,Matlab实现起来足够支撑一篇学位论文的核心章节。另一类是工程师,园区能源系统在规划阶段就需要评估“要不要上电解槽”“储氢罐配多大”“燃料电池在什么电价下有经济性”,这种调度模型直接就是决策工具。

切入角度通常有三个:最基础的是经济调度,目标函数就是运行成本最低,适合入门;进阶一点的是低碳调度,在目标里加碳排放成本,适合现在的主流研究方向;再深一点是多目标优化,成本、碳排放、弃风弃光率几个指标同时权衡,适合作为论文的创新点。第一次做的话,建议先从经济调度入手,跑通再往上叠。

2. 系统建模:先把每台设备的“脾气”摸清楚

2.1 电源、负荷与预测数据的给定方式

做日前调度,第一步要给定的是各时段的基础数据:24小时的电负荷曲线、热负荷曲线、风电和光伏的预测出力曲线、分时电价、天然气价格。这个模拟园区的典型配置是这样:光伏装机5MW,风电3MW,电负荷峰值约8MW,热负荷峰值约4MWth。风电晚上大早上小,光伏中午高峰,电负荷则是早晚两个峰——这些都是调度模型的外部输入,不是决策变量。

某模拟园区的分时电价设置得很典型:谷时段00:00—07:00和21:00—24:00为0.4元/kWh,平时段07:00—10:00和15:00—18:00为0.8元/kWh,峰时段10:00—15:00和18:00—21:00为1.2元/kWh。天然气价格按2.6元/m³折算,折合每千瓦时热值大约0.27元。这些数据直接决定了储氢、储电设备什么时候充电什么时候放电,所以取值一定要贴合实际。

2.2 电转氢链条:电解槽、储氢罐、燃料电池

电转氢链条是模型的核心,也是和普通电热耦合系统最大的区别。电解槽的输入是电功率P_el,输出是氢气流量;储氢罐负责存储;燃料电池输入氢气,输出电功率P_fc。三者之间由氢平衡方程串起来。

电解槽建模时,我习惯用一个固定效率η_el,一般在0.55到0.75之间。PEM电解槽效率偏高,碱性槽偏低。制氢量用公式F_h2_prod = η_el · P_el / LHV_H2计算,其中LHV_H2是氢的低位热值,约33.33 kWh/kg。换句话说,产1kg氢大约需要44到60kWh的电,具体看效率。燃料电池方向相反,耗氢量F_h2_consum = P_fc / (η_fc · LHV_H2),η_fc一般取0.45到0.55。

储氢罐的核心变量是罐内氢量SOC_h(t),单位直接用kg,动态方程是: SOC_h(t+1) = SOC_h(t) + F_h2_prod(t) · Δt − F_h2_consum(t) · Δt − F_h2_load(t) · Δt

其中F_h2_load是外部氢负荷,比如加氢站。储氢罐有容量上限和初始/终态约束,一般会要求调度周期结束时回到初始储量,防止模型“白嫖”储氢容量。

2.3 蓄电池与储热罐的动态约束

蓄电池的建模和储氢罐很相似,SOC_b(t+1) = SOC_b(t) + P_bess_ch(t)·η_ch·Δt − P_bess_dis(t)·Δt/η_dis。充放电效率η_ch和η_dis我都取0.95,容量配置1MWh,最大充放电功率0.5MW。这里有个常见处理技巧:如果模型允许同时充放电,线性规划会利用充放电损耗自动避免这个无意义操作,所以入门版本可以不额外加0-1变量;但严谨起见,后续可以加上“禁止同时充放电”的约束。

储热罐也一样,容量2MWh,最大充放热功率1MWth,蓄热效率0.9。它连接CHP机组和燃气锅炉,负责解耦“热需求”和“发电需求”。比如白天电负荷不高但热负荷还在,CHP如果按电出力走会多产热,多余的热就存进储热罐,晚上再放出来。这就是储热罐在调度里的价值。

2.4 热电联产和燃气锅炉的耦合建模

CHP机组是“一石二鸟”的设备,输入天然气,同时输出电和热。这里用最简单的定热电比模型:电效率η_chp_e取0.35,热电比α取1.2,那么热功率H_chp = α · P_chp,电功率P_chp本身是决策变量。最大电出力2MW,最大热出力2.4MWth。天然气耗量F_gas_chp = P_chp / η_chp_e,再折算成天然气体积。

燃气锅炉则是纯供热设备,输入天然气输出热,效率η_gb取0.9,最大热出力3MWth。天然气耗量F_gas_gb = H_gb / η_gb。可以用表格把设备参数固定下来,方便后面写代码时核对:

设备输入→输出效率/关键参数出力范围
电解槽电→氢η_el=0.650~2MW
燃料电池氢→电η_fc=0.50~1MW
储氢罐氢储存容量500kg初始50kg
蓄电池电双向效率0.95充放≤0.5MW,容量1MWh
储热罐热双向效率0.9充放≤1MWth,容量2MWh
CHP气→电+热电效率0.35,热电比1.2电≤2MW
燃气锅炉气→热效率0.9热≤3MWth

这里最容易被忽略的是单位统一。功率用kW或MW,能量用kWh或MWh,天然气用m³,氢用kg。制氢产率、耗氢率的计算里一旦把kW和kg的换算关系搞错,结果会偏差几十倍还不自知。

3. 优化模型:目标函数和约束条件是同一个硬币的两面

3.1 目标函数:成本都由哪些部分构成

优化调度的目标函数一般写成一个24小时的总运行成本,包含购电费用、购气费用、设备维护费用,以及如果要考虑低碳的话,再加碳排放费用。表达式可以写为:

min F = Σ [P_buy(t)·Δt·c_buy(t) − P_sell(t)·Δt·c_sell + F_gas_total(t)·Δt·c_gas + Σ_i c_maint,i·P_i(t)·Δt + e_total(t)·Δt·c_co2]

其中P_buy是购电功率,c_buy是分时电价;P_sell是向电网售电功率,c_sell是上网电价;F_gas_total是CHP和燃气锅炉的天然气耗量;c_maint,i是各设备的单位运维成本;e_total是碳排放速率,由电网购电对应的排放因子和天然气燃烧排放因子折算;c_co2是碳价。

注意,维护成本里的P_i要包含电解槽、燃料电池、蓄电池充放电、储热罐充放等所有设备。这些成本单价不高,但决定了调度方案会不会让储能设备频繁动作。碳价可以当成一个可调参数,从0元/吨扫到200元/吨,观察系统的购电和制氢策略怎么变化——这是论文里很常见也很出效果的敏感性分析。

3.2 核心约束:功率平衡、设备边界、储能动态

约束是整个模型真正的骨架。第一个是电功率平衡:

P_buy(t) + P_wt(t) + P_pv(t) + P_fc(t) + P_chp(t) + P_bess_dis(t) = P_load(t) + P_el(t) + P_bess_ch(t)

左边是供电侧,右边是用电侧。注意电解槽在这里是负荷,燃料电池是电源,方向别搞反。

第二个是热功率平衡:

H_chp(t) + H_gb(t) + H_tst_dis(t) = H_load(t) + H_tst_ch(t)

第三个是氢平衡,连接电转氢链条:

η_el·P_el(t) / LHV_H2 + F_h2_buy(t) = P_fc(t)/(η_fc·LHV_H2) + F_h2_load(t) + [SOC_h(t+1) − SOC_h(t)]

这里我把储氢罐变化量写到了等式右边,相当于储氢罐是一个“缓冲”节点。如果系统不允许外购氢,F_h2_buy就设为0。

除此之外还有大量不等式约束:每个设备的出力上下限、爬坡约束、储能的SOC上下限、以及储能的终态回到初态的等式约束。比如储氢罐终态要求SOC_h(24) = SOC_h(0),蓄电池也一样。这样调度方案才具有跨日可重复性,不会第一天把储能放空第二天就没得用了。

3.3 非线性环节的线性化处理

Matlab的linprog只能解线性规划,因此所有非线性项都要处理。最常见的几个来源:一是效率随负荷率变化,比如电解槽在低负载时效率明显下降,这时候可以用分段线性近似,把效率曲线拆成几段,每段用一个线性关系表达。二是乘积项,比如“是否启停”和“出力大小”相乘,需要引入0-1变量,用大M法线性化,交给intlinprog求解。

还有一个容易被忽略的细节是绝对值约束。比如希望系统购电曲线不要太振荡,目标里加入Σ|P_buy(t)−P_buy(t−1)|的惩罚项,这不是线性的,解决办法是引入辅助变量u(t),把目标拆成u(t)≥P_buy(t)−P_buy(t−1)和u(t)≥−(P_buy(t)−P_buy(t−1))两条约束。这样虽然变量变多,但模型还是线性规划,求解速度和稳定性都有保障。

4. Matlab落地:矩阵拼装与求解全流程

4.1 变量顺序定义与索引约定

写Matlab代码最怕的就是变量多了之后索引混乱。我的做法是固定一个“变量字典”,把每个设备定义成一组连续变量,每组内部按时段展开。假设T=24,变量顺序如下:

变量编号含义维度
1P_buy 购电功率24
2P_el 电解槽功率24
3P_fc 燃料电池功率24
4P_bess_ch 蓄电池充电24
5P_bess_dis 蓄电池放电24
6P_chp CHP电功率24
7H_chp CHP热功率24
8H_gb 锅炉热功率24
9H_tst_ch 储热充热24
10H_tst_dis 储热放热24
11SOC_b 蓄电池电量24
12SOC_h 储氢罐氢量24

总决策变量数就是12×24=288个。对linprog来说这是很小的规模,求解只需要不到一秒钟。关键的是提前定义一个索引函数,后面拼约束矩阵时直接调用:

T = 24; idx = @(k,t) (k-1)*T + t; % 第k个变量在第t时段的列位置 Nvar = 12 * T;

有了这个idx函数,任何一行约束都按照变量字典去填系数。这个方法看似笨,但实际用起来非常抗错,排查约束时对人名对列号就行。

4.2 目标函数和约束矩阵的拼装

目标函数系数向量f的拼装,就是把每个变量的单位成本系数填到对应位置。初始化和购电成本的部分这样写:

f = zeros(Nvar,1); c_buy = [0.4*ones(1,7), 0.8*ones(1,3), 1.2*ones(1,5), ... 0.8*ones(1,3), 1.2*ones(1,3), 0.8*ones(1,3)]; % 示例分时电价 for t = 1:T f(idx(1,t)) = c_buy(t); % 购电成本 f(idx(2,t)) = 0.02; % 电解槽维护成本 f(idx(3,t)) = 0.03; % 燃料电池维护成本 % 其余设备类似…… end

约束矩阵的拼装,先初始化Aeq和beq,再按行填。以电功率平衡为例:

Aeq = zeros(T, Nvar); beq = zeros(T,1); for t = 1:T Aeq(t, idx(1,t)) = 1; % P_buy Aeq(t, idx(3,t)) = 1; % P_fc Aeq(t, idx(6,t)) = 1; % P_chp Aeq(t, idx(5,t)) = 1; % P_bess_dis Aeq(t, idx(2,t)) = -1; % P_el Aeq(t, idx(4,t)) = -1; % P_bess_ch beq(t) = P_load(t) - P_wt(t) - P_pv(t); % 已知量移到右边 end

热平衡、氢平衡、储能动态约束都按同样的思路填进去。不等式约束填进A和b,设备上下限填进lb和ub,储能终态约束单独补几行等式。这里有个经验:把所有约束写完后,先检查Aeq的行数是否正确,再检查每行系数之和是否符合“能量守恒”的直觉,很多笔误在这一步就能抓出来。

4.3 求解器调用与结果可视化

模型拼装完成后,调用Matlab内置的linprog:

options = optimoptions('linprog', 'Algorithm', 'dual-simplex', 'Display', 'iter'); [x, fval, exitflag] = linprog(f, A, b, Aeq, beq, lb, ub, options); if exitflag ~= 1 error('求解失败,exitflag = %d', exitflag); end

如果用了二进制变量,换成intlinprog,调用格式里多一个intcon参数,指定哪些变量是整数/二进制。exitflag等于1代表求解成功,等于-2代表模型不可行,等于-3代表无界。这两类问题我在下一章专门讲排查方法。

求解完成后,把x按变量字典切回去:

P_buy = x(idx(1,:)); P_el = x(idx(2,:)); P_fc = x(idx(3,:)); % 其余同理……

绘图我用堆叠条形图看电功率平衡最直观:

figure; bar(1:T, [P_buy; P_wt; P_pv; P_fc; P_fc*0], 'stacked'); hold on; plot(1:T, P_load, 'k-', 'LineWidth', 2); legend('购电','风电','光伏','燃料电池','电负荷');

实际项目里我还会画氢罐SOC曲线、蓄电池SOC曲线、热功率平衡图和24小时总成本柱状图,这几张图放进论文里基本够用。

4.4 一个24小时算例的预期表现

用前面给的参数跑一版最简单的经济调度,结果通常能看到几个明显的规律:谷时段购电电价低且风电出力大,电解槽启动,储氢罐氢量稳步上升;峰时段燃料电池启动,配合蓄电池放电一起削减购电峰值;CHP机组基本跟着热负荷走,热负荷高时满发,多余的热存在储热罐里。调度方案里几乎不会出现“高价买电制氢、低价时段燃料电池发电”这种亏钱的操作,除非你把碳价设得很高,让系统宁可多花成本也要压低碳排放。

5. 调试路上我踩过的五个坑

5.1 常见报错与排查清单

第一次跑这种模型,报错几乎是必然的。我把最容易遇到的几类问题整理成了一张速查表:

现象可能原因排查方法
exitflag=-2,模型不可行功率平衡约束左右两侧不匹配,或储能终态约束设置不合理逐个去掉约束做二分定位;检查初始SOC与终态是否冲突
exitflag=-3,模型无界某个变量缺少上界,或等式约束漏掉了关联变量检查lb/ub是否覆盖所有变量;检查功率平衡行系数是否写反
求解很慢大M法的M值取得太大,或变量规模膨胀M值尽量取紧一点,能在约束成立范围内取小就取小
结果出现同时充放电没有加禁止同时充放的0-1约束入门版可接受;正式版用intlinprog加互斥约束
氢量结算对不上单位换算错误,kW与kg之间的能量密度关系搞混统一用LHV_H2=33.33kWh/kg校验每个时段氢平衡

其中模型不可行是最磨人的。我有一个笨但有效的办法:先把所有不等式约束放宽到物理极限,比如设备出力上限设成无穷大,看模型是否可行。如果可行,说明问题出在约束设置上;如果仍然不可行,那就是功率平衡方程本身写错了,回到能量守恒的直觉逐项检查。

5.2 参数敏感性分析

调度模型跑通之后,不要急着写论文,先做一轮参数敏感性分析。我常用的做法是固定其他参数不变,逐个扫描关键参数,看系统总成本和设备利用小时数怎么变。

最影响结果的三个参数:电解槽效率、氢价(如果考虑外购氢)、碳价。把电解槽效率从0.55提到0.75,制氢成本下降明显,电解槽的利用小时数会大幅提高,储氢罐的周转次数也增加。碳价从0升到200元/吨时,系统会逐渐把一部分高排放的电网购电量转移给燃料电池和CHP,购电曲线会发生变化。这些扫描结果画成二维曲线,直接就是论文里的敏感性分析图,也是答辩时最能展示工作量的一部分。

5.3 从入门版到进阶版:扩展路径

如果基础版本已经稳定跑通,后续扩展其实是一层层往上加模型复杂度。第一个扩展方向是考虑风光出力的不确定性,把确定性调度改成多场景随机优化,用历史数据聚类生成典型场景,目标函数变成期望成本。第二个方向是加碳交易机制,让碳排放配额成为约束或成本项。第三个方向是加网络潮流约束,从母线级能量平衡升级到节点级功率平衡,算直流潮流近似。第四个方向是做日内滚动调度,用15分钟尺度做模型预测控制。

这几个方向任选一个都能撑起论文的半壁江山。但我的建议是先把基础版打磨到“换套数据就能跑”的程度,再把代码模块化,扩展起来会顺手得多。

最后说点个人体会。这类题目最容易犯的错,不是模型不够高级,而是太想一步到位。先跑通一个“电加氢、氢发电”的最简版本,把矩阵拼装和变量索引理顺,再去堆CHP、储热、碳成本这些花活,效率会高很多。还有一个小技巧,代码里所有单位换算、初始条件、边界条件都要写清楚注释,尤其是氢的LHV、天然气热值这种常量,两周之后再翻自己的代码,你会感谢当时的自己。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进