做综合能源系统优化调度的人,十有八九都要跟风光不确定性打交道。我复现IGDT(信息间隙决策理论)版本的调度模型时,最大的感触是:这个方法看着绕,用起来其实很直接——它不赌分布,只回答一个问题:“风光预测偏差大到什么程度,我的调度策略依然扛得住?”这篇内容适合正在做综合能源优化调度、尤其是想复现含光热电站IGDT代码的同学。我会把IGDT原理、系统建模、不确定集嵌入、求解技巧和踩过的坑一次说清,尽量让论文里的公式能真正落到代码上。
1. 为什么最终选了IGDT而不是随机规划和鲁棒优化
1.1 确定性优化的天花板
综合能源系统的优化调度,第一步往往是做确定性模型:风电、光伏取预测值,负荷取预测值,然后最小化系统总运行成本,得到一组设备出力计划。这个模型不难,CHP机组、燃气锅炉、储能、光热电站一一建好,加上电热冷功率平衡约束,用Gurobi或CPLEX几分钟就能出结果。
问题在于,确定性调度方案在真实运行中未必可靠。风电预测误差一上来,原来的“最优出力计划”可能直接导致功率不平衡,或者需要临时高价购电,成本远超预期。这时候就需要在调度模型里显式考虑不确定性。
1.2 随机优化需要概率分布,但风光预测误差太难给准
传统做法里,最常见的是随机优化和鲁棒优化。
随机优化需要给不确定参数一个精确的概率分布,比如假设风电预测误差服从正态分布,然后用蒙特卡洛抽样或场景削减技术生成大量场景,把期望成本作为目标。这个方法理论成熟,但有两个在实际复现中很头疼的问题:第一,风光预测误差的真实分布常常是偏态、厚尾的,正态假设本身就有风险;第二,场景数量一多,模型规模暴涨,求解时间指数级上升,尤其是加了整数变量(机组启停)之后,一个场景集就能把求解器卡死。
1.3 IGDT的核心主张:不赌分布,只赌偏差幅度
IGDT走的是另一条路:我不去猜测预测误差服从什么分布,只需要假设实际值会在预测值附近一个区间内波动,区间的半径用α表示。然后问一个关键问题:在给定成本预算上限的前提下,系统能容忍多大的α?
这个方法的好处非常实际:它只需要预测值本身,不需要历史误差数据做分布拟合,建模量小;模型规模也不随场景数量爆炸。而且IGDT天然给出两种风格的决策选项——保守型和机会型,灵活度高。我把随机规划、鲁棒优化和IGDT放在一起对比过,差别很直观:
| 对比维度 | 随机优化 | 鲁棒优化 | IGDT |
|---|---|---|---|
| 不确定性刻画方式 | 概率分布+场景 | 不确定集合(盒式/椭球式) | 信息间隙模型(偏差幅度) |
| 是否需要误差分布数据 | 需要 | 不需要 | 不需要 |
| 决策风格 | 期望成本最优 | 最坏情况下可行 | 保证成本上界/追求成本下界 |
| 模型规模增长 | 随场景数快速增长 | 规模适中 | 规模增长很小 |
| 结果表达 | 一组决策变量 | 一组决策变量 | 决策变量+最大可容忍偏差α* |
对于一篇典型的综合能源系统调度论文来说,IGDT的建模量最轻,又能把“不确定性”这条线讲透,这也正是很多论文选它的原因。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 把IGDT翻译成人话:不确定度半径与两种决策风格
2.1 信息间隙模型的数学形式与直观理解
IGDT的基本不确定集是这样写的:
U(α, ū) =
其中ū是不确定参数的预测值(比如风电预测出力100 MW),α是不确定度半径。这个式子就是说:实际值u落在预测值上下α倍的范围里。
第一次看这个定义,很多人会觉得抽象。我用一个生活化的例子解释:你每天开车上班,导航告诉你需要30分钟。但是路况有波动,实际用时可能是25分钟到35分钟之间。这里的“30分钟”就是预测值,“±5分钟”就是偏差范围。IGDT的α就好比这个偏差范围的缩放系数——α=1时偏差是5分钟,α=2时偏差是10分钟。我们不知道真实路况会差多少,只想知道:如果我还想保证不迟到(成本不超标),最多能扛住多大的偏差?
2.2 鲁棒模型:风险规避者的逻辑
鲁棒模型(也叫风险规避模型)的数学表达是:
max α
s.t. max f(x, u) ≤ (1 + δ) · C_det
u ∈ U(α, ū)
这里的C_det是确定性模型的最优成本,δ是成本偏差系数,代表决策者愿意额外付出的成本比例。比如确定性调度成本是100万元,δ=0.15就表示愿意最多花115万元来换取对不确定性更强的抵抗能力。
在这个模型里,α是决策目标:我们希望找到一个调度计划,使得即使在最恶劣的风光出力情况下,系统总成本也不超过(1+δ)C_det,同时α尽量大。α越大,说明系统对不确定性的容忍度越高,方案越“皮实”。
2.3 机会模型:机会追逐者的逻辑
机会模型走的是另一个方向:
min β
s.t. min f(x, u) ≤ (1 - ε) · C_det
u ∈ U(β, ū)
这里ε是期望收益系数。机会模型问的是:如果风光出力比预测值更给力(偏差方向是“有利”的),系统成本能降到什么程度?β越小,说明只需要很小的有利偏差就能实现目标成本;β越大,说明需要比较显著的有利偏差才能触达收益。
实际项目中,这两种模型往往成对出现。论文里一般会用前者做主结果,后者做补充。我复现的时候也是先跑鲁棒模型,把α*-δ曲线画出来,再跑机会模型对比,这样整篇的叙事逻辑就完整了。
2.4 关键参数选择的直觉
IGDT模型里有两个调节旋钮:δ和ε。它们决定决策者愿意付出多少成本去换“抗偏差能力”(鲁棒),或者期望在“运气好”时获得多少收益(机会)。
实际调试时,δ从0.05开始,每次增加0.05,一直算到α曲线趋于平缓为止。注意δ=0时,鲁棒模型退化为确定性模型,α必然是0,这个结果可以用来验证代码正确性。
3. 系统建模:从光热电站开始的能量枢纽拓扑
3.1 光热电站为什么是这套模型的核心特色
光热电站(CSP)和光伏电站完全不同。光伏直接把太阳能变成电,而光热电站是先把太阳能收集成热能,存在储热系统里,再按需释放热能去驱动汽轮机发电。这个“先集热、再储热、后发电”的结构,让光热电站在调度里拥有独特的灵活性:白天太阳辐照强的时候,可以把多余的热能储起来,留到晚上或者风光出力低谷时再发电。
在综合能源系统里,这个特性太值钱了。风电、光伏出力是“看天吃饭”的,而光热电站相当于一个带大型储能的“可调度电源”,它可以在一定程度上弥补风光出力的波动。
建模型的时候,光热电站至少需要三个模块:
- 集热场:收集太阳能,产出的热功率直接与太阳辐照强度相关,有时需要加一个集热效率系数。
- 储热系统:用熔盐或者其他储热介质,有充热、放热功率上限,有储热量上下限。
- 发电岛:把高温热能转化为电能,有发电效率、最低出力约束和爬坡约束。
光热电站的建模细节我要提醒一点:储热系统的状态递推方程是整个模块最容易出错的地方。储热量的动态变化是:
E_TES(t) = E_TES(t-1) + η_ch · Q_ch(t) - Q_dch(t) / η_dch - Q_loss(t)
其中η_ch是充热效率,η_dch是放热效率。很多人在复现的时候漏掉了效率项,或者把充放热效率放反了,导致能量不平衡。这个我在第六章会再展开讲。
3.2 能量枢纽拓扑与设备单元建模
除了光热电站,我搭的模型还是一个典型的冷热电联供综合能源系统。设备包括:
- 风力发电(WT):出力上限由预测值和不透度半径决定。
- 光伏发电(PV):同样是可变动出力电源。
- CHP机组(热电联产):同时产电和产热,热电比是固定的或在一定范围可调。
- 燃气锅炉(GB):补足热负荷。
- 电锅炉(EB):在电价低谷或者风电大发时,用电制热。
- 电制冷机(EC)和吸收式制冷机(AC):共同满足冷负荷。
- 蓄电池(BESS)和储热罐(TST):作为跨时间尺度的调节资源。
电平衡约束:
P_wt(t) + P_pv(t) + P_csp(t) + P_chp(t) + P_buy(t) + P_bess_dis(t) = P_load(t) + P_eb(t) + P_ec(t) + P_bess_ch(t)
热平衡约束:
Q_csp_heat(t) + Q_chp_heat(t) + Q_gb(t) + Q_tst_dis(t) = Q_load(t) + Q_tst_ch(t)
冷平衡约束由电制冷和吸收式制冷共同承担。每个设备还要加上出力上下限、爬坡约束(CHP和光热发电岛尤其要注意)。
3.3 储能类设备的递推方程与日循环约束
蓄电池和储热罐都是“跨时段”设备,它们的状态量会继承上一时刻的值。蓄电池建模时,除了SOC递推,通常还需要加上首末SOC一致的约束,避免模型“吃老本”——比如第一天把电放光,第二天再把电充满,这种结果没有实际意义。
光热电站的储热系统也是一样,最好在日调度周期结束时,让储热量回到初始状态。实际操作里,我一般写成:
E_TES(0) = E_TES(24)
如果论文里没有硬性要求,可以把初值设定为一个固定值,然后再加末端不低于某个阈值的软约束。这两种方式我都试过,固定初值+末端一致性的方案调起来最省心,不会出现因为初末不一致导致的“储热凭空消失”类bug。
4. 风光不确定性嵌入调度的完整推导
4.1 确定性基准模型的建立
先把风光出力取预测值,代入系统模型,求解得到确定性最优成本C_det。这一步是所有IGDT分析的基础,代码上可以直接复用前面搭好的模型,只把目标函数和不确定参数改成确定值。
注意:C_det必须是对同一个系统模型下的“完美预测”最优解。很多人在后面算IGDT时会回头改目标函数,或者改约束条件,导致基准不一致。这是一个隐蔽的坑——如果确定性基准本身就错了,后面所有δ对应α*的曲线都是无根之木。
4.2 不确定参数集合的IGDT等价形式
在综合能源系统里,主要的不可控参数是风电出力、光伏出力。对每个时刻t,不确定集是:
P_wt_real(t) ∈ [(1-α)·P_wt_pre(t), (1+α)·P_wt_pre(t)]
P_pv_real(t) ∈ [(1-α)·P_pv_pre(t), (1+α)·P_pv_pre(t)]
这里的α就是IGDT的不确定度半径,对所有时刻统一取值。也就是说,风光出力在预测值附近一个“带形”区间内波动。
4.3 max-min双层模型与单层化处理
引入不确定集后,鲁棒IGDT模型变成了一个max-min问题:外层最大化α,内层在给定α下寻找导致成本最高的风光出力组合。这个双层结构没法直接用求解器处理,必须化简。
化简的核心思想是:对于线性规划模型,内层最大化的最优解一定出现在不确定集的“最极端点”。对风电和光伏来说,出力减少会迫使系统更多购电、购气,成本上升,因此最恶劣场景是:
P_wt_real(t) = (1-α)·P_wt_pre(t)
P_pv_real(t) = (1-α)·P_pv_pre(t)
把这两个式子代入功率平衡约束,内层max问题就变成了关于决策变量的常规约束,双层模型随之退化为单层模型:
max α
s.t. C(x, (1-α)P_pre) ≤ (1+δ)·C_det
运行约束(所有t)
这个单层模型可以直接用Gurobi求解。α是连续变量,目标函数线性,约束里α与决策变量相乘会出现双线性项,需要进一步处理。
4.4 为什么最恶劣场景通常在边界取到
上面提到一个关键判断:最恶劣场景在边界。这在数学上是线性目标函数在凸多面体上求最大值,最优点一定在顶点。但如果你是第一次做IGDT,我建议先不要依赖这个结论,而是用一个小规模测试来验证:对单时刻系统,枚举几个不同α值,分别求解内层max问题,看最优场景是不是风电和光伏都取下限。
我最初做的时候,就遇到过反直觉的情况:当弃风惩罚设置得过高时,风电出力上限(而不是下限)会成为最恶劣场景,因为大量风电导致必须弃风,而惩罚成本吃掉了收益。所以“最恶劣方向”不是想当然的,而是由目标函数和惩罚系数共同决定的。稳妥的做法是在代码里把风向参数化,用枚举法确认最恶劣端点。
5. 代码实现:求解器选型、线性化与迭代流程
5.1 求解环境与接口选择
我复现这类模型用的是MATLAB+Yalmip+Gurobi的组合。Yalmip的建模语言接近数学表达,写IGDT这种带不确定集的模型很顺手,Gurobi的MILP求解性能在同类里属于第一梯队。
如果你更熟悉Python,用Pyomo+Gurobi也完全可以,差别不大。真正需要花心思的是建模结构,而不是语言本身。
5.2 变量定义与矩阵化思路
先把所有决策变量定义成24维向量,这样后续约束可以矢量化书写:
code复制% 决策变量
P_buy = sdpvar(24, 1); % 购电功率
P_chp = sdpvar(24, 1); % CHP电出力
Q_chp = sdpvar(24, 1); % CHP热出力
P_gb = sdpvar(24, 1); % 燃气锅炉出力
P_csp = sdpvar(24, 1); % 光热电站发电功率
Q_ch = sdpvar(24, 1); % 光热储热充热功率
Q_dch = sdpvar(24, 1); % 光热储热放热功率
E_tes = sdpvar(24, 1); % 储热容量状态
alpha = sdpvar(1, 1); % IGDT不确定度半径
使用sdpvar定义变量时,注意E_tes这类状态变量一般要加非负约束或者设定上下限。
5.3 二分搜索求α*的实现逻辑
先讲一个最容易上手的实现方案:二分法。对于给定的δ,求解最大α*可以转化为一系列可行性判断问题。
具体做法是:在(0, α_max)区间内二分。每次取一个中点α_mid,把α固定为这个值,然后求解一个可行性问题——在这个α下,系统是否存在一个调度计划,使得所有约束满足且总成本不超过(1+δ)C_det。
这个可行性问题是一个标准的LP或MILP,Gurobi可以直接处理。找到可行解,说明α还可以往上走;找不到,说明α太大了,往下缩。
二分法的优势是调试方便。初期可以用它验证单层化模型的正确性,确认无误后再切换成直接求解max α的等价模型,速度会快很多。
5.4 直接求解双层模型的等价单层化方案
单层化的关键是把不确定参数替换为最恶劣方向后的表达式。把所有出现P_wt_real(t)的地方都换成(1-α)·P_wt_pre(t),所有出现P_pv_real(t)的地方都换成(1-α)·P_pv_pre(t)。这样模型里就只剩下α一个额外变量。
但这里会出现一个双线性项:α和调度变量x相乘。比如功率平衡约束里,风电项是(1-α)·P_wt_pre(t),P_wt_pre是常数,所以α会和其他变量出现在同一条约束里,如果没有两个变量相乘,就不会产生双线性。实际上,在这个模型里α本身是全局变量,而调度变量是各时刻的出力,约束中的(1-α)·P_wt_pre(t)是α的线性项,P_buy等变量是线性项,它们之间没有乘积,所以没有双线性问题。
只有当约束里出现“α乘以决策变量”这种结构时才需要处理。我见过的做法是对α进行分段线性化,或者在优化循环内固定α逐步搜索。我的建议是优先检查模型里是否真的有α与决策变量的乘积项,很多时候并没有,直接用线性模型求解即可。
5.5 验证和结果输出
每次求解完成后,至少检查三件事:
- 最优值α*是否在0到合理范围之间。
- 各功率平衡约束的残差是否接近0。
- 储热、储电的初末值是否满足设定的日循环约束。
输出结果时,我会保存每个时刻的各设备出力、储能量和系统总成本,后续画图做敏感性分析都要用。
6. 复现中容易翻车的细节和参数调试经验
6.1 最恶劣方向不是想当然的那一个
如前面所说,最恶劣方向需要验证。我复现时最开始默认风电下限是最恶劣方向,结果在求解机会模型时发现结果完全不合理,后来排查才发现是弃风惩罚系数设的关系。建议在代码里把每个不确定参数的“方向”单独参数化,而不是写死:
code复制P_wt_real = P_wt_pre - alpha * P_wt_amp * direction_wt;
P_pv_real = P_pv_pre - alpha * P_pv_amp * direction_pv;
direction_wt、direction_pv取1表示下限方向,取-1表示上限方向。先跑小规模枚举,确定真正的极端方向,再投入到全模型计算。
6.2 δ参数怎么选:算例标定思路
δ太小,α可能只有零点几,最后画出来的曲线太平,论文里不好看;δ太大,α虽然很高,但对应的调度计划过于保守,成本上涨过多,物理意义就不合理了。
我一般这样标定:从δ=0开始,步长0.05,算到δ=0.6左右。记录每个δ下的α*。理想状态下,α*随δ增加呈单调递增,曲线先陡后缓。如果曲线出现“平台”或者下降,就要检查模型有没有数值问题。
6.3 光热电站储热SOC初末约束的坑
光热电站储热SOC初末约束一定要加,否则模型会通过“晚上把储热全部放空,早上白嫖太阳能重新充满”来降低成本,得到一个虚假的α*。
但初末一致性加得太死也会有副作用:如果系统在调度周期末本来就预期有一笔未完成的储能,强制的E(0)=E(24)可能会导致无解。我的做法是E(0)固定为E_max的50%,E(24)允许在E(0)±10%范围内波动,这样既防止白嫖,又保留调度灵活性。
6.4 结果分析:怎么从调度方案反推IGDT的价值
跑完α*曲线后,不要只盯着数值看,要会看调度方案的变化。对比确定性调度和鲁棒调度,你会看到几个典型差异:鲁棒调度下,CHP机组出力更稳,储能设备的可用容量预留更多,光热电站倾向于把储热留到晚间负荷高峰,购电策略变得更保守。
这些差异其实就是IGDT带来的“决策价值”:系统牺牲了一部分经济性,换来了面对不确定性的鲁棒性。把这些差异具体地写出来,比单纯贴公式更有说服力,这也是论文复现里最能体现思考深度的部分。
6.5 一个可以快速上手的调试路径
最后分享一下我复现这类模型时的调试顺序,照着做能少走很多弯路:
- 先跑确定性模型,验证所有约束的物理正确性,确保成本C_det合理。
- 固定一个小α(比如0.1),求解可行性问题,看系统能否适应这个偏差。
- 用二分法跑几个δ值,画出α*-δ曲线的雏形。
- 将二分法结果和直接max α的单层模型结果对比,验证单层化是否正确。
- 全部无误后,跑完整参数扫描,整理结果图表。
我在实际做的时候,第2步就能过滤掉大半的建模错误。建议你也别急着直接跑大面积参数扫描,先把一个点跑透。
如果你正卡在IGDT的公式推导和代码实现之间,希望这篇内容能帮你把那条路走通。特别是光热电站+储热+IGDT的组合,网上现成的完整案例不多,调试时要有耐心,先把模型拆到最小可验证的单元,再一步一步加回来。
