code wiki / _hdl_build / nx_cg_restprobe.nx
nx_cg_restprobe.nx source
↩ module page · 81 lines · 3410 B
1// nx_cg_restprobe.nx -- DIAGNOSTIC: the damped 3-point solver did not reach an exact fixed point in
2// 20,000 ticks after a kick, yet nx_softtissue_mr_gate T5 proves it stays EXACTLY at rest when seated
3// there. Both cannot be waved at: rest is a stable fixed point the solver apparently does not CONVERGE
4// to. This measures the residual instead of theorising about it -- amplitude, velocity, and whether it
5// is a periodic limit cycle or a slow drift, over a budget far larger than the gate's.
6// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_softbind.nx"
9import "nx_gate_verdict.nx"
10
11const RP_STRIDE: i64 = 6
12const RP_WORDS: i64 = 18
13const RP_K: i64 = 60
14const RP_C: i64 = 100
15const RP_MAXD: i64 = 64
16const RP_KICK: i64 = 400
17const RP_WARM: i64 = 200000
18const RP_WIN: i64 = 4000
19const RP_SHOW: i64 = 24
20
21func rp_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
22func rp_same(a: *i64, b: *i64, n: i64) -> i64 { var i: i64 = 0; while i < n { if a[i] != b[i] { return 0 } i = i + 1 } return 1 }
23
24func main() -> i64 {
25 gv_head("nx_cg_restprobe -- residual motion of the damped 3-pt solver after a kick" as *u8)
26 let st: *i64 = sb_alloc(1)
27 sb_seat_mob(st, 0, 0, 0, 0)
28 sb_impulse_mob(st, 0, 0, RP_KICK, 0)
29 let b: i64 = SB_CHEST*RP_STRIDE
30
31 var t: i64 = 0
32 while t < RP_WARM { sb_tick_pt(st, 0, SB_CHEST, 0, 0, 0, RP_K, RP_C, RP_MAXD); t = t + 1 }
33 gv_puts(" after " as *u8); gv_num(RP_WARM); gv_puts(" ticks (10x the gate budget):\n" as *u8)
34
35 // window statistics on the Y channel (the kicked axis)
36 var elo: i64 = 0
37 var ehi: i64 = 0
38 var vlo: i64 = 0
39 var vhi: i64 = 0
40 var first: i64 = 1
41 t = 0
42 while t < RP_WIN {
43 sb_tick_pt(st, 0, SB_CHEST, 0, 0, 0, RP_K, RP_C, RP_MAXD)
44 let e: i64 = sb_off_y_q8(st, 0, SB_CHEST, 0)
45 let v: i64 = st[b+4]
46 if first == 1 { elo = e; ehi = e; vlo = v; vhi = v; first = 0 }
47 if e < elo { elo = e }
48 if e > ehi { ehi = e }
49 if v < vlo { vlo = v }
50 if v > vhi { vhi = v }
51 t = t + 1
52 }
53 gv_puts(" offset q8 range [" as *u8); gv_num(elo); gv_puts(", " as *u8); gv_num(ehi)
54 gv_puts("] velocity q8/tick range [" as *u8); gv_num(vlo); gv_puts(", " as *u8); gv_num(vhi)
55 gv_puts("]\n" as *u8)
56
57 // limit-cycle detection: snapshot, then look for an exact state repeat
58 let snap: *i64 = sys_mmap(RP_WORDS*8) as *i64
59 var i: i64 = 0
60 while i < RP_WORDS { snap[i] = st[i]; i = i + 1 }
61 var period: i64 = 0 - 1
62 t = 1
63 while t <= RP_WIN {
64 sb_tick_pt(st, 0, SB_CHEST, 0, 0, 0, RP_K, RP_C, RP_MAXD)
65 if rp_same(st, snap, RP_WORDS) == 1 { period = t; t = RP_WIN + 1 } else { t = t + 1 }
66 }
67 gv_puts(" exact state repeat after " as *u8); gv_num(period)
68 gv_puts(" ticks (-1 = no repeat within the window => drift, not a cycle)\n" as *u8)
69
70 // raw tail so the shape is visible rather than inferred
71 gv_puts(" raw tail (offset q8, velocity q8/tick):\n" as *u8)
72 t = 0
73 while t < RP_SHOW {
74 sb_tick_pt(st, 0, SB_CHEST, 0, 0, 0, RP_K, RP_C, RP_MAXD)
75 gv_puts(" e=" as *u8); gv_num(sb_off_y_q8(st, 0, SB_CHEST, 0))
76 gv_puts(" v=" as *u8); gv_num(st[b+4]); gv_puts("\n" as *u8)
77 t = t + 1
78 }
79 gv_puts("\n CONTEXT: 1 model unit = 256 q8 = 1.56 cm, so 1 q8 = 0.061 mm.\n" as *u8)
80 return 0
81}