Ex 3.2 Modeling a Particle Projectile Trajectory Using OOP

This example was developed by Mr. P. Solver, who does a great job of explaining the problem and the program. This example begins at 16.30 in the linked youtube video. This segment begins at 16:30 of the video. The code below is almost identical to his code, with a few exceptions. The author indicates that this would be most appropriate to simulate the motion of a barrage of objects moving under the force of gravity.

Projectile Motion Problem

r0: the initial position of the projectile (x,y)
v0: the initial velocity of the projectile ($v_x$,$v_y$)
T: an array of times which generated using np.linspace()

Methods

get_peak_height: returns the maximum height of the projectile.
get_peak_time: returns the time at which the peak is reached.
get_peak_range: returns the x distance when the peak is reached.
get_range: returns the maximum distance traveled before hitting the ground.
get_range_time: returns the time when the projectile hits the ground.

Line 3-4 When describing the motion of a projectile in a gravitational field with no air friction, the only properties characterizing the motion are the initial position, the initial velocity, the gravitational constant and the array of times (T) over which we want to compute the position.

Lines 6-7 We pass two tuples to the object constructor reprenting the initial position and the initial velocity. In these statements we EXTRACT the two components of the initial position and the initial velocity.

Line 8 We must include the time array T in the attributes of the object.

Lines 9-10 introduces NEW VARIABLES NOT PASSED TO THE OBJECT CONSTRUCTOR. These represent the x and y positions at the time T. Since T is an array, x and y are arrays. This leads us to think about how we will eventually implement the four methods the author proposed in the statement of the problem.

Lines11-12 The first method we define is get_peak_height().The argument is self. Recalling that y is an array, we can use the Python function max() to find the largest value in that array. Of course doing this in the definition of the class and it's methods requires us to use self.y.

Lines 13-14 Here we define the method get_peak_range (the value of x when y reaches its maximum) What we want to do is look at the array of x values self.x and select the index for which y is a maximum. This is achieved using the Numpy function np.argmax(self.y), which passes the index of y for which y is max.

Lines 15-16 is the method used to find the peak time. Again, we use argmax(self.y) to find the index at which y is maximized.

Lines 17-20 Finally, we want to find the range when the projectile reaches y=0. However, we do not want to use the initial launch point for this. We will look only at values of y after it reaches the peak. By using the absolute value of y_after_peak, we know that we want the smallest value using np.argmin(np.abs(yafterpeak)).



Beginning at Line 22 we create a projectile object named p. We set its initial position [0,0] and initial velocity [5,6] all given in consistent units. We set the gravitational constant as 9.81 m/s^2 and define the array of times we will condider using T=np.linspace(0,2,500)) . Lines 26-39 plot the results. HOWEVER, by choosing an arbitrary time span, it is likely that the projectile will reach it's peak, come to the ground level, and mathematically keep moving with negative values of y. In order to avoid this, we will define new arrays x
and y. Using a for loop indexed over the range of values of the time increments, we append values computed by the object p.x and p.y to x and y_ as long as p.y is positive or zero. The remainder is pretty standard pyplot statements.

In [1]:
# Ex 3.2
import numpy as np
import csv
import matplotlib.pyplot as plt
class Projectile:
    def __init__(self,r0,v0,g,T):
        x0,y0=r0
        vx0,vy0=v0
        self.T=T
        self.x=x0+vx0*self.T
        self.y=y0+vy0*T-.5*g*self.T**2     
    def get_peak_height(self):
        return max(self.y)
    def get_peak_range(self):
        return self.x[np.argmax(self.y)]
    def get_peak_time(self):
        return self.T[np.argmax(self.y)]
    def get_hits_ground(self):
        x_after_peak=self.x[self.T>self.get_peak_time()]
        y_after_peak=self.y[self.T>self.get_peak_time()]
        return[x_after_peak[np.argmin(np.abs(y_afterpeak))]]
    
p= Projectile(r0=[0,0], 
               v0=[5,6],
               g=9.81,
               T=np.linspace(0,2,500)) 
y_=[]
x_=[]
for i in range(500):
    if(p.y[i]>=0):
        y_.append(p.y[i])
        x_.append(p.x[i])
plt.figure(figsize=(10,5))
plt.plot(x_,y_, 'blue')
plt.axhline(p.get_peak_height(), color='red', ls='--')
plt.axvline(p.get_peak_range(), color='red',ls='--')
plt.xlabel('x Position')
plt.ylabel('y Position')
plt.grid()
plt.show()
In [ ]: