nx_stability_rh.nx
buildroot/runtime/nx_stability_rh.nx
about
nx_stability_rh.nx -- the MOISTURE axis of stability, and the machinery to
SEPARATE it from the temperature axis.
===== WHY THIS EXISTS ============================================
nx_stability recovers an activation energy from ICH's declaration that
6 months at 40 C / 75% RH supports 24 months at 25 C / 60% RH. Those two
conditions differ in temperature AND in humidity, so what comes out is a
LUMPED effective parameter carrying the moisture contribution inside it.
nx_stability says so honestly but cannot do anything about it, because
two conditions differing in two variables are underdetermined -- one
equation, two unknowns, and no amount of arithmetic fixes that.
This file adds the second axis and, with it, the ability to separate them
when the experiment actually supports separation.
===== THE MODEL ==================================================
The moisture-modified Arrhenius used by accelerated-stability practice:
ln k = ln A - Ea/(RT) + B*RH
so between two conditions, in base ten (this suite's convention):
log10(k2/k1) = E10*(1/T1 - 1/T2) + B10*(RH2 - RH1)
where E10 = Ea/(R ln10) and B10 = B/ln10. Two unknowns, so two
independent contrasts -- three conditions -- determine both.
===== THE REFUSAL IS THE FEATURE =================================
Three conditions are NECESSARY but not SUFFICIENT: they must not be
collinear in (1/T, RH) space. Three points on a line give a singular
system, and a solver that "handles" that by picking one of the infinitely
many solutions would emit a confident, specific, meaningless Ea. So the
determinant is computed and a zero REFUSES.
srh_ich_pair_alone_is_separable() returns 0 as a FUNCTION, so this file
mechanically demonstrates the limitation nx_stability could only describe.
dependencies 3 imports · 1 importers
imports: nx_syscalls.nxnx_pow10.nxnx_stability.nx
imported by: nx_labsci_svc.nx
structs
| none |
consts
| 56 | const SRH_MAGIC_10000000: i64 = 10000000 |
| 57 | const SRH_MAGIC_10000: i64 = 10000 |
| 58 | const SRH_MAGIC_1000000: i64 = 1000000 |
| 60 | const SRH_INVALID: i64 = 0 - 1 |
| 64 | const SRH_UNDERDETERMINED: i64 = 0 - 2 |
| 67 | const SRH_INV_T_SCALE: i64 = 1000000000 |
| 72 | const SRH_PUB_B10_LO_MILLI: i64 = 5 |
| 73 | const SRH_PUB_B10_HI_MILLI: i64 = 25 |
| 189 | const SRH_MIN_CONDITIONING_PERMIL: i64 = 100 |
functions
| 79 | func srh_inv_t_e7(t_c: i64) -> i64 |
| 90 | func srh_log10_rate_ratio_milli(e10_mk: i64, b10_milli: i64, t1_c: i64, rh1: i64, t2_c: i64, rh2: i64) -> i64 |
| 108 | func srh_lifetime_months(ref_months: i64, e10_mk: i64, b10_milli: i64, t1_c: i64, rh1: i64, t2_c: i64, rh2: i64) -> i64 |
| 123 | func srh_determinant(t1_c: i64, rh1: i64, t2_c: i64, rh2: i64, t3_c: i64, rh3: i64) -> i64 |
| 145 | func srh_is_separable(t1_c: i64, rh1: i64, t2_c: i64, rh2: i64, t3_c: i64, rh3: i64) -> i64 calls 1: srh_determinant |
| 162 | func srh_design_conditioning_permil(t1_c: i64, rh1: i64, t2_c: i64, rh2: i64, t3_c: i64, rh3: i64) -> i64 |
| 191 | func srh_design_is_well_conditioned(t1_c: i64, rh1: i64, t2_c: i64, rh2: i64, t3_c: i64, rh3: i64) -> i64 |
| 199 | func srh_ich_pair_alone_is_separable() -> i64 called by 1: lab_stability_separate |
| 203 | func srh_conditions_required() -> i64 |
| 217 | func srh_separate(t1_c: i64, rh1: i64, m1: i64, t2_c: i64, rh2: i64, m2: i64, t3_c: i64, rh3: i64, m3: i64, out: *i64) -> i64 |
| 259 | func srh_ea_from_e10(e10_mk: i64) -> i64 called by 1: lab_stability_separate |
| 267 | func srh_b10_in_published_band(b10_milli: i64) -> i64 called by 1: lab_stability_separate |
| 277 | func srh_moisture_share_permil(e10_mk: i64, b10_milli: i64, t1_c: i64, rh1: i64, t2_c: i64, rh2: i64) -> i64 calls 1: srh_log10_rate_ratio_milli |