Skip to content

Enhanced Launch Angle Estimation Design

ARCHIVED DOCUMENT

This is a historical design or implementation note, kept as a record of why the code is shaped the way it is. It describes the project as of the date in its filename and is not a guide to follow — commands, paths, and constants may no longer match the code. See the Archive index for current alternatives.

Problem

The camera-based launch angle measurement is fragile (Hough circle detection, depth estimation heuristics, lighting sensitivity). The fallback is a per-club lookup table that only uses ball speed, producing low-confidence estimates. Additionally, launch angle is never used in carry distance calculation -- it only affects the uncertainty band width.

Goal

Improve launch angle estimation using data we already collect (smash factor, spin rate), and wire launch angle into the carry distance model. Target: 3-5 degree accuracy for normal swings, with honest confidence signaling.

Design

1. Enhanced estimate_launch_angle()

Location: server.py (existing function)

Current inputs: club type, ball speed New inputs: club type, ball speed, club_speed (optional), spin_rpm (optional)

Smash factor adjustment: Smash factor (ball_speed / club_speed) indicates strike quality. For each club category, there's an optimal smash factor. Deviation from optimal shifts the launch angle estimate:

  • Low smash (thin/toe) -> lower launch. ~0.3-0.5 deg per 0.01 smash below optimal.
  • High smash (slight up-on-it for driver) -> slightly higher launch. ~0.2 deg per 0.01 above optimal.

Optimal smash factors by club category: - Driver: 1.48 - Fairway woods: 1.42-1.45 - Hybrids: 1.36-1.40 - Irons: 1.33-1.38 - Wedges: 1.20-1.25

Spin rate adjustment (when available): Spin correlates with launch angle. High spin + low smash = thin topped (very low launch). High spin + high smash = high-launching iron. Use spin deviation from optimal as a secondary signal, weighted less than smash factor.

Confidence model: - Ball speed only: 0.2 - Ball speed + smash factor: 0.35 - Ball speed + smash factor + spin: 0.5

2. Launch angle carry adjustment

Location: New function in launch_monitor.py

Each club has an optimal launch angle (from TrackMan data, already in the lookup table). Deviation from optimal costs carry:

  • Too low: -2.0 yards per degree below optimal (ball doesn't get enough height)
  • Too high: -1.5 yards per degree above optimal (ball balloons, less severe due to Magnus lift)
  • Cap: 10% max penalty to prevent wild swings from bad estimates
  • Apply confidence weighting: scale the adjustment by launch angle confidence so low-confidence estimates produce smaller corrections

3. Integration into Shot carry calculation

Wire into Shot.estimated_carry_yards and Shot.estimated_carry_range: - If launch angle is available, apply the angle-based carry adjustment - Update estimated_carry_range to reflect the tighter estimate when angle is known - Keep backward compatibility: no launch angle = current behavior unchanged

4. Unified carry estimation

Consider a single estimate_carry() that accepts all available inputs (ball speed, club, launch angle, spin, smash factor) and applies adjustments incrementally. This avoids the current pattern of separate estimate_carry_distance() and estimate_carry_with_spin() functions that don't compose.

Non-goals

  • No new hardware
  • No camera changes
  • No changes to the UI (it already displays launch angle)