2014-07-05 23:17:30 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
Created on Sat Jul 05 09:54:39 2014
|
|
|
|
|
|
|
|
@author: rlabbe
|
|
|
|
"""
|
|
|
|
|
|
|
|
from __future__ import division
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
from scipy.integrate import ode
|
2014-07-05 23:47:28 +02:00
|
|
|
import math
|
2014-07-05 23:17:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
class BallEuler(object):
|
|
|
|
def __init__(self, y=100., vel=10.):
|
|
|
|
self.x = 0.
|
|
|
|
self.y = y
|
|
|
|
self.vel = vel
|
|
|
|
self.y_vel = 0.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def step (self, dt):
|
|
|
|
|
|
|
|
g = -9.8
|
|
|
|
|
|
|
|
|
|
|
|
self.x += self.vel*dt
|
|
|
|
self.y += self.y_vel*dt
|
|
|
|
|
|
|
|
self.y_vel += g*dt
|
|
|
|
|
|
|
|
#print self.x, self.y
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rk4(y, x, dx, f):
|
|
|
|
"""computes 4th order Runge-Kutta for dy/dx.
|
|
|
|
y is the initial value for y
|
|
|
|
x is the initial value for x
|
|
|
|
dx is the difference in x (e.g. the time step)
|
|
|
|
f is a callable function (y, x) that you supply to compute dy/dx for
|
|
|
|
the specified values.
|
|
|
|
"""
|
|
|
|
|
|
|
|
k1 = dx * f(y, x)
|
|
|
|
k2 = dx * f(y + 0.5*k1, x + 0.5*dx)
|
|
|
|
k3 = dx * f(y + 0.5*k2, x + 0.5*dx)
|
|
|
|
k4 = dx * f(y + k3, x + dx)
|
|
|
|
|
|
|
|
return y + (k1 + 2*k2 + 2*k3 + k4) / 6
|
|
|
|
|
2014-07-05 23:47:28 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
def fx(x,t):
|
|
|
|
return fx.vel
|
2014-07-05 23:47:28 +02:00
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
def fy(y,t):
|
|
|
|
return fy.vel - 9.8*t
|
|
|
|
|
|
|
|
|
2014-07-05 23:17:30 +02:00
|
|
|
class BallRungeKutta(object):
|
2014-07-06 10:31:40 +02:00
|
|
|
def __init__(self, x=0, y=100., vel=10., omega = 0.0):
|
2014-07-05 23:47:28 +02:00
|
|
|
self.x = x
|
2014-07-05 23:17:30 +02:00
|
|
|
self.y = y
|
|
|
|
self.t = 0
|
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
omega = math.radians(omega)
|
2014-07-05 23:17:30 +02:00
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
fx.vel = math.cos(omega) * vel
|
|
|
|
fy.vel = math.sin(omega) * vel
|
2014-07-05 23:17:30 +02:00
|
|
|
|
2014-07-05 23:47:28 +02:00
|
|
|
def step (self, dt):
|
2014-07-06 10:31:40 +02:00
|
|
|
self.x = rk4 (self.x, self.t, dt, fx)
|
|
|
|
self.y = rk4 (self.y, self.t, dt, fy)
|
2014-07-07 06:15:16 +02:00
|
|
|
self.t += dt
|
|
|
|
return (self.x, self.y)
|
2014-07-05 23:17:30 +02:00
|
|
|
|
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
def ball_scipy(y0, vel, omega, dt):
|
2014-07-05 23:47:28 +02:00
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
vel_y = math.sin(math.radians(omega)) * vel
|
|
|
|
|
|
|
|
def f(t,y):
|
|
|
|
return vel_y-9.8*t
|
|
|
|
|
|
|
|
solver = ode(f).set_integrator('dopri5')
|
|
|
|
solver.set_initial_value(y0)
|
|
|
|
|
|
|
|
ys = [y0]
|
|
|
|
while brk.y >= 0:
|
|
|
|
t += dt
|
|
|
|
brk.step (dt)
|
2014-07-05 23:47:28 +02:00
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
ys.append(solver.integrate(t))
|
|
|
|
|
|
|
|
|
2014-07-05 23:17:30 +02:00
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
|
|
dt = 1./30
|
|
|
|
y0 = 15.
|
|
|
|
vel = 100.
|
2014-07-06 10:31:40 +02:00
|
|
|
omega = 0.
|
2014-07-05 23:47:28 +02:00
|
|
|
vel_y = math.sin(math.radians(omega)) * vel
|
|
|
|
|
|
|
|
def f(t,y):
|
|
|
|
return vel_y-9.8*t
|
|
|
|
|
2014-07-05 23:17:30 +02:00
|
|
|
be = BallEuler (y=y0, vel=vel)
|
2014-07-06 10:31:40 +02:00
|
|
|
ball_rk = BallRungeKutta (y=y0, vel=vel, omega=omega)
|
2014-07-05 23:17:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
while be.y >= 0:
|
|
|
|
be.step (dt)
|
2014-07-06 10:31:40 +02:00
|
|
|
ball_rk.step(dt)
|
|
|
|
|
|
|
|
plt.scatter (be.x, be.y, color='red')
|
2014-07-05 23:17:30 +02:00
|
|
|
|
2014-07-06 10:31:40 +02:00
|
|
|
plt.scatter (ball_rk.x, ball_rk.y, color='blue', marker='v')
|
|
|
|
#plt.scatter (brk.x, y[0], color='green', marker='+')
|
|
|
|
#plt.axis('equal')
|