The Engine

From launch numbers to ball flight

Your launch monitor measures only the moment of impact — how fast the ball leaves, at what angle, and how it spins. Everything you see plotted on this site (carry, apex, descent, dispersion, roll-out) is computed from those launch numbers by integrating the physics of flight. This page documents exactly how, with the real equations.

What the R50 gives us Launch-data-only Air & launch vectors Forces in flight Drag & lift coefficients Integration Bounce & roll Our one tweak Sources

01What the launch monitor actually measures

The Garmin Approach R50 reports a set of launch quantities — the ball's state in the first instants after impact:

The R50 also reports its own estimate of carry, apex, and total. We do not use those for anything plotted. They appear only on the Raw Data page, for reference. Every curve on this site is rebuilt from the launch quantities above.

02Why launch-data-only

A launch monitor measures launch conditions extremely well but infers carry and apex from a short observation window. By taking only the directly measured launch state and integrating the flight ourselves, every downstream number comes from one transparent, reproducible physics model rather than a black box. The trade-off is honesty: if the model and the monitor disagree, you can see exactly why, in the equations below.

03Setting up: air, launch velocity, and spin

Before any forces act, the model converts launch conditions into vectors and folds the atmosphere into two scalars.

Air density

Density is computed from temperature, pressure, elevation, and humidity (the site uses a fixed standard atmosphere: 70°F, 29.92 inHg, sea level, 50% RH):

air density (kg/m³), with humidity & elevation correction
\[ \rho = \rho_0 \,\frac{273.15}{T_K}\cdot\frac{P\,e^{-\beta h} - 0.3783\,\phi\,(\text{SVP}/100)}{P_0} \]

where \(\rho_0=1.2929\) kg/m³, \(T_K\) is temperature in kelvin, \(P\) barometric pressure (mmHg), \(P_0=760\) mmHg, \(\beta=1.217\times10^{-4}\), \(h\) elevation (m), \(\phi\) relative humidity, and SVP the saturation vapor pressure of water.

The lumped drag scalar

Rather than carry area and mass through every step, libgolf folds them — with density — into a single coefficient \(c_0\) that turns a coefficient and speed directly into an acceleration in ft/s²:

lumped aerodynamic constant
\[ c_0 = 0.07182\;\rho_{\text{imp}}\;\frac{m_{\text{ref}}}{m}\left(\frac{C}{C_{\text{ref}}}\right)^{2} \]

\(\rho_{\text{imp}}\) is density in lb/ft³, \(m\) the ball mass (1.62 oz), \(C\) its circumference (5.277 in), and \(m_{\text{ref}}=5.125\) oz, \(C_{\text{ref}}=9.125\) in are libgolf's reference normalizers.

Reynolds number reference

Air viscosity follows Sutherland's law; a reference Reynolds number is taken at 100 mph and then scaled by the instantaneous speed during flight:

Sutherland viscosity & reference Reynolds number
\[ \mu = \frac{1.512\times10^{-6}\,T_K^{1.5}}{T_K + 120}, \qquad Re_{100} = \frac{\rho\,(44.7)\,d}{\mu} \]

\(d\) is the ball diameter in metres. During flight the working Reynolds number scales linearly with speed: \(Re = (v_{\text{mph}}/100)\,Re_{100}\).

Launch velocity and spin vectors

With launch angle \(\theta\), direction \(\psi\), and ball speed \(v_0\) (converted to ft/s), the initial velocity is

launch velocity vector (ft/s) — x lateral, y downrange, z vertical
\[ \mathbf{v}_0 = v_0\big(\cos\theta\sin\psi,\;\cos\theta\cos\psi,\;\sin\theta\big) \]

and the spin vector is built from backspin \(\omega_b\) and sidespin \(\omega_s\) (rpm → rad/s):

spin vector (rad/s)
\[ \boldsymbol{\omega} = \tfrac{\pi}{30}\big(\omega_b\cos\psi - \omega_s\sin\theta\sin\psi,\;\; -\omega_b\sin\psi - \omega_s\sin\theta\cos\psi,\;\; \omega_s\cos\theta\big) \]

04The forces in flight

Once airborne, three accelerations act on the ball: gravity, aerodynamic drag (opposing motion), and the Magnus force (from spin, perpendicular to motion — this is what curves the ball and holds it up).

Drag

Drag points opposite the ball's velocity relative to the air, \(\mathbf{v}_{\text{rel}}=\mathbf{v}-\mathbf{w}\) (with wind \(\mathbf{w}\)):

drag acceleration (ft/s²)
\[ \mathbf{a}_{\text{drag}} = -\,c_0\,C_d\,\lVert\mathbf{v}_{\text{rel}}\rVert\;\mathbf{v}_{\text{rel}} \]

Magnus (lift)

The Magnus acceleration is proportional to the lift coefficient and to the cross product of spin and velocity — a full 3D treatment, which is exactly why sidespin and a tilted spin axis produce slice/hook curvature, not just height:

Magnus acceleration (ft/s²)
\[ \mathbf{a}_{\text{Magnus}} = c_0\,\frac{C_l}{\lVert\boldsymbol{\omega}\rVert}\,\lVert\mathbf{v}_{\text{rel}}\rVert\;\big(\boldsymbol{\omega}\times\mathbf{v}_{\text{rel}}\big) \]

Total acceleration

net acceleration each step
\[ \mathbf{a} = \mathbf{a}_{\text{drag}} + \mathbf{a}_{\text{Magnus}} - g\,\hat{\mathbf{z}}, \qquad g = 32.174\ \text{ft/s}^2 \]

Spin decay

Spin bleeds off exponentially in flight with a speed-dependent time constant:

spin decay per step
\[ \tau = \frac{r}{\lambda\,v},\quad \lambda=2\times10^{-5}; \qquad \boldsymbol{\omega} \leftarrow \boldsymbol{\omega}\,e^{-\Delta t/\tau} \]

05The drag & lift coefficients

\(C_d\) and \(C_l\) are not constants — they depend on the Reynolds number \(Re\) (binned, in units of \(10^5\)) and the spin ratio \(S = \omega r / v\). These fits trace to dimpled-sphere wind-tunnel data (Bearman & Harvey) and a Washington State University study (Lyu et al.), as used by Nathan's trajectory calculator.

Drag coefficient

C_d — piecewise in Reynolds, with a spin term
\[ C_d = \begin{cases} 0.500 + 0.180\,S, & Re \le 0.5\\[4pt] 0.500 - 0.300\,\dfrac{Re-0.5}{0.5} + 0.180\,S, & 0.5 < Re < 1.0\\[8pt] 0.200 + 0.180\,S, & Re \ge 1.0 \end{cases} \]

A faster ball (higher \(Re\)) has lower drag — the classic "drag crisis" of a dimpled sphere — and more spin adds a little drag.

Lift coefficient

\(C_l\) interpolates between four spin-ratio polynomials keyed to Reynolds bins (\(Re\) at 50k, 60k, 65k, 70k), capped by a spin-dependent maximum \(C_{l,\max}\):

lift polynomials (argument is spin ratio S)
\[ \begin{aligned} C_l^{50k}(S) &= 0.0472 + 2.848\,S - 23.434\,S^2 + 45.485\,S^3\\ C_l^{60k}(S) &= 0.3205 - 4.703\,S + 14.061\,S^2\\ C_l^{65k}(S) &= 0.2667 - 4.000\,S + 13.333\,S^2\\ C_l^{70k}(S) &= 0.0496 + 0.00211\,S + 2.342\,S^2 \end{aligned} \]

Below \(Re=0.3\) there is no lift; above \(Re=0.7\) a saturating spin-gain form is used; in between the model blends the bracketing polynomials linearly. The cap rises with spin ratio:

