Spaces:
Sleeping
Sleeping
Commit
β’
7efe007
1
Parent(s):
aa651cf
Refactoring and adding simulator to README.md
Browse files- app/Disc Golf Simulator.py β Disc Golf Simulator.py +0 -0
- README.md +1 -1
- bootstrap.py +1 -1
- examples/disc_experimental_trajectory_comparison.py +0 -106
- examples/disc_golf_throw.py +0 -66
- examples/disc_gui2d.py +0 -105
- examples/driver.py +0 -35
- examples/validation_balls.py +0 -50
- examples/validation_spinning_ball.py +0 -48
- {utils β utilities}/disc_geometric_properties.py +0 -0
- {app β utilities}/extrema.py +0 -0
- {app β utilities}/get_disc.py +0 -0
- {app β utilities}/visualize.py +0 -0
app/Disc Golf Simulator.py β Disc Golf Simulator.py
RENAMED
File without changes
|
README.md
CHANGED
@@ -5,7 +5,7 @@ colorFrom: purple
|
|
5 |
colorTo: gray
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.17.0
|
8 |
-
app_file:
|
9 |
pinned: false
|
10 |
license: gpl-3.0
|
11 |
---
|
|
|
5 |
colorTo: gray
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.17.0
|
8 |
+
app_file: Disc Golf Simulator.py
|
9 |
pinned: false
|
10 |
license: gpl-3.0
|
11 |
---
|
bootstrap.py
CHANGED
@@ -3,7 +3,7 @@ import streamlit.web.bootstrap
|
|
3 |
from streamlit import config as _config
|
4 |
|
5 |
proj_dir = Path(__file__).parent
|
6 |
-
filename = proj_dir / "
|
7 |
|
8 |
_config.set_option("server.headless", True)
|
9 |
args = []
|
|
|
3 |
from streamlit import config as _config
|
4 |
|
5 |
proj_dir = Path(__file__).parent
|
6 |
+
filename = proj_dir / "Disc Golf Simulator.py"
|
7 |
|
8 |
_config.set_option("server.headless", True)
|
9 |
args = []
|
examples/disc_experimental_trajectory_comparison.py
DELETED
@@ -1,106 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
|
3 |
-
import sys
|
4 |
-
from shotshaper.projectile import DiscGolfDisc
|
5 |
-
import matplotlib.pyplot as pl
|
6 |
-
import numpy as np
|
7 |
-
import shotshaper.environment as env
|
8 |
-
from shotshaper.transforms import T_12
|
9 |
-
from random import uniform
|
10 |
-
|
11 |
-
|
12 |
-
def rotz(pos,betad):
|
13 |
-
beta = np.radians(betad)
|
14 |
-
TZ = np.array([[np.cos(beta), -np.sin(beta), 0],
|
15 |
-
[np.sin(beta), np.cos(beta), 0],
|
16 |
-
[0, 0, 1]])
|
17 |
-
|
18 |
-
return np.matmul(TZ,pos)
|
19 |
-
|
20 |
-
throws=[1,6,15]
|
21 |
-
|
22 |
-
nthrow = len(throws)
|
23 |
-
# pitch, roll, nose,speed,spin, yaw, wind, length
|
24 |
-
params = [[15.5, 21.8, 0.0, 24.7, 138, -31.6, 4.8, 89.7],
|
25 |
-
[12.3, 14.7, 0.8, 24.2, 128.5, -9.60, 4.8, 87.0],
|
26 |
-
[5.20,-0.70, 0.0, 24.5, 147.7, 8.00, 4.8, 106.6]]
|
27 |
-
|
28 |
-
|
29 |
-
d = DiscGolfDisc('dd2')
|
30 |
-
fig1, ax1 = pl.subplots( )
|
31 |
-
|
32 |
-
fig1.set_figheight(4)
|
33 |
-
fig1.set_figwidth(6)
|
34 |
-
|
35 |
-
for i in range(nthrow):
|
36 |
-
p = params[i]
|
37 |
-
t = throws[i]
|
38 |
-
U = p[3]
|
39 |
-
omega = p[4]
|
40 |
-
z0 = 1.5
|
41 |
-
pos = np.array((0,0,z0))
|
42 |
-
pitch = p[0]
|
43 |
-
yaw = p[5]
|
44 |
-
nose = p[2]
|
45 |
-
roll = p[1]
|
46 |
-
|
47 |
-
env.Uref = p[6]
|
48 |
-
env.winddir = np.array((1,0,0))
|
49 |
-
|
50 |
-
# Currently handle yaw by rotating the position after the throw, hence
|
51 |
-
# also need to rotate the wind vector accordingly
|
52 |
-
env.winddir = rotz(env.winddir, -yaw)
|
53 |
-
|
54 |
-
s = d.shoot(speed=U, omega=omega, pitch=pitch, position=pos, nose_angle=nose, roll_angle=roll)
|
55 |
-
|
56 |
-
pos = s.position
|
57 |
-
for j in range(len(pos[0,:])):
|
58 |
-
pos[:,j] = rotz(pos[:,j], yaw)
|
59 |
-
x,y,z = pos
|
60 |
-
arc,alphas,betas,lifts,drags,moms,rolls = d.post_process(s, omega)
|
61 |
-
|
62 |
-
# Plot trajectory
|
63 |
-
ax1.plot(x,y,f'C{i}-')
|
64 |
-
|
65 |
-
# Experiment
|
66 |
-
te,xe,ye,ve = np.loadtxt(f'data/throw{t}',skiprows=2,unpack=True)
|
67 |
-
ax1.plot(xe,ye,f'C{i}--')
|
68 |
-
|
69 |
-
ax1.set_xlabel('Distance (m)')
|
70 |
-
ax1.set_ylabel('Drift (m)')
|
71 |
-
ax1.axis('equal')
|
72 |
-
|
73 |
-
# Plot other parameters
|
74 |
-
|
75 |
-
# axes[0,0].plot(arc, lifts)
|
76 |
-
# axes[0,0].set_xlabel('Distance (m)')
|
77 |
-
# axes[0,0].set_ylabel('Lift force (N)')
|
78 |
-
|
79 |
-
# axes[0,1].plot(arc, drags)
|
80 |
-
# axes[0,1].set_xlabel('Distance (m)')
|
81 |
-
# axes[0,1].set_ylabel('Drag force (N)')
|
82 |
-
|
83 |
-
# axes[0,2].plot(arc, moms)
|
84 |
-
# axes[0,2].set_xlabel('Distance (m)')
|
85 |
-
# axes[0,2].set_ylabel('Moment (Nm)')
|
86 |
-
|
87 |
-
# axes[1,0].plot(arc, alphas)
|
88 |
-
# axes[1,0].set_xlabel('Distance (m)')
|
89 |
-
# axes[1,0].set_ylabel('Angle of attack (deg)')
|
90 |
-
|
91 |
-
# axes[1,1].plot(arc, s.velocity[0,:])
|
92 |
-
# axes[1,1].plot(arc, s.velocity[1,:])
|
93 |
-
# axes[1,1].plot(arc, s.velocity[2,:])
|
94 |
-
# axes[1,1].set_xlabel('Distance (m)')
|
95 |
-
# axes[1,1].set_ylabel('Velocities (m/s)')
|
96 |
-
|
97 |
-
# axes[1,2].plot(arc, rolls)
|
98 |
-
# axes[1,2].set_xlabel('Distance (m)')
|
99 |
-
# axes[1,2].set_ylabel('Roll rate (rad/s)')
|
100 |
-
|
101 |
-
pl.tight_layout()
|
102 |
-
pl.show()
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/disc_golf_throw.py
DELETED
@@ -1,66 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""
|
3 |
-
Example showing a single disc throw.
|
4 |
-
"""
|
5 |
-
|
6 |
-
from shotshaper.projectile import DiscGolfDisc
|
7 |
-
import matplotlib.pyplot as pl
|
8 |
-
import numpy as np
|
9 |
-
import plotly.express as px
|
10 |
-
|
11 |
-
d = DiscGolfDisc('dd2')
|
12 |
-
U = 24.2
|
13 |
-
omega = 116.8
|
14 |
-
z0 = 1.3
|
15 |
-
pos = np.array((0,0,z0))
|
16 |
-
pitch = 15.5
|
17 |
-
nose = 0.0
|
18 |
-
roll = 14.7
|
19 |
-
|
20 |
-
shot = d.shoot(speed=U, omega=omega, pitch=pitch,
|
21 |
-
position=pos, nose_angle=nose, roll_angle=roll)
|
22 |
-
|
23 |
-
# Plot trajectory
|
24 |
-
pl.figure(1)
|
25 |
-
x,y,z = shot.position
|
26 |
-
pl.plot(x,y)
|
27 |
-
fig = px.scatter(x,y)
|
28 |
-
fig.show()
|
29 |
-
|
30 |
-
pl.xlabel('Distance (m)')
|
31 |
-
pl.ylabel('Drift (m)')
|
32 |
-
pl.axis('equal')
|
33 |
-
|
34 |
-
# Plot other parameters
|
35 |
-
arc,alphas,betas,lifts,drags,moms,rolls = d.post_process(shot, omega)
|
36 |
-
fig, axes = pl.subplots(nrows=2, ncols=3, dpi=80,figsize=(13,5))
|
37 |
-
|
38 |
-
axes[0,0].plot(arc, lifts)
|
39 |
-
axes[0,0].set_xlabel('Distance (m)')
|
40 |
-
axes[0,0].set_ylabel('Lift force (N)')
|
41 |
-
|
42 |
-
axes[0,1].plot(arc, drags)
|
43 |
-
axes[0,1].set_xlabel('Distance (m)')
|
44 |
-
axes[0,1].set_ylabel('Drag force (N)')
|
45 |
-
|
46 |
-
axes[0,2].plot(arc, moms)
|
47 |
-
axes[0,2].set_xlabel('Distance (m)')
|
48 |
-
axes[0,2].set_ylabel('Moment (Nm)')
|
49 |
-
|
50 |
-
axes[1,0].plot(arc, alphas)
|
51 |
-
axes[1,0].set_xlabel('Distance (m)')
|
52 |
-
axes[1,0].set_ylabel('Angle of attack (deg)')
|
53 |
-
|
54 |
-
axes[1,1].plot(arc, shot.velocity[0,:])
|
55 |
-
axes[1,1].plot(arc, shot.velocity[1,:])
|
56 |
-
axes[1,1].plot(arc, shot.velocity[2,:])
|
57 |
-
axes[1,1].set_xlabel('Distance (m)')
|
58 |
-
axes[1,1].set_ylabel('Velocities (m/s)')
|
59 |
-
axes[1,1].legend(('u','v','w'))
|
60 |
-
|
61 |
-
axes[1,2].plot(arc, rolls)
|
62 |
-
axes[1,2].set_xlabel('Distance (m)')
|
63 |
-
axes[1,2].set_ylabel('Roll rate (rad/s)')
|
64 |
-
pl.tight_layout()
|
65 |
-
|
66 |
-
pl.show()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/disc_gui2d.py
DELETED
@@ -1,105 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""
|
3 |
-
Graphical user interface to explore the influence
|
4 |
-
of disc throw parameters on the trajectory
|
5 |
-
"""
|
6 |
-
|
7 |
-
import numpy as np
|
8 |
-
import matplotlib.pyplot as pl
|
9 |
-
from matplotlib.widgets import Slider, TextBox
|
10 |
-
from shotshaper.projectile import DiscGolfDisc
|
11 |
-
|
12 |
-
name = 'dd2'
|
13 |
-
mass = 0.175
|
14 |
-
|
15 |
-
d = DiscGolfDisc(name, mass=mass)
|
16 |
-
speed = 24
|
17 |
-
omega = d.empirical_spin(speed)
|
18 |
-
z0 = 1.3
|
19 |
-
pos = np.array((0,0,z0))
|
20 |
-
pitch = 10
|
21 |
-
nose = 0.0
|
22 |
-
roll = 15.0
|
23 |
-
yaw = 0
|
24 |
-
adjust_axes = False
|
25 |
-
|
26 |
-
s = d.shoot(speed=speed, omega=omega, pitch=pitch, position=pos, nose_angle=nose, roll_angle=roll,yaw=yaw)
|
27 |
-
|
28 |
-
x,y,z = s.position
|
29 |
-
|
30 |
-
# Creating figure
|
31 |
-
fig = pl.figure(1,figsize=(13, 6), dpi=80)
|
32 |
-
ax1 = pl.subplot(2,3,2)
|
33 |
-
ax2 = pl.subplot(2,3,5)
|
34 |
-
ax3 = pl.subplot(1,3,3)
|
35 |
-
fac = 1.6
|
36 |
-
ylim = fac*max(abs(min(y)),abs(max(y)))
|
37 |
-
ax1.axis((min(x),fac*max(x),-ylim,ylim))
|
38 |
-
ax2.axis((min(x),fac*max(x),min(z),fac*max(z)))
|
39 |
-
ax3.axis((-ylim,ylim,min(z),fac*max(z)))
|
40 |
-
|
41 |
-
ax3.invert_xaxis()
|
42 |
-
|
43 |
-
l1, = ax1.plot(x,y,lw=2)
|
44 |
-
ax1.set_xlabel('Distance (m)')
|
45 |
-
ax1.set_ylabel('Drift (m)')
|
46 |
-
l2, = ax2.plot(x,z,lw=2)
|
47 |
-
ax2.set_xlabel('Distance (m)')
|
48 |
-
ax2.set_ylabel('Height (m)')
|
49 |
-
|
50 |
-
l3, = ax3.plot(y,z,lw=2)
|
51 |
-
ax3.set_xlabel('Drift (m)')
|
52 |
-
ax3.set_ylabel('Height (m)')
|
53 |
-
|
54 |
-
xax = 0.07
|
55 |
-
ax4 = pl.axes([xax, 0.80, 0.25, 0.03], facecolor='lightgrey')
|
56 |
-
ax5 = pl.axes([xax, 0.75, 0.25, 0.03], facecolor='lightgrey')
|
57 |
-
ax6 = pl.axes([xax, 0.70, 0.25, 0.03], facecolor='lightgrey')
|
58 |
-
#ax7 = pl.axes([xax, 0.65, 0.25, 0.03], facecolor='lightgrey')
|
59 |
-
ax8 = pl.axes([xax, 0.65, 0.25, 0.03], facecolor='lightgrey')
|
60 |
-
ax9 = pl.axes([xax, 0.60, 0.25, 0.03], facecolor='lightgrey')
|
61 |
-
ax11 = pl.axes([xax, 0.55, 0.25, 0.03], facecolor='lightgrey')
|
62 |
-
|
63 |
-
s1 = Slider(ax=ax4, label='Speed (m/s)', valmin=15, valmax=35, valinit=speed)
|
64 |
-
s2 = Slider(ax=ax5, label='Roll (deg)', valmin=-110, valmax=110, valinit=roll)
|
65 |
-
s3 = Slider(ax=ax6, label='Pitch (deg)', valmin=-10, valmax=50, valinit=pitch)
|
66 |
-
s5 = Slider(ax=ax8, label='Nose (deg)', valmin=-5, valmax=5, valinit=nose)
|
67 |
-
s7 = Slider(ax=ax9, label='Mass (kg)', valmin=0.140, valmax=0.200, valinit=mass)
|
68 |
-
s6 = Slider(ax=ax11, label='Spin (-)', valmin=0, valmax=2, valinit=1.0)
|
69 |
-
|
70 |
-
def update(x):
|
71 |
-
speed = s1.val
|
72 |
-
roll = s2.val
|
73 |
-
pitch = s3.val
|
74 |
-
nose = s5.val
|
75 |
-
spin = s6.val
|
76 |
-
mass = s7.val
|
77 |
-
d = DiscGolfDisc(name,mass=mass)
|
78 |
-
|
79 |
-
omega = spin*d.empirical_spin(speed)
|
80 |
-
s = d.shoot(speed=speed, omega=omega, pitch=pitch, position=pos, nose_angle=nose, roll_angle=roll)
|
81 |
-
x,y,z = s.position
|
82 |
-
|
83 |
-
l1.set_xdata(x)
|
84 |
-
l1.set_ydata(y)
|
85 |
-
l2.set_xdata(x)
|
86 |
-
l2.set_ydata(z)
|
87 |
-
l3.set_xdata(y)
|
88 |
-
l3.set_ydata(z)
|
89 |
-
|
90 |
-
if adjust_axes:
|
91 |
-
ax1.axis((min(x),max(x),min(y),max(y)))
|
92 |
-
ax2.axis((min(x),max(x),min(z),max(z)))
|
93 |
-
ax3.axis((min(y),max(y),min(z),max(z)))
|
94 |
-
|
95 |
-
fig.canvas.draw_idle()
|
96 |
-
|
97 |
-
s1.on_changed(update)
|
98 |
-
s2.on_changed(update)
|
99 |
-
s3.on_changed(update)
|
100 |
-
s5.on_changed(update)
|
101 |
-
s6.on_changed(update)
|
102 |
-
s7.on_changed(update)
|
103 |
-
|
104 |
-
pl.show()
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/driver.py
DELETED
@@ -1,35 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""
|
3 |
-
Simple example comparing different projectiles.
|
4 |
-
"""
|
5 |
-
|
6 |
-
from shotshaper.projectile import _Particle, ShotPutBall, SoccerBall
|
7 |
-
import matplotlib.pyplot as pl
|
8 |
-
import numpy as np
|
9 |
-
|
10 |
-
U = 10.0
|
11 |
-
angle = 20.0
|
12 |
-
|
13 |
-
p = _Particle()
|
14 |
-
shot = p.shoot(speed=U, pitch=angle)
|
15 |
-
pl.plot(shot.position[0,:],shot.position[2,:])
|
16 |
-
|
17 |
-
p = ShotPutBall('M')
|
18 |
-
shot = p.shoot(speed=U, pitch=angle)
|
19 |
-
pl.plot(shot.position[0,:],shot.position[2,:])
|
20 |
-
|
21 |
-
p = SoccerBall()
|
22 |
-
|
23 |
-
spin = np.array((0,0,0))
|
24 |
-
shot = p.shoot(speed=U, pitch=angle, spin=spin)
|
25 |
-
pl.plot(shot.position[0,:],shot.position[2,:])
|
26 |
-
|
27 |
-
spin = np.array((0,-10,0))
|
28 |
-
shot = p.shoot(speed=U, pitch=angle, spin=spin)
|
29 |
-
pl.plot(shot.position[0,:],shot.position[2,:])
|
30 |
-
|
31 |
-
pl.legend(('vacuum','air', 'no spin','spin'))
|
32 |
-
|
33 |
-
pl.show()
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/validation_balls.py
DELETED
@@ -1,50 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""
|
3 |
-
This program calculates trajectories that were experimentally conducted in
|
4 |
-
|
5 |
-
Mencke, J. E., Salewski, M., Trinhammer, O. L., & Adler, A. T. (2020).
|
6 |
-
Flight and bounce of spinning sports balls. American Journal of Physics,
|
7 |
-
88(11), 934-947.
|
8 |
-
|
9 |
-
Specifically, this includes data for:
|
10 |
-
- a shot put throw, representing a heavy projectile where the
|
11 |
-
gravitational forces dominate over the aerodynamic forces
|
12 |
-
- a soccer ball, with slightly more influence of air drag
|
13 |
-
- a table tennis ball, significantly impacted by air drag due
|
14 |
-
to low weight
|
15 |
-
"""
|
16 |
-
|
17 |
-
from shotshaper.projectile import SoccerBall, ShotPutBall, TableTennisBall
|
18 |
-
import matplotlib.pyplot as pl
|
19 |
-
import numpy as np
|
20 |
-
|
21 |
-
cases = ('Shot','Soccer ball','Table tennis ball')
|
22 |
-
projectiles = (ShotPutBall('M'), SoccerBall(), TableTennisBall())
|
23 |
-
ux = (9.0, 11.0, 11.8)
|
24 |
-
uy = (7.1, 10.2, 12.0)
|
25 |
-
z0 = (2.4, 0.0, 1.0)
|
26 |
-
spin = (0,0,0)
|
27 |
-
|
28 |
-
f, ax = pl.subplots(1, 1, figsize=(6,4))
|
29 |
-
for i,c in enumerate(cases):
|
30 |
-
speed = np.sqrt(ux[i]**2 + uy[i]**2)
|
31 |
-
pitch = np.degrees(np.arctan2(uy[i],ux[i]))
|
32 |
-
position = (0, 0, z0[i])
|
33 |
-
|
34 |
-
s = projectiles[i].shoot(speed=speed,pitch=pitch,position=position,spin=spin)
|
35 |
-
|
36 |
-
x,y,z = s.position
|
37 |
-
|
38 |
-
ax.plot(x,z,'C0-')
|
39 |
-
ax.text(x[0]-0.5, z[0], c, fontsize=9, ha='right')
|
40 |
-
|
41 |
-
x,z = np.loadtxt(f'data/{c}_trajectory.dat', unpack=True, delimiter=';')
|
42 |
-
ax.plot(x,z,'C1--')
|
43 |
-
|
44 |
-
ax.legend(('Simulation','Experiment'))
|
45 |
-
ax.axis((-10,25,-1,6))
|
46 |
-
|
47 |
-
pl.xlabel('Length (m)')
|
48 |
-
pl.ylabel('Height (m)')
|
49 |
-
|
50 |
-
pl.show()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/validation_spinning_ball.py
DELETED
@@ -1,48 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""
|
3 |
-
This program calculates the trajectory of a spinning soccer ball
|
4 |
-
that was experimentally investigated in
|
5 |
-
|
6 |
-
Mencke, J. E., Salewski, M., Trinhammer, O. L., & Adler, A. T. (2020).
|
7 |
-
Flight and bounce of spinning sports balls. American Journal of Physics,
|
8 |
-
88(11), 934-947.
|
9 |
-
|
10 |
-
"""
|
11 |
-
|
12 |
-
from shotshaper.projectile import SoccerBall
|
13 |
-
import matplotlib.pyplot as pl
|
14 |
-
import numpy as np
|
15 |
-
from scipy.linalg import norm
|
16 |
-
|
17 |
-
ball = SoccerBall()
|
18 |
-
u = np.array([20.0, 2.5, 4.9])
|
19 |
-
# Note that spin is here negative along the z-axis, as opposed
|
20 |
-
# to positive around the y-axis, since we define z as upwards,
|
21 |
-
# while Mencke et al. define y as upwards
|
22 |
-
spin = (0,0,-46)
|
23 |
-
speed = norm(u)
|
24 |
-
pitch = np.degrees(np.arctan2(u[2],u[0]))
|
25 |
-
yaw = -np.degrees(np.arctan2(u[1],u[0]))
|
26 |
-
|
27 |
-
s = ball.shoot(speed=speed,pitch=pitch,yaw=yaw,spin=spin)
|
28 |
-
|
29 |
-
x,y,z = s.position
|
30 |
-
|
31 |
-
f, (ax1, ax2) = pl.subplots(2, 1, figsize=(5,7))
|
32 |
-
|
33 |
-
ax1.plot(x,z,'C0-')
|
34 |
-
ax2.plot(x,y,'C0-')
|
35 |
-
x,z = np.loadtxt('data/Spin_z_trajectory.dat', unpack=True, delimiter=';')
|
36 |
-
ax1.plot(x,z,'C1--')
|
37 |
-
x,y = np.loadtxt('data/Spin_y_trajectory.dat', unpack=True, delimiter=';')
|
38 |
-
ax2.plot(x,y,'C1--')
|
39 |
-
|
40 |
-
ax1.legend(('Simulation','Experiment'))
|
41 |
-
ax2.legend(('Simulation','Experiment'))
|
42 |
-
|
43 |
-
ax1.set_xlabel('Length (m)')
|
44 |
-
ax1.set_ylabel('Height (m)')
|
45 |
-
ax2.set_xlabel('Length (m)')
|
46 |
-
ax2.set_ylabel('Drift (m)')
|
47 |
-
|
48 |
-
pl.show()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{utils β utilities}/disc_geometric_properties.py
RENAMED
File without changes
|
{app β utilities}/extrema.py
RENAMED
File without changes
|
{app β utilities}/get_disc.py
RENAMED
File without changes
|
{app β utilities}/visualize.py
RENAMED
File without changes
|