Grid Analysis Advanced
EnerOS v0.44.0 significantly enhances grid analysis capabilities, building state estimation, optimal power flow (OPF), short circuit analysis, electromagnetic transient simulation (EMTP), and other advanced analysis capabilities into kernel services. Agents invoke through a unified API, completing all analysis tasks without external commercial simulation software. The analysis capabilities are provided by the eneros-powerflow and eneros-analysis crates working together.
Analysis Capability Architecture
┌──────────────────────────────────────────────────────────────┐
│ Analysis Service Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ State │ │ Optimal │ │ Short │ │ EMTP │ │
│ │ Estimation│ │ Power │ │ Circuit │ │ Simulation│ │
│ │ SE │ │ OPF │ │ SC │ │ │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
└───────┼─────────────┼─────────────┼─────────────┼───────────┘
│ │ │ │
┌───────▼─────────────▼─────────────▼─────────────▼───────────┐
│ Solver Layer │
│ Newton-Raphson / Fast Decoupled / Interior Point / │
│ Simplex / Trapezoidal / WLS / LAV │
└──────────────────────────┬───────────────────────────────────┘
│
┌──────────────────────────▼───────────────────────────────────┐
│ Data Layer │
│ Topology Model / Device Parameters / Measurement Data / │
│ Time-Series Database │
└──────────────────────────────────────────────────────────────┘
| Analysis Type | Solver | Typical Duration | Output |
|---|
| State Estimation | WLS / LAV | < 50ms | Bus voltage phasors |
| Load Flow | Newton-Raphson / Fast Decoupled | < 20ms | Bus voltage, branch power |
| DC OPF | Simplex | < 100ms | Generation dispatch |
| AC OPF | Interior Point | < 500ms | Generation + voltage |
| Short Circuit Analysis | IEC 60909 | < 30ms | Short circuit current |
| EMTP | Trapezoidal | < 5s | Transient waveform |
| Harmonic Analysis | Frequency scan | < 1s | Harmonic spectrum |
State Estimation
WLS (Weighted Least Squares) based state estimation, fusing SCADA and PMU data. Supports bad data identification and observability analysis.
use eneros_analysis::{StateEstimator, Measurement, Weight, Confidence};
use std::time::Duration;
let estimator = StateEstimator::wls()
.max_iterations(20)
.tolerance(1e-6)
.flat_start(false);
// Input measurements
let measurements = vec![
Measurement::power_injection(bus_id, 50.0, Weight::from_sigma(2.0)),
Measurement::power_flow(line_id, 30.0, Weight::from_sigma(1.5)),
Measurement::voltage_magnitude(bus_id, 1.02, Weight::from_sigma(0.005)),
Measurement::current_magnitude(line_id, 0.45, Weight::from_sigma(0.01)),
Measurement::pmu(bus_id, 1.02, 0.1, Weight::high()), // PMU high weight
Measurement::pmu(bus_id2, 1.01, 0.15, Weight::high()),
];
let result = estimator.estimate(&network, &measurements).await?;
println!("Converged: {}", result.converged);
println!("Iterations: {}", result.iterations);
println!("Residual: {:.4}", result.total_residual);
println!("Max residual: {:.4}", result.max_residual);
for (bus, v) in &result.voltages {
println!("Bus {}: {:.4} ∠ {:.4}°",
bus, v.magnitude, v.angle_deg);
}
Bad Data Identification
// Identify bad data based on chi-square test
let bad = estimator.detect_bad_data(&result, Confidence::percent(99))?;
for data in &bad {
println!("Bad data: bus={}, type={:?}, residual={:.2}, normalized residual={:.2}",
data.bus_id, data.measurement_type, data.residual, data.normalized_residual);
}
// Re-estimate after removing bad data
let cleaned = estimator.remove_bad_data(&measurements, &bad);
let result2 = estimator.estimate(&network, &cleaned).await?;
Observability Analysis
use eneros_analysis::observability::ObservabilityAnalyzer;
let analyzer = ObservabilityAnalyzer::new();
let obs = analyzer.analyze(&network, &measurements).await?;
println!("Observable: {}", obs.is_observable);
println!("Observable buses: {}/{}", obs.observable_buses, network.bus_count());
if !obs.is_observable {
for island in &obs.unobservable_islands {
println!("Unobservable island: {:?}", island.buses);
println!("Suggested measurements: {:?}", island.suggested_measurements);
}
}
Optimal Power Flow (OPF)
Supports DC OPF and AC OPF, with multiple objective functions and constraints:
use eneros_analysis::opf::{OpfSolver, Objective, Method, CostCurve, Constraint};
let solver = OpfSolver::new()
.method(Method::InteriorPoint)
.objective(Objective::MinGenerationCost)
.tolerance(1e-6)
.max_iterations(100);
// Add generator cost curves
solver.add_cost_curve(gen_id, CostCurve::quadratic(0.001, 20.0, 100.0));
solver.add_cost_curve(gen_id2, CostCurve::piecewise(&[
(0.0, 50.0),
(100.0, 55.0),
(200.0, 65.0),
]));
// Add constraints
solver.add_constraint(Constraint::line_flow(line_id, 100.0)); // Line power upper limit
solver.add_constraint(Constraint::voltage_range(bus_id, 0.95, 1.05));
solver.add_constraint(Constraint::gen_range(gen_id, 50.0, 200.0));
let result = solver.solve(&network).await?;
println!("Converged: {}", result.converged);
println!("Total cost: ${:.2}/h", result.total_cost);
println!("Network losses: {:.2} MW", result.losses);
for (gen, p) in &result.generation {
println!("Gen {}: {:.2} MW", gen, p);
}
OPF Objective Functions
| Objective | Formula | Applicable Scenarios |
|---|
| Minimum generation cost | min ΣC_i(P_i) | Economic dispatch |
| Minimum network losses | min Σlosses | Loss optimization |
| Maximum transmission capacity | max P_transfer | TTC/ATC |
| Minimum voltage deviation | min Σ|V_i - V_ref| | Power quality |
| Maximum reactive reserve | max Σ(Q_max - Q_i) | Safety margin |
OPF Solver Comparison
| Solver | Type | Speed | Accuracy | Global Optimum |
|---|
| Simplex | DC | Very fast | High | ✅ |
| Interior Point | AC | Fast | High | ✅ |
| SQP | AC | Medium | Very high | Local |
| Heuristic | Any | Slow | Medium | Approximate |
Short Circuit Analysis
Supports short circuit calculation complying with IEC 60909 and ANSI/IEEE C37 standards, covering various fault types:
use eneros_analysis::shortage::{ShortCircuit, FaultType, Standard, FaultLocation};
let sc = ShortCircuit::new()
.standard(Standard::IEC60909)
.fault(FaultType::ThreePhase)
.at(FaultLocation::bus(bus_id))
.prefault_voltage(1.0); // Pre-fault voltage
let result = sc.calculate(&network).await?;
println!("Fault bus: {}", bus_id);
println!("Short circuit current (RMS): {:.2} kA", result.current_kA);
println!("Short circuit capacity: {:.2} MVA", result.mva);
println!("Peak current: {:.2} kA", result.peak_current_kA);
println!("DC component: {:.2} kA", result.dc_component_kA);
// Branch contributions
for (line, current) in &result.branch_contributions {
println!("Branch {}: {:.2} kA", line, current);
}
Fault Types
| Type | Description | Typical Scenarios |
|---|
| Three-phase short circuit | LLL | Most severe fault |
| Line-to-line short circuit | LL | Line fault |
| Double line-to-ground | LLG | Single-phase ground evolution |
| Single line-to-ground | LG | Most common fault (80%+) |
Batch Short Circuit Analysis
use eneros_analysis::shortage::BatchShortCircuit;
let batch = BatchShortCircuit::new()
.faults(vec![
Fault::three_phase(bus_1),
Fault::single_phase_to_ground(bus_2),
Fault::line_to_line(bus_3),
])
.parallelism(4);
let results = batch.calculate(&network).await?;
for (i, result) in results.iter().enumerate() {
println!("Fault {}: short circuit current {:.2} kA", i, result.current_kA);
}
Electromagnetic Transient Simulation (EMTP)
Used for analyzing transient processes such as switching operations and lightning overvoltage:
use eneros_analysis::emtp::{EmtpSimulator, SimulationConfig, SimulationEvent, IntegrationMethod};
let sim = EmtpSimulator::new(SimulationConfig {
dt: Duration::from_micros(50), // 50μs step
duration: Duration::from_millis(100), // Simulate 100ms
method: IntegrationMethod::Trapezoidal,
tolerance: 1e-6,
output: OutputConfig::all_buses(),
});
// Add events
sim.event(SimulationEvent::close_breaker(breaker_id, t0)).await?;
sim.event(SimulationEvent::open_breaker(breaker_id2, t0 + Duration::from_millis(10))).await?;
sim.event(SimulationEvent::lightning_strike(bus_id, 100.0, t0 + Duration::from_millis(20))).await?;
let result = sim.run(&network).await?;
// Extract bus voltage waveform
let waveform = result.voltage(bus_id);
let peak = waveform.iter().map(|s| s.value).fold(0.0f64, f64::max);
let trough = waveform.iter().map(|s| s.value).fold(0.0f64, f64::min);
println!("Overvoltage peak: {:.2} kV", peak);
println!("Lowest voltage: {:.2} kV", trough);
// Export waveform as CSV
result.export_csv("waveforms.csv", ExportOptions::default()).await?;
EMTP Configuration Parameters
| Parameter | Default | Description |
|---|
| dt | 50μs | Simulation step |
| duration | 100ms | Simulation duration |
| method | Trapezoidal | Integration method |
| tolerance | 1e-6 | Convergence tolerance |
| max_iterations | 50 | Max iterations per step |
| output | all_buses | Output buses |
Harmonic Analysis
use eneros_analysis::harmonic::{HarmonicAnalyzer, HarmonicMethod};
let analyzer = HarmonicAnalyzer::new()
.orders(1..=50) // 1st-50th harmonics
.method(HarmonicMethod::FrequencyScan)
.scan_step(0.1); // 0.1 Hz scan step
let result = analyzer.analyze(&network).await?;
// Total harmonic distortion
let thd = result.thd(bus_id);
println!("THD: {:.2}%", thd * 100.0);
// Individual harmonic components
for order in 2..=50 {
let mag = result.harmonic_magnitude(bus_id, order);
if mag > 0.001 {
println!("{}-th harmonic: {:.2f}%", order, mag * 100.0);
}
}
// Whether exceeding limit
let limit = HarmonicLimit::ieee_519();
if result.exceeds(bus_id, &limit) {
println!("Warning: {} bus harmonics exceed IEEE 519", bus_id);
}
Harmonic Standards
| Standard | Applicable | THD Limit |
|---|
| IEEE 519 | International | 5% |
| GB/T 14549 | China | 5% (380V) |
| IEC 61000 | International | 8% |
Analysis Capability Matrix
| Analysis Type | Solver | Typical Duration | Parallelism |
|---|
| State Estimation | WLS / LAV | < 50ms | ✅ |
| Load Flow | Newton-Raphson / Fast Decoupled | < 20ms | ✅ |
| DC OPF | Simplex | < 100ms | ✅ |
| AC OPF | Interior Point | < 500ms | ✅ |
| Short Circuit Analysis | IEC 60909 | < 30ms | ✅ Batch |
| EMTP | Trapezoidal | < 5s (100ms simulation) | Partial |
| Harmonic Analysis | Frequency scan | < 1s | ✅ |
| Operation | Latency (1000 buses) | Latency (10000 buses) |
|---|
| State Estimation | < 50ms | < 200ms |
| Load Flow | < 20ms | < 100ms |
| DC OPF | < 100ms | < 500ms |
| AC OPF | < 500ms | < 2s |
| Short Circuit Analysis (single fault) | < 30ms | < 100ms |
| Short Circuit Analysis (batch 100) | < 1s | < 5s |
| EMTP (100ms simulation) | < 5s | < 30s |
| Harmonic Analysis (50th order) | < 1s | < 5s |
Relationship with Other Capabilities