99- Comparison between 3 DOF and 6 DOF simulations
1010- Validation of key flight metrics
1111
12- The tests use realistic rocket configurations and scenarios to ensure the
13- robustness of the 3 DOF implementation.
12+ The tests use realistic rocket configurations based on the Bella Lui rocket
13+ to ensure the robustness of the 3 DOF implementation.
1414
1515All fixtures are defined in tests/fixtures/flight/flight_fixtures.py.
1616"""
1919
2020from rocketpy import Flight
2121
22+ # Test tolerance constants
23+ MIN_APOGEE_ALTITUDE = 500 # meters
24+ MAX_APOGEE_ALTITUDE = 3000 # meters
25+ MIN_APOGEE_TIME = 5 # seconds
26+ MAX_APOGEE_TIME = 60 # seconds
27+ MIN_VELOCITY = 50 # m/s
28+ MAX_VELOCITY = 400 # m/s
29+ APOGEE_SPEED_RATIO = 0.3 # Max ratio of apogee speed to max speed
30+ MAX_LATERAL_TO_ALTITUDE_RATIO = 0.5 # Max lateral displacement vs altitude ratio
31+ QUATERNION_CHANGE_TOLERANCE = 0.1 # Max quaternion change without weathercocking
32+ WEATHERCOCK_COEFFICIENTS = [0.0 , 0.5 , 1.0 , 2.0 ] # Test weathercock coefficients
33+ WEATHERCOCK_RANGE_THRESHOLD = 1.0 # Minimum apogee difference (meters)
34+ LATERAL_INCREASE_THRESHOLD = 0.5 # Minimum lateral increase (meters)
35+ LAUNCH_INCLINATION = 85 # degrees from horizontal
36+ LAUNCH_HEADING = 0 # degrees
37+ MASS_TOLERANCE = 0.001 # kg
38+ THRUST_TOLERANCE = 1e-6 # N
39+
2240
2341def test_3dof_flight_basic_trajectory (flight_3dof_no_weathercock ):
2442 """Test that 3 DOF flight produces reasonable trajectory.
2543
2644 This test validates that the basic 3 DOF flight simulation produces
27- physically reasonable results for key flight metrics.
45+ physically reasonable results for key flight metrics using Bella Lui
46+ based rocket parameters.
2847
2948 Parameters
3049 ----------
@@ -33,21 +52,24 @@ def test_3dof_flight_basic_trajectory(flight_3dof_no_weathercock):
3352 """
3453 flight = flight_3dof_no_weathercock
3554
36- # Validate apogee is reasonable (between 500m and 3000m)
55+ # Validate apogee is reasonable
3756 apogee_altitude = flight .apogee - flight .env .elevation
38- assert 500 < apogee_altitude < 3000 , (
39- f"Apogee altitude { apogee_altitude :.1f} m is outside expected range"
57+ assert MIN_APOGEE_ALTITUDE < apogee_altitude < MAX_APOGEE_ALTITUDE , (
58+ f"Apogee altitude { apogee_altitude :.1f} m is outside expected range "
59+ f"[{ MIN_APOGEE_ALTITUDE } , { MAX_APOGEE_ALTITUDE } ]"
4060 )
4161
42- # Validate apogee time is reasonable (between 5s and 60s)
43- assert 5 < flight .apogee_time < 60 , (
44- f"Apogee time { flight .apogee_time :.1f} s is outside expected range"
62+ # Validate apogee time is reasonable
63+ assert MIN_APOGEE_TIME < flight .apogee_time < MAX_APOGEE_TIME , (
64+ f"Apogee time { flight .apogee_time :.1f} s is outside expected range "
65+ f"[{ MIN_APOGEE_TIME } , { MAX_APOGEE_TIME } ]"
4566 )
4667
4768 # Validate maximum velocity is reasonable (subsonic to low supersonic)
4869 max_velocity = flight .max_speed
49- assert 50 < max_velocity < 400 , (
50- f"Maximum velocity { max_velocity :.1f} m/s is outside expected range"
70+ assert MIN_VELOCITY < max_velocity < MAX_VELOCITY , (
71+ f"Maximum velocity { max_velocity :.1f} m/s is outside expected range "
72+ f"[{ MIN_VELOCITY } , { MAX_VELOCITY } ]"
5173 )
5274
5375 # Validate impact velocity is reasonable (with no parachute, terminal velocity)
@@ -78,9 +100,9 @@ def test_3dof_flight_energy_conservation(flight_3dof_no_weathercock):
78100 max_speed = flight .max_speed
79101
80102 # Apogee speed should be significantly less than max speed
81- assert apogee_speed < 0.3 * max_speed , (
103+ assert apogee_speed < APOGEE_SPEED_RATIO * max_speed , (
82104 f"Apogee speed { apogee_speed :.1f} m/s should be much less than "
83- f"max speed { max_speed :.1f} m/s"
105+ f"max speed { max_speed :.1f} m/s (ratio < { APOGEE_SPEED_RATIO } ) "
84106 )
85107
86108 # Potential energy at apogee should be positive
@@ -112,9 +134,10 @@ def test_3dof_flight_lateral_motion_no_weathercock(flight_3dof_no_weathercock):
112134
113135 # Lateral displacement should be reasonable (not too extreme)
114136 apogee_altitude = flight .apogee - flight .env .elevation
115- assert lateral_displacement < 0.5 * apogee_altitude , (
137+ assert lateral_displacement < MAX_LATERAL_TO_ALTITUDE_RATIO * apogee_altitude , (
116138 f"Lateral displacement { lateral_displacement :.1f} m seems too large "
117- f"compared to apogee altitude { apogee_altitude :.1f} m"
139+ f"compared to apogee altitude { apogee_altitude :.1f} m "
140+ f"(ratio > { MAX_LATERAL_TO_ALTITUDE_RATIO } )"
118141 )
119142
120143
@@ -142,11 +165,13 @@ def test_3dof_weathercocking_affects_trajectory(
142165
143166 # They should be reasonably close but not identical
144167 apogee_difference = abs (apogee_no_wc - apogee_with_wc )
145- assert apogee_difference > 0.1 , "Weathercocking should affect apogee altitude"
168+ assert apogee_difference > LATERAL_INCREASE_THRESHOLD , (
169+ f"Weathercocking should affect apogee altitude (difference: { apogee_difference :.2f} m)"
170+ )
146171
147172 # Both should still be in reasonable range
148- assert 500 < apogee_no_wc < 3000
149- assert 500 < apogee_with_wc < 3000
173+ assert MIN_APOGEE_ALTITUDE < apogee_no_wc < MAX_APOGEE_ALTITUDE
174+ assert MIN_APOGEE_ALTITUDE < apogee_with_wc < MAX_APOGEE_ALTITUDE
150175
151176
152177def test_3dof_weathercocking_coefficient_stored (flight_3dof_with_weathercock ):
@@ -257,16 +282,17 @@ def test_3dof_flight_quaternion_evolution_no_weathercock(flight_3dof_no_weatherc
257282
258283 # Without weathercocking, quaternion change should be minimal
259284 # (allowing for some numerical drift)
260- assert quat_change < 0.1 , (
261- f"Quaternion change { quat_change :.6f} is too large without weathercocking"
285+ assert quat_change < QUATERNION_CHANGE_TOLERANCE , (
286+ f"Quaternion change { quat_change :.6f} is too large without weathercocking "
287+ f"(tolerance: { QUATERNION_CHANGE_TOLERANCE } )"
262288 )
263289
264290
265291def test_3dof_flight_mass_variation (flight_3dof_no_weathercock ):
266292 """Test that rocket mass varies correctly during flight.
267293
268294 The rocket mass should decrease during motor burn and remain constant
269- after burnout.
295+ after burnout. Based on Bella Lui motor with ~2.43s burn time.
270296
271297 Parameters
272298 ----------
@@ -281,8 +307,8 @@ def test_3dof_flight_mass_variation(flight_3dof_no_weathercock):
281307 # Get mass during burn (at t=1s)
282308 mass_during_burn = flight .rocket .total_mass (1.0 )
283309
284- # Get mass after burnout (at t=5s , after 3.5s burn time)
285- post_burn_mass = flight .rocket .total_mass (5 .0 )
310+ # Get mass after burnout (at t=4s , after ~2.43s burn time)
311+ post_burn_mass = flight .rocket .total_mass (4 .0 )
286312
287313 # Initial mass should be greater than mass during burn
288314 assert initial_mass > mass_during_burn , "Mass should decrease during burn"
@@ -294,19 +320,20 @@ def test_3dof_flight_mass_variation(flight_3dof_no_weathercock):
294320 )
295321
296322 # Mass should remain constant after burnout
297- # Check at t=6s and t=7s to verify constant mass
323+ # Check at t=5s and t=6s to verify constant mass
324+ mass_at_5s = flight .rocket .total_mass (5.0 )
298325 mass_at_6s = flight .rocket .total_mass (6.0 )
299- mass_at_7s = flight . rocket . total_mass ( 7.0 )
300- assert abs (mass_at_6s - mass_at_7s ) < 0.001 , (
301- "Mass should remain constant after burnout "
326+ assert abs ( mass_at_5s - mass_at_6s ) < MASS_TOLERANCE , (
327+ f"Mass should remain constant after burnout (difference: { abs (mass_at_5s - mass_at_6s ):.4f } kg, "
328+ f"tolerance: { MASS_TOLERANCE } kg) "
302329 )
303330
304331
305332def test_3dof_flight_thrust_profile (flight_3dof_no_weathercock ):
306333 """Test that thrust profile is correct for point mass motor.
307334
308- For a constant thrust motor, thrust should be constant during burn
309- and zero after burnout.
335+ For the Bella Lui motor (K828FJ) , thrust should be positive during burn
336+ (~2.43s) and zero after burnout.
310337
311338 Parameters
312339 ----------
@@ -318,14 +345,17 @@ def test_3dof_flight_thrust_profile(flight_3dof_no_weathercock):
318345 # Get thrust during burn (at t=1s)
319346 thrust_during_burn = flight .rocket .motor .thrust (1.0 )
320347
321- # Get thrust after burnout (at t=5s )
322- thrust_after_burnout = flight .rocket .motor .thrust (5 .0 )
348+ # Get thrust after burnout (at t=4s, after ~2.43s burn time )
349+ thrust_after_burnout = flight .rocket .motor .thrust (4 .0 )
323350
324351 # Thrust during burn should be positive
325352 assert thrust_during_burn > 0 , "Thrust should be positive during burn"
326353
327354 # Thrust after burnout should be zero
328- assert abs (thrust_after_burnout ) < 1e-6 , "Thrust should be zero after burnout"
355+ assert abs (thrust_after_burnout ) < THRUST_TOLERANCE , (
356+ f"Thrust should be zero after burnout (got { thrust_after_burnout :.9f} N, "
357+ f"tolerance: { THRUST_TOLERANCE } N)"
358+ )
329359
330360
331361def test_3dof_flight_reproducibility (
@@ -347,8 +377,8 @@ def test_3dof_flight_reproducibility(
347377 rocket = acceptance_point_mass_rocket ,
348378 environment = example_spaceport_env ,
349379 rail_length = 5.0 ,
350- inclination = 85 ,
351- heading = 0 ,
380+ inclination = LAUNCH_INCLINATION ,
381+ heading = LAUNCH_HEADING ,
352382 simulation_mode = "3 DOF" ,
353383 weathercock_coeff = 0.5 ,
354384 )
@@ -357,8 +387,8 @@ def test_3dof_flight_reproducibility(
357387 rocket = acceptance_point_mass_rocket ,
358388 environment = example_spaceport_env ,
359389 rail_length = 5.0 ,
360- inclination = 85 ,
361- heading = 0 ,
390+ inclination = LAUNCH_INCLINATION ,
391+ heading = LAUNCH_HEADING ,
362392 simulation_mode = "3 DOF" ,
363393 weathercock_coeff = 0.5 ,
364394 )
@@ -390,16 +420,16 @@ def test_3dof_flight_different_weathercock_coefficients(
390420 acceptance_point_mass_rocket : rocketpy.PointMassRocket
391421 Rocket fixture for testing.
392422 """
393- coefficients = [ 0.0 , 0.5 , 1.0 , 2.0 ]
423+ coefficients = WEATHERCOCK_COEFFICIENTS
394424 flights = []
395425
396426 for coeff in coefficients :
397427 flight = Flight (
398428 rocket = acceptance_point_mass_rocket ,
399429 environment = example_spaceport_env ,
400430 rail_length = 5.0 ,
401- inclination = 85 ,
402- heading = 0 ,
431+ inclination = LAUNCH_INCLINATION ,
432+ heading = LAUNCH_HEADING ,
403433 simulation_mode = "3 DOF" ,
404434 weathercock_coeff = coeff ,
405435 )
@@ -408,15 +438,16 @@ def test_3dof_flight_different_weathercock_coefficients(
408438 # All flights should have reasonable apogees
409439 for flight , coeff in zip (flights , coefficients ):
410440 apogee = flight .apogee - flight .env .elevation
411- assert 500 < apogee < 3000 , (
412- f"Apogee { apogee :.1f} m with weathercock_coeff={ coeff } is outside expected range"
441+ assert MIN_APOGEE_ALTITUDE < apogee < MAX_APOGEE_ALTITUDE , (
442+ f"Apogee { apogee :.1f} m with weathercock_coeff={ coeff } is outside expected range "
443+ f"[{ MIN_APOGEE_ALTITUDE } , { MAX_APOGEE_ALTITUDE } ]"
413444 )
414445
415446 # Apogees should vary with weathercock coefficient
416447 # Calculate the range of apogees to ensure they're different
417448 apogees = [f .apogee for f in flights ]
418449 apogee_range = max (apogees ) - min (apogees )
419- assert apogee_range > 1.0 , (
450+ assert apogee_range > WEATHERCOCK_RANGE_THRESHOLD , (
420451 f"Different weathercock coefficients should produce different apogees. "
421- f"Range was only { apogee_range :.2f} m"
452+ f"Range was only { apogee_range :.2f} m (threshold: { WEATHERCOCK_RANGE_THRESHOLD } m) "
422453 )
0 commit comments