STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
pressure.py
Go to the documentation of this file.
1"""Which pressures on a drawing are absolute, which are differences, and what a
2bare "psi" means.
3
4The model works in absolute pascals. People do not: a tank "at 500 psi" is at
5500 psig, a COPV "at 4500" is at 4500 psig, a regulator "set to 500" holds 500 on
6a gauge. Every shipped drawing's own notes say so ("500 psig operating
7pressure", "bottle gauge", "gives 550 at the tanks"). The library used to read a
8bare "psi" as absolute, so every one of those was 14.7 psi low -- the drawn dome
9loader disagreed with the dome knob by an atmosphere, a delivered bottle started
10an atmosphere under its own fill target, and the Hookup tab printed a psia number
11labelled psig.
12
13So on a drawing, two rules, both here and nowhere else:
14
15* **An absolute pressure written bare is gauge.** ``psi`` on a tank's
16 ``pressure`` or a regulator's ``setpoint`` reads as ``psig``; ``bar`` as
17 ``barg``, ``kPa`` as ``kPag``. Write ``psia`` (``bara``, ``kPaa``) to mean
18 absolute. ``atm`` is absolute by nature and stays so.
19* **Except at the engine.** A chamber pressure is quoted absolute, by long
20 convention and everywhere EngineDesign quotes one; on an ENGINE or INJECTOR
21 symbol a bare pressure is read as absolute.
22* **A difference never carries a reference.** A droop, a dome bias, a crack or
23 relief set pressure is the same size in psia and psig; ``psig`` on one is a
24 drawing error, refused with the parameter named, because an atmosphere
25 silently added to a 50 psi bias is a 65 psi bias.
26
27A pressure parameter in neither list is read as absolute -- what nearly every
28pressure on a drawing is -- so a field pid-designer adds tomorrow still imports.
29``tests/test_pressure_reference.py`` fails until it is listed here, which is what
30keeps the lists complete.
31
32How a drawing is *read* is not how a pressure is *shown*. Whatever reference a
33drawing wrote, a person is shown the absolute pressure in psia (ADR 0007):
34:func:`say` is the one formatter.
35"""
36
37from __future__ import annotations
38
39from feedtwin.model.units import get_unit
40
41#: Pressures measured from zero: what a gauge or a transducer reads at a place.
42ABSOLUTE = frozenset(
43 {
44 "pressure", # a tank, bottle, dewar or source boundary
45 "chamber_pressure",
46 "setpoint", # a regulator's outlet
47 "dome_pressure",
48 "inlet_reference", # retired: the supply effect is measured from zero inlet
49 "MAWP",
50 "burst_pressure",
51 "range_max", # an instrument's full scale
52 "range_min",
53 }
54)
55
56#: Pressures that are a difference between two places.
57DIFFERENCE = frozenset(
58 {
59 "dome_bias",
60 "flow_droop",
61 "lockup_rise",
62 "cracking_pressure",
63 "set_pressure", # a relief's, across the valve
64 "reseat_pressure",
65 "min_inlet_differential",
66 "pressure_drop",
67 "dp",
68 }
69)
70
71#: A bare spelling's gauge counterpart.
72GAUGE = {"psi": "psig", "bar": "barg", "kPa": "kPag", "MPa": "MPag", "Pa": "Pag"}
73#: Spellings that say which reference they are.
74QUALIFIED = frozenset(
75 {"psia", "bara", "kPaa", "MPaa", "psig", "barg", "kPag", "MPag", "Pag", "atm"}
76)
77
78
79class PressureReferenceError(ValueError):
80 """A pressure on a drawing whose reference cannot be read."""
81
82
83#: Symbols whose pressures are quoted absolute: the chamber.
84ABSOLUTE_SYMBOLS = frozenset({"ENGINE", "INJECTOR"})
85
86
87def drawn_unit(name: str, unit: str, symbol: str = "") -> str:
88 """The unit a drawing's ``name`` parameter is really in.
89
90 Not a pressure: unchanged. A difference: unchanged, unless it names a
91 reference, which is refused. Anything else is an absolute pressure, and
92 written bare it is its gauge spelling.
93 """
94 if get_unit(unit).dimension != "pressure":
95 return unit
96 if name in DIFFERENCE:
97 if unit in QUALIFIED:
98 raise PressureReferenceError(
99 f"{name} is a pressure difference; write it in {_bare(unit)}, not "
100 f"{unit} -- a difference has no gauge or absolute reference"
101 )
102 return unit
103 if symbol in ABSOLUTE_SYMBOLS:
104 return unit
105 return GAUGE.get(unit, unit)
106
107
108def _bare(unit: str) -> str:
109 for bare, gauge in GAUGE.items():
110 if unit in (gauge, bare + "a"):
111 return bare
112 return "psi"
113
114
115# ------------------------------------------------------------ what people read
116
117#: One psi [Pa].
118_PSI: float = get_unit("psi").factor
119
120
121def psia(pascal: float) -> float:
122 """Absolute pressure [Pa] in psia: the number a person is shown (ADR 0007).
123
124 A vented vessel reads 14.7.
125 """
126 return pascal / _PSI
127
128
129def say(pascal: float, places: int = 0) -> str:
130 """An absolute pressure [Pa] as a person reads it: ``"514.7 psia"``.
131
132 ``places`` decimals, thousands grouped (``"4,514.7 psia"``). The one place a
133 message, a note or a hover spells a pressure out, so each says psia and none
134 adds an atmosphere by hand. A gauge number off the wire goes in as
135 ``say(from_psig(value))`` (:mod:`feedtwin.session.gauge`). A difference --
136 a bias, a droop, a sag -- is not a pressure at a place: plain psi.
137
138 Here rather than in :mod:`feedtwin.session.gauge`, which re-exports it, so
139 the drawing reader and the engine importer can say a pressure without
140 importing the session.
141 """
142 places = max(int(places), 0)
143 value = round(pascal / _PSI, places) + 0.0 # never "-0 psia"
144 return f"{value:,.{places}f} psia"
#define max(a, b)
Definition Arduino.h:43