
综合能源系统调度这种题目论文里写得再漂亮落到代码上往往就是一连串的平衡约束、爬坡约束和成本项。最近我在做的这个研究方向是用信息间隙决策理论IGDT去处理风光出力和负荷预测误差同时在系统里加入碳捕集与煤制氢的耦合整体走一遍“建模—求解—Matlab代码实现”的完整流程。整套东西跑完之后我对这个组合的理解比看文献时深了不少也踩了一些值得记录下来的坑。这套研究适合谁参考一类是做综合能源系统优化调度的研究生尤其是准备拿IGDT当创新点的另一类是研究低碳电力或氢能耦合方向的工程师想看看碳捕集和煤制氢在一个模型里到底怎么关联。我的经验是IGDT是一个被低估但非常好用的不确定性处理工具它不需要精确概率分布也不需要人为构造大量场景只需要一个预测值和一组可容忍的偏差半径就能给出兼顾鲁棒性和经济性的调度方案。这篇博文我会从研究逻辑、模型构建、IGDT求解框架、Matlab代码实现、常见问题五个方面展开尽量把关键的“为什么”和“怎么调”都讲清楚。1. 项目定位与研究思路1.1 为什么要在综合能源系统里同时引入碳捕集和煤制氢很多做IES调度的朋友模型里已经有风电、光伏、燃气轮机、电锅炉、储能这些常规设备了。这时候再加入碳捕集CCS和煤制氢第一反应往往是“这不就是堆设备吗”。实际不是这两个环节耦合起来有明确的物理和经济学逻辑。先说碳捕集。燃煤或燃气机组是系统里的主力电源也是主要碳排放源。碳捕集装置投运后机组发电的同时可以用化学吸收法、膜分离等方法把烟气里的CO2捕集下来。但捕集不是免费的它要消耗能量通常表现为电耗或热耗也就是所谓的“能量惩罚”。比如一台200MW的燃煤机组捕集率设为0.9碳排放强度约0.82 tCO2/MWh单位捕集能耗0.25 MWh/tCO2的话捕集能耗占发电出力的比例大约是0.9×0.82×0.25≈18.5%。这意味着机组净外送功率会明显下降。可换个角度看碳捕集装置本身就是一个可调节的“电-碳”耦合负荷新能源出力高时可以提高捕集功率来削峰新能源出力低时适当降低捕集功率保证供电灵活性很好。再说煤制氢。氢能在综合能源系统里的角色越来越重要可以供给氢燃料汽车、氢燃气轮机也能通过储氢罐平抑波动。煤制氢是目前成本最低的规模化制氢方式之一单位投资和运行成本都比电解水制氢低但缺点是碳排放高。煤气化得到的合成气经过水煤气变换后会产生高浓度CO2这部分CO2如果直接排放系统碳成本会很高。把它和碳捕集装置耦合起来相当于让高浓度CO2走更经济的捕集路径实现“低碳氢”甚至接近“零碳氢”的生产。这个耦合逻辑就是本项目最核心的思路煤制氢为系统提供低成本氢源碳捕集装置消纳煤制氢和燃煤机组的高浓度CO2两者配套形成“电-碳-氢”协同。1.2 为什么选择IGDT处理不确定性综合能源系统调度里不确定性来源很多风电出力、光伏出力、电负荷、热负荷、氢负荷、批发电价甚至碳价都会波动。处理不确定性的主流方法有三类随机规划、鲁棒优化、IGDT。随机规划最理想需要知道各不确定量的概率分布然后再生成大量典型场景。问题是现实中预测误差的分布往往很难准确刻画场景数量一多计算量也上来了。鲁棒优化则反过来只需要确定一个不确定集合但它追求的是“最坏情况下一定可行”结果往往偏保守运行成本高得让人不太愿意接受。IGDT卡在两者中间它不要求概率分布只要求你心里有一个“预测值”和一个“信息间隙”的概念。所谓信息间隙就是你掌握的信息和真实情况之间的差距。IGDT要做的事情是给定一个可以接受的性能损失范围比如成本比基准解最多高20%反过来求系统能容忍多大的信息间隙也就是不确定性半径。它给决策者提供的不是一个固定方案而是一条“经济性换鲁棒性”的权衡曲线非常实用。三种方法的对比我放在表格里方便大家比较方法需要输入优点缺点随机规划概率分布或典型场景期望意义下的最优分布难获取场景多时计算量大鲁棒优化不确定集合绝对保守安全余量大方案可能过度保守经济性差IGDT预测值偏差半径不依赖概率分布提供风险-成本权衡依赖目标对不确定变量的单调性假设所以我的选择很明确在研究初期数据不充分、概率分布难以确定的时候IGDT是处理风光出力波动和负荷偏差的实用武器。这里也顺带提醒一句用IGDT的时候要先确认目标函数和约束里各个不确定变量的“最坏方向”是清楚的这个后面第三节会详细讲。2. 关键设备建模与耦合机制2.1 系统总体结构与能量流建模之前先把系统结构理清楚。我设计的综合能源系统包含电力、热力、氢气、碳四个维度的能量流主要设备包括风电、光伏清洁电源出力随机波动燃煤机组带碳捕集主力电源承担大部分电负荷和碳捕集能耗燃气轮机快速调节电源弥补新能源波动煤制氢装置产生氢气同时产出高浓度CO2电解水制氢装置利用富余清洁电力制氢储氢罐/氢燃料电池氢气时移和再发电电锅炉电转热消纳新能源碳捕集装置捕集燃煤机组和煤制氢过程产生的CO2能量流关系大概是电力经由风电、光伏、燃煤机组、燃气轮机、电锅炉、电解水制氢等形成电平衡煤制氢和电解水制氢产生氢气进入储氢罐再供给氢负荷或氢燃料电池燃煤机组和煤制氢产生的CO2进入碳捕集装置捕集后封存或利用。这样一个多能互补结构问题约束会比单一电网调度复杂很多但也正是这种复杂性给了优化调度发挥空间。2.2 碳捕集机组与煤制氢装置的建模细节碳捕集机组需要抓住三个关键量发电功率、实际碳排放量、捕集能耗。我习惯用下面的简化模型燃煤机组实际碳排放量E_g等于碳排放强度e_g乘以发电量P_g再乘上1-捕集率η_ccs也就是实际排放量 e_g × P_g × (1 - η_ccs)。捕集到的CO2量为C_cap e_g × P_g × η_ccs。这部分捕集需要电耗即P_ccs λ_ccs × C_cap其中λ_ccs是单位捕集能耗。净出力P_net P_g - P_ccs。这里有个容易被忽略的点碳捕集装置的捕集率不是固定不能变的它可以作为一个决策变量在约束范围内调节。你说它是负荷也行说它是“减排设备”也行。实际建模时我会给捕集率设定区间比如0.5到0.95同时给捕集能耗设置对应的爬坡约束避免捕集功率剧烈波动。煤制氢装置模型相对简单。输入是煤耗量F_coal输出是氢气产量H_h2 η_h2 × F_coal同时产生CO2排放E_coal e_coal × F_coal。这里的排放强度比燃煤机组高很多但好在煤制氢尾气CO2浓度高捕集成本反而低。在模型里可以把这部分CO2直接导向碳捕集装置设置一个捕集比例μ_coal那么煤制氢的实际排放就是E_coal × (1 - μ_coal)。这样建模以后煤制氢的“高碳”问题就被碳捕集吸收了一部分系统总体碳排放可以明显降下来。2.3 目标函数与主要约束优化调度的目标函数我采用的是运行成本最小化模型min C_total C_grid C_fuel C_om C_co2其中C_grid是向上级电网购电成本C_fuel是燃煤机组和燃气轮机的燃料成本C_om是各设备运行维护成本C_co2是碳排放交易成本。碳排放交易成本的表达式为C_co2 λ_co2 × (E_total - E_quota)λ_co2是单位碳价E_total是系统实际碳排放E_quota是系统获得的免费碳排放配额。如果实际排放小于配额这项就是负值相当于卖碳收益如果大于配额就要掏钱买碳。这个机制把碳捕集的减排收益直接体现到目标函数里是碳捕集装置参与经济调度的核心驱动力。主要约束包括四类第一类是电功率平衡风电、光伏、各机组出力加上储能放电等于负荷加上各设备耗电第二类是设备出力上下限和爬坡约束燃煤机组、燃气轮机、电解槽、碳捕集装置都要有第三类是储能约束储氢罐和电储能的SOC递推关系以及容量限制第四类是碳约束包括碳排放配额、碳捕集装置捕集能力限制、CO2储罐容量限制。这些约束一起构成了确定性基准模型。3. IGDT两阶段求解框架3.1 基准确定性模型的求解IGDT的完整思路是两步走第一步先求确定性基准解。把所有不确定性参数取预测值风电光伏出力用预测曲线负荷也用预测曲线然后求解目标函数得到一个基准最优成本C0。这个C0是后续IGDT模型的参照物。有了C0之后第二步就是让决策者回答一个关键问题你愿意为了让系统在面对不确定性时更稳健最多付出多少额外成本这个“愿意付出的比例”就是成本偏差系数σ。比如σ0.2意思是你允许系统在最坏情况下成本比基准最优高出20%。反过来问在这样的成本预算约束下系统能容忍风光出力和负荷的预测偏差到底有多大这个最大可容忍偏差就是IGDT的鲁棒半径α。我把基准模型的Matlab实现放在第四节先说说理论框架。3.2 鲁棒IGDT模型的构建与求解鲁棒IGDT模型的数学形式可以写成决策变量包括所有调度变量X和不确定性半径α目标函数是max α约束是对任意偏差不超过α的不确定参数实现系统总成本不超过(1σ)C0且所有运行约束可满足。这里最关键的问题是怎么把“对任意偏差不超过α”这个无限约束转换成可计算的有限约束。好在综合能源系统模型里目标函数对风电、光伏、负荷的单调性通常很明确。风电光伏出力越大购电成本越低负荷越大购电成本越高。所以在鲁棒模型里最坏情况就是风电、光伏取预测值的下界(1-α)倍负荷取预测值的上界(1α)倍。把这三个边界值代入功率平衡和目标函数成本计算里问题就变成了一个确定性的优化问题只是决策变量变成了α加原调度变量。鲁棒IGDT模型形式如下max αs.t.C_total(X, P_w^lb, P_pv^lb, P_L^ub) ≤ (1 σ) * C0g(X, P_w^lb, P_pv^lb, P_L^ub) ≤ 00 ≤ α ≤ α_max其中P_w^lb P_w_f × (1-α)P_pv^lb P_pv_f × (1-α)P_L^ub P_L_f × (1α)。这样得到的α越大说明系统应付预测偏差的鲁棒能力越强。3.3 机会IGDT模型的构建与求解IGDT还有另外一个视角叫机会函数。它回答的问题是如果在现实中不确定性带来的不是坏消息而是好消息——比如风电实际出力比预测高多了、负荷实际比预测低——系统有没有机会做到比基准成本更低的运行这个机会有多大取决于信息间隙β的大小。机会IGDT模型追求的是“付出最低的成本改善希望”数学上写成min βs.t.C_total(X, P_w^ub, P_pv^ub, P_L^lb) ≤ (1 - σ) * C0g(X, P_w^ub, P_pv^ub, P_L^lb) ≤ 0其中P_w^ub P_w_f × (1β)P_pv^ub P_pv_f × (1β)P_L^lb P_L_f × (1-β)。简单说鲁棒模型是“防守”机会模型是“进攻”。一套完整的IGDT分析应该把鲁棒曲线和机会曲线都画出来。鲁棒曲线上升说明付出额外成本能换来更大的不确定性容忍度机会曲线下降说明对成本改善的期待越高现实中需要运气越好。两条曲线合在一起决策者就能从经济性和风险两个角度综合选择调度方案。4. Matlab代码实现细节4.1 代码结构与核心数据结构Matlab实现我建议分成三个文件主程序run_igd_ies.m、数据准备文件case_data.m、求解函数文件solve_deterministic.m和solve_igd_robust.m。这样结构清晰便于调参复现。核心数据结构我用一个data结构体装载所有参数% case_data.m data.T 24; % 调度周期小时 data.P_w_f [100 105 98 90 ...]; % 风电预测出力MW data.P_pv_f [0 0 0 0 5 20 ...]; % 光伏预测出力MW data.P_L_f [120 115 110 ...]; % 电负荷预测值MW data.P_g_max 200; % 燃煤机组上限MW data.P_g_min 60; % 燃煤机组下限MW data.e_g 0.82; % 燃煤机组碳排放强度tCO2/MWh data.eta_ccs 0.9; % 碳捕集率上限 data.lambda_ccs 0.25; % 单位捕集能耗MWh/tCO2 data.eta_h2 0.7; % 煤制氢效率kg H2/kg 煤 data.e_coal 3.0; % 煤制氢碳排放强度tCO2/t 煤 data.c_coal 800; % 煤价元/t data.c_carbon 60; % 碳价元/t data.c_grid ...主程序框架% run_igd_ies.m clc; clear; close all; data case_data; % 第一步求解确定性基准模型 [C0, x0] solve_deterministic(data); % 第二步求解鲁棒IGDT模型扫描多个sigma值 sigma_grid 0.05:0.05:0.3; alpha_opt zeros(size(sigma_grid)); for i 1:length(sigma_grid) alpha_opt(i) solve_igd_robust(data, C0, sigma_grid(i)); end % 绘图sigma-alpha曲线 figure; plot(sigma_grid, alpha_opt, -o); grid on; xlabel(成本偏差系数 \sigma); ylabel(鲁棒半径 \alpha); title(IGDT鲁棒性-经济性权衡曲线);4.2 YALMIP建模与求解器配置调度模型本质上是混合整数线性规划因为机组启停状态往往要用二进制变量。我不建议手写矩阵系数直接用YALMIP建模会快很多。求解器方面如果只是线性规划用Matlab自带的linprog和intlinprog就能跑但要处理几千个变量和约束时用Gurobi或CPLEX更稳。我的建议是% 求解器配置 ops sdpsettings(solver, gurobi, verbose, 2, gurobi.MIPGap, 0.01);MIPGap设置成1%左右可以在精度和速度之间取得平衡。如果你没有Gurobi把solver换成cplex或者intlinprog也可以代码主体不用改这就是YALMIP的好处。4.3 确定性模型求解函数确定性模型把所有预测值当作已知量求解最小成本C0。function [C0, x] solve_deterministic(data) T data.T; % 定义决策变量 P_w sdpvar(1, T); % 风电出力 P_pv sdpvar(1, T); % 光伏出力 P_g sdpvar(1, T); % 燃煤机组出力 P_t sdpvar(1, T); % 燃气轮机出力 P_ccs sdpvar(1, T); % 碳捕集装置耗电 P_h2 sdpvar(1, T); % 煤制氢装置耗电 P_el sdpvar(1, T); % 电解水制氢耗电 P_dis sdpvar(1, T); % 储能放电 P_ch sdpvar(1, T); % 储能充电 SOC sdpvar(1, T1); % 储能SOC C_cap sdpvar(1, T); % 碳捕集量 E_real sdpvar(1, T); % 实际碳排放量 Constraints []; % 功率平衡约束确定性模型用预测值 Constraints [Constraints, ... P_w P_pv P_g P_t P_dis ... data.P_L_f P_ccs P_h2 P_el P_ch]; % 风电机组出力约束确定性模型只能等于预测值可加小范围调节 Constraints [Constraints, P_w data.P_w_f]; Constraints [Constraints, P_pv data.P_pv_f]; % 燃煤机组出力上下限 Constraints [Constraints, P_g data.P_g_min, P_g data.P_g_max]; % 碳捕集装置模型 Constraints [Constraints, C_cap data.e_g .* P_g .* data.eta_ccs]; Constraints [Constraints, P_ccs data.lambda_ccs .* C_cap]; % 储能约束 Constraints [Constraints, SOC(2:T1) SOC(1:T) P_ch - P_dis]; Constraints [Constraints, SOC 0, SOC data.SOC_max]; Constraints [Constraints, P_ch 0, P_dis 0]; Constraints [Constraints, P_ch data.P_ch_max]; Constraints [Constraints, P_dis data.P_dis_max]; Constraints [Constraints, SOC(1) data.SOC_init, SOC(T1) data.SOC_init]; % 目标函数购电成本 燃料成本 运维 碳交易 C_grid sum(data.c_grid .* P_w); % 这里简化实际购电成本对应上级电网购电 C_fuel sum(data.c_coal .* P_g data.c_gas .* P_t); C_om sum(data.c_om_g .* P_g data.c_om_t .* P_t data.c_om_ccs .* C_cap); E_total sum(E_real); C_co2 data.c_carbon * (E_total - data.E_quota); C_total C_grid C_fuel C_om C_co2; % 求解 optimize(Constraints, C_total, ops); C0 value(C_total); x.P_w value(P_w); x.P_g value(P_g); x.P_ccs value(P_ccs); end这段代码有几个细节值得注意碳捕集能耗P_ccs是通过C_cap和λ_ccs耦合到功率平衡里的这会同时影响机组净出力储能SOC用T1个变量避免初始和末端状态冲突目标函数里的购电成本我做了简化实际项目中上级电网购电量和分时电价需要单独建模。4.4 鲁棒IGDT模型的核心代码实现鲁棒IGDT模型的关键是把风电、光伏预测值替换成带(1-α)系数的下界把负荷替换成带(1α)系数的上界。这里要特别小心双线性项α和预测值相乘的时候预测值是常数所以没问题但是绝对不能出现α乘决策变量否则模型就变成非线性甚至非凸Gurobi也解不了。function alpha_opt solve_igd_robust(data, C0, sigma) T data.T; alpha sdpvar(1, 1, full); % 不确定性半径 % 定义原调度决策变量 P_w sdpvar(1, T); P_pv sdpvar(1, T); P_g sdpvar(1, T); P_t sdpvar(1, T); P_ccs sdpvar(1, T); P_h2 sdpvar(1, T); P_el sdpvar(1, T); P_dis sdpvar(1, T); P_ch sdpvar(1, T); SOC sdpvar(1, T1); C_cap sdpvar(1, T); E_real sdpvar(1, T); % 最坏情况下的不确定参数取值 P_w_rb data.P_w_f .* (1 - alpha); % 风电取下界 P_pv_rb data.P_pv_f .* (1 - alpha); % 光伏取下界 P_L_rb data.P_L_f .* (1 alpha); % 负荷取上界 Constraints []; % 功率平衡最坏组合 Constraints [Constraints, ... P_w P_pv P_g P_t P_dis ... P_L_rb P_ccs P_h2 P_el P_ch]; % 风电光伏实际出力不低于下界不高于上界 Constraints [Constraints, P_w P_w_rb, P_w data.P_w_f .* (1 alpha)]; Constraints [Constraints, P_pv P_pv_rb, P_pv data.P_pv_f .* (1 alpha)]; % 燃煤机组与碳捕集模型同确定性模型 Constraints [Constraints, P_g data.P_g_min, P_g data.P_g_max]; Constraints [Constraints, C_cap data.e_g .* P_g .* data.eta_ccs]; Constraints [Constraints, P_ccs data.lambda_ccs .* C_cap]; % 储能约束 Constraints [Constraints, SOC(2:T1) SOC(1:T) P_ch - P_dis]; Constraints [Constraints, SOC 0, SOC data.SOC_max]; Constraints [Constraints, P_ch 0, P_dis 0]; Constraints [Constraints, P_ch data.P_ch_max, P_dis data.P_dis_max]; Constraints [Constraints, SOC(1) data.SOC_init, SOC(T1) data.SOC_init]; % 不确定性半径范围 Constraints [Constraints, alpha 0, alpha data.alpha_max]; % 成本约束最坏情况下总成本不超过 (1sigma)*C0 C_grid sum(data.c_grid .* P_w); C_fuel sum(data.c_coal .* P_g data.c_gas .* P_t); C_om sum(data.c_om_g .* P_g data.c_om_t .* P_t data.c_om_ccs .* C_cap); E_total sum(E_real); C_total C_grid C_fuel C_om data.c_carbon * (E_total - data.E_quota); Constraints [Constraints, C_total (1 sigma) * C0]; % 目标最大化alpha optimize(Constraints, -alpha, ops); alpha_opt value(alpha); end这段代码里最关键的一行是功率平衡约束等式右边的负荷用P_L_rb等式左边的风电光伏用的是决策变量P_w、P_pv。虽然这两个决策变量被约束在[下界上界]区间内但为了保证最坏情况下仍然可行优化器在实际求解时会倾向于让它们落到下界因为下界对应的电源出力最小需要燃煤机组出更多力、成本更高自然会在成本约束边界上形成平衡。机会IGDT模型的代码对应修改风电、光伏取上界、负荷取下界目标变为min beta这里就不再单独贴完整代码了。5. 实操中的常见问题与排查5.1 从确定性模型到IGDT逐步调试我建议所有做这个方向的人先别急着上IGDT。拿到Matlab代码后第一步一定是先让确定性模型跑通把功率平衡、储能SOC、碳捕集约束这些都验证一遍。比如把风电出力设成0、燃煤机组出力接近上限看看系统还能不能平衡把碳捕集率设成0.95看看捕集能耗会不会让机组净出力变成负值。这类边界测试能帮你快速定位模型逻辑错误。确认确定性模型没问题后再加入IGDT。此时一般会遇到两类错误一类是α无法变成正数也就是模型无解。这时候先检查σ设的是不是太小比如只有0.02成本预算太紧鲁棒约束无论如何都无法满足另一类是α求解结果异常大比如超过0.5这时候要怀疑是不是最坏方向搞反了风电、光伏取成了上界导致目标函数在“乐观世界”里被最大化。5.2 数值尺度问题这类模型最常见的技术问题不是逻辑而是数值病态。比如煤耗成本可能是几千万元级别碳捕集量是几百吨级别单位差异一旦悬殊Gurobi求解时就会出现数值警告甚至解出来非常不合理。我的解决办法是统一量纲。功率用MW能量用MWh成本用万元碳排放用tCO2。如果某个参数天然量级很大就给它除以一个基准值归一化比如总成本除以10000再进目标函数让所有系数落在0.01到100这个范围内。这一条做了之后Gurobi的求解稳定性会好很多。5.3 参数选择经验IGDT模型里α和σ的选择直接影响结果。σ太小鲁棒模型几乎没有可行域σ太大虽然α大但运行成本高得离谱决策者也接受不了。我实际跑下来的经验σ取0.05到0.3之间比较合理。α的上限如果设成0.4意味着你允许风光出力预测偏差达到40%这个范围已经覆盖绝大多数现实情况了。另外如果你同时考虑风电、光伏和负荷三类不确定性可以用同一个α也可以分成α_w和α_L两组分别代表电源侧和负荷侧的不确定半径。后者更精细但约束会多一组求解变量也多一个代码复杂度和计算时间都会上升。我建议初学者先从单一α开始跑通后再扩展。5.4 结果合理性判断与常见坑跑完结果不要直接抄进论文先检验几件事。第一看功率平衡是否严格成立特别是购电量不为负第二看碳捕集量和实际碳排放是否满足等式关系第三看储能SOC曲线是否连续且首末相等第四看鲁棒模型下的成本是否真的接近(1σ)C0如果远小于这个值说明鲁棒约束没有对目标函数形成紧约束α可能还能继续增大要重新检查约束。还有一个很多人容易忽略的坑在鲁棒模型中风电、光伏的出力虽然被限制在[下界,上界]区间但这些变量本身还是变量不是直接等于下界。如果你为了简化直接令P_w P_w_f × (1-α)然后去求平衡而α又是一个变量这就产生了一个α乘以常数的线性项没问题但如果你不小心写了P_w α × 某个变量那模型就非线性了YALMIP要么报错要么Gurobi无法处理。所以实现时一定要检查有没有出现两个变量相乘的表达式。最后一个建议是把“匹配确定性调度计划”作为对照组。你可以把确定性模型得到的调度计划代入真实场景模拟里比如假设风电实际出力比预测低10%看成本超了多少。如果超限超过σ说明确定性方案确实无法抵御这种偏差再用IGDT鲁棒方案做同样测试成本应该被控制在(1σ)C0以内。这套验证流程做完IGDT模型的价值就很直观了写论文或汇报时也很有说服力。我实际跑完这套东西最大的体会是IGDT真正解决的问题不是“预测得更准”而是在预测不准的时候系统还能有底线。碳捕集和煤制氢耦合的建模一开始确实容易把约束写飞尤其是碳捕集能耗那条很容易忽略它对机组净出力的压缩导致功率平衡对不上。但你只要把设备的能量流一个个拆开画一张带箭头的能量图再照着箭头写约束思路就会清晰很多。如果你也想动手实现我的建议很直接先跑确定性综合能源系统再把IGDT套上去一步一测问题定位会快很多。