eneros-powerflow
eneros-powerflow 提供电力系统潮流计算求解器,采用 Newton-Raphson 主方法,并支持 PQ 解耦与直流潮流作为快速近似。基于 eneros-linalg 的稀疏 LU 分解,1000 节点网络典型求解时间 < 10ms。潮流结果是约束校验、OPF、孪生体等上层分析的输入。
职责描述
eneros-powerflow 承担以下核心职责:
- YBus 构建:根据
eneros-topology提供的网络拓扑,构建稀疏 CSR 格式的节点导纳矩阵 - Newton-Raphson 求解:使用全雅可比矩阵迭代求解,自动处理 PQ / PV / Slack 三类节点
- 快速近似:提供 P-Q 解耦(FastDecoupled)与直流潮流(DC)两种轻量求解器
- 收敛诊断:功率残差 < 1e-8 收敛判定,发散时返回残差曲线供分析
- 结果缓存:拓扑未变更时复用上次结果,避免重复计算
- 支路潮流:求解后计算每条支路的有功、无功、损耗与负载率
关键类型与接口
PowerFlowSolver
use std::time::Duration;
use eneros_core::{BusId, BranchId, Result};
use eneros_topology::NetworkGraph;
pub struct PowerFlowSolver {
method: PowerFlowMethod,
tolerance: f64,
max_iterations: usize,
enable_cache: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PowerFlowMethod {
NewtonRaphson,
FastDecoupled,
DcPowerFlow,
}
impl Default for PowerFlowSolver {
fn default() -> Self {
Self {
method: PowerFlowMethod::NewtonRaphson,
tolerance: 1e-8,
max_iterations: 50,
enable_cache: true,
}
}
}
impl PowerFlowSolver {
pub fn new() -> Self {
Self::default()
}
pub fn method(mut self, m: PowerFlowMethod) -> Self {
self.method = m;
self
}
pub fn tolerance(mut self, t: f64) -> Self {
self.tolerance = t;
self
}
pub fn max_iterations(mut self, n: usize) -> Self {
self.max_iterations = n;
self
}
pub fn enable_cache(mut self, on: bool) -> Self {
self.enable_cache = on;
self
}
pub fn solve(&self, network: &NetworkGraph) -> Result<PowerFlowResult> {
let ybus = YBusMatrix::build(network);
let start = std::time::Instant::now();
let inner = match self.method {
PowerFlowMethod::NewtonRaphson => Self::solve_nr(network, &ybus, self.tolerance, self.max_iterations)?,
PowerFlowMethod::FastDecoupled => Self::solve_fd(network, &ybus, self.tolerance, self.max_iterations)?,
PowerFlowMethod::DcPowerFlow => Self::solve_dc(network, &ybus)?,
};
let duration = start.elapsed();
let branch_flows = Self::compute_branch_flows(network, &inner.buses);
Ok(PowerFlowResult {
converged: inner.converged,
iterations: inner.iterations,
residual: inner.residual,
duration,
buses: inner.buses,
branch_flows,
})
}
}
YBusMatrix
use eneros_linalg::SparseMatrix;
pub struct YBusMatrix {
pub data: SparseMatrix<Complex64>,
pub bus_order: Vec<BusId>,
}
impl YBusMatrix {
pub fn build(network: &NetworkGraph) -> Self {
let buses: Vec<BusId> = collect_bus_ids(network);
let n = buses.len();
let mut matrix = SparseMatrix::new(n, n);
let index: HashMap<BusId, usize> = buses
.iter()
.enumerate()
.map(|(i, id)| (id.clone(), i))
.collect();
for branch in network.iter_branches() {
if branch.status != BranchStatus::Closed {
continue;
}
let i = index[&branch.from];
let j = index[&branch.to];
let z = Complex64::new(branch.params.r_pu, branch.params.x_pu);
let y = Complex64::new(0.0, 0.0) - z.inv();
matrix.add(i, j, -y);
matrix.add(j, i, -y);
matrix.add(i, i, y + Complex64::new(0.0, branch.params.b_pu / 2.0));
matrix.add(j, j, y + Complex64::new(0.0, branch.params.b_pu / 2.0));
}
Self { data: matrix, bus_order: buses }
}
}
PowerFlowResult
use eneros_core::{Voltage, BusId, BranchId};
pub struct PowerFlowResult {
pub converged: bool,
pub iterations: usize,
pub residual: f64,
pub duration: Duration,
pub buses: Vec<BusSolution>,
pub branch_flows: Vec<BranchFlow>,
}
#[derive(Debug, Clone)]
pub struct BusSolution {
pub id: BusId,
pub voltage: Voltage,
pub p_pu: f64,
pub q_pu: f64,
}
#[derive(Debug, Clone)]
pub struct BranchFlow {
pub from: BusId,
pub to: BusId,
pub p_from_pu: f64,
pub q_from_pu: f64,
pub p_to_pu: f64,
pub q_to_pu: f64,
pub loading_percent: f64,
pub loss_pu: f64,
}
impl PowerFlowResult {
pub fn bus_by_id(&self, id: &BusId) -> Option<&BusSolution> {
self.buses.iter().find(|b| &b.id == id)
}
pub fn total_loss_pu(&self) -> f64 {
self.branch_flows.iter().map(|f| f.loss_pu).sum()
}
pub fn max_loading(&self) -> Option<&BranchFlow> {
self.branch_flows.iter().max_by(|a, b| {
a.loading_percent.partial_cmp(&b.loading_percent).unwrap()
})
}
}
核心 API
| 方法 | 签名 | 说明 |
|---|---|---|
PowerFlowSolver::new | fn new() -> Self | 构造默认求解器(NR / 1e-8 / 50 iter) |
PowerFlowSolver::method | fn method(self, m: PowerFlowMethod) -> Self | 设置求解方法 |
PowerFlowSolver::tolerance | fn tolerance(self, t: f64) -> Self | 设置收敛容差 |
PowerFlowSolver::max_iterations | fn max_iterations(self, n: usize) -> Self | 设置最大迭代次数 |
PowerFlowSolver::enable_cache | fn enable_cache(self, on: bool) -> Self | 启用/禁用结果缓存 |
PowerFlowSolver::solve | fn solve(&self, network: &NetworkGraph) -> Result<PowerFlowResult> | 执行潮流计算 |
YBusMatrix::build | fn build(network: &NetworkGraph) -> Self | 构建节点导纳矩阵 |
PowerFlowResult::bus_by_id | fn bus_by_id(&self, id: &BusId) -> Option<&BusSolution> | 按母线 ID 查询解 |
PowerFlowResult::total_loss_pu | fn total_loss_pu(&self) -> f64 | 网络总有功损耗(标幺值) |
PowerFlowResult::max_loading | fn max_loading(&self) -> Option<&BranchFlow> | 最大负载率支路 |
使用示例
基础潮流计算
use eneros_powerflow::{PowerFlowSolver, PowerFlowMethod};
use eneros_topology::{NetworkGraph, Bus, Branch, BranchParams, BusType};
use eneros_core::Voltage;
let mut net = NetworkGraph::new();
net.add_bus(Bus::new("1", BusType::Slack, Voltage::new(1.05, 0.0)));
net.add_bus(Bus::new("2", BusType::PQ, Voltage::new(1.00, 0.0)));
net.add_bus(Bus::new("3", BusType::PV, Voltage::new(1.02, 0.0)));
net.add_branch(Branch::new("1", "2", BranchParams::line(0.1, 0.2, 0.02)));
net.add_branch(Branch::new("2", "3", BranchParams::line(0.05, 0.1, 0.01)));
net.add_branch(Branch::new("1", "3", BranchParams::line(0.08, 0.15, 0.015)));
let solver = PowerFlowSolver::new()
.method(PowerFlowMethod::NewtonRaphson)
.tolerance(1e-8)
.max_iterations(50);
let result = solver.solve(&net)?;
println!(
"收敛: {} 迭代: {} 残差: {:.2e} 耗时: {:?}",
result.converged, result.iterations, result.residual, result.duration
);
for bus in &result.buses {
println!(
"母线 {}: V={:.4} θ={:.4}rad P={:.4} Q={:.4}",
bus.id, bus.voltage.magnitude.0, bus.voltage.angle.as_radians(),
bus.p_pu, bus.q_pu
);
}
支路潮流与负载率
let result = solver.solve(&net)?;
for flow in &result.branch_flows {
println!(
"支路 {}-{}: P={:.4} Q={:.4} 负载率={:.1}% 损耗={:.4}",
flow.from, flow.to,
flow.p_from_pu, flow.q_from_pu,
flow.loading_percent, flow.loss_pu
);
}
println!("网络总损耗: {:.6} pu", result.total_loss_pu());
if let Some(max) = result.max_loading() {
println!("最大负载支路: {}-{} ({:.1}%)", max.from, max.to, max.loading_percent);
}
直流潮流快速估算
use eneros_powerflow::PowerFlowMethod;
let dc_solver = PowerFlowSolver::new()
.method(PowerFlowMethod::DcPowerFlow);
let dc_result = dc_solver.solve(&net)?;
println!("直流潮流耗时: {:?}", dc_result.duration);
PQ 解耦快速求解
let fd_solver = PowerFlowSolver::new()
.method(PowerFlowMethod::FastDecoupled)
.tolerance(1e-6)
.max_iterations(30);
let fd_result = fd_solver.solve(&net)?;
println!(
"解耦潮流: 收敛={} 迭代={} 耗时={:?}",
fd_result.converged, fd_result.iterations, fd_result.duration
);
结果缓存失效
let solver = PowerFlowSolver::new().enable_cache(true);
let r1 = solver.solve(&net)?;
let r2 = solver.solve(&net)?;
println!("第二次复用缓存: {:?}", r2.duration);
// 拓扑变更后缓存自动失效
// net.add_branch(...);
let r3 = solver.solve(&net)?;
println!("拓扑变更后重新计算: {:?}", r3.duration);
收敛与诊断
Newton-Raphson 方法在每次迭代中求解线性方程组 J · Δx = -ΔS,其中:
J:雅可比矩阵(2N-2 阶,稀疏)Δx:电压修正量[Δθ, ΔV]ΔS:功率残差[ΔP, ΔQ]
收敛条件:max(|ΔP|, |ΔQ|) < tolerance
发散诊断返回每次迭代残差,便于排查:
match solver.solve(&net) {
Ok(result) if !result.converged => {
println!(
"未收敛: 已迭代 {} 次, 最终残差 {:.2e}",
result.iterations, result.residual
);
}
Ok(result) => println!("收敛于第 {} 次迭代", result.iterations),
Err(e) => println!("求解错误: {}", e),
}
性能指标
测试环境:4 核 / 8GB / Ubuntu 22.04 / Rust 1.78 release build。
| 网络规模 | Newton-Raphson | Fast Decoupled | DC Power Flow |
|---|---|---|---|
| IEEE-14 | < 1ms | < 0.5ms | < 0.1ms |
| IEEE-30 | < 2ms | < 1ms | < 0.2ms |
| IEEE-118 | < 5ms | < 3ms | < 0.5ms |
| 1000 节点 | < 10ms | < 6ms | < 1ms |
| 10000 节点 | < 120ms | < 80ms | < 10ms |
YBus 构建性能
| 网络规模 | 构建耗时 | 内存占用 |
|---|---|---|
| IEEE-14 | < 50μs | < 4KB |
| IEEE-118 | < 500μs | < 32KB |
| 1000 节点 | < 5ms | < 256KB |
| 10000 节点 | < 60ms | < 2.5MB |
配置参数表
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
method | PowerFlowMethod | NewtonRaphson | 求解方法 |
tolerance | f64 | 1e-8 | 收敛容差 |
max_iterations | usize | 50 | 最大迭代次数 |
enable_cache | bool | true | 是否启用结果缓存 |
依赖关系
自身依赖
[dependencies]
eneros-core = { path = "../core", version = "0.47.0" }
eneros-linalg = { path = "../linalg", version = "0.47.0" }
eneros-topology = { path = "../topology", version = "0.47.0" }
num-complex = "0.4"
tracing = "0.1"
被依赖
eneros-analysis— OPF 与状态估计以潮流结果为初值eneros-constraint— 校验潮流结果是否越限eneros-twin— 孪生体在 What-If 中触发潮流eneros-simulator— 场景模拟器调用潮流eneros-network— 拓扑-潮流统一管线
版本与兼容性
| eneros-powerflow 版本 | EnerOS 版本 | 关键变更 |
|---|---|---|
| 0.47.x | 0.47.x | 雅可比矩阵 CSR 化,性能提升 2x |
| 0.46.x | 0.46.x | 新增 PQ 解耦与直流潮流方法 |
| 0.45.x (LTS) | 0.45.x | LTS 版本,至 2028 年安全更新 |
相关文档
- 潮流计算实战 — 教程
- eneros-topology — 拓扑建模
- eneros-constraint — 潮流结果校验
- eneros-linalg — 稀疏矩阵
- Crate 索引 — 完整列表