Skip to content

Commit f74b635

Browse files
committed
added unit tests for ggv sim
1 parent fbc162d commit f74b635

File tree

7 files changed

+150
-37
lines changed

7 files changed

+150
-37
lines changed
7.46 KB
Binary file not shown.

outputs/comp_eval_outputs/debug.txt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@ X_OFFSET = 0.5
44
SCALE_FACTOR = 0.01
55

66
GGV values:
7-
v=0.1 m/s: ax_max=5.1986 m/s^2, ay_max=0.2936 m/s^2
8-
v=10 m/s: ax_max=25.7152 m/s^2, ay_max=20.8102 m/s^2
9-
v=20 m/s: ax_max=4.9050 m/s^2, ay_max=0.0000 m/s^2
7+
v=0.1 m/s: ax_max=5.1989 m/s^2, ay_max=0.2939 m/s^2
8+
v=10 m/s: ax_max=30.3921 m/s^2, ay_max=25.4871 m/s^2
9+
v=20 m/s: ax_max=46.5253 m/s^2, ay_max=41.6203 m/s^2
1010

1111
ACCELERATION EVENT:
12-
Time: 4.440 s
13-
First 10 velocities: [0.01 0.06198563 0.11397127 0.16636587 0.22029161 0.27578899
14-
0.3328993 0.39166465 0.45212792 0.51433278]
15-
Last 5 velocities: [20.00726205 20.00726205 20.00726205 20.00726205 20.00726205]
16-
First 10 accelerations: [0. 5.19856333 5.19856333 5.23946037 5.39257412 5.54973785
17-
5.71103149 5.87653471 6.04632677 6.22048632]
18-
Max velocity: 20.0073 m/s
12+
Time: 2.780 s
13+
First 10 velocities: [0.01 0.06198932 0.11397864 0.16637825 0.22031456 0.27583054
14+
0.3329702 0.39177864 0.45230208 0.51458786]
15+
Last 5 velocities: [40.01812436 40.01812436 40.01812436 40.01812436 40.01812436]
16+
First 10 accelerations: [0. 5.19893189 5.19893189 5.23996088 5.39363178 5.55159769
17+
5.71396556 5.88084417 6.05234411 6.22857774]
18+
Max velocity: 40.0181 m/s
1919

2020
SKIDPAD EVENT:
21-
Time: 7.292 s
22-
Optimal velocity: 13.1403 m/s
23-
Lateral accel: 22.6449 m/s^2
24-
Lateral G: 2.3083 G
21+
Time: 6.250 s
22+
Optimal velocity: 21.3141 m/s
23+
Lateral accel: 42.8577 m/s^2
24+
Lateral G: 4.3688 G

src/simulations/comp_eval/comp_eval.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def ggv_max_accel(self, v, direction=0):
8282
"""Get max acceleration at velocity v in direction (radians)"""
8383
if v < 0.1:
8484
return 0.0, 0.0
85-
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 2000.0) # v^3/2000
85+
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 4000.0) # v^3/4000
8686
if radius_squared < 0:
8787
return 0.0, 0.0 # no grip, prolyl spin
8888
radius = np.sqrt(radius_squared)
@@ -94,7 +94,7 @@ def ggv_envelope(self, v):
9494
"""Get full envelope at velocity v"""
9595
if v < 0.1:
9696
return np.array([0.0]), np.array([0.0])
97-
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 2000.0)
97+
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 4000.0)
9898
if radius_squared < 0:
9999
return np.array([0.0]), np.array([0.0])
100100
radius = np.sqrt(radius_squared)
@@ -107,7 +107,7 @@ def ggv_max_long_accel(self, v):
107107
"""Max forward acceleration - don't apply X_OFFSET here, it's for the full envelope"""
108108
if v < 0.1:
109109
v = 0.1 # no zero for math
110-
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 2000.0)
110+
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 4000.0)
111111
if radius_squared < 0:
112112
return 0.0
113113
radius = np.sqrt(radius_squared)
@@ -118,7 +118,7 @@ def ggv_max_lat_accel(self, v):
118118
"""Max lateral acceleration"""
119119
if v < 0.1:
120120
v = 0.1
121-
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 2000.0)
121+
radius_squared = 9*(self.SCALE_FACTOR * v**2 - v**3 / 4000.0)
122122
if radius_squared < 0:
123123
return 0.0
124124
radius = np.sqrt(radius_squared)
@@ -226,7 +226,7 @@ def plot_ggv_surface(self):
226226
ax.set_title('GGV Surface', fontsize=16, pad=20)
227227

