You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数值求解满足指定棒球飞行距离的最小初始速度

解决黑箱棒球飞行距离最小初始速度问题

问题本质

你需要解决的是带等式约束的极小化问题:固定自旋given_spin,找到最小初始速度v和对应发射角度θ,使得baseball(v, θ, given_spin) = target_d。核心思路是避开低效的角度遍历,利用优化算法和数值方法减少计算量。

高效解法一:拆分问题为两步优化(推荐)

第一步:对给定速度,找最大化飞行距离的角度

实际物理中,固定速度和自旋时,飞行距离随角度呈单峰分布(090度内有唯一最大值)。用**黄金分割搜索**(单峰函数极值的高效搜索法)替代`linspace`遍历,只需1020次函数调用就能找到最优角度。

import numpy as np
from scipy.optimize import golden

def get_max_distance_and_angle(v, spin):
    # 黄金分割默认找最小值,因此对距离取负
    def neg_flight_distance(theta):
        return -baseball(v, theta, spin)
    # 限定角度在[0, π/2](有效发射范围,排除向后抛的无效角度)
    optimal_theta = golden(neg_flight_distance, brack=(0, np.pi/2))
    max_d = baseball(v, optimal_theta, spin)
    return max_d, optimal_theta

第二步:单变量根查找找最小速度

最小速度的本质是:当速度为该值时,其能达到的最大飞行距离刚好等于目标target_d(速度再小就无法达到目标距离)。因此问题转化为找v使得get_max_distance_and_angle(v, spin)[0] - target_d = 0,用二分法或牛顿法求解:

from scipy.optimize import root_scalar

def find_speed(target_d, given_spin):
    def objective(v):
        max_d, _ = get_max_distance_and_angle(v, given_spin)
        return max_d - target_d
    
    # 确定搜索区间:先找到足够大的v_high,使得其最大距离超过目标
    v_low = 0.0
    v_high = 1.0
    while objective(v_high) < 0:
        v_high *= 2
    
    # 二分法找根,稳定可靠
    result = root_scalar(objective, bracket=[v_low, v_high], method='bisect')
    optimal_v = result.root
    _, optimal_theta = get_max_distance_and_angle(optimal_v, given_spin)
    return optimal_v, optimal_theta

高效解法二:直接约束优化(拉格朗日乘数法的数值实现)

如果想直接应用拉格朗日乘数法,可使用带等式约束的优化算法(如SLSQP),内部会自动处理拉格朗日乘数的数值求解:

from scipy.optimize import minimize

def find_speed_lagrange(target_d, given_spin):
    # 初始猜测:用无空气阻力时的近似解(速度√(g*d),角度45度)
    init_v = np.sqrt(target_d * 9.8)
    init_theta = np.pi/4
    initial_guess = [init_v, init_theta]
    
    # 目标函数:最小化初始速度
    def minimize_speed(x):
        v, theta = x
        return v
    
    # 等式约束:飞行距离等于目标值
    def distance_constraint(x):
        v, theta = x
        return baseball(v, theta, given_spin) - target_d
    
    # 变量边界:速度非负,角度限定在有效范围
    bounds = [(0.0, None), (0.0, np.pi/2)]
    constraints = ({'type': 'eq', 'fun': distance_constraint})
    
    # 求解约束优化
    result = minimize(minimize_speed, initial_guess, method='SLSQP', bounds=bounds, constraints=constraints)
    return result.x[0], result.x[1]

为什么这些方法比遍历高效?

  • 黄金分割搜索找最优角度的时间复杂度是O(log(ε)),ε是精度要求,远低于线性遍历的O(N)。
  • 单变量根查找或约束优化的迭代次数都在几十次以内,整体函数调用次数控制在几百次以内,而遍历角度+每个角度求解速度的组合会带来数千次甚至更多的函数调用。

内容的提问来源于stack exchange,提问作者panji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 00:34:55