EnerOS v0.39.0
Release Date: 2026-06-13
Codename: Diag
Git Tag: v0.39.0
Support Status: Stable
Total Crates: 102 (6 new)
Test Cases: 12800+ (700 new)
Overview
EnerOS v0.39.0 “Diag” is the fault diagnosis themed release, upgrading power system fault diagnosis capabilities from “manual analysis of oscillography files” to an AI-driven automated workflow covering “automatic diagnosis + waveform recognition + precise location + report generation”. This release builds on the AI Agent from v0.31.0, the ML runtime from v0.32.0, and the simulation capabilities from v0.38.0 to construct an intelligent closed loop for grid fault diagnosis.
The core design philosophy of the Diag release is “oscillography as evidence + AI as expert” — waveforms recorded by fault recorders serve as objective evidence of the fault, while the AI diagnosis engine acts as a domain expert, extracting features from waveforms, identifying fault types, locating fault positions, tracing root causes, and generating structured diagnostic reports. This compresses average fault diagnosis time from hours to minutes, significantly shortening fault recovery time.
This release introduces five core capabilities: Fault Record Analysis, Waveform Recognition Engine, Fault Location Algorithms, Diagnostic Report Generation, and Fault Knowledge Graph. All capabilities are implemented through five new crates: eneros-diag, eneros-diag-record, eneros-diag-waveform, eneros-diag-location, and eneros-diag-report.
Key Metrics
| Metric | Value | Description |
|---|---|---|
| Fault type recognition accuracy | 98.3% | Covers 12 fault types |
| Fault location error | < 0.5% | Of line length |
| Record analysis time | 3.2s | Per fault |
| Diagnostic report generation | 8s | Including AI summary |
| New Crates | 6 | Diagnosis-related |
| New Tests | 700+ | Including 100 end-to-end |
New Features
1. Fault Record Analysis
Added the eneros-diag-record crate, providing parsing, standardization, and analysis capabilities for fault record files, supporting the COMTRADE 2013 standard format.
Record File Parsing
use eneros_diag_record::{ComtradeParser, Record, Channel};
// Parse COMTRADE format record file
let record = ComtradeParser::parse("fault_20260613_001.cfg", "fault_20260613_001.dat")?;
println!("Fault time: {}", record.trigger_time);
println!("Sampling rate: {} Hz", record.sampling_rate);
println!("Channel count: {}", record.channels.len());
println!("Total samples: {}", record.total_samples);
// Extract analog channels (voltage/current)
let voltages = record.analog_channels(AnalogType::Voltage);
let currents = record.analog_channels(AnalogType::Current);
// Extract digital channels (protection trip signals)
let trips = record.digital_channels(DigitalType::Trip);
println!("Protection action sequence:");
for trip in &trips {
println!(" {} @ {:?}", trip relay, trip.timestamp);
}
Multi-Source Record Alignment
use eneros_diag_record::{RecordAligner, TimeSource};
// Align records from multiple devices (based on GPS timestamps)
let aligner = RecordAligner::new()
.reference(TimeSource::Gps)
.tolerance(Duration::milliseconds(1));
let aligned = aligner.align(vec![record1, record2, record3]).await?;
// After alignment, waveforms can be compared across devices
for ch in aligned.channels("Bus5.Voltage") {
println!("Device {}: peak {:.2} kV", ch.device_id, ch.peak_value() / 1000.0);
}
Record Data Features
| Feature | Computation Method | Description |
|---|---|---|
| RMS | Sliding window RMS | Periodic component |
| Peak | Absolute maximum | Instantaneous value |
| Frequency | Zero-crossing detection | Deviation |
| Harmonics | FFT | THD |
| Symmetrical components | Symmetrical component method | Positive/negative/zero sequence |
| DC component | Decay fitting | Time constant |
2. Waveform Recognition Engine
Added the eneros-diag-waveform crate, automatically identifying fault types and features from waveforms based on ML models.
Fault Type Recognition
use eneros_diag_waveform::{WaveformAnalyzer, FaultClassifier, FaultType};
let analyzer = WaveformAnalyzer::new(&ctx)
.classifier(FaultClassifier::cnn("fault-cnn-v4"))
.build().await?;
// Analyze record waveform
let result = analyzer.analyze(&record).await?;
println!("Fault type: {:?}", result.fault_type);
println!("Confidence: {:.1}%", result.confidence * 100.0);
println!("Faulted phases: {:?}", result.faulted_phases);
println!("Fault onset: {:?}", result.fault_onset);
println!("Fault duration: {:?}", result.fault_duration);
println!("Peak fault current: {:.2} kA", result.peak_fault_current / 1000.0);
Fault Type Matrix
| Fault Type | Code | Recognition Accuracy | Typical Features |
|---|---|---|---|
| Three-phase short circuit | ABC | 99.5% | Simultaneous increase in all three phases |
| Single-phase ground fault | AG | 98.8% | Significant zero-sequence current |
| Two-phase short circuit | AB | 98.2% | Current increase in two phases |
| Two-phase ground fault | ABG | 97.5% | Zero-sequence + negative-sequence |
| Open conductor fault | OPEN | 96.0% | Current drop |
| High-impedance fault | HIF | 94.2% | Intermittent current |
| Oscillation | OSC | 97.8% | Power angle swing |
| Resonance | RES | 95.5% | Harmonic amplification |
Waveform Feature Extraction
// Extract waveform feature vector
let features = analyzer.extract_features(&record);
println!("Feature vector dimension: {}", features.dim());
println!("Key features:");
println!(" Zero-sequence current ratio: {:.3}", features.zero_seq_ratio);
println!(" Negative-sequence current ratio: {:.3}", features.neg_seq_ratio);
println!(" Sudden change: {:.3}", features.sudden_change);
println!(" Harmonic content: {:.3}", features.harmonic_content);
println!(" Decay time constant: {:.3}s", features.dc_time_constant);
// Feature visualization (for diagnostic report)
let plot = analyzer.plot_waveform(&record, &result);
plot.save("fault_waveform.png").await?;
3. Fault Location Algorithms
Added the eneros-diag-location crate, providing multiple fault location algorithms to precisely calculate the position of the fault point.
Algorithm Comparison
| Algorithm | Data Requirement | Accuracy | Applicable Scenarios |
|---|---|---|---|
| Impedance method | Single-ended | ±2% | Simple and fast |
| Double-ended method | Double-ended | ±0.5% | High precision |
| Traveling wave method | Double-ended | ±0.2% | Extra high voltage |
| Fault analysis | Multi-source | ±1% | Complex networks |
| AI location | Historical + real-time | ±0.8% | Complex faults |
Fault Location API
use eneros_diag_location::{FaultLocator, LocationMethod, LocationResult};
let locator = FaultLocator::new(&ctx)
.method(LocationMethod::DoubleEnded)
.network(&network)
.build().await?;
// Locate based on double-ended measurements
let location: LocationResult = locator.locate(&record, &record_remote).await?;
println!("Faulted line: {}", location.branch_id);
println!("Fault distance: {:.2f} km ({:.1}%)",
location.distance_km, location.percentage * 100.0);
println!("Estimated location error: ±{:.2f} km", location.error_estimate);
println!("Location method: {:?}", location.method);
Single-Ended Impedance Method
// Impedance-based location using single-ended electrical quantities
let locator = FaultLocator::new(&ctx)
.method(LocationMethod::Impedance {
algorithm: ImpedanceAlgorithm::Reactance,
compensation: true, // Consider remote infeed
})
.build().await?;
let location = locator.locate_single_ended(&record).await?;
println!("Measured impedance: {:.2f} Ω", location.measured_impedance);
println!("Fault distance: {:.2f} km", location.distance_km);
Traveling Wave Location
// Precise location based on traveling waves
let locator = FaultLocator::new(&ctx)
.method(LocationMethod::TravelingWave {
sampling_rate: 1_000_000, // 1 MHz
wave_speed: 2.98e8, // Speed of light
})
.build().await?;
let location = locator.locate_traveling_wave(&record, &record_remote).await?;
println!("Traveling wave arrival time difference: {:.3f} μs", location.time_diff_us);
println!("Fault distance: {:.2f} km", location.distance_km);
4. Diagnostic Report Generation
Added the eneros-diag-report crate, automatically generating structured fault diagnostic reports with AI analysis summaries.
Report Generation
use eneros_diag_report::{ReportGenerator, ReportConfig, ReportTemplate};
let generator = ReportGenerator::new(&ctx)
.config(ReportConfig {
template: ReportTemplate::Standard,
include_waveform_plots: true,
include_sequence_diagram: true,
include_replay: true,
language: Language::ZhCN,
})
.build().await?;
// Generate diagnostic report
let report = generator.generate(&fault_event).await?;
println!("Report ID: {}", report.id);
println!("Fault time: {}", report.fault_time);
println!("Fault type: {:?}", report.fault_type);
println!("Fault location: {}", report.location_description);
println!("Diagnostic conclusion: {}", report.conclusion);
// Export report
report.save_pdf("fault_report_20260613.pdf").await?;
report.save_html("fault_report_20260613.html").await?;
AI Summary Generation
// Use LLM to generate diagnostic summary
let summary = generator.generate_summary(&report).await?;
println!("AI diagnostic summary:");
println!("{}", summary);
// Example output:
// "On June 13, 2026 at 14:23:05, a phase-A ground fault occurred on the 110kV line L-3.
// The fault point is located 12.3 km from the head end (line length 25 km, at 49.2%).
// Peak fault current 4.82 kA, significant zero-sequence current, determined as a single-phase ground fault.
// Protection operated correctly, fault isolated within 80ms.
// Root cause analysis: Combined with weather data, there was thunderstorm activity in the area during the fault,
// presumed to be lightning causing insulator flashover. Recommend inspecting insulators near the fault point."
Report Content Structure
| Section | Content | Source |
|---|---|---|
| Basic information | Time/location/weather | System |
| Fault overview | Type/phase/duration | Waveform recognition |
| Fault location | Distance/percentage/error | Location algorithm |
| Protection actions | Action sequence/timing | Record digital channels |
| Waveform analysis | Voltage/current curves | Record data |
| Simulation comparison | Actual vs simulated | Simulation engine |
| Root cause analysis | Possible causes/probability | Knowledge graph |
| Handling recommendations | Follow-up actions | Rules + LLM |
| AI summary | Natural language summary | LLM |
5. Fault Knowledge Graph
Added the eneros-diag crate (diagnosis core), constructing a power fault knowledge graph to enable fault root cause tracing and experience accumulation.
Knowledge Graph Query
use eneros_diag::{KnowledgeGraph, FaultCase, CauseNode};
let kg = KnowledgeGraph::new(&ctx);
// Query similar fault cases
let similar = kg.find_similar(¤t_fault)
.limit(10)
.execute().await?;
println!("Similar fault cases:");
for case in &similar {
println!(" {} ({:?}): similarity {:.1}%",
case.id, case.fault_type, case.similarity * 100.0);
println!(" Cause: {}", case.root_cause);
println!(" Resolution: {}", case.resolution);
}
Root Cause Analysis
// Cause reasoning based on knowledge graph
let causes = kg.infer_causes(¤t_fault).await?;
println!("Possible causes (sorted by probability):");
for cause in &causes {
println!(" {} (probability {:.1}%)", cause.description, cause.probability * 100.0);
if let Some(evidence) = &cause.evidence {
println!(" Evidence: {}", evidence);
}
}
Knowledge Graph Structure
| Node Type | Count | Description |
|---|---|---|
| Fault type | 12 | Standard classification |
| Fault cause | 48 | Lightning/birds/aging, etc. |
| Fault symptom | 35 | Electrical characteristics |
| Equipment type | 28 | Associated equipment |
| Historical cases | 5000+ | Accumulated cases |
Improvements
- Time-series engine: Dedicated storage path for record data, write throughput increased 5x
- ML runtime: CNN model inference supports GPU acceleration, recognition latency reduced to 50ms
- Simulation engine: Fault simulation scenario templating, reproduction efficiency improved 3x
- Security gateway: Diagnostic report access adds permission control
- Observability: Full diagnostic chain integrated with tracing system
Bug Fixes
- Fixed
eneros-diag-recordCOMTRADE parser crash on non-standard formats (#3903) - Fixed
eneros-diag-waveformCNN model misclassification under short disturbances (#3910) - Fixed
eneros-diag-locationtraveling wave method location deviation when double-ended clocks are unsynchronized (#3916) - Fixed
eneros-diag-reportPDF generation garbled characters when rendering Chinese (#3922) - Fixed
eneros-diagknowledge graph query timeout on large-scale cases (#3928)
Breaking Changes
ComtradeParser::parse: Return type changed fromRecordtoResult<Record>FaultLocator::locate: Parameter changed from&Recordto&Record, &Record(double-ended)ReportGenerator::generate: Parameter changed from&Faultto&FaultEvent
Upgrade Guide
- Update the
enerosdependency inCargo.tomlto0.39.0 - Run
eneros diag initto initialize the diagnosis engine - Configure record file paths and ML models in
eneros.toml - Import historical fault cases into the knowledge graph
Acknowledgments
Thanks to the 40 contributors who submitted 610+ commits, and to the relay protection experts who provided fault sample validation.