ARTICLE DETAIL

资讯详情

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

综合能源系统热电优化:阶梯碳交易与电制氢建模实践

综合能源系统热电优化:阶梯碳交易与电制氢建模实践 综合能源系统热电优化这个题目我在MATLABCPLEX平台上前后折腾了快三个月最难处理的不是风光怎么接入也不是热负荷怎么平衡而是“阶梯式碳交易机制”和“电制氢”这两个模块怎么自然嵌进同一个调度模型。现在复盘看这题目的复杂度是叠加的阶梯碳价一进来模型就带上分段非线性电制氢一进来能流结构就多了一条氢回路。两者合在一起模型直接变成混合整数线性规划不是随便换一个求解函数就能糊弄过去的。这篇东西我按自己实际踩坑的顺序写先讲模型结构和目标函数怎么定再拆解阶梯式碳交易机制的分段线性化思路然后说电制氢与储氢设备的建模细节接着是CHP可行域和热电平衡约束最后是MATLABYALMIPCPLEX的搭建、算例设计以及几个隐藏很深的坑。适合正在做综合能源系统优化、碳交易机制建模或者想在课题里引入电制氢模块的同学参考。基础要求不高会MATLAB基本操作、知道优化问题里的变量和约束是怎么回事就能跟完全程。1. 把题目翻译成一个能求解的数学模型1.1 系统结构电、热、氢三条能流怎么握手论文标题看着长拆开其实就是三层供给侧、转换侧和负荷侧。供给侧主要有风电、光伏以及向上级电网购电、购买天然气。转换侧是核心包括热电联产机组CHP、燃气锅炉、电解槽、储氢罐、氢燃料电池、储电和储热设备。负荷侧则有电负荷、热负荷和可能的氢气负荷。真正让模型复杂化的是设备之间的能流耦合。CHP机组天生就是“热电耦合”发一度电就跟着产生一份热不能像普通火电那样只盯电出力。电解槽则是“电-氢”耦合的入口用电制氢氢气可以存起来在需要的时候通过氢燃料电池再变回电和热。这样一来电、热、氢三条能量流在模型里互相牵制没法简单把热和电分开算。如果系统里还有储热罐它又会给热负荷加一个时间平移的能力。比如中午热负荷低可以用CHP多产热存起来晚上热负荷高了再放出来。储电、储氢、储热三个环节分别作用于三条能流而它们的调度是同时发生的所以整体模型天然是一个多能互补的协同优化问题。1.2 优化目标与决策变量怎么定这个方向的研究最常用的目标函数是“日运行总成本最小”因为购电、购气、碳交易、运维这些成本都在同一个账本里工程意义最直接。题目如果强调碳排放也可以把碳排放最小化作为第二个目标但CPLEX直接解双目标很别扭常规做法是把碳排折算成碳成本放进目标函数这样既能优化成本也能反映减排效果。我采用的日运行成本结构是min F F_fuel F_grid F_om F_carbon - F_hydrogen其中F_fuel是天然气购气成本F_grid是向上级电网购电费用F_om是所有设备的运维成本F_carbon是阶梯碳交易成本F_hydrogen是售氢收益允许系统对外供氢时这一项就是正的收益。决策变量包括每台设备的逐时段出力、电解槽产氢量、储氢罐充放氢功率、储电和储热的充放功率、向上级电网购电功率以及碳交易量。有一点务必注意只要引入了阶梯碳价碳交易量就必须作为决策变量出现而不是按固定比例事后折算。否则阶梯进位完全体现不出来模型优化出来的调度策略也是错的。1.3 为什么不能先优化电再优化热我一开始图省事试过两阶段解耦先根据电负荷和风光出力定CHP电出力再根据热负荷算燃气锅炉补多少热。结果在迭代过程中来回振荡怎么都不收敛。原因不复杂CHP的电出力和热出力在可行域内是可以相互调整的电制氢又给系统增加了一个“灵活用电”的口子。如果先定电再定热等于把CHP的电热耦合关系强行切断电制氢在风电高发时段消纳富余电力的能力也完全发挥不出来。反过来把电平衡、热平衡、氢平衡放在同一个MILP模型里求解CHP可以在可行域里自由选择工作点电解槽也会根据电价和风电出力自动决定何时制氢、制多少氢。所以我最后的结论很直接场景里只要有CHP、电解槽这类跨能流设备就建整体优化模型不要自己去拆问题。2. 阶梯式碳交易机制建模从固定碳价到阶梯碳价2.1 碳配额与碳交易的基础算法碳交易成本不是简单的“排放量×固定碳价”。常规做法是给系统一个免费碳排放配额比如按照机组出力和负荷水平折算出一个基准配额或者给一个配额系数乘以电负荷和热负荷。每一时段的具体碳排放量由燃气设备的出力计算超过配额的部分需要购买配额低于配额的部分可以出售。基础碳成本写作C_carbon_basic P_carbon × (E_total - E_quota)但阶梯式碳交易机制会在这个基础上把超过配额的部分再分成若干区间每个区间执行不同的碳价超额越多碳价越高。比如超额量在0-1000 kg以内碳价是0.2元/kg1000-3000 kg之间碳价跳到0.4元/kg超过3000 kg再用0.8元/kg。这样一来碳交易成本就成了一段分段线性函数不能再用一个固定的连续碳价表达。2.2 阶梯分段的数学表达假设超额排放量X是一个决策变量分为K档每档边界是L_1, L_2, …, L_{K-1}对应碳价d_1 d_2 … d_K。如果X落在第k段也就是L_{k-1} ≤ X L_k那么碳交易成本要按累进方式计算C_carbon d_1 × L_1 d_2 × (L_2 - L_1) … d_{k-1} × (L_{k-1} - L_{k-2}) d_k × (X - L_{k-1})也就是说前面每一档的满额成本是固定的只有落在当前档位的超额部分按当前档价格计算。这个累进结构很像个人所得税不能拿总超额量直接乘以最高档价格。麻烦的地方在于这个函数在每档边界处不可微是典型的分段线性函数。CPLEX这类线性求解器无法直接处理不可微目标或约束所以必须先做分段线性化。2.3 用二进制变量和大M法做分段线性化分段线性化的标准套路是引入二进制变量表示X落在哪个区间。我在YALMIP里做的时候核心逻辑是这样引入二进制变量z_kz_k1表示超额量X落在第k个区间再引入连续变量X_k表示第k段内实际计入的量。约束写为X X_1 X_2 … X_K z_1 z_2 … z_K 1 L_{k-1} × z_k ≤ X_k ≤ L_k × z_k z_k ∈ {0,1}这样只有z_k1的那一档对应的X_k可以非零其他档的X_k会被上下界同时夹成0。碳交易成本就可以线性表示成各档的累进成本之和。下面是一段可以放在YALMIP里的示意代码%% 阶梯碳交易成本分段线性化 K 3; % 档数 L [0, 1000, 3000, 6000]; % 各档边界 dk [0.2, 0.4, 0.8]; % 各档碳价 X sdpvar(1, T); % 总超额排放量 Xk sdpvar(K, T); % 各档内计入量 Z binvar(K, T); % 档位选择变量 Cons []; for t 1:T Cons [Cons, X(:,t) sum(Xk(:,t))]; Cons [Cons, sum(Z(:,t)) 1]; Cons [Cons, Xk(1,t) 0, Xk(1,t) L(1)*Z(1,t)]; for k 2:K Cons [Cons, Xk(k,t) L(k-1)*Z(k,t)]; Cons [Cons, Xk(k,t) L(k)*Z(k,t)]; end end C_buy 0; for k 1:K C_buy C_buy dk(k) * (Xk(k,:) - L(k)*Z(k,:) * 0); end % 注意目标函数里要写成各档累进成本之和不能只乘当前档实际写目标函数时要对“每档的累计固定成本”和“当前档位的边际成本”分别处理避免成本被重复计算。更简洁的做法是直接构造成本分段函数用YALMIP内置的piecewise线性表达但手写约束更可控尤其当你想把碳交易成本拆开导出到结果表里的时候。2.4 边界情况的处理分段线性化最容易翻车的位置是“恰好落在边界上”比如X L_1。理论上它既算第1段的结束也算第2段的开始。如果两段都写成闭区间求解器选哪一段都能得到相同成本不影响最优值但如果有人偷懒写成开区间比如第2段下限是“L_1”模型就可能出现不可行解。我给的建议是统一写成闭边界第1段上限是L_1×z_1第2段下限是L_1×z_2重叠只是单个点最优值不受影响。还有一点如果允许系统出售多余配额要区分买入和卖出两条路径。买入部分按阶梯碳价计算卖出部分按基础价计算。引入E_buy和E_sell两个非负变量约束E_total - E_quota E_buy - E_sell再靠目标函数的成本方向自然保证二者不会同时取正值。3. 电制氢与氢储能把电-氢-热闭环写进约束3.1 电解槽效率模型和运行区间电制氢的核心设备是电解槽碱性槽和PEM槽在优化模型里都不需要深究电化学机理用效率模型就够。典型表达式是P_H2_t η_el × P_el_t其中P_el_t是电解槽消耗的电功率η_el是综合效率P_H2_t是产出氢气的功率。注意这里的η_el取0.5-0.7左右比较常见如果按氢气低热值折算1kg氢约等于33.3 kWh的等价值。比效率更容易踩坑的是最小运行功率。电解槽不是从0到满负荷连续可调的设备实际运行通常有最低负荷限制。我按额定功率的20%作为下限低于这个值就直接停机。停机本身需要启停变量不然模型会给出“蚊子腿式”的微功率运行结果比如P_el_t 0.01 MW实际工程里这种状态根本没法操作。爬坡约束也别忘了。很多人建储能模型时记得爬坡率一到电解槽就只写上下限。实际上电解槽的温度、压力调节都需要时间功率调整速度是受限的。我习惯加一个双向爬坡约束-δ_el ≤ P_el_t - P_el_{t-1} ≤ δ_elδ_el按额定功率的20%-30%取折算到单位时段。加了这条约束以后求解出来的电解槽出力曲线明显平滑很多不会出现一小时内从满负荷跳到停机的抖断行为。3.2 储氢罐容量、SOC和互斥约束储氢罐建模可以类比储电都是能量时移设备但有一个差异在题目里不能忽略储氢的状态变化对应系统压力变化所以一般用容量储能模型描述S_t S_{t-1} (P_in_t × η_in - P_out_t / η_out) × Δt约束包括容量上下限、充放氢功率上下限以及最重要的“不能同时充放”约束。我第一版模型漏了后者结果某些时段出现了边充边放的套利现象目标函数还因为这个假象变小了。补上互斥约束之后这个漏洞才堵住。互斥约束的写法很简单引入两个二进制变量或一个二进制变量控制方向即可0 ≤ P_in_t ≤ P_in_max × u_in_t 0 ≤ P_out_t ≤ P_out_max × u_out_t u_in_t u_out_t ≤ 1u_in_t和u_out_t都是0-1变量。如果嫌二进制变量太多有一种替代是用储氢罐功率乘以符号变量但实际经验是互斥约束用二进制的求解稳定性更好尤其当模型规模可控的时候。3.3 氢燃料电池电热联产的回补逻辑电负荷高峰或者电价偏高时系统可以调用储氢通过氢燃料电池发电。氢燃料电池发电的同时会产生余热这部分余热在热电优化里一定要写进去否则等于扔掉了热负荷侧的一大块免费资源。简单建模时把它当作微型CHPP_FC_t η_e × P_H2_in_t H_FC_t η_h × P_H2_in_tη_e取40%-50%η_h取40%左右两项相加通常不会超过90%。这里的氢气输入功率和电解槽的产氢功率共用同一个储氢罐平衡方程形成完整的“电-氢-热”闭环。这个闭环正是题目把“热电优化”和“电制氢”放在一起的核心价值可再生能源富余时电解水储能负荷高峰时氢能回补电和热。3.4 电制氢如何影响碳交易结果电制氢对碳交易的影响是间接的它增加了用电负荷尤其在风电出力大的时段消纳便宜电减少外购电和天然气消耗从而降低了系统整体碳排放。这个传导路径在模型里要能体现出来。我在算例里做过对比加电制氢之后天然气购买量下降碳交易成本明显减少这直接来自CHP和燃气锅炉出力被替代。反过来如果某组仿真结果显示电制氢让总成本下降但碳排放完全没变不用怀疑数据基本是电解槽约束写错了。最常见的原因是漏了电解槽最小出力约束让模型在低负荷时“隐形”消耗电力结果碳排和成本都对不上。4. 热电耦合约束CHP可行域与热功率平衡4.1 CHP机组可行域怎么描述CHP机组的电出力和热出力不是独立的它们被可行域约束限制。最简单的描述是“以热定电”即电出力在一个由热出力决定的线性区间内。更通用的做法是用多边形可行域把可行域用若干顶点的组合表示让电出力和热出力在凸包内取值。如果系统里有一台抽汽式CHP可行域大致是由以下几个不等式围成的四边形P_chp_min ≤ P_chp_t ≤ P_chp_max H_chp_min ≤ H_chp_t ≤ H_chp_max P_chp_t α × H_chp_t ≥ β P_chp_t - γ × H_chp_t ≤ θ具体系数由机组的电效率、热效率和最大进汽量决定。这些约束都是线性的可以直接交给CPLEX。重点在于评价一个CHP约束写得好不好要看它能不能表达“电出力最大时热出力不是随便取的”这个物理事实。如果热出力完全自由那CHP就退化成了普通的燃气发电机热电优化的特色就没了。4.2 热功率平衡与储热模型热功率平衡约束比电平衡多了一个柔性环节热负荷可以不完全靠实时产热满足储热罐可以把多余的热存起来。热平衡写成H_chp_t H_gb_t H_fc_t H_dis_t H_load_t H_chg_t其中H_chg_t和H_dis_t分别是储热罐的充放热功率。储热罐的SOC方程、容量约束和充放互斥约束与储氢类似唯一区别是储热有自损耗一般用散热系数表示。一个容易被忽略的点是热负荷曲线和电负荷曲线在时间上往往不同步白天电负荷高但热负荷低夜间相反。储热罐就是用来抹平这个错位的。如果模型里没有储热罐CHP就会被热负荷死死拽住电出力不得不跟随热需求电制氢的灵活性也会大打折扣。4.3 爬坡、启停与最小出力限制燃气锅炉、CHP、氢燃料电池都要写爬坡约束和出力上下限。CHP的爬坡尤其关键因为它同时影响电和热两条能流。有些文献只对电出力写爬坡热出力直接从可行域推导这样也能跑但实际机组的热出力变化受锅炉燃烧系统限制建议对电出力和热出力分别写爬坡约束或至少用可行域耦合限制。启停变量也不是越多越好。每个二进制变量都会增加MILP求解复杂度所以我在课题里只对电解槽、燃气锅炉这类启停影响大的设备加了启停变量储热、储氢罐的非同时充放约束用单独的0-1变量表达不再额外加启停状态。这样做能显著减少求解时间。5. MATLABYALMIPCPLEX求解平台搭建与调试5.1 为什么选CPLEX而不是MATLAB自带求解器阶梯碳机制引入后模型天然带二进制变量属于混合整数线性规划。MATLAB自带的linprog只能解连续LPintlinprog虽然能解MILP但遇到千级以上的二进制变量时不管收敛速度还是解的质量都远不如专业商用求解器。CPLEX在中小规模MILP上的表现非常稳定配合YALMIP在MATLAB里建模很顺手。教育版和社区版都能覆盖单园区24或48时段这类算例不需要额外购买昂贵许可。安装好之后在MATLAB里设置好路径输入yalmiptest能看到CPLEX被识别就可以开始建模了。5.2 YALMIP建模框架和最小示例我的建模流程分四步定义变量、写约束、写目标、调用求解器。下面给一个最小框架变量名称按实际项目习惯调整T 24; % 调度周期 %% 决策变量 P_chp sdpvar(1, T); % CHP电出力 H_chp sdpvar(1, T); % CHP热出力 P_gb sdpvar(1, T); % 燃气锅炉热出力 P_el sdpvar(1, T); % 电解槽耗电 P_h2 sdpvar(1, T); % 产氢功率 S_h2 sdpvar(1, T); % 储氢罐容量 z_el binvar(1, T); % 电解槽启停 % ... 其他变量 %% 约束 Cons []; Cons [Cons, P_chp P_wind P_pv P_fc P_grid ... P_load P_el P_charge]; % ... 热平衡、氢平衡、设备出力区间、爬坡、储能耗损约束 %% 目标函数 Objective sum(fuel_cost grid_cost om_cost) ... C_carbon_total - hydrogen_income; %% 求解 ops sdpsettings(solver, cplex, verbose, 2, savesolveroutput, 1); optimize(Cons, Objective, ops);新手最常见的错误是两个一是把二进制变量定义成sdpvar而不是binvar模型被当成LP求解阶梯碳分段的逻辑完全失效二是忘记把外购电功率设成非负变量导致模型用负数购电来“卖电赚钱”算出一堆离谱结果。检查模型类型的最快方法是看求解器日志如果显示LP而不是MILP马上回头查binvar。5.3 求解参数设置与MILP调优跑通之后下一步是调求解参数。我常用的几个设置cplex.mip.tolerances.mipgap设置相对最优间隙比如0.01避免求解器为了最后一点精度耗尽时间。cplex.mip.timelimit设置时间上限做灵敏度批量扫描时特别重要。cplex.mip.pool.capacity需要分析多个可行调度方案时可以让CPLEX保留若干近最优解。还有一个实操经验阶梯碳机制下二进制变量数量会成倍增加48时段模型如果变量到几千个求解时间可能从几秒涨到几分钟。这时先检查有没有写进不必要的大M约束尤其是可以用线性关系直接表达的互斥逻辑不要动不动就引入额外二进制变量。比如储氢罐充放互斥直接用两个功率变量和一个互斥约束就够不需要给每个时段额外加两个状态变量。5.4 结果提取、出图和快速排查YALMIP求解结束后用value()函数把最优变量值取出来P_chp_opt value(P_chp); S_h2_opt value(S_h2); C_carbon_opt value(C_buy_total);出图时我喜欢把电负荷、风光出力、CHP电出力、电解槽耗电和储氢容量画在一张双Y轴图里看时间线上的耦合关系热负荷单独一张图燃气锅炉、CHP热出力、氢燃料电池热回收放一起。如果某个时段出现负出力或者SOC突变基本是约束漏洞优先检查功率平衡方程方向是否写反、爬坡约束是否少了时段衔接。6. 算例设计与结果分析让结论站得住6.1 参数怎么设才可信基础算例通常取典型日24或48时段数据包括电负荷曲线、热负荷曲线、风电和光伏预测出力、天然气价格、分时电价、设备技术参数。参数至少要覆盖这些维度并且注明数据是来自典型文献还是公开数据集否则同行第一眼就会怀疑结论的普适性。设备参数里CHP电效率、热效率、最小出力、爬坡率必须有电解槽效率、运行范围、储氢容量、氢燃料电池电效率与热效率必须有储电、储热容量和自放电率必须有碳配额基准和阶梯碳价各档边界必须有。参数表建好之后我习惯先跑一个连续变量版本看量级是否合理再上MILP这样能快速定位是参数错误还是整数约束错误。6.2 四象限对照场景设计要独立评估阶梯碳交易机制与电制氢各自的作用我设置了四个场景场景阶梯碳交易电制氢说明S1否否基准场景S2是否只看阶梯碳机制S3否是只看电制氢S4是是两者联合这种四象限设计比只跑一个联合场景扎实得多。分析时可以分别回答“阶梯碳交易如何改变调度策略”和“电制氢如何帮助系统降碳”再把S4和S1的差值拆成两部分一部分来自碳交易机制一部分来自电制氢。如果两者有交互效应S1到S4的差值不会等于S2-S1加上S3-S1这个差值本身也是可以讨论的研究点。6.3 关键指标怎么解读我固定看四类指标总运行成本、碳排放总量、弃风弃光量、储氢设备利用率。联合场景S4的预期结论是总成本可能比S1略高或持平但碳排放显著下降弃风率基本归零。和S2相比加入电制氢后外购气量和购电量都会下降碳交易成本进一步减少。如果发现S4的碳排放反而比S3高说明电制氢负荷增加了系统对火电的依赖调度模型没有把“电制氢优先消纳风光电力”这个逻辑引导好。解决办法通常是给弃风弃光加惩罚项或者调整目标函数里售氢收益的权重。6.4 灵敏度分析怎么扫才有效阶梯碳交易部分最值得扫的参数是各档碳价的上浮比例和免费配额的宽松程度。做法是每次只改一个参数连续扫描10-20个取值画出“碳价-碳排放量”或“配额-总成本”曲线。曲线要出现拐点才有研究价值比如碳价从0.2元/kg上升到0.8元/kg时碳排放先快速下降后趋于平缓这个拐点说明减排潜力存在天花板。电制氢部分可以扫电解槽容量和储氢容量看风电消纳率和系统运行成本的边际改善效果。容量从0开始逐步增大时边际收益一定递减找到“再加容量也不划算”的位置可以作为设备配置建议。7. 调试过程中几个坑和绕开方法7.1 分段碳成本“累计段”写错阶梯计价的本质是“每档按该档单价计费前面档位的成本固定”所以目标函数里要把每一档的计入量乘以对应单价不能把总量X整体乘一个“当前档位价格”。我见过不少人在二次建模时直接写C d_k × X结果成本曲线完全失真最优调度会刻意把排放压到边界下方一点点出现不真实的“卡边界”现象。一种自查方法单独造一个极小算例固定所有出力只改变碳配额检验碳交易成本是否按手算的阶梯值变化。成本曲线有任何折点不符合预期就说明分段约束写歪了。7.2 储氢罐SOC初末值影响整个日调度储氢罐、储电、储热如果不设置初末值关系求解器会把第一个时段或最后几个时段当成“倒垃圾口”。比如调度结束时储氢罐容量被放空会吹高最后时段的电力回补影响整个成本评估。合理的做法是设定周期循环约束比如S_0 S_T表示一个调度周期结束回到初始容量。如果不方便做循环约束至少要在目标函数里给末值一个惩罚系数否则灵敏度分析会失真。7.3 单位换算的量级坑单位换算是看着低级但杀伤力极大的坑。电功率常用MW或kW热功率常用GJ/h氢的计量有人用kg/h有人用kW。如果用kW统一氢的低热值约33.3 kWh/kg1kg氢对应3.33 kWh的等价值。储氢罐容量如果写成kg而电解槽产氢写成功率统一口径时就必须严格乘效率换算。我调过一次48时段模型算出的碳排放量比预期大了三倍多最后发现是天然气热值单位从GJ写成了MW却忘了除以3.6。单位一致性问题建议在参数表里单独开一列“量纲”建模前先做一遍维度检查。7.4 二进制变量爆炸后的求解策略加入阶梯碳分段、储氢互斥、电解槽启停之后二进制变量数量可能膨胀到基础LP模型的几十倍。如果求解时间不能接受可以先跑一个LP松弛版本也就是把所有binvar都改成sdpvar并加0到1边界看最优值接近MILP结果多少。如果LP松弛下界和MILP最优值只差几个百分点说明整数约束带来的紧性不强可以把部分互斥约束用大惩罚系数替代模型退化成LP求解速度会快很多结果也足够说明趋势。如果差得远那说明启停或互斥约束是模型的核心不能用松弛替代。这时优先减少不必要的二进制变量比如储热罐不写启停状态、CHP不额外引入最小启停时间先把主问题解出来再考虑进阶约束。如果让我重新做一遍这个课题最先做的一定不是急着敲代码而是把“阶梯碳交易成本如何在MILP里表达”这件事彻底想透再动手写约束。阶梯碳与电制氢的耦合不是两段独立代码的物理拼接而是从目标函数和变量定义开始就交织在一起。这套框架跑通之后你完全可以在上面继续加碳捕集、绿氢交易、需求响应这些模块只要分段线性化的思路不变CPLEX的求解架构就始终能兜住。上面提到的坑我已经替你踩过一轮按这个顺序来应该能少折腾很多。
返回列表