code wiki / (root) / nx_gcode_extrude_test.nx

nx_gcode_extrude_test.nx source

↩ module page · 88 lines · 3501 B

1// nx_gcode_extrude_test.nx -- extrusion math hand-verified against 2// closed-form physics (volume conservation: mass-in == mass-out for 3// incompressible deposit). 4// 5// Reference computation for a 10mm move at standard 0.4mm width + 6// 0.2mm height + 1.75mm filament: 7// 8// filament_radius = 0.875mm 9// filament_xsect = π × 0.875² = π × 0.765625 ≈ 2.405 mm² 10// extruded_volume = 0.4 × 0.2 × 10 = 0.8 mm³ 11// E_delta = 0.8 / 2.405 ≈ 0.3326 mm of filament 12// 13// In Q14: E_delta ≈ 0.3326 × 16384 ≈ 5451 Q14 units. 14// 15// Closed-form invariants: 16// (a) filament_xsect for 1.75mm dia = 2.405mm² ≈ 39408 Q14. 17// Acceptable tolerance: ±2 Q14 units (rounding in radius+π+r²). 18// (b) move_length for (0,0)->(10,0) = 10mm = 163840 Q14. 19// (c) move_length for (0,0)->(0,10) = 10mm = 163840 Q14. 20// (d) move_length for (3,0)->(0,4) (3-4-5 triangle hypotenuse) = 5mm = 81920 Q14 21// NOTE: Q14 sqrt has small rounding error; accept ±2. 22// (e) E_delta for the standard move = ~5451 Q14. 23// (f) E_delta scales linearly with move length: 20mm move = 2× E_delta of 10mm move. 24// (g) E_delta is 0 for zero-length move. 25// (h) Zero filament_xsect returns 0 (defensive, not crash). 26// 27// expect_exit: 0 28// license_tier: ORIGINAL 29 30import "nx_syscalls.nx" 31import "nx_gcode_extrude.nx" 32 33const Q14: i64 = 16384 34 35// Verify x is within tol of expected. 36func smoke_near(actual: i64, expected: i64, tol: i64) -> i64 { 37 let diff: i64 = actual - expected 38 if diff < 0 { if -diff <= tol { return 1 } } 39 if diff >= 0 { if diff <= tol { return 1 } } 40 return 0 41} 42 43func main() -> i64 { 44 // --- (a) Filament cross-section --- 45 let xsect: i64 = nx_gcex_filament_xsect_q14(1750) 46 if smoke_near(xsect, 39408, 50) != 1 { return 10 } 47 48 // --- (b) Move length pure-X --- 49 let mlx: i64 = nx_gcex_move_length_q14(0, 0, 10 * Q14, 0) 50 if smoke_near(mlx, 10 * Q14, 2) != 1 { return 20 } 51 52 // --- (c) Move length pure-Y --- 53 let mly: i64 = nx_gcex_move_length_q14(0, 0, 0, 10 * Q14) 54 if smoke_near(mly, 10 * Q14, 2) != 1 { return 21 } 55 56 // --- (d) 3-4-5 triangle --- 57 let m345: i64 = nx_gcex_move_length_q14(3 * Q14, 0, 0, 4 * Q14) 58 if smoke_near(m345, 5 * Q14, 2) != 1 { return 22 } 59 60 // --- (e) Standard extrusion --- 61 // width 0.4mm = 6554 Q14 (0.4*16384 ≈ 6553.6) 62 // height 0.2mm = 3277 Q14 (0.2*16384 ≈ 3276.8) 63 let width_q14: i64 = 6554 64 let height_q14: i64 = 3277 65 let E1: i64 = nx_gcex_E_delta_for_move(0, 0, 10 * Q14, 0, 66 width_q14, height_q14, xsect) 67 // Expected ~5451 Q14; tolerance generous because width/height 68 // rounding contributes (~0.5% combined). 69 if smoke_near(E1, 5451, 60) != 1 { return 30 } 70 71 // --- (f) Linear scaling: 20mm move = 2 × 10mm E --- 72 let E2: i64 = nx_gcex_E_delta_for_move(0, 0, 20 * Q14, 0, 73 width_q14, height_q14, xsect) 74 let expected_2x: i64 = E1 * 2 75 if smoke_near(E2, expected_2x, 4) != 1 { return 40 } 76 77 // --- (g) Zero-length move --- 78 let E0: i64 = nx_gcex_E_delta_for_move(5 * Q14, 5 * Q14, 5 * Q14, 5 * Q14, 79 width_q14, height_q14, xsect) 80 if E0 != 0 { return 50 } 81 82 // --- (h) Defensive: zero xsect returns 0 --- 83 let E_bad: i64 = nx_gcex_E_delta_for_move(0, 0, 10 * Q14, 0, 84 width_q14, height_q14, 0) 85 if E_bad != 0 { return 60 } 86 87 return 0 88}