STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
feedtwin.comps.regulator.Regulator Class Reference
Inheritance diagram for feedtwin.comps.regulator.Regulator:
[legend]
Collaboration diagram for feedtwin.comps.regulator.Regulator:
[legend]

Public Member Functions

float commanded_setpoint (self, FlowConditions flow)
float supply_effect (self, FlowConditions flow)
float outlet_setpoint (self, float mdot, FlowConditions flow)
float lockup_pressure (self, FlowConditions|None flow=None)
float|None seat_capacity (self, FlowConditions flow, float xT=XT_TYPICAL)
float|None pinned_flow (self, float dp_available, FlowConditions flow)
dict[str, object] seat_model (self, float xT=XT_TYPICAL)
float pressure_drop (self, float mdot, FlowConditions flow)
float total_dp (self, float mdot, FlowConditions flow)
float|None flow_ceiling (self, FlowConditions flow)
bool is_choked (self, float dp_available, FlowConditions flow)
bool is_saturated (self, float mdot, FlowConditions flow)
dict[str, float] diagnostics (self, float mdot, FlowConditions flow)
list[Violation] check (self)
list[Violation] envelope_violations (self, float mdot, FlowConditions flow)
Public Member Functions inherited from feedtwin.comps.base.HydraulicComponent
None __init__ (self, ComponentInstance instance)
str id (self)
str type (self)
float static_head (self, FlowConditions flow)
float signal (self, FlowConditions flow, str name, float default=1.0)
bool isolates (self, Mapping[str, float]|None signals=None)
int n_residuals (self)
Sequence[float] residuals (self, EvalContext ctx)
Mapping[str, float] outputs (self, EvalContext ctx)
FlowConditions conditions (self, PortState port, Mapping[str, float] signals)
str __repr__ (self)

Protected Member Functions

GasCv|None _gas_seat (self, FlowConditions flow)
float _seat_dp (self, float magnitude, FlowConditions flow)
float _creep (self, float magnitude)
float _rated_multiple (self, float mdot)

Additional Inherited Members

Public Attributes inherited from feedtwin.comps.base.HydraulicComponent
 instance = instance
 p = instance.si_params()
 opt = dict(instance.options)
Static Public Attributes inherited from feedtwin.comps.base.HydraulicComponent
str inlet_port = "inlet"
str outlet_port = "outlet"
bool symmetric = False
 conditions_provider = None

Detailed Description

A pressure regulator holding an outlet setpoint.

The outlet it defends is

.. code-block:: text

    p_set  -  S . p_in                     supply-pressure effect, p_in gauge
           -  D . (|mdot| / mdot_rated)    flow droop

clamped by two physical limits: it can never raise pressure, and it can
never pass more than a wide-open seat allows.

Both coefficients default to zero with ``source = "default"``, so a
regulator declared without them behaves as an ideal one *and says so* in the
provenance report. That is deliberate: an unstated droop should look like a
missing measurement, not like a regulator that happens to be perfect.

Definition at line 174 of file regulator.py.

Member Function Documentation

◆ _creep()

float feedtwin.comps.regulator.Regulator._creep ( self,
float magnitude )
protected
The part of the lockup rise still on the outlet at this flow [Pa].

All of it at zero flow (lockup), none once the flow has paid it back at
the droop's own rate (``rise . rated / droop``). Without the ramp the
rise stepped the branch at zero flow -- lockup there, the droop line
just above -- and a tank sitting between the setpoint and lockup, which
is where one held at lockup rests, had no root. No rise, no creep: a
regulator that declares none is exactly what it was.

Definition at line 370 of file regulator.py.

References p, and feedtwin.comps.base.HydraulicComponent.p.

Referenced by is_choked(), and pressure_drop().

◆ _gas_seat()

GasCv | None feedtwin.comps.regulator.Regulator._gas_seat ( self,
FlowConditions flow )
protected
The seat as IEC 60534-2-1 sees a gas, or None for the old law.

