Asset-dynamics data grounding
Which per-asset dynamics parameters are grounded in real UK data (mined from the GDA lake) versus
literature-approximated [VERIFY] (unmeasurable / absent from the lake). This is the honest
provenance ledger behind the authored asset classes (data/<case>/asset-classes.json, and GDA's
NetworkModel/build_asset_classes.py). Every value below was read from an actual file, not a catalogue
claim. Paths are relative to D:\Work\GDA\v1.
The rule: a grounded value is tagged Recorded (published fact) or DerivedFromRecorded (computed from
records); everything else is CuratedPlaceholder + the literal [VERIFY] token, and the aggregate
fleet result is UnvalidatedAtScale. The curve shape is assumption-driven; capacity/location and the
few grounded dynamics below are not.
Grounded — inverter fleet
| Parameter | Grounded value | Source |
|---|---|---|
dispatchRampMwPerMin (per fuel) |
wind ≈ 32, solar ≈ 39, storage 60 MW/min | Outputs/ramp_correlation.json (observed gas-vs-renewable ramp bands, 24 mo) |
rocofTripHzPerS (modern) |
1.0 Hz/s | ALoMCP setting, Documentation/manual/54-frequency-rocof-detectors.md; GridSim FrequencyLimits.RocofLimitModernHzPerS |
rocofTripHzPerS (legacy) |
0.125 Hz/s | legacy LoM relay, same source; FrequencyLimits.RocofLimitLegacyHzPerS |
rocofTripConfirmS (modern) |
0.5 s definite-time delay | ALoMCP 500 ms definite-time delay, manual/54 |
rocofTripConfirmS (legacy) |
0.0 s (instantaneous) | legacy relays had no intentional delay, manual/54 |
deadbandHz |
0.015 Hz | NESO frequency-response service deadband (published) |
| per-technology capacity + bus | grounded per unit | TEC TECRegister/…/tec_2026-07-10.parquet (Built 81.6 GW), REPD, DUKES, BMU crosswalk |
| fleet ramp-absorption context | 0.40–0.55 of a renewable swing | Outputs/flex_stack_response.json (informs headroom plausibility) |
Grounded — passive plant (transformer / cable)
| Parameter | Grounded value | Source |
|---|---|---|
transformer tapStepPu |
~0.0125 (1.0–1.25% nominal) | SCADA-recovered DataSources/Derived/tap_changers/tap_changers.parquet step_pct (0.46% observed) |
transformer minTap/maxTap |
±0.15 (≈31% span, −12…+4 ≈ 16 steps) | LTDS ltds_tap_span_pct (median 31%) + NetworkModel/normalized/<lic>_tx2.parquet tap positions |
| transformer emergency headroom | 1.58–2.0× nominal (short-term) | <lic>_tx2.parquet emergency_rating_mva/nominal_rating_mva (median 1.583) |
cable/line derateAtFullThermal |
0.11 (summer ≈ 0.89 × winter) | <lic>_circuits.parquet summer_rating_mva/winter_rating_mva (0.86–0.91; NPGN = 1.0) |
| cable-vs-OHL split | cable ≈ 6.5% of route-km (transmission) | NetworkModel/resolved/etys_circuits.parquet circuit_type + ohl_km/cable_km |
| line R/X/B + ratings + length | grounded per circuit | normalized LTDS <lic>_circuits.parquet (feeds transmission.json) |
Grounded — system context (validation, not per-asset params)
| Quantity | Grounded value | Source |
|---|---|---|
| GB system inertia | 101–338 GVA·s; typical ~150; synchronous floor 107.5 | Derived/inertia_reconstructed/…_validation.json, Derived/weather_inertia_coupling/…_validation.json |
| inertia ← synchronous GW | 7.45 GVA·s per GW synchronous (r²=0.87) | weather_inertia_coupling_validation.json |
| worst-case RoCoF | ~0.42 Hz/s @ 1800 MW at the inertia floor | inertia_reconstructed_validation.json |
| response-curve deviation grid | 0.2 / 0.5 / 0.8 Hz | NESO firm_frequency_response_ffr_post_tender_reports schema |
arrest-layer held volumes (SystemResponseService MW) |
DC ≈ 950–1000 MW, DM ≈ 500–550 MW, DR ≈ 480–500 MW each direction; legacy FFR ≈ 0.5 GW Primary @0.5 Hz (207 MW @0.2 Hz) | NESO EAC auction clears (enduring_auction_capability_eac_auction_results), DM/DR/DC requirement forecasts, FFR post-tender — all materialised. Delivery-curve shape (DC full @0.5 Hz, DM/DR full @0.2 Hz, 0.015 Hz deadband) is NESO published spec |
| reserve held | Positive Balancing Reserve ≈ 450 MW, Negative 1450 MW; Quick Reserve 300–500 MW | NESO balancing_reserve_…, quick_reserve_… forecasts |
| frequency validation data | 1 s (NESO), 10 Hz (EirGrid all-island) | Derived/frequency_all_srcs, EirGrid/frequency_10hz — materialised |
| GB phasor (per-node RoCoF + phase angle) | 4 nodes (london, buckingham, manchester, strathclyde), 100 ms free / 6 kHz tier | Gridradar/gb_frequency — schema-registered but not materialised (token-gated). NB: the framework is worded "5-node" in places — the real GB Gridradar network is 4 nodes; corrected. |
| PMU event signatures | forced-oscillation / ring-down, ~30 fps, 16 points | GESL/signatures — US data, not GB (physics/method validation only), and not materialised |
| per-domain inertia shares (sync-vs-converter split) | thermal 98.6% / hydro 1.4% / inverter 0% of spinning inertia; converters ≈ 57% of online MW; LOS-fragmentation flag true ~9% | Derived/speed_domains/… (grounds the distributed multi-domain model; the H-constant table itself stays [VERIFY]) |
| sub-cycle RoCoF uplift (local > COI) | instantaneous RoCoF ≈ 1.16× typical, up to 1.35× the 1 s-averaged value | Derived/subcycle_period_features/… rocof_uplift_ratio (reconstruction-based, not PMU-measured) |
| inter-domain propagation τ | ~5–8 ms/corridor (wave speed 500–1500 km/s) | Derived/propagation_delays/… — synthetic (is_synthetic_speed=True, literature band); τ stays [VERIFY] |
| BSP transformer power factor | ≈ 0.95 mean / 0.98 median (so MVA ≈ MW at most BSPs) | Derived/bsp_power_factor_summary/… |
Grounded — synchronous plant (Elexon per-BMU dynamic parameters)
The Elexon dynamic-parameter hives (DataSources/Elexon/Parquet/{rure,rdre,sel,mels,mzt,mnzt,ndz}/…,
git-ignored but materialised) carry the real per-unit dispatch primitives, joined to fuel via
Reference/bmunits_all.json. These ground a future synchronous-machine asset class (deferred — a
machine trip must drop E live, plan risk 1), not the inverter classes:
| Parameter | Grounded value (per fuel) | Note |
|---|---|---|
run-up ramp (rure rate3) |
CCGT ≈ 15 MW/min, pumped-storage ≈ unconstrained | WIND / NUCLEAR / interconnectors submit no run-up rate — not run-up-dispatchable |
run-down ramp (rdre) |
CCGT ≈ 15–25 MW/min | — |
headroom (MELS−SEL)/MELS |
CCGT ≈ 0.40, nuclear ≈ 0.03 | grounds a synchronous headroom; inverter headroom stays [VERIFY] |
| min run / min off / notice | CCGT ≈ 6 h / 6 h / 70 min; PS 30 / 15 / 2 min | grounds unit-commitment constraints |
Consequence for the inverter classes: dispatchRampMwPerMin for wind/solar is correctly a system-level
proxy (DerivedFromRecorded from ramp_correlation), because those technologies do not submit a
per-unit run-up rate at all — they track weather / curtail rather than ramp on command.
Grounded — recorded event targets (validation anchors)
The GDA lake's post-event replay reports (reports/…) give the real numbers the asset-fleet back-test
must reproduce (AssetValidation.Compare). The anchor is 2019-08-09:
| Quantity | Recorded value | Source |
|---|---|---|
| pre-event frequency | 49.992 Hz | reports/rocof_events-20190809T155233-0386/report.json |
| nadir | 48.787 Hz @ 15:53:49Z | same |
| peak |RoCoF| | −0.151 Hz/s (1 s window) | same |
| infeed loss ΔP | 1618 MW (detector est.; real-world ≈1878 MW = 800 Hornsea + 640 Little Barford + ≈430 embedded) | co-located infeed_loss-… |
| inertia at event | NESO Outturn 215 GVA·s (swing-equation estimate 267.8) | same |
| LFDD | armed at the 48.787 Hz nadir (no MW disconnected recorded) | same |
Gap: the report records only the aggregate loss — no per-asset (Hornsea/Little Barford/embedded) breakdown and no LFDD MW. Those must come from the ESO Technical Report, not GDA. So the embedded-gen trip volume (the cascade's headline) stays externally-sourced / swept.
Blind-predict set (freeze params on the anchor, predict these): cleanest is 2026-05-31, 992 MW →
49.806 Hz nadir (reports/infeed_loss-20260531T180031-31869). Loss-magnitude-only (no frequency
trajectory): 601 MW (IC trip 2026-06-26), 1014 / 798 / 514 MW (2026-07-03). The 2024-08-14 "19.7 GW"
record is a detector artefact — reject.
Grounded — protections (device operation from the GDA event-detector layer)
The protections layer (ch. 15) grounds its frequency-domain thresholds in the pre-detected, graded
gda-events/1 event streams:
| Protection | Grounded value | Source |
|---|---|---|
| RoCoF / Loss-of-Mains grades | 0.0625 / 0.125 / 0.25 / 0.5 Hz/s (+ 1 s & 3 s streams); modern ALoMCP 1.0 Hz/s + 500 ms delay | Events/rocof_events (794 events), Random/detect_rocof_events.py |
| LFDD first stage | 48.8 Hz (Recorded) + 632 MW coincident block, 2019-08-09 | Events/lfdd_risk, Random/find_lfdd_events.py |
| under/over-frequency | statutory 49.5 / 50.5 Hz | FrequencyLimits; GDA lfdd_risk stages |
| loss-of-infeed / interconnector trip | MW + nadir + RoCoF + recovery per event | Events/infeed_loss (8,288), Events/interconnector_trips (755) |
Protections that stay [VERIFY] (no operational data exists): recloser / auto-reclose / breaker
operation (only distribution customer-outage counts, no device data), under/over-voltage (no measured GB
voltage series), thermal / reactive overload, and fault level / short-circuit MVA (confirmed absent). These
are generic settings; the topology recloser's mechanism is modelled fully, but its settings are assumed.
Stays [VERIFY] / swept — genuinely not in the lake
- All inverter internal control loops: droop/df·dt gains, detection/compute/actuate latencies, PLL & current-loop time constants, fast-slew MW/s, LVRT/FRT — vendor-proprietary, absent everywhere.
- BESS
capacityMwh/ storage duration — confirmed absent from REPD, TEC, DUKES and the BMU register (no MWh/hours/energy column anywhere). Must be assumed as a C-rate × MW. MW sizing is grounded (REPD operational batteries: 171 sites, 4,755 MW, median ~23 MW); the duration is not. - The legacy-vs-upgraded DG relay fraction — the single highest-leverage knob for the RoCoF-trip
cascade. The lake encodes the relay thresholds (
manual/54) but no register of how much embedded DG was upgraded under ALoMCP. This is exactly why the deliverable for any real-fleet claim is a parameter-sweep envelope over this fraction (AssetEnvelope), not a point prediction — if the band brackets cascade/no-cascade, that is the honest finding. - OLTC mechanical delay (seconds/tap) and transformer/cable thermal time constants (minutes) — no
tap-position/time channel and no temperature series exist (confirmed in
DataSources/UkPowerNetworks/Processors/detect_tap_changers.py). Grounded ratings give steady-state headroom only, not the time constant. - Fault level / short-circuit MVA (grid stiffness) — no fault-level product exists in the lake (no
normalized/resolved fault tables). The local-stiffness / effective-local-inertia proxy stays
[VERIFY]. - Transformer MW/MVAr loading — no
transformer_flowsproduct; only a BSP power-factor summary (≈0.95, so MVA ≈ MW). Real per-transformer thermal duty stays[VERIFY]. - Inter-domain propagation τ / wave speed —
Derived/propagation_delaysis flagged synthetic (is_synthetic_speed=True, literature 500–1500 km/s band), not a GB measurement.
Known modelling limitations (honest caveats)
- Vector-shift trip is a
|Δf|proxy, not a true phase-jump detector. Phase is smoothly integrated (phaseDeg += 360·(f−f0)·dt), so the "vector-shift" trip effectively fires on sustained frequency offset, not on a discrete loss-of-mains angle step (no discrete angle event is modelled).vectorShiftTripDegtherefore does not carry a real relay's setting meaning — treat it as a proxy. - OLTC tap direction is convention-dependent.
TransformerDynamicsassumes loweringTapRatiolowers the controlled-bus voltage; whether that holds depends on the power-flow solver's tap convention (primary/secondary vs secondary/primary). Verify against the solver before wiring the passive fleet into the live tap loop (PassivePlantFleet.ApplyTois a pure helper, not yet in the per-tick solve).
localRocofUpliftFactor — grounded and wired
The sub-cycle data grounds that local RoCoF ≈ 1.16× (up to 1.35×) the 1 s COI RoCoF. This is now a
parameter (AssetParams.LocalRocofUpliftFactor, default 1.0 so the reduction gate and all existing
tests are unchanged) that multiplies the RoCoF the LoM relay acts on — and only the relay, since the
slower FFR response effectively sees the averaged value. The GDA emitter sets it to 1.16
(DerivedFromRecorded) on every inverter class, so a real-fleet run trips on the realistic local RoCoF
rather than the COI average. Suite-pinned (InverterTripCascadeTests.Local_rocof_uplift_...).
Validation — the 2019-08-09 cascade: what is real vs calibrated (read this carefully)
The framework reproduces the 9 Aug 2019 cascade mechanism from first principles: fed only the primary Hornsea + Little Barford losses at the recorded 215 GVA·s, a legacy pre-ALoMCP DG fleet (0.125 Hz/s, sub-cycle uplift) crosses its RoCoF threshold and trips on its own protection, unprompted — the timing and triggering are emergent physics.
But the depth is NOT predicted, and the close agreement you may see is not independent validation. Measured honestly (single-bus lumped model — network topology is not used here):
| Path | Nadir | Why |
|---|---|---|
| Recorded (Ofgem/GDA) | 48.787 Hz | — |
| Scripted replay (Ofgem 9-step + recorded LFDD) | 48.82 Hz | it is the report's loss sequence fed back in — replay, not prediction |
| Dynamic fleet, 500 MW embedded | 48.85 Hz | |
| Dynamic fleet, 1290 MW embedded | 48.23 Hz | the nadir swings 2.7 Hz across plausible fleet sizes |
| Dynamic fleet, 2500 MW embedded | 47.29 Hz | |
| Dynamic fleet, 4000 MW embedded | 46.12 Hz |
The embedded volume that trips is [VERIFY]/swept (not per-unit recorded), and the nadir is a strong
function of it. So the honest claim is the envelope one: the recorded 48.787 Hz lies within the band
the fleet spans (≈47.3–48.85), which brackets — but does not independently predict — reality. The
agreement of the scripted path is replay of recorded inputs; the dynamic path is calibration-
sensitive. This is a mechanism + envelope result, tagged UnvalidatedAtScale. Suite-pinned
(Asset2019EventTests), which asserts the mechanism and the bracketing band, not a nadir match — the
genuine test of predictive power is a blind cross-event prediction (e.g. the held-out 2026-05-31 event),
which no parameter set has yet been shown to pass.
Method / safety
Mined under the GDA hardware-fragility rules: no recursive lake scans; files located via git ls-files
and one-level listing; data read one file at a time (normalized network parquets and derived-analysis
JSONs are materialized; the large raw timeseries hives are not on this checkout, so system-context values
come from the derived validation JSONs, which carry real computed values). See also
docs/technical/05-frequency-dynamics.md (the pAssetFleet term) and docs/manual/18-extending-gridsim.md.