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}