nx_vessel_io_test.nx source
↩ module page · 59 lines · 2542 B
1// nx_vessel_io_test.nx -- smoke for nx_vessel_io (H1, hardware-in-the-loop).
2//
3// Proves the real control software regulates against IMPERFECT hardware:
4// - sensor quantizes to the ADC resolution (1)
5// - PWM actuator is on below the duty, off above (2-3)
6// - sensor LAG: a laggy probe reads below true during a ramp (4-5)
7// - HIL: the R1 controller, reading a NOISY+LAGGY sensor, drives the H0
8// physics twin into the setpoint neighborhood (6-7) and NEVER reaches
9// culture-kill (8) -- the control design validated pre-build
10// Exit code = failed assertion number; 0 = all pass.
11
12import "nx_syscalls.nx"
13import "nx_ferment_safety.nx"
14import "nx_ferment_thermal.nx"
15import "nx_vessel_thermal.nx"
16import "nx_vessel_io.nx"
17
18func main() -> i64 {
19 // --- sensor quantization (instant, 0.1 C ADC, +/-0.1 C noise) ---
20 let s: *NxSensor = nx_sensor_new(20000, 1000, 100, 100)
21 let m: i64 = nx_sensor_update(s, 43050, 5)
22 if m % 100 != 0 { return 1 }
23
24 // --- PWM actuator ---
25 if nx_heater_pwm(600, 300) != 1000 { return 2 }
26 if nx_heater_pwm(600, 700) != 0 { return 3 }
27
28 // --- sensor lag: a laggy probe trails the true temperature on a ramp ---
29 let sl: *NxSensor = nx_sensor_new(20000, 200, 0, 0)
30 var i: i64 = 0
31 while i < 5 {
32 nx_sensor_update(sl, 40000, i)
33 i = i + 1
34 }
35 let lagged: i64 = nx_sensor_update(sl, 40000, 6)
36 if lagged >= 40000 { return 4 } // still catching up
37 if lagged <= 20000 { return 5 } // but climbing
38
39 // --- HARDWARE-IN-THE-LOOP: R1 controller + noisy/laggy sensor + twin ---
40 let env: *NxFermentSafetyEnvelope = nx_ferment_safety_envelope_default(1)
41 let ctrl: *NxFermentThermal = nx_ferment_thermal_new(env, 43000, 700, 4, 0, 4000000, 1000)
42 let twin: *NxVesselThermal = nx_vessel_thermal_new(16744, 50000, 1000, 20000)
43 let sens: *NxSensor = nx_sensor_new(20000, 300, 100, 100) // 30% lag, 0.1C ADC, +/-0.1C noise
44 var truet: i64 = 20000
45 var maxt: i64 = truet
46 var step: i64 = 0
47 while step < 400 {
48 let meas: i64 = nx_sensor_update(sens, truet, step)
49 let duty: i64 = nx_ferment_thermal_step(ctrl, meas)
50 truet = nx_vessel_thermal_step(twin, truet, duty, 60)
51 if truet > maxt { maxt = truet }
52 step = step + 1
53 }
54 if truet < 39000 { return 6 } // regulated up to the setpoint band
55 if truet > 47000 { return 7 } // bounded (no runaway)
56 if maxt >= 55000 { return 8 } // SAFETY holds under realistic IO
57
58 return 0
59}