228228
# Add equation at bottom (in Gs)
229-
fig.text(0.5, 0.02, f"GGV: (ax_g+{self.X_OFFSET})^2 + (ay_g)^2 = 9*({self.SCALE_FACTOR}*v^2 - v^3/2000) | accel = G * 9.81",
229+
fig.text(0.5, 0.02, f"GGV: (ax_g+{self.X_OFFSET})^2 + (ay_g)^2 = 9*({self.SCALE_FACTOR}*v^2 - v^3/4000) | accel = G * 9.81",
230230
fontsize=10, ha='center')
231231

232232
return fig
7.46 KB
Binary file not shown.

src/simulations/comp_eval/comp_eval_outputs/debug.txt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@ X_OFFSET = 0.5
44
SCALE_FACTOR = 0.01
55

66
GGV values:
7-
v=0.1 m/s: ax_max=5.1986 m/s^2, ay_max=0.2936 m/s^2
8-
v=10 m/s: ax_max=25.7152 m/s^2, ay_max=20.8102 m/s^2
9-
v=20 m/s: ax_max=4.9050 m/s^2, ay_max=0.0000 m/s^2
7+
v=0.1 m/s: ax_max=5.1989 m/s^2, ay_max=0.2939 m/s^2
8+
v=10 m/s: ax_max=30.3921 m/s^2, ay_max=25.4871 m/s^2
9+
v=20 m/s: ax_max=46.5253 m/s^2, ay_max=41.6203 m/s^2
1010

1111
ACCELERATION EVENT:
12-
Time: 4.440 s
13-
First 10 velocities: [0.01 0.06198563 0.11397127 0.16636587 0.22029161 0.27578899
14-
0.3328993 0.39166465 0.45212792 0.51433278]
15-
Last 5 velocities: [20.00726205 20.00726205 20.00726205 20.00726205 20.00726205]
16-
First 10 accelerations: [0. 5.19856333 5.19856333 5.23946037 5.39257412 5.54973785
17-
5.71103149 5.87653471 6.04632677 6.22048632]
18-
Max velocity: 20.0073 m/s
12+
Time: 2.780 s
13+
First 10 velocities: [0.01 0.06198932 0.11397864 0.16637825 0.22031456 0.27583054
14+
0.3329702 0.39177864 0.45230208 0.51458786]
15+
Last 5 velocities: [40.01812436 40.01812436 40.01812436 40.01812436 40.01812436]
16+
First 10 accelerations: [0. 5.19893189 5.19893189 5.23996088 5.39363178 5.55159769
17+
5.71396556 5.88084417 6.05234411 6.22857774]
18+
Max velocity: 40.0181 m/s
1919

2020
SKIDPAD EVENT:
21-
Time: 7.292 s
22-
Optimal velocity: 13.1403 m/s
23-
Lateral accel: 22.6449 m/s^2
24-
Lateral G: 2.3083 G
21+
Time: 6.250 s
22+
Optimal velocity: 21.3141 m/s
23+
Lateral accel: 42.8577 m/s^2
24+
Lateral G: 4.3688 G

unit_tests/python_test_results/test_results.html

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from src.simulations.comp_eval.comp_eval import CompEval
2+
from unittest import TestCase
3+
import numpy as np
4+
5+
6+
class TestGGVEnvelope(TestCase):
7+
def setUp(self):
8+
self.comp_eval = CompEval.__new__(CompEval)
9+
self.comp_eval.V_MAX = 31.1
10+
self.comp_eval.X_OFFSET = 0.5
11+
self.comp_eval.SCALE_FACTOR = 0.01
12+
13+
def test_never_closes(self):
14+
"""radius^2 > 0 for all v in [0, V_MAX]"""
15+
velocities = np.linspace(0.1, self.comp_eval.V_MAX, 50)
16+
17+
for v in velocities:
18+
radius_squared = 9 * (self.comp_eval.SCALE_FACTOR * v**2 - v**3 / 4000.0)
19+
self.assertGreater(radius_squared, 0,
20+
f"Envelope closed at v={v:.2f} m/s")
21+
22+
def test_forms_loop(self):
23+
"""Envelope first point ≈ last point"""
24+
velocities = [5, 10, 15, 20, 25, 30]
25+
26+
for v in velocities:
27+
if v > self.comp_eval.V_MAX:
28+
continue
29+
30+
ax_env, ay_env = self.comp_eval.ggv_envelope(v)
31+
32+
self.assertAlmostEqual(ax_env[0], ax_env[-1], places=1)
33+
self.assertAlmostEqual(ay_env[0], ay_env[-1], places=1)
34+
35+
36+
class TestGGVBounds(TestCase):
37+
def setUp(self):
38+
self.comp_eval = CompEval.__new__(CompEval)
39+
self.comp_eval.V_MAX = 31.1
40+
self.comp_eval.X_OFFSET = 0.5
41+
self.comp_eval.SCALE_FACTOR = 0.01
42+
43+
def test_ax_positive(self):
44+
"""ax_max > 0 for all v"""
45+
velocities = np.linspace(0.1, self.comp_eval.V_MAX, 50)
46+
47+
for v in velocities:
48+
ax = self.comp_eval.ggv_max_long_accel(v)
49+
self.assertGreater(ax, 0, f"ax not positive at v={v:.2f} m/s")
50+
51+
def test_ay_positive(self):
52+
"""ay_max > 0 for all v"""
53+
velocities = np.linspace(0.1, self.comp_eval.V_MAX, 50)
54+
55+
for v in velocities:
56+
ay = self.comp_eval.ggv_max_lat_accel(v)
57+
self.assertGreater(ay, 0, f"ay not positive at v={v:.2f} m/s")
58+
59+
def test_within_circle(self):
60+
"""(ax_g + X_OFFSET)^2 + ay_g^2 = radius²"""
61+
velocities = [5, 10, 15, 20, 25, 30]
62+
directions = np.linspace(0, 2*np.pi, 16)
63+
64+
for v in velocities:
65+
if v > self.comp_eval.V_MAX:
66+
continue
67+
68+
radius_squared = 9 * (self.comp_eval.SCALE_FACTOR * v**2 - v**3 / 4000.0)
69+
radius = np.sqrt(radius_squared)
70+
71+
for direction in directions:
72+
ax, ay = self.comp_eval.ggv_max_accel(v, direction)
73+
ax_g, ay_g = ax / 9.81, ay / 9.81
74+
75+
actual_r2 = (ax_g + self.comp_eval.X_OFFSET)**2 + ay_g**2
76+
77+
self.assertAlmostEqual(actual_r2, radius**2, places=3,
78+
msg=f"Outside envelope at v={v:.2f}, θ={np.degrees(direction):.0f}°")
79+
80+
81+
class TestGGVEdgeCases(TestCase):
82+
def setUp(self):
83+
self.comp_eval = CompEval.__new__(CompEval)
84+
self.comp_eval.V_MAX = 31.1
85+
self.comp_eval.X_OFFSET = 0.5
86+
self.comp_eval.SCALE_FACTOR = 0.01
87+
88+
def test_min_velocity(self):
89+
"""v = 0.1 m/s"""
90+
ax = self.comp_eval.ggv_max_long_accel(0.1)
91+
ay = self.comp_eval.ggv_max_lat_accel(0.1)
92+
93+
self.assertGreater(ax, 0)
94+
self.assertGreater(ay, 0)
95+
96+
def test_max_velocity(self):
97+
"""v = V_MAX"""
98+
ax = self.comp_eval.ggv_max_long_accel(self.comp_eval.V_MAX)
99+
ay = self.comp_eval.ggv_max_lat_accel(self.comp_eval.V_MAX)
100+
101+
self.assertGreater(ax, 0)
102+
self.assertGreater(ay, 0)
103+
104+
def test_no_nan(self):
105+
"""Never returns NaN"""
106+
velocities = np.linspace(0.1, self.comp_eval.V_MAX + 5, 50)
107+
108+
for v in velocities:
109+
ax = self.comp_eval.ggv_max_long_accel(v)
110+
ay = self.comp_eval.ggv_max_lat_accel(v)
111+
112+
self.assertFalse(np.isnan(ax))
113+
self.assertFalse(np.isnan(ay))

0 commit comments

Comments
 (0)