Skip to content

Commit 0dbc808

Browse files
authored
ENH: Improve parachute geometric parametrization (#835)
* ENH: added radius and porosity to parachute * ENH: added parachute radius * ENH: fixing radius and height attribute in flight class * STY: ruff formatting * TST: updated test value due to gravity update in u_dot_parachute * ENH: added new parameters into add_parachute method in Rocket class * DOC: added new parameters to the documentation * TST: updated test values to match the right gravity model * DOC: improved descriptions of the new parameters * ENH: added new parameters to the stochastic parachute * ENH: implementing previous comments * ENH: fixing formatting and adding docs * ENH: added ka property to Parachute class * ENH: fixing variable name * ENH: fixed attribute name * ENH: simplifying variable names * DOC: adding parameters documentation into StochasticParachute description * ENH: changing ma calculation and porosity documentation from previous comments * TST: updated test value due to change in ma calculation * ENH: changing parameter ka to added_mass_coefficient * DOC: updating the CHANGELOG * ENH: properly substituted all ka parameters for added_mass_coefficient
1 parent 7846e5a commit 0dbc808

File tree

10 files changed

+180
-19
lines changed

10 files changed

+180
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Attention: The newest changes should be on top -->
3737
- DOC: Add Flight class usage documentation and update index [#841](https://github.com/RocketPy-Team/RocketPy/pull/841)
3838
- ENH: Discretized and No-Pickle Encoding Options [#827] (https://github.com/RocketPy-Team/RocketPy/pull/827)
3939
- ENH: Add the Coriolis Force to the Flight class [#799](https://github.com/RocketPy-Team/RocketPy/pull/799)
40+
- ENH: Improve parachute geometric parametrization [#835](https://github.com/RocketPy-Team/RocketPy/pull/835)
4041

4142
### Changed
4243

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ main = calisto.add_parachute(
262262
sampling_rate=105,
263263
lag=1.5,
264264
noise=(0, 8.3, 0.5),
265+
parachute_radius=1.5,
266+
parachute_height=1.5,
267+
porosity=0.0432,
265268
)
266269

267270
drogue = calisto.add_parachute(
@@ -271,6 +274,9 @@ drogue = calisto.add_parachute(
271274
sampling_rate=105,
272275
lag=1.5,
273276
noise=(0, 8.3, 0.5),
277+
parachute_radius=1.5,
278+
parachute_height=1.5,
279+
porosity=0.0432,
274280
)
275281
```
276282

docs/user/first_simulation.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@ Finally, we can add any number of Parachutes to the ``Rocket`` object.
276276
sampling_rate=105,
277277
lag=1.5,
278278
noise=(0, 8.3, 0.5),
279+
parachute_radius=1.5,
280+
parachute_height=1.5,
281+
porosity=0.0432,
279282
)
280283

281284
drogue = calisto.add_parachute(
@@ -285,6 +288,9 @@ Finally, we can add any number of Parachutes to the ``Rocket`` object.
285288
sampling_rate=105,
286289
lag=1.5,
287290
noise=(0, 8.3, 0.5),
291+
parachute_radius=1.5,
292+
parachute_height=1.5,
293+
porosity=0.0432,
288294
)
289295

290296
We can then see if the rocket is stable by plotting the static margin:

docs/user/rocket/rocket_usage.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ apogee and another that will be deployed at 800 meters above ground level:
302302
sampling_rate=105,
303303
lag=1.5,
304304
noise=(0, 8.3, 0.5),
305+
parachute_radius=1.5,
306+
parachute_height=1.5,
307+
porosity=0.0432,
305308
)
306309

307310
drogue = calisto.add_parachute(
@@ -311,6 +314,9 @@ apogee and another that will be deployed at 800 meters above ground level:
311314
sampling_rate=105,
312315
lag=1.5,
313316
noise=(0, 8.3, 0.5),
317+
parachute_radius=1.5,
318+
parachute_height=1.5,
319+
porosity=0.0432,
314320
)
315321

316322
.. seealso::

rocketpy/rocket/parachute.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010

1111
class Parachute:
12-
"""Keeps parachute information.
12+
"""Keeps information of the parachute, which is modeled as a hemispheroid.
1313
1414
Attributes
1515
----------
@@ -92,6 +92,20 @@ class Parachute:
9292
Function of noisy_pressure_signal.
9393
Parachute.clean_pressure_signal_function : Function
9494
Function of clean_pressure_signal.
95+
Parachute.radius : float
96+
Length of the non-unique semi-axis (radius) of the inflated hemispheroid
97+
parachute in meters.
98+
Parachute.height : float, None
99+
Length of the unique semi-axis (height) of the inflated hemispheroid
100+
parachute in meters.
101+
Parachute.porosity : float
102+
Geometric porosity of the canopy (ratio of open area to total canopy area),
103+
in [0, 1]. Affects only the added-mass scaling during descent; it does
104+
not change ``cd_s`` (drag). The default, 0.0432, yields an added-mass
105+
of 1.0 (“neutral” behavior).
106+
Parachute.added_mass_coefficient : float
107+
Coefficient used to calculate the added-mass due to dragged air. It is
108+
calculated from the porosity of the parachute.
95109
"""
96110

97111
def __init__(
@@ -102,6 +116,9 @@ def __init__(
102116
sampling_rate,
103117
lag=0,
104118
noise=(0, 0, 0),
119+
radius=1.5,
120+
height=None,
121+
porosity=0.0432,
105122
):
106123
"""Initializes Parachute class.
107124
@@ -154,6 +171,19 @@ def __init__(
154171
The values are used to add noise to the pressure signal which is
155172
passed to the trigger function. Default value is ``(0, 0, 0)``.
156173
Units are in Pa.
174+
radius : float, optional
175+
Length of the non-unique semi-axis (radius) of the inflated hemispheroid
176+
parachute. Default value is 1.5.
177+
Units are in meters.
178+
height : float, optional
179+
Length of the unique semi-axis (height) of the inflated hemispheroid
180+
parachute. Default value is the radius of the parachute.
181+
Units are in meters.
182+
porosity : float, optional
183+
Geometric porosity of the canopy (ratio of open area to total canopy area),
184+
in [0, 1]. Affects only the added-mass scaling during descent; it does
185+
not change ``cd_s`` (drag). The default, 0.0432, yields an added-mass
186+
of 1.0 (“neutral” behavior).
157187
"""
158188
self.name = name
159189
self.cd_s = cd_s
@@ -170,6 +200,15 @@ def __init__(
170200
self.clean_pressure_signal_function = Function(0)
171201
self.noisy_pressure_signal_function = Function(0)
172202
self.noise_signal_function = Function(0)
203+
self.radius = radius
204+
self.height = height or radius
205+
self.porosity = porosity
206+
self.added_mass_coefficient = 1.068 * (
207+
1
208+
- 1.465 * self.porosity
209+
- 0.25975 * self.porosity**2
210+
+ 1.2626 * self.porosity**3
211+
)
173212

174213
alpha, beta = self.noise_corr
175214
self.noise_function = lambda: alpha * self.noise_signal[-1][
@@ -268,6 +307,9 @@ def to_dict(self, **kwargs):
268307
"sampling_rate": self.sampling_rate,
269308
"lag": self.lag,
270309
"noise": self.noise,
310+
"radius": self.radius,
311+
"height": self.height,
312+
"porosity": self.porosity,
271313
}
272314

273315
if kwargs.get("include_outputs", False):
@@ -298,6 +340,9 @@ def from_dict(cls, data):
298340
sampling_rate=data["sampling_rate"],
299341
lag=data["lag"],
300342
noise=data["noise"],
343+
radius=data.get("radius", 1.5),
344+
height=data.get("height", None),
345+
porosity=data.get("porosity", 0.0432),
301346
)
302347

303348
return parachute

rocketpy/rocket/rocket.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,16 @@ def add_free_form_fins(
14331433
return fin_set
14341434

14351435
def add_parachute(
1436-
self, name, cd_s, trigger, sampling_rate=100, lag=0, noise=(0, 0, 0)
1436+
self,
1437+
name,
1438+
cd_s,
1439+
trigger,
1440+
sampling_rate=100,
1441+
lag=0,
1442+
noise=(0, 0, 0),
1443+
radius=1.5,
1444+
height=None,
1445+
porosity=0.0432,
14371446
):
14381447
"""Creates a new parachute, storing its parameters such as
14391448
opening delay, drag coefficients and trigger function.
@@ -1492,16 +1501,39 @@ def add_parachute(
14921501
The values are used to add noise to the pressure signal which is
14931502
passed to the trigger function. Default value is (0, 0, 0). Units
14941503
are in pascal.
1504+
radius : float, optional
1505+
Length of the non-unique semi-axis (radius) of the inflated hemispheroid
1506+
parachute. Default value is 1.5.
1507+
Units are in meters.
1508+
height : float, optional
1509+
Length of the unique semi-axis (height) of the inflated hemispheroid
1510+
parachute. Default value is the radius of the parachute.
1511+
Units are in meters.
1512+
porosity : float, optional
1513+
Geometric porosity of the canopy (ratio of open area to total canopy area),
1514+
in [0, 1]. Affects only the added-mass scaling during descent; it does
1515+
not change ``cd_s`` (drag). The default, 0.0432, yields an added-mass
1516+
of 1.0 (“neutral” behavior).
14951517
14961518
Returns
14971519
-------
14981520
parachute : Parachute
1499-
Parachute containing trigger, sampling_rate, lag, cd_s, noise
1500-
and name. Furthermore, it stores clean_pressure_signal,
1521+
Parachute containing trigger, sampling_rate, lag, cd_s, noise, radius,
1522+
height, porosity and name. Furthermore, it stores clean_pressure_signal,
15011523
noise_signal and noisyPressureSignal which are filled in during
15021524
Flight simulation.
15031525
"""
1504-
parachute = Parachute(name, cd_s, trigger, sampling_rate, lag, noise)
1526+
parachute = Parachute(
1527+
name,
1528+
cd_s,
1529+
trigger,
1530+
sampling_rate,
1531+
lag,
1532+
noise,
1533+
radius,
1534+
height,
1535+
porosity,
1536+
)
15051537
self.parachutes.append(parachute)
15061538
return self.parachutes[-1]
15071539

rocketpy/simulation/flight.py

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,24 @@ def __simulate(self, verbose):
761761
callbacks = [
762762
lambda self, parachute_cd_s=parachute.cd_s: setattr(
763763
self, "parachute_cd_s", parachute_cd_s
764-
)
764+
),
765+
lambda self,
766+
parachute_radius=parachute.parachute_radius: setattr(
767+
self, "parachute_radius", parachute_radius
768+
),
769+
lambda self,
770+
parachute_height=parachute.parachute_height: setattr(
771+
self, "parachute_height", parachute_height
772+
),
773+
lambda self, parachute_porosity=parachute.porosity: setattr(
774+
self, "parachute_porosity", parachute_porosity
775+
),
776+
lambda self,
777+
added_mass_coefficient=parachute.added_mass_coefficient: setattr(
778+
self,
779+
"parachute_added_mass_coefficient",
780+
added_mass_coefficient,
781+
),
765782
]
766783
self.flight_phases.add_phase(
767784
node.t + parachute.lag,
@@ -1007,7 +1024,31 @@ def __simulate(self, verbose):
10071024
lambda self,
10081025
parachute_cd_s=parachute.cd_s: setattr(
10091026
self, "parachute_cd_s", parachute_cd_s
1010-
)
1027+
),
1028+
lambda self,
1029+
parachute_radius=parachute.radius: setattr(
1030+
self,
1031+
"parachute_radius",
1032+
parachute_radius,
1033+
),
1034+
lambda self,
1035+
parachute_height=parachute.height: setattr(
1036+
self,
1037+
"parachute_height",
1038+
parachute_height,
1039+
),
1040+
lambda self,
1041+
parachute_porosity=parachute.porosity: setattr(
1042+
self,
1043+
"parachute_porosity",
1044+
parachute_porosity,
1045+
),
1046+
lambda self,
1047+
added_mass_coefficient=parachute.added_mass_coefficient: setattr(
1048+
self,
1049+
"parachute_added_mass_coefficient",
1050+
added_mass_coefficient,
1051+
),
10111052
]
10121053
self.flight_phases.add_phase(
10131054
overshootable_node.t + parachute.lag,
@@ -1960,24 +2001,27 @@ def u_dot_parachute(self, t, u, post_processing=False):
19602001
wind_velocity_x = self.env.wind_velocity_x.get_value_opt(z)
19612002
wind_velocity_y = self.env.wind_velocity_y.get_value_opt(z)
19622003

1963-
# Get Parachute data
1964-
cd_s = self.parachute_cd_s
1965-
19662004
# Get the mass of the rocket
19672005
mp = self.rocket.dry_mass
19682006

1969-
# Define constants
1970-
ka = 1 # Added mass coefficient (depends on parachute's porosity)
1971-
R = 1.5 # Parachute radius
19722007
# to = 1.2
19732008
# eta = 1
19742009
# Rdot = (6 * R * (1 - eta) / (1.2**6)) * (
19752010
# (1 - eta) * t**5 + eta * (to**3) * (t**2)
19762011
# )
19772012
# Rdot = 0
19782013

2014+
# tf = 8 * nominal diameter / velocity at line stretch
2015+
19792016
# Calculate added mass
1980-
ma = ka * rho * (4 / 3) * np.pi * R**3
2017+
ma = (
2018+
self.parachute_added_mass_coefficient
2019+
* rho
2020+
* (2 / 3)
2021+
* np.pi
2022+
* self.parachute_radius**2
2023+
* self.parachute_height
2024+
)
19812025

19822026
# Calculate freestream speed
19832027
freestream_x = vx - wind_velocity_x
@@ -1986,14 +2030,14 @@ def u_dot_parachute(self, t, u, post_processing=False):
19862030
free_stream_speed = (freestream_x**2 + freestream_y**2 + freestream_z**2) ** 0.5
19872031

19882032
# Determine drag force
1989-
pseudo_drag = -0.5 * rho * cd_s * free_stream_speed
2033+
pseudo_drag = -0.5 * rho * self.parachute_cd_s * free_stream_speed
19902034
# pseudo_drag = pseudo_drag - ka * rho * 4 * np.pi * (R**2) * Rdot
1991-
Dx = pseudo_drag * freestream_x
2035+
Dx = pseudo_drag * freestream_x # add eta efficiency for wake
19922036
Dy = pseudo_drag * freestream_y
19932037
Dz = pseudo_drag * freestream_z
19942038
ax = Dx / (mp + ma)
19952039
ay = Dy / (mp + ma)
1996-
az = (Dz - 9.8 * mp) / (mp + ma)
2040+
az = (Dz - mp * self.env.gravity.get_value_opt(z)) / (mp + ma)
19972041

19982042
# Add coriolis acceleration
19992043
_, w_earth_y, w_earth_z = self.env.earth_rotation_vector

rocketpy/stochastic/stochastic_parachute.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ class StochasticParachute(StochasticModel):
2929
time-correlation).
3030
name : list[str]
3131
List with the name of the parachute object. This cannot be randomized.
32+
radius : tuple, list, int, float
33+
Radius of the parachute in meters.
34+
height : tuple, list, int, float
35+
Height of the parachute in meters.
36+
porosity : tuple, list, int, float
37+
Porosity of the parachute.
3238
"""
3339

3440
def __init__(
@@ -39,6 +45,9 @@ def __init__(
3945
sampling_rate=None,
4046
lag=None,
4147
noise=None,
48+
radius=None,
49+
height=None,
50+
porosity=None,
4251
):
4352
"""Initializes the Stochastic Parachute class.
4453
@@ -63,13 +72,22 @@ def __init__(
6372
noise : list
6473
List of tuples in the form of (mean, standard deviation,
6574
time-correlation).
75+
radius : tuple, list, int, float
76+
Radius of the parachute in meters.
77+
height : tuple, list, int, float
78+
Height of the parachute in meters.
79+
porosity : tuple, list, int, float
80+
Porosity of the parachute.
6681
"""
6782
self.parachute = parachute
6883
self.cd_s = cd_s
6984
self.trigger = trigger
7085
self.sampling_rate = sampling_rate
7186
self.lag = lag
7287
self.noise = noise
88+
self.radius = radius
89+
self.height = height
90+
self.porosity = porosity
7391

7492
self._validate_trigger(trigger)
7593
self._validate_noise(noise)
@@ -81,6 +99,9 @@ def __init__(
8199
lag=lag,
82100
noise=noise,
83101
name=None,
102+
radius=radius,
103+
height=height,
104+
porosity=porosity,
84105
)
85106

86107
def _validate_trigger(self, trigger):

0 commit comments

Comments
 (0)