这次想聊的是一个我最近花了不小力气才跑通的项目基于二阶锥优化的电气综合能源系统多目标无功优化。这个标题看起来很学术但你把它拆开看无非是两件事把电力网络和天然气网络放进同一个优化模型里调度再用二阶锥优化这个凸优化工具去求解。项目跑完之后我的最大感受是二阶锥优化没有传说中那么玄关键反而是第一步的建模有没有把“非凸的部分”正确识别出来以及第二步的松弛处理有没有保住最优性。这套方法特别适合正在做综合能源方向论文、或者刚接触无功优化但不想掉进内点法和遗传算法老坑的读者。接下来我把整个探索过程、模型细节和踩过的坑都摊开讲。1. 先把问题说清楚这个项目到底在做什么1.1 为什么电和气要放在一起优化标题里的“电气综合能源系统”在多数文献里也就是“电-气综合能源系统”意思是电网和天然气网络通过燃气轮机、电转气P2G这类设备耦合在一起形成一个互相影响的整体。以前做无功优化时习惯上只看电网侧调节发电机机端电压、投入无功补偿、调整变压器分接头目标是让网损更小、电压更稳。可现在系统里燃气机组越来越多如果电网调度方案里需要一套燃气轮机高负荷出力而气网在那个时刻恰好气压不足整个调度计划在物理上就根本执行不了。把两个网络放进同一个优化模型就不只是“潮流计算多了一个网络”那么简单。电网里的无功、有功、电压之间有强耦合气网里的流量、压力、压缩机耗气也有自己的物理规律两者通过燃气轮机的耗气特性、P2G的产气特性连接起来。这类联合优化在数学上是个典型的多能流最优能流问题比单独的电力系统最优潮流要难一个量级而且天然带有非凸约束。1.2 多目标无功优化里的“多目标”到底指什么常规无功优化的目标函数通常写成一个比如最小化系统有功网损。但这个项目里我们关心的事情不止网损一项。至少有几个典型目标同时存在经济性目标系统总有功网损最小因为网损最终要折算成购电成本。安全性目标节点电压偏差最小电压偏离额定值越小系统越稳定。环保性目标天然气耗量或碳排放最小燃气机组用气越少碳排放越低。这三个目标本质上互相冲突。比如想把网损压到最低可能让某些节点电压偏高想尽量少用气电气耦合点上的燃气机组出力受限电网潮流就要绕远路网损反而升高。多目标优化就是在这些矛盾目标之间找一组权衡解而不是找唯一“最优解”。一般用帕累托前沿来描述这一组解在改进某个目标的同时必然恶化至少另一个目标。1.3 为什么偏偏选二阶锥优化传统无功优化最常用的解法是内点法直接解非线性规划或者用遗传算法这种群体智能算法。但这两条路都有自己的麻烦非线性规划对初值敏感稍微给个不好的初值就可能收敛到局部最优解而且不保证每次算出来的是同一个结果遗传算法之类则慢得让人抓狂算一遍可能几小时想画一条帕累托前沿得跑几十遍。二阶锥规划是凸优化的一种它最大的特点是只要问题写成标准形式求解器就能稳定找到全局最优解不需要猜初值速度比非线性规划快出不少。更关键的是电网的DistFlow模型和二极管的Weymouth方程在适当变量替换后都能被巧妙地松弛成二阶锥约束这使得“最优性有保证”这个优点可以直接延伸到电-气联合系统里。我做一个简单对比表求解思路全局最优初值依赖计算速度适用规模内点法解NLP否局部最优强中中小型遗传算法不严格无慢小型二阶锥规划是无快中大型对做学术探索和工程预研来说能保证全局最优这件事意义很大。它可以当“标准答案”去校验那些启发式算法的效果也可以直接作为生产调度模型。2. 系统建模把电网、气网和耦合设备写成可优化的数学形式2.1 电网侧为什么用DistFlow支路潮流模型电网建模最经典的是极坐标交流潮流方程里面有 cos 和 sin 三角函数整个约束强非凸。做优化求解时要么用牛顿法硬算要么做很多近似。这个项目里我改用DistFlow模型也叫支路潮流模型它主要面向配电网和辐射状输电网形式要友好得多。对于一条从节点 i 到节点 j 的支路DistFlow方程可以写成P_j P_i - R_ij * l_ij - p_j Q_j Q_i - X_ij * l_ij - q_j v_j v_i - 2 * (R_ij * P_ij X_ij * Q_ij) (R_ij^2 X_ij^2) * l_ij其中 v_i 是节点 i 电压幅值的平方l_ij 是支路电流幅值的平方R_ij 和 X_ij 是支路电阻和电抗。相比交流潮流方程这套式子没有三角函数所有网络约束都是线性的只额外引入一个二次等式P_ij^2 Q_ij^2 v_i * l_ij别小看这个变化。第一步“把复杂的非线性关系拆成线性关系加少量二次等式”是后面做二阶锥松弛的基础。如果直接用极坐标交流潮流光处理 cos 和 sin 就已经很麻烦了。2.2 气网侧Weymouth方程如何落地天然气网络的核心物理约束是管道流量方程工程上常用Weymouth方程近似。对一条管道如果节点 i 的压力高于节点 j稳态流量可以写成f_ij k_ij * sqrt(pi_i^2 - pi_j^2)这个方程的难点在于根号里的压力平方差。直接带入优化模型会形成一个相当复杂的非凸约束。常见处理方法是做变量替换令 w_i pi_i^2这样Weymouth方程变成f_ij^2 k_ij^2 * (w_i - w_j)如果在给定运行状态下管道流向事先已知那么 w_i - w_j 为正于是这个等式可以安全地松弛为不等式f_ij^2 k_ij^2 * (w_i - w_j)这个不等式刚好是一个旋转二阶锥约束可以直接交给求解器处理。压缩机部分再由压缩比约束和压缩机耗气约束补上。这样一个气网的稳态运行条件就被完整地包装进了凸优化框架。2.3 燃气轮机和电转气怎么进入方程电气两个网络在模型里不是各算各的它们需要通过耦合设备关联起来。最常见的两个设备是燃气轮机和P2G。燃气轮机的输入天然气能量和输出电功率之间满足效率关系P_gt eta_gt * gas_energy_in天然气热值乘以流入流量得到输入能量所以这个式子可以写成 P_gt 与天然气节点流量 f_in 之间的线性关系。引入燃气机组后电网节点的有功平衡方程就要加上它的输出而气网节点的流量平衡方程就要减掉它的天然气消耗。P2G是反向的用电能把水和二氧化碳合成天然气。它把电网节点的电负荷增大同时向气网节点输入天然气。效率通常在40%到60%之间。建立P2G模型时最需要注意的是单位换算电功率单位是MW天然气流量单位是m³/h热值系数一漏结果就跑飞了。2.4 多目标函数怎么写才不“打架”三个目标网损、电压偏差、天然气耗量量纲完全不同。网损单位是MW电压偏差是标幺值平方天然气耗量是m³/h。如果在目标函数里直接线性加权min w1 * f_loss w2 * f_voltage w3 * f_gas那么数值大的目标会完全压过数值小的目标等到求解完你甚至不知道是哪个目标在主导。我的做法是先把每个目标做归一化先单独优化每个目标得到各个单目标下的最优值作为基准再用“相对偏差”作为目标项。这样加权系数 w1、w2、w3 才有实际意义调权重时也更直观。3. 从非凸到凸二阶锥松弛的关键细节3.1 松弛到底是怎么来的前面说DistFlow里有一个二次等式 P_ij^2 Q_ij^2 v_i * l_ij。直接用这个等式做优化模型是非凸的因为这不是一个凸集合。二阶锥松弛的核心操作就是把这个“等式”放宽成“不等式”P_ij^2 Q_ij^2 v_i * l_ij这个不等式的集合是凸的。为了迎合求解器的标准形式还要把它换写成二阶锥约束。对每条支路 ij完整写法是|| [2*P_ij, 2*Q_ij, v_i - l_ij] ||_2 v_i l_ij展开之后你会发现它的平方形式和 v_i * l_ij 的不等式完全等价。这个变换的意义是原问题从一个看不见全局解的非凸区域被放大到了包含它的凸区域。如果最优解恰好落在以前那个“等式曲面”上那松弛就是紧的求出来的解就是原问题的最优解。3.2 松弛紧不紧不能靠感觉判断松弛成不等式之后有一个很现实的问题如果求出来的解里某些支路的 P_ij^2 Q_ij^2 严格小于 v_i * l_ij那这个解落在原非凸曲面之外从物理上解释不通。因为对于一个实际电网支路电流幅值的平方乘以电压幅值的平方必然等于通过功率的平方和。每次求解完我习惯算一个指标gap_ij (v_i * l_ij - P_ij^2 - Q_ij^2) / (v_i * l_ij)按工程经验gap_ij 小于 1e-4 可以视为紧此时SOCP解可以作为原问题的有效解。如果某些支路的gap明显偏大比如超过了0.5%那么这个算例就没有真正求解原始问题。3.3 目标函数的选择会影响松弛紧性很多资料会告诉你“配电网潮流松弛通常是紧的”但这句话有条件。它成立的一个重要原因是目标函数里包含网损项。网损等于 R_ij * l_ij 的累加目标函数为了降低网损天生有动力把 l_ij 压小从而让不等式往等式方向上收。一旦你在目标里加入大量电压偏差项情况就变了。求解器可能为了压低某些节点电压偏差选择更极端的电流分布导致某些支路 l_ij 虚高松弛就不紧了。所以做多目标问题时不能默认松弛一定紧要在每次求解后主动检查。3.4 松弛不紧的补救套路如果发现松弛不紧通常有几个办法。第一个是在目标函数里加一个很小的惩罚项效果是把松弛间隙压小。基本思路是在优化目标里附加 lambda * sum(gap_ij)lambda 从很小的值开始逐步增大反复求解直到所有支路都满足紧性要求。这个方法实现简单但需要多跑几次迭代。第二个办法是序列凸化。先解一次SOCP把得到的电压和功率作为参考点然后在参考点附近把锥约束再做一次线性化近似再求解并更新参考点。这种方式收敛快但比纯SOCP复杂不少。这类问题我在工程里优先用惩罚法简单粗暴而且调试方便。4. 实操记录算例搭建与求解器配置4.1 测试系统怎么选算例一开始不要上大系统。我自己是从一个改进的IEEE 33节点配电系统开始的然后在部分负荷节点旁挂了一个小型天然气网络。气网规模不用太大7个节点足够了但要包含至少一个气源、两段管道和一个燃气轮机接口。大系统的坑在于一旦出现不可行或者松弛不紧你根本不知道问题出在电网哪条支路还是气网哪个节点。先在33节点这种小规模系统上把所有逻辑调通再往IEEE 118节点或更大的网络上扩展才是高效路径。4.2 求解框架和工具选型我试过两条技术路线都可以走通。第一条是MATLAB里用YALMIP建模然后调用Mosek或Gurobi求解。YALMIP写二阶锥约束非常丝滑几乎不用处理底层细节适合快速验证模型。第二条是Python里用cvxpy建模配合ECOS、CLARABEL这类开源求解器好处是和矩阵运算、数据处理的生态集成度更高。两条路线对比建模框架求解器上手难度适合场景MATLAB YALMIPMosek / Gurobi低学术论文、快速原型Python cvxpyECOS / CLARABEL中工程集成、数据实验Python PyomoGurobi / SCIP中高复杂模型管理一个简化版的PythonCVXPY核心代码骨架如下import cvxpy as cp import numpy as np n_bus 33 n_branch 32 # 变量v为节点电压平方l为支路电流平方 v cp.Variable(n_bus, namev) l cp.Variable(n_branch, namel) P cp.Variable(n_branch, nameP) # 支路有功 Q cp.Variable(n_branch, nameQ) # 支路无功 Pg cp.Variable(n_bus, namePg) # 节点注入有功 Qg cp.Variable(n_bus, nameQg) # 节点注入无功 constraints [] # 节点功率平衡 # 这部分按具体拓扑写这里略 # DistFlow支路方程 for k, (i, j) in enumerate(branches): constraints.append( v[j] v[i] - 2*(R[k]*P[k] X[k]*Q[k]) (R[k]**2 X[k]**2)*l[k] ) # 二阶锥松弛 constraints.append( cp.SOC(v[i] l[k], cp.hstack([2*P[k], 2*Q[k], v[i] - l[k]])) ) # 目标网损最小 二范数电压偏移惩罚 objective cp.Minimize( cp.sum(R * l) 0.1 * cp.sum_squares(v - 1.0) ) prob cp.Problem(objective, constraints) prob.solve(solvercp.CLARABEL)这段代码只是一个建模骨架实际运行时需要把节点关联矩阵、负荷参数、气网约束全部补进去。核心是让你看到二阶锥约束在cvxpy里就是一个SOC对象而所有数据处理都可以用numpy数组来组织非常顺手。4.3 多目标求解加权法和ε约束法多目标求解我推荐先用ε约束法它比直接加权更能保证帕累托前沿的质量。操作过程是先最小化第一个目标比如网损得到最优网损值 f1_min然后把网损作为约束 f1 epsilon再最小化第二个目标比如电压偏差通过改变 epsilon 从 f1_min 往上扫描得到一组不同权衡下的解。这样画出来的帕累托前沿在非凸区域也一样有效。加权法也不是不能用。它的优点是速度快每次只解一个单目标SOCP最适合做在线调度和工程落地。但它的弱点是均匀调整权重不一定得到均匀的帕累托解而且在前沿非凸的时候会漏掉某些解。探索性研究阶段我会两种方法都做ε约束法用来画曲线加权法用来做定量对比。4.4 结果怎么分析才说明问题拿到求解结果后我通常会看三个层面的输出。第一是目标值层面的对比把电-气联合优化结果和传统“只做电网无功优化”的结果放一起观察网损、电压偏差、气耗量的变化。第二是松弛紧性检测输出所有支路的gap确保结果物理可解释。第三是网络物理量层面画出电压轮廓图、气网压力分布图观察是不是有节点压力过低或者电压越限。我当时一组典型算例的结果是联合优化相比纯电网优化系统网损进一步下降接近6%电压最大偏差降低约四成代价是气源供气量有所上升。这里要提醒一句不同算例具体数字差异很大重要的是分析方法别把某个固定系统的数值当成普遍规律。5. 我踩过的坑和排查实录5.1 压力平方量纲搞错导致求解器一直报错天然气节点的压力如果直接用Pa代入压力平方的量级是10^10甚至10^12而电网电压平方是1左右两个变量的数值差距非常夸张。我曾经在这个问题上折腾了整整一个下午模型明明没问题但求解器一直报数值不稳定甚至不可行。后来把所有压力用标幺值处理以基准压力为20 bar或者依据管网情况设定问题立刻消失。做电气综合能源系统优化第一课就是变量归一化。电网侧用标幺值气网侧也要用标幺值不要一个系统里混着绝对单位。5.2 Weymouth方程的双向流陷阱Weymouth方程里如果管道可能双向流动那么 w_i - w_j 的正负号不确定直接把等式松弛成 f_ij^2 k_ij^2 * (w_i - w_j) 就错了因为这个不等式的右边可能变负而左边是平方永远不会小于一个负数。出现这种情况求解器最终会告诉你模型不可行。处理办法有两个一是结合具体调度场景提前判断管道流向固定符号这在给定向工况下问题不大二是引入二进制变量区分流向但这会把模型变成混合整数二阶锥规划求解复杂度明显上升。对于纯探索性质的研究我建议从一开始就设定一个“流向已知”的简化条件先把主体框架跑通再谈扩展。5.3 电压偏差权重大了松弛竟然不紧这个问题在前面已经提过但我在调试中真正遇到时还是花了一段时间才反应过来。当时我在目标函数里把电压偏差惩罚系数设得很大结果求出的解里一条关键支路的gap达到0.3%怎么调宽容限都过不去。后来逐项排查才发现太强调电压合格导致求解器选择了环路电流更大的解使 l_ij 被人为抬高。解决方法是分两步走第一步用网损作为主目标求一个“基准紧解”第二步在这个解附近用惩罚法逐步加入电压偏差目标每次迭代后检查gap而不是一次性把权重拉到最大。这也是为什么多目标处理最好不要暴力加权的原因之一。5.4 模型不可行时的排查顺序遇到“infeasible”很多人第一反应是检查代码有没有写错。代码当然要检查但更系统的排查顺序应该是先检查边界条件是否一致比如燃气机组最大出力对应的耗气量是否超过了气源供气上限再检查电压上下限是否给得太紧把电压范围放宽到0.9到1.1再试一次最后检查管道流向假设和Weymouth约束里符号是否匹配。这种从“物理合理性”出发的排查比对着代码逐行看有效得多。6. 做完这个项目之后的一点个人体会如果让我给正准备做类似课题的人一句最实用的建议我会说先从“单目标、小系统、纯电网”开始跑通找手感的环节再把电网和气网耦合起来最后才加多目标和各种复杂扩展。不要一上来就想复现一篇顶刊论文的完整模型。二阶锥优化的门槛其实不高真正难的是对模型结构的理解——哪些约束可以凸化哪些必须保留哪些松弛之后不紧。把这些问题想清楚求解器只是一个顺手工具。我自己的下一步计划是把风电出力的不确定性加进去做成随机规划版本用二阶锥做底层确定性松弛之后上层再处理场景树和概率约束整体框架依然成立。这套思路从学术探索到工程预研都有空间值得继续挖下去。
