#!/usr/bin/env python # coding: utf-8 # # # # # Throw into the Wind with Air Drag # # ### Examples - Mechanics #
# By Magnus A. Gjennestad, Vegard Hagen, Aksel Kvaal, Morten Vassvik, Trygve B. Wiig and Peter Berg #
# Last edited: March 15th 2018 # ___ # In this example we will study the trajectory of a ball that is moving through the air, subject to air drag and wind. We expect the optimal angle to change compared to no drag and/or no wind, meaning the angle under which we can throw the ball the furthest for a given launch speed. # Let us apply Newton’s law and solve the governing equations numerically. In particular, we launch a ball at the origin within the $xy$-plane at an angle $\theta$ with the horizontal and initial speed $v_0$. # ### Governing Equations # Newton's second law states that # $$\vec{F} = m\vec{a},$$ # where $\vec{F}$ is the force acting on the ball, $\vec{a}$ is the acceleration, and $m$ is the mass of the ball. In this example there are two forces acting on the ball: the gravitational force # $$m\vec{g}$$ # and air drag # $$-\frac{\rho}{2}C_DA\left|\vec{v}-\vec{V}\right|\left(\vec{v}-\vec{V}\right),$$ # where $\rho$ is the air density, $A$ the ball’s projected area, $\vec{v}$ the # velocity of the ball, $\vec{V}$ the wind speed, and $C_D\sim 0.47$ the friction coefficient. # This equation is only accurate for objects that move fast enough to generate turbulence. In this case the drag is proportional to the square of the relative velocity. A baseball thrown at over 80 mph is a good example. # In contrast, for slow, non-turbulent motion # $$− 6 \pi \eta R \left(\vec{v} − \vec{V} \right)$$ # is a good model to describe the drag, where $\eta$ is the air’s viscosity and $R$ the ball’s radius. This is called Stokes’ law and can be found in most college-level textbooks on mechanical physics. # In a coordinate system where $x$ points horizontally along the ground and $y$ points vertically upwards, the governing equations become # $$ # \begin{align} # m\ddot{x} &= -\frac{\rho}{2}C_DA\left(\dot{x}-V_x\right)\left|\dot{\vec{r}}-\vec{V}\right|,\\ # m\ddot{y} &= -\frac{\rho}{2}C_DA\left(\dot{y}-V_y\right)\left|\dot{\vec{r}}-\vec{V}\right|-mg, # \end{align} # $$ # where $V_x$ and $V_y$ are the $x$ and $y$ components of the wind velocity, and # $$\left|\dot{\vec{r}}-\vec{V}\right| = \left[(\dot{x}-V_x)^2+(\dot{y}-V_y)^2\right]^{1/2}.$$ # For simplicity, we assume that $V_y = 0$, i.e. the wind only blows horizontally. # The one-dimensional governing equations are two second-order ordinary differential equations which can be written as four first-order differential equations in the following way: # $$ # \begin{align} # \dot{x} &= u,\\ # \dot{u} &= -\frac{\rho}{2m}C_DA\left(u-V_x\right)\left[(u-V_x)^2+w^2\right]^{1/2},\\ # \dot{y} &= w,\\ # \dot{w} &= -\frac{\rho}{2m}C_DAw\left[(u-V_x)^2+w^2\right]^{1/2}-g # \end{align} # $$ # ### Discretization: Euler's Method # To solve the previous four equations numerically, we can discretize time: # $$t \rightarrow t_n = t_0 + n\Delta t,$$ # where $\Delta t$ is called the time step, and $n$ is the number of time steps. The derivative of $x$, for example, can then be approximated by # $$\dot{x} \approx \frac{x_{n+1}-x_n}{\Delta t}.$$ # Using Euler's method in this manner, the discretized version of the four first-order differential equations is # $$ # \begin{align} # x_{n+1} &= x_n + \Delta t \cdot u_n,\\ # u_{n+1} &= u_n - \Delta t \frac{\rho}{2m}C_DA\left(u-V_x\right)\left[(u-V_x)^2+w^2\right]^{1/2},\\ # y_{n+1} &= y_n + \Delta t \cdot w_n, \\ # w_{n+1} &= w_n - \Delta t \left[\frac{g+\rho}{2m}C_DAw\left[(u-V_x)^2+w^2\right]^{1/2}\right], # \end{align} # $$ # where $x_n = x(t_n)$, $u_n = u(t_n)$ etc. # #### Initial Conditions # We now need to decide on the initial conditions, i.e. $x_0$, $y_0$, $u_0$ and $w_0$ at $t_0 = 0$. If we assume that the throw starts at the origin, we get $x_0 = y_0 = 0$. We further assume that the throw is made with velocity $v_0$ at an angle $\theta$, with $\theta = 0^\circ$ being a throw along the horizontal (positive $x$) axis and $\theta = 90^\circ$ being a throw straight up. This gives us $u_0 = v_0 \cos \theta$ and $w_0 = v_0 \sin \theta$. # ### Implementation # First we import the relevant packages and set options for nicer plots. # In[1]: get_ipython().run_line_magic('matplotlib', 'inline') import numpy as np import matplotlib.pyplot as plt from matplotlib import rc newparams = {'figure.figsize': (15, 7), 'axes.grid': False, 'lines.markersize': 10, 'lines.linewidth': 2, 'font.size': 15, 'mathtext.fontset': 'stix', 'font.family': 'STIXGeneral'} plt.rcParams.update(newparams) # The following code uses Euler's method to calculate and plot the trajectory of a throw in wind. # In[3]: def ThrowInWind(v0, theta0, windX, dt, t_max, collisionCheck, plotOn): """ Function for simulation a throw in wind. Parameters: v0 # start velocity theta0 # throw angle (degrees) windX # wind velocity in the x-direction dt # length of time step t_max # maximum simulation time collisionCheck # Bool, only simulates until ball hits ground if True plotOn # Bool, generates plots if True Returns coordinates x and y. """ # Set values: g = 9.81 # Gravity m = 0.1 # Mass of the ball rad = 0.05 # Radius of the ball cd = 0.47 # Drag coefficient rho = 1.15 # Air density in kg/m^3 area = np.pi*rad**2 # Projected area of the ball k = rho*cd*area/(2*m) # Air drag n_max = int(t_max/dt) # Number of time steps x = np.zeros(n_max) u = np.zeros(n_max) y = np.zeros(n_max) w = np.zeros(n_max) theta0 = theta0*np.pi/180 # Convert throwing angle to radians x[0] = y[0] = 0 # Define starting position u[0] = v0*np.cos(theta0) # Initial velocity in x-direction w[0] = v0*np.sin(theta0) # Initial velocity in y-direction for n in range(n_max-1): drag = k*dt*np.sqrt((u[n]-windX)**2 + w[n]**2) x[n+1] = x[n] + dt*u[n] u[n+1] = u[n] - drag*(u[n]-windX) y[n+1] = y[n] + dt*w[n] w[n+1] = w[n] - g*dt - drag*w[n] if collisionCheck: if y[n+1] <= 0: x = x[0:n+2] y = y[0:n+2] break if plotOn: plt.plot(x,y) plt.legend(["Ball trajectory"]) plt.ylabel(r"$y$") plt.xlabel(r"$x$") if collisionCheck: plt.gca().set_ylim(bottom=0) return x,y # #### Optimal Launch Angle # The following code can be used to estimate the optimal launch angle. The plot generated below is for when there is no wind. # In[4]: thetas = np.linspace(30, 70, 9) for theta0 in thetas: x, y = ThrowInWind(v0=10, theta0=theta0, windX=0, dt=0.001, t_max=3, collisionCheck=True, plotOn=False) plt.plot(x,y,'--') plt.legend(thetas) plt.ylabel(r"$y$") plt.xlabel(r"$x$") plt.gca().set_ylim(bottom=0); # We see that the optimal angle is approximately $45^\circ$. How does this angle change when there is wind, especially head wind? # In[5]: thetas = np.linspace(30, 70, 9) for theta0 in thetas: x, y = ThrowInWind(v0=10, theta0=theta0, windX=-10, dt=0.001, t_max=3, collisionCheck=True, plotOn=False) plt.plot(x,y,'--') plt.legend(thetas) plt.ylabel(r"$y$") plt.xlabel(r"$x$") plt.gca().set_ylim(bottom=0); # We see that with a head wind with velocity $10$, the optimal angle is lower than $45^\circ$, approximately $35^\circ$. # ### Questions # - What role does the Time Step parameter play? What happens when this is set to high? # - Set the Simulation Time to 60 s. Can you explain why the ball’s path becomes linear? (hint: terminal velocity) # - Is it possible to make the ball do a loop-the-loop (a path that crosses itself)?