@@ -141,6 +141,7 @@ def test_invalid_simulation_mode(example_plain_env, calisto):
141141
142142def test_weathercock_coeff_stored (example_plain_env , point_mass_rocket ):
143143 """Tests that the weathercock_coeff parameter is correctly stored.
144+
144145 Parameters
145146 ----------
146147 example_plain_env : rocketpy.Environment
@@ -160,6 +161,7 @@ def test_weathercock_coeff_stored(example_plain_env, point_mass_rocket):
160161
161162def test_weathercock_coeff_default (example_plain_env , point_mass_rocket ):
162163 """Tests that the default weathercock_coeff is 1.0.
164+
163165 Parameters
164166 ----------
165167 example_plain_env : rocketpy.Environment
@@ -180,6 +182,7 @@ def test_weathercock_zero_gives_fixed_attitude(example_plain_env, point_mass_roc
180182 """Tests that weathercock_coeff=0 results in fixed attitude (no quaternion change).
181183 When weathercock_coeff is 0, the quaternion derivatives should be zero,
182184 meaning the attitude does not evolve.
185+
183186 Parameters
184187 ----------
185188 example_plain_env : rocketpy.Environment
@@ -208,6 +211,7 @@ def test_weathercock_nonzero_evolves_attitude(example_plain_env, point_mass_rock
208211 """Tests that non-zero weathercock_coeff causes attitude evolution.
209212 When the body axis is misaligned with the relative wind and weathercock_coeff
210213 is positive, the quaternion derivatives should be non-zero.
214+
211215 Parameters
212216 ----------
213217 example_plain_env : rocketpy.Environment
@@ -238,6 +242,7 @@ def test_weathercock_aligned_no_evolution(example_plain_env, point_mass_rocket):
238242 """Tests that when body axis is aligned with relative wind, no rotation occurs.
239243 When the rocket's body z-axis is already aligned with the negative of the
240244 freestream velocity, the quaternion derivatives should be approximately zero.
245+
241246 Parameters
242247 ----------
243248 example_plain_env : rocketpy.Environment
@@ -266,3 +271,42 @@ def test_weathercock_aligned_no_evolution(example_plain_env, point_mass_rocket):
266271 assert e_dot_magnitude < 1e-8 , (
267272 "Quaternion derivatives should be very small when aligned"
268273 )
274+
275+
276+ def test_weathercock_anti_aligned_uses_perp_axis_and_evolves (
277+ example_plain_env , point_mass_rocket
278+ ):
279+ """Tests the anti-aligned case where body z-axis is opposite freestream.
280+
281+ This should exercise the branch that selects a perpendicular axis (y-axis)
282+ when the cross with x-axis is nearly zero, producing a non-zero quaternion
283+ derivative.
284+ """
285+ flight = Flight (
286+ rocket = point_mass_rocket ,
287+ environment = example_plain_env ,
288+ rail_length = 1 ,
289+ simulation_mode = "3 DOF" ,
290+ weathercock_coeff = 1.0 ,
291+ )
292+
293+ sqrt2_2 = np .sqrt (2 ) / 2
294+ # Build quaternion that makes body z-axis = [-1, 0, 0]
295+ # This corresponds to a -90 deg rotation about the y-axis: e0=cos(45°), e2=-sin(45°)
296+ e0 = sqrt2_2
297+ e1 = 0
298+ e2 = - sqrt2_2
299+ e3 = 0
300+
301+ # State: [x, y, z, vx, vy, vz, e0, e1, e2, e3, w1, w2, w3]
302+ # Set velocity so desired_direction becomes [1,0,0]
303+ u = [0 , 0 , 100 , 50 , 0 , 0 , e0 , e1 , e2 , e3 , 0 , 0 , 0 ]
304+
305+ result = flight .u_dot_generalized_3dof (0 , u )
306+
307+ # Quaternion derivatives (indices 6-9) should be non-zero in anti-aligned case
308+ e_dot = result [6 :10 ]
309+ e_dot_magnitude = sum (ed ** 2 for ed in e_dot ) ** 0.5
310+ assert e_dot_magnitude > 1e-6 , (
311+ "Quaternion derivatives should be non-zero for anti-aligned"
312+ )
0 commit comments