From b4d723b2d5a0d77e899d37ab8c4e20f5cc02df29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Nov 2025 00:43:12 +0000 Subject: [PATCH 1/6] Fix hard-coded radius value for parachute added mass calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculate radius from cd_s using a typical hemispherical parachute drag coefficient (1.4) when radius is not explicitly provided. This fixes drift distance calculations for smaller parachutes like drogues. Formula: R = sqrt(cd_s / (Cd * π)) Closes #860 Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com> --- rocketpy/rocket/parachute.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/rocketpy/rocket/parachute.py b/rocketpy/rocket/parachute.py index 83b0ce0fd..9e8adb479 100644 --- a/rocketpy/rocket/parachute.py +++ b/rocketpy/rocket/parachute.py @@ -94,8 +94,8 @@ class Parachute: Function of clean_pressure_signal. Parachute.radius : float Length of the non-unique semi-axis (radius) of the inflated hemispheroid - parachute in meters. - Parachute.height : float, None + parachute in meters. Estimated from ``cd_s`` if not explicitly provided. + Parachute.height : float Length of the unique semi-axis (height) of the inflated hemispheroid parachute in meters. Parachute.porosity : float @@ -108,6 +108,10 @@ class Parachute: calculated from the porosity of the parachute. """ + # Typical drag coefficient for hemispherical parachute + # Used to estimate radius from cd_s when radius is not provided + HEMISPHERICAL_CD = 1.4 + def __init__( self, name, @@ -116,7 +120,7 @@ def __init__( sampling_rate, lag=0, noise=(0, 0, 0), - radius=1.5, + radius=None, height=None, porosity=0.0432, ): @@ -173,7 +177,9 @@ def __init__( Units are in Pa. radius : float, optional Length of the non-unique semi-axis (radius) of the inflated hemispheroid - parachute. Default value is 1.5. + parachute. If not provided, it is estimated from ``cd_s`` assuming a + typical hemispherical parachute drag coefficient of 1.4, using the + formula: ``radius = sqrt(cd_s / (HEMISPHERICAL_CD * pi))``. Units are in meters. height : float, optional Length of the unique semi-axis (height) of the inflated hemispheroid @@ -200,8 +206,13 @@ def __init__( self.clean_pressure_signal_function = Function(0) self.noisy_pressure_signal_function = Function(0) self.noise_signal_function = Function(0) - self.radius = radius - self.height = height or radius + # Estimate radius from cd_s if not provided + if radius is None: + # cd_s = Cd * S = Cd * π * R² => R = sqrt(cd_s / (Cd * π)) + self.radius = np.sqrt(cd_s / (self.HEMISPHERICAL_CD * np.pi)) + else: + self.radius = radius + self.height = height or self.radius self.porosity = porosity self.added_mass_coefficient = 1.068 * ( 1 @@ -341,8 +352,8 @@ def from_dict(cls, data): sampling_rate=data["sampling_rate"], lag=data["lag"], noise=data["noise"], - radius=data.get("radius", 1.5), - height=data.get("height", None), + radius=data.get("radius"), + height=data.get("height"), porosity=data.get("porosity", 0.0432), ) From b7b2ddff278d03b88fbc58fdf2d21545d175c5ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Nov 2025 00:46:08 +0000 Subject: [PATCH 2/6] Address code review: improve docstrings and add explicit None defaults Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com> --- rocketpy/rocket/parachute.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rocketpy/rocket/parachute.py b/rocketpy/rocket/parachute.py index 9e8adb479..2b820b0a4 100644 --- a/rocketpy/rocket/parachute.py +++ b/rocketpy/rocket/parachute.py @@ -94,7 +94,8 @@ class Parachute: Function of clean_pressure_signal. Parachute.radius : float Length of the non-unique semi-axis (radius) of the inflated hemispheroid - parachute in meters. Estimated from ``cd_s`` if not explicitly provided. + parachute in meters. Estimated from ``cd_s`` using the formula + ``R = sqrt(cd_s / (1.4 * π))`` if not explicitly provided. Parachute.height : float Length of the unique semi-axis (height) of the inflated hemispheroid parachute in meters. @@ -352,8 +353,8 @@ def from_dict(cls, data): sampling_rate=data["sampling_rate"], lag=data["lag"], noise=data["noise"], - radius=data.get("radius"), - height=data.get("height"), + radius=data.get("radius", None), + height=data.get("height", None), porosity=data.get("porosity", 0.0432), ) From 3100036f3790a0a7945bd8a4dd9c27c1b4e3c19e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Nov 2025 01:01:40 +0000 Subject: [PATCH 3/6] Add CHANGELOG entry for PR #889 Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com> --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d85ddb110..91977f485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,8 +55,10 @@ Attention: The newest changes should be on top --> ### Fixed +- BUG: Fix hard-coded radius value for parachute added mass calculation [#889](https://github.com/RocketPy-Team/RocketPy/pull/889) - DOC: Fix documentation build [#908](https://github.com/RocketPy-Team/RocketPy/pull/908) - BUG: energy_data plot not working for 3 dof sims [[#906](https://github.com/RocketPy-Team/RocketPy/issues/906)] +- BUG: Fix parallel Monte Carlo simulation showing incorrect iteration count [#806](https://github.com/RocketPy-Team/RocketPy/pull/806) - BUG: Fix CSV column header spacing in FlightDataExporter [#864](https://github.com/RocketPy-Team/RocketPy/issues/864) - BUG: Fix parallel Monte Carlo simulation showing incorrect iteration count [#806](https://github.com/RocketPy-Team/RocketPy/pull/806) - BUG: Duplicate _controllers in Flight.TimeNodes.merge() [#931](https://github.com/RocketPy-Team/RocketPy/pull/931) From 0988f98231ce6d270ca3abca3d106fe0e8f43ece Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Dec 2025 01:58:37 +0000 Subject: [PATCH 4/6] Update rocket.add_parachute to use radius=None for consistency Changed the default radius from 1.5 to None in the add_parachute method to match the Parachute class behavior. This ensures consistent automatic radius calculation from cd_s across both APIs. Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com> --- rocketpy/rocket/rocket.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 93ab46321..0fbe6ad6f 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -1488,7 +1488,7 @@ def add_parachute( sampling_rate=100, lag=0, noise=(0, 0, 0), - radius=1.5, + radius=None, height=None, porosity=0.0432, ): @@ -1551,7 +1551,9 @@ def add_parachute( are in pascal. radius : float, optional Length of the non-unique semi-axis (radius) of the inflated hemispheroid - parachute. Default value is 1.5. + parachute. If not provided, it is estimated from ``cd_s`` assuming a + typical hemispherical parachute drag coefficient of 1.4, using the + formula: ``radius = sqrt(cd_s / (1.4 * pi))``. Units are in meters. height : float, optional Length of the unique semi-axis (height) of the inflated hemispheroid From 9c43855a0b490d2b4a87c6626a4c920f496362c2 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 27 Feb 2026 22:07:00 -0300 Subject: [PATCH 5/6] Refactor Parachute class to remove hard-coded radius value and introduce drag_coefficient parameter for radius estimation --- rocketpy/rocket/parachute.py | 62 +++++++---- rocketpy/rocket/rocket.py | 32 +++--- rocketpy/stochastic/stochastic_parachute.py | 9 ++ tests/unit/rocket/test_parachute.py | 111 ++++++++++++++++++++ 4 files changed, 181 insertions(+), 33 deletions(-) create mode 100644 tests/unit/rocket/test_parachute.py diff --git a/rocketpy/rocket/parachute.py b/rocketpy/rocket/parachute.py index 2b820b0a4..7ced05105 100644 --- a/rocketpy/rocket/parachute.py +++ b/rocketpy/rocket/parachute.py @@ -92,27 +92,30 @@ class Parachute: Function of noisy_pressure_signal. Parachute.clean_pressure_signal_function : Function Function of clean_pressure_signal. + Parachute.drag_coefficient : float + Drag coefficient of the inflated canopy shape, used only when + ``radius`` is not provided to estimate the parachute radius from + ``cd_s``: ``R = sqrt(cd_s / (drag_coefficient * pi))``. Typical + values: 1.4 for hemispherical canopies (default), 0.75 for flat + circular canopies, 1.5 for extended-skirt canopies. Parachute.radius : float Length of the non-unique semi-axis (radius) of the inflated hemispheroid - parachute in meters. Estimated from ``cd_s`` using the formula - ``R = sqrt(cd_s / (1.4 * π))`` if not explicitly provided. + parachute in meters. If not provided at construction time, it is + estimated from ``cd_s`` and ``drag_coefficient``. Parachute.height : float Length of the unique semi-axis (height) of the inflated hemispheroid parachute in meters. Parachute.porosity : float - Geometric porosity of the canopy (ratio of open area to total canopy area), - in [0, 1]. Affects only the added-mass scaling during descent; it does - not change ``cd_s`` (drag). The default, 0.0432, yields an added-mass - of 1.0 (“neutral” behavior). + Geometric porosity of the canopy (ratio of open area to total canopy + area), in [0, 1]. Affects only the added-mass scaling during descent; + it does not change ``cd_s`` (drag). The default value of 0.0432 is + chosen so that the resulting ``added_mass_coefficient`` equals + approximately 1.0 ("neutral" added-mass behavior). Parachute.added_mass_coefficient : float Coefficient used to calculate the added-mass due to dragged air. It is calculated from the porosity of the parachute. """ - # Typical drag coefficient for hemispherical parachute - # Used to estimate radius from cd_s when radius is not provided - HEMISPHERICAL_CD = 1.4 - def __init__( self, name, @@ -122,6 +125,7 @@ def __init__( lag=0, noise=(0, 0, 0), radius=None, + drag_coefficient=1.4, height=None, porosity=0.0432, ): @@ -177,20 +181,33 @@ def __init__( passed to the trigger function. Default value is ``(0, 0, 0)``. Units are in Pa. radius : float, optional - Length of the non-unique semi-axis (radius) of the inflated hemispheroid - parachute. If not provided, it is estimated from ``cd_s`` assuming a - typical hemispherical parachute drag coefficient of 1.4, using the - formula: ``radius = sqrt(cd_s / (HEMISPHERICAL_CD * pi))``. + Length of the non-unique semi-axis (radius) of the inflated + hemispheroid parachute. If not provided, it is estimated from + ``cd_s`` and ``drag_coefficient`` using: + ``radius = sqrt(cd_s / (drag_coefficient * pi))``. Units are in meters. + drag_coefficient : float, optional + Drag coefficient of the inflated canopy shape, used only when + ``radius`` is not provided. It relates the aerodynamic ``cd_s`` + to the physical canopy area via + ``cd_s = drag_coefficient * pi * radius**2``. Typical values: + + - **1.4** — hemispherical canopy (default, NASA SP-8066) + - **0.75** — flat circular canopy + - **1.5** — extended-skirt canopy + + Has no effect when ``radius`` is explicitly provided. height : float, optional Length of the unique semi-axis (height) of the inflated hemispheroid parachute. Default value is the radius of the parachute. Units are in meters. porosity : float, optional - Geometric porosity of the canopy (ratio of open area to total canopy area), - in [0, 1]. Affects only the added-mass scaling during descent; it does - not change ``cd_s`` (drag). The default, 0.0432, yields an added-mass - of 1.0 (“neutral” behavior). + Geometric porosity of the canopy (ratio of open area to total + canopy area), in [0, 1]. Affects only the added-mass scaling + during descent; it does not change ``cd_s`` (drag). The default + value of 0.0432 is chosen so that the resulting + ``added_mass_coefficient`` equals approximately 1.0 ("neutral" + added-mass behavior). """ self.name = name self.cd_s = cd_s @@ -207,10 +224,11 @@ def __init__( self.clean_pressure_signal_function = Function(0) self.noisy_pressure_signal_function = Function(0) self.noise_signal_function = Function(0) - # Estimate radius from cd_s if not provided + self.drag_coefficient = drag_coefficient + # Estimate radius from cd_s if not provided. + # cd_s = Cd * S = Cd * π * R² => R = sqrt(cd_s / (Cd * π)) if radius is None: - # cd_s = Cd * S = Cd * π * R² => R = sqrt(cd_s / (Cd * π)) - self.radius = np.sqrt(cd_s / (self.HEMISPHERICAL_CD * np.pi)) + self.radius = np.sqrt(cd_s / (drag_coefficient * np.pi)) else: self.radius = radius self.height = height or self.radius @@ -321,6 +339,7 @@ def to_dict(self, **kwargs): "lag": self.lag, "noise": self.noise, "radius": self.radius, + "drag_coefficient": self.drag_coefficient, "height": self.height, "porosity": self.porosity, } @@ -354,6 +373,7 @@ def from_dict(cls, data): lag=data["lag"], noise=data["noise"], radius=data.get("radius", None), + drag_coefficient=data.get("drag_coefficient", 1.4), height=data.get("height", None), porosity=data.get("porosity", 0.0432), ) diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 0fbe6ad6f..ed76c1fdc 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -1489,6 +1489,7 @@ def add_parachute( lag=0, noise=(0, 0, 0), radius=None, + drag_coefficient=1.4, height=None, porosity=0.0432, ): @@ -1550,28 +1551,34 @@ def add_parachute( passed to the trigger function. Default value is (0, 0, 0). Units are in pascal. radius : float, optional - Length of the non-unique semi-axis (radius) of the inflated hemispheroid - parachute. If not provided, it is estimated from ``cd_s`` assuming a - typical hemispherical parachute drag coefficient of 1.4, using the - formula: ``radius = sqrt(cd_s / (1.4 * pi))``. + Length of the non-unique semi-axis (radius) of the inflated + hemispheroid parachute. If not provided, it is estimated from + `cd_s` and `drag_coefficient` using: + `radius = sqrt(cd_s / (drag_coefficient * pi))`. Units are in meters. + drag_coefficient : float, optional + Drag coefficient of the inflated canopy shape, used only when + `radius` is not provided. Typical values: 1.4 for hemispherical + canopies (default), 0.75 for flat circular canopies, 1.5 for + extended-skirt canopies. Has no effect when `radius` is given. height : float, optional Length of the unique semi-axis (height) of the inflated hemispheroid parachute. Default value is the radius of the parachute. Units are in meters. porosity : float, optional - Geometric porosity of the canopy (ratio of open area to total canopy area), - in [0, 1]. Affects only the added-mass scaling during descent; it does - not change ``cd_s`` (drag). The default, 0.0432, yields an added-mass - of 1.0 (“neutral” behavior). + Geometric porosity of the canopy (ratio of open area to total + canopy area), in [0, 1]. Affects only the added-mass scaling + during descent; it does not change `cd_s` (drag). The default + value of 0.0432 yields an `added_mass_coefficient` of + approximately 1.0. Returns ------- parachute : Parachute - Parachute containing trigger, sampling_rate, lag, cd_s, noise, radius, - height, porosity and name. Furthermore, it stores clean_pressure_signal, - noise_signal and noisyPressureSignal which are filled in during - Flight simulation. + Parachute containing trigger, sampling_rate, lag, cd_s, noise, + radius, drag_coefficient, height, porosity and name. Furthermore, + it stores clean_pressure_signal, noise_signal and + noisyPressureSignal which are filled in during Flight simulation. """ parachute = Parachute( name, @@ -1581,6 +1588,7 @@ def add_parachute( lag, noise, radius, + drag_coefficient, height, porosity, ) diff --git a/rocketpy/stochastic/stochastic_parachute.py b/rocketpy/stochastic/stochastic_parachute.py index dea8a077d..038907187 100644 --- a/rocketpy/stochastic/stochastic_parachute.py +++ b/rocketpy/stochastic/stochastic_parachute.py @@ -31,6 +31,9 @@ class StochasticParachute(StochasticModel): List with the name of the parachute object. This cannot be randomized. radius : tuple, list, int, float Radius of the parachute in meters. + drag_coefficient : tuple, list, int, float + Drag coefficient of the inflated canopy shape, used only when + ``radius`` is not provided. height : tuple, list, int, float Height of the parachute in meters. porosity : tuple, list, int, float @@ -46,6 +49,7 @@ def __init__( lag=None, noise=None, radius=None, + drag_coefficient=None, height=None, porosity=None, ): @@ -74,6 +78,9 @@ def __init__( time-correlation). radius : tuple, list, int, float Radius of the parachute in meters. + drag_coefficient : tuple, list, int, float + Drag coefficient of the inflated canopy shape, used only when + ``radius`` is not provided. height : tuple, list, int, float Height of the parachute in meters. porosity : tuple, list, int, float @@ -86,6 +93,7 @@ def __init__( self.lag = lag self.noise = noise self.radius = radius + self.drag_coefficient = drag_coefficient self.height = height self.porosity = porosity @@ -100,6 +108,7 @@ def __init__( noise=noise, name=None, radius=radius, + drag_coefficient=drag_coefficient, height=height, porosity=porosity, ) diff --git a/tests/unit/rocket/test_parachute.py b/tests/unit/rocket/test_parachute.py new file mode 100644 index 000000000..e5191cea6 --- /dev/null +++ b/tests/unit/rocket/test_parachute.py @@ -0,0 +1,111 @@ +"""Unit tests for the Parachute class, focusing on the radius and +drag_coefficient parameters introduced in PR #889.""" + +import numpy as np +import pytest + +from rocketpy import Parachute + + +def _make_parachute(**kwargs): + defaults = dict( + name="test", + cd_s=10.0, + trigger="apogee", + sampling_rate=100, + ) + defaults.update(kwargs) + return Parachute(**defaults) + + +class TestParachuteRadiusEstimation: + """Tests for auto-computed radius from cd_s and drag_coefficient.""" + + def test_radius_auto_computed_from_cd_s_default_drag_coefficient(self): + """When radius is not provided the radius is estimated using the + default drag_coefficient of 1.4 and the formula R = sqrt(cd_s / (Cd * pi)).""" + cd_s = 10.0 + parachute = _make_parachute(cd_s=cd_s) + expected_radius = np.sqrt(cd_s / (1.4 * np.pi)) + assert parachute.radius == pytest.approx(expected_radius, rel=1e-9) + + def test_radius_auto_computed_uses_custom_drag_coefficient(self): + """When drag_coefficient is provided and radius is not, the radius + must be estimated using the given drag_coefficient.""" + cd_s = 10.0 + custom_cd = 0.75 + parachute = _make_parachute(cd_s=cd_s, drag_coefficient=custom_cd) + expected_radius = np.sqrt(cd_s / (custom_cd * np.pi)) + assert parachute.radius == pytest.approx(expected_radius, rel=1e-9) + + def test_explicit_radius_overrides_estimation(self): + """When radius is explicitly provided, it must be used directly and + drag_coefficient must be ignored for the radius calculation.""" + explicit_radius = 2.5 + parachute = _make_parachute(radius=explicit_radius, drag_coefficient=0.5) + assert parachute.radius == explicit_radius + + def test_drag_coefficient_stored_on_instance(self): + """drag_coefficient must be stored as an attribute regardless of + whether radius is provided or not.""" + parachute = _make_parachute(drag_coefficient=0.75) + assert parachute.drag_coefficient == 0.75 + + def test_drag_coefficient_default_is_1_4(self): + """Default drag_coefficient must be 1.4 for backward compatibility.""" + parachute = _make_parachute() + assert parachute.drag_coefficient == pytest.approx(1.4) + + def test_drogue_radius_smaller_than_main(self): + """A drogue (cd_s=1.0) must have a smaller radius than a main (cd_s=10.0) + when using the same drag_coefficient.""" + main = _make_parachute(cd_s=10.0) + drogue = _make_parachute(cd_s=1.0) + assert drogue.radius < main.radius + + def test_drogue_radius_approximately_0_48(self): + """For cd_s=1.0 and drag_coefficient=1.4, the estimated radius + must be approximately 0.48 m (fixes the previous hard-coded 1.5 m).""" + drogue = _make_parachute(cd_s=1.0) + assert drogue.radius == pytest.approx(0.476, abs=1e-3) + + def test_main_radius_approximately_1_51(self): + """For cd_s=10.0 and drag_coefficient=1.4, the estimated radius + must be approximately 1.51 m, matching the old hard-coded value.""" + main = _make_parachute(cd_s=10.0) + assert main.radius == pytest.approx(1.508, abs=1e-3) + + +class TestParachuteSerialization: + """Tests for to_dict / from_dict round-trip including drag_coefficient.""" + + def test_to_dict_includes_drag_coefficient(self): + """to_dict must include the drag_coefficient key.""" + parachute = _make_parachute(drag_coefficient=0.75) + data = parachute.to_dict() + assert "drag_coefficient" in data + assert data["drag_coefficient"] == 0.75 + + def test_from_dict_round_trip_preserves_drag_coefficient(self): + """A Parachute serialized to dict and restored must have the same + drag_coefficient.""" + original = _make_parachute(cd_s=5.0, drag_coefficient=0.75) + data = original.to_dict() + restored = Parachute.from_dict(data) + assert restored.drag_coefficient == pytest.approx(0.75) + assert restored.radius == pytest.approx(original.radius, rel=1e-9) + + def test_from_dict_defaults_drag_coefficient_to_1_4_when_absent(self): + """Dicts serialized before drag_coefficient was added (no key) must + fall back to 1.4 for backward compatibility.""" + data = dict( + name="legacy", + cd_s=10.0, + trigger="apogee", + sampling_rate=100, + lag=0, + noise=(0, 0, 0), + # no drag_coefficient key — simulates old serialized data + ) + parachute = Parachute.from_dict(data) + assert parachute.drag_coefficient == pytest.approx(1.4) From fb64171033be7d11d7f5373c464b5397203d538b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Mar 2026 01:33:15 +0000 Subject: [PATCH 6/6] MNT: Extract noise initialization to fix pylint too-many-statements in Parachute.__init__ Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com> --- rocketpy/rocket/parachute.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/rocketpy/rocket/parachute.py b/rocketpy/rocket/parachute.py index 7ced05105..5e0f63f5c 100644 --- a/rocketpy/rocket/parachute.py +++ b/rocketpy/rocket/parachute.py @@ -215,15 +215,6 @@ def __init__( self.sampling_rate = sampling_rate self.lag = lag self.noise = noise - self.noise_signal = [[-1e-6, np.random.normal(noise[0], noise[1])]] - self.noisy_pressure_signal = [] - self.clean_pressure_signal = [] - self.noise_bias = noise[0] - self.noise_deviation = noise[1] - self.noise_corr = (noise[2], (1 - noise[2] ** 2) ** 0.5) - self.clean_pressure_signal_function = Function(0) - self.noisy_pressure_signal_function = Function(0) - self.noise_signal_function = Function(0) self.drag_coefficient = drag_coefficient # Estimate radius from cd_s if not provided. # cd_s = Cd * S = Cd * π * R² => R = sqrt(cd_s / (Cd * π)) @@ -240,16 +231,33 @@ def __init__( + 1.2626 * self.porosity**3 ) + self.__init_noise(noise) + self.prints = _ParachutePrints(self) + self.__evaluate_trigger_function(trigger) + + def __init_noise(self, noise): + """Initializes all noise-related attributes. + + Parameters + ---------- + noise : tuple, list + List in the format (mean, standard deviation, time-correlation). + """ + self.noise_signal = [[-1e-6, np.random.normal(noise[0], noise[1])]] + self.noisy_pressure_signal = [] + self.clean_pressure_signal = [] + self.noise_bias = noise[0] + self.noise_deviation = noise[1] + self.noise_corr = (noise[2], (1 - noise[2] ** 2) ** 0.5) + self.clean_pressure_signal_function = Function(0) + self.noisy_pressure_signal_function = Function(0) + self.noise_signal_function = Function(0) alpha, beta = self.noise_corr self.noise_function = lambda: ( alpha * self.noise_signal[-1][1] + beta * np.random.normal(noise[0], noise[1]) ) - self.prints = _ParachutePrints(self) - - self.__evaluate_trigger_function(trigger) - def __evaluate_trigger_function(self, trigger): """This is used to set the triggerfunc attribute that will be used to interact with the Flight class.