Skip to content

Commit 8598260

Browse files
authored
Correction of Flight
Clean comments and clear code
1 parent 972f1c5 commit 8598260

File tree

1 file changed

+128
-94
lines changed

1 file changed

+128
-94
lines changed

rocketpy/simulation/flight.py

Lines changed: 128 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44
import warnings
55
from copy import deepcopy
66
from functools import cached_property
7-
87
import numpy as np
98
import simplekml
109
from scipy.integrate import BDF, DOP853, LSODA, RK23, RK45, OdeSolver, Radau
11-
1210
from ..mathutils.function import Function, funcify_method
1311
from ..mathutils.vector_matrix import Matrix, Vector
1412
from ..plots.flight_plots import _FlightPlots
@@ -1010,8 +1008,7 @@ def __simulate(self, verbose):
10101008
i += 1
10111009
# Create flight phase for time after inflation
10121010
callbacks = [
1013-
lambda self,
1014-
parachute_cd_s=parachute.cd_s: setattr(
1011+
lambda self, parachute_cd_s=parachute.cd_s: setattr(
10151012
self, "parachute_cd_s", parachute_cd_s
10161013
)
10171014
]
@@ -1404,7 +1401,9 @@ def udot_rail2(self, t, u, post_processing=False): # pragma: no cover
14041401
# Hey! We will finish this function later, now we just can use u_dot
14051402
return self.u_dot_generalized(t, u, post_processing=post_processing)
14061403

1407-
def u_dot(self, t, u, post_processing=False): # pylint: disable=too-many-locals,too-many-statements
1404+
def u_dot(
1405+
self, t, u, post_processing=False
1406+
): # pylint: disable=too-many-locals,too-many-statements
14081407
"""Calculates derivative of u state vector with respect to time
14091408
when rocket is flying in 6 DOF motion during ascent out of rail
14101409
and descent without parachute.
@@ -1718,173 +1717,210 @@ def u_dot(self, t, u, post_processing=False): # pylint: disable=too-many-locals
17181717

17191718
return u_dot
17201719

1721-
# Dans flight.py, dans la classe Flight
1722-
17231720
def u_dot_generalized(self, t, u, post_processing=False):
17241721
"""
1725-
Calcule la dérivée du vecteur d'état u (6-DOF) en utilisant un formalisme généralisé
1726-
adapté pour les clusters moteurs et incluant toutes les forces physiques.
1722+
Calculates the derivative of the state vector u (6-DOF) using a
1723+
generalized formalism suitable for motor clusters and including all
1724+
physical forces.
17271725
"""
1728-
# Extraction des variables d'état
1729-
x, y, z, vx, vy, vz, e0, e1, e2, e3, w1, w2, w3 = u
1726+
# State variable extraction
1727+
_, _, z, vx, vy, vz, e0, e1, e2, e3, w1, w2, w3 = u
17301728

1731-
# Création des vecteurs pour les calculs
1729+
# Create vectors for calculations
17321730
velocity_vector = Vector([vx, vy, vz])
17331731
euler_params = [e0, e1, e2, e3]
17341732
angular_velocity_vector = Vector([w1, w2, w3])
17351733
w = angular_velocity_vector
17361734

1737-
# Propriétés de la fusée à l'instant t
1735+
# Rocket properties at time t
17381736
total_mass = self.rocket.total_mass.get_value_opt(t)
1739-
1740-
# Matrice de transformation du repère corps au repère inertiel
1737+
1738+
# Transformation matrix from body frame to inertial frame
17411739
K = Matrix.transformation(euler_params)
17421740
Kt = K.transpose
17431741

1744-
# --- Calcul des forces et moments ---
1745-
1746-
# Gravité dans le repère corps
1747-
gravity_force_inertial = Vector([0, 0, -total_mass * self.env.gravity.get_value_opt(z)])
1742+
# --- Forces and Moments Calculation ---
1743+
1744+
# Gravity in body frame
1745+
gravity_force_inertial = Vector(
1746+
[0, 0, -total_mass * self.env.gravity.get_value_opt(z)]
1747+
)
17481748
gravity_force_body = Kt @ gravity_force_inertial
17491749

1750-
# --- DÉBUT DU BLOC DE CALCUL AÉRODYNAMIQUE INTÉGRÉ ---
1750+
# --- START OF INTEGRATED AERODYNAMIC CALCULATION BLOCK ---
17511751
R1, R2, R3, M1, M2, M3 = 0, 0, 0, 0, 0, 0
1752-
1752+
17531753
# Get freestream speed
17541754
wind_velocity_x = self.env.wind_velocity_x.get_value_opt(z)
17551755
wind_velocity_y = self.env.wind_velocity_y.get_value_opt(z)
17561756
speed_of_sound = self.env.speed_of_sound.get_value_opt(z)
17571757
rho = self.env.density.get_value_opt(z)
17581758

1759-
# Vitesse relative au vent dans le repère inertiel
1760-
stream_velocity_inertial = Vector([wind_velocity_x - vx, wind_velocity_y - vy, -vz])
1759+
# Relative wind speed in inertial frame
1760+
stream_velocity_inertial = Vector(
1761+
[wind_velocity_x - vx, wind_velocity_y - vy, -vz]
1762+
)
17611763
free_stream_speed = abs(stream_velocity_inertial)
17621764
free_stream_mach = free_stream_speed / speed_of_sound
1763-
1764-
# Déterminer la traînée de base de la fusée
1765+
1766+
# Determine the base drag of the rocket
17651767
if t < self.rocket.motor.burn_out_time:
17661768
drag_coeff = self.rocket.power_on_drag.get_value_opt(free_stream_mach)
17671769
else:
17681770
drag_coeff = self.rocket.power_off_drag.get_value_opt(free_stream_mach)
1769-
1770-
R3_base_drag = -0.5 * rho * (free_stream_speed**2) * self.rocket.area * drag_coeff
1771+
1772+
R3_base_drag = (
1773+
-0.5 * rho * (free_stream_speed**2) * self.rocket.area * drag_coeff
1774+
)
17711775
R3 += R3_base_drag
17721776

1773-
# Ajouter la traînée des aérofreins si actifs
1777+
# Add air brakes drag if active
17741778
for air_brakes in self.rocket.air_brakes:
17751779
if air_brakes.deployment_level > 0:
1776-
air_brakes_cd = air_brakes.drag_coefficient.get_value_opt(air_brakes.deployment_level, free_stream_mach)
1777-
air_brakes_force = -0.5 * rho * (free_stream_speed**2) * air_brakes.reference_area * air_brakes_cd
1780+
air_brakes_cd = air_brakes.drag_coefficient.get_value_opt(
1781+
air_brakes.deployment_level, free_stream_mach
1782+
)
1783+
air_brakes_force = (
1784+
-0.5
1785+
* rho
1786+
* (free_stream_speed**2)
1787+
* air_brakes.reference_area
1788+
* air_brakes_cd
1789+
)
17781790
if air_brakes.override_rocket_drag:
17791791
R3 = air_brakes_force
17801792
else:
17811793
R3 += air_brakes_force
1782-
1783-
# Moment dû à l'excentricité du CdP
1794+
1795+
# Moment due to CoP eccentricity
17841796
M1 += self.rocket.cp_eccentricity_y * R3
17851797
M2 -= self.rocket.cp_eccentricity_x * R3
17861798

1787-
# Vitesse de la fusée dans le repère corps
1799+
# Rocket velocity in body frame
17881800
velocity_body_frame = Kt @ velocity_vector
1789-
1790-
# Calculer la portance et le moment pour chaque surface aérodynamique
1791-
for aero_surface, position in self.rocket.aerodynamic_surfaces:
1801+
1802+
# Calculate lift and moment for each aerodynamic surface
1803+
for aero_surface, _ in self.rocket.aerodynamic_surfaces:
17921804
comp_cp = self.rocket.surfaces_cp_to_cdm[aero_surface]
1793-
# Vitesse absolue du composant dans le repère corps
1805+
# Component absolute velocity in body frame
17941806
comp_vb = velocity_body_frame + (w ^ comp_cp)
1795-
# Vitesse du vent à l'altitude du composant
1807+
# Wind velocity at component altitude
17961808
comp_z = z + (K @ comp_cp).z
17971809
comp_wind_vx = self.env.wind_velocity_x.get_value_opt(comp_z)
17981810
comp_wind_vy = self.env.wind_velocity_y.get_value_opt(comp_z)
1799-
# Vitesse du vent dans le repère corps
1811+
# Wind velocity in body frame
18001812
comp_wind_vb = Kt @ Vector([comp_wind_vx, comp_wind_vy, 0])
18011813
comp_stream_velocity = comp_wind_vb - comp_vb
18021814
comp_stream_speed = abs(comp_stream_velocity)
18031815
comp_stream_mach = comp_stream_speed / speed_of_sound
1804-
1816+
18051817
comp_reynolds = (
18061818
self.env.density.get_value_opt(comp_z)
18071819
* comp_stream_speed
18081820
* aero_surface.reference_length
18091821
/ self.env.dynamic_viscosity.get_value_opt(comp_z)
18101822
)
18111823

1812-
# Calcul des forces et moments pour la surface
1824+
# Calculate forces and moments for the surface
18131825
X, Y, Z, M, N, L = aero_surface.compute_forces_and_moments(
1814-
comp_stream_velocity, comp_stream_speed, comp_stream_mach, rho, comp_cp, w, comp_reynolds
1826+
comp_stream_velocity,
1827+
comp_stream_speed,
1828+
comp_stream_mach,
1829+
rho,
1830+
comp_cp,
1831+
w,
1832+
comp_reynolds,
18151833
)
18161834
R1 += X
18171835
R2 += Y
18181836
R3 += Z
18191837
M1 += M
18201838
M2 += N
18211839
M3 += L
1822-
1823-
# Moment dû à l'excentricité du CdP
1840+
1841+
# Moment due to CoP eccentricity
18241842
M3 += self.rocket.cp_eccentricity_x * R2 - self.rocket.cp_eccentricity_y * R1
1825-
1826-
# Création des vecteurs finaux pour les forces et moments aéro
1843+
1844+
# Create final vectors for aero forces and moments
18271845
R_aero_body = Vector([R1, R2, R3])
18281846
M_aero_body = Vector([M1, M2, M3])
1829-
# --- FIN DU BLOC DE CALCUL AÉRODYNAMIQUE ---
1847+
# --- END OF AERODYNAMIC CALCULATION BLOCK ---
18301848

1831-
# Poussée et moment du cluster/moteur
1832-
if hasattr(self.rocket.motor, 'get_total_thrust_vector'): # C'est un ClusterMotor
1849+
# Thrust and moment from cluster/motor
1850+
if hasattr(self.rocket.motor, "get_total_thrust_vector"): # It's a ClusterMotor
18331851
thrust_vector_body = self.rocket.motor.get_total_thrust_vector(t)
18341852
rocket_cm = self.rocket.center_of_mass.get_value_opt(t)
18351853
moment_vector_body = self.rocket.motor.get_total_moment(t, rocket_cm)
18361854
net_thrust_scalar = abs(thrust_vector_body)
1837-
else: # C'est un moteur standard
1855+
else: # It's a standard motor
18381856
pressure = self.env.pressure.get_value_opt(z)
1839-
net_thrust_scalar = max(self.rocket.motor.thrust.get_value_opt(t) + self.rocket.motor.pressure_thrust(pressure), 0)
1840-
thrust_vector_body = Vector([0, 0, net_thrust_scalar]) # Poussée axiale
1841-
moment_vector_body = Vector([ # Moment dû à l'excentricité
1842-
self.rocket.thrust_eccentricity_y * net_thrust_scalar,
1843-
-self.rocket.thrust_eccentricity_x * net_thrust_scalar,
1844-
0
1845-
])
1846-
1847-
# Force et moment totaux dans le repère corps
1857+
net_thrust_scalar = max(
1858+
self.rocket.motor.thrust.get_value_opt(t)
1859+
+ self.rocket.motor.pressure_thrust(pressure),
1860+
0,
1861+
)
1862+
thrust_vector_body = Vector([0, 0, net_thrust_scalar]) # Axial thrust
1863+
moment_vector_body = Vector(
1864+
[ # Moment due to eccentricity
1865+
self.rocket.thrust_eccentricity_y * net_thrust_scalar,
1866+
-self.rocket.thrust_eccentricity_x * net_thrust_scalar,
1867+
0,
1868+
]
1869+
)
1870+
1871+
# Total force and moment in body frame
18481872
total_force_body = gravity_force_body + thrust_vector_body + R_aero_body
18491873
total_moment_body = moment_vector_body + M_aero_body
18501874

1851-
# --- Équations du mouvement ---
1875+
# --- Equations of Motion ---
18521876

1853-
# Accélération linéaire
1877+
# Linear acceleration
18541878
linear_acceleration_body = total_force_body / total_mass
18551879
linear_acceleration_inertial = K @ linear_acceleration_body
1856-
1857-
# Accélération angulaire (Équation d'Euler pour corps rigide à masse variable)
1880+
1881+
# Angular acceleration (Euler's equation for rigid body with variable mass)
18581882
inertia_tensor = self.rocket.get_inertia_tensor_at_time(t)
18591883
I_w = inertia_tensor @ angular_velocity_vector
18601884
w_cross_Iw = angular_velocity_vector.cross(I_w)
18611885
I_dot = self.rocket.get_inertia_tensor_derivative_at_time(t)
1862-
1863-
angular_acceleration_body = inertia_tensor.inverse @ (total_moment_body - w_cross_Iw - (I_dot @ angular_velocity_vector))
1864-
1865-
# Dérivées des paramètres d'Euler
1866-
e0dot = 0.5 * (-w1*e1 - w2*e2 - w3*e3)
1867-
e1dot = 0.5 * ( w1*e0 + w3*e2 - w2*e3)
1868-
e2dot = 0.5 * ( w2*e0 - w3*e1 + w1*e3)
1869-
e3dot = 0.5 * ( w3*e0 + w2*e1 - w1*e2)
1870-
1871-
# Assemblage du vecteur dérivé
1886+
1887+
angular_acceleration_body = inertia_tensor.inverse @ (
1888+
total_moment_body - w_cross_Iw - (I_dot @ angular_velocity_vector)
1889+
)
1890+
1891+
# Euler parameters derivatives
1892+
e0dot = 0.5 * (-w1 * e1 - w2 * e2 - w3 * e3)
1893+
e1dot = 0.5 * (w1 * e0 + w3 * e2 - w2 * e3)
1894+
e2dot = 0.5 * (w2 * e0 - w3 * e1 + w1 * e3)
1895+
e3dot = 0.5 * (w3 * e0 + w2 * e1 - w1 * e2)
1896+
1897+
# Assemble the derivative vector
18721898
u_dot = [
1873-
vx, vy, vz,
1899+
vx,
1900+
vy,
1901+
vz,
18741902
*linear_acceleration_inertial,
1875-
e0dot, e1dot, e2dot, e3dot,
1876-
*angular_acceleration_body
1903+
e0dot,
1904+
e1dot,
1905+
e2dot,
1906+
e3dot,
1907+
*angular_acceleration_body,
18771908
]
1878-
1879-
# Post-processing (si nécessaire)
1909+
1910+
# Post-processing (if necessary)
18801911
if post_processing:
1881-
self.__post_processed_variables.append([
1882-
t, *linear_acceleration_inertial, *angular_acceleration_body,
1883-
*R_aero_body, *total_moment_body, net_thrust_scalar
1884-
])
1885-
1886-
return u_dot
1912+
self.__post_processed_variables.append(
1913+
[
1914+
t,
1915+
*linear_acceleration_inertial,
1916+
*angular_acceleration_body,
1917+
*R_aero_body,
1918+
*total_moment_body,
1919+
net_thrust_scalar,
1920+
]
1921+
)
18871922

1923+
return u_dot
18881924

18891925
def u_dot_parachute(self, t, u, post_processing=False):
18901926
"""Calculates derivative of u state vector with respect to time
@@ -1924,8 +1960,8 @@ def u_dot_parachute(self, t, u, post_processing=False):
19241960
mp = self.rocket.dry_mass
19251961

19261962
# Define constants
1927-
ka = 1 # Added mass coefficient (depends on parachute's porosity)
1928-
R = 1.5 # Parachute radius
1963+
# ka = 1 # Added mass coefficient (depends on parachute's porosity)
1964+
# R = 1.5 # Parachute radius
19291965
# to = 1.2
19301966
# eta = 1
19311967
# Rdot = (6 * R * (1 - eta) / (1.2**6)) * (
@@ -1934,7 +1970,7 @@ def u_dot_parachute(self, t, u, post_processing=False):
19341970
# Rdot = 0
19351971

19361972
# Calculate added mass
1937-
ma = ka * rho * (4 / 3) * np.pi * R**3
1973+
ma = 0
19381974

19391975
# Calculate freestream speed
19401976
freestream_x = vx - wind_velocity_x
@@ -1950,7 +1986,7 @@ def u_dot_parachute(self, t, u, post_processing=False):
19501986
Dz = pseudo_drag * freestream_z
19511987
ax = Dx / (mp + ma)
19521988
ay = Dy / (mp + ma)
1953-
az = (Dz - 9.8 * mp) / (mp + ma)
1989+
az = (Dz - self.env.gravity.get_value_opt(z) * mp) / (mp + ma)
19541990

19551991
if post_processing:
19561992
self.__post_processed_variables.append(
@@ -2028,7 +2064,7 @@ def x(self):
20282064

20292065
@funcify_method("Time (s)", "Y (m)", "spline", "constant")
20302066
def y(self):
2031-
"""Rocket y position relative to the lauch pad as a Function of
2067+
"""Rocket y position relative to the launch pad as a Function of
20322068
time."""
20332069
return self.solution_array[:, [0, 2]]
20342070

@@ -2924,7 +2960,7 @@ def max_rail_button2_shear_force(self):
29242960
"Time (s)", "Horizontal Distance to Launch Point (m)", "spline", "constant"
29252961
)
29262962
def drift(self):
2927-
"""Rocket horizontal distance to tha launch point, in meters, as a
2963+
"""Rocket horizontal distance to the launch point, in meters, as a
29282964
Function of time."""
29292965
return np.column_stack(
29302966
(self.time, (self.x[:, 1] ** 2 + self.y[:, 1] ** 2) ** 0.5)
@@ -3473,7 +3509,7 @@ def time_iterator(self, node_list):
34733509
yield i, node_list[i]
34743510
i += 1
34753511

3476-
def to_dict(self, include_outputs=False):
3512+
def to_dict(self, include_outputs=False, **_kwargs):
34773513
data = {
34783514
"rocket": self.rocket,
34793515
"env": self.env,
@@ -3696,9 +3732,7 @@ def add(self, flight_phase, index=None): # TODO: quite complex method
36963732
new_index = (
36973733
index - 1
36983734
if flight_phase.t < previous_phase.t
3699-
else index + 1
3700-
if flight_phase.t > next_phase.t
3701-
else index
3735+
else index + 1 if flight_phase.t > next_phase.t else index
37023736
)
37033737
flight_phase.t += adjust
37043738
self.add(flight_phase, new_index)

0 commit comments

Comments
 (0)