nx_ac_enthalpy_metrics.nx source
↩ module page · 123 lines · 6021 B
1// nx_ac_enthalpy_metrics.nx -- the AC PERFORMANCE crown, built on the
2// psychrometric floor. This is the R4 rung the HVAC-efficiency workstream
3// flagged as "the crown number, NOT built": independent delivered-capacity,
4// COP/EER, and efficiency-drift measured from out-of-band sensors -- the
5// data-center air-side method (delivered capacity = airflow * enthalpy drop),
6// which SOTA DCIM (Vertiv/Schneider/Sunbird) uses per cooling unit.
7//
8// Everything here is a physics quantity a vendor thermostat cannot fake and
9// does not report. Paired with nx_hvac_efficiency (fault verdict) and the
10// reading-level liar-killer (nx_ac_sensor_verify), it is the measurement core
11// of the "Flume for AC" product.
12//
13// KEY LIAR-KILL SURFACE (why this organ is trustworthy, not just a calculator):
14// - delivered cooling with h_return <= h_supply returns NEGATIVE (loud):
15// the air is not being cooled -- never a fabricated positive capacity.
16// - COP with electrical power <= 0 returns INFEASIBLE (loud), never inf.
17// - the CARNOT COP ceiling Tc/(Th-Tc) is a HARD physical bound: any measured
18// or claimed COP above it is thermodynamically impossible -> the downstream
19// liar-killer rejects the reading. carnot with T_cold >= T_hot is INFEASIBLE.
20// - superheat / subcooling / evaporator-split are returned VERBATIM incl.
21// negatives, so a flooded coil or a swapped/failed sensor shows as an
22// impossible value the liar-killer flags -- not silently clamped.
23//
24// NO-FLOAT integer fixed-point (ecosystem doctrine):
25// temperature = milli-degC (mC) airflow = CFM power = W
26// air density = g/m^3 (1200 = 1.2 kg/m^3; data-driven for altitude/temp)
27// enthalpy = J/kg dry air cooling = W
28// COP = x100 (centi-COP) EER = x100
29// Carnot COP = x100 drift = permille (positive = degraded)
30// abs temp = centi-Kelvin (cK): cK = mC/10 + 27315 (0 degC = 273.15 K)
31//
32// NEVER-BRICK #26: pure computation, read-only, no device/firmware write.
33//
34// genealogy_id: project-hvac-efficiency-sclass-2026-06-23 (R4 COP/EER crown)
35// + project-nishi-sensor-gap-census-2026-07-14 (axis-4 external-comp)
36// license_tier: ORIGINAL
37//
38// nx_capability_claims:
39// needs: [nx_psychrometrics]
40// provides: [delivered_cooling_capacity, cop_measure, eer_measure,
41// carnot_cop_ceiling, superheat_measure, subcooling_measure,
42// evaporator_split, efficiency_drift, air_side_enthalpy_method]
43// safety: [no_floating_point, no_syscall, bounded_iteration,
44// read_only_no_device_write, infeasible_input_is_loud,
45// carnot_bounded]
46// verdict: [physical_invariant, external_comp_band, no_silent_failure]
47// license: ORIGINAL
48// kind: iot_runtime_primitive
49// sss: [S0 (bit-equal), S6 (no cloud), S7 (sealed verdict)]
50
51import "nx_psychrometrics.nx"
52const NX_MAGIC_47195: i64 = 47195
53const NX_MAGIC_100000000000: i64 = 100000000000
54const NX_MAGIC_3412: i64 = 3412
55const NX_MAGIC_27315: i64 = 27315
56
57const NX_ACM_INFEASIBLE: i64 = -2000000000
58
59// Delivered cooling capacity in Watts, air-side enthalpy method:
60// Q = mdot_dryair * (h_return - h_supply)
61// mdot [kg/s] = CFM * 0.00047195 [m^3/s per CFM] * rho [kg/m^3]
62// integer: Q_W = CFM * dh_J * rho_gm3 * 47195 / 1e11
63// dh_j = h_return - h_supply (J/kg). NEGATIVE dh -> negative Q (loud: not cooling).
64func nx_ac_delivered_cooling_w(cfm: i64, dh_j: i64, rho_gm3: i64) -> i64 {
65 let a: i64 = cfm * dh_j
66 let b: i64 = a * rho_gm3
67 return (b * NX_MAGIC_47195) / NX_MAGIC_100000000000
68}
69
70// Coefficient of performance x100 = cooling_W / electrical_W.
71// P <= 0 -> INFEASIBLE (loud), never a divide-by-zero / infinite COP.
72func nx_ac_cop_x100(q_cool_w: i64, p_elec_w: i64) -> i64 {
73 if p_elec_w <= 0 { return NX_ACM_INFEASIBLE }
74 return (q_cool_w * 100) / p_elec_w
75}
76
77// EER x100 = COP * 3.412 (EER = BTU/h per W; 1 W = 3.412 BTU/h).
78func nx_ac_eer_x100(cop_x100: i64) -> i64 {
79 return (cop_x100 * NX_MAGIC_3412) / 1000
80}
81
82// Absolute temperature in centi-Kelvin from milli-degC. 0 degC = 273.15 K.
83func nx_ac_temp_cK(t_mC: i64) -> i64 {
84 return (t_mC / 10) + NX_MAGIC_27315
85}
86
87// Carnot COP ceiling x100 for a cooling cycle: COP_max = Tc / (Th - Tc).
88// Tc = cold reservoir (indoor/evaporator), Th = hot reservoir (outdoor/condenser).
89// T_cold >= T_hot is physically impossible for cooling -> INFEASIBLE (loud).
90func nx_ac_carnot_cop_x100(t_cold_mC: i64, t_hot_mC: i64) -> i64 {
91 let tc: i64 = nx_ac_temp_cK(t_cold_mC)
92 let th: i64 = nx_ac_temp_cK(t_hot_mC)
93 let d: i64 = th - tc
94 if d <= 0 { return NX_ACM_INFEASIBLE }
95 return (tc * 100) / d
96}
97
98// Refrigerant superheat (mC) = suction line temp - evaporator saturation temp.
99// Physically >= 0 in normal operation; a negative value is returned VERBATIM
100// (loud) so the liar-killer flags flooding / a swapped-or-failed sensor.
101func nx_ac_superheat_mC(t_suction_mC: i64, t_sat_evap_mC: i64) -> i64 {
102 return t_suction_mC - t_sat_evap_mC
103}
104
105// Refrigerant subcooling (mC) = condenser saturation temp - liquid line temp.
106// Physically >= 0 in normal operation; negatives returned verbatim (loud).
107func nx_ac_subcool_mC(t_sat_cond_mC: i64, t_liquid_mC: i64) -> i64 {
108 return t_sat_cond_mC - t_liquid_mC
109}
110
111// Evaporator air split (mC) = return air temp - supply air temp (cooling).
112// Healthy residential split ~ 8-12 degC (14-22 degF). > 0 in cooling.
113func nx_ac_evap_split_mC(t_return_air_mC: i64, t_supply_air_mC: i64) -> i64 {
114 return t_return_air_mC - t_supply_air_mC
115}
116
117// Efficiency drift permille vs the unit's OWN baseline COP (the Flume bill-hook:
118// "18% more energy per degree-day than last season"). Positive = degraded.
119// Baseline <= 0 -> INFEASIBLE (loud, no fabricated drift).
120func nx_ac_efficiency_drift_permille(cop_now_x100: i64, cop_base_x100: i64) -> i64 {
121 if cop_base_x100 <= 0 { return NX_ACM_INFEASIBLE }
122 return ((cop_base_x100 - cop_now_x100) * 1000) / cop_base_x100
123}