-
-
Notifications
You must be signed in to change notification settings - Fork 200
ENH: Implementing 3-dof-simulation #745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
e557e17
a768648
9b00c57
87e9180
4524219
57b4732
81ce869
0673076
47c9f2f
f6ad658
33cb63a
1d2d4dc
fe21271
b18b241
8aa1016
87e7dce
0e4d8a4
41e94f1
e299a30
d4dc989
c8096c5
724f9dd
f1e0fb0
4b9b952
45380fd
5cd1535
1e590c2
981dda5
5c75298
70f24ee
0cb0994
58f8b0d
191744f
265dd93
5aa2027
464212d
a1b1d1f
d9cbde5
0aa32b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
from functools import cached_property | ||
from typing import Callable | ||
|
||
import numpy as np | ||
|
||
from rocketpy.mathutils.function import Function, funcify_method | ||
|
||
from .motor import Motor | ||
|
||
|
||
class PointMassMotor(Motor): | ||
"""Motor modeled as a point mass for 3-DOF simulations.""" | ||
|
||
def __init__( | ||
self, | ||
thrust_source, | ||
dry_mass, | ||
propellant_initial_mass, | ||
burn_time=None, | ||
propellant_final_mass=None, | ||
reshape_thrust_curve=False, | ||
interpolation_method="linear", | ||
): | ||
if isinstance(thrust_source, (int, float, Callable)): | ||
if propellant_initial_mass is None: | ||
raise ValueError( | ||
"For constant or callable thrust, 'propellant_initial_mass' is required." | ||
) | ||
if burn_time is None and propellant_final_mass is None: | ||
raise ValueError( | ||
"For constant or callable thrust, either 'burn_time' or " | ||
"'propellant_final_mass' must be provided." | ||
) | ||
elif isinstance(thrust_source, (Function, np.ndarray, str)): | ||
if propellant_initial_mass is None: | ||
raise ValueError( | ||
"For thrust from a Function, NumPy array, or CSV, 'propellant_initial_mass' is required." | ||
) | ||
else: | ||
raise TypeError( | ||
"Invalid 'thrust_source' type. Must be int, float, callable, str, numpy.ndarray, or Function." | ||
) | ||
|
||
self._propellant_initial_mass = propellant_initial_mass | ||
self.propellant_final_mass = propellant_final_mass | ||
|
||
super().__init__( | ||
thrust_source=thrust_source, | ||
dry_inertia=(0, 0, 0), | ||
nozzle_radius=0, | ||
center_of_dry_mass_position=0, | ||
dry_mass=dry_mass, | ||
nozzle_position=0, | ||
burn_time=burn_time, | ||
reshape_thrust_curve=reshape_thrust_curve, | ||
interpolation_method=interpolation_method, | ||
coordinate_system_orientation="nozzle_to_combustion_chamber", | ||
) | ||
|
||
@property | ||
def propellant_initial_mass(self): | ||
return self._propellant_initial_mass | ||
|
||
@funcify_method("Time (s)", "Exhaust velocity (m/s)") | ||
def exhaust_velocity(self): | ||
"""Assume constant exhaust velocity: total impulse / propellant mass""" | ||
v_e = self.total_impulse / self.propellant_initial_mass | ||
return Function(v_e).set_discrete_based_on_model(self.thrust) | ||
|
||
@cached_property | ||
def total_mass_flow_rate(self) -> Function: | ||
"""Mass flow rate: -thrust / exhaust_velocity""" | ||
return -self.thrust / self.exhaust_velocity | ||
|
||
@cached_property | ||
def center_of_propellant_mass(self): | ||
"""Center of propellant mass is always zero""" | ||
return Function(0.0) | ||
|
||
# Propellant inertias: always zero, but return as Function objects | ||
def _zero_inertia_func(self): | ||
return Function(0.0) | ||
|
||
@cached_property | ||
def propellant_I_11(self): | ||
return self._zero_inertia_func() | ||
|
||
@cached_property | ||
def propellant_I_12(self): | ||
return self._zero_inertia_func() | ||
|
||
@cached_property | ||
def propellant_I_13(self): | ||
return self._zero_inertia_func() | ||
|
||
@cached_property | ||
def propellant_I_22(self): | ||
return self._zero_inertia_func() | ||
|
||
@cached_property | ||
def propellant_I_23(self): | ||
return self._zero_inertia_func() | ||
|
||
@cached_property | ||
def propellant_I_33(self): | ||
return self._zero_inertia_func() |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could we also accept drag curves, instead of only float values? |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2052,3 +2052,112 @@ def from_dict(cls, data): | |
) | ||
|
||
return rocket | ||
|
||
|
||
class PointMassRocket(Rocket): | ||
def __init__( | ||
self, | ||
radius: float = 0.05, | ||
mass: float = 0, | ||
center_of_mass_without_motor: float = 0, | ||
power_off_drag: float = 0.4, | ||
power_on_drag: float = 0.4, | ||
): | ||
self._center_of_mass_without_motor_pointmass = center_of_mass_without_motor | ||
self._center_of_dry_mass_position = center_of_mass_without_motor | ||
self._center_of_mass = center_of_mass_without_motor | ||
# Dry inertias are zero for point mass | ||
self._dry_I_11 = 0.0 | ||
self._dry_I_22 = 0.0 | ||
self._dry_I_33 = 0.0 | ||
self._dry_I_12 = 0.0 | ||
self._dry_I_13 = 0.0 | ||
self._dry_I_23 = 0.0 | ||
|
||
# Call base init with safe defaults | ||
super().__init__( | ||
radius=radius, | ||
mass=mass, | ||
inertia=(0, 0, 0), | ||
power_off_drag=power_off_drag, | ||
power_on_drag=power_on_drag, | ||
center_of_mass_without_motor=center_of_mass_without_motor, | ||
) | ||
|
||
# ------------------------------------------------------------------ | ||
# Center of Mass Properties | ||
# ------------------------------------------------------------------ | ||
@property | ||
def center_of_mass_without_motor(self): | ||
return self._center_of_mass_without_motor_pointmass | ||
|
||
@center_of_mass_without_motor.setter | ||
def center_of_mass_without_motor(self, value): | ||
self._center_of_mass_without_motor_pointmass = value | ||
|
||
@property | ||
def center_of_dry_mass_position(self): | ||
return self._center_of_dry_mass_position | ||
|
||
@center_of_dry_mass_position.setter | ||
def center_of_dry_mass_position(self, value): | ||
self._center_of_dry_mass_position = value | ||
|
||
@property | ||
def center_of_mass(self): | ||
return self._center_of_mass | ||
|
||
@center_of_mass.setter | ||
def center_of_mass(self, value): | ||
self._center_of_mass = value | ||
|
||
# ------------------------------------------------------------------ | ||
# Inertia Properties (always zero) | ||
# ------------------------------------------------------------------ | ||
@property | ||
def dry_I_11(self): | ||
return 0.0 | ||
|
||
@dry_I_11.setter | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: do you really need a |
||
def dry_I_11(self, value): | ||
self._dry_I_11 = 0.0 | ||
|
||
@property | ||
def dry_I_22(self): | ||
return 0.0 | ||
|
||
@dry_I_22.setter | ||
def dry_I_22(self, value): | ||
self._dry_I_22 = 0.0 | ||
|
||
@property | ||
def dry_I_33(self): | ||
return 0.0 | ||
|
||
@dry_I_33.setter | ||
def dry_I_33(self, value): | ||
self._dry_I_33 = 0.0 | ||
|
||
@property | ||
def dry_I_12(self): | ||
return 0.0 | ||
|
||
@dry_I_12.setter | ||
def dry_I_12(self, value): | ||
self._dry_I_12 = 0.0 | ||
|
||
@property | ||
def dry_I_13(self): | ||
return 0.0 | ||
|
||
@dry_I_13.setter | ||
def dry_I_13(self, value): | ||
self._dry_I_13 = 0.0 | ||
|
||
@property | ||
def dry_I_23(self): | ||
return 0.0 | ||
|
||
@dry_I_23.setter | ||
def dry_I_23(self, value): | ||
self._dry_I_23 = 0.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two methods seem to be equal to the parent class
Motor.exhaust_velocity
andMotor.total_mass_flow_rate
. If I understood correctly, they could be deleted without any problems (the parent class one would be used).