On only when the session sends :data:`SEAT_XT_SIGNAL` (the opt-in) and
the inlet is a gas. The drawing's own ``xT`` wins over the signal's.

Definition at line 248 of file regulator.py.

References p, feedtwin.comps.base.HydraulicComponent.p, feedtwin.comps.base.FlowConditions.signal(), feedtwin.comps.base.HydraulicComponent.signal(), fsw::config::T7Channel.signal, and fsw::t7::FakeT7Device::Options.signal.

Referenced by _seat_dp(), and pinned_flow().

◆ _rated_multiple()

float feedtwin.comps.regulator.Regulator._rated_multiple ( self,
float mdot )
protected
``|mdot| / rated_flow``: how far along the datasheet's droop line
this flow is (0 when the regulator has no droop scale).

Definition at line 490 of file regulator.py.

References p, and feedtwin.comps.base.HydraulicComponent.p.

Referenced by diagnostics(), and envelope_violations().

◆ _seat_dp()

float feedtwin.comps.regulator.Regulator._seat_dp ( self,
float magnitude,
FlowConditions flow )
protected
Drop the wide-open seat takes at ``magnitude`` [Pa].

Definition at line 260 of file regulator.py.

References feedtwin.comps.regulator._dynamic_head(), _gas_seat(), p, and feedtwin.comps.base.HydraulicComponent.p.

Referenced by is_saturated(), and pressure_drop().

◆ check()

list[Violation] feedtwin.comps.regulator.Regulator.check ( self)
Design limits this component's configuration breaks.

Configuration only -- nothing here depends on the operating point, so it
can be run the moment a network is loaded and long before it is solved.
Bend radius is the case that motivated it: a line bent tighter than its
tube allows is a fabrication problem, and finding out at the bender is
expensive.

Reimplemented from feedtwin.comps.base.HydraulicComponent.

Definition at line 496 of file regulator.py.

References feedtwin.comps.base.HydraulicComponent.instance.

◆ commanded_setpoint()

float feedtwin.comps.regulator.Regulator.commanded_setpoint ( self,
FlowConditions flow )
What this regulator has been told to hold [Pa], before any droop.

For a dome-loaded unit that is the dome pressure plus the regulator's
own bias; for anything else it is the setpoint as configured. The dome
pressure is read as a *signal* first, so a scenario or an operator can
move it during a run the way a hand on the control regulator does.

Definition at line 193 of file regulator.py.

References p, feedtwin.comps.base.HydraulicComponent.p, feedtwin.comps.base.FlowConditions.signal(), feedtwin.comps.base.HydraulicComponent.signal(), fsw::config::T7Channel.signal, and fsw::t7::FakeT7Device::Options.signal.

Referenced by diagnostics(), feedtwin.comps.regulator.CurveRegulator.outlet_setpoint(), feedtwin.comps.regulator.IdealRegulator.outlet_setpoint(), outlet_setpoint(), and feedtwin.comps.regulator.IdealRegulator.pressure_drop().

◆ diagnostics()

dict[str, float] feedtwin.comps.regulator.Regulator.diagnostics ( self,
float mdot,
FlowConditions flow )

◆ envelope_violations()

list[Violation] feedtwin.comps.regulator.Regulator.envelope_violations ( self,
float mdot,
FlowConditions flow )
Limits broken at *this* operating point, unlike :meth:`check`.

Separate because a regulator can be configured perfectly and still be
outside its envelope on a given run, and a solver wants to know which.

Definition at line 583 of file regulator.py.

References _rated_multiple(), _USBD_HandleTypeDef.id, anonymous_namespace{idle_e2e.cpp}::Check.id, check_t.id, feedtwin.comps.elements.OrificeISO5167.id, feedtwin.comps.gas.GasOrifice.id, feedtwin.comps.manifold.Manifold.id, id, is_saturated(), p, feedtwin.comps.base.HydraulicComponent.p, and feedtwin.comps.base.HydraulicComponent.pressure_drop().

