Files
pumpingStation/wiki/modes/levelbased.md
2026-05-05 10:38:24 +02:00

5.2 KiB
Raw Blame History

title, mode, status, updated
title mode status updated
Level-based mode levelbased implemented 2026-04-22

Level-based mode

The simplest and most widely deployed control strategy. Demand is a direct, static piecewise-linear function of basin level — no feedback loop, no predictions beyond the level measurement itself. This page uses the shared basin model; see modes/README.md for the template other mode pages follow.

At a glance

Item Value
Signal driving demand basin level (measured, predicted fallback)
Output demand 0100 % forwarded to every MGC child
Thresholds adjusted at runtime? No — static from editor config
Use when Inflow is sewer-gravity (no smart metering) and operator wants a predictable, inspectable response

Diagram

Level-linear basin mode — demand vs level transfer function

Editable source: ../diagrams/modes/basin-mode-level-linear.drawio.svg (drag into draw.io — it round-trips).

Inputs

Signal Where from Role
current level measurement child (measured) → predicted from volume integrator (fallback) X-axis of the transfer function
config.control.levelbased.minLevel editor, static below → pumps hard OFF
config.control.levelbased.startLevel editor, static where demand-ramp starts
config.control.levelbased.maxLevel editor, static where demand saturates at 100 %

The three control thresholds are the only mode-specific configuration. Nothing here is recomputed at runtime.

Threshold policy

Threshold Source Adjustable at runtime?
minLevel config.control.levelbased.minLevel No
startLevel config.control.levelbased.startLevel No
maxLevel config.control.levelbased.maxLevel No

That this policy is trivial (all static) is the defining simplicity of this mode. Modes like powerBased or future weather-aware variants will recompute these thresholds on the fly.

Demand formula

if level < minLevel:
    demand = 0
    MGC → turnOffAllMachines()      # explicit shutdown, not just "0 %"
elif level < startLevel:
    demand = <previous demand>      # dead zone — hold last command (hysteresis)
elif level <= maxLevel:
    demand = lerp(level, [startLevel, maxLevel], [0 %, 100 %])
else:
    demand = 100 %                  # saturated; MGC clamps internally if overshoot

Where lerp is linear interpolation. The MGC is free to distribute the demand across its pumps however its own policy dictates (equal split, lead-lag, staging — that's the MGC's business).

Edge cases

  • Cold start with level in the dead zone. demand has no prior value; it defaults to 0. Pumps stay OFF until the level first crosses startLevel upward. Once it does, normal ramp-and-hold behaviour engages.
  • Level sensor drops out mid-run. _selectBestNetFlow falls back to predicted level (computed from the volume integrator) — the mode doesn't care which variant wins, it just reads the chosen level.
  • Both sensor and predictor unavailable. The mode's preconditions fail; _controlLogic logs a warning and exits without issuing a command. The last-known demand is held, which is safe.
  • Level crosses maxLevel upward. Demand saturates at 100 %. Level may still continue rising if inflow > station capacity — this is the scenario that trips the overflow-safety layer (see below).
  • Level crosses dryRunLevel downward. The safety layer (not this mode) force-shuts all downstream pumps regardless of what demand the mode is commanding. The mode's demand is effectively overridden until level climbs back above dryRunLevel + hysteresis_margin.
  • Level crosses overflowLevel upward. The safety layer logs the spill event and raises an alarm. The mode continues commanding at 100 % — which is what you want, because the pumps should keep draining as fast as physically possible. (See functional description § Safety controller for the gravity-sewer caveat.)

Why this is worth migrating off of

Level-based is fine for steady-state sewer inflows. It has two known weaknesses:

  1. Predictable, not proactive. It can't pre-empty the basin ahead of a forecasted storm or a power-price peak. Modes like weather-aware or powerBased can — by moving startLevel down or up at runtime.
  2. Thresholds assume pump capacity is fixed. If you add or remove pumps, the startLevel ↔ maxLevel band that gave smooth 0-100 % coverage no longer matches the new capacity. Flow-based and percentage-based modes are less brittle to capacity changes because they close the loop on what you actually measure (outflow or fill %) rather than what you assume the level→capacity map is.
  • Functional description — basin model, net-flow selection, safety layer (shared across all modes)
  • modes/README.md — mode index + template
  • Other mode pages: to be written (flowbased.md, pressurebased.md, percentagebased.md, powerbased.md, hybrid.md, manual.md)