diff --git a/CHANGELOG.md b/CHANGELOG.md index 90aa086ca..87e3c50a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - MNT: Refactor flight prints module [#579](https://github.com/RocketPy-Team/RocketPy/pull/579) - DOC: Convert CompareFlights example notebooks to .rst files [#576](https://github.com/RocketPy-Team/RocketPy/pull/576) +- MNT: Refactor inertia calculations using parallel axis theorem [#573] (https://github.com/RocketPy-Team/RocketPy/pull/573) - ENH: Optional argument to show the plot in Function.compare_plots [#563](https://github.com/RocketPy-Team/RocketPy/pull/563) ### Fixed diff --git a/rocketpy/motors/hybrid_motor.py b/rocketpy/motors/hybrid_motor.py index 4b28a96d2..6f0849cd0 100644 --- a/rocketpy/motors/hybrid_motor.py +++ b/rocketpy/motors/hybrid_motor.py @@ -1,3 +1,5 @@ +from rocketpy.tools import parallel_axis_theorem_from_com + from ..mathutils.function import Function, funcify_method, reset_funcified_methods from ..plots.hybrid_motor_plots import _HybridMotorPlots from ..prints.hybrid_motor_prints import _HybridMotorPrints @@ -455,22 +457,21 @@ def propellant_I_11(self): ---------- .. [1] https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor """ - solid_correction = ( - self.solid.propellant_mass - * (self.solid.center_of_propellant_mass - self.center_of_propellant_mass) - ** 2 - ) - liquid_correction = ( - self.liquid.propellant_mass - * (self.liquid.center_of_propellant_mass - self.center_of_propellant_mass) - ** 2 - ) - I_11 = ( - self.solid.propellant_I_11 - + solid_correction - + self.liquid.propellant_I_11 - + liquid_correction + solid_mass = self.solid.propellant_mass + liquid_mass = self.liquid.propellant_mass + + cm = self.center_of_propellant_mass + solid_cm_to_cm = self.solid.center_of_propellant_mass - cm + liquid_cm_to_cm = self.liquid.center_of_propellant_mass - cm + + solid_prop_inertia = self.solid.propellant_I_11 + liquid_prop_inertia = self.liquid.propellant_I_11 + + I_11 = parallel_axis_theorem_from_com( + solid_prop_inertia, solid_mass, solid_cm_to_cm + ) + parallel_axis_theorem_from_com( + liquid_prop_inertia, liquid_mass, liquid_cm_to_cm ) return I_11 diff --git a/rocketpy/motors/liquid_motor.py b/rocketpy/motors/liquid_motor.py index ac525b379..01f728473 100644 --- a/rocketpy/motors/liquid_motor.py +++ b/rocketpy/motors/liquid_motor.py @@ -7,6 +7,7 @@ funcify_method, reset_funcified_methods, ) +from rocketpy.tools import parallel_axis_theorem_from_com from ..plots.liquid_motor_plots import _LiquidMotorPlots from ..prints.liquid_motor_prints import _LiquidMotorPrints @@ -388,10 +389,9 @@ def propellant_I_11(self): for positioned_tank in self.positioned_tanks: tank = positioned_tank.get("tank") tank_position = positioned_tank.get("position") - I_11 += ( - tank.inertia - + tank.fluid_mass - * (tank_position + tank.center_of_mass - center_of_mass) ** 2 + distance = tank_position + tank.center_of_mass - center_of_mass + I_11 += parallel_axis_theorem_from_com( + tank.inertia, tank.fluid_mass, distance ) return I_11 diff --git a/rocketpy/motors/motor.py b/rocketpy/motors/motor.py index 6c2242a9f..3834f4a15 100644 --- a/rocketpy/motors/motor.py +++ b/rocketpy/motors/motor.py @@ -7,7 +7,7 @@ from ..mathutils.function import Function, funcify_method from ..plots.motor_plots import _MotorPlots from ..prints.motor_prints import _MotorPrints -from ..tools import tuple_handler +from ..tools import parallel_axis_theorem_from_com, tuple_handler try: from functools import cached_property @@ -513,25 +513,19 @@ def I_11(self): ---------- .. [1] https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor """ - # Propellant inertia tensor 11 component wrt propellant center of mass - propellant_I_11 = self.propellant_I_11 - # Dry inertia tensor 11 component wrt dry center of mass + prop_I_11 = self.propellant_I_11 dry_I_11 = self.dry_I_11 - # Steiner theorem the get inertia wrt motor center of mass - propellant_I_11 += ( - self.propellant_mass - * (self.center_of_propellant_mass - self.center_of_mass) ** 2 - ) + prop_to_cm = self.center_of_propellant_mass - self.center_of_mass + dry_to_cm = self.center_of_dry_mass_position - self.center_of_mass - dry_I_11 += ( - self.dry_mass - * (self.center_of_dry_mass_position - self.center_of_mass) ** 2 + prop_I_11 = parallel_axis_theorem_from_com( + prop_I_11, self.propellant_mass, prop_to_cm ) + dry_I_11 = parallel_axis_theorem_from_com(dry_I_11, self.dry_mass, dry_to_cm) - # Sum of inertia components - return propellant_I_11 + dry_I_11 + return prop_I_11 + dry_I_11 @funcify_method("Time (s)", "Inertia I_22 (kg m²)") def I_22(self): diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 8154f2967..aaf585091 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -18,6 +18,7 @@ ) from rocketpy.rocket.components import Components from rocketpy.rocket.parachute import Parachute +from rocketpy.tools import parallel_axis_theorem_from_com class Rocket: @@ -619,6 +620,10 @@ def evaluate_dry_inertias(self): ---------- .. [1] https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor """ + # Get masses + motor_dry_mass = self.motor.dry_mass + mass = self.mass + # Compute axes distances noMCM_to_CDM = ( self.center_of_mass_without_motor - self.center_of_dry_mass_position @@ -628,18 +633,18 @@ def evaluate_dry_inertias(self): ) # Compute dry inertias - self.dry_I_11 = ( - self.I_11_without_motor - + self.mass * noMCM_to_CDM**2 - + self.motor.dry_I_11 - + self.motor.dry_mass * motorCDM_to_CDM**2 + self.dry_I_11 = parallel_axis_theorem_from_com( + self.I_11_without_motor, mass, noMCM_to_CDM + ) + parallel_axis_theorem_from_com( + self.motor.dry_I_11, motor_dry_mass, motorCDM_to_CDM ) - self.dry_I_22 = ( - self.I_22_without_motor - + self.mass * noMCM_to_CDM**2 - + self.motor.dry_I_22 - + self.motor.dry_mass * motorCDM_to_CDM**2 + + self.dry_I_22 = parallel_axis_theorem_from_com( + self.I_22_without_motor, mass, noMCM_to_CDM + ) + parallel_axis_theorem_from_com( + self.motor.dry_I_22, motor_dry_mass, motorCDM_to_CDM ) + self.dry_I_33 = self.I_33_without_motor + self.motor.dry_I_33 self.dry_I_12 = self.I_12_without_motor + self.motor.dry_I_12 self.dry_I_13 = self.I_13_without_motor + self.motor.dry_I_13 @@ -696,18 +701,14 @@ def evaluate_inertias(self): CM_to_CPM = self.center_of_mass - self.center_of_propellant_position # Compute inertias - self.I_11 = ( - self.dry_I_11 - + self.motor.I_11 - + dry_mass * CM_to_CDM**2 - + prop_mass * CM_to_CPM**2 - ) - self.I_22 = ( - self.dry_I_22 - + self.motor.I_22 - + dry_mass * CM_to_CDM**2 - + prop_mass * CM_to_CPM**2 - ) + self.I_11 = parallel_axis_theorem_from_com( + self.dry_I_11, dry_mass, CM_to_CDM + ) + parallel_axis_theorem_from_com(self.motor.I_11, prop_mass, CM_to_CPM) + + self.I_22 = parallel_axis_theorem_from_com( + self.dry_I_22, dry_mass, CM_to_CDM + ) + parallel_axis_theorem_from_com(self.motor.I_22, prop_mass, CM_to_CPM) + self.I_33 = self.dry_I_33 + self.motor.I_33 self.I_12 = self.dry_I_12 + self.motor.I_12 self.I_13 = self.dry_I_13 + self.motor.I_13 diff --git a/rocketpy/tools.py b/rocketpy/tools.py index bcff91fb8..1ce588636 100644 --- a/rocketpy/tools.py +++ b/rocketpy/tools.py @@ -382,6 +382,33 @@ def check_requirement_version(module_name, version): return True +def parallel_axis_theorem_from_com(com_inertia_moment, mass, distance): + """Calculates the moment of inertia of a object relative to a new axis using + the parallel axis theorem. The new axis is parallel to and at a distance + 'distance' from the original axis, which *must* passes through the object's + center of mass. + + Parameters + ---------- + com_inertia_moment : float + Moment of inertia relative to the center of mass of the object. + mass : float + Mass of the object. + distance : float + Perpendicular distance between the original and new axis. + + Returns + ------- + float + Moment of inertia relative to the new axis. + + Reference + --------- + https://en.wikipedia.org/wiki/Parallel_axis_theorem + """ + return com_inertia_moment + mass * distance**2 + + # Flight