machwave 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- machwave/models/__init__.py +0 -0
- machwave/models/atmosphere/__init__.py +87 -0
- machwave/models/atmosphere/atm_1976.py +86 -0
- machwave/models/materials/__init__.py +37 -0
- machwave/models/materials/metals.py +86 -0
- machwave/models/materials/polymers.py +50 -0
- machwave/models/propulsion/__init__.py +209 -0
- machwave/models/propulsion/grain/__init__.py +342 -0
- machwave/models/propulsion/grain/fmm/_2d.py +187 -0
- machwave/models/propulsion/grain/fmm/_3d.py +157 -0
- machwave/models/propulsion/grain/fmm/__init__.py +162 -0
- machwave/models/propulsion/grain/fmm/services.py +227 -0
- machwave/models/propulsion/grain/fmm/stl.py +68 -0
- machwave/models/propulsion/grain/geometries/__init__.py +17 -0
- machwave/models/propulsion/grain/geometries/bates.py +74 -0
- machwave/models/propulsion/grain/geometries/conical.py +55 -0
- machwave/models/propulsion/grain/geometries/d_grain.py +40 -0
- machwave/models/propulsion/grain/geometries/multi_port.py +64 -0
- machwave/models/propulsion/grain/geometries/rod_and_tube.py +53 -0
- machwave/models/propulsion/grain/geometries/star.py +67 -0
- machwave/models/propulsion/grain/geometries/wagon_wheel.py +81 -0
- machwave/models/propulsion/propellants/__init__.py +17 -0
- machwave/models/propulsion/propellants/solid.py +260 -0
- machwave/models/propulsion/structure/__init__.py +16 -0
- machwave/models/propulsion/structure/chamber.py +222 -0
- machwave/models/propulsion/structure/nozzle.py +73 -0
- machwave/models/propulsion/thermals.py +14 -0
- machwave/models/recovery/__init__.py +58 -0
- machwave/models/recovery/events.py +116 -0
- machwave/models/recovery/parachutes.py +105 -0
- machwave/models/rocket/__init__.py +91 -0
- machwave/models/rocket/fuselage.py +89 -0
- machwave/montecarlo/__init__.py +255 -0
- machwave/montecarlo/random.py +184 -0
- machwave/operations/__init__.py +33 -0
- machwave/operations/ballistics/_1dof.py +188 -0
- machwave/operations/ballistics/__init__.py +28 -0
- machwave/operations/internal_ballistics/__init__.py +423 -0
- machwave/services/__init__.py +0 -0
- machwave/services/common.py +5 -0
- machwave/services/conversions.py +64 -0
- machwave/services/decorators.py +62 -0
- machwave/services/equations.py +81 -0
- machwave/services/export_formats.py +63 -0
- machwave/services/factories.py +28 -0
- machwave/services/isentropic_flow.py +388 -0
- machwave/services/math/__init__.py +0 -0
- machwave/services/math/geometric.py +115 -0
- machwave/services/numpy.py +22 -0
- machwave/services/plots/__init__.py +0 -0
- machwave/services/plots/ballistics.py +52 -0
- machwave/services/plots/internal_ballistics.py +83 -0
- machwave/simulations/__init__.py +69 -0
- machwave/simulations/ballistics.py +147 -0
- machwave/simulations/internal_balistics_coupled.py +151 -0
- machwave/simulations/internal_ballistics.py +103 -0
- machwave/solvers/__init__.py +0 -0
- machwave/solvers/odes.py +60 -0
- machwave-0.1.0.dist-info/METADATA +746 -0
- machwave-0.1.0.dist-info/RECORD +61 -0
- machwave-0.1.0.dist-info/WHEEL +4 -0
|
File without changes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Atmospheric models for use in rocket simulations. The models are used to
|
|
3
|
+
calculate the properties of the atmosphere at a given altitude above mean sea
|
|
4
|
+
level (AMSL).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Atmosphere(ABC):
|
|
11
|
+
"""Abstract class that represents an atmospheric model."""
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def get_density(self, y_amsl: float) -> float:
|
|
15
|
+
"""
|
|
16
|
+
Get the air density at the given altitude above mean sea level (AMSL).
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
y_amsl (float): Altitude above mean sea level in meters.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
float: Air density in kg/m^3.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def get_gravity(self, y_amsl: float) -> float:
|
|
27
|
+
"""
|
|
28
|
+
Get the acceleration due to gravity at the given altitude above mean
|
|
29
|
+
sea level (AMSL).
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
y_amsl (float): Altitude above mean sea level in meters.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
float: Acceleration due to gravity in m/s^2.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def get_pressure(self, y_amsl: float) -> float:
|
|
40
|
+
"""
|
|
41
|
+
Get the air pressure at the given altitude above mean sea level (AMSL).
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
y_amsl (float): Altitude above mean sea level in meters.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
float: Air pressure in Pascal (Pa).
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
def get_sonic_velocity(self, y_amsl: float) -> float:
|
|
52
|
+
"""
|
|
53
|
+
Get the speed of sound in air at the given altitude above mean sea
|
|
54
|
+
level (AMSL).
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
y_amsl (float): Altitude above mean sea level in meters.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
float: Speed of sound in m/s.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
def get_wind_velocity(self, y_amsl: float) -> tuple[float, float]:
|
|
65
|
+
"""
|
|
66
|
+
Get the wind velocity components at the given altitude above mean
|
|
67
|
+
sea level (AMSL).
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
y_amsl (float): Altitude above mean sea level in meters.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
tuple[float, float]: Wind velocity components (Northward, Eastward) in m/s.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
@abstractmethod
|
|
77
|
+
def get_viscosity(self, y_amsl: float) -> float:
|
|
78
|
+
"""
|
|
79
|
+
Get the dynamic viscosity of air at the given altitude above mean sea
|
|
80
|
+
level (AMSL).
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
y_amsl (float): Altitude above mean sea level in meters.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
float: Dynamic viscosity of air in Pascal-second (Pa-s).
|
|
87
|
+
"""
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Implementation of the 1976 Standard Atmosphere model.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from fluids.atmosphere import ATMOSPHERE_1976
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from machwave.models.atmosphere import Atmosphere
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Atmosphere1976(Atmosphere):
|
|
12
|
+
"""
|
|
13
|
+
Atmospheric model based on the 1976 Standard Atmosphere. This model uses
|
|
14
|
+
the fluids library to calculate the properties of the atmosphere.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def get_density(self, y_amsl: float) -> float:
|
|
18
|
+
return ATMOSPHERE_1976(y_amsl).rho
|
|
19
|
+
|
|
20
|
+
def get_gravity(self, y_amsl: float) -> float:
|
|
21
|
+
return ATMOSPHERE_1976.gravity(y_amsl)
|
|
22
|
+
|
|
23
|
+
def get_pressure(self, y_amsl: float) -> float:
|
|
24
|
+
return ATMOSPHERE_1976(y_amsl).P
|
|
25
|
+
|
|
26
|
+
def get_sonic_velocity(self, y_amsl: float) -> float:
|
|
27
|
+
return ATMOSPHERE_1976(y_amsl).v_sonic
|
|
28
|
+
|
|
29
|
+
def get_wind_velocity(self, y_amsl: float) -> tuple[float, float]:
|
|
30
|
+
"""
|
|
31
|
+
7 m/s wind velocity in both x and y directions.
|
|
32
|
+
"""
|
|
33
|
+
return (7, 7)
|
|
34
|
+
|
|
35
|
+
def get_viscosity(self, y_amsl: float) -> float:
|
|
36
|
+
return ATMOSPHERE_1976(y_amsl).mu
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Atmosphere1976WindPowerLaw(Atmosphere1976):
|
|
40
|
+
"""
|
|
41
|
+
Atmospheric model based on the 1976 Standard Atmosphere, using a power-law
|
|
42
|
+
model for wind velocity variation with altitude.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, v_ref: float, z_ref: float, alpha: float, direction_deg: float):
|
|
46
|
+
"""
|
|
47
|
+
Initialize the atmosphere model with power-law wind parameters.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
v_ref (float): Wind speed at the reference height (in m/s).
|
|
51
|
+
z_ref (float): Reference height (in meters) where the wind speed is known.
|
|
52
|
+
alpha (float): Wind shear exponent.
|
|
53
|
+
direction_deg (float): Wind direction in degrees (0° is North, 90° is East).
|
|
54
|
+
"""
|
|
55
|
+
super().__init__()
|
|
56
|
+
|
|
57
|
+
if z_ref == 0:
|
|
58
|
+
raise ValueError("Please provide a non-zero reference height 'z_ref'.")
|
|
59
|
+
|
|
60
|
+
self.v_ref = v_ref
|
|
61
|
+
self.z_ref = z_ref
|
|
62
|
+
self.alpha = alpha
|
|
63
|
+
self.direction_deg = direction_deg
|
|
64
|
+
|
|
65
|
+
def get_wind_velocity(self, y_amsl: float) -> tuple[float, float]:
|
|
66
|
+
"""
|
|
67
|
+
Get the wind velocity components at the given altitude above mean sea level (AMSL)
|
|
68
|
+
using the power law.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
y_amsl (float): Altitude above mean sea level in meters.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
tuple[float, float]: Wind velocity components (Northward, Eastward) in m/s.
|
|
75
|
+
"""
|
|
76
|
+
if y_amsl <= 0:
|
|
77
|
+
y_amsl = self.z_ref
|
|
78
|
+
|
|
79
|
+
wind_speed = self.v_ref * (y_amsl / self.z_ref) ** self.alpha
|
|
80
|
+
|
|
81
|
+
direction_rad = np.radians(self.direction_deg)
|
|
82
|
+
|
|
83
|
+
v_northward = wind_speed * np.cos(direction_rad)
|
|
84
|
+
v_eastward = wind_speed * np.sin(direction_rad)
|
|
85
|
+
|
|
86
|
+
return v_northward, v_eastward
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@dataclass
|
|
5
|
+
class Material:
|
|
6
|
+
"""
|
|
7
|
+
Base class representing a generic material.
|
|
8
|
+
|
|
9
|
+
Attributes:
|
|
10
|
+
density (float): Density of the material.
|
|
11
|
+
yield_strength (float): Yield strength of the material.
|
|
12
|
+
ultimate_strength (float): Ultimate strength of the material.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
density: float
|
|
16
|
+
yield_strength: float
|
|
17
|
+
ultimate_strength: float
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class NozzleMaterial(Material):
|
|
22
|
+
"""
|
|
23
|
+
Base class for a Nozzle material.
|
|
24
|
+
|
|
25
|
+
Contains all attributes from the Material class, adding c_1 and c_2 for
|
|
26
|
+
calculating isentropic flow correction factors. These special parameters
|
|
27
|
+
are referenced in the a015140 paper.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
c_1 (float): Coefficient related to heat transfer properties of a BATES
|
|
31
|
+
motor.
|
|
32
|
+
c_2 (float): Time constant obtained from the analysis of the transient
|
|
33
|
+
heating of a standard BATES motor.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
c_1: float
|
|
37
|
+
c_2: float
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from . import NozzleMaterial
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class Steel(NozzleMaterial):
|
|
8
|
+
"""
|
|
9
|
+
Steel material class derived from the NozzleMaterial base class.
|
|
10
|
+
|
|
11
|
+
This class represents a specific type of material, Steel, which inherits
|
|
12
|
+
properties from the NozzleMaterial base class. It provides default values
|
|
13
|
+
for the density, yield strength, ultimate strength, c_1, and c_2 specific to
|
|
14
|
+
Steel.
|
|
15
|
+
|
|
16
|
+
Data obtained from:
|
|
17
|
+
https://www.thyssenkrupp-materials.co.uk/stainless-steel-304-14301.html
|
|
18
|
+
|
|
19
|
+
Inherits:
|
|
20
|
+
NozzleMaterial: Base class representing a nozzle material.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
None
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
density: float = 8000
|
|
27
|
+
yield_strength: float = 210e6
|
|
28
|
+
ultimate_strength: float = 520e6
|
|
29
|
+
c_1: float = 0.00506
|
|
30
|
+
c_2: float = 0.0
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class Al6063T5(NozzleMaterial):
|
|
35
|
+
"""
|
|
36
|
+
Al6063T5 (Aluminum) material class derived from the NozzleMaterial base
|
|
37
|
+
class.
|
|
38
|
+
|
|
39
|
+
This class represents a specific type of material, Al6063T5 (Aluminum),
|
|
40
|
+
which inherits properties from the NozzleMaterial base class. It provides
|
|
41
|
+
default values for the density, yield strength, ultimate strength, c_1, and
|
|
42
|
+
c_2 specific to Al6063T5.
|
|
43
|
+
|
|
44
|
+
Data obtained from:
|
|
45
|
+
https://www.makeitfrom.com/material-properties/6063-T5-Aluminum
|
|
46
|
+
|
|
47
|
+
Inherits:
|
|
48
|
+
NozzleMaterial: Base class representing a nozzle material.
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
None
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
density: float = 2700
|
|
55
|
+
yield_strength: float = 145e6
|
|
56
|
+
ultimate_strength: float = 185e6
|
|
57
|
+
c_1: float = 0.00506
|
|
58
|
+
c_2: float = 0.0
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class Al6061T6(NozzleMaterial):
|
|
63
|
+
"""
|
|
64
|
+
Al6061T6 (Aluminum) material class derived from the NozzleMaterial base
|
|
65
|
+
class.
|
|
66
|
+
|
|
67
|
+
This class represents a specific type of material, Al6061T6 (Aluminum),
|
|
68
|
+
which inherits properties from the NozzleMaterial base class. It provides
|
|
69
|
+
default values for the density, yield strength, ultimate strength, c_1, and
|
|
70
|
+
c_2 specific to Al6061T6.
|
|
71
|
+
|
|
72
|
+
Data obtained from:
|
|
73
|
+
https://matweb.com/search/DataSheet.aspx?MatGUID=b8d536e0b9b54bd7b69e4124d8f1d20a&ckck=1
|
|
74
|
+
|
|
75
|
+
Inherits:
|
|
76
|
+
NozzleMaterial: Base class representing a nozzle material.
|
|
77
|
+
|
|
78
|
+
Attributes:
|
|
79
|
+
None
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
density: float = 2700
|
|
83
|
+
yield_strength: float = 262e6
|
|
84
|
+
ultimate_strength: float = 290e6
|
|
85
|
+
c_1: float = 0.00506
|
|
86
|
+
c_2: float = 0.0
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from . import Material
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class EPDM(Material):
|
|
8
|
+
"""
|
|
9
|
+
EPDM (Ethylene Propylene Diene Monomer) material class.
|
|
10
|
+
|
|
11
|
+
Data obtained from:
|
|
12
|
+
https://www.matweb.com/search/datasheet.aspx?matguid=f8e3355cc2c541fbb0174960466819c0&ckck=1
|
|
13
|
+
|
|
14
|
+
Inherits:
|
|
15
|
+
Material: Base class representing a generic material.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
None
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
density: float = 1500
|
|
22
|
+
yield_strength: float = None
|
|
23
|
+
ultimate_strength: float = 17e6
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EpoxiResin(Material):
|
|
27
|
+
"""
|
|
28
|
+
EpoxiResin material class.
|
|
29
|
+
|
|
30
|
+
Inherits:
|
|
31
|
+
Material: Base class representing a generic material.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
None
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Initialize an EpoxiResin object.
|
|
40
|
+
|
|
41
|
+
This constructor sets the default values for the density, yield
|
|
42
|
+
strength, and ultimate strength of EpoxiResin.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
None
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
None
|
|
49
|
+
"""
|
|
50
|
+
super().__init__(density=1100, yield_strength=60e6, ultimate_strength=60e6)
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from machwave.models.propulsion.grain import Grain
|
|
6
|
+
from machwave.models.propulsion.propellants import Propellant
|
|
7
|
+
from machwave.models.propulsion.structure import MotorStructure
|
|
8
|
+
from machwave.services.isentropic_flow import (
|
|
9
|
+
get_thrust_coefficients,
|
|
10
|
+
get_thrust_from_cf,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Motor(ABC):
|
|
15
|
+
"""
|
|
16
|
+
Abstract rocket motor/engine class. Can be used to model any chemical
|
|
17
|
+
rocket propulsion system, such as Solid, Hybrid and Liquid.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
propellant: Propellant,
|
|
23
|
+
structure: MotorStructure,
|
|
24
|
+
) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Instantiates object attributes common to any motor/engine (Solid,
|
|
27
|
+
Hybrid or Liquid).
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
propellant (Propellant): Object representing the propellant used in the motor.
|
|
31
|
+
structure (MotorStructure): Object representing the structure of the motor.
|
|
32
|
+
"""
|
|
33
|
+
self.propellant = propellant
|
|
34
|
+
self.structure = structure
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def get_launch_mass(self) -> float:
|
|
38
|
+
"""
|
|
39
|
+
Calculates the total mass of the rocket before launch.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
float: Total mass of the rocket before launch, in kg
|
|
43
|
+
"""
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def get_dry_mass(self) -> float:
|
|
48
|
+
"""
|
|
49
|
+
Calculates the dry mass of the rocket at any time.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
float: Dry mass of the rocket, in kg
|
|
53
|
+
"""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def get_center_of_gravity(self) -> np.ndarray:
|
|
58
|
+
"""
|
|
59
|
+
Calculates center of gravity of the propulsion system.
|
|
60
|
+
|
|
61
|
+
Coordinate system is originated in the point defined by the nozzle's
|
|
62
|
+
exit area surface and the combustion chamber axis.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
np.ndarray: Center of gravity position, in m, [x, y, z]
|
|
66
|
+
"""
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def get_thrust_coefficient_correction_factor(self) -> float:
|
|
71
|
+
"""
|
|
72
|
+
Calculates the thrust coefficient correction factor. This factor is
|
|
73
|
+
adimensional and should be applied to the ideal thrust coefficient to
|
|
74
|
+
get the real thrust coefficient.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
float: Thrust coefficient correction factor
|
|
78
|
+
"""
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
@abstractmethod
|
|
82
|
+
def get_thrust_coefficient(self) -> float:
|
|
83
|
+
"""
|
|
84
|
+
Calculates the thrust coefficient at a particular instant.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
float: Thrust coefficient
|
|
88
|
+
"""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
def get_thrust(self, cf: float, chamber_pressure: float) -> float:
|
|
92
|
+
"""
|
|
93
|
+
Calculates the thrust based on instantaneous thrust coefficient and
|
|
94
|
+
chamber pressure.
|
|
95
|
+
|
|
96
|
+
Utilized nozzle throat area from the structure and nozzle classes.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
cf (float): Instantaneous thrust coefficient, adimensional
|
|
100
|
+
chamber_pressure (float): Instantaneous chamber pressure, in Pa
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
float: Instantaneous thrust, in Newtons
|
|
104
|
+
"""
|
|
105
|
+
return get_thrust_from_cf(
|
|
106
|
+
cf,
|
|
107
|
+
chamber_pressure,
|
|
108
|
+
self.structure.nozzle.get_throat_area(),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class SolidMotor(Motor):
|
|
113
|
+
def __init__(
|
|
114
|
+
self,
|
|
115
|
+
grain: Grain,
|
|
116
|
+
propellant: Propellant,
|
|
117
|
+
structure: MotorStructure,
|
|
118
|
+
) -> None:
|
|
119
|
+
self.grain = grain
|
|
120
|
+
super().__init__(propellant, structure)
|
|
121
|
+
|
|
122
|
+
self.cf_ideal = None # ideal thrust coefficient
|
|
123
|
+
self.cf_real = None # real thrust coefficient
|
|
124
|
+
|
|
125
|
+
def get_free_chamber_volume(self, propellant_volume: float) -> float:
|
|
126
|
+
"""
|
|
127
|
+
Calculates the chamber volume without any propellant.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
propellant_volume (float): Propellant volume, in m^3
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
float: Free chamber volume, in m^3
|
|
134
|
+
"""
|
|
135
|
+
return self.structure.chamber.empty_volume - propellant_volume
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def initial_propellant_mass(self) -> float:
|
|
139
|
+
"""
|
|
140
|
+
Returns:
|
|
141
|
+
float: Initial propellant mass, in kg
|
|
142
|
+
"""
|
|
143
|
+
return (
|
|
144
|
+
self.grain.get_propellant_volume(web_distance=0) * self.propellant.density
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
def get_thrust_coefficient_correction_factor(
|
|
148
|
+
self, n_kin: float, n_bl: float, n_tp: float
|
|
149
|
+
) -> float:
|
|
150
|
+
"""
|
|
151
|
+
Args:
|
|
152
|
+
n_kin (float): Kinematic correction factor, adimensional
|
|
153
|
+
n_bl (float): Boundary layer correction factor, adimensional
|
|
154
|
+
n_tp (float): Two-phase correction factor, adimensional
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
float: Thrust coefficient correction factor, adimensional
|
|
158
|
+
"""
|
|
159
|
+
return (
|
|
160
|
+
(100 - (n_kin + n_bl + n_tp))
|
|
161
|
+
* self.structure.nozzle.get_divergent_correction_factor()
|
|
162
|
+
/ 100
|
|
163
|
+
* self.propellant.combustion_efficiency
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def get_thrust_coefficient(
|
|
167
|
+
self,
|
|
168
|
+
chamber_pressure: float,
|
|
169
|
+
exit_pressure: float,
|
|
170
|
+
external_pressure: float,
|
|
171
|
+
expansion_ratio: float,
|
|
172
|
+
k_2ph_ex: float,
|
|
173
|
+
n_cf: float,
|
|
174
|
+
) -> float:
|
|
175
|
+
"""
|
|
176
|
+
Args:
|
|
177
|
+
chamber_pressure (float): Chamber pressure, in Pa
|
|
178
|
+
exit_pressure (float): Exit pressure, in Pa
|
|
179
|
+
external_pressure (float): External pressure, in Pa
|
|
180
|
+
expansion_ratio (float): Expansion ratio, adimensional
|
|
181
|
+
k_2ph_ex (float): Two-phase isentropic coefficient, adimensional
|
|
182
|
+
n_cf (float): Thrust coefficient correction factor, adimensional
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
float: Instanteneous thrust coefficient, adimensional
|
|
186
|
+
"""
|
|
187
|
+
self.cf_ideal, self.cf_real = get_thrust_coefficients(
|
|
188
|
+
chamber_pressure,
|
|
189
|
+
exit_pressure,
|
|
190
|
+
external_pressure,
|
|
191
|
+
expansion_ratio,
|
|
192
|
+
k_2ph_ex,
|
|
193
|
+
n_cf,
|
|
194
|
+
)
|
|
195
|
+
return self.cf_real
|
|
196
|
+
|
|
197
|
+
def get_launch_mass(self) -> float:
|
|
198
|
+
return self.structure.dry_mass + self.initial_propellant_mass
|
|
199
|
+
|
|
200
|
+
def get_dry_mass(self) -> float:
|
|
201
|
+
return self.structure.dry_mass
|
|
202
|
+
|
|
203
|
+
def get_center_of_gravity(self) -> np.ndarray:
|
|
204
|
+
"""
|
|
205
|
+
Constant CG throughout the operation. Half the chamber length.
|
|
206
|
+
|
|
207
|
+
TODO: implement grain CG calculation.
|
|
208
|
+
"""
|
|
209
|
+
return np.array([self.structure.chamber.length / 2, 0, 0])
|