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}