Using the equations for modelling drag, and lift of a golf ball along with measured values of a ball's aerodynamic profile, we can create simple models of the golf ball's flight.
Throughout this document, we have taken data from academic studies to assume coefficients of drag for different types of ball. We have also taken data for average ball speeds and rotation from a professional golf tracking company.
These sources are listed at the bottom of the document.
Let's start with a very simple model of projectile motion, ignoring all air resistance. First we need to set up the environment in python,
import numpy
import matplotlib.pyplot as pyplot
Create a function to model the flight of a golf ball, ignoring the effects of aerodynamic drag,
def simpleTrajectory(u, theta_deg):
'''define the value for the acceleration due to gravity'''
g = 9.81
'''convert the angle to radians'''
theta_rad = numpy.radians(theta_deg)
'''use the angle to find the components of initial velocity'''
u_x = u * numpy.cos(theta_rad)
u_y = u * numpy.sin(theta_rad)
'''find the time when the ball will hit the floor'''
t_end = (2 * u_y) / g
'''create an array of points to sample'''
t = numpy.linspace(0, t_end, 30)
'''find the x, y, and z co-ordinates at each point'''
s_x = u_x * t
s_y = u_y * t - 0.5 * g * t ** 2
'''return the output arrays of points'''
return s_x, s_y
Plot the result of the model for a shot with initial velocty 40 m/s and launch angle 15 degrees.
initial_velocity = 40
launch_angle = 15
x_values = simpleTrajectory(initial_velocity, launch_angle)[0]
y_values = simpleTrajectory(initial_velocity, launch_angle)[1]
pyplot.plot(x_values, y_values, 'wo')
pyplot.xlim(0,100)
pyplot.ylim(0,20)
pyplot.gca().set_aspect('equal', adjustable='box')
pyplot.xlabel('Disance travelled (m)')
pyplot.ylabel('Height of the ball (m)')
pyplot.title('Simple trajectory model without drag')
pyplot.show()
print("The ball travelled ", x_values[-1], "m")
Drag in a situation is given by the equation: $$ F_{D}\,=\,{\tfrac {1}{2}}\,\rho \,v^{2}\,C_{D}\,A $$ where: $ F_{D}\ $ is the force exerted by drag, $ \rho $ is the density of the fluid in which the object is travelling, $ v $ is the velocity of the object, $ A $ is the cross-sectional area of the object, $ C_{D}\ $ is the coefficient of drag.
For a golf ball travelling through the air, we can assume the following values for $\rho$ and $ A $:
$\rho =$ 1.225 kg/m$^3$,
$ A = $ 1385.44 mm$^2$ or $=$0.001385m$^2$.
Finding the coefficient of drag is slightly more complex and involves analysing the ball's shape and surface texture. This is the variable that will change when we consider smooth and dimpled balls.
For the purpose of this simulation, we shall use a reference value for the values of the coefficient of drag for each the smooth and dimpled balls.
$C_{D} smooth = $ 0.45,
$C_{D} dimpled = $ 0.60.
def forceDrag(rho, v, C_D, area):
force = - 0.5 * rho * v ** 2 * C_D * area
return force
def dragTrajectory(u, theta_deg, C_D):
'''initialise variables'''
interval = 0.01
g = - 9.81
rho = 1.225
area = 0.00138
'''convert angles to radians'''
theta_rad = numpy.radians(theta_deg)
s_x = 0
s_y = 0
v_x = u * numpy.cos(theta_rad)
v_y = u * numpy.sin(theta_rad)
'''mass in kg'''
m = 0.045
a_x = forceDrag(rho, v_x, C_D, area)/m
a_y = (forceDrag(rho, v_y, C_D, area) )/m +g
'''intialise arrays'''
x_array = numpy.array([0])
y_array = numpy.array([0])
t_array = numpy.array([0])
count = 0
while s_y >= 0:
count = count + 1
time = count * interval
'''find the next point's position '''
s_x = s_x + v_x * interval + 0.5 * a_x * interval ** 2
s_y = s_y + v_y * interval + 0.5 * a_y * interval ** 2
'''find the new velocity at the next point'''
v_x = v_x + a_x * interval
v_y = v_y + a_y * interval
'''find the new acceleration'''
a_x = forceDrag(rho, v_x, C_D, area)/m
a_y = (forceDrag(rho, v_y, C_D, area) )/m +g
'''append data to arrays'''
x_array = numpy.append(x_array, s_x)
y_array = numpy.append(y_array, s_y)
t_array = numpy.append(t_array, time)
return x_array, y_array, t_array
Now, let's plot the path of the ball with drag against the one without drag.
initial_velocity = 40
launch_angle = 15
CD_smooth = 0.45
CD_dimpled = 0.2
x_values = simpleTrajectory(initial_velocity, launch_angle)[0]
y_values = simpleTrajectory(initial_velocity, launch_angle)[1]
x_values_drag_smooth = dragTrajectory(initial_velocity, launch_angle, CD_smooth)[0]
y_values_drag_smooth = dragTrajectory(initial_velocity, launch_angle, CD_smooth)[1]
x_values_drag_dimpled = dragTrajectory(initial_velocity, launch_angle, CD_dimpled)[0]
y_values_drag_dimpled = dragTrajectory(initial_velocity, launch_angle, CD_dimpled)[1]
pyplot.xlim(0,100)
pyplot.ylim(0,20)
pyplot.gca().set_aspect('equal', adjustable='box')
pyplot.plot(x_values, y_values, 'wo')
pyplot.plot(x_values_drag_smooth, y_values_drag_smooth, 'b')
pyplot.plot(x_values_drag_dimpled, y_values_drag_dimpled, 'g')
pyplot.xlabel('Distance travelled (m)')
pyplot.ylabel('Height of the ball (m)')
pyplot.title('Simple trajectory model with and without drag')
pyplot.show()
print("Distance travelled by ball with no drag :", x_values[-1], "m")
print("Distance travelled by smooth ball with drag :", x_values_drag_smooth[-1], "m")
print("Distance travelled by dimpled ball with drag :", x_values_drag_dimpled[-1], "m")
The average golfer will usually hit the ball with a spin rate of around 3275 RPM. [Trackman Golf Tracking] Assuming this rate of spin, lets look at how lift due to the Magnus effect factors in.
def liftTrajectory(u, theta_deg, C_D, spin_RPM):
'''initialise variables'''
interval = 0.01
g = - 9.81
rho = 1.225
area = 0.00138
'''convert angles to radians'''
theta_rad = numpy.radians(theta_deg)
'''find the magnitude of the lift force'''
lift_mag = 0.285 * (1-numpy.exp(-0.00026*spin_RPM))
s_x = 0
s_y = 0
v_x = u * numpy.cos(theta_rad)
v_y = u * numpy.sin(theta_rad)
'''mass in kg'''
m = 0.045
a_x = forceDrag(rho, v_x, C_D, area)/m
a_y = (forceDrag(rho, v_y, C_D, area) )/m +g
'''intialise arrays'''
x_array = numpy.array([0])
y_array = numpy.array([0])
t_array = numpy.array([0])
count = 0
while s_y >= 0:
count = count + 1
time = count * interval
'''find the next point's position '''
s_x = s_x + v_x * interval + 0.5 * a_x * interval ** 2
s_y = s_y + v_y * interval + 0.5 * a_y * interval ** 2
'''find the new velocity at the next point'''
v_x = v_x + a_x * interval
v_y = v_y + a_y * interval
'''find the components of lift'''
theta_i = numpy.arctan(v_y/v_x)
l_x = lift_mag * numpy.sin(theta_i)
l_y = lift_mag * numpy.cos(theta_i)
'''find the new acceleration'''
a_x = forceDrag(rho, v_x, C_D, area)/m + l_x/m
a_y = (forceDrag(rho, v_y, C_D, area) )/m +g +l_y/m
'''append data to arrays'''
x_array = numpy.append(x_array, s_x)
y_array = numpy.append(y_array, s_y)
t_array = numpy.append(t_array, time)
return x_array, y_array, t_array
initial_velocity = 40
launch_angle = 15
spin = 3275
CD_dimpled = 0.2
x_values = simpleTrajectory(initial_velocity, launch_angle)[0]
y_values = simpleTrajectory(initial_velocity, launch_angle)[1]
x_values_drag_dimpled = dragTrajectory(initial_velocity, launch_angle, CD_dimpled)[0]
y_values_drag_dimpled = dragTrajectory(initial_velocity, launch_angle, CD_dimpled)[1]
x_values_lift_dimpled = liftTrajectory(initial_velocity, launch_angle, CD_dimpled, spin)[0]
y_values_lift_dimpled = liftTrajectory(initial_velocity, launch_angle, CD_dimpled, spin)[1]
pyplot.xlim(0,120)
pyplot.ylim(0,15)
pyplot.gca().set_aspect('equal', adjustable='box')
pyplot.plot(x_values, y_values, 'wo')
pyplot.plot(x_values_lift_dimpled, y_values_lift_dimpled, 'b')
pyplot.plot(x_values_drag_dimpled, y_values_drag_dimpled, 'g')
pyplot.xlabel('Distance travelled (m)')
pyplot.ylabel('Height of the ball (m)')
pyplot.title('Simple trajectory model with and without drag')
pyplot.show()
print("Distance travelled by ball with no drag :", x_values[-1], "m")
print("Distance travelled by dimpled ball with drag :", x_values_drag_dimpled[-1], "m")
print("Distance travelled by dimpled ball with drag and lift :", x_values_lift_dimpled[-1], "m")
Golf ball launch speed, angle and spin - http://blog.trackmangolf.com/
Golf ball coefficients of drag - http://ac.els-cdn.com/S187770581100991X/1-s2.0-S187770581100991X-main.pdf?_tid=f8329444-f780-11e6-93f8-00000aacb362&acdnat=1487604577_286f8cb403c90b53497a2961ab3e35f4