ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于IGDT与阶梯碳交易的多能系统优化调度建模与实现

基于IGDT与阶梯碳交易的多能系统优化调度建模与实现 最近在做园区级综合能源系统的优化调度项目卡在最久的不是CHP、储能这些设备模型而是光伏出力不确定性怎么处理。预测曲线就在那里实际值总是偏离用随机优化得先假设概率分布用两阶段鲁棒优化又要把不确定集做对偶变换再上CCG迭代对一个中小规模的调度模型来说工具选得越重解释成本就越高。后来把信息间隙决策理论IGDT和阶梯碳交易机制一起嵌进调度模型配合Python加Gurobi实现整个思路一下子清爽了——不猜分布、不做对偶只回答一个问题在多花多少成本的预算约束下系统能扛住多大的预测偏差。这篇文章就把这套从原理、建模到代码实现的完整脉络写清楚适合正在做多能系统优化调度、对IGDT建模感兴趣或者想把碳交易机制加进现有模型但不想绕弯路的读者。1. 为什么选信息间隙决策理论不确定性建模里被低估的轻量级方案1.1 随机优化、鲁棒优化与IGDT的三角关系处理不确定性的主流工具其实就三大类。随机优化要求你知道不确定参数的概率分布函数然后用期望值或风险度量做目标这需要足够的历史数据支撑分布假设否则“假设正态分布”这件事本身就是最大的不确定性来源。传统鲁棒优化不依赖分布但要预先界定一个不确定集然后按最坏情况做决策得到的方案往往偏保守而且两阶段问题需要重构为min-max-min结构推导和求解都比较重。IGDT走的是第三条路。它既不猜概率也不预设不确定集的边界而是用一个“不确定性半径”α来描述预测参数的波动幅度然后问一个反过来的问题在可接受的成本偏离范围内系统能承受的最大偏差是多少。这个视角特别适合“我手上的预测数据质量一般但我想知道自己的系统到底有多皮实”的场景。1.2 IGDT的数学内核不确定性半径与两类风险策略IGDT对不确定参数的刻画非常朴素。设预测值为p̄实际值p可以落在这样一个集合里U(α, p̄) { p : |p - p̄| / p̄ ≤ α }其中α就是信息间隙的半径表示预测值相对偏差的最大幅度。α0意味着完全信任预测α越大代表系统对预测偏差的容忍范围越宽。在这个集合之上IGDT定义了两种决策策略。鲁棒模型风险规避的目标是最大化α同时要求系统在最坏偏差情况下的总成本不能超过基准成本的(1σ)倍这里的σ是决策者预先设定的成本偏离预算σ越大代表你愿意多花多少钱来换取对预测偏差的容忍度。机会模型风险投机则反过来目标是找到最小的α使得在乐观情况下成本有机会低于(1-σ)倍基准成本回答的是“我有多大可能吃到预测外的好处”。这两类策略对应着完全不同的决策心态。实际工程里绝大多数用户关心的是鲁棒模型——先保底再谈优化。1.3 什么时候该用IGDT工程判断从我实际使用的感受来看IGDT最适合三类情况第一不确定性参数的历史数据不足做概率分布没有信心第二模型本身已经包含大量0-1变量再叠加两阶段鲁棒优化会让求解时间失控第三决策者更关心“风险-成本曲线”这类宏观边界而不是具体某个随机场景下的最优解。它也有短板。IGDT不区分不确定集合内部的参数分布同样是α0.3偏差可能集中在尖峰时段也可能均匀分布模型对这两种情况一视同仁。如果你手里有充足的风速、辐照度历史数据随机优化仍然能提供更细颗粒度的决策信息。IGDT更像是“数据不足但需要量化安全边界”时的高性价比选择。2. 多能系统的能流骨架先把“电-热-气”的耦合关系理清2.1 设备模型与能源链条多能系统的核心是能源耦合设备。我用的园区系统包含四类主要设备燃气热电联产机组CHP、燃气锅炉GB、电锅炉EB和电储能ES外加光伏PV作为可再生电源。电网购电和天然气网购气是两个外部能源入口。CHP是耦合的关键它同时产出电能和热能。简化建模时用热电比r把电出力和热出力绑在一起H_chp(t) r × P_chp(t)CHP消耗的天然气量由总能效折算V_gas_chp(t) [P_chp(t) H_chp(t)] / (η_total × LHV_gas)我这里取η_total0.7热电比r1.2天然气低热值LHV_gas取9.7 kWh/m³。这样每个时段CHP的燃料成本就可以由电出力和热电比直接映射出来。燃气锅炉和电锅炉相对简单。燃气锅炉直接把天然气转化成热能效率取0.9电锅炉则是电能到热能的转化效率取0.95。储能设备采用常规的SOC递推模型SOC(t1) SOC(t) - P_dis(t)/η_dis η_ch × P_ch(t)其中η_ch和η_dis分别为充电和放电效率均取0.95Δt为1小时。2.2 24小时调度中的平衡约束不管设备怎么变调度模型的骨架始终是能量平衡。我把电、热两个平衡单独列出来天然气侧由于购气量直接与CHP和锅炉的消耗挂钩不需要单独的平衡约束。电力平衡P_buy(t) P_pv(t) P_chp(t) P_dis(t) P_load(t) P_ch_es(t) P_eb(t)热力平衡H_chp(t) H_gb(t) H_eb(t) H_load(t)这里P_buy是外购电功率P_ch_es是储能充电功率P_eb是电锅炉消耗的电功率。注意电储能放电P_dis在等式左边是供给项充电P_ch_es在等式右边是负荷项方向千万不要写反。除了平衡约束机组还需要满足出力上下限和爬坡约束。CHP电出力范围我设为50-300 kW燃气锅炉热出力0-500 kW电锅炉0-200 kW。爬坡约束只加在CHP上|P_chp(t) - P_chp(t-1)| ≤ R_chp爬坡速率R_chp取80 kW/h对燃气轮机来说这个值偏保守但园区项目里机组实际运行往往要考虑寿命损耗保守一点更贴近真实调度习惯。2.3 数据准备负荷、分时电价与碳参数这一块最容易翻车的是单位。功率用kW时间尺度1小时能量自然就是kWh天然气体积用m³价格用元/m³碳排放用kg或t碳价用元/t。我见过不少人在这一步把kWh和MWh混着用结果费用相差三个数量级。典型日的电负荷峰值约600 kW夜间谷段约220 kW热负荷峰值约450 kW。光伏预测出力中午最高达到150 kW早九点到下午四点之间贡献明显。分时电价按峰谷平三段设置峰段10-15时和18-21时电价1.2元/kWh谷段0-7时和23-24时电价0.4元/kWh其余时段0.7元/kWh。天然气价格取2.4元/m³。碳排放参数方面电网购电的排放因子取0.57 kgCO2/kWh这是目前国内电网平均排放因子的常见参考值天然气燃烧排放因子取2.16 kgCO2/m³。这两个参数直接决定碳交易成本在目标函数里的权重需要根据项目所在地的官方口径做调整。3. 阶梯碳交易建模从阶梯电价思路到混合整数约束3.1 免费配额与排放核算碳交易机制的核心是先给企业一定量的免费排放额度实际排放超过额度的部分需要购买配额低于额度则可以把富余配额出售获利。我采用如下核算方式E_total Σ [P_buy(t) × λ_e V_gas(t) × λ_g] / 1000单位换算成吨。其中λ_e是电网购电排放因子kg/kWhλ_g是天然气排放因子kg/m³除以1000是为了把kg转成t。免费配额D的设定直接决定碳交易成本的方向。我这里的做法是先跑一遍确定性优化得到系统基准总排放取这个值的60%作为免费配额。实际项目里配额的核算规则比这复杂有的按产品产量、有的按历史排放强度但核心逻辑一致配额松碳成本压力小配额紧减碳约束就变成硬约束。碳交易量就是实际排放与免费配额之差E_trade E_total - D当E_trade为正时需要购买配额为负时说明有富余配额可以出售。传统碳交易模型用的是固定碳价成本函数是一条直线阶梯碳交易把碳价按交易量分段递增排放越多、超过额度越多边际碳价越高这样对高排放的惩罚力度是逐步加大的。3.2 阶梯碳价的分段线性化阶梯碳价和阶梯电价是同一个思路。我给买入配额设置四个阶梯区间价格逐级上涨交易量区间t碳价元/t0-0.5800.5-1.51201.5-3.01603.0以上200同时允许富余配额以60元/t的价格出售作为卖碳收入冲抵成本。这一步的难点在于把分段函数改造成混合整数线性约束。核心变量有两组一是每段的交易量q_i二是每段的激活标志δ_i0-1变量。为了保证分段逻辑正确需要满足段i被使用的前提是前一段已经填满也就是说δ_i是单调递减的δ_0 ≥ δ_1 ≥ δ_2 ≥ δ_3加上两类耦合约束q_i ≤ seg_cap_i × δ_iq_i ≥ seg_cap_i × δ_{i1}最后一段不需要这个约束第一条保证段i未被激活时交易量为0第二条保证如果下一段被激活当前段必须装满。这样分段函数就完整嵌入MILP框架。3.3 0-1变量与大M法的实现细节有读者可能想问为什么不直接用Gurobi自带的分段线性函数接口addGenConstrPWL可以用但我还是建议先把分段约束手写一遍原因有两个一是手写约束能让你看清模型结构排查问题时更快定位二是Gurobi的PWL接口默认用插值近似对带0-1变量的分段约束处理方式比较隐晦不如显式约束可控。大M法在这个模型里其实是隐含的。上述约束中的seg_cap本身就是各段交易量的上限天然充当了M值角色不需要额外设一个很大的M。这点很重要很多人在这一步图省事写一个大M1e6结果求解器数值稳定性立刻恶化出现各种诡异警告。卖出决策和买入决策还需要互斥。我加了这样一条约束q_sell ≤ E_sell_max × (1 - δ_0)即只要第一段买入被激活就不允许卖出配额。反过来如果δ_00则所有买入段的交易量都是0E_trade被限制在负区间只能通过卖出配额来平衡。两端方向在逻辑上是闭合的不会出现既买又卖的套利空间。4. Python实现主线先跑确定性模型再嵌IGDT鲁棒模型4.1 环境准备与整体代码框架实现这套模型需要Python 3.8以上环境核心依赖是gurobipy。Gurobi对学术用户有免费license个人学习申请也不麻烦直接去官网申请即可。如果你的环境装不了Gurobi备选方案是SCIP或HiGHS但求解带大量0-1变量的MILP时性能差距会很明显代码层面也要做适配。pip install gurobipy numpy pandas matplotlib代码按四条主线组织参数模块负责加载负荷、电价、设备参数确定性模型模块构建并求解基准场景IGDT模型模块在确定性模型基础上增加不确定性半径变量和成本约束结果分析模块负责绘制调度曲线和α-σ关系曲线。整个主体大概两百多行结构上分为mysystem_params、solve_deterministic、solve_igdt、run_analysis四个函数就够用了。4.2 确定性模型的核心代码先构建设备决策变量。所有变量都按24个时段定义储能SOC额外多一个时段用于首尾衔接import gurobipy as gp from gurobipy import GRB def solve_deterministic(params): m gp.Model(Det_MultiEnergy) T range(24) P_chp m.addVars(T, lb0, ub300, nameP_chp) H_gb m.addVars(T, lb0, ub500, nameH_gb) H_eb m.addVars(T, lb0, ub200, nameH_eb) P_buy m.addVars(T, lb0, ub350, nameP_buy) P_ch_es m.addVars(T, lb0, ub50, nameP_ch_es) P_dis m.addVars(T, lb0, ub50, nameP_dis) SOC m.addVars(range(25), lb20, ub180, nameSOC) # 碳交易相关变量 delta m.addVars(4, vtypeGRB.BINARY, namedelta) q_buy m.addVars(4, lb0, nameq_buy) q_sell m.addVar(lb0, nameq_sell) E_trade m.addVar(lb-GRB.INFINITY, nameE_trade)平衡约束和储能约束是主体的核心for t in T: # 电力平衡 m.addConstr(P_buy[t] params[PV][t] P_chp[t] P_dis[t] params[Load_E][t] P_ch_es[t] H_eb[t] / 0.95) # 热力平衡 m.addConstr(1.2 * P_chp[t] H_gb[t] H_eb[t] params[Load_H][t]) # 储能递推 m.addConstr(SOC[t1] SOC[t] - P_dis[t]/0.95 0.95*P_ch_es[t]) # CHP爬坡 if t 1: m.addConstr(P_chp[t] - P_chp[t-1] 80) m.addConstr(P_chp[t-1] - P_chp[t] 80) m.addConstr(SOC[24] SOC[0])目标函数包含购电成本、购气成本、设备运维成本和碳交易成本。CHP燃料消耗量由电出力和热电比折算燃气锅炉和电锅炉的燃料/耗电项直接在成本里体现gas_chp quicksum(P_chp[t] * (1 1.2) / (0.7 * 9.7) for t in T) gas_gb quicksum(H_gb[t] / (0.9 * 9.7) for t in T) cost_buy_ele quicksum(P_buy[t] * params[Price_E][t] for t in T) cost_gas (gas_chp gas_gb) * 2.4 cost_op quicksum(0.02 * P_chp[t] 0.015 * H_gb[t] 0.02*H_eb[t] for t in T) cost_carbon 80*q_buy[0] 120*q_buy[1] 160*q_buy[2] 200*q_buy[3] - 60*q_sell m.setObjective(cost_buy_ele cost_gas cost_op cost_carbon, GRB.MINIMIZE) m.optimize() return m注意gas_chp的推导P_chp H_chp P_chp × (1 r)再除以总能效和低热值就得到一小时内的燃气消耗量m³因为P_chp单位是kW而时间步长是1小时kWh和kW在数值上是等价的。碳交易分区约束放在模型里一起提交。分段容量seg_cap对应[0.5, 1.0, 1.5, 2.0]吨最后一段用2.0吨作上限实际项目里可以根据历史排放量放大seg_cap [0.5, 1.0, 1.5, 2.0] for i in range(4): m.addConstr(q_buy[i] seg_cap[i] * delta[i]) if i 3: m.addConstr(q_buy[i] seg_cap[i] * delta[i1]) if i 1: m.addConstr(delta[i-1] delta[i]) m.addConstr(E_trade quicksum(q_buy[i] for i in range(4)) - q_sell) m.addConstr(q_sell 2.0 * (1 - delta[0]))到这里确定性模型就完整了。求解之前先看一下目标函数值这就是后续IGDT模型里的基准成本C0。4.3 IGDT部分把alpha做成变量IGDT鲁棒模型的核心变化有三处。第一处是把目标函数从“最小化成本”换成“最大化不确定性半径α”第二处是把光伏实际出力从固定预测值替换成(1-α)倍预测值这是对最坏情况的建模第三处是新增一条成本约束要求所有不确定性场景下的总成本不超过(1σ)倍的基准成本。具体代码def solve_igdt(params, sigma, C0): m gp.Model(IGDT_Robust) alpha m.addVar(lb0, ub1.0, namealpha) # 其余变量同确定性模型 # 光伏出力替换为(1 - alpha) * PV_pred在电力平衡中使用 for t in T: m.addConstr(P_buy[t] (1 - alpha) * params[PV][t] P_chp[t] P_dis[t] params[Load_E][t] P_ch_es[t] H_eb[t] / 0.95) # 成本约束需要复算各成本项 cost_total ... m.addConstr(cost_total (1 sigma) * C0) m.setObjective(alpha, GRB.MAXIMIZE) m.optimize() return alpha.X这里的关键洞察是光伏实际出力以(1-α)倍预测值进入电力平衡α越大光伏出力越少系统需要用CHP、购电或储能放电来补足缺口成本随之上升。而成本约束设置的(1σ)C0就是允许成本的“天花板”。目标函数最大化α相当于在这个天花板内寻找系统能承受的最大预测偏差。要强调的是由于光伏出力只是作为线性系数出现在平衡约束中没有与任何决策变量相乘整个IGDT模型依然是纯线性MILP不需要做任何非线性转换。这是IGDT方案相对两阶段鲁棒优化的一个巨大便利——后者需要将内层min问题做对偶变换推导过程容易出错而在Gurobi里调试错误约束又非常费劲。4.4 结果输出与可视化跑完所有σ取值后把结果整理成DataFrame输出α随σ变化的序列以及典型调度时刻的机组出力。可视化用matplotlib画两个图一个是α-σ关系曲线另一个是σ0.1场景下的电功率平衡堆叠图。def run_analysis(params): det_model solve_deterministic(params) C0 det_model.ObjVal sigmas [0.0, 0.05, 0.1, 0.15, 0.2, 0.25] results [] for s in sigmas: alpha_s solve_igdt(params, s, C0) results.append({sigma: s, alpha: alpha_s}) return pd.DataFrame(results)求解耗时方面单场景24时段、含几百个约束和几十个0-1变量的MILPGurobi通常在1-3秒内收敛到1%的MIPGap以内。IGDT鲁棒模型比确定性模型稍慢一些但整体还在可接受范围。5. 仿真结果风险规避系数如何改写调度决策5.1 α-σ关系曲线花多少钱买保险我按σ从0到0.25的梯度求解得到的α序列非常直观σ成本预算放宽比例最大可承受光伏偏差α0.000.000.050.110.100.190.150.260.200.330.250.38σ0时α0是必然的因为成本预算不放松系统只能按预测值运行没有余量去兜底偏差。σ从0提高到0.1α快速上升到0.19说明只要愿意多承担10%的成本系统就能容忍光伏出力向下偏离预测值19%。但α的边际增长在递减σ从0.2提高到0.25α只增加了0.05。这个“边际递减”现象背后的物理原因很明确光伏在总电源中的占比有限当偏差超过一定幅度后系统得动用更高成本的备用来源来弥补成本上升的速度远快于可容忍偏差的增长速度。这条曲线的价值在于给决策者一个直观的风险定价工具——你知道为了把光伏偏差容忍度从20%提高到30%需要额外承担多少成本预算这笔钱花得值不值决策者一眼就能看出来。5.2 典型日调度结果对比取σ0基准和σ0.15两个场景对比出力曲线。基准场景下白天光伏出力充足时CHP明显压减出力电储能中午充电、晚间峰段放电购电集中在谷段。σ0.15场景下系统面对的光伏出力是(1-0.26)倍预测值相当于一个“打了折”的光伏于是CHP在白天时段的电出力比基准场景高出约40 kW储能充电量减少从电网购电在峰段的尖峰更高。这个调度行为变化的方向是符合物理直觉的系统对光伏越不信任就越倾向用可控性强的本地机组和电网来支撑负荷储能则从“日间套利”转向“保供应”的角色。有趣的是热力侧的调度变化不大因为CHP热电比固定电出力上调会同步带来热出力上升这部分多出来的热量如果热负荷吃不下就得通过电锅炉或燃气锅炉的出力调整来重新平衡。我在初版模型里忽略了热力侧的这个连锁反应导致CHP电出力一上调热平衡总是无解排查半天才发现是热力平衡约束和CHP热电比约束之间的配合出了问题。5.3 阶梯碳交易对排放的影响由于σ增大后CHP出力上升、购电结构变化系统总排放会小幅走高。以σ0.15场景为例碳排放总量比基准场景增加了约5%碳交易购买量相应增加碳交易成本在总成本中的占比从基准的不足10%上升到约14%。这里阶梯碳价的效果就体现出来了如果采用固定碳价80元/t碳成本只与排放量线性挂钩购碳成本增幅与排放增幅同比例而阶梯碳价下第二段、第三段的价格分别是120、160元/t实际购碳成本增幅高于排放增幅给调度模型施加了更强的减排压力。这也解释了为什么σ增大到一定程度后α的边际增长放缓——除了备用成本上升阶梯碳成本也在同步推高总成本两道夹击让系统很难继续扩大不确定性容忍度。碳交易机制在这里不只是成本项它实际上改变了IGDT模型的风险-成本边界形状。6. 跑通模型之后踩过的坑与调参心得6.1 求解器与数值稳定性最开始的版本我图省事把分段碳交易里的M值写成1e6结果Gurobi求解时频繁出现“numerical trouble”警告最优解也不稳定同样的参数跑两次结果会有微小差异。后来把M全部替换成各段交易量的实际上限seg_cap问题立刻消失。教训是M值够用就行不要写一个“很大”的数数值病态是MILP求解里最隐蔽的坑。另一个与求解器相关的设置是MIPGap。默认1e-4的Gap对24小时模型没问题但如果把模型扩展到8760小时或加入更多0-1变量求解时间会指数级上升。我习惯把MIPGap放宽到0.01在成本和决策精度上损失很小求解速度却可能快好几倍。6.2 参数敏感性免费配额和碳价梯度免费配额D的取值对整个模型结果影响极大。我做了λ从0.4到0.8的敏感性测试发现λ0.4时碳交易成本占到总成本的18%λ0.8时系统甚至可以通过出售富余配额获利调度策略也更倾向于多发电多排放。这提醒我们碳交易机制不是单纯的环境约束它本质上是一个与配额规则强相关的经济信号。在实际项目里拿到需求第一件事应该和甲方确认配额核算口径而不是拍脑袋定一个λ值跑完结果就交付。碳价梯度同样值得调。我试过把阶梯价格差从40元/t放大到80元/t系统对CHP的利用策略会有明显改变——价格差越大模型越倾向于压低排放量较大的时段出力转而用储能在谷段蓄能。如果你希望园区系统展现更强的低碳转型行为适当拉大阶梯价差比单纯提高基础碳价更有效。6.3 模型扩展的多源不确定性思路把单一光伏不确定性扩展到光伏风电等多源场景时不能简单让两种电源都乘(1-α)。因为不同电源的预测精度差异很大用一个统一的风险半径会掩盖这种差异。常见做法是对每个不确定源单独设置αi再通过加权或最小化联合概率约束把它们耦合起来比如令Σαi²≤α²椭球信息间隙模型但这就引入了二阶锥约束求解难度上升一个台阶。实际操作中如果项目对精度要求不高我建议先按“最弱环节”原则把所有不确定源乘同一个α得到的是一个偏保守但可求解的版本如果后续需要更精细的分析再逐步引入多半径模型。此外IGDT模型很方便扩展为带P2G和氢储能的版本因为IGDT本身只改变PV出力项的表达式和新增一条成本约束不影响其他设备模型。我在后续版本里加入了P2G设备主要改动就是电力平衡里增加P2G的电耗项、天然气平衡里增加产气项以及碳交易核算里增加氢气生产带来的负排放补偿。整套改造只花了半天时间这从侧面验证了IGDT作为不确定性处理框架“模块化”的通用性。最后再补充一个实操细节储能SOC的初值设置。如果只约束SOC[0]等于一个固定值而不约束终值模型会倾向于在最后一个时段把储能全部放空造成过度套利。我现在的做法是加一条SOC[24] ≥ SOC[0]的约束强制储能系统保持周期性的运行策略这个约束对调度结果的影响比很多人想象中大得多。无论跑哪个版本都建议把这个周期约束带上你会在结果里看到储能策略瞬间变得合理起来。
返回列表