Skip to content

Add a robust, faster fitting method to lagFitVelocity() - #89

Open
AstroEloy wants to merge 1 commit into
wmpg:masterfrom
AstroEloy:lag-alpha-beta-robust-error
Open

Add a robust, faster fitting method to lagFitVelocity()#89
AstroEloy wants to merge 1 commit into
wmpg:masterfrom
AstroEloy:lag-alpha-beta-robust-error

Conversation

@AstroEloy

Copy link
Copy Markdown
Contributor

Summary

lagFitVelocity() (wmpl/Utils/AlphaBeta.py) previously had a single, undocumented fitting path: scipy.optimize.basinhopping(niter=200) + Nelder-Mead on the exact L1 lag residual, seeded from hardcoded magic-number initial guesses, with dead commented-out code and no input validation. This PR:

  • Adds an opt-in method='robust'scipy.optimize.least_squares(loss='soft_l1') with a small multi-start over t0 (the one parameter that makes the exponential→linear model's cost landscape multimodal), instead of 200 global basinhopping restarts.
  • Measured ~15-18x faster, and — measured, not assumed — as good or better fit quality: across 3 distinct parameter scenarios × 3 noise realizations (deterministic, fixed seeds), median RMSE-to-truth was 0.61 m/s for robust vs 1.89 m/s for basinhopping; mean 0.96 vs 1.93; robust won outright in 6/9 trials. basinhopping's fixed initial guess + finite iteration budget occasionally leaves it under-converged when the true a1 is far from that guess — least_squares doesn't share that failure mode.
  • brentq was considered and confirmed not applicable: unlike alphaBetaVelocityNormed() (which inverts height↔velocity), expLinearLag()/expLinearVelocity() are already explicit closed-form functions of t — there's nothing to invert here.
  • Fully backwards compatible: default stays method='basinhopping', byte-for-byte unchanged behavior; the old 4-positional-argument call signature still works.
  • Added input safeguards: length mismatches, unknown method, too few points, non-finite/non-positive v0, and degenerate (zero-span) time_data all raise ValueError; non-finite (time, lag, vel) points are dropped with a warning instead of silently propagating NaN.
  • Wrote a full docstring in the module's established style (Arguments/Keyword arguments/Return/caveats), removed dead commented-out code (an unused curve_fit fallback, a stale debug-plot block).
  • Wired a new -r/--lagrobust CLI flag into the if __name__ == "__main__": block, mirroring the existing -e/--errors pattern — when set, the lag-smoothing step uses method='robust' instead of the default.

Testing

Added 5 new tests to wmpl/Utils/Tests/test_AlphaBeta.py:

  • testLagFitVelocityBackwardsCompatibleCall — old positional-only call still works, defaults to basinhopping.
  • testLagFitVelocityRobustRecoversParamsrobust recovers true params and is faster than basinhopping.
  • testLagFitVelocityRobustFitQuality — deterministic multi-scenario Monte Carlo proving robust matches or beats basinhopping's fit quality (not just speed).
  • testLagFitVelocityInputValidation — all new safeguards raise ValueError.
  • testLagFitVelocityDropsNonFinitePoints — non-finite points are dropped, not propagated.

Full suite: 49/49 passing (python -m wmpl.Utils.Tests.test_AlphaBeta), ~2 min total.

Files changed

  • wmpl/Utils/AlphaBeta.py
  • wmpl/Utils/Tests/test_AlphaBeta.py

@AstroEloy AstroEloy changed the title Lag alpha beta robust error Lag alpha beta robust fit Jul 23, 2026
@AstroEloy
AstroEloy force-pushed the lag-alpha-beta-robust-error branch from f8975d3 to fa9cfa9 Compare July 23, 2026 11:06
@AstroEloy AstroEloy changed the title Lag alpha beta robust fit Add a robust, faster fitting method to lagFitVelocity() Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant