EnerOS v0.7.0
发布日期:2024年7月7日 版本代号:Equipment(设备) Git Tag:v0.7.0 支持状态:内部预览(Internal Preview) Crate 总数:6 测试用例数:942
版本概述
EnerOS v0.7.0「Equipment」引入了电力设备模型库。本版本发布 eneros-equipment crate,提供了变压器(两绕组、三绕组)、输电线路(PI 型等值电路)、开关(断路器、隔离开关)与负荷(ZIP 模型)四大类设备的详细数学模型。v0.3.0 的拓扑模型仅包含设备的「连接关系」,而 v0.7.0 补齐了设备的「物理特性」——变压器不仅有变比,还有分接头档位、空载损耗、短路阻抗;线路不仅有 R/X/B,还有温度特性与频率特性;负荷不仅有有功无功,还有电压频率静态特性。
设备模型库的设计遵循 IEC 61970 CIM 与中国电力行业标准 DL/T 698 的双重规范。CIM 提供了设备类的本体论框架,而 DL/T 698 定义了设备参数的工程取值范围与命名约定。EnerOS 在两者之间做了映射:对外可导出 CIM 兼容的 RDF/JSON,对内使用 Rust enum 表达设备类型,使用 trait 表达设备行为。例如,所有设备都实现 Equipment trait,提供 impedance()、admittance()、status() 等方法;变压器额外实现 TapChanger trait,提供分接头调节能力。
v0.7.0 的一个重要设计决策是将「设备模型」与「设备实例」分离。TransformerModel 描述某型号变压器的参数模板(如 SZ11-31500/110),而 TransformerInstance 描述具体部署的某一台变压器(如「变电站 A 的 1 号主变」)。这种分离使得设备库可以基于厂家提供的型式试验数据建立模型库,运行时根据实际安装的设备实例化。模型库预置了 50+ 常见型号的参数,覆盖 10kV 至 500kV 各电压等级。
关键数据
| 指标 | 数值 | 说明 |
|---|---|---|
| 设备类型 | 4 大类 | 变压器/线路/开关/负荷 |
| 预置型号 | 52 | 覆盖常见厂家 |
| 设备模型参数 | 32 | 单设备平均 |
| 变压器分接头档位 | ±8 | 标准配置 |
| ZIP 负荷特性系数 | 3 | Z/I/P 比例 |
新特性
1. 变压器模型
两绕组变压器
// crates/eneros-equipment/src/transformer/two_winding.rs
use serde::{Deserialize, Serialize};
use eneros_topology::bus::BusId;
/// 两绕组变压器
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TwoWindingTransformer {
pub id: String,
pub name: String,
pub hv_bus: BusId, // 高压侧母线
pub lv_bus: BusId, // 低压侧母线
pub rated_hv_kv: f64, // 高压侧额定电压
pub rated_lv_kv: f64, // 低压侧额定电压
pub rated_mva: f64, // 额定容量
/// 短路阻抗百分比(%)
pub short_circuit_z_pct: f64,
/// 短路电阻百分比(%),通常 = 铜耗/(额定容量*10)
pub short_circuit_r_pct: f64,
/// 空载电流百分比(%)
pub no_load_i_pct: f64,
/// 空载损耗(kW)
pub no_load_loss_kw: f64,
/// 分接头配置
pub tap_changer: TapChanger,
/// 是否在运
pub in_service: bool,
}
/// 分接头调节器
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TapChanger {
/// 额定档位对应的变比
pub nominal_tap: f64,
/// 每档调节量(百分比)
pub step_pct: f64,
/// 最大档位(正)
pub max_tap: i32,
/// 最小档位(负)
pub min_tap: i32,
/// 当前档位
pub current_tap: i32,
}
impl TapChanger {
/// 当前实际变比
pub fn current_ratio(&self) -> f64 {
self.nominal_tap * (1.0 + self.current_tap as f64 * self.step_pct / 100.0)
}
/// 升档
pub fn raise(&mut self) -> Result<(), EquipmentError> {
if self.current_tap >= self.max_tap {
return Err(EquipmentError::TapAtMax);
}
self.current_tap += 1;
Ok(())
}
/// 降档
pub fn lower(&mut self) -> Result<(), EquipmentError> {
if self.current_tap <= self.min_tap {
return Err(EquipmentError::TapAtMin);
}
self.current_tap -= 1;
Ok(())
}
}
impl TwoWindingTransformer {
/// 计算标幺值参数(基于给定基准容量)
pub fn pi_parameters(&self, base_mva: f64) -> PiParameters {
let tap = self.tap_changer.current_ratio();
// 阻抗从百分比换算到标幺值
let z_pu = (self.short_circuit_z_pct / 100.0) * (base_mva / self.rated_mva);
let r_pu = (self.short_circuit_r_pct / 100.0) * (base_mva / self.rated_mva);
let x_pu = (z_pu * z_pu - r_pu * r_pu).sqrt();
// 励磁导纳
let b_half = (self.no_load_i_pct / 100.0) * (base_mva / self.rated_mva);
PiParameters {
r_pu,
x_pu,
b_half_pu: b_half / 2.0,
tap_ratio: tap,
phase_shift: 0.0,
}
}
}
三绕组变压器
// crates/eneros-equipment/src/transformer/three_winding.rs
/// 三绕组变压器:用三个两绕组变压器等值(星形等值电路)
pub struct ThreeWindingTransformer {
pub id: String,
pub hv_bus: BusId, // 高压侧
pub mv_bus: BusId, // 中压侧
pub lv_bus: BusId, // 低压侧
pub rated_hv_mva: f64,
pub rated_mv_mva: f64,
pub rated_lv_mva: f64,
pub z_hm_pct: f64, // 高-中 短路阻抗
pub z_hl_pct: f64, // 高-低 短路阻抗
pub z_ml_pct: f64, // 中-低 短路阻抗
// ... 三对短路参数
}
impl ThreeWindingTransformer {
/// 转换为星形等值电路的三个支路
pub fn to_star_equivalent(&self) -> [PiParameters; 3] {
// 将三绕组参数转换为星形等值
let z_h = 0.5 * (self.z_hm_pct + self.z_hl_pct - self.z_ml_pct);
let z_m = 0.5 * (self.z_hm_pct + self.z_ml_pct - self.z_hl_pct);
let z_l = 0.5 * (self.z_hl_pct + self.z_ml_pct - self.z_hm_pct);
// 返回 H/M/L 三个支路的 PI 参数
[
PiParameters::transformer(z_h / 100.0, 0.0, 1.0),
PiParameters::transformer(z_m / 100.0, 0.0, 1.0),
PiParameters::transformer(z_l / 100.0, 0.0, 1.0),
]
}
}
2. 线路模型(PI 型等值电路)
// crates/eneros-equipment/src/line.rs
use eneros_topology::bus::BusId;
/// 输电线路(PI 型等值电路)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransmissionLine {
pub id: String,
pub from_bus: BusId,
pub to_bus: BusId,
pub length_km: f64,
/// 单位长度电阻(Ω/km)
pub r_per_km: f64,
/// 单位长度电抗(Ω/km)
pub x_per_km: f64,
/// 单位长度电纳(S/km)
pub b_per_km: f64,
/// 单位长度电导(S/km)
pub g_per_km: f64,
/// 并联线路数(1, 2, 3, 4)
pub num_circuits: u32,
/// 额定电流(A,单回路)
pub rated_current_a: f64,
/// 20°C 时的电阻(温度修正基准)
pub reference_temp_c: f64,
/// 电阻温度系数(1/°C)
pub temp_coefficient: f64,
pub in_service: bool,
}
impl TransmissionLine {
/// 计算给定温度下的 PI 参数
pub fn pi_parameters(&self, base_mva: f64, base_kv: f64, temp_c: f64) -> PiParameters {
let z_base = base_kv * base_kv / base_mva;
// 温度修正
let temp_factor = 1.0 + self.temp_coefficient * (temp_c - self.reference_temp_c);
let r_total = self.r_per_km * self.length_km * temp_factor / z_base;
let x_total = self.x_per_km * self.length_km / z_base;
let b_total = self.b_per_km * self.length_km * z_base;
// 多回路并联
let n = self.num_circuits as f64;
PiParameters {
r_pu: r_total / n,
x_pu: x_total / n,
b_half_pu: b_total / (2.0 * n),
tap_ratio: 1.0,
phase_shift: 0.0,
}
}
/// 计算线路热稳定极限(A)
pub fn thermal_limit_a(&self) -> f64 {
self.rated_current_a * self.num_circuits as f64
}
}
3. 开关模型
// crates/eneros-equipment/src/switch.rs
use eneros_topology::bus::BusId;
/// 开关类型
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SwitchKind {
Breaker, // 断路器
Disconnector, // 隔离开关
LoadBreakSwitch,// 负荷开关
EarthingSwitch, // 接地开关
Fuse, // 熔断器
}
/// 开关状态
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SwitchState {
Closed, // 合闸
Open, // 分闸
Tripped,// 跳闸(故障)
}
/// 开关设备
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Switch {
pub id: String,
pub from_bus: BusId,
pub to_bus: BusId,
pub kind: SwitchKind,
pub state: SwitchState,
/// 额定电流(A)
pub rated_current_a: f64,
/// 额定开断电流(A,断路器用)
pub breaking_capacity_a: f64,
/// 操作次数计数
pub operation_count: u32,
/// 上次操作时间戳
pub last_operated_at: Option<i64>,
}
impl Switch {
pub fn new(id: impl Into<String>, from: BusId, to: BusId, kind: SwitchKind) -> Self {
Self {
id: id.into(),
from_bus: from,
to_bus: to,
kind,
state: SwitchState::Closed,
rated_current_a: 1250.0,
breaking_capacity_a: 25000.0,
operation_count: 0,
last_operated_at: None,
}
}
/// 合闸
pub fn close(&mut self) -> Result<(), EquipmentError> {
if self.state == SwitchState::Closed {
return Err(EquipmentError::AlreadyClosed);
}
self.state = SwitchState::Closed;
self.operation_count += 1;
self.last_operated_at = Some(chrono::Utc::now().timestamp());
Ok(())
}
/// 分闸
pub fn open(&mut self) -> Result<(), EquipmentError> {
if self.state == SwitchState::Open {
return Err(EquipmentError::AlreadyOpen);
}
self.state = SwitchState::Open;
self.operation_count += 1;
self.last_operated_at = Some(chrono::Utc::now().timestamp());
Ok(())
}
/// 是否导通
pub fn is_conducting(&self) -> bool {
self.state == SwitchState::Closed
}
}
4. 负荷模型(ZIP)
ZIP 负荷模型将负荷表示为恒阻抗(Z)、恒电流(I)、恒功率(P)三部分的加权和,是电力系统稳态分析的标准负荷模型。
// crates/eneros-equipment/src/load.rs
use eneros_topology::bus::BusId;
/// ZIP 负荷模型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ZipLoad {
pub id: String,
pub bus: BusId,
/// 额定有功(MW)
pub p_nominal_mw: f64,
/// 额定无功(MVar)
pub q_nominal_mvar: f64,
/// 恒阻抗比例
pub a_z: f64,
/// 恒电流比例
pub a_i: f64,
/// 恒功率比例
pub a_p: f64,
/// 频率静特性系数(有功)
pub kp_f: f64,
/// 频率静特性系数(无功)
pub kq_f: f64,
pub in_service: bool,
}
impl ZipLoad {
pub fn new(bus: BusId, p_mw: f64, q_mvar: f64) -> Self {
Self {
id: format!("load_{}", bus),
bus,
p_nominal_mw: p_mw,
q_nominal_mvar: q_mvar,
a_z: 0.4,
a_i: 0.3,
a_p: 0.3,
kp_f: 1.0,
kq_f: -1.0,
in_service: true,
}
}
/// 计算给定电压与频率下的实际功率
pub fn power_at(&self, v_pu: f64, freq_hz: f64) -> (f64, f64) {
let df = (freq_hz - 50.0) / 50.0;
let v2 = v_pu * v_pu;
let v3 = v2 * v_pu;
let p = self.p_nominal_mw * (
self.a_z * v2 + self.a_i * v_pu + self.a_p
) * (1.0 + self.kp_f * df);
let q = self.q_nominal_mvar * (
self.a_z * v2 + self.a_i * v_pu + self.a_p
) * (1.0 + self.kq_f * df);
(p, q)
}
}
ZIP 模型特性对比:
| 负荷类型 | 电压依赖 | 功率-电压关系 | 适用设备 |
|---|---|---|---|
| 恒阻抗 Z | V² | P ∝ V² | 加热器、白炽灯 |
| 恒电流 I | V¹ | P ∝ V | 通用工业负荷 |
| 恒功率 P | V⁰ | P = const | 电机驱动(变频) |
| 典型混合 | - | 40%Z+30%I+30%P | 综合负荷 |
5. 预置设备型号库
// crates/eneros-equipment/src/catalog.rs
use crate::transformer::TwoWindingTransformer;
/// 预置变压器型号库
pub fn transformer_catalog() -> Vec<TwoWindingTransformer> {
vec![
// SZ11-31500/110(110kV/10kV,31.5MVA)
TwoWindingTransformer {
id: "SZ11-31500/110".into(),
name: "SZ11-31500/110 三相双绕组有载调压".into(),
rated_mva: 31.5,
rated_hv_kv: 110.0,
rated_lv_kv: 10.5,
short_circuit_z_pct: 10.5,
short_circuit_r_pct: 0.5,
no_load_i_pct: 0.7,
no_load_loss_kw: 29.0,
// ...
},
// SZ11-63000/220
// SZ11-150000/500
// ...
]
}
改进
eneros-topology:Branch支持关联详细设备模型eneros-powerflow:潮流计算考虑变压器分接头变比- 依赖:新增
chrono、uuid
Bug 修复
- 修复
TwoWindingTransformer::pi_parameters中基准容量换算错误(#103) - 修复
TransmissionLine::pi_parameters在多回路并联时未除以回路数的问题(#107) - 修复
Switch::open在已分闸时未返回错误的问题(#110)
破坏性变更
eneros_topology::Branch:params字段改为Option<PiParameters>,运行时由设备模型计算
性能提升
| 操作 | 耗时 |
|---|---|
| 变压器 PI 参数计算 | 240 ns |
| 线路 PI 参数计算 | 180 ns |
| ZIP 负荷功率计算 | 95 ns |
| 开关状态切换 | 32 ns |
| 型号库加载(52 型号) | 1.4 ms |
贡献者
| 贡献者 | 角色 | 提交数 |
|---|---|---|
| @eneros-foundation | 架构师 | 28 |
| @equipment-expert | 设备建模专家 | 52 |
| @transformer-guru | 变压器专家 | 31 |
| @grid-rustacean | Rust 工程师 | 22 |
升级指南
新增依赖
[dependencies]
eneros-equipment = { version = "0.7", path = "../eneros-equipment" }
使用设备模型
use eneros_equipment::transformer::TwoWindingTransformer;
use eneros_topology::bus::BusId;
let mut transformer = TwoWindingTransformer {
id: "T1".into(),
hv_bus: BusId(1),
lv_bus: BusId(2),
rated_hv_kv: 110.0,
rated_lv_kv: 10.5,
rated_mva: 31.5,
short_circuit_z_pct: 10.5,
// ...
};
transformer.tap_changer.raise()?; // 升一档
let pi = transformer.pi_parameters(100.0);