资讯动态

虚拟电厂优化调度中的P2G-CCS耦合与阶梯碳交易建模及Matlab实现

发布时间:2026/9/28 8:51:49 来源:尧图企业网站定制
做这个课题之前我其实有点怀疑虚拟电厂本来就是个聚合优化问题加上碳交易已经很常见为什么还要再叠上P2G-CCS耦合和燃气掺氢直到我把Matlab代码跑通、把P2G产氢、甲烷化、碳捕集储能、掺氢燃烧这些环节在同一个优化模型里串起来之后才明白这个耦合设计不是炫技而是实实在在解决了虚拟电厂“既要降碳、又要降成本、还要消纳新能源”的三角矛盾。这篇文章我就把完整的建模过程和Matlab代码实现思路整理出来从阶梯碳交易的线性化处理到P2G-CCS、掺氢燃气轮机的耦合约束再到典型算例和调试心得适合正在做虚拟电厂优化调度、碳交易机制设计、以及用Yalmip/Gurobi搭调度模型的同学参考。1. 为什么虚拟电厂要引入碳交易和P2G-CCS耦合1.1 虚拟电厂做调度的逻辑变了传统虚拟电厂的优化调度核心是把风电、光伏、燃气轮机、储能、可调负荷聚合起来在满足负荷和电网约束的前提下最小化购电成本和燃料成本。但“双碳”目标落地之后碳排放成本不再是可忽略的边界条件而是直接影响调度方案的关键因素。尤其有了《虚拟电厂资源配置与评估技术规范》GB/T 44260-2024这类标准后虚拟电厂在参与电网互动时资源配置和运行评估都要考虑低碳属性单纯看电价去调度已经不够了。碳交易机制就是那把“看得见的手”通过给碳排放定价让虚拟电厂自己算账是继续烧天然气多排放还是花成本去消纳弃风、捕集碳如果碳价固定不变模型大概率会选择刚刚不超过配额、然后交一笔固定碳费不愿意多花成本减排。但阶梯碳交易机制下超过配额越多、碳价越高这时候模型就会主动去改变运行策略比如提高掺氢率、提高碳捕集量甚至让燃气轮机降出力。1.2 P2G-CCS耦合到底解决了什么P2G电转气和CCS碳捕集与封存单独看都不新鲜P2G能用电把水电解成氢气CCS能把烟气里的二氧化碳捕集下来。但两者耦合起来妙处就出来了。先说CCS的问题捕集下来的二氧化碳如果只封存那是一个纯成本项捕集能耗要花钱、捕集设备要运维产生不了收益。P2G的问题是电解水只产氢气不产碳而如果想把氢气变成可以大规模储存和利用的甲烷需要另一路二氧化碳参与甲烷化反应。这时候把CCS捕集到的CO2直接送给甲烷化装置和电解出来的氢气反应生成合成天然气二氧化碳就有了“去处”氢能也有了稳定的转化路径。再说燃气掺氢。氢气和天然气掺混后送入燃气轮机燃烧掺入的这部分氢气燃烧不产生二氧化碳直接降低了燃料侧碳排放。而且P2G电解出来的氢气不用全部送去甲烷化可以留一部分直接掺进燃气轮机烧掉这就形成了一个灵活的氢能分配问题每个时段氢气是送去掺烧、送去甲烷化还是先存进储氢罐这个最优比例由模型根据电价、碳价、天然气价格联合决策这正是这个课题最有意思的部分。1.3 项目实施的大体路线我在代码实现时把整个问题放在了“日前优化调度”框架里调度周期取24小时步长1小时已知风光出力预测、负荷曲线、分时电价、天然气价格、碳交易参数需要决策每小时燃气轮机电/热出力、P2G电解功率、碳捕集功率、储氢罐充放策略、以及掺氢比例。目标函数是总运行成本最小化其中碳排放成本用阶梯碳交易函数计算。这个路线有个好处它天然是一个线性规划或混合整数线性规划问题只需要把碳交易阶梯函数做线性化处理就可以用YalmipGurobi、CPLEX这类求解器直接求解。后续如果要扩展鲁棒优化、机会约束也只需要在这个确定性模型上改约束形式不用推翻重来。2. 核心单元建模P2G、CCS与掺氢燃气轮机2.1 电解水制氢与储氢模型电解水制氢的建模不复杂核心是一句能量守恒氢气能量的产出等于电解功率乘以电解效率。我统一用“能量流”来建模不自找麻烦地去算摩尔数、标准立方米这样后续和燃气轮机燃料热值、甲烷化能量效率对接都方便。H2_prod(t) η_P2G * P_P2G(t)其中P_P2G(t)是第t小时电解槽消耗的电功率η_P2G取0.65左右。这个0.65是典型碱性电解槽效率如果考虑PEM电解槽可以往上调到0.7以上。注意这里的单位如果P_P2G(t)单位是MW那么H2_prod(t)就是“MW的氢功率”代表每小时的氢能量产生速率不是氢气质量。这一点非常重要后面氢平衡、甲烷化耦合都基于这个能量口径。储氢罐的模型沿用电储能的思路但比电池简单——我默认充放效率都取1原因是不想在氢能流上再叠加损耗系数否则氢平衡关系会变得很难解释。约束形式是H2_soc(t1) H2_soc(t) H2_prod(t) - H2_blend(t) - H2_meth(t) 0 ≤ H2_soc(t) ≤ H2_soc_max H2_soc(1) H2_soc_init其中H2_blend(t)是送去掺氢燃烧的氢功率H2_meth(t)是送去甲烷化的氢功率。这三者加在一起每个时段氢的产、用、存就闭环了。2.2 碳捕集与封存模型碳捕集装置的建模需要同时考虑三件事能捕多少、要花多少电、捕下来的碳去哪。碳捕集量M_cap(t)的单位是kg/h或t/h它满足捕集功率约束和捕集上限约束M_cap(t) ≤ M_cap_max P_CCS(t) e_ccs * M_cap(t)其中e_ccs是捕集单位质量CO2所需的电耗单位是MWh/kgCO2或者kWh/kgCO2注意统一换算。实际场景中捕集能耗受吸收剂再生影响在小范围内不是完全线性但日前调度模型取0.3~0.6 kWh/kg的线性近似已经足够这样做的好处是保持整个模型线性求解器能很快收敛。最关键的是碳流去向约束。捕集下来的二氧化碳只有两条路一部分M_meth(t)送去甲烷化与氢气反应生成合成甲烷剩下M_stored(t)送去封存。所以严格满足M_cap(t) M_meth(t) M_stored(t) M_meth(t) ≥ 0 M_stored(t) ≥ 0很多书上只把“封存”的部分计入碳减排收益而“甲烷化”的部分因为又变成了燃料最后烧了还是会回到大气。但在这个模型里需要注意送去甲烷化的CO2对应的碳原子最后确实以合成甲烷的形式进入燃气轮机燃烧并再次排放所以我在净排放核算时只把M_stored(t)作为碳扣减项而M_meth(t)不直接扣减。后面第4节的目标函数和约束里能看到这个处理的完整形式。2.3 甲烷化耦合环节甲烷化反应本质是萨巴蒂埃反应CO2 4H2 → CH4 2H2O。我不用化学计量去建方程而是用两个关键系数第一个是能量转化系数。1单位氢能送去甲烷化能产出约0.83单位的甲烷能F_sng(t) η_meth * H2_meth(t)F_sng(t)就是t小时产出的合成甲烷功率MW。0.83这个数字可以自己验算1kg氢气低位热值约120MJ1kg甲烷低位热值约50MJ1kg氢气和4.75kg二氧化碳反应生成1.9kg甲烷所以甲烷能量/氢气能量约等于 (1.9×50)/120 ≈ 0.79再留一点反应效率余量取0.83比较合理。第二个是碳质量系数。产出的每1MJ合成甲烷能需要约0.0055kg二氧化碳去参与反应。写成约束就是M_meth(t) 0.055 * F_sng(t)注意单位协作F_sng(t)是MW换算成MJ/h时是F_sng * 36000.055这个常数实际是按“kgCO2/MJ甲烷”来的所以写成约束时要小心乘3600。我习惯让程序里所有能量变量统一使用MW碳质量统一使用kg/h这样约束里写M_meth(t) 0.055 * 3600 * F_sng(t) / 1000最后得到t/h数值上才不会偏差。2.4 燃气轮机掺氢燃烧模型燃气轮机建模我这里不做非线性热力学模型只抓住电、热、燃料三者的线性关系。设燃气轮机燃料总输入功率为F_fuel(t)电效率η_e取0.4热电比按抽凝工况简化处理热效率η_h取0.45P_chp(t) η_e * F_fuel(t) H_chp(t) η_h * F_fuel(t)掺氢比例我用能量比例h2_rate(t)表示氢气能量占燃料总能量的比例。那么H2_blend(t) h2_rate(t) * F_fuel(t)F_fuel里的另一部分就是天然气包括外购天然气和合成甲烷F_fuel(t) F_gas_buy(t) F_sng(t)燃气轮机的启停和爬坡约束P_chp_min ≤ P_chp(t) ≤ P_chp_max -r ≤ P_chp(t1) - P_chp(t) ≤ r掺氢比例不是越高越好。实际燃气轮机掺氢受燃烧稳定性、回火风险、NOx排放限制影响调度优化里我会加一个上限0 ≤ h2_rate(t) ≤ 0.20这个场景是比较稳妥的。很多燃气轮机已经能到30%甚至更高掺氢比例但工程上要考虑设备耐受性模型里先限到20%比较符合实际。3. 阶梯碳交易机制与线性化建模3.1 为什么用阶梯碳价固定碳价模型里每吨CO2的价格是常数不管排放量是刚刚超过配额还是翻倍超过边际减排成本都一样。这种情况下只要减排技术的边际成本高于碳价模型就会选择不减排。但现实里的碳市场往往是配额越超、额外购买额度越贵用阶梯碳价接近这种“惩罚递增”的市场信号。阶梯碳交易机制对虚拟电厂的调度行为影响非常明显如果第一阶价格低模型会倾向于刚好买第一阶的配额如果第二阶价格显著升高模型宁可多开P2G、多捕集CO2、提高掺氢率也不愿意让碳排放量突破第二阶。这就是“阶梯”二字的精髓——给调度模型一个非线性的碳价信号让降碳行为真正进入优化决策。3.2 阶梯碳价的数学表达设计一个三阶阶梯免费配额为E0分段间隔为d基准碳价为λ第二阶碳价取2λ第三阶取4λ。如果当日总净排放量为E_total单位tCO2/d碳成本函数是C_co2 0 若 E_total ≤ E0 C_co2 λ * (E_total - E0) 若 E0 E_total ≤ E0 d C_co2 λ*d 2λ * (E_total - E0 - d) 若 E0d E_total ≤ E02d C_co2 λ*d 2λ*d 4λ * (E_total - E0 - 2d) 若 E_total E02d这个函数是分段线性的而且因为碳价阶梯是递增的整个函数是凸函数。很多同学一看到分段函数就想用二进制变量做0-1线性化其实没有必要。凸分段函数在优化目标里可以用“最大值不等式”等价表达不需要二进制求解速度快得多。3.3 用“凸函数不等式”直接建模的技巧设C_carbon是一个自由连续变量加入下面四组不等式约束C_carbon ≥ 0 C_carbon ≥ λ * (E_total - E0) C_carbon ≥ λ*d 2λ * (E_total - E0 - d) C_carbon ≥ λ*d 2λ*d 4λ * (E_total - E0 - 2d)然后让C_carbon进入目标函数、并参与最小化。因为目标函数会让C_carbon取最紧的下界而这四条不等式在最紧时正好取到四段直线在上方的最大值效果就和分段阶梯成本完全一致。这是我在这个课题里最想分享的一个技巧梯形函数不一定要用二进制变量拆先判断凸性如果是递增的凸分段函数就可以用一组不等式约束直接线性化避免引入大量整数变量求解时间能大幅下降。如果用的是非递增或者凹分段函数比如价格递减的阶梯那这个技巧不适用必须用二进制拆区间。但碳交易阶梯通常都是递增惩罚的所以这里完全能用。4. 优化调度模型的完整数学表达4.1 目标函数调度模型的目标是让虚拟电厂日运行总成本最小包括六个部分购电成本、天然气成本、碳交易成本、弃风惩罚、P2G与CCS运维成本、以及电网售电收益如果有。min Σ_t [ π_grid_buy(t)*P_buy(t) - π_grid_sell(t)*P_sell(t) ] Σ_t [ π_gas * F_gas_buy(t) ] C_carbon Σ_t [ π_curt * P_curt(t) ] Σ_t [ π_p2g * P_P2G(t) π_ccs * M_cap(t) ]各项说明π_grid_buy、π_grid_sell分时购电价和售电价单位元/MWh。π_gas天然气价格按能量计费单位元/MWh。C_carbon前面构造的阶梯碳成本单位元。π_curt弃风惩罚系数单位元/MWh设置得高一些比如800元/MWh让模型尽量不弃风。π_p2g电解槽运维单位成本π_ccs碳捕集运维单位成本这两者都是为了不让P2G和CCS滥用。需要注意的是这里不包含设备投资折旧成本属于“运行层优化”。如果你要算全生命周期或者日折旧可以再加一个常量项但因为它不参与变量决策对最优调度结果没有影响。4.2 功率平衡、氢平衡、碳平衡约束功率平衡是最容易拼错的一条约束。完整的电功率平衡是P_buy(t) P_wind(t) P_chp(t) P_bess_dis(t) P_load(t) P_P2G(t) P_ccs(t) P_bess_ch(t) P_sell(t)左侧是供电源右侧是负荷、P2G耗电、CCS耗电、储能充电和外送。很多人会把P2G和CCS漏掉导致模型里电能不知道怎么消耗结果P2G疯狂出力也不违反平衡调度结果全是错的。我调试时第一件事就是检查功率平衡里有没有把P2G和CCS侧用电项写进去。风电出力约束P_wind(t) P_curt(t) P_wind_fcst(t) 0 ≤ P_curt(t) ≤ P_wind_fcst(t)储能模型SOC_bess(t1) SOC_bess(t) η_ch * P_bess_ch(t) - P_bess_dis(t) / η_dis 0 ≤ P_bess_ch(t) ≤ P_bess_ch_max 0 ≤ P_bess_dis(t) ≤ P_bess_dis_max SOC_bess_min ≤ SOC_bess(t) ≤ SOC_bess_max氢平衡和碳平衡在第二节已经给出但这里我把所有关键等式汇总成一张表方便大家对照实现环节约束表达式说明电解产氢H2_prod(t) η_P2G * P_P2G(t)能量流口径储氢动态H2_soc(t1)H2_soc(t)H2_prod(t)-H2_blend(t)-H2_meth(t)无损耗简化掺氢分配H2_blend(t) h2_rate(t) * F_fuel(t)能量占比甲烷化产气F_sng(t) η_meth * H2_meth(t)能量效率甲烷化耗碳M_meth(t) K_CO2_per_MJ * 3600 * F_sng(t) / 1000K取0.055kg/MJCCS捕集M_cap(t) M_meth(t) M_stored(t)碳流去向捕集耗电P_ccs(t) e_ccs * M_cap(t)线性化处理燃料总量F_fuel(t) F_gas_buy(t) F_sng(t)外购自产净碳排放的计算公式要单独说。按日累计的口径E_total Σ_t [ β_grid * P_buy(t) α_gas * (F_gas_buy(t) F_sng(t)) * 1000 ] - Σ_t [ M_stored(t) ]注意单位β_grid单位kg/kWhP_buy单位MW要乘以1000变成kWα_gas也是kg/kWh燃气轮机燃料能量要把MW换算成kW同样乘以1000。M_stored(t)单位是kg/h逐小时累加正好是kg除以1000变成吨。这个表达式的物理含义很清晰购电对应的上游碳排放 天然气燃烧排放包括外购天然气和自产合成甲烷减去封存掉的CO2。送去甲烷化的CO2没有直接扣减因为合成甲烷燃烧时又排了但作为燃料的合成甲烷在表达式里已经作为排放源计入。如果你采用“捕集即扣减”的核算口径可以把M_stored换成M_cap模型会在碳减排上有不同倾向论文里往往要写清楚采用哪种口径。4.3 决策变量与边界参数汇总为方便对照我把主要决策变量和参数整理成一份“检查清单”决策变量包括P_buy(t)、P_sell(t)购电、售电功率单位MWP_wind(t)、P_curt(t)风电上网和弃风单位MWP_chp(t)、H_chp(t)燃气轮机电、热出力单位MWF_fuel(t)燃气轮机燃料总输入单位MWh2_rate(t)掺氢比例无量纲P_P2G(t)电解功率单位MWH2_prod(t)、H2_blend(t)、H2_meth(t)氢能量流单位MWH2_soc(t)储氢罐氢功率存量单位MWh注意与MW的区别M_cap(t)、M_meth(t)、M_stored(t)碳流量单位kg/hC_carbon碳成本单位元典型参数我放在算例章节展示。需要额外说明的是H2_soc(t)用的是“能量当量”而不是氢气体积所以储氢罐容量用MWh标定这在实际系统中对应“折合成电量的储氢能量”对于氢气储罐可以用60MWh这类典型容量对接。5. Matlab代码实现的关键细节5.1 代码架构与文件组织我通常把代码拆成四个文件方便维护和复用main.m % 主入口设置参数、构建模型、求解、结果输出 init_system_params.m % 系统参数表 build_vpp_model.m % 构建目标函数和约束 plot_vpp_results.m % 可视化main.m的核心只有十几行调用的顺序是读参数 - 声明决策变量 - 构建约束和目标 - 调用Yalmip求解 - 取结果画图。如果你习惯单文件跑也可以把所有代码放在一个脚本里但拆开后调试效率高很多尤其适合反复修改碳交易参数或掺氢率上限的敏感性分析。5.2 核心代码片段与注释我用Yalmip搭建模型求解器用的是Gurobi。首先声明决策变量注意binvar我完全没有用因为模型里没有启停变量和二进制选择变量整问题是纯线性规划求解非常快T 24; P_buy sdpvar(1, T); P_sell sdpvar(1, T); P_wind sdpvar(1, T); P_curt sdpvar(1, T); P_chp sdpvar(1, T); H_chp sdpvar(1, T); F_fuel sdpvar(1, T); h2_rate sdpvar(1, T); % 注意不要用eps作为变量名会和matlab内置函数冲突 P_P2G sdpvar(1, T); H2_prod sdpvar(1, T); H2_blend sdpvar(1, T); H2_meth sdpvar(1, T); H2_soc sdpvar(1, T); M_cap sdpvar(1, T); M_meth sdpvar(1, T); M_stored sdpvar(1, T); P_bess_ch sdpvar(1, T); P_bess_dis sdpvar(1, T); SOC_bess sdpvar(1, T);然后是约束组装。这里我给出最关键的几段其余按清单补全。功率平衡Constraints []; Constraints [Constraints, P_buy P_wind P_chp P_bess_dis ... P_load P_P2G P_ccs P_bess_ch P_sell]; Constraints [Constraints, P_wind P_curt P_wind_fcst];P2G-CCS-掺氢耦合约束% 电解 Constraints [Constraints, H2_prod P2G_eta * P_P2G]; % 甲烷化 Constraints [Constraints, F_sng Meth_eta * H2_meth]; Constraints [Constraints, M_meth 0.055 * 3600 * F_sng / 1000]; % CCS Constraints [Constraints, M_cap M_meth M_stored]; Constraints [Constraints, P_ccs e_ccs * M_cap]; Constraints [Constraints, M_cap M_cap_max]; % 掺氢 Constraints [Constraints, H2_blend h2_rate .* F_fuel]; Constraints [Constraints, F_fuel F_gas_buy F_sng]; Constraints [Constraints, 0 h2_rate 0.20];这里要注意Matlab里的矩阵点乘.×和普通乘法的区别。H2_blend h2_rate .* F_fuel是对24个时段分别建立等式约束。如果你粗心写成h2_rate * F_fuel那是向量内积得到的是一个1×1的表达式约束维数直接对不上Yalmip会报dimension mismatch。储能和储氢约束Constraints [Constraints, SOC_bess(2:T) SOC_bess(1:T-1) ... eta_ch * P_bess_ch(1:T-1) ... - P_bess_dis(1:T-1) / eta_dis]; Constraints [Constraints, H2_soc(2:T) H2_soc(1:T-1) ... H2_prod(1:T-1) - H2_blend(1:T-1) - H2_meth(1:T-1)];碳成本线性化是我最推荐照抄的一段E_total sum( beta_grid * P_buy * 1000 alpha_gas * (F_gas_buy F_sng) * 1000 ... - M_stored ) / 1000; C_carbon sdpvar(1, 1); Constraints [Constraints, C_carbon 0]; Constraints [Constraints, C_carbon lambda * (E_total - E0)]; Constraints [Constraints, C_carbon lambda * d 2*lambda * (E_total - E0 - d)]; Constraints [Constraints, C_carbon lambda * d 2*lambda*d 4*lambda * (E_total - E0 - 2*d)];目标函数Objective sum(price_buy .* P_buy - price_sell .* P_sell) ... sum(price_gas * F_gas_buy) ... C_carbon ... sum(price_curt * P_curt) ... sum(price_p2g * P_P2G price_ccs * M_cap);求解和结果输出ops sdpsettings(solver, gurobi, verbose, 1); result optimize(Constraints, Objective, ops); if result.problem ~ 0 disp(求解失败); disp(result.info); end P_chp_opt value(P_chp); P_P2G_opt value(P_P2G);5.3 求解器配置与数值稳定性第一优先选Gurobi或CPLEX。Yalmip本身不自带求解器如果电脑上装了Matlab自带的linprog也能解但大规模连续线性规划用linprog会慢不少。Gurobi在学术许可下可以免费申请安装后Yalmip会自动识别你只要在sdpsettings里指定solver,gurobi就行。第二单位一定要统一。我在代码里已经做了换算但第一次调试时还是会经常出现约束量级差几千倍的问题比如碳捕集量E07、氢能量E-02数值跨度太大容易触发求解器数值容差问题。建议所有变量单位按“功率MW、电量MWh、碳质量kg/h”统一然后碳成本变量按“元”来避免出现过大系数。第三如果模型里加入了二进制启停变量求解从LP变成MILP这时候线性化约束中的大M系数不要一律取1000000应该根据变量的实际物理范围取最小可行上界比如碳配额超出量上界设为E_ub用这个值当大M数值稳定性会好很多。6. 典型算例结果与敏感性分析6.1 场景设置与输入数据我构造了一个典型虚拟电厂测试系统燃气轮机额定电出力60MW电效率0.4热效率0.45掺氢率上限0.2电解槽额定功率30MW效率0.65CCS捕集能力上限30t/h捕集电耗0.4MWh/tCO2储氢罐容量20MWh。风电装机80MW负荷峰值150MW分时电价在低谷0.25元/kWh、高峰0.9元/kWh之间波动。碳交易参数设置如下免费配额E0400t/d阶梯间隔d80t基准碳价λ50元/t因此第二阶碳价100元/t、第三阶200元/t。天然气价格按能量折算成260元/MWh弃风惩罚取800元/MWh。6.2 三种方案下的调度结果我跑三个方案做对比方案A是传统虚拟电厂不含P2G/CCS/掺氢方案B只加P2G和燃气掺氢不加CCS方案C是完整模型含P2G-CCS耦合和燃气掺氢。所有方案都用同一套负荷、风电、电价、碳价输入。结果整理在表里方案弃风率%掺氢率均值%CCS捕集量t/d碳配额净排放t/d碳交易成本万元总运行成本万元A 传统17.2004921.4786.2B P2G掺氢6.49.804310.7982.5C 完整P2G-CCS掺氢2.112.51083680.3578.9方案C比方案A总运行成本下降了8.5%同时碳排放从492t/d降到368t/d效果是很显著的。这里面要特别留意弃风率传统模型在风电大发时段只能弃风因为电网购电和燃气轮机出力已经压到最小负荷又没那么大而方案C里P2G把弃风变成了氢CCS又把碳捕集和甲烷化联动起来P2G耗电给系统增加了灵活性弃风率自然大幅下降。还需要说明方案C的碳交易成本只有0.35万元实际上碳成本降了那么多并不是因为排放接近配额而是因为碳成本这个变量在目标函数里和“弃风惩罚运维成本”之间存在权衡。模型宁可多花一点P2G和CCS的运维成本也要把净排放拉开避开高碳价阶梯。6.3 碳价和掺氢上限的敏感性分析我单独扫描了基准碳价λ从30元/t到100元/t的变化结果发现λ低于40元/t时模型基本不主动捕集CO2掺氢率也在7%左右徘徊因为减排的边际收益太低λ到了60元/t以后CCS捕集量明显上升掺氢率也突破12%λ到100元/t时CCS捕集量接近设备上限掺氢率逼近设定上限20%这时继续升碳价对减排效果影响就不大了。这说明耦合模型存在“饱和效应”设备容量上限和掺氢上限约束了进一步减排的空间。如果你想在更高碳价场景下有更好的表现就得扩容CCS设备或提高掺氢率上限。这类敏感性分析对虚拟电厂投资规划和设备容量配置很有参考价值算是这个代码模型的一个扩展用途。掺氢率上限的影响我也跑了一下上限从10%提高到20%总成本只下降了不到1%但碳排放下降了约6%。原因在于掺氢率提高后燃料里便宜的天然气用量减少可再生能源电解制氢的“机会成本”在电价低时才划算。如果电解槽只靠弃风电而不是在高峰时段买电制氢掺氢的经济性会好很多一旦电价高了模型会自动降低掺氢量把电留给负荷侧。7. 常见问题与调试心得7.1 一上来就报Infeasible怎么办这是所有做优化调度的人都会遇到的第一道坎。我的排查顺序是第一步打印每个变量的上下界是否合理。特别是储能、储氢的初值和终值约束最容易因为索引写错导致明明明显有解却不可行。第二步检查每个平衡约束的单位。我遇到过最典型的问题是把CCS捕集量写成t/h但净排放计算里M_stored还是没有除以1000的kg量纲差了一千倍直接导致可行域为空。用Yalmip调试时可以敲size(Constraints)检查约束个数再用check(Constraints)逐条看哪组约束的残差最大通常很快就能定位到问题约束。第三步把碳交易不等式先砍掉换成固定碳价看看模型有没有解。如果有解就说明问题出在碳成本线性化的约束上检查是否把“最大值”写成了“等于某一条直线”或者漏写了C_carbon 0。7.2 碳流核算里的“人为”陷阱我在做这个课题时踩过最深的坑是碳核算口径。如果净排放公式写成“总排放减去捕集量M_cap”那么甲烷化消耗的CO2也被扣减了但合成甲烷燃烧排放又算进去了这等于把同一个碳原子既扣除又计排结果会重复优化碳收益。正确的做法是只有封存的M_stored才是净排放的扣减项。这个细节虽然在一开始建模时不显眼但对调度结果影响非常大建议在论文里把碳流图画出逐股流标注“排放/扣减/消耗”。另外要强调一点送去甲烷化的CO2虽然没有直接扣减但它带来了一个好处——合成甲烷替代了外购天然气减少了外购天然气带来的那部分排放因为外购天然气没有CCS。所以模型里甲烷化环节是通过“替代燃料”间接降碳的不要把它当成直接的碳补贴。7.3 数据、可复现性和绘图检查调试完成后我习惯做三个检查一是看每个时段功率平衡残差是否接近零二是看掺氢率曲线是否出现高频抖动如果抖得很厉害通常说明目标函数里缺了运维成本或调节成本惩罚三是看风电出力曲线是否贴预测值弃风时段是否是凌晨低负荷时段。绘图时我会把风电、燃气轮机、P2G、CCS这四类功率放在同一张堆叠图里再把碳流捕集、甲烷化消耗、封存画到第二张图能很直观地看出“弃风怎么变成氢、氢怎么变成电、碳怎么被处理”的全过程。这个图在答辩和论文里非常有用比一堆表格直观得多。7.4 关于求解器的额外提示Yalmip Gurobi跑这类线性规划其实是“杀鸡用牛刀”通常几秒就解完。但如果后续你扩展了设备启停变量、引入了负荷的0-1状态变成MILP之后就要关注求解时长和Gap值。建议先跑确定性日前模型设定一个MIPGap比如0.1%然后检查gap值是否太大。如果MILP规模大到几百个二进制变量可以考虑把24小时分成峰、平、谷三个时段分别求解再合并结果速度能快很多。另外Gurobi默认使用多线程如果Matlab里同时开着其他工具箱求解前可以手动把线程数限制一下避免电脑卡顿。代码里这一行很实用sdpsettings(gurobi.Threads, 4);。最后再说一点个人体会项目做完最大的体会是虚拟电厂优化调度里的“耦合”两个字不是多个模块堆在一起就完了而是要让不同能量流在约束里真正形成闭环。P2G、CCS、储氢、燃气掺氢这四个模块单独跑每个都只能说“可以减排”只有把它们写进同一个调度模型里让功率平衡、氢平衡、碳平衡互相咬合才能看到弃风被消纳、碳排放被阶梯碳价压缩、总运行成本反而下降这个反直觉的结果。我当时从简化模型起步先跑通无碳交易的传统虚拟电厂调度第二步加入固定碳价第三步才加入阶梯碳交易和P2G-CCS、掺氢这些环节每加入一层我都会重新检查一遍平衡约束和目标函数这个方法在复杂模型调试里特别推荐。希望这份建模和代码梳理能帮你少走一些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