The science
F = mg = kx + b
Expected k = 12.00 N/m; g = 9.81 m/s². Fit force against measured extension with a free intercept. Percentage error = 100(k̂ − k)/k. The band shows ±3σ for the fitted mean line (parameter uncertainty).
Dynamics: m ẍ = mg − kx − c ẋ − d ẋ|ẋ| − s F₍guide₎. A fixed 1/120 s RK4 step advances the actual mass position. c = 0.16 N·s/m. Air drag adds d = 0.80 kg/m. Guide friction adds F₍guide₎ = 0.018 N, s = +1 loading or −1 unloading.
Guide friction is a branch-dependent static offset, not a full stick-slip model. It shifts the intercept ±0.018 N; parallax scales extension by 1.018 and biases k by −1.768%. Air drag changes settling time without changing equilibrium.
Ruler resolution 1 mm, Gaussian σ = 0.45 mm; scale resolution 0.1 g, Gaussian σ = 0.07 g. Each captured reading combines independent seeded Gaussian noise and rounding. The spring’s zero reference is calibrated exactly. No repeated averaging is hidden.
Uncertainty: σₖ = √(v / Σ(x−x̄)²), v = max(SSE/(n−2), σF² + k̂²σx²). Quantization adds q²/12 to each instrument variance. Ordinary least squares is adequate for these small independent reading errors; it is not an errors-in-variables fit. Systematic errors are excluded from this random uncertainty.
Assumptions: massless ideal spring, linear range to 0.35 m, rigid supports, one vertical degree of freedom, constant gravity, no hanger mass omitted. Time is simulated at 6×; clock resolution 0.01 s is display only, not a stopwatch measurement. Auto-record requires |v| < 0.1 mm/s and extension within 0.05 mm of the branch equilibrium for 0.5 simulated seconds.
Verification & setup
Serve the ZIP contents as the web root and open /lab.html (HTTP, not file://). The included module is served only from /assets/vendor/three/0.160.0/build/three.module.js. Use ?q=low for low quality. Modules and physics use absolute URLs.
The deterministic 200-trial check tests random measurement uncertainty with all systematic errors off. It does not promise universal 3σ coverage for every possible seed.