derek-thomas HF staff commited on
Commit
7efe007
β€’
1 Parent(s): aa651cf

Refactoring and adding simulator to README.md

Browse files
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: app.py
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 / "app" / "app.py"
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