1. 为什么区域综合能源系统的能流计算比想象中难
先聊一个经常被忽略的事实:在传统电力系统里,能流计算(潮流计算)早就成熟到可以无脑调库,但在区域综合能源系统里,电气热三种能源互相耦合之后,问题就完全变样了。电网的潮流方程、天然气网的管道方程、热网的供回水温度方程,各自单独算都很成熟,一旦用耦合设备(燃气轮机、电锅炉、吸收式制冷机、热泵)把它们接到一起,就出现了一个共同的问题——每个子网络都有自己的“状态变量”和“边界条件”,但耦合设备又把不同网络的物理量绑在一起。这时候再分网迭代,经常出现不收敛或者收敛极慢的情况。
我做这个课题时候的切入点是“计及多能耦合”,说白了就是要把电、气、热三个网络放在一个统一的框架里联立求解,而不是各自为政。这个思路在算法层面体现为:建立统一的能流方程,把电网的电压幅值与相角、气网的节点气压、热网的供回水温度与节点流量全部作为待求状态变量,联立成一个大规模非线性方程组,然后用牛顿-拉夫逊法统一迭代。
适合看这篇文章的读者,应该是有一定Matlab编程基础、正在做综合能源系统方向研究或工程项目的同学。你可以从这里拿到一套可复用的程序思路和建模细节,而不是只看到一个“能跑”的结论。整套方案我自己在Matlab里实现过,也算踩了不少坑,文中会把关键细节和容易出错的地方都写清楚。
2. 多能耦合建模:从设备物理过程到网络方程
2.1 耦合设备的数学描述是整套模型的灵魂
先明确一个基本事实:区域综合能源系统的“耦合点”不在物理管道或线路本身,而在那些连接不同能源网络的设备上。比如热电联产机组一边烧天然气发电,一边回收余热供热;电锅炉一边耗电一边产热;热泵用电力驱动从低温热源提取热量。这些设备的输入输出关系,就是连接电气热三网方程的那几根“导线”。
以最常见的燃气轮机CHP机组为例,它的发电功率和天然气消耗量之间有关系,余热回收又和热功率输出有关系。实际建模中我通常用下面这组关系简化:
- 燃气消耗量(输入能量)乘以发电效率得到电功率,剩余热量中一部分通过余热锅炉回收为热功率;
- 发电效率不是常数,而是随负荷率变化的曲线,但在一阶近似里可以取额定工况点附近的线性化结果。
这里有一个关键决定:不能只用固定效率模型,因为后续做能流计算时需要雅可比矩阵,涉及对这些变量求偏导。如果效率是常数,方程形式简单,但准确度在偏离额定工况较远时不够。我最终采用的方法是:用二次曲线拟合发电效率与电功率的关系,也就是:
F_gas(P_e) = (a * P_e^2 + b * P_e + c) / eta_rated * LHV
其中LHV是天然气低位热值。这样虽然让方程稍微复杂了点,但后续在雅可比矩阵里只需要多算两个多项式导数项,影响不大。
热泵和电锅炉的模型就简单得多:热泵的制热功率等于耗电功率乘以制热系数COP,电锅炉则是把电能近似全部转化为热能,效率一般在0.95以上。
必须提醒的是:热网侧的换热站、热力站等节点同样存在“等效耦合”关系。比如一次网供水温度进入换热站,经过换热后变成二次网供水,换热量与一次网流量、温差、换热效率三者相关。如果这些环节全都要建模,整个热网方程会在温度变量之外多出一层流量-温度耦合关系,方程组的非线性程度会显著上升。在你的程序里,建议先做简化:把换热站处理成固定热功率或固定流量节点,等基本能流计算收敛稳定了,再做精细化展开。
2.2 电网、气网、热网的方程形式差异
三个网络的方程结构差异是统一求解最大的麻烦来源,这里得认认真真对比着看。
电网的潮流方程是最经典的形式。对于节点i,有功与无功注入满足:
P_i = V_i * Σ(V_j * (G_ij * cos(θ_ij) + B_ij * sin(θ_ij))) Q_i = V_i * Σ(V_j * (G_ij * sin(θ_ij) - B_ij * cos(θ_ij)))
这里的G和B是节点导纳矩阵的实部虚部,θ_ij是节点电压相角差。电网的独立变量是V和θ,每个节点两个变量。
天然气网的方程走的是管道流量公式。对连接节点m和n的管道,标况流量f_mn与两侧气压p_m、p_n的关系可以写成:
f_mn = k_mn * sqrt(p_m^2 - p_n^2)
这里的k_mn是管道特性参数,由管径、管长、摩擦系数、气体温度等决定。每个节点只有一个气压变量,方程比电网少一半。但气体流动是有方向性的,如果系统存在环网,需要在管网里设定流动方向,节点气压可能低于某个值导致压缩机需要参与调节,这部分让非线性进一步增加。
热网方程又要换一套思路。热网本质上是一个水力-热力联合系统:水力工况决定各管段流量分配,热力工况决定节点供回水温度。用节点法建模时,热水管网的状态变量是:各节点的供回水温度(T_s、T_r)和管道流量(m),再加上压力相关变量。如果采用简化集总参数模型,整个管网可以用下面三个核心关系描述:
- 节点流量连续性方程(基尔霍夫第一定律在热网上的应用)
- 环路压力平衡方程(各环路的压降代数和为零)
- 节点温度混合方程(多股不同温度水流在节点混合后的温度)
温度混合方程是热网非线性最强的部分。不同温度、不同流量的热水在一个节点汇合,平均温度取决于加权流量:
T_mix = Σ(m_i * T_i) / Σ(m_i)
这个方程在雅可比矩阵里会带来流量和温度变量之间的交叉导数项,写程序时容易漏。
2.3 耦合变量的统一表达框架
既然要把三个网络放在同一个方程组里求解,核心问题是:状态变量选什么?
我的做法是全部状态变量按列堆叠成一个大的向量:
x = [θ; V; p_gas; T_s; T_r; m]
其中θ是电网除平衡节点外的相角,V是电网PQ节点电压幅值,p_gas是气网除平衡节点外的节点气压,T_s、T_r是热网各节点供回水温度,m是热网各管段流量。
方程组的残差也按同样顺序排列:
F = [F_elec_active; F_elec_reactive; F_gas_flow; F_thermal_hydraulic; F_thermal_heat]
统一方程写成 F(x) = 0,然后用牛顿-拉夫逊法迭代:
x_{k+1} = x_k - J^{-1} * F(x_k)
这里的J就是整个综合能源系统的雅可比矩阵。它的规模是所有子网络雅可比矩阵的叠加,再加上耦合设备带来的分块耦合项。写程序时可以直接对整个F和x求数值偏导,不必手工推导所有解析导数,但如果追求计算速度和稳定性,还是建议对电网、气网、热网分别形成子雅可比矩阵,再按耦合关系拼接成块状矩阵,这样更加清晰可控。
3. 牛顿-拉夫逊统一求解法在Matlab中的落地细节
3.1 整体求解流程与初值设定
这套程序的核心框架其实不复杂,关键步骤就五步。
第一步,初始化各网络参数,包括电网线路阻抗、气网管道参数、热网管道阻力系数和换热参数,以及所有耦合设备的运行参数。第二步,给定初值:电网各节点电压幅值设1.0(标幺值),相角设0;气网各节点气压设管网额定压力,一般取0.4MPa到0.8MPa之间;热网各节点供回水温度分别设设计值,比如供水90摄氏度、回水50摄氏度;热网管道流量初值用各节点设计负荷除以比热容和设计温差粗略估算。第三步,计算所有节点的残差F。第四步,组装雅可比矩阵,求解增量Δx。第五步,判断收敛条件,一般取Δx的无穷范数小于1e-6,或者F的无穷范数小于1e-6。
这里初值的选取真的非常影响收敛性。尤其是热网温度,如果初值和实际运行值偏差超过40摄氏度,迭代过程中温度混合方程和热负荷方程很容易出现负温度或者发散。我自己的经验是,热网温度从设计工况初值出发是最稳的,不要在完全未知的情况下乱猜。
3.2 雅可比矩阵的组装技巧
统一雅可比矩阵的结构长这样:
| ∂F_e / ∂θ ∂F_e / ∂V ∂F_e / ∂p ∂F_e / ∂T ∂F_e / ∂m | | ∂F_g / ∂θ ∂F_g / ∂V ∂F_g / ∂p ∂F_g / ∂T ∂F_g / ∂m | | ∂F_t / ∂θ ∂F_t / ∂V ∂F_t / ∂p ∂F_t / ∂T ∂F_t / ∂m |
其中对角块恰好对应各自的子网络雅可比矩阵。非对角块是耦合设备的贡献。比如CHP机组连接电网节点和气网节点,那么它会在电网有功方程中对气网节点压力求偏导产生一个非零项,同时会在气网流量方程中对电网电压相角求偏导有非零项。所有非对角块都来自耦合设备,一般用稀疏矩阵存储就足够了。
Matlab实现时有个性能陷阱:如果直接对全系统用数值差分法算雅可比矩阵,一个n维系统每次迭代要做n次完整残差计算,n稍微大一点(比如超过200个状态变量),速度就开始拉了。我建议至少对电网部分使用解析式或半解析式写雅可比,气网和热网如果嫌麻烦可以用差分,但整体稀疏化一定要做。用稀疏矩阵配合Matlab的lu分解,求解速度能比稠密矩阵快一个数量级。
3.3 收敛判据与阻尼牛顿法的必要性
牛顿法在接近解附近收敛极快,但如果初值离解太远,很容易振荡甚至发散。我在实际计算中遇到最典型的情况是:气网方程中的平方根项在迭代中间步骤出现负电压平方差值,导致复数出现,整个残差变成NaN。
解决办法是加阻尼因子,也就是修正方程变成:
x_{k+1} = x_k - α * J^{-1} * F(x_k)
其中α取自适应策略:初始设为1,如果这次迭代后残差范数没有下降,就把α减半重试,直到残差确实下降再继续下一步。这个操作实现起来不过十行代码,但稳定性提升非常明显。
另一个提高鲁棒性的做法是变量归一化。电网电压是标幺值,数量级接近1;气压可能到几兆帕;热网温度是几十到一百摄氏度。这些变量数量级差太大,雅可比矩阵容易出现严重的条件数问题,导致求解器精度下降。我把气压除以基准压力、温度减去基准温度再除以基准温差,全部转为相对量,整个迭代过程平稳得多。
4. Matlab程序实现的核心模块划分
4.1 数据输入与网络拓扑搭建
程序整体结构我分成了四个模块:数据输入模块、方程残差模块、雅可比矩阵模块和主迭代模块。
数据输入模块用结构体保存所有网络参数。电网结构体保存节点导纳矩阵、平衡节点编号、PV节点列表、各节点负荷;气网结构体保存管道连接关系、管道直径、长度、摩擦系数、节点负荷流量;热网结构体保存管道拓扑、阻力系数、节点热负荷、换热站参数;耦合设备结构体保存CHP机组参数表、热泵容量、电锅炉效率等。
这里有个非常重要的拓扑处理细节:热网的温度混合方程依赖各管段流向。我的做法是把每条热网管道赋予一个初始假设流向,在迭代过程中检查流量符号,如果为负就翻转管段方向并重新组装温度混合矩阵。这个话题在文献里往往被一笔带过,实际代码里却直接影响正确性,不处理会出现混合温度算错的情况。
4.2 残差计算函数的设计逻辑
残差计算函数是整个程序最核心的地方。函数签名建议写成:
function F = system_residual(x, net)
% 从x中提取电网、气网、热网状态变量
% 1. 计算电网潮流残差
% 2. 计算气网流量残差
% 3. 计算热网水力和热力残差
% 4. 计算耦合设备接口方程残差
end
电网潮流残差就是经典的有功无功失配量。气网残差是把每个节点的注入流量与管道流出流量之差作为残差。热网残差分为两部分:水力方程残差是各节点流量连续量和环路压降,热力方程残差是节点温度方程和热负荷方程。
耦合设备接口残差要特别说明。一台CHP机组连接电网和气网,它在电网里是一个功率注入源,注入量取决于自身发电功率P_e(这个变量需要单独处理)。我的处理方法是在状态变量里显式加入耦合设备的内部变量(比如CHP的P_e),让方程维度稍微增加,但方程结构更加规整。这样处理的好处是,限制设备运行可行域和爬坡约束时,可以直接在迭代过程中检测这些变量是否越界,而不需要额外映射。
4.3 主迭代控制与结果输出
主迭代部分我写了一个标准牛顿-拉夫逊流程,附加自适应阻尼和收敛监视。每次迭代后把残差范数和最大修正量打印出来,方便实时观察收敛趋势。程序收敛后,把所有状态变量还原为物理值,输出到table结构体里保存。
这里有一个我自己踩过的坑:Matlab的struct嵌套访问会拖慢循环速度,尤其是残差计算里反复调用net.elec.branch这种路径。在规模不大(几十个节点)的情况下感受不明显,但一旦热网节点超过100个,单次残差函数调用时间会线性恶化。解决办法是在初始化时把所有参数展开成扁平数组,比如直接保存导纳矩阵为完整稀疏矩阵,管道参数存成列向量,这样残差函数内部只做向量和矩阵运算,不反复访问嵌套结构体。
5. 典型算例验证:收敛行为、精度与灵敏度
5.1 算例配置
为了验证程序可靠性,我构造了一个24节点的综合能源系统算例。电网部分用IEEE 24节点系统的拓扑参数,在原基础上挑出6个节点挂接CHP机组和电锅炉;气网部分设置11个节点,包含2个气源节点,其中1个作为平衡节点;热网部分设置14个负荷节点,换热站接入CHP和电锅炉供热。
耦合配置如下:2台CHP机组容量分别为1.8MW和2.4MW,连接电网和气网并向热网供热;1台2MW电锅炉连接电网和热网;1台1.5MW热泵连接电网和热网。所有负荷取典型冬季工况值,总电负荷约12MW,总热负荷约9MW。
5.2 收敛过程与精度分析
程序在初值给定后第6次迭代达到10^-6的收敛精度。观察每次迭代的残差范数变化,能明显看到前两轮下降幅度大,之后进入了牛顿法典型的二次收敛区间。这说明统一求解法的收敛特性和传统单一潮流很接近,只要初值合理、雅可比矩阵组装正确,没有出现因为多能耦合而导致的本质性数值困难。
精度方面我做了交叉验证:把程序算出来的CHP出口电功率和热功率分别代入独立的电网潮流程序和热网水力热力计算工具,各自独立算一遍结果基本吻合。电网电压偏差在0.001标幺值以内,热网节点供回水温度偏差在0.5摄氏度以内。这个精度对于规划和运行分析都够用了。
5.3 耦合强度对迭代行为的影响
我还专门做了耦合强度扫描实验,看耦合设备容量变化对收敛性和能流结果的影响。方法是把CHP和热泵的容量乘以一个比例系数,从0.5扫到1.5,记录收敛迭代次数和关键节点电压、温度变化。
结果是比较符合预期的:耦合系数从0.5提高到1.5的过程中,电网平衡机出力理论上下降约30%,热网节点平均温度整体提高约12摄氏度,迭代次数从5次慢慢增加到7次,没有出现发散。说明这个程序架构对于一定范围内的工况变化是稳定的,不需要针对每种工况做特殊处理。
6. 多能流计算中的常见错误排查与性能优化
6.1 量纲与单位不统一导致的隐性错误
这类程序里最隐蔽的问题几乎都是单位问题。电网习惯用MW和MVar,气网用m³/h或者kg/s,热网用kW或者MW。如果从文献或实际管网拿到的数据不加以统一就直接代入方程,结果往往看起来正常、实际上有数量级的偏差。
我的建议是在数据输入模块的最前面,把所有量纲强制转换到统一单位体系。电功率统一用MW,天然气流量统一转换成对应的能量单位MW(通过低位热值折算),热功率统一用MW,天然气压力统一用MPa,温度统一用摄氏度。这样每个方程里就不再残留任何隐含换算因子,后续调试时用能量守恒一验就能发现大部分错误。
6.2 边界条件的合理设置直接决定方程定解
统一能流方程能不能解,很大程度上取决于边界条件数量。电网需要一个平衡节点承担全网有功无功缺额,气网需要一个气源平衡节点,热网需要至少一个定温节点(通常是热源出口供水温度固定),或者用定流量边界再加足够的热负荷方程。三者缺任何一个,方程组都可能出现秩亏,导致雅可比矩阵奇异。
我在代码里做了一个基础检查函数:计算状态变量数和方程数是否相等,并在主迭代开始前检测雅可比矩阵是否奇异。如果发现奇异,就打印提示,指出是哪类变量少了约束。这个检查帮我在调整算例时省了大量排查时间。
6.3 性能瓶颈分析与稀疏化改造
程序跑起来之后,我最关心的性能瓶颈是雅可比矩阵求解环节。24节点系统状态变量数大约在150左右,稠密矩阵迭代一次要几十毫秒,但如果把系统规模扩到300个节点,稠密矩阵的求解速度就开始难以接受。
我做的优化有两条:
- 雅可比矩阵用稀疏存储,求解用Matlab内置的lu分解和左除(即 \ 运算)。Matlab的左除会自动对稀疏矩阵做重排序,效果比自己手工选主元好得多。
- 对常系数部分做预分解缓存。电网导纳矩阵和热网水力拓扑结构在一次计算中是不变的,只有运行工况变化导致雅可比矩阵局部变化,因此可以把结构不变部分的LU分解缓存起来,只更新耦合设备相关的模块系数,从而避免每次迭代都对整矩阵重新分解。实际测试下来,这个优化在反复运行多工况方案时能减少约50%的总体计算时间。
7. 扩展应用方向:从稳态能流迈向优化与动态分析
做完稳态能流计算,很多人马上会想着朝优化方向走。我自己在课题后续做的内容,是把能流计算嵌入到多能系统优化调度里。
代表性做法是:外部是优化层,决策变量是各耦合设备的出力设定值;内部是能流计算层,接收决策变量后计算全网能流,返回网损、节点电压越限量、天然气节点压力越限量等约束参数。这种“优化-能流”嵌套结构,常见于综合能源系统的日前调度和规划研究。
Matlab里实现这个嵌套需要额外做一件事:让能流计算函数在给定设备出力情况下不能出现不收敛。我采用的方法是给内部能流只保留3到5次迭代机会,如果在允许迭代次数内不收敛,就返回一个较大的惩罚值给优化目标,而不是让程序直接报错终止。这一招在实际操作中非常管用,可以避免在寻优过程中因个别不可行解导致整个优化中断。
另外,这套稳态能流程序也是进一步做动态仿真的很好起点。把热网管道用一阶惯性环节近似,电网用微分代数方程描述,能在同一套拓扑和参数基础上扩展为仿真模型。至少对我来说,稳态能流程序和动态仿真程序共用同一套数据表,能减少大量重复建模工作。
8. 个人实操总结与小结
项目做到后期,我对这套“统一能量流求解”框架的整体判断是:模型原理上讲得通,程序实现也没有想象中困难,但工程细节决定成败。
初值设定上我建议保守一点。多数收敛失败不是算法问题,而是给了太离谱的初始点。尽量从设计工况出发,逐步改变参数再热启动,会比一开始就瞄准高负荷工况稳定得多。
单位统一和边界条件检查应该做在程序框架的第一层,而不是等到计算结果出错再回头检查。我现在每次新建算例都会先跑一个“空载一致性检查”:把负荷全部设成零,看看全系统的状态变量是否收敛到平凡解,如果连这个都不收敛,那肯定是建模或拓扑哪里出了错。
阻尼牛顿法的实现虽然只有几行代码,但在气网和热网同时强耦合的场景下几乎等于救命稻草。维护代码时我会在每一次迭代后都记录残差序列,方便画出收敛曲线,不仅能直观看到收敛趋势,也能快速定位从第几步开始出问题。
最后一个建议是:所有计算结果的输出都保留原始物理量纲和中间变量的完整记录。做能流计算的最终目的不一定是算出一个电压或一个温度,而是为上层优化和决策提供可信的基础数据。如果输出只保留最终电压而不保留中间迭代信息,后续排查和复核的难度会成倍增加。
这套程序目前我已经拓展到了区域级综合能源系统的多场景运行分析,从稳态能流计算走向了安全校核和可靠性评估的层面。后续如果继续深化,可能还会加入热惯性时移特性和多时间尺度的能量管理逻辑,但无论怎么扩展,稳定可靠的能流计算始终是整个系统的地基。