Skip to main content

v0.39.0 Release Notes

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

MetricValueDescription
Fault type recognition accuracy98.3%Covers 12 fault types
Fault location error< 0.5%Of line length
Record analysis time3.2sPer fault
Diagnostic report generation8sIncluding AI summary
New Crates6Diagnosis-related
New Tests700+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

FeatureComputation MethodDescription
RMSSliding window RMSPeriodic component
PeakAbsolute maximumInstantaneous value
FrequencyZero-crossing detectionDeviation
HarmonicsFFTTHD
Symmetrical componentsSymmetrical component methodPositive/negative/zero sequence
DC componentDecay fittingTime 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 TypeCodeRecognition AccuracyTypical Features
Three-phase short circuitABC99.5%Simultaneous increase in all three phases
Single-phase ground faultAG98.8%Significant zero-sequence current
Two-phase short circuitAB98.2%Current increase in two phases
Two-phase ground faultABG97.5%Zero-sequence + negative-sequence
Open conductor faultOPEN96.0%Current drop
High-impedance faultHIF94.2%Intermittent current
OscillationOSC97.8%Power angle swing
ResonanceRES95.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

AlgorithmData RequirementAccuracyApplicable Scenarios
Impedance methodSingle-ended±2%Simple and fast
Double-ended methodDouble-ended±0.5%High precision
Traveling wave methodDouble-ended±0.2%Extra high voltage
Fault analysisMulti-source±1%Complex networks
AI locationHistorical + 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

SectionContentSource
Basic informationTime/location/weatherSystem
Fault overviewType/phase/durationWaveform recognition
Fault locationDistance/percentage/errorLocation algorithm
Protection actionsAction sequence/timingRecord digital channels
Waveform analysisVoltage/current curvesRecord data
Simulation comparisonActual vs simulatedSimulation engine
Root cause analysisPossible causes/probabilityKnowledge graph
Handling recommendationsFollow-up actionsRules + LLM
AI summaryNatural language summaryLLM

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(&current_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(&current_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 TypeCountDescription
Fault type12Standard classification
Fault cause48Lightning/birds/aging, etc.
Fault symptom35Electrical characteristics
Equipment type28Associated equipment
Historical cases5000+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-record COMTRADE parser crash on non-standard formats (#3903)
  • Fixed eneros-diag-waveform CNN model misclassification under short disturbances (#3910)
  • Fixed eneros-diag-location traveling wave method location deviation when double-ended clocks are unsynchronized (#3916)
  • Fixed eneros-diag-report PDF generation garbled characters when rendering Chinese (#3922)
  • Fixed eneros-diag knowledge graph query timeout on large-scale cases (#3928)

Breaking Changes

  • ComtradeParser::parse: Return type changed from Record to Result<Record>
  • FaultLocator::locate: Parameter changed from &Record to &Record, &Record (double-ended)
  • ReportGenerator::generate: Parameter changed from &Fault to &FaultEvent

Upgrade Guide

  1. Update the eneros dependency in Cargo.toml to 0.39.0
  2. Run eneros diag init to initialize the diagnosis engine
  3. Configure record file paths and ML models in eneros.toml
  4. 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.