code wiki / (root) / nx_ferment_thermal_test.nx

nx_ferment_thermal_test.nx source

↩ module page · 75 lines · 3115 B

1// nx_ferment_thermal_test.nx -- smoke for nx_ferment_thermal (R1). 2// 3// Proves hardware temperature control that is SAFE BY CONSTRUCTION: 4// - unsafe setpoints are clamped below culture-kill (1-2) 5// - command is heat-only (4) and bounded (5-6) 6// - a room-temp vessel is driven into the 43 C yogurt neighborhood (7-8) 7// - temperature NEVER reaches culture-kill dynamically (9, 12) 8// - a 70 C request is clamped to 54 C and the loop converges to the 9// CLAMPED safe temp, never the unsafe target (10-12) 10// Exit code = failed assertion number; 0 = all pass. 11 12import "nx_syscalls.nx" 13import "nx_pid.nx" 14import "nx_ferment_safety.nx" 15import "nx_ferment_thermal.nx" 16 17func main() -> i64 { 18 let env: *NxFermentSafetyEnvelope = nx_ferment_safety_envelope_default(1) 19 20 // --- safety clamp: 60 C requested (> 55 C kill) -> 54 C (kill - 1) --- 21 if nx_ferment_thermal_safe_setpoint(env, 60000) != 54000 { return 1 } 22 // --- a safe setpoint passes through unchanged --- 23 if nx_ferment_thermal_safe_setpoint(env, 43000) != 43000 { return 2 } 24 25 // yogurt controller: target 43 C; gentle, anti-windup-bounded PI. 26 // heater_max 800 * heat_gain 1.0 = max 800 milli-C/step < 1000 margin 27 // => a single step can never cross culture-kill. 28 let t: *NxFermentThermal = nx_ferment_thermal_new(env, 43000, 29 800, 8, 0, 1638400, 800) 30 if t.setpoint_milli_c != 43000 { return 3 } 31 32 // --- heat-only: above setpoint / ceiling -> command 0 --- 33 if nx_ferment_thermal_step(t, 60000) != 0 { return 4 } 34 nx_pid_reset(t.pid) 35 36 // --- below setpoint -> positive, bounded command --- 37 var c0: i64 = nx_ferment_thermal_step(t, 20000) 38 if c0 <= 0 { return 5 } 39 if c0 > t.heater_max { return 6 } 40 nx_pid_reset(t.pid) 41 42 // --- closed-loop sim: ambient 20 C, heat_gain 1.0, loss 160/Q --- 43 var temp: i64 = 20000 44 let amb: i64 = 20000 45 var maxtemp: i64 = temp 46 var step: i64 = 0 47 while step < 400 { 48 let cmd: i64 = nx_ferment_thermal_step(t, temp) 49 temp = nx_ferment_plant_step(temp, cmd, amb, 16384, 160) 50 if temp > maxtemp { maxtemp = temp } 51 step = step + 1 52 } 53 if temp < 38000 { return 7 } // climbed >= 18 C of the 23 C gap 54 if temp > 50000 { return 8 } // did not run away past +7 C 55 if maxtemp >= 55000 { return 9 } // SAFETY: never reached culture-kill 56 57 // --- unsafe 70 C request: clamped to 54 C; loop converges to the 58 // CLAMPED temp and never breaches kill --- 59 let t2: *NxFermentThermal = nx_ferment_thermal_new(env, 70000, 60 800, 8, 0, 1638400, 800) 61 if t2.setpoint_milli_c != 54000 { return 10 } 62 var temp2: i64 = 20000 63 var max2: i64 = temp2 64 var s2: i64 = 0 65 while s2 < 600 { 66 let cmd2: i64 = nx_ferment_thermal_step(t2, temp2) 67 temp2 = nx_ferment_plant_step(temp2, cmd2, amb, 16384, 160) 68 if temp2 > max2 { max2 = temp2 } 69 s2 = s2 + 1 70 } 71 if temp2 < 49000 { return 11 } // reached the clamped-safe neighborhood 72 if max2 >= 55000 { return 12 } // SAFETY: never breached culture-kill 73 74 return 0 75}