nx_maint_rul_test.nx source
↩ module page · 93 lines · 3371 B
1// nx_maint_rul_test.nx -- gate for RUL prognostics (the learning loop's prediction).
2//
3// Proves the RUL bands (plenty / plan / soon / imminent / failed), the stable
4// (not-wearing) case, and the liar-kill: the predicted life tracks the measured
5// wear RATE -- faster wear => shorter remaining life. This is the proactive
6// exceed over OBD/Sense (which only report the present).
7//
8// expect_exit: 0
9//
10// license_tier: ORIGINAL
11
12import "nx_syscalls_x86_64.nx"
13import "nx_maint_rul.nx"
14
15func main() -> i64 {
16 if nx_rul_verdict_is_valid(NX_RUL_IMMINENT) != 1 { return 1 }
17 if nx_rul_verdict_is_valid(NX_RUL_N) != 0 { return 2 }
18
19 let m: *i64 = sys_mmap(128) as *i64
20 let t: *i64 = sys_mmap(128) as *i64
21 let out: *RulEst = sys_mmap(64) as *RulEst
22 let spec: *RulSpec = sys_mmap(64) as *RulSpec
23 spec.fail_threshold = 150
24 spec.imminent_window = 5
25 spec.soon_window = 15
26 spec.plan_window = 40
27
28 // ===== PLAN: response rate declining 400->280 over 30 cycles ====
29 m[0]=400; m[1]=360; m[2]=320; m[3]=280
30 t[0]=0; t[1]=10; t[2]=20; t[3]=30
31 nx_rul_estimate(m, t, 4, spec, out)
32 if out.verdict != NX_RUL_PLAN { return 10 }
33 if out.rul != 32 { return 11 } // ~32 cycles to failure
34 if out.wear_rate_milli != 4000 { return 12 } // 4.0 / cycle
35 if out.current != 280 { return 13 }
36
37 // ===== IMMINENT: near threshold, fast decline ===================
38 m[0]=200; m[1]=170; m[2]=158
39 t[0]=0; t[1]=10; t[2]=20
40 nx_rul_estimate(m, t, 3, spec, out)
41 if out.verdict != NX_RUL_IMMINENT { return 20 }
42
43 // ===== SOON =====================================================
44 m[0]=215; m[1]=195; m[2]=175
45 t[0]=0; t[1]=10; t[2]=20
46 nx_rul_estimate(m, t, 3, spec, out)
47 if out.verdict != NX_RUL_SOON { return 30 }
48
49 // ===== PLENTY ===================================================
50 m[0]=500; m[1]=490; m[2]=480
51 t[0]=0; t[1]=10; t[2]=20
52 nx_rul_estimate(m, t, 3, spec, out)
53 if out.verdict != NX_RUL_PLENTY { return 40 }
54
55 // ===== STABLE: not wearing -> no predicted failure =============
56 m[0]=400; m[1]=400; m[2]=400
57 t[0]=0; t[1]=10; t[2]=20
58 nx_rul_estimate(m, t, 3, spec, out)
59 if out.verdict != NX_RUL_STABLE { return 50 }
60 if out.rul != (0 - 1) { return 51 }
61
62 // ===== FAILED: already past threshold ==========================
63 m[0]=200; m[1]=170; m[2]=140
64 t[0]=0; t[1]=10; t[2]=20
65 nx_rul_estimate(m, t, 3, spec, out)
66 if out.verdict != NX_RUL_FAILED { return 60 }
67 if out.rul != 0 { return 61 }
68
69 // ===== BAD_ARG: zero time span =================================
70 m[0]=400; m[1]=300
71 t[0]=0; t[1]=0
72 nx_rul_estimate(m, t, 2, spec, out)
73 if out.verdict != NX_RUL_BAD_ARG { return 70 }
74
75 // ===== INSUFFICIENT_DATA =======================================
76 m[0]=400
77 t[0]=0
78 nx_rul_estimate(m, t, 1, spec, out)
79 if out.verdict != NX_RUL_INSUFFICIENT { return 80 }
80
81 // ===== LIAR-KILL: life tracks the wear rate =====================
82 m[0]=400; m[1]=390
83 t[0]=0; t[1]=100
84 nx_rul_estimate(m, t, 2, spec, out)
85 let slow_rul: i64 = out.rul
86 m[0]=400; m[1]=300
87 t[0]=0; t[1]=100
88 nx_rul_estimate(m, t, 2, spec, out)
89 if out.rul >= slow_rul { return 90 } // faster wear -> SHORTER life
90 if slow_rul != 2400 { return 91 }
91
92 return 0
93}