◆ flow_ceiling()

float | None feedtwin.comps.regulator.Regulator.flow_ceiling ( self,
FlowConditions flow )
Zero: what a shut regulator passes.

Consulted by the solver only when :meth:`is_choked` says the regulator
has closed, so the constant is not a claim that a regulator never flows.

Reimplemented from feedtwin.comps.base.HydraulicComponent.

Definition at line 417 of file regulator.py.

◆ is_choked()

bool feedtwin.comps.regulator.Regulator.is_choked ( self,
float dp_available,
FlowConditions flow )
Whether the regulator has shut because downstream is already high.

A regulator is a one-way device. Turn the control regulator down below
what the tank is already sitting at and the dome reg simply closes --
it cannot pull the tank back down, and nothing flows until the tank is
vented or drained past the new setting. That is what happens on the
stand, and it is what makes "turn the knob down and watch" a question
the model can answer.

Without this the branch equation asks for a pressure drop larger than
the network has, which has no solution and diverges rather than
reporting a shut valve.

Reimplemented from feedtwin.comps.base.HydraulicComponent.

Definition at line 425 of file regulator.py.

References _creep(), and outlet_setpoint().

◆ is_saturated()

bool feedtwin.comps.regulator.Regulator.is_saturated ( self,
float mdot,
FlowConditions flow )
Whether the regulator has run out of authority at this operating point.

True means the outlet is being set by the seat rather than by the
setpoint -- the regulator is wide open and no longer regulating. Worth
surfacing loudly: the pressure it reports is still a real number, and it
is no longer the number anybody designed for.

Reimplemented in feedtwin.comps.regulator.IdealRegulator.

Definition at line 453 of file regulator.py.

References _seat_dp(), and outlet_setpoint().

Referenced by diagnostics(), and envelope_violations().

◆ lockup_pressure()

float feedtwin.comps.regulator.Regulator.lockup_pressure ( self,
FlowConditions | None flow = None )
Outlet at zero flow [Pa]: setpoint plus the seat's overshoot.

Real seats do not close at exactly the setpoint -- the outlet creeps up
until the poppet seals. It matters because lockup, not setpoint, is what
a downstream relief valve and a burst disc actually see between firings,
and on a dome-loaded unit it moves with the dome.

The base is the outlet the regulator holds at zero flow,
``outlet_setpoint(0)``, so it carries the supply-pressure effect: the
inlet pushing on the poppet does not stop when the flow does, and the
branch is continuous across zero flow. (Leaving it out stepped the
branch by the whole supply term at zero flow, and a tank inside that
step had no root.)

Definition at line 227 of file regulator.py.

References outlet_setpoint(), p, and feedtwin.comps.base.HydraulicComponent.p.

Referenced by pressure_drop(), and total_dp().

◆ outlet_setpoint()

float feedtwin.comps.regulator.Regulator.outlet_setpoint ( self,
float mdot,
FlowConditions flow )
The pressure this regulator is trying to hold right now [Pa].

Reimplemented in feedtwin.comps.regulator.CurveRegulator, and feedtwin.comps.regulator.IdealRegulator.

Definition at line 217 of file regulator.py.

References commanded_setpoint(), p, feedtwin.comps.base.HydraulicComponent.p, and supply_effect().

Referenced by diagnostics(), is_choked(), is_saturated(), lockup_pressure(), pinned_flow(), and pressure_drop().

◆ pinned_flow()

float | None feedtwin.comps.regulator.Regulator.pinned_flow ( self,
float dp_available,
FlowConditions flow )
The choked flow, when the compressible seat is wide open and choked.

Wide open: the downstream is below what the regulator would hold even at
that flow, ``p_in - target(W_c)``. Choked: the drop ratio is past
``F_gamma xT``. Both, and the flow is the seat's capacity whatever
downstream does. Never with the seat off (the old law has no choke).

Reimplemented from feedtwin.comps.base.HydraulicComponent.

Definition at line 288 of file regulator.py.

