
最近好几个做电力系统优化的同行都在聊同一件事电网侧新能源渗透率越来越高碳中和约束又一步步收紧传统“只管有功、无功随便调”的思路越来越玩不转。“碳中和”目标下电气互联系统有功-无功协同优化模型这几年从论文标题一路火到实际工程验证Matlab生态里相关的开源代码和复现案例也越来越多。这篇文章就把这个模型从数学原理到代码实现完整拆一遍希望能给正在做电气互联系统优化、无功优化以及想用Matlab快速验证协同优化算法的朋友一些可落地的参考。不讲虚的全部按我实际跑通项目的经验来写。1. 为什么“碳中和”目标下必须做有功-无功协同优化1.1 电气互联系统究竟是什么先说清楚建模对象。所谓“电气互联系统”在国内论文里最常见的指代是电力系统与天然气系统的耦合也就是Electricity-Gas Integrated System。为什么这两个系统要放在一起看因为燃气轮机是当前支撑新能源消纳的重要调峰资源一台燃气轮机的出力直接决定从气网取多少燃料天然气的网络约束反过来又会限制电力的发电计划。你单独优化电网气网节点压力越界单独优化气网电网潮流又过载。这就是“互联”带来的核心矛盾。除了电力-天然气耦合有些研究还会把热力系统也拉进来形成电-气-热综合能源系统。但工程上电力系统和天然气系统的耦合建模最成熟也是“有功-无功协同优化”最经典的应用场景。这里的“电气互联”核心要抓住三点一是电能流和气能流分别遵循各自的网络方程二是燃气轮机是耦合变量三是两个网络的时间尺度不同稳态优化时可统一到同一个时段。1.2 只调有功或只调无功会出什么问题很多传统电力系统优化只把有功出力当作决策变量无功通过固定功率因数或简单比例分摊来处理。这个做法在N-1工况不复杂、网架结构坚强的系统里勉强能用但碰上高比例可再生能源接入问题就很明显了。新能源出力波动导致节点电压频繁越限此时如果无功资源不能灵活响应电压失稳风险会迅速放大反过来如果只优化无功不调整有功系统的线路潮流可能长时间处于重载状态网损居高不下碳排放也跟着增加。打个生活化的比方开一辆车跑山路你只踩油门不修方向车早晚冲出路肩你只打方向盘不控制车速遇到连续弯道或者陡坡也一样出事。只有油门和方向盘协同配合才能在保证安全的前提下跑得又快又省油。电网里的“油门”是有功“方向盘”就是无功。协同优化要做的就是在满足电压、潮流、气网压力等一系列约束的前提下同时找出有功和无功的最优配合策略让运行成本、网损和碳排放综合指标最优。2. 协同优化模型的数学表达2.1 目标函数的设计建立协同优化模型的第一步是把“碳中和”目标翻译成可以优化的数学语言。最常规的做法是采用多目标加权求和把经济性、低碳性和网络损耗一起放进目标函数[ \min \quad F \alpha_1 \sum_{i \in G}(a_i P_{Gi}^2 b_i P_{Gi} c_i) \alpha_2 \sum_{j \in S} C_{j} F_{Sj} \alpha_3 \cdot P_{loss} ]其中第一项是常规机组发电成本第二项是气源供气成本第三项是全网有功损耗。向量 (\alpha) 是各个分目标的权重具体数值可以根据运行偏好调整。如果想让模型更有“碳中和”色彩还可以在目标函数里加入碳排放成本项比如给燃气轮机和火电机组的单位碳排放量乘一个碳价系数把排放量折算成经济成本。我在实际建模时的一个习惯是先跑一次不带权重的单目标优化看每个子目标的大致量级再根据量级差选择权重。否则容易出现某个子目标数值特别大直接主导整个目标函数其他子目标形同虚设。这一点看起来不起眼但很多人第一次跑出来的结果非常离谱根子就在权重没归一化。2.2 约束条件的梳理约束条件是这个模型真正复杂的地方。电网侧需要满足交流潮流方程包括节点有功功率平衡和无功功率平衡[ P_{Gi} P_{Wi} - P_{Di} V_i \sum_{j \in N_i} V_j (G_{ij}\cos\theta_{ij} B_{ij}\sin\theta_{ij}) ][ Q_{Gi} - Q_{Di} V_i \sum_{j \in N_i} V_j (G_{ij}\sin\theta_{ij} - B_{ij}\cos\theta_{ij}) ]此外还有节点电压上下限、发电机有功/无功出力上下限、线路潮流上限、变压器分接头范围和无功补偿装置容量限制。气网侧则需要满足节点气流平衡、气源供气能力约束、管道稳态水力方程通常用Weimouth方程描述和节点压力上下限。电气互联的耦合约束是整个模型的关键它把燃气轮机的有功出力和气网节点的注入流量联系起来[ P_{GT} \eta_{GT} \cdot LHV \cdot F_{GT} ]式中 (F_{GT}) 是燃气轮机消耗的天然气流量(\eta_{GT}) 是发电效率LHV是天然气低位热值。这条约束一旦写错或漏掉电网和气网就变成两个互不影响的独立系统模型也就失去“协同”的意义了。2.3 耦合变量与求解难点有功-无功协同优化模型的难点首先来自决策变量类型杂。有功出力、无功出力、节点电压幅值、电压相角、气源流量、压力变量这些变量分布在两个网络里量纲完全不统一数值尺度可能差好几个数量级直接扔给求解器很容易出现数值病态问题。其次是模型非凸。交流潮流约束本身就是非凸的Weimouth方程也是非线性的再加上整数变量变压器档位、电容器投切组数整个模型是一个混合整数非线性规划MINLP。严格求解这个模型在多项式时间内是做不到的。这也是为什么很多文章会引入凸松弛技术比如二阶锥松弛或半定规划松弛把交流潮流约束松弛成凸形式从而把原问题转化为可以高效求解的凸优化问题。我自己的项目经验是对于小规模测试系统比如IEEE 9节点或IEEE 39节点电网搭配一个20节点左右气网直接使用非线性规划求解器就能处理如果扩展到较大规模系统二阶锥松弛几乎是必须的。下面Matlab实现章节会分别给出这两种思路的代码组织方式。3. Matlab代码实现全流程3.1 建模工具与求解器选型Matlab做协同优化最舒服的路径不是手写求解器而是用优化建模工具箱封装问题。我推荐用YALMIP它的语法接近数学表达式本身写起来直观、迭代快。求解器方面针对非线性规划问题选择Ipopt或fmincon如果采用二阶锥松弛后的凸优化模型用Mosek或Gurobi效果最好如果问题规模不大且需要兼容性好Matlab自带的quadprog也能应付。这里有个选型上的注意点YALMIP只是建模层真正求解还是要靠后端求解器。如果只想快速验证算法IpoptFmincon的组合够用Mosek和Gurobi则需要额外安装学术许可证。Mosek对二阶锥问题的求解稳定性非常突出做大规模协同优化值得专门花时间配置。3.2 核心代码段以YALMIP搭建协同优化模型下面这段代码是我项目中核心建模部分的简化版本基本把协同优化模型的骨架搭出来了。使用YALMIP定义变量和约束用非线性规划求解器求解。% 电网络参数节点数n_ebus支路导纳G/B发电机节点gen_bus % 气网络参数气节点数n_gbus管道参数K_pipe气源节点source_bus % 决策变量 P_G sdpvar(n_gen, 1); % 发电机有功出力 Q_G sdpvar(n_gen, 1); % 发电机无功出力 V sdpvar(n_ebus, 1); % 节点电压幅值 Th sdpvar(n_ebus, 1); % 节点电压相角 F_s sdpvar(n_source, 1); % 气源注入流量 F_p sdpvar(n_pipe, 1); % 管道流量 P_gas sdpvar(n_GT, 1); % 燃气轮机有功出力 % 目标函数 Cost_G sum(a.*P_G.^2 b.*P_G c); % 发电成本 Cost_S sum(gas_price.*F_s); % 供气成本 P_loss sum(P_G) - sum(P_D); % 网损近似 Objective Cost_G Cost_S lambda * P_loss; % 电网络约束 Constraints []; Constraints [Constraints, V_min V V_max]; Constraints [Constraints, P_G_min P_G P_G_max]; Constraints [Constraints, Q_G_min Q_G Q_G_max]; % 节点有功平衡只列关键表达式实际需含全部节点 for k 1:n_ebus % 简化的潮流等式实际项目中调用函数calc_power_balance Constraints [Constraints, ... P_G(k) P_W(k) - P_D(k) V(k)*sum(V.*(G(k,:).*cos(Th-Th(k)) B(k,:).*sin(Th-Th(k))))]; end % 气网络约束 for p 1:n_pipe % Weimouth方程简化形式此处用二次约束示例 Constraints [Constraints, F_p(p)^2 K_pipe(p)*(Pi_in(p)^2 - Pi_out(p)^2)]; end % 气源与压力约束 Constraints [Constraints, F_s_min F_s F_s_max]; Constraints [Constraints, Pi_min Pi Pi_max]; % 电气耦合约束燃气轮机耗气量决定其有功出力 Constraints [Constraints, P_gas eta_GT * LHV * F_gas_GT]; % 汇总所有约束并求解 Constraints [Constraints, sum(P_gas) F_GT_total]; % 发电机与燃气轮机的连接关系 optimize(Constraints, Objective, sdpsettings(solver,ipopt,verbose,2));这段代码不是完整能直接跑的项目文件但结构上代表了典型实现。你拿到一个别人的代码包时照着这个骨架去识别变量定义、约束组装和求解设置三个部分通常能很快定位问题。3.3 数据组织与求解流程协同优化模型的代码工程化最考验练习者的地方其实是数据组织。电网的节点、支路、负荷参数气网的管道、气源、压力参数以及耦合单元参数如果全部手写在脚本里后期改一个节点都要翻半天。我建议把所有原始数据放到Excel或struct结构体里按系统编号索引。求解流程上一般分成三步第一步读入并校验数据包括电网拓扑是否完整、气网管道连接是否成环第二步构建变量、目标函数和约束这一阶段最容易出错的是for循环里节点编号和数组索引对不上第三步调用求解器并分析结果。如果追求更稳定的数值性能建议把电压和角度归一化到1附近把流量参数处理成标幺值模型可以显著降低求解器遇到数值病态的概率。4. 仿真算例设计与结果解读4.1 测试系统构建为了验证协同优化算法的有效性一个标准做法是构造一个由IEEE标准电网和标准天然气网络通过燃气轮机耦合而成的测试系统。我在项目中常用的配置是电网部分用IEEE 39节点系统气网部分用一个10节点左右的天然气网络通过三台燃气轮机将电网节点与气网节点连接起来。把新能源出力设置为高渗透率场景比如风电渗透率30%左右同时保留部分常规火电作为备用。算例设计要特别注意对照组的设置。至少要跑两个场景场景A是“独立优化”即电网只按负荷需求抛出有功计划无功用固定功率因数折算气网仅根据燃气轮机预测出力做供气安排场景B是“协同优化”也就是采用本章前面建立的有功-无功协同模型。没有对照组优化结果的好坏就无从谈起。4.2 从结果数据中能读到什么协同优化相对独立优化的收益通常体现在三个维度总有功损耗下降、电压偏差减小、运行成本与碳排放降低。在我的测试算例中场景B相比场景A通常可以使系统总网损降低5%-12%最大电压偏差缩小20%以上。如果气网压力约束紧张协同优化的优势会更明显因为模型能主动调整燃气轮机出力安排避免气网局部压力越限。这里补充一个容易忽略的细节协同优化变优的空间和系统参数强相关。天然气网络越“拥挤”电网负荷峰谷差越大协同优化的收益越高。你如果复现一个算例发现收益只有2%-3%先别怀疑算法检查一下系统是否本来就非常松弛约束几乎没有起作用。这种情况下优化空间的物理极限就很小模型再好也变不出花来。5. 实操中常见的坑与调参经验5.1 求解不收敛或收敛慢怎么办我在这类项目上被“折磨”最多的就是求解器不收敛。经常出现的情况是YALMIP建模没问题但Ipopt迭代几百步后停在边界上或者直接报“Restoration failed”。这个问题八成出在初始点上。非线性规划对初值非常敏感你可以按以下策略尝试先用直流潮流(忽略无功和电压幅值)求一个粗糙的有功计划作为交流潮流变量的初值电压幅值初始值设成1.0相角设成0这是最保守也最常用的做法气网压力初值不要全设上限值取管道两端的平均值往往效果更好如果仍然不收敛尝试把Weimouth方程两侧同时开方做变量代换把二次等式转化为线性约束代价是损失精度但能有效提高收敛性。5.2 数值尺度问题协同优化模型里电网和气网的变量尺度差异很大电压量级是1气网压力可能是几十甚至上百导致Jacobian矩阵条件数变大。一个常见的解决方法是把所有物理量标幺化。我习惯以100MVA为基准功率以管道标准压力为基准压力把整个系统做成纯标幺值模型。改造之后Ipopt的迭代步数通常能减少三分之二以上。另外目标函数权重差异化过大也会导致求解器走偏。比如网损项数值很小发电成本项数值很大加权求和之后梯度被发电成本主导网损优化相当于名存实亡。面对这种情况我通常先跑一次不包含次要目标的优化得到各分量的参考量级再按1:1:0.1这种比例去设定权重。这个方法虽然土但非常有效。5.3 结果合理性检验最后提醒一点拿到求解结果不要急着画图先做两步校验。第一步是回代校验把最优解代入原始潮流方程看等式两侧残差是否在可接受范围内。第二步是看物理量是否有“诡异值”比如某个节点电压等于下限值同时该节点附近又没有任何无功补偿或者某条管道流量接近上限但两侧压力几乎相等这种结果大概率是约束建模漏了或变量关系写错。6. 顺手分享一个提高开发效率的小技巧做这类协同优化模型代码里的矩阵运算和for循环最容易消磨耐心。我个人的工作习惯是在Matlab脚本里把所有可复用的计算潮流计算、气网流动计算、目标函数评估都封装成function文件然后在主脚本里用统一的输入输出结构体去调用。这样在对比不同求解器、调节权重时只需要修改主脚本传入参数而不需要到处改动核心函数。另一个小技巧是合理使用YALMIP的assign和value命令在做灵敏度分析时不用重复求解整个优化问题可以直接在原最优解附近做扰动计算节省的时间非常可观。这个有功-无功协同优化模型的实际坑点和调试手段基本就是上面这些。如果你手头正拿到一份Matlab代码复现项目建议按“数据核对-约束审查-初值调整-结果回代”的顺序走一遍大多数跑不通、跑不对的问题都能在这个流程里找到源头。我最初做这个模型时也绕了不少弯路后来发现把功夫花在约束正确性和数值稳定性上比盲目调求解器选项有用得多。希望这篇文章能帮你少踩几个坑较快跑通第一版可用的协同优化算例。