ARTICLE DETAIL

资讯详情

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

P2G厂站电-气综合能源系统规划Matlab复现:模型、代码与避坑全解析

P2G厂站电-气综合能源系统规划Matlab复现:模型、代码与避坑全解析 最近有个学弟拿着一个标题来找我“硕士论文复现计及P2G厂站的电-气综合能源系统规划研究附Matlab代码。”他想让我帮忙看看这个课题怎么入手。说实话这类标题在电气工程和能源系统方向的毕业论文里相当常见P2GPower-to-Gas厂站作为电力系统和天然气系统的耦合环节在规划阶段同时考虑投资决策和运行模拟最后用Matlab把模型跑通。这篇文章我就把整个复现过程中的思路、模型、代码结构和踩过的坑一起整理出来给同样要做论文复现的人一条可以直接参考的路径。先说适用范围如果你手头也有类似方向的硕士论文需要复现或者正在做电-气综合能源系统规划选题又或者单纯想搞懂Yalmip怎么搭MILP模型这篇文章应该能帮你省下不少时间。我默认你至少会用Matlab的基本语法但不要求你已经有商业求解器因为后面我会专门说明如何配置求解环境。1. 复现之前先搞懂这套系统到底在做什么1.1 论文复现不是“翻译代码”而是还原思路很多同学拿到一篇硕士论文第一反应是找“源代码”或者“现成包”。实际上绝大多数毕业论文并不会附完整代码标题里出现“附Matlab代码”往往是作者自己在复现时写的版本或者培训机构打包出来的材料。真正的复现工作应该是把论文里的数学模型用代码重新表达一遍并让它在标准算例上得出可解释的结果。我的习惯是分四步走第一步通读摘要和结论弄清这篇论文解决了什么问题创新点到底是P2G厂站建模、规划模型改进还是求解算法改良。第二步看核心章节的数学模型把目标函数、约束条件一条条摘出来理清变量下标是节点、时段还是场景。第三步根据模型找算例数据硕士论文通常会用IEEE节点系统或者某个区域系统的简化数据自己编数据时也要和论文口径尽量一致。第四步才是动手写代码写的时候不是逐行翻译公式而是要让每个约束都能在代码里找到对应的可计算表达式。这一篇要复现的论文核心就是“电-气综合能源系统规划”。所谓规划就是在已知负荷、风电出力等条件下回答“P2G厂站应该建在哪、建多大容量、电网气网需不需要扩容、系统总成本最低是多少”这几个问题。理解了这个问题代码的逻辑就清晰了。1.2 电-气综合能源系统和P2G厂站的定位先把这个系统拆开看。电力系统一侧有常规机组、风电场、电网线路和电负荷天然气系统一侧有气源、输气管道、压缩机和气负荷。传统规划是把这两个系统分开做的互不影响。但P2G厂站一出现电网和气网就被“挂钩”了P2G消耗电能通过电解水制氢再把氢进一步甲烷化后注入天然气管道或者直接以氢能形式供给其他用户。这样一来原本可能被弃掉的风电可以转化成天然气被储存利用电气系统之间的能量流动变成一个闭环。这也是论文标题里“计及P2G厂站”的意义所在规划时如果不考虑这个耦合环节就可能低估风电消纳能力也会错过跨系统优化带来的成本下降空间。复现的时候你要时刻记住P2G不是一个简单的负荷也不是简单的气源而是一个可以双向调节的柔性耦合设备。它在数学上表现为“消耗多少电功率就相应产生多少天然气流量”两者之间靠效率和运行约束连接。我复现时用的算例规模不大电网取33节点配电网气网取20节点的简化输气网两个系统通过若干个候选P2G节点耦合。规模小不是问题关键是模型要完整求解器能算出结果曲线趋势能解释得通这就达到复现的目的了。2. 核心建模P2G厂站怎么“吃电产气”2.1 P2G过程拆分从电解水到燃气P2G的技术路线主要有两种一种是电解水制氢氢气直接利用或储存另一种是电解水后再进行甲烷化反应把氢气和二氧化碳合成为甲烷这样可以完全兼容现有天然气管道和用气设备。论文里如果想突出“注入气网”这个环节大多采用甲烷化路线。从能量转换角度看P2G整体的效率通常在55%到75%之间。简化建模时不需要把电解槽、甲烷化反应器分别建模只需要定义[ G_{P2G}(t) \eta_{P2G} \cdot P_{P2G}(t) ]其中(P_{P2G}(t)) 是第t个时段P2G消耗的电功率(G_{P2G}(t)) 是注入气网的天然气流量通常换算成热值或等效功率(\eta_{P2G}) 是综合转换效率。这里有个容易踩的坑如果不把单位统一算出来的结果会非常离谱。比如电功率用MW天然气流量用立方米每小时就需要乘上天然气的热值系数再转换为MW或MWh。P2G厂站还要考虑运行范围。实际设备不会在零到额定容量之间任意运行通常会有一个最小技术出力比例比如额定值的10%或20%。此外升降负荷速率也有限制。因此在模型里除了容量约束还要加上爬坡约束和启停状态变量。不过如果论文主要研究规划运行部分往往只做典型日简化爬坡约束可以按整个时段步长设置不需要太复杂。2.2 耦合约束与能量平衡P2G在系统里同时出现在两个网络中电能侧它是一个“电负荷”天然气侧它是一个“气源”。所以建模时需要把P2G的功率变量同时写到电网节点功率平衡方程和气网节点流量平衡方程里。电网节点功率平衡是经典形式[ \sum_{g \in i} P_{g,t} \sum_{w \in i} P_{w,t} P_{line,t}^{in} - P_{line,t}^{out} - P_{P2G,i,t} L_{i,t} ]天然气网络的节点平衡则要复杂一些。简单起见很多硕士论文把天然气管网看成稳态模型只考虑管道流量约束忽略储气动态。那么对每个气网节点有[ \sum_{s \in i} S_{s,t} \sum_{p2g \in i} G_{P2G,i,t} - \sum_{l \in i} G_{load,l,t} \sum_{k} Q_{k,t}^{out} - \sum_{k} Q_{k,t}^{in} ]天然气管道的流量由管道两端压力决定通常用Weymouth方程描述这是一个非线性约束。实际代码里必须把它线性化或松弛化否则Matlab里的求解器很难直接处理。关于这一点我在第4章会专门展开。2.3 规划模型的目标函数与决策变量规划模型的目标函数一般是最小化总成本。总成本分成两大部分投资成本与运行成本。投资成本是待建P2G厂站的建设费用可能还要包括电网扩容、气管网扩容的费用运行成本包括机组燃料成本、购气成本、弃风惩罚等。用公式表达就是[ \min \ C^{inv} \sum_{t \in T} \left( C^{gen}_t C^{gas}_t C^{curtail}_t \right) ]决策变量包括两类。投资决策变量通常是0-1变量比如某个候选节点是否建设P2G连续变量则是P2G建设容量。运行决策变量各时段都有机组出力、气源产气量、P2G消耗电功率、P2G产气流量、管道流量、节点相角或压力等。这里有个关键点需要提醒规划模型里的投资变量和运行变量是耦合的。比如P2G建设容量是(C_{p2g})运行功率就不能超过这个容量还要受“是否建设”这个0-1变量的限制。写成约束就是[ 0 \le P_{P2G,i,t} \le C_{p2g,i} \cdot x_{p2g,i} ]如果(x_{p2g,i}0)那么这个节点就不能消耗电功率如果为1容量上限就是(C_{p2g,i})。这类约束是混合整数规划的基本写法代码里必须保证所有运行变量都通过类似方式与投资变量挂钩否则就会出现“没建厂站却在运行”的荒谬结果。3. Matlab代码实现与复现步骤3.1 整体代码框架与文件目录我复现时用的是Matlab Yalmip Gurobi这套组合。Yalmip是一个建模工具箱它最大的好处是不需要自己手写大规模稀疏矩阵可以直接用符号变量写约束然后调任意底层求解器。Gurobi负责求解混合整数线性规划MILP性能远好于Matlab自带的intlinprog尤其是节点规模稍大时差距明显。代码建议按下面的目录组织main.m % 主程序跑整个流程 load_data.m % 读取系统参数和负荷数据 build_network.m % 构建电网/气网节点导纳矩阵、管道参数 define_variables.m % 定义所有决策变量 constraints.m % 添加所有约束 objective.m % 添加目标函数 solve_and_post.m % 求解、提取结果、画图这样拆的好处是论文里每修改一个假设只需改动对应的函数。比如想改P2G效率不用在几百行代码里找参数直接改load_data里的eta_p2g。主程序的运行逻辑很简单clear; clc; close all; load_data; build_network; define_variables; constraints; objective; solve_and_post;当然实际过程中我不会把所有变量都塞到全局空间但作为复现脚本这种线性流程最容易调试。如果想做成更正式的项目可以用结构体把数据包起来比如data.bus、data.branch、data.gas避免命名冲突。3.2 用Yalmip搭建优化模型的关键代码段这里我直接贴一段简化版的建模代码对应第2章里的P2G耦合约束% 候选P2G节点数量 n_bus 33; T 24; % 投资变量 C_p2g sdpvar(n_bus,1); % P2G建设容量 x_p2g binvar(n_bus,1); % 是否建设 % 运行变量 P_p2g sdpvar(n_bus,T); % P2G消耗电功率 G_p2g sdpvar(n_bus,T); % P2G注入气网功率 % 容量上限约束 Constraints [Constraints, 0 C_p2g C_max .* x_p2g]; Constraints [Constraints, sum(C_p2g) C_total_max]; % P2G运行约束功率不超过容量 Constraints [Constraints, 0 P_p2g C_p2g * ones(1,T)]; % P2G能量转换 Constraints [Constraints, G_p2g eta_p2g * P_p2g]; % 电网节点平衡约束简化 for i 1:n_bus Constraints [Constraints, ... sum(P_gen(i,:),2) ... % 机组出力 P_wind(i,:) ... P_line_in(i,:) - P_line_out(i,:) - P_p2g(i,:) P_load(i,:)]; end有几个地方需要特别说明。C_p2g * ones(1,T)这一步很关键。C_p2g是33×1的列向量P_p2g是33×24的矩阵直接写P_p2g C_p2g会报维度错误。乘上ones(1,T)是为了把列向量扩展成矩阵让每列都共享同一组容量上限。binvar定义了0-1变量这是Yalmip的语法。如果你用GurobiYalmip会自动转换成MIP格式不需要自己声明整数类型。sdpvar则用来定义连续变量虽然名字里带“SDP”其实主要用于线性、二次、二阶锥等各种问题。目标函数可以按这样加% 投资成本单位容量投资 * 容量 inv_cost cost_per_MW * sum(C_p2g); % 运行成本逐时段求和 op_cost sum(sum( ... c_gen .* P_gen ... % 机组燃料成本 c_gas .* G_source ... % 购气成本 c_curtail .* P_wind_curtail)); % 弃风惩罚 Objective inv_cost op_cost; % 求解 optimize(Constraints, Objective, sdpsettings(solver,gurobi,verbose,1));求解完毕后用value()提取变量结果C_p2g_opt value(C_p2g); x_p2g_opt value(x_p2g); P_p2g_opt value(P_p2g);只要Yalmip安装正确求解器配置没问题这一段代码就能跑通。当然真实论文里约束远不止这些还会有机组出力上下限、爬坡约束、气源容量约束、节点压力上下限等但建模思路是完全一样的。3.3 算例数据准备与参数设置没有原始数据是复现时最大的痛点。硕士论文通常只给部分参数我复现时以IEEE 33节点配电网为基础气网参照比利时20节点天然气管网做简化再通过5个候选节点把两个网络耦合起来。常用参数可以按下面这个表设置参数名称数值说明P2G综合效率0.65电解水甲烷化整体效率P2G单位投资成本5000元/kW不同论文差异较大按目标年份调整P2G最大单点容量10 MW候选点容量上限风电装机28 MW分布在多个节点电负荷峰值60 MW典型日负荷曲线缩放气负荷峰值30 MW折算为等效功率天然气热值36 MJ/m³用于单位转换负荷曲线我一般取24个时段的典型日数据分成春夏秋冬四个代表日模型里用多场景方式处理。多场景会显著增加变量数量但在单台电脑上求解几个典型日不算难事。有个单位换算的经验如果电力侧用MW天然气侧也用MW即把流量乘以热值转换为功率那么P2G的效率就可以直接用无量纲系数。这是最稳妥的做法可以避免在后面结果分析时被一堆系数绕晕。等模型跑通后再按论文要求把天然气流量换算回立方米每小时用于画图。3.4 结果后处理把指标变成图表跑出最优解只是第一步论文里需要看的是结果图表。我的后处理脚本会一次性画出下面几种图系统拓扑图在电网单线图上标出P2G建设位置和容量用不同颜色表示容量大小。P2G各时段运行功率曲线可以看到风电出力大的夜间P2G消耗功率明显上升风电出力小的时段P2G基本停机。弃风率对比柱状图不装P2G和安装P2G后的弃风量对比这是体现P2G价值最直观的图。气网节点压力分布检查天然气管道压力是否越限。画图代码我习惯用figuresubplot组合先画出来再统一调整样式。导出图片时用exportgraphics(gcf, result.png, Resolution, 300)这样论文插图直接够用。如果遇到新版Matlab的exportgraphics在某些旧版本不可用也可以用print(gcf, -dpng, -r300, result.png)。还有个细节做结果对比时最好把“不含P2G”和“含P2G”两种场景都跑一遍。很多论文的价值就体现在这个对比里比如总成本下降多少、弃风率降低多少、P2G建在哪几个节点。复现时如果只跑一个场景很容易漏掉这个关键结论。4. 复现过程中最常见的六类坑附排查方法4.1 求解器安装与许可证问题Yalmip本身只需要下载解压然后把文件夹加入Matlab路径。真正麻烦的是底层求解器。Gurobi和Cplex都提供学术许可证用学校邮箱申请很方便安装时注意版本要和Matlab系统兼容。安装完之后在Matlab里运行yalmiptest看到输出里Gurobi显示available就说明配置成功。如果拿不到商业求解器可以先用Matlab自带的intlinprog试试。在Yalmip里只需要把solver改成intlinprogoptimize(Constraints, Objective, sdpsettings(solver,intlinprog));不过intlinprog对大规模MILP问题会明显吃力特别是有上千个0-1变量时求解时间可能从几分钟变成几个小时。我的建议是初学阶段用intlinprog验证模型正确性正式跑算例时再切回Gurobi。这里必须多说一句网上流传的各种所谓“离线包”和“密钥文件”不建议碰一方面有法律风险另一方面容易带恶意脚本。学校能提供学术许可就要用学术许可没有也没关系换开源求解器SCIP也完全可以跑通论文算例。4.2 维度不匹配和稀疏矩阵构造错误这是新手最容易卡住的地方也是我帮人调试时见到最多的问题。Yalmip虽然比手写矩阵友好但变量维度不匹配照样会报错或者产生错误模型。特别是C_p2g * ones(1,T)这类扩展写法稍不留神就会变成“隐式扩大约束”的错误逻辑。排查维度问题有几个技巧。第一定义变量之后就打印size()确认每个变量的行列数。第二写约束时尽量保持同一个物理量使用同一维度比如所有节点变量用n_bus × T所有时段变量用1 × T。第三遇到Yalmip报“Unable to perform assignment because size of left side is X and right side is Y”时不要急着堆repmat先想清楚这个约束数学上到底是逐点约束还是矩阵约束。有时候模型不报错但结果异常也可能是维度扩展写错了。比如我想让每个节点的P2G容量不超过该节点上限写成P_p2g C_p2g就不会触发维度错误因为Yalmip会把列向量和矩阵做广播运算但这个广播不一定是你要的。最稳妥的写法是明确扩展成P_p2g repmat(C_p2g, 1, T)肉眼一看就明白。4.3 管道非线性约束的处理不当天然气管道流量与节点压力的关系是论文模型里最大的坑。Weymouth方程是[ Q_{ij}^2 K_{ij}^2 (p_i^2 - p_j^2) ]这个约束里有平方项直接放到MILP模型里是没法求解的。常见的处理方式有两种。第一种是增量分段线性化。把管道流量和节点压力差关系拆成多段直线用一组连续变量和二进制变量表示强制落在某一段。这个方法精度高但变量数量会随分段数增加。第二种是二阶锥松弛。将(p_i^2 - p_j^2)替换成中间变量并把等式写成不等式[ Q_{ij}^2 \le K_{ij}^2 (p_i^2 - p_j^2) ]的形式这样问题就变成混合整数二阶锥规划MISOCPYalmip可以直接用optimize求解Gurobi从9.0开始也原生支持二阶锥约束不需要额外处理。复现论文时我建议先看原文用的是什么方法。如果原文没说就先用分段线性化因为它在MILP框架内实现起来更直觉后处理也容易画图。如果节点数很多导致计算太慢再换成二阶锥松弛求解时间通常能降一个量级。4.4 MILP求解太慢、收敛性差规划模型里如果候选P2G节点有10个每个节点有0-1变量再加上机组启停变量MILP规模很容易膨胀。Gurobi求解器默认的MIPGap是1e-4对论文复现来说没有必要这么严格。可以在求解设置里放宽一点op sdpsettings(solver,gurobi,gurobi.MIPGap,0.01); optimize(Constraints, Objective, op);百分之1的间隙对规划结果影响不大但求解时间可能从半小时降到两分钟。另外给所有变量设置合理的上下界也很重要。Yalmip默认变量范围是正负无穷这会让分支定界过程搜索空间巨大。即使模型里没有显式约束也应该给关键变量加上边界比如C_p2g sdpvar(n_bus,1); Constraints [Constraints, C_p2g 0, C_p2g 50];设置初始可行解也很有帮助。可以先固定投资变量为0即不建P2G求解一次得到运行成本再把投资变量设为1得到一个粗略的可行解然后用Yalmip的assign赋值给变量再调用optimize求解器会用这个初始点开始搜索收敛会快很多。4.5 结果数值不合理但代码能跑这种情况最让人头大。代码没报错求解状态是“solved”但结果明显不对劲比如P2G建设容量极小弃风率反而更高或者气网流量为负。我总结下来最常见的原因是单位不一致。电源侧用kW负荷侧用MW天然气侧再用m³/h这些单位混在一起模型还能解但解读全乱了。建议整个项目统一用标幺值或统一用MW和MWh。如果论文给了基础功率就在load_data里先把所有数据折算到同一基准。第二个原因是热值系数错了。天然气的热值按36 MJ/m³算1 m³/h约等于0.01 MW如果漏乘这个系数P2G产气量就会被低估或高估一个数量级。检查办法很简单单独设置一个只有一台P2G、无其他约束的小测试模型输入1 MW电功率看输出是不是0.65 MW等热值如果不是就说明单位换算出错了。第三是目标函数中某个成本项权重过大导致求解器通过降低这项成本来“优化”。比如弃风惩罚设得特别高模型可能倾向于建设极贵的储能或P2G来消除弃风结果总成本反而更高。看到这类结果时要把目标函数拆分打印出来看投资成本、燃料成本、惩罚成本各自占比多少问题往往一目了然。4.6 版权、引用与代码分享规范复现论文不是为了抄袭而是为了把方法跑通并验证可用性。如果你准备把复现代码放到GitHub或者自己的博客一定要在README里注明原始论文标题、作者、年份和DOI同时写明这份代码是基于论文模型自己的实现。如果参考了别人的开源代码还必须遵守对应的开源协议比如MIT、GPL等。Matlab代码中如果引用了第三方工具箱也要注意许可证兼容问题。Yalmip是BSD协议可以放心用Gurobi虽然免费给学术使用但开源项目分发时不能捆绑Gurobi的安装包只能让用户自己申请。这些看起来都是小事但真到分享阶段都是必须处理的雷区。5. 从复现到迁移还能怎么扩展这套代码5.1 加入储氢罐打破“即产即用”假设基础的P2G模型默认产气后立刻注入气网不允许存储。实际系统中加一个储氢罐可以显著提升灵活性风电大发时可以多产氢存起来等气价高或者气负荷高峰时再释放。这段代码的改动并不复杂只需要增加一个状态变量表示储氢量E_h2 sdpvar(1,T); % 储氢罐能量状态 Constraints [Constraints, E_h2(:,1) E_h2_init]; Constraints [Constraints, E_h2(:,t1) E_h2(:,t) ... G_p2g_partial(:,t) - G_release(:,t)]; Constraints [Constraints, 0 E_h2 E_h2_max];有了储氢环节P2G就不需要严格满足“产气量注入气网量”而是可以用额外的变量表示氢气流向储罐或燃料电池/燃气轮机。这类改动适合作为论文第4章的扩展场景。5.2 改成多目标规划或考虑碳交易原始论文如果只做单目标成本最小你可以把碳排放量作为第二个目标。最常用的方法是epsilon约束法把碳排放设成一个约束比如总碳排放不超过某个阈值然后观察总成本如何随阈值变化画出帕累托前沿。Matlab里实现epsilon约束法很方便。外层循环用for epsilon [0.9, 0.8, ...]内层在约束中加入total_emission epsilon * emission_base依次求解把成本记录到一个数组里即可。这个结果放到论文里可以写“随着碳排放约束收紧系统总成本上升至xxxP2G配置容量增加说明P2G在低碳转型中起关键作用。”逻辑很顺。如果论文涉及碳交易机制也可以在目标函数中加入碳价乘以碳排放量的项。这样P2G的价值就能直接反映在成本上比单纯看弃风率更有说服力。5.3 从气网平移到热网/电热耦合P2G的思路稍作修改就是P2HPower-to-Heat。电转热设备比如电锅炉、热泵与P2G一样都是消耗电能、产出另一种能量。区别在于热网通常不需要Weymouth方程而是用热力管道传输延迟和温度混合方程建模。如果你能跑通电气系统再换成热网时只需要把网络约束替换成热网节点功率平衡模型框架不用变。这类“换汤不换药”的扩展最适合在毕设里做不同场景对比同一个规划模型分别考虑P2G、P2H、P2GP2H看哪种技术路线经济性最好、对风电消纳贡献最大。代码上的改动集中在耦合设备参数和网络约束部分其他都不动非常能体现工作量。5.4 用AI工具辅助Matlab代码生成近几年AI代码辅助工具进步很快也有不少人在问“Codex能不能像执行Python一样直接操作Matlab任务”。我的实测感受是AI可以用来生成一段模型约束代码但它不会帮你理解论文里的物理建模逻辑。比如你让它写Weymouth线性化它写得像模像样可参数设置、分段数选择、求解器兼容性这些细节仍然要自己把关。我自己的做法是先把论文中的公式逐条写在注释里再让AI工具按注释生成初步代码然后逐段检查约束是不是和公式一致。这样既省时间又保留了核心的建模控制权。说到底论文复现的本质是验证你对模型的理解而不是生成一段能跑的代码。最后再分享一点个人体会。我在复现这类论文时最大的收获不是得到了一堆可用的Matlab代码而是真正理解了规划模型里“投资决策”和“运行模拟”之间怎么互相作用。P2G厂站的位置和容量不是拍脑袋定的而是由风电出力、电网阻塞、气网压力、设备效率和经济性共同决定的结果。你把这个过程亲手用代码实现一遍才算是把“计及P2G厂站的电-气综合能源系统规划”这个课题真正吃透了。后续如果你想在这个方向深入建议把代码里每个约束对应的物理含义都标注清楚然后慢慢把单目标扩展成多目标把典型日扩展成全年8760小时场景再到加入不确定性鲁棒优化。这条路走通之后再做其他综合能源系统规划论文基本就是改网络数据和设备参数的事。
返回列表