论文简介
《基于碰撞模型的台球击球问题探究》一文由王新光、张晨斌、庹忠曜和陈伟共同撰写,发表于《大学物理实验》2025年第38卷第1期。该论文以台球运动中的击球问题为研究对象,通过建立物理模型,深入分析了台球碰撞过程中的力学原理,旨在为提高击球效率提供理论支持。张晨斌作为论文的作者之一,参与了整个研究过程,包括模型的建立、理论分析以及实验验证。论文中,他与其他作者共同探讨了台球运动中的碰撞问题,特别是球杆击球、白球与目标球碰撞以及白球与台边碰撞这三种情况。这些碰撞过程被近似视为理想的完全弹性碰撞,基于动量定理、转动定律、动量守恒定律和机械能守恒定律等物理原理,分析了击球时的力、碰撞角度与白球终态方位之间的关系。
一、击球动力学分析
1. 球与球的碰撞
以图1所示的单次出杆击球全过程为例,通过球杆击打白球,使其按照预定轨迹(蓝色线条)撞击目标球,使目标球沿着预定轨迹(黄色线条)入袋;白球在撞击目标球后按照预定轨迹(白色线条)继续运动并撞击台边,最终停止在预设终态位置(虚白球)。白球理想的终态方位是按照预设轨迹(红色虚线)下一击球的关键,它直接关系着选手能否连续使目标球入袋。
在台球运动中,球与球的碰撞是最常见的场景之一。论文中分析了球与球碰撞后的运动轨迹和速度变化。假设碰撞是完全弹性的,且不考虑滚动摩擦,台布的摩擦系数为 μ,母球半径为 r,质量为 m,转动惯量为 J=52mr2。在碰撞过程中,母球的运动轨迹可以近似为一条抛物线,其运动方程可以通过以下公式推导: vc=v+ω×r 其中,vc 是接触点的速度,v 是母球的质心速度,ω 是角速度,r 是半径向量。通过对上述方程的微分和受力分析,可以得到母球在滑动过程中的速度变化和摩擦力的方向。最终,母球的运动轨迹被证明是一条抛物线,这一结论也得到了实验的验证。
2. 杆与球的作用
在台球运动中,球杆击打母球是击球过程的关键环节。论文中对这一过程进行了详细的动力学分析,假设球杆的质量为 mc,母球的质量为 m,球杆关于质心的转动惯量为 Jc=3mch2,母球关于球心的转动惯量为 Jb=52mr2。其中,h 是球杆的长度,r 是母球的半径。
在球杆击打母球的过程中,根据动量定理和角动量定理,可以推导出母球的最终速度和角速度。假设球杆击打母球时,母球在 y 方向上的初始速度为 vy1,恢复系数为 ey,则母球在碰撞后的速度 vy2 和球杆的反向速度 vy 可以
在球杆击打母球的过程中,球杆对母球施加的冲量 IF 是影响母球运动状态的关键因素。假设球杆击打母球时的角度为 θ 和 ψ,球杆与水平面的夹角为 ϕ,则母球在 x 方向和 y 方向上的初始速度可以通过以下公式计算:
通过上述公式,可以建立球杆击打母球的动力学模型。球杆击打母球时,冲量 IF 的大小和方向直接影响母球的运动状态。论文中通过实验验证了这些公式的准确性,表明球杆击打母球后的速度和角速度可以通过上述公式进行精确预测。
二、数学模型建立
在论文中,球杆击打母球的动力学模型基于动量定理和角动量定理。关键公式如下:
-
母球在 y 方向上的速度变化:
vy2=vy1⋅m+mcmey−mc -
球杆在 y 方向上的反向速度:
vy=vy1⋅m+mcmc(1+ey) -
母球在 x 方向和 y 方向上的初始速度:
{vx=−mIFsinθcosψ+IFcosϕsinθsinψvy=mIFcosθcosϕ
这些公式描述了球杆击打母球后的速度变化,其中 m 是母球的质量,mc 是球杆的质量,ey 是恢复系数,IF 是球杆对母球施加的冲量,θ、ψ 和 ϕ 是击球角度。而为了模拟这些动力学过程,我们可以使用 Python 编写一个简单的程序。以下是一个完整的代码示例,包括必要的注释,以帮助理解每个步骤。
import numpy as np
# 定义常量
m = 0.17 # 母球质量,单位:千克
m_c = 0.5 # 球杆质量,单位:千克
e_y = 0.8 # 恢复系数
I_F = 1.0 # 球杆对母球施加的冲量,单位:牛顿·秒
theta = np.radians(30) # 击球角度,单位:弧度
psi = np.radians(45) # 击球角度,单位:弧度
phi = np.radians(10) # 球杆与水平面的夹角,单位:弧度
# 计算母球在 y 方向上的速度变化
def calculate_velocity_after_collision(v_y1, m, m_c, e_y):
v_y2 = v_y1 * (m * e_y - m_c) / (m + m_c)
v_y = v_y1 * (m_c * (1 + e_y)) / (m + m_c)
return v_y2, v_y
# 计算母球在 x 和 y 方向上的初始速度
def calculate_initial_velocity(I_F, m, theta, psi, phi):
v_x = -(I_F * np.sin(theta) * np.cos(psi) + I_F * np.cos(phi) * np.sin(theta) * np.sin(psi)) / m
v_y = (I_F * np.cos(theta) * np.cos(phi)) / m
return v_x, v_y
# 主程序
if __name__ == "__main__":
# 假设母球在 y 方向上的初始速度为 0
v_y1 = 0.0
# 计算碰撞后的速度
v_y2, v_y = calculate_velocity_after_collision(v_y1, m, m_c, e_y)
print(f"母球在 y 方向上的速度变化:v_y2 = {v_y2:.2f} m/s")
print(f"球杆在 y 方向上的反向速度:v_y = {v_y:.2f} m/s")
# 计算母球的初始速度
v_x, v_y = calculate_initial_velocity(I_F, m, theta, psi, phi)
print(f"母球在 x 方向上的初始速度:v_x = {v_x:.2f} m/s")
print(f"母球在 y 方向上的初始速度:v_y = {v_y:.2f} m/s")
运行上述代码后,程序将输出母球在 y 方向上的速度变化、球杆的反向速度以及母球在 x 方向和 y 方向上的初始速度。这些结果可以帮助我们更好地理解球杆击打母球后的动力学过程。
三、物理模型的优化
1.加入摩擦力和滚动效应
在实际台球运动中,摩擦力对球的运动轨迹和速度衰减有显著影响。可以引入滚动摩擦系数和滑动摩擦系数,分别计算球在滚动和滑动阶段的速度变化。
滚动摩擦可以通过以下公式进行简化计算:
Froll=μroll⋅m⋅g
其中,μroll 是滚动摩擦系数,m 是球的质量,g 是重力加速度。然后根据牛顿第二定律,计算球的速度变化。
滑动摩擦可以通过类似的方式计算,但需要考虑球的初始速度和摩擦力的方向。当球的速度减小到一定程度时,球会从滑动状态转变为滚动状态,需要在代码中加入状态转换的逻辑。
2.考虑空气阻力
在高速运动时,空气阻力会对球的轨迹产生影响。可以引入空气阻力公式:
Fdrag=21⋅Cd⋅ρ⋅A⋅v2
其中,Cd 是阻力系数,ρ 是空气密度,A 是球的截面积,v 是球的速度。根据空气阻力的方向(与速度方向相反),在牛顿第二定律中加入空气阻力项,更新球的速度和位置。
3.更复杂的碰撞模型
目前的模型假设完全弹性碰撞,但实际上台球碰撞可能更接近非弹性碰撞。可以引入恢复系数 e 的变化,使其根据碰撞的具体情况(如碰撞角度、球的材质等)动态调整。
考虑球的形变和能量损失。在碰撞过程中,球会发生微小的形变,导致部分机械能转化为内能。可以通过引入能量损失因子来模拟这种现象,从而更准确地描述碰撞后的速度和运动轨迹。
四、代码结构的优化
1.面向对象编程
将球、球杆、台球桌等元素定义为类。例如,创建一个 Ball
类,包含球的质量、半径、位置、速度、角速度等属性,以及运动和碰撞的方法。创建一个 Cue
类,表示球杆,包含球杆的质量、长度、击球角度等属性,以及击打球的方法。
import numpy as np
class Ball:
def __init__(self, mass, radius, position, velocity, angular_velocity):
self.mass = mass # 质量
self.radius = radius # 半径
self.position = np.array(position) # 位置向量
self.velocity = np.array(velocity) # 速度向量
self.angular_velocity = np.array(angular_velocity) # 角速度向量
def update_position(self, dt):
"""根据速度更新位置"""
self.position += self.velocity * dt
def update_velocity(self, acceleration, dt):
"""根据加速度更新速度"""
self.velocity += acceleration * dt
def apply_friction(self, friction_coefficient, dt):
"""应用摩擦力"""
friction_force = -friction_coefficient * self.velocity
acceleration = friction_force / self.mass
self.update_velocity(acceleration, dt)
def collide_with_ball(self, other_ball, restitution_coefficient):
"""球与球的碰撞"""
relative_position = self.position - other_ball.position
distance = np.linalg.norm(relative_position)
if distance < self.radius + other_ball.radius:
# 计算碰撞后的速度
normal = relative_position / distance
relative_velocity = self.velocity - other_ball.velocity
impulse = (1 + restitution_coefficient) * self.mass * other_ball.mass / (self.mass + other_ball.mass)
impulse *= np.dot(relative_velocity, normal) / distance
self.velocity -= impulse * normal / self.mass
other_ball.velocity += impulse * normal / other_ball.mass
创建一个 Table
类,表示台球桌,包含桌的尺寸、摩擦系数等属性,以及检测球是否出界、碰撞台边等方法。通过面向对象的方式,代码的结构更加清晰,易于扩展和维护。
2.模块化设计
将不同的功能封装成独立的模块。例如,将物理计算(如碰撞计算、摩擦力计算等)封装成一个模块,将图形绘制(如果需要可视化)封装成另一个模块。
class Cue:
def __init__(self, mass, length):
self.mass = mass # 质量
self.length = length # 长度
def strike_ball(self, ball, impulse, angle):
"""击打球"""
# 假设球杆击打方向为 x 轴方向
ball.velocity += np.array([impulse / ball.mass, 0])
class Table:
def __init__(self, width, length, friction_coefficient):
self.width = width # 桌宽
self.length = length # 桌长
self.friction_coefficient = friction_coefficient # 摩擦系数
def check_collision_with_edges(self, ball):
"""检测球与台边的碰撞"""
if ball.position[0] - ball.radius < 0 or ball.position[0] + ball.radius > self.length:
ball.velocity[0] = -ball.velocity[0] # 反向 x 方向速度
if ball.position[1] - ball.radius < 0 or ball.position[1] + ball.radius > self.width:
ball.velocity[1] = -ball.velocity[1] # 反向 y 方向速度
这样可以提高代码的复用性,方便在其他项目中使用相同的物理计算模块,或者在需要时更换图形绘制模块(例如从简单的文本输出改为复杂的图形界面)。
3.优化算法性能
如果需要模拟大量球的运动(如斯诺克中的多球碰撞),可以优化碰撞检测算法。例如,使用空间划分技术(如四叉树、八叉树等)来快速检测哪些球之间可能发生碰撞,减少不必要的碰撞检测计算。
if __name__ == "__main__":
# 初始化台球桌
table = Table(width=1.5, length=3.0, friction_coefficient=0.01)
# 初始化母球和目标球
cue_ball = Ball(mass=0.17, radius=0.057, position=[1.5, 0.75], velocity=[0, 0], angular_velocity=[0, 0, 0])
target_ball = Ball(mass=0.17, radius=0.057, position=[1.0, 0.75], velocity=[0, 0], angular_velocity=[0, 0, 0])
# 初始化球杆
cue = Cue(mass=0.5, length=1.5)
# 模拟击球
cue.strike_ball(cue_ball, impulse=1.0, angle=0)
# 模拟时间步长
dt = 0.01 # 时间步长
total_time = 10.0 # 总模拟时间
for t in np.arange(0, total_time, dt):
# 更新母球位置
cue_ball.update_position(dt)
cue_ball.apply_friction(table.friction_coefficient, dt)
# 检测母球与台边的碰撞
table.check_collision_with_edges(cue_ball)
# 检测母球与目标球的碰撞
cue_ball.collide_with_ball(target_ball, restitution_coefficient=0.8)
# 更新目标球位置
target_ball.update_position(dt)
target_ball.apply_friction(table.friction_coefficient, dt)
# 检测目标球与台边的碰撞
table.check_collision_with_edges(target_ball)
# 打印当前状态
print(f"Time: {t:.2f} s")
print(f"Cue Ball Position: {cue_ball.position}")
print(f"Cue Ball Velocity: {cue_ball.velocity}")
print(f"Target Ball Position: {target_ball.position}")
print(f"Target Ball Velocity: {target_ball.velocity}")
对于复杂的运动轨迹计算,可以采用更高效的数值积分方法(如龙格 - 库塔法),以提高计算精度和效率。
五、功能的扩展
1.可视化
使用图形库(如 Matplotlib、Pygame 或 OpenGL)将台球的运动轨迹实时绘制出来。这样可以更直观地观察球的运动,帮助理解物理模型的效果。
可以绘制球的轨迹、速度向量、角速度向量等信息,还可以通过颜色变化表示速度的大小或球的状态(如滚动、滑动等)。
2.交互式模拟
开发一个交互式的台球模拟程序,允许用户通过鼠标或键盘输入击球的角度、力度等参数,实时观察球的运动结果。
可以为用户提供一些挑战性的任务,如要求用户击球使球进入指定的球洞,或者完成特定的球形排列,增加程序的趣味性和实用性。
3.数据分析与优化
收集模拟数据,分析不同击球参数(如角度、力度、球杆位置等)对球的运动轨迹和最终位置的影响。通过数据分析,为用户提供最佳击球策略的建议。
可以使用机器学习算法,根据大量的模拟数据训练一个模型,预测在给定的击球条件下球的运动结果,从而帮助用户优化击球技巧。
4.多球碰撞模拟
目前的模型主要关注单次碰撞,可以扩展到多球碰撞的情况。例如,在斯诺克或九球比赛中,经常出现多个球同时碰撞的情况。需要考虑多个球之间的相互作用,以及碰撞的顺序和时间间隔。
可以通过事件驱动的模拟方法,将每个碰撞事件作为一个独立的事件进行处理,按照时间顺序依次解决碰撞,从而模拟复杂的多球碰撞场景。