User manual — chapter list

Frequency studies

Three tools look at frequency over time: the freq verb (statistics and limit checks on a recorded NESO frequency CSV), the transient verb (a headless time-domain run at a fine time-step, with an optional infeed trip), and the live frequency simulation in the GUI (trip an infeed on the map and watch the RoCoF and nadir play out). The console replay verb plays a frequency CSV back interactively.

freq - score a recorded frequency trace

dotnet run --project src/GridSim.Cli freq [<csv>]

<csv> defaults to data/neso/frequency-sample.csv next to the built binaries. A missing file exits 1.

The output has three parts:

  1. Statistics - sample count (1 s cadence), min/mean/max frequency, and the maximum |RoCoF| with its timestamp.
  2. vs GB limits - whether the trace exceeded 0.125 Hz/s RoCoF, how many seconds it spent below the 49.8 Hz operational and 49.5 Hz statutory floors, and whether it reached the 48.8 Hz LFDD threshold.
  3. Upsample demo - the first seconds expanded from 1 s frames to 20 ms by RoCoF interpolation, showing the per-slice values the replay tools use.

transient - a demanding time-domain run

dotnet run --project src/GridSim.Cli transient <case|--cases a,b,c|--cases suite>
    [--minutes 60] [--dt-ms 1] [--trip <MW>] [--trip-at <s>] [--trip-window 2]
    [--log-every 1] [--export-every 0] [--export-jac] [--solver auto] [--out <dir>]
Flag Default Meaning
<case> case9 one case; or --cases with a comma list, or suite/all for the built-in batch (case9...case300 + a PEGASE file)
--minutes 60 simulated duration (--duration is an alias)
--dt-ms 1.0 slice length in milliseconds
--trip 0 (off) MW of infeed to trip during the run
--trip-at 0 trip time in seconds; must fall inside the run or the verb aborts with exit 2 rather than "succeed" with no event
--trip-window 2.0 seconds around the trip in which every slice is logged and exported
--log-every 1 write every Nth slice to the CSV (the first, last and trip-window slices are always written)
--export-every 0 (off) write a full solve-math export every Nth slice
--export-jac off include the (large) Jacobian in those exports
--solver auto dense, sparse, or bfs to force an engine
--out results/transient-<case>-<stamp> in the current directory run directory (batch runs get one subdirectory per case)

Each slice warm-starts a power-flow solve and integrates the swing-equation frequency, so a 60-minute run at 1 ms is 3.6 million solves - expect it to take a while and watch the progress line on stderr.

Per-slice output goes to timeseries.csv in the run directory, with columns:

tick,t_seconds,freq_hz,rocof_hz_s,gen_mw,demand_mw,iters,max_mismatch,vmin_pu,vmax_pu,solve_ms,converged

The run directory also contains run-metadata.json (commit, backend, host, the full run description), exports/slice-*.json (full solve-math exports: always slice 1, every slice in the trip window, and every --export-everyth slice), and summary.md with the headline results: frequency nadir and when, maximum |RoCoF| and when, non-convergence count (and the first offending slice), and how many exports were written.

Exit codes: 0 on success; 2 if --trip-at falls past the end of the run; 1 if no case in a batch could be loaded.

A transient run directory is a valid replay source for the desktop app - load it with LOAD RUN... and scrub through it (see the desktop app).

Note: --inertia-model distributed makes transient report the speed- domain split, but the per-slice integration remains the lumped scalar model. Only trip integrates the distributed model.

replay - play a frequency CSV in the console

dotnet run --project src/GridSim.Cli replay [<csv>] [--sps 50] [--seconds 600] [--frames N]
Flag Default Meaning
<csv> data/neso/frequency-sample.csv the trace to play (1 s cadence, upsampled to 20 ms)
--sps 50 slices per second (50 = real time)
--seconds 600 how much of the source to load
--frames 0 > 0 runs headless: print N slices and exit

Interactive keys: space = play/pause, up/down = speed, <-/-> = step while paused, Home = restart, Q/Esc = quit. The gauge colours by deviation from 50 Hz. Use it to eyeball a trip --export trajectory or any NESO-format CSV.

The live frequency simulation in the GUI

The desktop app integrates frequency continuously while the live sim runs: every tick, the imbalance between generation and demand drives the swing-equation integrator, and the frequency and RoCoF read-outs on the HUD, OPERATOR, SCADA, NESO RP1 and MECHANICAL tabs all follow it.

To run a frequency event by hand:

  1. Load a case and let the sim run (see the desktop app).
  2. Pick a fine time-step in the transport bar's STEP picker. Choices run from 1 ms to 20 min; at 1-100 ms the transient plays out in slow motion, at the default 20 min you will only see the aftermath.
  3. Right-click a bus on the NETWORK map. The largest generator dispatched there trips: the lost MW is injected into the live integrator as an infeed deficit and the deficit recovers over roughly five minutes of simulated time as reserve and redispatch pick it up. Repeated trips accumulate.
  4. Watch the frequency fall: the initial slope is the RoCoF, the turning point the nadir. The event log carries the headline figures (TRIP <unit> (<MW>) RoCoF ... nadir ...), an alarm is raised, and SCADA raises its P2 frequency alarm if the excursion leaves 49.9-50.1 Hz.
  5. Open the GENERATION & INERTIA tab: the same trip also drives an analytical side-by-side - the baseline trajectory against the same event with the configured TSGB device, the baseline scored against the GB limits, and the device size that would secure the loss (RoCoF <= 0.125 Hz/s, nadir

    = 49.5 Hz). The tab's own trip button runs the identical comparison on the largest unit without touching the map.

The map right-click and the tab button share one code path, so either drives the same plot and read-outs. In bridge mode right-click instead offers on-demand what-if queries - see contingency analysis.

Honesty note: the live integrator is the lumped scalar swing model with a single system inertia; it is the same physics trip and replay-event use, not a network-resolved electromechanical simulation. Machine-by-machine rotor-angle stability is the stability verb's territory.

See also