This is an old revision of the document!
Table of Contents
Application note: finding an intermittent fault from Sampled Values
The problem
A feeder trips every few weeks. Nobody knows why.
The relay's own disturbance record shows the trip and the half-second around it, which is enough to confirm that the relay did what it was set to do and nothing at all about what caused the event. Worse, the interesting behaviour usually does not trip: the plant reports flickering lights, a drive faulting out, a contactor that chatters, and by the time anyone looks there is nothing to look at. The evidence exists for a few milliseconds somewhere on the bus and then it is gone.
What is needed is a recorder that is always listening, that keeps the cycles from before the event as well as after it, that writes what it caught in a format a protection engineer can open, and that can say something useful about several hundred captures without a person opening each one.
This note describes that application, built from the IEC 61850 beans and the waveform beans together. The same diagram runs against a merging unit on a live bus and against a folder of COMTRADE files on a laptop, which is what makes it possible to develop with confidence.
The approach
┌─ the substation ──────────────┐ ┌─ the application ───────────────────────────────────┐
│ │ │ │
│ merging unit ──── SV 9-2 LE ────▶ Iec61850SvSubscriber ──▶ TimeSeriesWindowBuffer │
│ (CT/VT, 4000 frames/s) │ │ │ │ │
│ │ │ └─ RMS ──▶ display ▼ │
│ protection relay ── GOOSE ─────▶ Iec61850GooseSubscriber ──▶ DisturbanceRecorder │
│ (trip, in 4 ms) │ │ │ │
└───────────────────────────────┘ │ ▼ │
│ ComtradeWriter │
│ │ │
│ .cfg / .dat on disk │
│ │ │
│ ▼ │
│ ComtradeParser ──▶ FeatureExtractor ──▶ per-cycle │
│ │ features │
│ ▼ │
│ detector ──▶ LLMPrompt ──▶ a │
│ screen │
└─────────────────────────────────────────────────────┘
The left half is IEC 61850 and the right half has never heard of it. That separation is the design,
not an accident of packaging: DisturbanceRecorder, ComtradeWriter, ComtradeParser and
the feature beans take records, and a record is a record whether it arrived from a merging unit or
from a file. Build the right half against a folder of captures, then put a subscriber in front of
it.
The pieces
GOOSE is the trigger, not the data
Iec61850GooseSubscriber follows one publisher, normally the protection relay, and republishes
its data set members as data sources. The trip signal is the obvious trigger for a capture, and it
arrives within the 4 ms GOOSE is engineered for, which is well inside the window the buffer is
already holding.
Two properties of the subscription matter more than they look.
- A subscription going quiet is data. Every frame carries the publisher's
timeAllowedToLive; when it expires with no successor the subscriber marks its values bad rather than holding the last good one. A trigger that silently stopped arriving is the failure mode this design most needs to not have. - ConfRev is worth setting. A publisher whose data set is re-engineered increments it, and a mismatch is refused rather than decoded into the wrong members.
The trigger does not have to be GOOSE. A detector's flag or an operator's button reaches the same inport, and the interesting configurations usually have both: the relay's opinion, and a threshold of your own for the events that never trip.
Sampled Values are the waveform
A merging unit sends four thousand frames a second. Nothing in an application wants four thousand
values a second and no connector should carry them, so Iec61850SvSubscriber emits one record
every ChunkCycles cycles — a time column and the channel columns, in amps and volts — and
publishes the RMS of each channel beside it for the screen. One value per cycle crosses one
connector instead of four thousand.
The window comes before the recorder
TimeSeriesWindowBuffer holds the last MaxAge of waveform, continuously, whether anything is
happening or not. This is the part that is easy to leave out and impossible to add later: the
half of a disturbance record that matters most is the half from before the trigger. What the
current was doing in the cycles leading up to the trip is what says whether the relay was right, and
a recorder that began collecting when something happened would have missed exactly that.
DisturbanceRecorder then takes the window on a trigger, keeps collecting for
PostTriggerSeconds, and emits one record. RetriggerHoldOff stops a chattering source from
producing a hundred captures of one event.
COMTRADE is the deliverable
ComtradeWriter writes an IEEE C37.111 .cfg/.dat pair. This is not an implementation
detail — it is the reason the application is worth building. A protection engineer opens COMTRADE
in the tool they already own, the utility's own analysis suite reads it, and it can be sent to the
relay vendor with a fault report. A capture in a proprietary format is an argument; a capture in
COMTRADE is evidence.
ComtradeParser reads them back, which is what lets the analytics and the whole right-hand half
of the diagram be developed and regression-tested against captures nobody has to reproduce.
One number per cycle
Several hundred captures is too many to open by hand, so the analytics reduce each one to something
sortable. FeatureExtractor is asked for a feature vector per cycle — one 20 ms window at
50 Hz — and the metric that carries the most information for the least explanation is the share of
each cycle's energy that is not at the fundamental:
impurity = 1 - (energy in the 45-55 Hz band / total energy in the cycle)
which is band_power_ratio over two named bands. A clean 50 Hz cycle scores near zero however
large its amplitude. Arcing, switching transients, converter misbehaviour and partial discharge all
move energy away from the fundamental and score high.
Two numbers per record then say most of what is worth knowing:
- the median impurity across every cycle and channel, which is the steady state, and
- the worst cycle, with the channel and the time it occurred on.
A record whose median is low and whose worst is high had a brief event. A record whose median is already high has a sustained harmonic problem — a different fault, and a different report.
The diagnosis
LLMPrompt is given the feature vectors and the two summary numbers, not the waveform, and asked
what they are consistent with. The value is not that it is clever; it is that it writes the same
paragraph for the four hundredth record as for the first, and names the evidence it used so that a
person can disagree with it.
A worked example
The screen below is one record from an RTE digital fault recorder, 6400 Hz, 50 Hz nominal, one 20 ms cycle per feature vector — a file, played through the same beans that would be fed by a merging unit.
Upload the screenshot to the wiki and correct the image name above to match; ?900 sets the
displayed width.
Three panes, top to bottom.
- Raw waveform — six channels, three currents and three voltages. Something happens just
before 17:27:41, the currents collapse, and roughly a second later everything comes back. That
is a fault, a breaker opening, and a successful reclose. It is also about as much as the raw trace will tell you. * **Per-cycle spectral purity** — the impurity of every cycle of every channel. The steady state sits on the floor at 0.033 and below. During the event it goes to nearly 1: for a cluster of cycles, almost none of the energy is at 50 Hz. * **Diagnosis** — median 0.00217, worst 0.96135 on I3. The steady state was clean, so this is not a harmonic load; the excursion is a factor of several hundred over a short cluster of cycles; within those cycles the fundamental is nearly gone and the energy is spread over 400–3150 Hz. That signature is arcing or contact operation, not a clean high-amplitude 50 Hz fault current.
The last sentence of the diagnosis is the important one, and it is a limitation stated rather than hidden: to remove the remaining ambiguity, check where rms and peak maximised across the record. A clean high-amplitude fault current is pure — it would score near zero on this metric and the screening would pass it. See below.
What to build
| Bean | Role |
|---|---|
Iec61850SvSubscriber | the waveform, chunked one record per ChunkCycles cycles |
Iec61850GooseSubscriber | the relay's trip, as the trigger |
TimeSeriesWindowBuffer | the rolling pre-trigger window |
DisturbanceRecorder | pre-trigger window plus PostTriggerSeconds, on a trigger |
ComtradeWriter | the .cfg/.dat pair |
ComtradeParser | reads captures back for the analytics |
FeatureExtractor | per-cycle features, including band_power_ratio |
LLMPrompt | the written diagnosis |
Set PollPeriod to -1 on anything fed by a report or a subscription so nothing is asked for
twice. See IEC 61850 for the subscriber beans, Disturbance recording for the recorder and
the writer, and FeatureExtractor for the metric vocabulary and the request format.
What this does not do
- The impurity metric does not see a clean fault. A high-amplitude fault current at the
fundamental is spectrally pure and scores near zero. This screening finds events with a
distorted signature — arcing, switching, converter faults — and must be paired with an amplitude test to find the rest. Neither test subsumes the other. * **A dead channel looks perfectly clean.** A channel reading zero, or a stuck value, has no out-of-band energy at all. A liveness gate on RMS belongs in front of any threshold set on this metric, or an instrument failure will be reported as a healthy bus. * **Nothing here is protection.** This is a recorder and an analysis of what it recorded. The relay protects the plant, the application explains it afterwards. * **A capture is only as good as its clock.** Sampled Values are timestamped from the kernel's receive time of the frame that begins the cycle; comparing captures from two applications means both need real time synchronisation.
Getting started without a substation
The right-hand half of the diagram needs no IEC 61850 at all. Point ComtradeParser at a folder
of existing captures — a relay's own records, or a public fault-recorder set — and build the
extraction, the detector and the screen against files. When it works, put Iec61850SvSubscriber
in front of it.
To go the other way, Iec61850SvPublisher plays a record back onto the wire as 9-2 LE, so a
relay on the same segment sees a fault it cannot tell from the one that happened. That is how
protection settings are proved before they are trusted, and it is also how this pipeline gets
tested end to end without waiting weeks for the feeder to trip again.

