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}