Waterschap Brabantse Delta · R&D-lab · uitleg
valve is de digitale twin én besturingsmodule voor één regelklep of
afsluiter. Uit de klepstand (opening %) voorspelt hij via een leverancierscurve
de klepcapaciteit Kv, en berekent daaruit met een hydraulisch model de drukval
Δp over de klep bij de actuele — gemeten of voorspelde — flow. Het model is bewust
één-richting: flow is een input, wordt niet samen met de klepstand opgelost —
vandaar een Δp-plafond (100 bar) tegen blow-up bij een bijna-dichte klep. De node is
event-driven: hij rekent op state- en measurement-events, niet op een vaste tick.
Deze pagina volgt letterlijk wat de code doet aan de hand van één voorbeeld en een paar
interactieve figuren die de kernfuncties getrouw naspelen.
RnD/EVOLV, submodule valve
@ 14ef7a4c8712 (peildatum 2026-07-17, gelijk aan origin/main;
zie verantwoording onderaan).docs/research/) en op het
EVOLV-spoor in HELIX.valve is een S88-Equipment Module (lane L3, kleur
#86bbdd; nodes/valve/CLAUDE.md:14-16;
src/specificClass.js:3-6). De kern is één functie: opening % →
Kv via de curve → Δp bij de actuele flow
(src/measurement/measurementRouter.js:107-124). Bijzonder aan deze node is de
dubbele familierol: als child registreert hij zich bij startup via de Port-2
child.register-handshake bij een groepscontroller
(valveGroupControl, machineGroupControl of
pumpingStation); als parent is hij zélf eigenaar van upstream-bronnen
(pomp/pompgroep) — niet voor telemetrie, maar voor fluid-contract-bewaking (gas vs.
vloeistof), waarvoor registerChild is overschreven zodat registratie in
FluidCompatibility landt i.p.v. de standaard ChildRouter
(src/specificClass.js:97-100).
De node is event-driven — static tickInterval = null: state- en
measurement-events triggeren de hercompute, alleen de status-badge wordt elke 1000 ms
gepolld (src/nodeClass.js:10-11). Output verschijnt op het domein-event
'output-changed' via notifyOutputChanged()
(BaseNodeAdapter.js:134-154; measurementRouter.js:104,123).
Rode draad door de hele pagina: een BL2BA-RIG-klep
(as-installed rig-curve, echte catalogusdata; klep⊕leiding, DN 50, dichtheid
ρ = 997 kg/m³). Eén commando beweegt de klep naar opening
58,76 %; bij een flow Q = 10 m³/h vloeistof volgt
Δp ≈ 1,497 bar. Alle getallen in de rode draad zijn met node
tegen het echte curvebestand (BL2BA-RIG.json) en de echte
ValveHydraulicModel doorgerekend; illustratieve aannames zijn expliciet zo
gelabeld.
Het I/O-contract in één oogopslag: kies een verb, stel de velden in,
kopieer het exacte injecteerbare msg, en klik Injecteer ▸ om te zien wat
er uit de drie poorten komt — met live doorgerekende Kv en Δp op de
BL2BA-RIG-curve. Elke bewering draagt een pad:regel-chip. Poortlabels
["process","dbase","parent"].
["process","dbase","parent"],
valve.html:55-57). Port 0 is delta-gecomprimeerd: alleen
gewijzigde velden gaan mee (outputUtils.js:17-41). Output-units: mbar,
m³/h, °C.| Poort | Label | Belangrijkste keys |
|---|---|---|
| 0 | process |
Delta-gecomprimeerde snapshot (src/io/output.js:20-36):
dynamische measurement-keys <position>_<variant>_<type>
voor elke gevulde meetreeks (o.a. delta_predicted_pressure,
downstream_measured_flow, downstream_predicted_flow);
scalars state, percentageOpen, moveTimeleft,
mode. Alléén na een curve-commando ook de synchrone reply
{topic:'Showing curve', payload:{model, serviceType, expectedServiceType,
gasChokedRatioLimit, selectedDensity, selectedDiameter, curve, hydraulics}}
(specificClass.js:183-192). |
| 1 | dbase |
Zelfde getOutput()-velden via de influxdb-formatter
(default; ook frost/json/csv). Tags =
geflatteerde config-subset: id, softwareType, role, positionVsParent, uuid,
tagcode, geoLocation_*, category, type, model, unit (null/leeg gefilterd;
outputUtils.js:87-133). |
| 2 | parent |
Eenmalig, 100 ms na start: {topic:'child.register', payload:node.id,
positionVsParent, distance} (default 'atEquipment') naar de
ouder (BaseNodeAdapter.js:117-132). |
deltaPChange (mbar) bij elke eindige
Δp-herberekening — geconsumeerd door valveGroupControl voor de groeps-max-Δp
(measurementRouter.js:100-101) — plus fluidCompatibilityChange/
fluidContractChange en de state-events positionChange,
stateChange, movementComplete, movementAborted.De klep is tegelijk child (van een
groepscontroller, boven) én parent (van upstream-bronnen, onder). Registratie omhoog
en telemetrie lopen via draden; de deltaPChange naar de VGC is een apart
in-process event. Upstream-bronnen registreren naar boven, in de klep — puur
voor het fluid-contract (gas vs. vloeistof), niet voor telemetrie.
Het fluid-contract van elk kind komt uit
getFluidContract() → direct serviceType-veld → default per
softwareType (machine/rotatingmachine/machinegroup/pumpingstation ⇒ liquid).
Statussen: pending/unknown/match/inferred/mismatch/conflict; mismatch of conflict kleurt de
status-badge geel-ring met een ⚠-melding
(src/fluid/fluidCompatibility.js:4-10,92-137; io/output.js:62-65).
Klik een stap in de lijst (of gebruik ◀ ▶). Boven zie je waar in de pijplijn je bent;
rechts wat er gebeurt, de waarde van het rode-draadvoorbeeld op dat punt (met
node tegen BL2BA-RIG.json en de echte
ValveHydraulicModel doorgerekend), en het codepad.
Boven: de as-installed effectieve Kv(opening %) van de rig-klep — de 12 echte
catalogus-punten met de monotone-cubic-spline die de node gebruikt (de kale klep
BL2BA DN 25 staat als context op de rechter as: veel hogere Kv,
want zonder leidingverlies). Onder: de Δp bij een flow Q, doorgerekend met beide
hydraulische modellen zodat de service-type-gotcha zichtbaar wordt. Schuif de klepstand en
Q, en wissel het service-type — let op hoe ver de gas- en vloeistoflijn uit elkaar liggen,
en hoe bij bijna-dichte klep de choked-cap (gas) en het 100-bar-plafond
(vloeistof) inzetten.
Kv = Q/√(Δp/SG)) leverde een
serieweerstand-fit 1/Kv_eff² = 1/Kv_klep² + 1/Kv_loop² met een vaste
loop-restrictie Kv_loop ≈ 10.3. Daarom plafonneert de
effectieve Kv rond 10,21 terwijl de kale DN 25 tot 60 loopt
(catalog/valve.json:242-246; docs/research/README.md:14-29).normalizeServiceType geeft 'liquid' alléén
bij exact 'liquid', anders 'gas'
(hydraulicModel.js:29-35). En serviceType (net als
fluidDensity, valveDiameter, gasChokedRatioLimit)
staat niet in de editor-defaults van valve.html:18-51 — wél
geconsumeerd in nodeClass.js:21-32,42. Gevolg: een uit de editor
geconfigureerde klep draait feitelijk altijd het gas-model met
ρn = 1.293, ook voor water. aanname:
mogelijk achterstallig — het schema-veld valveDiameter bestaat wél
(configs/valve.json:205-212).(Q/Kv)²·SG terwijl een upstream node flow blijft
opleggen — daarom een absoluut plafond maxDeltaPBar (default 100 bar,
ver boven elke afvalwaterdienst): warn + clampedToMax:true. Een bewuste
pleister, geen fysica (hydraulicModel.js:20-27,79-99).gasChokedRatioLimit × p2_abs (default ratio 0.7 → choke-onset bij
Δp/p1 ≈ 0.41, conservatief t.o.v. xT≈0.5). Houdt de
Samson-relatie binnen haar subkritieke geldigheid
(hydraulicModel.js:123-128).predictKvForPosition geeft Math.max(0, kv) — de
eerdere 0.1-vloer fabriceerde een permanente lek zodat de twin nooit een gesloten
klep toonde. Bij kv≤0 (of flow=0, of niet-eindig) geeft het Δp-model null:
geen update (supplierCurve.js:113-128; hydraulicModel.js:63-65).null, dan blijft de laatst geschreven
pressure.predicted.delta in de meetcontainer staan; de delta-compressie op
Port 0 verstuurt hem niet opnieuw. Of downstream hiermee rekent is
niet geverifieerd (hydraulicModel.js:63-65;
measurementRouter.js:94).maintenance heeft géén allowedSources-entry
en weigert dus alle bronnen — maar er is geen maintenance-sequence of -state; de
mode blokkeert alleen commandobronnen (flowController.js:13-16;
CONTRACT.md:76-87).De state-machine komt uit de gedeelde state-klasse
(generalFunctions/src/state/state.js). Toestanden: idle, starting,
warmingup, operational, accelerating, decelerating, stopping, coolingdown, off,
maintenance (+ transient emergencystop). De klep start direct in
operational (src/specificClass.js:48). "Operationeel" voor
de Δp-hercompute = operational | accelerating | decelerating — alleen dán
herberekent updatePositionDependent (measurementRouter.js:110).
Sequences (config r.304-360): startup = starting→warmingup→operational;
shutdown = stopping→coolingdown→idle (rijdt bij operational eerst
naar stand 0, flowController.js:57-60); emergencystop =
emergencystop→off. Beweging loopt in [0, 100] % met staticspeed
(lineair) of dynspeed (default; ease-in/out), snelheid in %/s van de volle
slag; elke bewegingstick emit positionChange
(state/movementManager.js). Modes (los van states) met bron-gating:
auto (default; parent/GUI/fysical), virtualControl (GUI/fysical),
fysicalControl (fysical), maintenance (alle bronnen geweigerd).
valve.html:18-51). Volledige
defaults/enums: nodes/generalFunctions/src/configs/valve.json.| Veld | Default | Betekenis |
|---|---|---|
name | "" | wordt msg.topic / measurement-naam (fallback <softwareType>_<id>). |
speed | 1 (required) | "Reaction Speed", %/s van de volle slag. |
model | null | Verplicht bij startup: bepaalt de curve via assetResolver.resolve('curves', model). Klepmodellen met curve: ECDV, BL2BA, BL2BA-RIG. |
processOutputFormat / dbaseOutputFormat | process / influxdb | Port-0- resp. Port-1-formaat (process/json/csv resp. influxdb/frost/json/csv). |
unit | "" | Ongeldige flow-unit valt terug op m3/h (nodeClass.js:63-72). |
serviceType, fluidDensity, valveDiameter, gasChokedRatioLimit, fasetijden | — (editor-gat) | ⚠ geconsumeerd in nodeClass.js:21-32,42 maar niet in de editor-defaults → niet instelbaar via de editor, vallen altijd terug op defaults (serviceType → gas; diameter → nearest-125). Legacy supplier/category/assetType op een opgeslagen node → harde deploy-error (nodeClass.js:49-61). |
Alle punten zijn code-observaties d.d. 2026-07-17 (statisch, geen
runtime-verificatie); elk draagt een pad:regel. De submodule valve
stond op peildatum op 14ef7a4c8712, gelijk aan origin/main (na
git fetch); er zijn geen open fix-branches voor deze node aangetroffen.
serviceType,
fluidDensity, fluidTemperatureK,
gasChokedRatioLimit, valveDiameter en de fasetijden worden
geconsumeerd (nodeClass.js:21-32,42) maar staan niet in
valve.html:18-51. Omdat normalizeServiceType alléén bij exact
'liquid' liquid teruggeeft (hydraulicModel.js:29-35), draait
een editor-geconfigureerde klep feitelijk altijd het gas-model met
ρn = 1.293. aanname: of dit bewust is,
is onzeker.hydraulicModel.js:20-27).null,
hydraulicModel.js:63-65); de laatst geschreven
pressure.predicted.delta blijft in de meetcontainer staan en wordt door de
delta-compressie niet opnieuw geëmit. aanname: onzeker of
downstream hiermee rekent.updateFlow(predicted) leest
downstream-druk uit pressure.measured.downstream, terwijl
updatePressure(predicted) uit pressure.predicted.downstream
leest (measurementRouter.js:64 vs :36).
aanname: mogelijk onbedoeld.maintenance blokkeert alleen
commandobronnen; er bestaat geen maintenance-sequence (CONTRACT.md:76-87).Math.max(0, kv); de eerdere 0.1-vloer
fabriceerde een permanente lek (supplierCurve.js:113-128).child.register — het msg.topic-pad is expliciet
transitioneel tot de platformbrede registratiemigratie
(commands/index.js:72-75).Valve._pendingExtras tussen nodeClass en
constructor werkt, maar is niet herentrant bij gelijktijdige constructie
(nodeClass.js:18; specificClass.js:27,32-35).monotone_cubic_spline in
generalFunctions/src/predict/interpolation.js valt terug op
averaged-tangent cubic Hermite (de Fritsch-Carlson-limiter is gegate op
method=="fritschcarlson", r.312, terwijl het type-string
"monotone_cubic_spline" is). Voor de monotoon-stijgende, gladde
BL2BA-RIG-curve is er geen overshoot; de figuur hierboven is de exacte node-uitkomst
(node-geverifieerd op alle 12 tabelpunten én tussenpunten).
aanname: de gate is mogelijk onbedoeld.valve.html:164-168 is generiek
("Controls the flow of data through a valve-like mechanism").https://lab.wbd-rd.nl/rnd-lab/projects/evolv-valve.nodes/valve/docs/research/valve-kv-characterization.html en
docs/research/README.md (RnD/valve).nodes/valve/CONTRACT.md en de curve-catalogus onder
nodes/generalFunctions/datasets/assetData/curves/.RnD/EVOLV (super-repo 74c4089, 2026-07-03) — submodule
valve geanalyseerd @ 14ef7a4c8712, plus het feitendossier van
deze analyse. Analysedatum 2026-07-17.git fetch
gedraaid: de submodule-tip 14ef7a4c8712 is gelijk aan origin/main;
er zijn geen open fix-branches voor deze node.pad:regel-verwijzing. De interactieve figuren en de console
zijn getrouwe herimplementaties, vooraf met node tegen het echte curvebestand
BL2BA-RIG.json en de echte ValveHydraulicModel doorgerekend
(testgevallen als commentaar in de pagina-JS); illustratieve aannames zijn expliciet zo
gelabeld.