@@ -1929,79 +1929,58 @@ def u_dot_generalized_3dof(self, t, u, post_processing=False):
19291929 rotation_axis = body_z_inertial ^ desired_direction
19301930 rotation_axis_mag = abs (rotation_axis )
19311931
1932+ # Determine omega_body based on alignment state
1933+ omega_body = None
1934+
19321935 if rotation_axis_mag > 1e-8 :
1933- # Normalize rotation axis
1936+ # Normal case: compute angular velocity from misalignment
19341937 rotation_axis = rotation_axis / rotation_axis_mag
19351938
19361939 # The magnitude of the cross product of two unit vectors equals
19371940 # the sine of the angle between them
1938- sin_angle = rotation_axis_mag
1939-
1940- # Clamp sin_angle to valid range
1941- sin_angle = min (1.0 , max (- 1.0 , sin_angle ))
1941+ sin_angle = min (1.0 , max (- 1.0 , rotation_axis_mag ))
19421942
19431943 # Angular velocity magnitude proportional to misalignment angle
19441944 omega_mag = self .weathercock_coeff * sin_angle
19451945
1946- # Angular velocity in inertial frame
1947- omega_inertial = rotation_axis * omega_mag
1948-
1949- # Transform angular velocity to body frame
1950- omega_body = Kt @ omega_inertial
1951-
1952- # Quaternion derivative from angular velocity in body frame
1953- omega1_wc , omega2_wc , omega3_wc = (
1954- omega_body .x ,
1955- omega_body .y ,
1956- omega_body .z ,
1957- )
1958- e0_dot = 0.5 * (- omega1_wc * e1 - omega2_wc * e2 - omega3_wc * e3 )
1959- e1_dot = 0.5 * (omega1_wc * e0 + omega3_wc * e2 - omega2_wc * e3 )
1960- e2_dot = 0.5 * (omega2_wc * e0 - omega3_wc * e1 + omega1_wc * e3 )
1961- e3_dot = 0.5 * (omega3_wc * e0 + omega2_wc * e1 - omega1_wc * e2 )
1962- e_dot = [e0_dot , e1_dot , e2_dot , e3_dot ]
1963- w_dot = [0 , 0 , 0 ] # No angular acceleration in 3DOF model
1946+ # Angular velocity in inertial frame, then transform to body frame
1947+ omega_body = Kt @ (rotation_axis * omega_mag )
19641948 else :
19651949 # Check if aligned or anti-aligned using dot product
1966- dot = body_z_inertial @ desired_direction # Vector dot product
1967- if dot > 0.999 : # Aligned
1968- e_dot = [0 , 0 , 0 , 0 ]
1969- w_dot = [0 , 0 , 0 ]
1970- elif dot < - 0.999 : # Anti-aligned
1950+ dot = body_z_inertial @ desired_direction
1951+ if dot < - 0.999 : # Anti-aligned
19711952 # Choose an arbitrary perpendicular axis
1972- # Try [1,0,0] unless body_z_inertial is parallel to it
19731953 x_axis = Vector ([1.0 , 0.0 , 0.0 ])
19741954 perp_axis = body_z_inertial ^ x_axis
19751955 if abs (perp_axis ) < 1e-6 :
1976- # If parallel, use y axis
19771956 y_axis = Vector ([0.0 , 1.0 , 0.0 ])
19781957 perp_axis = body_z_inertial ^ y_axis
19791958 if abs (perp_axis ) < 1e-6 :
1980- # If still parallel, raise an error or choose a default axis
19811959 raise ValueError (
19821960 "Cannot determine a valid rotation axis: "
19831961 "body_z_inertial is parallel to both x and y axes."
19841962 )
19851963 rotation_axis = perp_axis .unit_vector
19861964 # 180 degree rotation: sin(angle) = 1
19871965 omega_mag = self .weathercock_coeff * 1.0
1988- omega_inertial = rotation_axis * omega_mag
1989- omega_body = Kt @ omega_inertial
1990- omega1_wc , omega2_wc , omega3_wc = (
1991- omega_body .x ,
1992- omega_body .y ,
1993- omega_body .z ,
1994- )
1995- e0_dot = 0.5 * (- omega1_wc * e1 - omega2_wc * e2 - omega3_wc * e3 )
1996- e1_dot = 0.5 * (omega1_wc * e0 + omega3_wc * e2 - omega2_wc * e3 )
1997- e2_dot = 0.5 * (omega2_wc * e0 - omega3_wc * e1 + omega1_wc * e3 )
1998- e3_dot = 0.5 * (omega3_wc * e0 + omega2_wc * e1 - omega1_wc * e2 )
1999- e_dot = [e0_dot , e1_dot , e2_dot , e3_dot ]
2000- w_dot = [0 , 0 , 0 ]
2001- else :
2002- # Vectors are nearly aligned, treat as aligned
2003- e_dot = [0 , 0 , 0 , 0 ]
2004- w_dot = [0 , 0 , 0 ]
1966+ omega_body = Kt @ (rotation_axis * omega_mag )
1967+ # else: aligned or nearly aligned, omega_body remains None
1968+
1969+ # Compute quaternion derivatives from omega_body
1970+ if omega_body is not None :
1971+ omega1_wc , omega2_wc , omega3_wc = (
1972+ omega_body .x ,
1973+ omega_body .y ,
1974+ omega_body .z ,
1975+ )
1976+ e0_dot = 0.5 * (- omega1_wc * e1 - omega2_wc * e2 - omega3_wc * e3 )
1977+ e1_dot = 0.5 * (omega1_wc * e0 + omega3_wc * e2 - omega2_wc * e3 )
1978+ e2_dot = 0.5 * (omega2_wc * e0 - omega3_wc * e1 + omega1_wc * e3 )
1979+ e3_dot = 0.5 * (omega3_wc * e0 + omega2_wc * e1 - omega1_wc * e2 )
1980+ e_dot = [e0_dot , e1_dot , e2_dot , e3_dot ]
1981+ else :
1982+ e_dot = [0 , 0 , 0 , 0 ]
1983+ w_dot = [0 , 0 , 0 ] # No angular acceleration in 3DOF model
20051984 else :
20061985 # No weathercocking or negligible freestream speed
20071986 e_dot = [0 , 0 , 0 , 0 ]
0 commit comments