spin-dependent lift ceiling and high-Re form
\[ C_{l,\max}(S) = \begin{cases}0.268, & S\le0.35\\ \text{lerp to }0.320, & 0.35
Reynolds bin (×10⁵)Lift behaviour
Re ≤ 0.3no lift (\(C_l = 0\))
0.3 – 0.5smoothstep ramp into \(C_l^{50k}\)
0.5 – 0.7linear blend across the 50k / 60k / 65k / 70k polynomials
Re ≥ 0.7saturating form \(C_{l,\max}\cdot 16S/(1+16S)\)

06Integrating the trajectory

With the forces defined, the ball's path is advanced in small time steps using semi-implicit (symplectic) Euler integration — velocity is updated, then position uses the updated terms. The step is dt = 0.01 s.

per-step update
\[ \mathbf{x} \leftarrow \mathbf{x} + \mathbf{v}\,\Delta t + \tfrac{1}{2}\mathbf{a}\,\Delta t^2, \qquad \mathbf{v} \leftarrow \mathbf{v} + \mathbf{a}\,\Delta t \]

Each step: decay the spin, recompute \(Re\) and \(S\), look up \(C_d\) and \(C_l\), form the net acceleration, and advance. The loop ends when the ball crosses the ground (\(z\le0\)); the exact landing point is found by linear interpolation across that final step. From the path the model reads off:

  • Carry — downrange distance at first landing
  • Apex — maximum height reached
  • Lateral — sideways deviation at landing (curvature from spin)
  • Descent angle — flight-path angle at landing
  • Flight time — used to pace the 3D animation in real time

07Bounce & roll (the roll-out)

For total distance, the model continues past landing through bounce and roll on a fairway-like surface. The bounce uses the Penner (2003) model: a spin-and-velocity-dependent coefficient of restitution governs the vertical rebound, while the tangential response depends on impact angle.

effective restitution at impact
\[ e_{\text{eff}} = e_0\big(1 - f_{\text{spin}}(\omega)\,f_{\text{vel}}(v_\perp)\big) \]

A steep, energetic impact with high backspin produces the spin-back / check you see on wedges, via a tangential spin-back term:

Penner tangential speed after a steep, energetic bounce
\[ v_{t}' = R_{\text{ret}}\,v\,\sin(\alpha-\alpha_c) - \frac{2\,r\,\omega_{\text{back}}}{7} \]

\(\alpha\) is the impact angle, \(\alpha_c=15^\circ\) the surface's critical angle, \(R_{\text{ret}}\) a spin-scaled retention factor. Shallow or low-energy impacts instead release forward with simple friction. Once the ball is moving slowly enough, Coulomb friction rolls it to rest. This is why on the 3D page a wedge can roll backward while a 3 wood releases forward.

Carry (the first landing) does not depend on the ground surface at all — only the post-landing roll does. The default surface is a typical fairway (restitution 0.40, static/dynamic friction 0.50/0.20, firmness 0.80, spin retention 0.75).

08The one place we depart from the library

Every coefficient above is copied verbatim from the published library. There is exactly one addition: a small low-spin drag correction. The published \(C_d\) fit slightly over-drags in the low-spin-ratio regime (long fairway woods and low-spin drivers, \(S\) below ~0.20), where measured carries ran longer than the unmodified model predicted. We apply a smooth, drag-only reduction that fades in below \(S=0.20\) and saturates at \(S=0.06\):

low-spin drag correction (smoothstep ramp on spin ratio)
\[ C_d \leftarrow C_d\big(1 - 0.16\,\,\text{smoothstep}(u)\big),\qquad u = \frac{0.20 - S}{0.20 - 0.06},\quad S<0.20 \]

It is drag-only on purpose — adding lift instead fixed the distance but ballooned the apex into an unphysical shape. This single change improves bag-wide carry accuracy (RMSE ~5.95 → ~4.2 yd) and leaves every club at \(S\ge0.20\) — the entire 4-iron-through-wedge set — untouched. Setting the gain to zero restores the pure library model.

09Sources & provenance

The flight engine is a faithful JavaScript port of the aerial, bounce, and roll physics in libgolf by Gabriel DiFiore, whose in-air aerodynamics are based on the work of Prof. Alan M. Nathan (University of Illinois Urbana-Champaign). The drag and lift coefficient fits trace to dimpled-sphere wind-tunnel data (Bearman & Harvey) and a Washington State University study (Lyu et al.).

Coefficients are copied verbatim from libgolf's DefaultAerodynamicModel, DefaultBounceModel, DefaultRollModel, physics_constants, ShotPhysicsContext, and DefaultIntegrator — with the single documented low-spin drag tweak above. The bounce model follows Penner (2003).

ABSHERMETRICS · the model behind every curve
libgolf — github.com/gdifiore/libgolf · physics after Prof. Alan M. Nathan (U. Illinois)
Internal units are feet, ft/s, and rad/s; outputs are converted to yards and feet to match the rest of the site.