-
-
Notifications
You must be signed in to change notification settings - Fork 204
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
c5152fa
a097ea0
d612fa3
5b6d7e5
5a47616
14c81f0
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? 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. @MateusStano maybe we should also a TODO for implementing this in the future? |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2102,3 +2102,61 @@ def from_dict(cls, data): | |
rocket._add_controllers(controller) | ||
|
||
return rocket | ||
|
||
|
||
class PointMassRocket(Rocket): | ||
def __init__( | ||
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 you make a docstring description for the class? It can short and simple, like: Class representing a point mass rocket. A point mass rocket is a
simplified model of a rocket that assumes all of its mass is concentrated
at a single point. |
||
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, | ||
Comment on lines
+2110
to
+2114
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. @MateusStano do you think it makes sense of having default values here? |
||
): | ||
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 | ||
Comment on lines
+2140
to
+2162
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. These properties are essentially the same as attributes, behavior wise, right? Are they needed (e.g. I don't see much use for a new attribute def __init__(self, ...):
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,
) |
Uh oh!
There was an error while loading. Please reload this page.