nx_vessel_twin.nx source
↩ module page · 60 lines · 2772 B
1// nx_vessel_twin.nx -- CAPSTONE of the HARDWARE-IN-THE-LOOP ladder: the
2// full DIGITAL TWIN sign-off. Given a candidate device (thermal mass,
3// heater, insulation, thermal-cutoff) and a target recipe, it certifies
4// the COMPLETE system end-to-end in software:
5//
6// 1. HARDWARE (H3 = H0 sizing + H1 control + H2 faults): the device can
7// reach, hold, and fail safe.
8// 2. PROCESS (R3 kinetics): at the recipe's hold temperature the ferment
9// actually acidifies to a safe pH within the never-poison window.
10// 3. SAFETY (H2): a stuck heater is contained by the independent fuse.
11//
12// Only if all three pass is the (device, recipe) pair CERTIFIED for build.
13// This is the model-based "iron-bird + flight-sim" certification a fighter
14// programme completes before the first metal is cut -- here for a fermenter
15// so the hardware is the LAST, de-risked step.
16//
17// genealogy_id: nishi_hil_h3 + nishi_ferment_kinetics_r3 + nishi_ferment_recipes_r4
18
19import "nx_syscalls.nx"
20import "nx_ferment_safety.nx"
21import "nx_ferment_kinetics.nx"
22import "nx_ferment_recipes.nx"
23import "nx_vessel_thermal.nx"
24import "nx_vessel_io.nx"
25import "nx_vessel_faults.nx"
26import "nx_vessel_design.nx"
27const NX_MAGIC_2000: i64 = 2000
28
29const NX_TWIN_CERTIFIED: i64 = 0
30const NX_TWIN_FAIL_DESIGN: i64 = 1 // hardware design rejected (H3)
31const NX_TWIN_FAIL_WONT_FERMENT:i64 = 2 // won't acidify in the window (R3)
32const NX_TWIN_FAIL_UNSAFE_FAULT:i64 = 3 // not contained under a fault (H2)
33
34func nx_vessel_twin_certify(env: *NxFermentSafetyEnvelope, twin: *NxVesselThermal,
35 cutoff_mc: i64, recipe_id: i64) -> i64 {
36 let r: *NxFermentRecipeSpec = nx_ferment_recipe(recipe_id)
37 let setpoint_c: i64 = r.hold_temp_c
38 let setpoint_mc: i64 = setpoint_c * 1000
39 let oxygen: i64 = r.oxygen
40
41 // 1. HARDWARE design certification (H3 rolls up H0 + H1 + H2).
42 if nx_vessel_design_verify(env, twin, cutoff_mc, setpoint_mc, 300) != NX_DV_PASS {
43 return NX_TWIN_FAIL_DESIGN
44 }
45
46 // 2. PROCESS feasibility: an anaerobic ferment must reach safe pH within
47 // the never-poison window at this hold temperature (R3 kinetics).
48 if oxygen == NX_OX_ANAEROBIC {
49 let set_h: i64 = nx_ferment_kinetics_set_time(setpoint_c)
50 if set_h <= 0 { return NX_TWIN_FAIL_WONT_FERMENT }
51 if set_h > (env.max_hours_to_acidify as i64) { return NX_TWIN_FAIL_WONT_FERMENT }
52 }
53
54 // 3. SAFETY: a stuck-on heater is bounded by the independent fuse (H2).
55 let fin: *i64 = (sys_mmap(8)) as *i64
56 let maxt: i64 = nx_vessel_fault_run(env, twin, NX_VFAULT_HEATER_STUCK_ON, cutoff_mc, 800, fin)
57 if maxt >= cutoff_mc + NX_MAGIC_2000 { return NX_TWIN_FAIL_UNSAFE_FAULT }
58
59 return NX_TWIN_CERTIFIED
60}