潮流计算实战
本教程演示如何使用 EnerOS 执行 IEEE 14-bus 标准测试系统的潮流计算,涵盖网络建模、求解、结果分析、越限校验、持久化与可视化全过程。
潮流计算是电力系统分析的基础,用于求解给定网络结构与边界条件下的稳态运行点(各母线电压幅值与相角、各支路功率分布)。EnerOS 将潮流求解器下沉到内核态(eneros-powerflow crate),所有 Agent 与上层应用可通过系统调用直接调用,无需重复建模。
准备工作
确保已按 安装与构建 完成 EnerOS 构建,并能正常运行 eneros-api。本教程涉及以下 crate:
| Crate | 作用 |
|---|---|
eneros-topology | 网络拓扑建模(母线、支路、开关) |
eneros-powerflow | 潮流求解器(牛顿-拉夫逊、快速解耦、直流) |
eneros-core | 基础类型(BusType、BranchType、YBusMatrix) |
eneros-timeseries | 时序数据持久化 |
eneros-api | REST/WebSocket 接口与可视化前端 |
新建一个二进制 crate 并添加依赖:
[package]
name = "ieee14-tutorial"
version = "0.1.0"
edition = "2021"
[dependencies]
eneros-topology = { path = "../eneros/crates/eneros-topology" }
eneros-powerflow = { path = "../eneros/crates/eneros-powerflow" }
eneros-core = { path = "../eneros/crates/eneros-core" }
eneros-timeseries = { path = "../eneros/crates/eneros-timeseries" }
tokio = { version = "1", features = ["full"] }
IEEE 14-bus 系统概览
IEEE 14-bus 是美国电气电子工程师协会发布的标准测试系统,广泛用于潮流算法验证。其拓扑如下:
- 14 个母线:1 个 Slack(平衡节点)、4 个 PV(电压控制节点)、9 个 PQ(负荷节点)
- 20 条支路:16 条线路 + 4 台变压器(含 3 台非标准变比变压器)
- 基准容量:100 MVA
- 9 号母线:装有 19 MVar 并联电容器
| 母线编号 | 类型 | 电压 (p.u.) | P 注入 (MW) | Q 注入 (MVar) |
|---|---|---|---|---|
| 1 | Slack | 1.060 | 平衡计算 | 平衡计算 |
| 2 | PV | 1.045 | 18.3 | -12.7 |
| 3 | PV | 1.010 | -94.2 | -19.0 |
| 4 | PQ | 1.019 | -47.8 | 3.9 |
| 5 | PQ | 1.020 | -7.6 | -1.6 |
| 6 | PV | 1.070 | -11.2 | -7.5 |
| 7 | PQ | 1.062 | 0.0 | 0.0 |
| 8 | PV | 1.090 | 0.0 | 0.0 |
| 9 | PQ | 1.056 | -29.5 | -16.6 |
| 10 | PQ | 1.051 | -9.0 | -5.8 |
| 11 | PQ | 1.057 | -3.5 | -1.8 |
| 12 | PQ | 1.055 | -6.1 | -1.6 |
| 13 | PQ | 1.050 | -13.5 | -5.8 |
| 14 | PQ | 1.036 | -14.9 | -5.0 |
| 支路 (From-To) | 类型 | R (p.u.) | X (p.u.) | B/2 (p.u.) | 变比 |
|---|---|---|---|---|---|
| 1-2 | 线路 | 0.01938 | 0.05917 | 0.0528 | 1.0 |
| 1-5 | 线路 | 0.05403 | 0.22304 | 0.0492 | 1.0 |
| 2-3 | 线路 | 0.04699 | 0.19797 | 0.0438 | 1.0 |
| 2-4 | 线路 | 0.05811 | 0.17632 | 0.0340 | 1.0 |
| 2-5 | 线路 | 0.05695 | 0.17388 | 0.0346 | 1.0 |
| 3-4 | 线路 | 0.06701 | 0.17103 | 0.0128 | 1.0 |
| 4-5 | 线路 | 0.01335 | 0.04211 | 0.0 | 1.0 |
| 4-7 | 变压器 | 0.0 | 0.20912 | 0.0 | 0.978 |
| 4-9 | 变压器 | 0.0 | 0.55618 | 0.0 | 0.969 |
| 5-6 | 变压器 | 0.0 | 0.25202 | 0.0 | 0.932 |
| 6-11 | 线路 | 0.09498 | 0.19890 | 0.0 | 1.0 |
| 6-12 | 线路 | 0.12291 | 0.25581 | 0.0 | 1.0 |
| 6-13 | 线路 | 0.06615 | 0.13027 | 0.0 | 1.0 |
| 7-8 | 变压器 | 0.0 | 0.17615 | 0.0 | 0.969 |
| 7-9 | 线路 | 0.0 | 0.11001 | 0.0 | 1.0 |
| 9-10 | 线路 | 0.03181 | 0.08450 | 0.0 | 1.0 |
| 9-14 | 线路 | 0.12711 | 0.27038 | 0.0 | 1.0 |
| 10-11 | 线路 | 0.08205 | 0.19207 | 0.0 | 1.0 |
| 12-13 | 线路 | 0.22092 | 0.19988 | 0.0 | 1.0 |
| 13-14 | 线路 | 0.17093 | 0.34802 | 0.0 | 1.0 |
步骤 1:构建网络拓扑
使用 eneros_topology::NetworkGraph 构建 IEEE 14-bus 网络。Slack 母线指定电压幅值与相角,PV 母线指定电压幅值与有功注入,PQ 母线指定有功/无功负荷。下面给出完整的母线与支路定义(无任何省略):
use eneros_topology::{NetworkGraph, Bus, Branch, BusType, BranchType};
use eneros_core::ElementId;
/// 构建 IEEE 14-bus 标准测试系统的网络拓扑
fn build_ieee14_network() -> NetworkGraph {
let mut graph = NetworkGraph::new();
// ===================== 母线定义 =====================
// 1 号:Slack(平衡节点),V=1.06 p.u.,θ=0°
graph.bus_add(Bus {
id: 1,
name: "Bus1_Slack".into(),
bus_type: BusType::Slack,
voltage_kv: 138.0,
zone_id: 1,
bus_type_pf: BusType::Slack,
p_gen: 0.0,
q_gen: 0.0,
p_load: 0.0,
q_load: 0.0,
v_pu: 1.060,
});
// 2 号:PV,P_inj=18.3 MW(发电 40 - 负荷 21.7),V=1.045 p.u.
graph.bus_add(Bus {
id: 2,
name: "Bus2_PV".into(),
bus_type: BusType::PV,
voltage_kv: 138.0,
zone_id: 1,
bus_type_pf: BusType::PV,
p_gen: 40.0,
q_gen: 0.0,
p_load: 21.7,
q_load: 12.7,
v_pu: 1.045,
});
// 3 号:PV(同步调相机),P_inj=-94.2 MW,V=1.010 p.u.
graph.bus_add(Bus {
id: 3,
name: "Bus3_PV".into(),
bus_type: BusType::PV,
voltage_kv: 138.0,
zone_id: 1,
bus_type_pf: BusType::PV,
p_gen: 0.0,
q_gen: 0.0,
p_load: 94.2,
q_load: 19.0,
v_pu: 1.010,
});
// 4 号:PQ,P_inj=-47.8 MW,Q_inj=3.9 MVar(容性负荷)
graph.bus_add(Bus {
id: 4,
name: "Bus4_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 138.0,
zone_id: 1,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 47.8,
q_load: -3.9,
v_pu: 1.019,
});
// 5 号:PQ,P_inj=-7.6 MW,Q_inj=-1.6 MVar
graph.bus_add(Bus {
id: 5,
name: "Bus5_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 138.0,
zone_id: 1,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 7.6,
q_load: 1.6,
v_pu: 1.020,
});
// 6 号:PV,P_inj=-11.2 MW,V=1.070 p.u.
graph.bus_add(Bus {
id: 6,
name: "Bus6_PV".into(),
bus_type: BusType::PV,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PV,
p_gen: 0.0,
q_gen: 0.0,
p_load: 11.2,
q_load: 7.5,
v_pu: 1.070,
});
// 7 号:PQ,无负荷
graph.bus_add(Bus {
id: 7,
name: "Bus7_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 0.0,
q_load: 0.0,
v_pu: 1.062,
});
// 8 号:PV(同步调相机),V=1.090 p.u.
graph.bus_add(Bus {
id: 8,
name: "Bus8_PV".into(),
bus_type: BusType::PV,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PV,
p_gen: 0.0,
q_gen: 0.0,
p_load: 0.0,
q_load: 0.0,
v_pu: 1.090,
});
// 9 号:PQ,P_inj=-29.5 MW,装有 19 MVar 并联电容器
graph.bus_add(Bus {
id: 9,
name: "Bus9_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 29.5,
q_load: 16.6,
v_pu: 1.056,
});
// 10 号:PQ,P_inj=-9.0 MW
graph.bus_add(Bus {
id: 10,
name: "Bus10_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 9.0,
q_load: 5.8,
v_pu: 1.051,
});
// 11 号:PQ,P_inj=-3.5 MW
graph.bus_add(Bus {
id: 11,
name: "Bus11_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 3.5,
q_load: 1.8,
v_pu: 1.057,
});
// 12 号:PQ,P_inj=-6.1 MW
graph.bus_add(Bus {
id: 12,
name: "Bus12_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 6.1,
q_load: 1.6,
v_pu: 1.055,
});
// 13 号:PQ,P_inj=-13.5 MW
graph.bus_add(Bus {
id: 13,
name: "Bus13_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 13.5,
q_load: 5.8,
v_pu: 1.050,
});
// 14 号:PQ,P_inj=-14.9 MW
graph.bus_add(Bus {
id: 14,
name: "Bus14_PQ".into(),
bus_type: BusType::PQ,
voltage_kv: 13.8,
zone_id: 2,
bus_type_pf: BusType::PQ,
p_gen: 0.0,
q_gen: 0.0,
p_load: 14.9,
q_load: 5.0,
v_pu: 1.036,
});
// ===================== 支路定义 =====================
// 辅助函数:添加线路
let add_line = |g: &mut NetworkGraph, id: ElementId, from: ElementId, to: ElementId,
r: f64, x: f64, b: f64| {
g.branch_add(Branch {
id,
name: format!("Line_{}_{}", from, to),
from_bus: from,
to_bus: to,
branch_type: BranchType::Line,
status: true,
r, x, b,
tap_ratio: 1.0,
});
};
// 辅助函数:添加变压器
let add_tx = |g: &mut NetworkGraph, id: ElementId, from: ElementId, to: ElementId,
x: f64, tap: f64| {
g.branch_add(Branch {
id,
name: format!("Tx_{}_{}", from, to),
from_bus: from,
to_bus: to,
branch_type: BranchType::Transformer,
status: true,
r: 0.0, x, b: 0.0,
tap_ratio: tap,
});
};
// 7 条线路(主网架)
add_line(&mut graph, 101, 1, 2, 0.01938, 0.05917, 0.0528);
add_line(&mut graph, 102, 1, 5, 0.05403, 0.22304, 0.0492);
add_line(&mut graph, 103, 2, 3, 0.04699, 0.19797, 0.0438);
add_line(&mut graph, 104, 2, 4, 0.05811, 0.17632, 0.0340);
add_line(&mut graph, 105, 2, 5, 0.05695, 0.17388, 0.0346);
add_line(&mut graph, 106, 3, 4, 0.06701, 0.17103, 0.0128);
add_line(&mut graph, 107, 4, 5, 0.01335, 0.04211, 0.0);
// 3 台变压器(4-7、4-9、5-6),含非标准变比
add_tx(&mut graph, 201, 4, 7, 0.20912, 0.978);
add_tx(&mut graph, 202, 4, 9, 0.55618, 0.969);
add_tx(&mut graph, 203, 5, 6, 0.25202, 0.932);
// 6-11、6-12、6-13 线路
add_line(&mut graph, 108, 6, 11, 0.09498, 0.19890, 0.0);
add_line(&mut graph, 109, 6, 12, 0.12291, 0.25581, 0.0);
add_line(&mut graph, 110, 6, 13, 0.06615, 0.13027, 0.0);
// 7-8 变压器(含非标准变比)
add_tx(&mut graph, 204, 7, 8, 0.17615, 0.969);
// 7-9、9-10、9-14、10-11、12-13、13-14 线路
add_line(&mut graph, 111, 7, 9, 0.0, 0.11001, 0.0);
add_line(&mut graph, 112, 9, 10, 0.03181, 0.08450, 0.0);
add_line(&mut graph, 113, 9, 14, 0.12711, 0.27038, 0.0);
add_line(&mut graph, 114, 10, 11, 0.08205, 0.19207, 0.0);
add_line(&mut graph, 115, 12, 13, 0.22092, 0.19988, 0.0);
add_line(&mut graph, 116, 13, 14, 0.17093, 0.34802, 0.0);
graph
}
fn main() {
let network = build_ieee14_network();
println!("母线数: {}", network.bus_count());
println!("支路数: {}", network.branch_count());
println!("连通区域数: {}", network.zone_count());
}
执行后应输出:
母线数: 14
支路数: 20
连通区域数: 1
:::tip 使用内置 IEEE 14 数据
eneros-powerflow 已内置完整的 IEEE 14-bus 标准数据,可直接通过 ieee14() 函数获取,无需手动构建。本节展示手动构建过程是为了让读者理解网络建模的完整流程。
:::
步骤 2:转换为求解器输入
NetworkGraph::to_solver_input(base_mva) 将拓扑导出为潮流求解器所需的四元组:
use eneros_core::BusTypeNR;
let base_mva = 100.0;
let (ybus, p_spec, q_spec, bus_types, v_initial) = network.to_solver_input(base_mva);
println!("Y-Bus 维度: {}x{}", ybus.size(), ybus.size());
println!("非零元数: {}", ybus.nnz());
println!("P_spec (p.u.): {:?}", p_spec);
println!("bus_types: {:?}", bus_types);
输出示例:
Y-Bus 维度: 14x14
非零元数: 56
P_spec (p.u.): [0.0, 0.183, -0.942, -0.478, ...]
bus_types: [Slack, PV, PV, PQ, PQ, PV, PQ, PV, PQ, PQ, PQ, PQ, PQ, PQ]
导出过程做了以下处理:
| 字段 | 说明 |
|---|---|
ybus | 节点导纳矩阵,包含支路 R/X/B 与变压器变比 |
p_spec | 每个节点的有功注入 (p_gen - p_load) / base_mva(标幺值) |
q_spec | 每个节点的无功注入 (q_gen - q_load) / base_mva(标幺值) |
bus_types | 节点类型枚举(Slack / PV / PQ),决定求解变量 |
v_initial | 初始电压幅值(来自 Bus::v_pu),用于热启动 |
步骤 3:配置并执行潮流求解
EnerOS 提供三种潮流算法:
| 算法 | 适用场景 | 收敛性 | 速度 |
|---|---|---|---|
NewtonRaphson | 输电网、环网 | 二阶收敛 | 中 |
BackwardForwardSweep | 配电网、辐射状 | 一阶收敛 | 快 |
DC | 实时筛查、规划 | 线性 | 最快 |
对 IEEE 14-bus 推荐牛顿-拉夫逊法:
use eneros_powerflow::{PowerFlowSolver, PowerFlowAlgorithm};
let solver = PowerFlowSolver::new(50, 1e-8)
.with_algorithm(PowerFlowAlgorithm::NewtonRaphson);
let result = solver.solve_with_initial(
&ybus,
&p_spec,
&q_spec,
&bus_types,
Some(&v_initial),
)?;
println!("收敛: {}", result.converged);
println!("迭代次数: {}", result.iterations);
println!("最大失配: {:.2e}", result.max_mismatch);
println!("总网损: {:.4} MW", result.total_losses * base_mva);
输出示例:
收敛: true
迭代次数: 4
最大失配: 3.21e-09
总网损: 13.8392 MW
启用 Q 限制
PV 母线的无功出力可能超出发电机容量。启用 Q 限制后,越限的 PV 母线会自动转换为 PQ 母线:
use eneros_powerflow::QLimits;
let mut q_limits = QLimits::new();
// 2 号机:Q ∈ [-50, 50] MVar
q_limits.add(1, -0.50, 0.50); // bus_idx=1(即 2 号母线),单位 p.u.
// 6 号机:Q ∈ [-25, 25] MVar
q_limits.add(5, -0.25, 0.25);
let result_q = solver.solve_with_options(
&ybus, &p_spec, &q_spec, &bus_types,
Some(&v_initial), Some(&q_limits), None,
)?;
println!("Q 限制后总网损: {:.4} MW", result_q.total_losses * base_mva);
使用 Recycle Cache 加速
对于拓扑不变的连续求解(如时序潮流),可复用上次电压结果作为初始值,减少迭代次数:
use eneros_powerflow::RecycleCache;
let mut cache = RecycleCache::new();
// 第一次求解
let r1 = solver.solve_with_options(
&ybus, &p_spec, &q_spec, &bus_types,
None, None, None,
)?;
cache.update(
&r1.bus_results.iter().map(|b| b.voltage_magnitude).collect::<Vec<_>>(),
&r1.bus_results.iter().map(|b| b.voltage_angle).collect::<Vec<_>>(),
);
// 第二次求解(负荷微调后),复用缓存
let p_spec_2: Vec<f64> = p_spec.iter().map(|p| p * 1.05).collect();
let r2 = solver.solve_with_options(
&ybus, &p_spec_2, &q_spec, &bus_types,
None, None, Some(&cache),
)?;
println!("复用缓存后迭代次数: {}", r2.iterations);
步骤 4:查看与导出结果
逐母线打印电压幅值与相角,并与 IEEE 标准参考值对比:
println!("{:>6} {:>10} {:>10} {:>12} {:>10}",
"Bus", "V(pu)", "θ(°)", "P_inj(MW)", "Q(MVar)");
println!("{}", "-".repeat(54));
for br in &result.bus_results {
let angle_deg = br.voltage_angle.to_degrees();
println!("{:>6} {:>10.4} {:>10.4} {:>12.4} {:>10.4}",
br.bus_id + 1, // 转回 1-based
br.voltage_magnitude,
angle_deg,
br.p_injection * base_mva,
br.q_injection * base_mva,
);
}
输出示例:
Bus V(pu) θ(°) P_inj(MW) Q(MVar)
------------------------------------------------------
1 1.0600 0.0000 232.3863 -16.5467
2 1.0450 -4.9826 18.3000 33.5234
3 1.0100 -12.7242 -94.2000 25.1468
4 1.0187 -10.3129 -47.8000 3.9000
5 1.0202 -8.7813 -7.6000 -1.6000
6 1.0700 -14.2210 -11.2000 12.7312
7 1.0620 -13.3620 0.0000 0.0000
8 1.0900 -13.3620 0.0000 17.5654
9 1.0564 -14.9385 -29.5000 -16.6000
10 1.0514 -15.0982 -9.0000 -5.8000
11 1.0569 -14.7953 -3.5000 -1.8000
12 1.0552 -15.0736 -6.1000 -1.6000
13 1.0505 -15.1548 -13.5000 -5.8000
14 1.0356 -16.0336 -14.9000 -5.0000
支路潮流与网损
println!("{:>10} {:>10} {:>10} {:>10} {:>10}",
"支路", "P_from(MW)", "Q_from", "P_to(MW)", "网损(MW)");
println!("{}", "-".repeat(56));
for br in &result.branch_results {
println!("{:>4}-{::<5} {:>10.4} {:>10.4} {:>10.4} {:>10.4}",
br.from_bus + 1, br.to_bus + 1,
br.p_from * base_mva,
br.q_from * base_mva,
br.p_to * base_mva,
br.loss_mw * base_mva,
);
}
println!("\n系统总网损: {:.4} MW", result.total_losses * base_mva);
步骤 5:越限校验
约束校验是 EnerOS 内核强制的”法律”。即便在教程场景中,也应主动检查电压与支路负载率是否越限:
fn check_violations(result: &eneros_powerflow::PowerFlowResult, base_mva: f64) {
// 电压越限检查(正常运行范围 0.95 ~ 1.05 p.u.,紧急范围 0.90 ~ 1.10)
let v_min_normal = 0.95;
let v_max_normal = 1.05;
let mut v_violations = 0;
for bus in &result.bus_results {
if bus.voltage_magnitude < v_min_normal || bus.voltage_magnitude > v_max_normal {
eprintln!("[电压越限] Bus {}: V={:.4} pu (允许范围 {}-{})",
bus.bus_id + 1, bus.voltage_magnitude, v_min_normal, v_max_normal);
v_violations += 1;
}
}
// 支路过载检查
let loading_limit = 100.0; // %
let mut b_violations = 0;
for branch in &result.branch_results {
if branch.loading_percent > loading_limit {
eprintln!("[支路过载] Branch {}-{}: {:.1}% (> {}%)",
branch.from_bus + 1, branch.to_bus + 1,
branch.loading_percent, loading_limit);
b_violations += 1;
}
}
println!("\n越限统计: 电压={}, 支路={}", v_violations, b_violations);
if v_violations == 0 && b_violations == 0 {
println("✓ 所有约束满足");
}
}
check_violations(&result, base_mva);
输出示例:
[电压越限] Bus 1: V=1.0600 pu (允许范围 0.95-1.05)
[电压越限] Bus 6: V=1.0700 pu (允许范围 0.95-1.05)
[电压越限] Bus 8: V=1.0900 pu (允许范围 0.95-1.05)
越限统计: 电压=3, 支路=0
:::warning 1 号、6 号、8 号为 PV 母线,其电压由发电机/调相机控制为 1.06 / 1.07 / 1.09,超出常规负荷母线的 0.95-1.05 范围是正常的。实际工程中应按母线类型分别设置约束。 :::
步骤 6:持久化与可视化
将结果写入时序引擎,便于历史回放与趋势分析:
use eneros_timeseries::{TimeseriesEngine, WriteOptions};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut ts = TimeseriesEngine::open("/var/lib/eneros/ts")?;
let opts = WriteOptions::default().tags([
("system", "ieee14"),
("scenario", "base_case"),
]);
// 逐母线写入电压时序
for bus in &result.bus_results {
let point_name = format!("ieee14.bus{}.voltage", bus.bus_id + 1);
ts.write_point(&point_name, bus.voltage_magnitude, &opts).await?;
}
// 写入系统级指标
ts.write_point("ieee14.total_losses_mw",
result.total_losses * base_mva, &opts).await?;
ts.write_point("ieee14.iterations",
result.iterations as f64, &opts).await?;
println!("✓ 已写入 {} 个测点", result.bus_results.len() + 1);
Ok(())
}
通过 REST API 触发可视化前端刷新:
let client = eneros_api::Client::new("https://api.eneros.internal");
// 发布潮流结果到事件总线
client.publish("/topics/powerflow/ieee14", &result).await?;
// 触发可视化前端刷新单线图
client.post("/api/visualization/refresh")
.json(&serde_json::json!({
"network_id": "ieee14",
"result_id": result.id(),
"layers": ["voltage", "loading", "loss"],
}))
.await?;
步骤 7:完整端到端示例
将上述步骤整合为一个完整的可运行程序:
use eneros_powerflow::{ieee14, PowerFlowSolver, PowerFlowAlgorithm};
fn main() -> eneros_core::Result<()> {
// 1. 加载 IEEE 14-bus 标准数据
let data = ieee14();
println!("加载网络: {} 母线, {} 支路", data.buses.len(), data.branches.len());
// 2. 转换为求解器输入
let (ybus, p_spec, q_spec, bus_types) = data.to_solver_input();
let v_initial: Vec<f64> = data.buses.iter().map(|b| b.v_pu).collect();
// 3. 求解
let solver = PowerFlowSolver::new(100, 1e-8)
.with_algorithm(PowerFlowAlgorithm::NewtonRaphson);
let result = solver.solve_with_initial(
&ybus, &p_spec, &q_spec, &bus_types, Some(&v_initial))?;
// 4. 输出关键指标
println!("收敛: {}, 迭代: {}, 失配: {:.2e}",
result.converged, result.iterations, result.max_mismatch);
println!("总网损: {:.4} MW", result.total_losses * data.base_mva);
// 5. Slack 母线有功(应接近 232.4 MW)
let slack_p = result.bus_results[0].p_injection * data.base_mva;
println!("Slack 有功: {:.2} MW (期望 ≈232.4 MW)", slack_p);
// 6. 越限校验
let overloaded = result.branch_results.iter()
.filter(|b| b.loading_percent > 100.0)
.count();
println!("过载支路数: {}", overloaded);
Ok(())
}
验证
按以下指标验证求解正确性:
| 指标 | 期望值 | 容差 |
|---|---|---|
| 收敛性 | true | — |
| 迭代次数 | 3-5 次 | < 20 |
| 最大失配 | < 1e-8 p.u. | — |
| Slack 有功 | ≈ 232.4 MW | ±1% |
| 总网损 | ≈ 13.8 MW | ±1 MW |
| 所有母线电压 | 0.9-1.1 p.u. | — |
| 支路负载率 | < 100% | — |
调试技巧
- 不收敛:检查 PV 母线是否有足够的无功容量,启用 Q 限制
- 网损偏大:检查变压器变比是否正确(0.978/0.969/0.932/0.969)
- 电压异常:检查 9 号母线的并联电容器(19 MVar = 0.19 p.u.)
- 迭代过多:使用
v_initial热启动,或启用RecycleCache - Y-Bus 错误:确认支路 B 值是总充电电纳(非 B/2)
命令行验证
# 运行单元测试
cargo test -p eneros-powerflow test_ieee14 -- --nocapture
# 查看详细输出
RUST_LOG=eneros_powerflow=debug cargo run --release
下一步
- 调度 Agent 开发 — 基于潮流结果构建自动调度
- 电网拓扑一等公民 — 深入拓扑建模
- 物理约束决策 — 约束引擎详解
- 时序存储引擎 — 时序数据持久化