
一说起硕士论文复现很多人以为就是照着代码跑一遍出个图。真正动手做过的心里都清楚论文里的公式推导和代码实现之间隔着一条参数怎么设约束怎么加解出来不对怎么办的鸿沟。我这次复现的课题是《计及P2G厂站的电-气综合能源系统规划研究》核心工具链锁定在Matlab Yalmip Gurobi目标是完整走通从原始数据、数学模型到优化求解的整条链路。这篇博文不整虚的把整个复现过程分物理建模、数学建模、编码实现、算例调试、踩坑复盘五段讲完准备做综合能源方向毕设或者单纯想把电-气耦合规划这个方向搞明白的同学可以直接抄作业。P2GPower-to-Gas电转气。你可以把它想成一台能量货币兑换机电力富余的时候通过电解水制氢再用氢气去还原CO₂合成甲烷注入天然气管道反过来天然气系统又通过燃气轮机发电回补电网。这样一来电网和气网就不再是两个孤立网络而是能双向互济的耦合系统。项目要解决的规划问题就是在给定的风电、光伏、气源和负荷条件下决定P2G厂站建在哪、建多大、哪些线路和管道需要扩容让系统在满足安全运行约束的前提下整个规划周期的投资与运行总成本最低。1. 项目全貌这个复现任务到底在做什么1.1 原文研究的核心问题题目拆开看是三个关键词P2G厂站、电-气综合能源系统、规划。三个词单独理解都不难合在一起就是一个典型的多能源耦合系统扩容规划问题。它的实际场景是这样的一个区域内电网和气网同时存在负荷逐年增长风电光伏不断并网燃气轮机发电在系统里的占比也在提升。电网用电高峰时希望燃气轮机多发点电但气网可能因为管道输送能力不够而供不上气风电大发、负荷低谷时电网消纳不了只能弃风这时如果把多余的电转成气打进气网既消化了可再生能源又给气网补充了气源。所以问题的关键决策项就变成了P2G厂站选在哪几个节点、每座装机多大、电网输电线路要不要扩建、气网管道要不要增容综合优化后使未来若干年的总成本最低。这是一个标准的**混合整数线性规划MILP**问题建不建建在哪用0-1整数变量刻画建多大怎么运行是连续变量。这类问题在Matlab生态里有很成熟的解法Yalmip负责建模Gurobi负责求解两侧配合得很顺。1.2 P2G在电-气系统里的角色定位要说清楚P2G的价值得先建立一个整体图景电网和气网本身的物理特性差异极大。电网讲究源-网-荷实时平衡电能几乎无法大规模经济存储发多少就得用多少气网靠节点之间的压力差驱动流量天然气可以大规模储存在管道和储气库里时间尺度比电网宽松得多。两者通过两类关键设备耦合起来燃气轮机Gas Turbine烧天然气发电把气网能量送往电网这是气转电通道。P2G厂站把电网电能转化为天然气注入气网这是电转气通道。两条通道方向相反构成电-气系统的双向闭环。P2G最核心的价值是解决可再生能源消纳和季节性调峰风电大发、负荷低谷时电力系统供大于求电价被压低P2G用这段低价电制气同时产出的是可以直接进管网的甲烷不像电解制氢那样面临储运难题。这里有一个很多复现者容易忽略的建模决策点P2G到底做到哪一层是只建模电制氢还是完整建电制氢氢制甲烷甲烷入网两级过程前者相对简单但氢气存储和输送有大量假设只能算半成品后者更贴近工程实际但必须把CO₂供应、甲烷化反应效率、缓冲储气装置一并引入。原论文的核心贡献之一就是按后者完整建模我在复现的时候也坚持走这条完整链路否则结果和工程意义都会打折扣。2. 耦合系统建模P2G厂站和两侧网络的数学关系2.1 电力系统侧的简化策略规划阶段处理电力系统不需要精细到逐节点交流潮流绝大多数论文用的是直流潮流近似或者更粗暴一点直接用节点功率平衡线路容量约束来近似潮流。我按后者实现每个电网节点上常规机组出力、风电场出力、P2G消耗电功率、节点负荷之间必须实时平衡每条输电线路的潮流不越限。直流潮流近似的合理性在于规划问题看重的是扩建什么、扩建多大这种趋势性结论而不是精确的电压和无功分布。复现的时候要注意有功网损在这个尺度下可以忽略强行引入网损系数会引入非线性项让MILP模型的求解复杂度陡增。真有需要体现网损的场景建议放到后续的运行模拟里去细化不要在规划模型里较真。2.2 天然气网络与Weymouth方程的分段线性化气网建模比电网麻烦一个量级。天然气管道流量和节点压力之间的关系遵循Weymouth稳态方程管道流量的平方正比于两端压力平方之差即f² K² × (πᵢ² - πⱼ²)这是一个二次约束直接丢给MILP求解器是肯定解不动的。当前主流处理手段是分段线性化Piecewise LinearizationPWL把压力平方差变量按区间离散逐段用线性函数逼近原二次曲线。我当时专门写了一个通用的分段工具把划段数量、断点位置和斜率都做成可配置参数。段数是精度和规模的权衡点对输气管道来说8~10段已经能把规划结果的误差控制在很小范围内继续加密求解时间急剧上升但结果基本不再变化。另外气网里的压缩机也是建模难点它消耗部分天然气来提升压力消耗量本身又是流量的非线性函数。很多论文直接把它简化成固定压缩比和固定耗气系数我在复现里也采用这个简化对规划层面的结论影响不大。2.3 P2G厂站的两级能量转换模型P2G的核心是两条能量转换链电解水环节电能 → 氢气效率 ηₑ甲烷化环节氢气 CO₂ → 甲烷效率 ηₘ综合下来输入电功率 P_P2G 和输出天然气功率 G_P2G 满足G_P2G η_P2G × P_P2G其中 η_P2G 是总效率原论文取值在0.55~0.65之间这也是业界对现阶段P2G全链路效率的共识区间。我在代码里把它设成可调参数方便做灵敏度分析。实测下来效率每提高0.05P2G装机方案就会出现明显变化这个参数是模型里最敏感的参数之一。另一个容易被忽略的点是P2G的运行范围。电解槽不能从0到额定容量随意运行通常有最小负载率大约在20%~40%。如果模型里允许在0到100%之间连续调节优化器就会倾向于在电价波动时频繁启停设备完全不符合电解槽的实际运行约束。我第一次跑模型就踩了这个坑P2G的出力曲线在时间序列上出现大量尖峰跳动后来加上最小负载率约束方案的运行曲线和收敛稳定性都明显改善。输出侧还需要约束注入气网的边界条件P2G生产的甲烷注入管网必须满足注入节点压力要求同时要考虑CO₂来源约束。CO₂供应在多数论文里被一笔带过但工程上很多P2G项目规划无法落地往往不是技术路线问题而是碳源保障问题。复现时我把CO₂作为外购资源计入成本项这样至少在经济模型里体现了碳源的稀缺性。3. 规划模型拆解目标函数、决策变量和约束条件3.1 决策变量设计决策变量分投资类和运行类两层。投资类变量以0-1变量为主某个节点是否新建P2G厂站、某条线路或管道是否扩容配套的连续变量是实际建设容量。运行类变量包括每个时段常规机组出力、风电场实际出力、P2G输入电功率与产气量、燃气轮机耗气量、气源产气量、储气系统储量等。设计变量的一个核心原则是能少则少因为MILP的求解难度随整数变量数量呈指数级增长。建模前我对候选选址做了预筛只把气网节点和大型风电基地邻近节点列为P2G候选厂址而不是把全网所有节点都塞进去。这样整数变量少了一个数量级求解时间从几小时降到几分钟方案结果几乎没有差别。3.2 目标函数投资年化与运行费用的权衡目标函数是系统总成本最小化分投资和运行两大类投资年化成本P2G厂站建设、电网线路扩容、气网管道扩容都通过资本回收系数CRF把一次性投资折算成等效年成本。运行成本常规机组燃料费、天然气购气费、系统运维费用、CO₂外购成本、弃风惩罚。CRF的计算依赖于折现率和设备寿命原论文里折现率取8%设备寿命按20年算出来的年化系数是0.10185。这个细节很多复现者会忽略但它直接决定投资成本与运行成本在目标函数里的权重关系折现率取错P2G的投资方案会明显偏离原文。3.3 约束条件清单与物理意义我把约束条件按照电网层、气网层、耦合层、安全层四个维度列成一张表方便对照代码逐条实现层次约束内容数学模型要点电网节点功率平衡机组出力风电-P2G消耗-负荷0电网线路容量约束新建/扩容线路输送功率受限气网节点气流平衡气源P2G注入-气负荷-压缩机耗气0气网管道Weymouth约束分段线性化近似耦合燃气轮机模型耗气量发电量/发电效率耦合P2G厂站模型产气量总效率×耗电量最小负载率限制安全旋转备用约束系统必须留足调节能力安全削峰约束P2G运行不得加剧电网尖峰负荷这里面有一个我刚开始没注意的约束气网节点注入压力上下限。P2G生产的天然气如果压力不够是送不进高压管网的。原论文用一个简化等式约束注入压力与节点压力的关系。这个约束在数学上不难加但它决定了P2G站点不能随意选在管网末端节点。复现时不加这个约束优化器经常会给出在管网末梢建站这种伪最优方案。4. Matlab Yalmip代码实现从公式到可运行工程4.1 环境配置与数据结构设计环境方面我用的是Matlab R2022b Yalmip Gurobi 10.0组合。Yalmip是一个建模层它把优化问题描述成变量、目标、约束三个部分底层再交给Gurobi求解。这套组合最大的优点是建模语法和数学表达非常接近跑通效率最高。安装上有一个常见坑Yalmip、Gurobi和Matlab版本之间兼容性问题。Matlab版本太新可能导致Gurobi的mex文件加载不上。我一开始用R2024a配Gurobi 9.5怎么都报Unable to load solver换了R2022b Gurobi 10.0才顺利跑通。如果你卡在这一步别急着重装环境先执行yalmiptest命令看看具体是哪个环节报错。数据准备建议单独建一个load_data.m脚本所有网络参数——节点数、线路参数、管道参数、负荷序列、风机容量、气源价格——统一放在这里不要散落在主程序里。我复现时把算例数据和自建测试数据整理进三个结构体grid、gasnet、scenario后面调参和画图都从这三个结构体取数。4.2 用Yalmip描述MILP的核心框架建模核心代码框架如下节选主要逻辑%% 决策变量 X_p2g binvar(N_p2g, 1); % 是否建设P2G站 C_p2g sdpvar(N_p2g, 1, full); % P2G装机容量 P_p2g sdpvar(N_p2g, T, full); % 每时段耗电功率 G_p2g sdpvar(N_p2g, T, full); % 每时段产气功率 %% 目标函数 Objective sum(inv_cost_p2g .* X_p2g) ... sum(op_cost_p2g) ... gas_purchase_cost ... wind_penalty_cost; %% 核心约束 Constraints []; % 容量与建设变量关联防止未建站点有非零容量 Constraints [Constraints, C_p2g C_p2g_max .* X_p2g]; % 输入输出功率转换关系 for t 1:T Constraints [Constraints, G_p2g(:, t) eta_p2g .* P_p2g(:, t)]; % 最小负载率约束 Constraints [Constraints, P_p2g(:, t) P_p2g_min_rate .* C_p2g]; end这段代码里有三个细节。第一容量和0-1变量的关联必须用大M约束形式C_p2g C_p2g_max .* X_p2g否则优化器会让未建站点的容量跑到非零值。第二如果效率是向量注意使用点乘.*。我第一次就是不小心写成矩阵乘Yalmip不报错结果却完全不对查了很久。第三最小负载率约束写成P_p2g_min_rate .* C_p2g比写成P_p2g_min_rate .* C_p2g_max .* X_p2g更紧凑也不会破坏松弛解空间。提示Yalmip里sdpvar定义的连续变量默认是可以取负值的。P2G耗电、产气、气源出力这类物理量如果不显式加非负约束优化器在极端情况下可能会利用负数值作弊来降低目标值。所以每个变量声明后面顺手补一组 0约束是成本最低的防呆手段。Weymouth方程分段线性化的实现思路也可以贴出来function [constraints, pi_var] weymouth_pwl(f, K, n_seg) % f: 管流变量K: 管道常数 % 将管道流量按段拆分建立压力平方差与流量的分段线性关系 f_max max(abs(f)); seg linspace(0, f_max, n_seg); s sdpvar(length(f), n_seg, full); constraints []; ... end这里的关键不是函数本身有多复杂而是拆分变量在设计时必须保证填充顺序的单调性流量从小到大只能依序占满前面的段否则线性化会失真。我在里面额外加了一组逻辑约束强制段填充顺序虽然多了几个变量但求解精度和收敛稳定性都得到了保障。4.3 求解调试和结果导出求解调用本身很简洁Yalmip会自动识别已安装的求解器options sdpsettings(solver, gurobi, verbose, 2, ... gurobi.MIPGap, 0.01); result optimize(Constraints, Objective, options);实际调试中我有一条非常重要的策略先不要一上来就加MIPGap和TimeLimit。先用默认设置把模型跑一遍观察模型规模和求解器表现再根据需要收紧MIPGap到0.01或0.005。如果一开始就把求解参数限得很死出了问题你根本分不清是参数问题还是模型本身的问题。具体调试路径我是这样走的先搭一个缩小规模版本——候选P2G站只保留1到2个模拟周期缩短到24小时等模型完全跑通后再把规模恢复到8760小时的完整年化模拟。这样做定位问题的效率特别高。结果导出统一用value()函数把所有变量取值提取出来存成result.mat画图单独用脚本处理。我习惯导出这些数据每个P2G节点的容量和年利用小时数、各时段P2G输入功率曲线、燃气轮机和气源的出力曲线、系统总成本明细。这些数据既是复盘的依据也是写论文放图表的一手素材。5. 算例测试与结果复盘5.1 测试系统搭建原论文的算例是基于改进的IEEE 39节点电力系统和20节点天然气网络外接多个风电场。问题是论文正文往往不会给出完整的网络参数特别是气网参数复现的时候经常得自己补。我的做法是分两路电力系统参数从经典测试系统库拿天然气系统参数从开源算例库整理最后用原论文公布的总气负荷去校核。自己额外搭了一套小规模的验证系统用于快速调试电网5节点气网4节点风电场2座P2G候选站点2个时间分辨率1小时模拟完整一年。这套小系统跑一次只要几十秒非常适合验证各模块的正确性等小系统通了再切回路39节点大系统验证规模化后的表现。5.2 关键结果解读基准场景下P2G厂站的最优选址落在风电接入节点附近装机容量大约是风电总装机的8%到12%。运行结果里有几个有意思的现象P2G在冬季和春秋季节的大风时段利用率最高因为此时风力强但负荷一般弃风压力最大P2G站建成后有余电时制气给气网气网负荷高峰时再通过燃气轮机发电两者形成明显的时段互补。成本结构上P2G投资和运行费用合计约占系统总成本的6%到8%但带来的弃风惩罚下降接近60%购气成本也有明显下降。这说明P2G虽然自身项目经济性平平但对整个系统的调节红利异常显著。工程上力推电-气耦合也正是因为单看P2G本身账算不过来放在系统层面账就立住了。5.3 与原论文结果的偏差分析完整跑完后我的方案和原论文结果基本吻合P2G的选址和容量偏差控制在5%以内。差异最大的是运行成本分解我的购气成本比原文低了一些。排查下来原因大概率出在气价的时间分辨率上——原文用了分时气价我一开始用的是恒定气价。把气价改成和电价同步的分时方式后差距立刻缩小了。这个排查过程很有代表性发现结果不一致时先不要怀疑模型错了而是优先检查输入参数的粒度和单位。单位错误是这个领域复现里出现频率最高的问题。我中间至少有三次因为单位换算会导致结果量级不对最后统一到同一套单位制并加上代码注释才彻底避免。6. 复现路上踩过的坑与扩展建议6.1 三个最典型的坑第一个坑是气网参数的单位混乱。天然气的单位在不同文献里可能是标准立方米、千克或者MWh按热值换算1千克天然气约等于13.9千瓦时。如果直接使用原文献的管道参数而不做单位统一Weymouth约束会完全失真。我的处理方式是把所有天然气物理量统一到MW功率体系和电网保持一致从源头上消除换算隐患。第二个坑是两阶段规划框架的层级理解。论文里写的是先投资决策再运行模拟两阶段方法这意味着投资和运行不是用一个单层MILP直接同时求出来的而是一个迭代机制。我一开始按单层模型写结果看着合理但和原文逻辑并不一致。后来改成Benders分解思路做迭代求解才和原文流程真正对齐。复现前务必先确认模型层级这是整个代码框架的地基。第三个坑是求解器数值容差问题。MILP求解时Gurobi默认的整数容差是1e-5但大规模模型中某些约束的数值尺度差异极大——投资成本可能到百万级效率只有0.6级这种尺度悬殊容易引发数值稳定性问题。我的做法是对目标函数做整体缩放所有成本先除以10000再进优化器求解完再乘回来。这个操作看着粗暴却显著减少了求解器报numerical trouble的概率。6.2 后续可以怎么扩展论文复现完成后我顺手做了几个扩展方向的尝试都很有价值不确定性规划把风电出力从确定性场景改成多场景随机规划或者用机会约束建模。P2G本身是消纳不确定性的核心手段引入不确定性后P2G的容量最优解会发生明显变化。碳交易机制在目标函数中加入碳排放配额和碳价观察P2G的减排价值。碳价超过某个价格阈值后P2G最优方案会明显向大容量高利用小时偏移。园区级综合能源系统把视角从区域大系统转向园区级P2G与储气、燃气轮机、光伏、直流微网配合能形成更贴近工程落地的方案设计。根据我个人复现这段代码的经验最深的体会是P2G本身并不是一个划算的设备它更像是整个电-气耦合系统的调节阀。评估它的价值必须站在系统层面看它释放了多少弃风、代替了多少燃气、削掉了多少尖峰规划方案才真正立得住。做这类模型复现时眼睛不能只盯着单个设备要随时抬头看整个系统的经济性和安全性指标。