EnerOS v0.13.0
Release Date: January 5, 2025 Codename: Twin Git Tag: v0.13.0 Support Status: Stable Total Crates: 30 (4 new) Test Cases: 4120+ (540 new)
Version Overview
EnerOS v0.13.0 “Twin” is the core version marking EnerOS’s entry into the “virtual-real fusion” phase. The core goal of this version is to introduce the Digital Twin Engine, building high-fidelity real-time mirrors for the physical grid, enabling dispatchers, Agents, and analytical tasks to perform state observation, historical replay, and What-if analysis on the digital twin without affecting real grid operations.
Power systems are a typical “cannot trial-and-error on the real system” domain — operations such as switch operations, generator output adjustments, and load shedding produce physical consequences once executed, and incorrect operations may lead to large-scale blackouts. Traditional approaches rely on offline simulation tools (such as PSS/E, BPA), but offline simulation data lags behind real-time status and cannot collaborate with online Agents. v0.13.0 brings digital twin capabilities down to operating system kernel first-class citizens, enabling the twin to stay synchronized with the physical grid within seconds, and to be directly invoked by Agents for decision rehearsal.
This version introduces four new crates: eneros-twin (twin engine core), eneros-twin-sync (real-time mirror synchronization), eneros-twin-replay (historical replay), and eneros-twin-whatif (What-if analysis). The design philosophy is “twin is mirror, mirror is verifiable” — the twin is not a simple data copy, but an executable mirror containing complete electrical models, physical constraints, and equipment characteristics; any operation on the twin goes through the same physical constraint validation as the real system.
Key Data
| Metric | v0.12.0 | v0.13.0 | Improvement |
|---|---|---|---|
| Twin sync latency | N/A | 80ms | Real-time level |
| Historical replay accuracy | N/A | 99.97% | High fidelity |
| What-if computation time | Offline minutes | 1.2s | Online level |
| State estimation accuracy | 92% | 99.2% | +7.2pp |
| Twin scale | N/A | 100,000 nodes | Provincial grid |
New Features
1. Digital Twin Engine
Introduces the eneros-twin crate, providing complete digital twin lifecycle management. The twin is an executable mirror of the physical grid, containing four types of data: topology model, equipment parameters, real-time state, and historical trajectory, with a built-in physical constraint engine ensuring twin state always satisfies electrical laws.
Twin Creation
use eneros_twin::{Twin, TwinId, TwinConfig};
use eneros_topology::Network;
// Create twin based on existing topology
let twin = Twin::new(TwinId::from("grid-province-a"))
.source_network(&network)
.config(TwinConfig {
fidelity: Fidelity::High,
sync_mode: SyncMode::Realtime,
state_estimation: true,
physics_engine: PhysicsEngine::NewtonRaphson,
history_depth: Duration::days(30),
})?;
// Start twin
twin.start().await?;
Twin Fidelity Levels
| Fidelity Level | Model Accuracy | State Update | Physical Constraints | Applicable Scenarios |
|---|---|---|---|---|
| Low | Topology level | 5s | Topology connectivity | Overview monitoring |
| Medium | Equivalent circuit | 1s | Power flow balance | Dispatch training |
| High | Detailed equipment | 200ms | Complete constraints | Decision rehearsal |
| Ultra | Component level | 50ms | Electromagnetic transient | Fault analysis |
Twin State Query
// Query twin current state
let state = twin.current_state()?;
println!("Bus 1 voltage: {:.3} pu", state.bus(1).voltage);
println!("Line 12-14 active power: {:.1} MW", state.line(12, 14).p_mw);
// Query equipment state
let transformer = state.transformer(7);
println!("Transformer tap position: {}", transformer.tap_position);
println!("Transformer loading rate: {:.1}%", transformer.loading * 100.0);
2. Real-time Mirror Synchronization
Introduces the eneros-twin-sync crate, continuously synchronizing real-time telemetry data from the physical grid to the twin, maintaining state consistency between the twin and physical grid. Synchronization uses a hybrid mode of incremental updates + state estimation, filling in data gaps through state estimation when data is missing.
Synchronization Configuration
use eneros_twin_sync::{SyncEngine, SyncConfig};
let sync = SyncEngine::new(&twin)
.config(SyncConfig {
sync_interval: Duration::milliseconds(200),
state_estimation: true,
bad_data_detection: BadDataDetection::ChiSquare,
observable_check: true,
pseudo_measurement: true,
})?;
// Bind telemetry data source
sync.bind_source(telemetry_stream).await?;
State Estimation
use eneros_twin_sync::StateEstimator;
let estimator = StateEstimator::new(&twin)
.method(EstimationMethod::Wls) // Weighted Least Squares
.max_iterations(20)
.convergence_tolerance(1e-6);
// Execute state estimation
let result = estimator.estimate().await?;
println!("Estimation accuracy: {:.2f}%", result.accuracy * 100.0);
println!("Bad data count: {}", result.bad_data_count);
Synchronization Performance Metrics
| Data Source | Data Points | Sync Period | End-to-end Latency | Loss Rate |
|---|---|---|---|---|
| SCADA telemetry | 48000 | 1s | 80ms | < 0.01% |
| PMU phasor | 1200 | 20ms | 25ms | < 0.05% |
| Fault recording | 256 | Event-triggered | 50ms | 0% |
3. State Snapshots
The twin supports periodic and on-demand state snapshots, serializing the complete grid state into immutable snapshots for historical replay and comparative analysis. Snapshots use columnar compression storage, with a single snapshot occupying only 2-8MB.
Snapshot Operations
use eneros_twin::snapshot::{Snapshot, SnapshotId};
// Create manual snapshot
let snapshot = twin.snapshot()
.tag("pre-dispatch-check")
.metadata("operator", "zhang")
.capture()
.await?;
// List historical snapshots
let snapshots: Vec<Snapshot> = twin.snapshots()
.range(now() - Duration::hours(24), now())
.list()?;
// Restore twin state from snapshot
twin.restore(&snapshot).await?;
Snapshot Storage Strategy
| Snapshot Type | Trigger | Retention | Compression Ratio | Single Size |
|---|---|---|---|---|
| Real-time snapshot | Every 200ms | 7 days | 8:1 | 2-4MB |
| Minute snapshot | Every 1min | 90 days | 12:1 | 4-6MB |
| Hourly snapshot | Every 1h | 1 year | 15:1 | 6-8MB |
| Event snapshot | Before operations | Permanent | 10:1 | 4-6MB |
4. Historical Replay
Introduces the eneros-twin-replay crate, supporting replay of grid operation processes from any historical time point, with adjustable replay speed, viewpoint, and granularity, for incident analysis, training exercises, and compliance audits.
Replay Control
use eneros_twin_replay::{Replay, ReplayConfig, Speed};
let replay = Replay::new(&twin)
.config(ReplayConfig {
start_time: "2025-01-03T14:30:00Z".parse()?,
end_time: "2025-01-03T15:00:00Z".parse()?,
speed: Speed::Realtime,
focus_area: Some(BusId::from(110).into()),
})?;
// Start replay
replay.play().await?;
// Pause / Fast forward / Rewind
replay.pause().await?;
replay.set_speed(Speed::Fast(10.0)).await?;
replay.seek("2025-01-03T14:45:00Z").await?;
Replay Event Tracking
// Listen to events during replay
replay.on_event(|event| {
match event {
ReplayEvent::SwitchOperated(switch_id, state) => {
log::info!("Switch {} operated to {}", switch_id, state);
}
ReplayEvent::FaultDetected(fault) => {
log::warn!("Fault detected: {:?}", fault);
}
ReplayEvent::VoltageViolation(bus, value) => {
log::warn!("Bus {} voltage violation: {:.3} pu", bus, value);
}
}
});
5. What-if Analysis
Introduces the eneros-twin-whatif crate, supporting hypothetical operations on the twin and predicting their consequences without affecting the real grid. What-if analysis is the core capability for Agent decision rehearsal — Agents validate operation safety on the twin before executing real operations.
What-if Scenarios
use eneros_twin_whatif::{WhatIf, Scenario, Action};
// Construct a What-if scenario
let scenario = Scenario::new("open-line-12-14")
.initial_state(&twin.current_state()?)
.action(Action::OpenLine { from: 12, to: 14 })
.action(Action::AdjustGeneration { bus: 5, delta_mw: 50.0 })
.duration(Duration::minutes(10))
.step(Duration::seconds(1));
// Execute What-if analysis
let result = WhatIf::run(&scenario).await?;
// View prediction results
println!("Power flow converged: {}", result.converged);
println!("Max voltage deviation: {:.3} pu", result.max_voltage_deviation);
println!("Violation equipment count: {}", result.violations.len());
for violation in &result.violations {
println!(" - {:?}: {:.3} (limit {:.3})",
violation.equipment, violation.value, violation.limit);
}
What-if Decision Rehearsal
// Agent rehearses before executing real operations
async fn safe_dispatch(ctx: &Context, cmd: DispatchCommand) -> Result<()> {
// 1. Rehearse on twin
let scenario = Scenario::from_current(&ctx.twin)
.action(Action::Dispatch(cmd.clone()))
.duration(Duration::minutes(5));
let result = WhatIf::run(&scenario).await?;
// 2. Validate whether rehearsal results are safe
if !result.is_safe() {
return Err(DispatchError::UnsafePrediction(result.violations));
}
// 3. Rehearsal passed, execute real operation
ctx.syscall(ExecuteDispatch(cmd)).await?;
Ok(())
}
What-if Performance Metrics
| Scenario Scale | Node Count | Simulation Duration | Computation Time | Speedup |
|---|---|---|---|---|
| Small | 100 | 10min | 80ms | 7500x |
| Medium | 1000 | 10min | 450ms | 1333x |
| Large | 10000 | 10min | 1.2s | 500x |
| Provincial | 50000 | 10min | 6.8s | 88x |
Improvements
- Topology Engine:
eneros-topologysupports incremental topology change notifications; the twin can sense physical topology changes within 50ms - State Estimation: Introduced PMU phasor data fusion, improving state estimation accuracy from 92% to 99.2%
- Storage Compression: Twin snapshots use ZSTD columnar compression, reducing storage footprint by 70%
- API: Added GraphQL twin query interface, supporting complex state retrieval
Bug Fixes
- Fixed
eneros-twinstate estimation divergence during topology changes (#1305) - Fixed
eneros-twin-syncstate jumps due to out-of-order PMU data arrival (#1312) - Fixed
eneros-twin-replayevent loss during cross-snapshot replay (#1319) - Fixed
eneros-twin-whatifpower flow non-convergence on large grids (#1325)
Breaking Changes
Twin::newmust specify source_network: Original default empty network behavior removedSnapshot::capturechanged to async: Original sync signature moved tocapture_blockingStateEstimator::estimate: Return type addsbad_datafield
Performance Improvements
- Twin sync latency reduced from 500ms to 80ms (6.3x improvement)
- What-if computation time reduced from offline minutes to 1.2s (online level)
- State estimation accuracy improved from 92% to 99.2%
- Snapshot storage compression ratio improved from 4:1 to 12:1
Contributors
This version was completed by 24 contributors with 412 commits. Special thanks to:
- @twin-engine: Digital twin engine core architecture
- @state-estimator: WLS state estimation and PMU fusion
- @replay-master: Historical replay and event tracking
- @whatif-arch: What-if analysis and decision rehearsal
Upgrade Guide
Upgrading from v0.12.0
1. Update Dependencies
# Cargo.toml
[dependencies]
eneros-twin = { version = "0.13", features = ["high-fidelity"] }
eneros-twin-sync = { version = "0.13" }
eneros-twin-replay = { version = "0.13" }
eneros-twin-whatif = { version = "0.13" }
2. Initialize Twin
use eneros_twin::Twin;
// Create default twin based on existing topology
let twin = Twin::new(TwinId::from("default"))
.source_network(&network)
.config(TwinConfig {
fidelity: Fidelity::High,
sync_mode: SyncMode::Realtime,
..Default::default()
})?;
twin.start().await?;
3. Enable State Estimation
# eneros.toml
[twin]
enabled = true
fidelity = "high"
state_estimation = true
estimation_method = "wls"
history_depth_days = 30
4. Configure Agent Decision Rehearsal
It is recommended to enable What-if rehearsal for critical operation-type Agents to ensure operation safety:
Agent::new("dispatcher", tenant)
.preflight_check(PreflightConfig {
what_if_enabled: true,
scenario_duration: Duration::minutes(5),
safety_threshold: 0.99,
})
.spawn()?;