code wiki / (root) / nx_acceleration.nx

nx_acceleration.nx source

↩ module page · 131 lines · 4874 B

1// nx_acceleration.nx -- 3D acceleration vector + Newton's second-law 2// composition with nx_force. Layer 1 physics per 3// [[feedback-engineering-sciences-bits-up-3d-print-first]]. 4// 5// Unit: Q14 metres-per-second² (m/s²). 1 Q14 unit = 1/16384 m/s² 6// = 61 µm/s². Range fits i64 to ±5e14 m/s² -- vastly exceeds any 7// engineering use (rocket sled peaks ~50g ≈ 490 m/s², centrifuge 8// ~10⁶ m/s²). 9// 10// Newton's second law composition (F = ma): 11// nx_force_from_mass_accel(mass_kg_q14, accel) -> *NxForce 12// This is the second cross-primitive composition demo in the 13// physics layer (after nx_torque_from_position_force). Verified 14// by smoke roundtrip: gravity acceleration × 1 kg produces the 15// same NxForce as nx_force_gravity_on_kg(1 kg) within Q14 16// rounding. 17// 18// Composes: 19// nx_force (for F = ma return type) 20// nx_isqrt (magnitude via Q28 sum-of-squares) 21// nx_i128 / 22// nx_muldiv_i64 (overflow protection) 23// 24// Per [[feedback-four-pillar-design-aware-response]] (META-CARDINAL): 25// all multi-line subtractions use named temporaries (Pillar 2 26// recommendation for the nishilang-multi-line-binop gotcha). All 27// value transforms use let-immutable + pure helpers (no inline 28// `if x < 0 { x = 0 - x }` -- composes nx_abs if needed). 29// 30// license_tier: ORIGINAL 31 32import "nx_syscalls.nx" 33import "nx_isqrt.nx" 34import "nx_i128.nx" 35import "nx_force.nx" 36 37const NX_ACCEL_Q14: i64 = 16384 38 39// Earth surface gravitational acceleration: 9.80665 m/s² (CODATA). 40// In Q14: 9.80665 * 16384 = 160664.9 -> rounded 160665. 41const NX_ACCEL_GRAVITY_EARTH_Q14: i64 = 160665 42 43// ===== sealed-enum verdicts ======================================== 44 45const NX_ACCEL_OK: i64 = 0 46const NX_ACCEL_ERR_NULL_INPUT: i64 = 1 47 48func nx_acceleration_verdict_name(v: i64) -> *u8 { 49 if v == NX_ACCEL_OK { return "OK" } 50 if v == NX_ACCEL_ERR_NULL_INPUT { return "NULL_INPUT" } 51 return "UNKNOWN" 52} 53 54// ===== struct ====================================================== 55 56struct NxAcceleration { 57 ax_q14: i64, 58 ay_q14: i64, 59 az_q14: i64, 60} 61 62const NX_ACCEL_BYTES: i64 = 24 63 64// ===== constructors ================================================ 65 66func nx_acceleration_new(ax_q14: i64, ay_q14: i64, az_q14: i64) -> *NxAcceleration { 67 let a: *NxAcceleration = (sys_mmap(NX_ACCEL_BYTES)) as *NxAcceleration 68 a.ax_q14 = ax_q14 69 a.ay_q14 = ay_q14 70 a.az_q14 = az_q14 71 return a 72} 73 74func nx_acceleration_zero() -> *NxAcceleration { 75 return nx_acceleration_new(0, 0, 0) 76} 77 78// Earth surface gravity: (0, 0, -g) in Q14 m/s². -Z is "down" 79// matching the slicer/printer convention. 80func nx_acceleration_g_earth() -> *NxAcceleration { 81 let neg_g: i64 = 0 - NX_ACCEL_GRAVITY_EARTH_Q14 82 return nx_acceleration_new(0, 0, neg_g) 83} 84 85// ===== arithmetic ================================================== 86 87func nx_acceleration_add(a: *NxAcceleration, b: *NxAcceleration) -> *NxAcceleration { 88 return nx_acceleration_new(a.ax_q14 + b.ax_q14, 89 a.ay_q14 + b.ay_q14, 90 a.az_q14 + b.az_q14) 91} 92 93func nx_acceleration_sub(a: *NxAcceleration, b: *NxAcceleration) -> *NxAcceleration { 94 return nx_acceleration_new(a.ax_q14 - b.ax_q14, 95 a.ay_q14 - b.ay_q14, 96 a.az_q14 - b.az_q14) 97} 98 99func nx_acceleration_scale(a: *NxAcceleration, scalar_q14: i64) -> *NxAcceleration { 100 return nx_acceleration_new(nx_muldiv_i64(a.ax_q14, scalar_q14, NX_ACCEL_Q14), 101 nx_muldiv_i64(a.ay_q14, scalar_q14, NX_ACCEL_Q14), 102 nx_muldiv_i64(a.az_q14, scalar_q14, NX_ACCEL_Q14)) 103} 104 105// ===== magnitude =================================================== 106 107func nx_acceleration_magnitude_q14(a: *NxAcceleration) -> i64 { 108 let sq_x: i64 = a.ax_q14 * a.ax_q14 109 let sq_y: i64 = a.ay_q14 * a.ay_q14 110 let sq_z: i64 = a.az_q14 * a.az_q14 111 let lsq: i64 = sq_x + sq_y + sq_z 112 return nx_isqrt(lsq) 113} 114 115// ===== Newton's second law: F = ma ================================= 116// 117// THE CROSS-PRIMITIVE COMPOSITION DEMO for the kinematics layer. 118// Given a mass (Q14 kg) and acceleration vector (Q14 m/s²), returns 119// the resulting force vector (Q14 N). Component-wise: F_i = m * a_i. 120// 121// Composition: returns *NxForce (defined in nx_force.nx). Slicer + 122// robotics + structural-analysis primitives downstream can compose 123// this with their own load/inertia models. 124 125func nx_force_from_mass_accel(mass_kg_q14: i64, 126 accel: *NxAcceleration) -> *NxForce { 127 let fx: i64 = nx_muldiv_i64(mass_kg_q14, accel.ax_q14, NX_ACCEL_Q14) 128 let fy: i64 = nx_muldiv_i64(mass_kg_q14, accel.ay_q14, NX_ACCEL_Q14) 129 let fz: i64 = nx_muldiv_i64(mass_kg_q14, accel.az_q14, NX_ACCEL_Q14) 130 return nx_force_new(fx, fy, fz) 131}