Protection assessment (a passive relay overlay)
Chapter 15 documents the active protection layer - the IActiveAssetDynamics controllers that trip
infeed, shed load and open branches during a simulation, changing the trajectory. This chapter documents
its passive counterpart: a protection-simulation overlay that reads a solved state and reports which
relays would operate and why, without ever altering the solve. It is the evidence-apparatus sibling
of the physics-conformance audit (ch. 16) - an independent read-only overlay, not a control loop - and it
exists to let a run conclude, with a straight face, "on branch PITS_3-WIBA_3, thermal-overload protection
would likely operate - loaded to 123% of RateA; the IEC inverse-time element trips in 3.3 s."
What it is not
Real relay settings are unobtainable (site-specific, commercially confidential), so this is deliberately not a certified protection study. The operating quantities are always computed from the solved state; the pickups they are compared against are generic standard-practice values, honestly graded:
- Grounded - the statutory GB frequency band (47.5 / 52 Hz) and the modern ALoMCP RoCoF limit (1.0 Hz/s).
- Generic - everything else (voltage band, overcurrent multiples, distance zone reaches, thermal pickup): a plausible default a real scheme would grade per site. Overridable per run.
- NotCheckable - elements a positive-sequence phasor model cannot evaluate, reported as such rather than fabricated (see below).
The engine (src/GridSim.Core/Protection/)
ProtectionAssessment.Assess(model, result, settings?, trajectory?) builds a ProtectionContext - every
operating quantity computed once from the solved state (per-bus voltage, per-branch apparent power /
current / loading / apparent impedance, the busbar KCL differential residual, system frequency) - then runs
each relay in ProtectionRegistry.All over it. The relays are pure comparisons, so the whole assessment is
a read-only overlay: it never calls the solver and never mutates the model or result (pinned by a test).
Each relay yields a RelayVerdict per location where it operates, plus the single closest
non-operating location for context, carrying: the ANSI device number, the operating quantity + unit, the
pickup, the signed margin, an inverse-time TimeToTripS where the element has a curve, a plain-language
Basis ("Vm 0.74 pu at bus 7 is below the 0.80 pu undervoltage pickup"), and the confidence grade.
ProtectionReport.Operating is the subset that would fire, worst-margin first.
The relay library
| ANSI | Element | Operating quantity | Notes |
|---|---|---|---|
| 27 / 59 | Under / overvoltage | bus Vm vs band | per bus |
| 32 | Reverse power | generator Pg < -pickup | motoring detection |
| 37 | Undercurrent | branch |I| below an absolute floor | a de-energized in-service circuit, NOT a normally lightly-loaded line |
| 49 | Thermal overload | branch loading vs RateA | first-order thermal replica gives the operating time |
| 50 | Instantaneous overcurrent | |I| / rated | definite/instant operation |
| 51 | Time overcurrent | |I| / rated | IEC 60255 standard-inverse t = TMS.0.14/(M^0.02-1) |
| 21 | Distance | apparent Z = V²/conj(S) at the from end | three forward zones scaled from the line's own Z; load encroachment shows here |
| 81U / 81O | Under / overfrequency | run min/max (or steady) frequency | statutory band (Grounded) |
| 81R | RoCoF | peak |df/dt| | needs a trajectory (else NotCheckable) |
| 78 | Vector shift / loss-of-mains | peak voltage-angle jump | needs a trajectory |
| 87 | Busbar differential | KCL current residual at the bus | ~machine-epsilon on a converged solve; bites only under an injected internal fault (the bus shunt is netted off, or a capacitor bank reads as a false fault) |
| 50N/51N/21N/46 | Earth / negative-sequence | - | NotCheckable: a positive-sequence model carries no zero/negative-sequence network, so there is no residual current to compute |
Honest scope (the "Gauss law" of protection)
Just as the physics audit reports Gauss's law as not modelled in a phasor model rather than inventing a
residual, the earth-fault and negative-sequence elements (50N/51N/21N/46) are reported NotCheckable with
exactly what a real assessment would need (an unbalanced sequence-impedance model). The busbar differential
(87) is checkable but ~zero on a balanced converged state - reported secure with the largest residual shown,
meaningful only once an internal fault is injected. RoCoF/vector-shift (81R/78) need a dynamic run; on a
steady snapshot they report NotCheckable rather than a fabricated transient. When a dynamic run is
available, a ProtectionTrajectory (peak RoCoF, min/max frequency, peak vector shift) enables them.
Surfacing
gridsim protection-check <case> [--uv pu] [--ov pu] [--uf/--of Hz] [--oc xIn] [--thermal frac] [--rocof Hz/s]- solve the case and print the operating elements (device, location, quantity, pickup, time, basis), the not-evaluated elements, and the headline "PROTECTION SIMULATION suggests N protection event(s)...". The flags override the generic pickups so a run can ask "what would a tighter relay do".- End of a plain solve -
PrintDetailedappends one line: either "no relay would operate on this state" or "N event(s) suggested - e.g. on X, relay Y would likely operate (...)". The solve above is untouched; this is the passive overlay, exactly as asked.
On the real GB spine one operating point yields two events - a thermal overload and its time-overcurrent on the branch loaded to 123% of its 1,500 MVA rating - and nothing else: the noise-free, defensible statement the overlay is for.
Fault injection (FaultAnalysis)
The differential (87) and distance (21) elements only bite on a real fault, so FaultAnalysis.ThreePhase
injects one. It is the classic Thevenin / bus-impedance superposition: from the prefault solved
voltages it builds the fault-study admittance (network Ybus + each load as a constant-impedance shunt +
each generator as its subtransient reactance to ground), solves one column of the bus-impedance matrix for
the fault bus, and superposes the fault:
If = V0_k / (Zth_kk + Zf), V_faulted = V0 - Zbus[:,k] . If
The faulted branch currents then drive the overlay. It is positive-sequence, so it represents the
balanced three-phase fault exactly; an earth (single-line-to-ground) fault needs a sequence-network
model and is reported not-representable. Generator subtransient reactances are synthesised (a generic
X"d, since the model carries no machine reactance) and provenance-noted. Dense (the bus-impedance column is
a dense complex solve), so it fails loud above a bus limit. ProtectionAssessment.AssessThreePhaseFault
applies the fault and assesses the faulted state in one call, feeding the fault current to the differential.
gridsim fault <case> --bus <id> [--zf pu] prints the fault current (pu and kA), the Thevenin impedance,
the collapsed bus voltage, and the relays that operate. On IEEE-14 a bolted fault at bus 4 draws ~12.4 pu,
collapses the bus to 0, and operates 87 on bus 4 (at the fault current), 21 Zone 2 on the two
faulted-branch relays with Zone 3 backup on remote relays, and 27 across the depressed network - textbook.
Cascade propagation (ProtectionCascade)
A read-only "what-if" that follows a protection event as it propagates: from a prefault state it
assesses the overlay, trips the branch element that would operate FIRST (shortest inverse-time), opens that
branch in a COPY of the model, re-solves, and re-assesses - chaining until nothing else trips, the re-solve
fails (a split / blackout, the honest terminal state), or a step cap is hit. It never touches the caller's
solve. Branch-tripping elements only (49/50/51/21); voltage/frequency elements shed or trip infeed and are
left to the active layer (ch. 15). gridsim protection-check <case> --cascade prints the ordered sequence.
On the GB spine the single 123%-overload seeds a seven-trip cascade that ends in a non-convergent split -
the cascade-to-blackout story, quantified.
Invariants (pinned by ProtectionAssessmentTests, FaultAndCascadeTests)
- Read-only -
Assessnever mutates the result (voltage array identical before/after). - No false differential - a healthy converged case raises no 87 (the bus shunt is netted off the KCL residual).
- Threshold logic - tightening the band around the real voltage spread fires 27 and 59; a branch rated below its flow fires 49/50/51 with sensible inverse-time; more current trips 51 sooner.
- Trajectory gating - 81R and 78 are NotCheckable and never operate without a trajectory; a supplied trajectory that dipped to 47.0 Hz at 2.0 Hz/s fires 81U and 81R.
- Honest not-checkable - the earth/negative-sequence element always reports NotCheckable.
Key files
Protection/{ProtectionTypes,ProtectionContext,ProtectionRelays,ProtectionAssessment,FaultAnalysis, ProtectionCascade}.cs; GridSim.Cli/Program.cs (protection-check + --cascade, fault verbs + the
PrintDetailed end-of-run line). Tests: ProtectionAssessmentTests, FaultAndCascadeTests.