References _gas_seat(), max, and outlet_setpoint().

◆ pressure_drop()

float feedtwin.comps.regulator.Regulator.pressure_drop ( self,
float mdot,
FlowConditions flow )
Flow-dependent pressure loss [Pa]. Always non-negative.

A *loss*: it opposes the flow, so it lowers the downstream pressure
whichever way the fluid is going. Reverse flow is each component's own
business -- symmetric for a pipe, very much not for a check valve.

Anything that does **not** depend on the direction of flow belongs in
:meth:`static_head`, not here. See that method for why the distinction
is load-bearing rather than tidy.

Reimplemented from feedtwin.comps.base.HydraulicComponent.

Reimplemented in feedtwin.comps.regulator.IdealRegulator.

Definition at line 350 of file regulator.py.

References _creep(), _seat_dp(), lockup_pressure(), max, and outlet_setpoint().

◆ seat_capacity()

float | None feedtwin.comps.regulator.Regulator.seat_capacity ( self,
FlowConditions flow,
float xT = XT_TYPICAL )
Choked gas flow through the wide-open seat [kg/s], IEC 60534-2-1.

What the regulator can pass at this inlet whatever is downstream: a
diagnostic (how close to wide open a burn runs), on whichever seat law
the solve uses. The drawing's ``xT`` wins over ``xT``. None for a liquid.

Definition at line 272 of file regulator.py.

References p, and feedtwin.comps.base.HydraulicComponent.p.

◆ seat_model()

dict[str, object] feedtwin.comps.regulator.Regulator.seat_model ( self,
float xT = XT_TYPICAL )
The run record's ``model`` block for the compressible seat.

Definition at line 309 of file regulator.py.

References feedtwin.comps.base.HydraulicComponent.instance.

◆ supply_effect()

float feedtwin.comps.regulator.Regulator.supply_effect ( self,
FlowConditions flow )
The supply-pressure term [Pa]: ``-S p_in``, the inlet in gauge.

Measured from zero inlet, never from a charge pressure: at 4000 psi a
1092-50 sits ``4 x 17`` psi under dome plus bias, and comes up as the
bottle falls.

Definition at line 207 of file regulator.py.

References p, and feedtwin.comps.base.HydraulicComponent.p.

Referenced by feedtwin.comps.regulator.CurveRegulator.outlet_setpoint(), and outlet_setpoint().

◆ total_dp()

float feedtwin.comps.regulator.Regulator.total_dp ( self,
float mdot,
FlowConditions flow )
Signed, and **not** the base class's mirror of the forward loss.

:meth:`HydraulicComponent.total_dp` negates the loss for reverse flow,
which is right for anything symmetric: run a pipe backwards and the
pressure falls backwards by the same amount. A regulator is not
symmetric. Its forward "loss" is the whole difference between a 4500 psi
bottle and a 550 psi setpoint, so mirroring it puts a step of
``2 (p_in - p_set)`` -- eight thousand psi -- across ``mdot = 0``.

The finite difference the solver takes across that step reports a slope
of order 1e16 Pa/(kg/s). One Newton iterate landing near zero flow on
the regulator is then enough to destroy the solve: the step it computes
is meaningless, the backtracking finds nothing better, and the run
stalls just above tolerance while the network quietly settles into
gas circulating backwards out of one tank and into the other. It cost
117 ticks out of 141 on a helium burn, and it presents as the tank
draining to atmosphere while the bottle stays full.

Forward, this is the base class. Backward, the poppet is on its seat:
continuous with the forward branch at zero and steeply resistant, so
Newton is pushed back toward non-negative flow rather than finding a
mirrored pressure source on the far side of a cliff.

Reimplemented from feedtwin.comps.base.HydraulicComponent.

Definition at line 388 of file regulator.py.

References lockup_pressure(), max, feedtwin.comps.base.HydraulicComponent.pressure_drop(), and feedtwin.comps.base.HydraulicComponent.static_head().


The documentation for this class was generated from the following file: