From 3d0627f3818aa50d046f553c6199f3803b5cb98f Mon Sep 17 00:00:00 2001 From: Guilherme Date: Tue, 27 Jun 2023 11:50:40 +0200 Subject: [PATCH 1/7] DOC: adding new .rst files to documentation --- docs/examples/index.rst | 15 +++++++++++++++ docs/reference/classes/Components.rst | 5 +++++ docs/reference/classes/Parachute.rst | 5 +++++ .../classes/aero_surfaces/EllipticalFins.rst | 5 +++++ docs/reference/classes/aero_surfaces/NoseCone.rst | 5 +++++ .../classes/aero_surfaces/RailButtons.rst | 5 +++++ docs/reference/classes/aero_surfaces/Tail.rst | 5 +++++ .../classes/aero_surfaces/TrapezoidalFins.rst | 5 +++++ docs/reference/classes/aero_surfaces/index.rst | 12 ++++++++++++ docs/reference/classes/motors/EmptyMotor.rst | 5 +++++ docs/reference/classes/motors/Fluid.rst | 5 +++++ docs/reference/classes/motors/GenericMotor.rst | 5 +++++ docs/reference/classes/motors/HybridMotor.rst | 5 +++++ docs/reference/classes/motors/LiquidMotor.rst | 5 +++++ .../reference/classes/{ => motors}/SolidMotor.rst | 0 docs/reference/classes/motors/index.rst | 15 +++++++++++++++ .../classes/motors/tanks/CylindricalTank.rst | 5 +++++ .../classes/motors/tanks/LevelBasedTank.rst | 5 +++++ .../classes/motors/tanks/MassBasedTank.rst | 5 +++++ .../motors/tanks/MassFlowRateBasedTank.rst | 5 +++++ .../classes/motors/tanks/SphericalTank.rst | 5 +++++ .../classes/motors/tanks/TankGeometry.rst | 5 +++++ .../classes/motors/tanks/UllageBasedTank.rst | 5 +++++ docs/reference/classes/motors/tanks/index.rst | 14 ++++++++++++++ docs/reference/classes/utils/index.rst | 11 +++++++++++ docs/reference/classes/utils/tools.rst | 5 +++++ docs/reference/classes/utils/units.rst | 5 +++++ docs/reference/classes/utils/utilities.rst | 14 ++++++++++++++ 28 files changed, 186 insertions(+) create mode 100644 docs/examples/index.rst create mode 100644 docs/reference/classes/Components.rst create mode 100644 docs/reference/classes/Parachute.rst create mode 100644 docs/reference/classes/aero_surfaces/EllipticalFins.rst create mode 100644 docs/reference/classes/aero_surfaces/NoseCone.rst create mode 100644 docs/reference/classes/aero_surfaces/RailButtons.rst create mode 100644 docs/reference/classes/aero_surfaces/Tail.rst create mode 100644 docs/reference/classes/aero_surfaces/TrapezoidalFins.rst create mode 100644 docs/reference/classes/aero_surfaces/index.rst create mode 100644 docs/reference/classes/motors/EmptyMotor.rst create mode 100644 docs/reference/classes/motors/Fluid.rst create mode 100644 docs/reference/classes/motors/GenericMotor.rst create mode 100644 docs/reference/classes/motors/HybridMotor.rst create mode 100644 docs/reference/classes/motors/LiquidMotor.rst rename docs/reference/classes/{ => motors}/SolidMotor.rst (100%) create mode 100644 docs/reference/classes/motors/index.rst create mode 100644 docs/reference/classes/motors/tanks/CylindricalTank.rst create mode 100644 docs/reference/classes/motors/tanks/LevelBasedTank.rst create mode 100644 docs/reference/classes/motors/tanks/MassBasedTank.rst create mode 100644 docs/reference/classes/motors/tanks/MassFlowRateBasedTank.rst create mode 100644 docs/reference/classes/motors/tanks/SphericalTank.rst create mode 100644 docs/reference/classes/motors/tanks/TankGeometry.rst create mode 100644 docs/reference/classes/motors/tanks/UllageBasedTank.rst create mode 100644 docs/reference/classes/motors/tanks/index.rst create mode 100644 docs/reference/classes/utils/index.rst create mode 100644 docs/reference/classes/utils/tools.rst create mode 100644 docs/reference/classes/utils/units.rst create mode 100644 docs/reference/classes/utils/utilities.rst diff --git a/docs/examples/index.rst b/docs/examples/index.rst new file mode 100644 index 000000000..37ef1eb23 --- /dev/null +++ b/docs/examples/index.rst @@ -0,0 +1,15 @@ +Flights simulated with RocketPy +=============================== + +Apart from the classical Calisto rocket, which is many times used as a +reference in the getting started tutorial, RocketPy also includes some very +interesting examples of real rockets. + +If you want to see your rocket here, please contact the maintainers! + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + ../notebooks/SEBLM.ipynb + diff --git a/docs/reference/classes/Components.rst b/docs/reference/classes/Components.rst new file mode 100644 index 000000000..a9f611983 --- /dev/null +++ b/docs/reference/classes/Components.rst @@ -0,0 +1,5 @@ +Components Class +---------------- + +.. automodule:: rocketpy.Components + :members: \ No newline at end of file diff --git a/docs/reference/classes/Parachute.rst b/docs/reference/classes/Parachute.rst new file mode 100644 index 000000000..ffb8bd66b --- /dev/null +++ b/docs/reference/classes/Parachute.rst @@ -0,0 +1,5 @@ +Parachute Class +--------------- + +.. automodule:: rocketpy.Parachute + :members: \ No newline at end of file diff --git a/docs/reference/classes/aero_surfaces/EllipticalFins.rst b/docs/reference/classes/aero_surfaces/EllipticalFins.rst new file mode 100644 index 000000000..17f9b7f33 --- /dev/null +++ b/docs/reference/classes/aero_surfaces/EllipticalFins.rst @@ -0,0 +1,5 @@ +EllipticalFins Class +-------------------- + +.. automodule:: rocketpy.EllipticalFins + :members: \ No newline at end of file diff --git a/docs/reference/classes/aero_surfaces/NoseCone.rst b/docs/reference/classes/aero_surfaces/NoseCone.rst new file mode 100644 index 000000000..b56eaf1d9 --- /dev/null +++ b/docs/reference/classes/aero_surfaces/NoseCone.rst @@ -0,0 +1,5 @@ +NoseCone Class +-------------- + +.. automodule:: rocketpy.NoseCone + :members: \ No newline at end of file diff --git a/docs/reference/classes/aero_surfaces/RailButtons.rst b/docs/reference/classes/aero_surfaces/RailButtons.rst new file mode 100644 index 000000000..7e7013566 --- /dev/null +++ b/docs/reference/classes/aero_surfaces/RailButtons.rst @@ -0,0 +1,5 @@ +RailButtons Class +----------------- + +.. automodule:: rocketpy.RailButtons + :members: \ No newline at end of file diff --git a/docs/reference/classes/aero_surfaces/Tail.rst b/docs/reference/classes/aero_surfaces/Tail.rst new file mode 100644 index 000000000..e3b60423f --- /dev/null +++ b/docs/reference/classes/aero_surfaces/Tail.rst @@ -0,0 +1,5 @@ +Tail Class +---------- + +.. automodule:: rocketpy.Tail + :members: \ No newline at end of file diff --git a/docs/reference/classes/aero_surfaces/TrapezoidalFins.rst b/docs/reference/classes/aero_surfaces/TrapezoidalFins.rst new file mode 100644 index 000000000..ba0335472 --- /dev/null +++ b/docs/reference/classes/aero_surfaces/TrapezoidalFins.rst @@ -0,0 +1,5 @@ +TrapezoidalFins Class +---------------------- + +.. automodule:: rocketpy.TrapezoidalFins + :members: \ No newline at end of file diff --git a/docs/reference/classes/aero_surfaces/index.rst b/docs/reference/classes/aero_surfaces/index.rst new file mode 100644 index 000000000..ce326247d --- /dev/null +++ b/docs/reference/classes/aero_surfaces/index.rst @@ -0,0 +1,12 @@ +AeroSurface Classes +=================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + NoseCone + TrapezoidalFins + EllipticalFins + Tail + RailButtons diff --git a/docs/reference/classes/motors/EmptyMotor.rst b/docs/reference/classes/motors/EmptyMotor.rst new file mode 100644 index 000000000..d0e3e480c --- /dev/null +++ b/docs/reference/classes/motors/EmptyMotor.rst @@ -0,0 +1,5 @@ +EmptyMotor Class +----------------- + +.. automodule:: rocketpy.EmptyMotor + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/Fluid.rst b/docs/reference/classes/motors/Fluid.rst new file mode 100644 index 000000000..cf8fdc731 --- /dev/null +++ b/docs/reference/classes/motors/Fluid.rst @@ -0,0 +1,5 @@ +Fluid Class +----------- + +.. automodule:: rocketpy.Fluid + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/GenericMotor.rst b/docs/reference/classes/motors/GenericMotor.rst new file mode 100644 index 000000000..a822e6f4c --- /dev/null +++ b/docs/reference/classes/motors/GenericMotor.rst @@ -0,0 +1,5 @@ +GenericMotor Class +------------------- + +.. automodule:: rocketpy.GenericMotor + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/HybridMotor.rst b/docs/reference/classes/motors/HybridMotor.rst new file mode 100644 index 000000000..eff062443 --- /dev/null +++ b/docs/reference/classes/motors/HybridMotor.rst @@ -0,0 +1,5 @@ +HybridMotor Class +----------------- + +.. automodule:: rocketpy.HybridMotor + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/LiquidMotor.rst b/docs/reference/classes/motors/LiquidMotor.rst new file mode 100644 index 000000000..7fb1243df --- /dev/null +++ b/docs/reference/classes/motors/LiquidMotor.rst @@ -0,0 +1,5 @@ +LiquidMotor Class +----------------- + +.. automodule:: rocketpy.LiquidMotor + :members: \ No newline at end of file diff --git a/docs/reference/classes/SolidMotor.rst b/docs/reference/classes/motors/SolidMotor.rst similarity index 100% rename from docs/reference/classes/SolidMotor.rst rename to docs/reference/classes/motors/SolidMotor.rst diff --git a/docs/reference/classes/motors/index.rst b/docs/reference/classes/motors/index.rst new file mode 100644 index 000000000..b2c882f00 --- /dev/null +++ b/docs/reference/classes/motors/index.rst @@ -0,0 +1,15 @@ +Motor Classes +============= + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + SolidMotor + Fluid + Tank and TankGeometry classes + LiquidMotor + HybridMotor + GenericMotor + EmptyMotor + diff --git a/docs/reference/classes/motors/tanks/CylindricalTank.rst b/docs/reference/classes/motors/tanks/CylindricalTank.rst new file mode 100644 index 000000000..3c749d4b2 --- /dev/null +++ b/docs/reference/classes/motors/tanks/CylindricalTank.rst @@ -0,0 +1,5 @@ +CylindricalTank Class +--------------------- + +.. automodule:: rocketpy.CylindricalTank + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/tanks/LevelBasedTank.rst b/docs/reference/classes/motors/tanks/LevelBasedTank.rst new file mode 100644 index 000000000..d9dc2aea1 --- /dev/null +++ b/docs/reference/classes/motors/tanks/LevelBasedTank.rst @@ -0,0 +1,5 @@ +LevelBasedTank Class +--------------------- + +.. automodule:: rocketpy.LevelBasedTank + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/tanks/MassBasedTank.rst b/docs/reference/classes/motors/tanks/MassBasedTank.rst new file mode 100644 index 000000000..ba820b654 --- /dev/null +++ b/docs/reference/classes/motors/tanks/MassBasedTank.rst @@ -0,0 +1,5 @@ +MassBasedTank Class +--------------------- + +.. automodule:: rocketpy.MassBasedTank + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/tanks/MassFlowRateBasedTank.rst b/docs/reference/classes/motors/tanks/MassFlowRateBasedTank.rst new file mode 100644 index 000000000..a19e8d690 --- /dev/null +++ b/docs/reference/classes/motors/tanks/MassFlowRateBasedTank.rst @@ -0,0 +1,5 @@ +MassFlowRateBasedTank Class +--------------------------- + +.. automodule:: rocketpy.MassFlowRateBasedTank + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/tanks/SphericalTank.rst b/docs/reference/classes/motors/tanks/SphericalTank.rst new file mode 100644 index 000000000..b283b0e20 --- /dev/null +++ b/docs/reference/classes/motors/tanks/SphericalTank.rst @@ -0,0 +1,5 @@ +SphericalTank Class +--------------------- + +.. automodule:: rocketpy.SphericalTank + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/tanks/TankGeometry.rst b/docs/reference/classes/motors/tanks/TankGeometry.rst new file mode 100644 index 000000000..4fed231de --- /dev/null +++ b/docs/reference/classes/motors/tanks/TankGeometry.rst @@ -0,0 +1,5 @@ +TankGeometry Class +------------------ + +.. automodule:: rocketpy.TankGeometry + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/tanks/UllageBasedTank.rst b/docs/reference/classes/motors/tanks/UllageBasedTank.rst new file mode 100644 index 000000000..6436a7218 --- /dev/null +++ b/docs/reference/classes/motors/tanks/UllageBasedTank.rst @@ -0,0 +1,5 @@ +UllageBasedTank Class +--------------------- + +.. automodule:: rocketpy.UllageBasedTank + :members: \ No newline at end of file diff --git a/docs/reference/classes/motors/tanks/index.rst b/docs/reference/classes/motors/tanks/index.rst new file mode 100644 index 000000000..f92f5e505 --- /dev/null +++ b/docs/reference/classes/motors/tanks/index.rst @@ -0,0 +1,14 @@ +Tanks and TanksGeometry Classes +=============================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + TankGeometry + CylindricalTank + SphericalTank + MassFlowRateBasedTank + UllageBasedTank + MassBasedTank + LevelBasedTank \ No newline at end of file diff --git a/docs/reference/classes/utils/index.rst b/docs/reference/classes/utils/index.rst new file mode 100644 index 000000000..9e7a202c3 --- /dev/null +++ b/docs/reference/classes/utils/index.rst @@ -0,0 +1,11 @@ +Utils functions +=============== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + tools + units + utilities + diff --git a/docs/reference/classes/utils/tools.rst b/docs/reference/classes/utils/tools.rst new file mode 100644 index 000000000..ccf804ae8 --- /dev/null +++ b/docs/reference/classes/utils/tools.rst @@ -0,0 +1,5 @@ +Tools functions +--------------- + +.. automodule:: rocketpy.tools + :members: \ No newline at end of file diff --git a/docs/reference/classes/utils/units.rst b/docs/reference/classes/utils/units.rst new file mode 100644 index 000000000..2c5e07ec6 --- /dev/null +++ b/docs/reference/classes/utils/units.rst @@ -0,0 +1,5 @@ +Units functions +--------------- + +.. automodule:: rocketpy.units + :members: \ No newline at end of file diff --git a/docs/reference/classes/utils/utilities.rst b/docs/reference/classes/utils/utilities.rst new file mode 100644 index 000000000..9e8ecb4df --- /dev/null +++ b/docs/reference/classes/utils/utilities.rst @@ -0,0 +1,14 @@ +Utilities functions +------------------- + +At RocketPy projects, utilities are functions that: + +1 - Depends on rocketpy classes, i.e. imports rocketpy classes +2 - Are not directly related to rocketpy classes, +3 - Performs a specific task, and +4 - Are not a part of a class. + +Below you have a list of all utilities functions available in rocketpy. + +.. automodule:: rocketpy.utilities + :members: \ No newline at end of file From 5f2280a46e17379a3e66208cc98aceefa585ae94 Mon Sep 17 00:00:00 2001 From: Guilherme Date: Tue, 27 Jun 2023 11:53:02 +0200 Subject: [PATCH 2/7] DOC: minor adjustments in the past .rst files - This was made to improve docs pages - The main change was related to the different toctree --- docs/conf.py | 3 ++- docs/index.rst | 3 ++- docs/reference/classes/Function.rst | 6 ++++-- docs/reference/index.rst | 8 ++++++-- docs/technical/equations_of_motion.rst | 6 +++--- docs/technical/index.rst | 3 ++- docs/user/index.rst | 5 +++++ docs/user/requirements.rst | 2 +- 8 files changed, 25 insertions(+), 11 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 81a21db16..da68e1780 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -78,7 +78,8 @@ "logo_link": "index", "github_url": "https://github.com/RocketPy-Team/RocketPy", "collapse_navigation": True, - "show_toc_level": 3, + "show_toc_level": 4, + "show_nav_level": 4, } html_sidebars = { diff --git a/docs/index.rst b/docs/index.rst index 3f2d21692..3eb160189 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,13 +4,14 @@ contain the root `toctree` directive. .. toctree:: - :maxdepth: 2 + :maxdepth: 4 :hidden: User Guide Code Reference Development Technical + Flight Examples .. _`RocketPy`: https://www.linkedin.com/company/75016723 diff --git a/docs/reference/classes/Function.rst b/docs/reference/classes/Function.rst index b34c0a31f..bc91ffd05 100644 --- a/docs/reference/classes/Function.rst +++ b/docs/reference/classes/Function.rst @@ -1,5 +1,7 @@ -Function Class --------------- +Function Classes +---------------- + +Here we describe the different classes that are defined in the rocketpy.Function module. .. automodule:: rocketpy.Function :members: \ No newline at end of file diff --git a/docs/reference/index.rst b/docs/reference/index.rst index c6aa4c414..52bcdd1d0 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -19,12 +19,16 @@ The following image shows how the four main classes interact with each other: For details about each class, see below. .. toctree:: - :maxdepth: 3 + :maxdepth: 4 :caption: Contents: classes/Function classes/Environment classes/EnvironmentAnalysis - classes/SolidMotor + Motor Classes + AeroSurface Classes + classes/Components classes/Rocket + classes/Parachute classes/Flight + Utils functions diff --git a/docs/technical/equations_of_motion.rst b/docs/technical/equations_of_motion.rst index da862c2f2..54aef9dd3 100644 --- a/docs/technical/equations_of_motion.rst +++ b/docs/technical/equations_of_motion.rst @@ -1,6 +1,6 @@ -=================== -Equations of Motion -=================== +====================== +Equations of Motion v0 +====================== Notes on the .rst file format version ===================================== diff --git a/docs/technical/index.rst b/docs/technical/index.rst index 865f8b62b..bad69224a 100644 --- a/docs/technical/index.rst +++ b/docs/technical/index.rst @@ -10,7 +10,8 @@ in their code. :maxdepth: 2 :caption: Contents: - Equations of Motion + Equations of Motion v0 + ../notebooks/rocketpy_equations_of_motion.ipynb Elliptical Fins Roll Moment diff --git a/docs/user/index.rst b/docs/user/index.rst index ef027af42..2e313bf70 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -12,7 +12,12 @@ Welcome to RocketPy's user documentation! ../notebooks/environment_analysis_class_usage.ipynb ../notebooks/environment_analysis_EuroC_example.ipynb ../notebooks/solid_motor_class_usage.ipynb + ../notebooks/tank_class_usage.ipynb + ../notebooks/example_liquid.ipynb + ../notebooks/example_liquid_empty.ipynb + ../notebooks/example_hybrid.ipynb ../notebooks/dispersion_analysis/dispersion_analysis.ipynb + ../notebooks/dispersion_analysis/parachute_drop_from_helicopter.ipynb ../notebooks/topography_usage.ipynb ../notebooks/utilities_usage.ipynb ../notebooks/compare_flights_usage.ipynb diff --git a/docs/user/requirements.rst b/docs/user/requirements.rst index a3556c9d1..a5edf83e9 100644 --- a/docs/user/requirements.rst +++ b/docs/user/requirements.rst @@ -17,7 +17,7 @@ Required Packages The following packages are needed in order to run RocketPy: - requests -- Numpy >= 1.0 +- Numpy >= 1.13 - Scipy >= 1.0 - Matplotlib >= 3.0 - netCDF4 >= 1.6.4 From d5bc0a0765399dceb51a8ac69d0e678fe6640138 Mon Sep 17 00:00:00 2001 From: Pedro Bressan Date: Sat, 1 Jul 2023 11:23:50 -0300 Subject: [PATCH 3/7] DOC: update README.md with new features of v1.0.0a1. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e4b838466..a54e765e7 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,10 @@ RocketPy is the next-generation trajectory simulation solution for High-Power Ro
-Solid motors models +Solid, Hybrid and Liquid motors models
  • Burn rate and mass variation properties from thrust curve
  • +
  • Define custom rocket tanks based on their flux data
  • CSV and ENG file support
@@ -156,12 +157,12 @@ To learn more about RocketPy's requirements, visit our [Requirements Docs](https ## Running Your First Simulation -In order to run your first rocket trajectory simulation using RocketPy, you can start a Jupyter Notebook and navigate to the _nbks_ folder. Open _Getting Started - Examples.ipynb_ and you are ready to go. +In order to run your first rocket trajectory simulation using RocketPy, you can start a Jupyter Notebook and navigate to the _docs/notebooks_ folder. Open _getting_started.ipynb_ and you are ready to go. Otherwise, you may want to create your own script or your own notebook using RocketPy. To do this, let's see how to use RocketPy's four main classes: - Environment - Keeps data related to weather. -- SolidMotor - Keeps data related to solid motors. Hybrid motor support is coming in the next weeks. +- Motor - Subdivided into SolidMotor, HybridMotor and LiquidMotor. Keeps data related to rocket motors. - Rocket - Keeps data related to a rocket. - Flight - Runs the simulation and keeps the results. From 8facdce868a06aae136c7770d8026fcfc6d74dae Mon Sep 17 00:00:00 2001 From: Guilherme Date: Sat, 1 Jul 2023 18:46:10 +0200 Subject: [PATCH 4/7] DOC: improve README and ensure simulation works --- README.md | 131 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index a54e765e7..113f5d289 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,12 @@ A typical workflow starts with importing these classes from RocketPy: from rocketpy import Environment, Rocket, SolidMotor, Flight ``` +An optional step is to import datetime, which is used to define the date of the simulation: + +```python +import datetime +``` + Then create an Environment object. To learn more about it, you can use: ```python @@ -189,9 +195,14 @@ env = Environment( latitude=32.990254, longitude=-106.974998, elevation=1400, - date=(2020, 3, 4, 12) # Tomorrow's date in year, month, day, hour UTC format ) +tomorrow = datetime.date.today() + datetime.timedelta(days=1) + +env.set_date( + (tomorrow.year, tomorrow.month, tomorrow.day, 12), timezone="America/Denver" +) # Tomorrow's date in year, month, day, hour UTC format + env.set_atmospheric_model(type='Forecast', file='GFS') ``` @@ -205,18 +216,23 @@ A sample Motor object can be created by the following code: ```python Pro75M1670 = SolidMotor( - thrust_source="../data/motors/Cesaroni_M1670.eng", + thrust_source="data/motors/Cesaroni_M1670.eng", + dry_mass=1.815, + dry_inertia=(0.125, 0.125, 0.002), + center_of_dry_mass=0.317, + grains_center_of_mass_position=0.397, burn_time=3.9, grain_number=5, - grain_separation=5/1000, + grain_separation=0.005, grain_density=1815, - grain_outer_radius=33/1000, - grain_initial_inner_radius=15/1000, - grain_initial_height=120/1000, - grains_center_of_mass_position=-0.85704, - nozzle_radius=33/1000, - throat_radius=11/1000, - interpolation_method='linear' + grain_outer_radius=0.033, + grain_initial_inner_radius=0.015, + grain_initial_height=0.12, + nozzle_radius=0.033, + throat_radius=0.011, + interpolation_method="linear", + nozzle_position=0, + coordinate_system_orientation="nozzle_to_combustion_chamber", ) ``` @@ -230,29 +246,38 @@ A sample code to create a Rocket is: ```python calisto = Rocket( - radius=127 / 2000, - mass=19.197 - 2.956, - inertia_i=6.60, - inertia_z=0.0351, - power_off_drag="../../data/calisto/powerOffDragCurve.csv", - power_on_drag="../../data/calisto/powerOnDragCurve.csv", - center_of_dry_mass_position=0, - coordinate_system_orientation="tail_to_nose" + radius=0.0635, + mass=14.426, # without motor + inertia=(6.321, 6.321, 0.034), + power_off_drag="data/calisto/powerOffDragCurve.csv", + power_on_drag="data/calisto/powerOnDragCurve.csv", + center_of_mass_without_motor=0, + coordinate_system_orientation="tail_to_nose", ) -calisto.set_rail_buttons(0.2, -0.5) + +buttons = calisto.set_rail_buttons( + upper_button_position=0.0818, + lower_button_position=-0.6182, + angular_position=45, +) + calisto.add_motor(Pro75M1670, position=-1.255) -calisto.add_nose(length=0.55829, kind="vonKarman", position=1.278) -calisto.add_trapezoidal_fins( + +nose = calisto.add_nose( + length=0.55829, kind="vonKarman", position=1.278 +) + +fins = calisto.add_trapezoidal_fins( n=4, root_chord=0.120, tip_chord=0.040, span=0.100, - position=-1.04956, + sweep_length=None, cant_angle=0, - radius=None, - airfoil=None + position=-1.04956, ) -calisto.add_tail( + +tail = calisto.add_tail( top_radius=0.0635, bottom_radius=0.0435, length=0.060, position=-1.194656 ) ``` @@ -260,35 +285,23 @@ calisto.add_tail( You may want to add parachutes to your rocket as well: ```python -def drogue_trigger(p, h, y): - # p = pressure considering parachute noise signal - # h = height above ground level considering parachute noise signal - # y = [x, y, z, vx, vy, vz, e0, e1, e2, e3, w1, w2, w3] - - # activate drogue when vz < 0 m/s. - return True if y[5] < 0 else False - -def main_trigger(p, h, y): - # p = pressure considering parachute noise signal - # h = height above ground level considering parachute noise signal - # y = [x, y, z, vx, vy, vz, e0, e1, e2, e3, w1, w2, w3] - - # activate main when vz < 0 m/s and z < 800 m - return True if y[5] < 0 and h < 800 else False - -calisto.add_parachute('Main', - cd_s=10.0, - trigger=main_trigger, - sampling_rate=105, - lag=1.5, - noise=(0, 8.3, 0.5)) - -calisto.add_parachute('Drogue', - cd_s=1.0, - trigger=drogue_trigger, - sampling_rate=105, - lag=1.5, - noise=(0, 8.3, 0.5)) +main = calisto.add_parachute( + name="main", + cd_s=10.0, + trigger=800, # ejection altitude in meters + sampling_rate=105, + lag=1.5, + noise=(0, 8.3, 0.5), +) + +drogue = calisto.add_parachute( + name="drogue", + cd_s=1.0, + trigger="apogee", # ejection at apogee + sampling_rate=105, + lag=1.5, + noise=(0, 8.3, 0.5), +) ``` Finally, you can create a Flight object to simulate your trajectory. To get help on the Flight class, use: @@ -300,7 +313,9 @@ help(Flight) To actually create a Flight object, use: ```python -test_flight = Flight(rocket=calisto, environment=env, rail_length=5.2, inclination=85, heading=0) +test_flight = Flight( + rocket=calisto, environment=env, rail_length=5.2, inclination=85, heading=0 +) ``` Once the Flight object is created, your simulation is done! Use the following code to get a summary of the results: @@ -319,6 +334,12 @@ Here is just a quick taste of what RocketPy is able to calculate. There are hund ![6-DOF Trajectory Plot](https://raw.githubusercontent.com/RocketPy-Team/RocketPy/master/docs/static/rocketpy_example_trajectory.svg) +If you want to see the trajectory on Google Earth, RocketPy acn easily export a KML file for you: + +```python +test_flight.export_kml(file_name="test_flight.kml") +``` +
# Authors and Contributors From 962c4b25450b7271f2bb4bbfc9392c4230523d5f Mon Sep 17 00:00:00 2001 From: Guilherme Date: Sat, 1 Jul 2023 18:46:50 +0200 Subject: [PATCH 5/7] FIX: a few missing variables in camelCase --- rocketpy/Environment.py | 2 +- rocketpy/prints/environment_prints.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rocketpy/Environment.py b/rocketpy/Environment.py index e169218ae..d5756cb7f 100644 --- a/rocketpy/Environment.py +++ b/rocketpy/Environment.py @@ -786,7 +786,7 @@ def set_atmospheric_model( so information from virtual soundings such as GFS and NAM can also be imported. - - 'WindyAtmosphere': sets pressure, temperature, wind-u and wind-v + - 'windy_atmosphere': sets pressure, temperature, wind-u and wind-v profiles and surface elevation obtained from the Windy API. See file argument to specify the model as either ECMWF, GFS or ICON. diff --git a/rocketpy/prints/environment_prints.py b/rocketpy/prints/environment_prints.py index db4e06efc..e621b4ae4 100644 --- a/rocketpy/prints/environment_prints.py +++ b/rocketpy/prints/environment_prints.py @@ -72,7 +72,7 @@ def launch_site_details(self): "Launch Date:", self.environment.datetime_date.strftime(time_format), "UTC |", - self.environment.localDate.strftime(time_format), + self.environment.local_date.strftime(time_format), self.environment.timezone, ) elif self.environment.datetime_date != None: From a39efc2648d4775758836c1fe4f031566711290a Mon Sep 17 00:00:00 2001 From: Guilherme Date: Sat, 1 Jul 2023 19:56:31 +0200 Subject: [PATCH 6/7] DOC: update .rst files to accomplish with alpha --- docs/user/disp.rst | 12 ++++++++++++ docs/user/environment.rst | 11 +++++++++++ docs/user/index.rst | 25 ++++++------------------- docs/user/intro.rst | 10 ++++++++++ docs/user/misc.rst | 11 +++++++++++ docs/user/motors.rst | 11 +++++++++++ 6 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 docs/user/disp.rst create mode 100644 docs/user/environment.rst create mode 100644 docs/user/intro.rst create mode 100644 docs/user/misc.rst create mode 100644 docs/user/motors.rst diff --git a/docs/user/disp.rst b/docs/user/disp.rst new file mode 100644 index 000000000..6a0bee248 --- /dev/null +++ b/docs/user/disp.rst @@ -0,0 +1,12 @@ +Dispersion Analysis +=================== + +This section contains notebooks that demonstrate how to perform Monte Carlo +simulations using RocketPy. + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + ../notebooks/dispersion_analysis/dispersion_analysis.ipynb + ../notebooks/dispersion_analysis/parachute_drop_from_helicopter.ipynb \ No newline at end of file diff --git a/docs/user/environment.rst b/docs/user/environment.rst new file mode 100644 index 000000000..7140b4e9b --- /dev/null +++ b/docs/user/environment.rst @@ -0,0 +1,11 @@ +Environment at RocketPy +======================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + ../notebooks/environment_class_usage.ipynb + ../notebooks/environment_analysis_class_usage.ipynb + ../notebooks/environment_analysis_EuroC_example.ipynb + ../notebooks/topography_usage.ipynb \ No newline at end of file diff --git a/docs/user/index.rst b/docs/user/index.rst index 2e313bf70..fa5d2cb27 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -2,25 +2,12 @@ Welcome to RocketPy's user documentation! ========================================= .. toctree:: - :maxdepth: 2 + :maxdepth: 4 :caption: Contents: - requirements.rst - installation.rst - ../notebooks/getting_started.ipynb - ../notebooks/environment_class_usage.ipynb - ../notebooks/environment_analysis_class_usage.ipynb - ../notebooks/environment_analysis_EuroC_example.ipynb - ../notebooks/solid_motor_class_usage.ipynb - ../notebooks/tank_class_usage.ipynb - ../notebooks/example_liquid.ipynb - ../notebooks/example_liquid_empty.ipynb - ../notebooks/example_hybrid.ipynb - ../notebooks/dispersion_analysis/dispersion_analysis.ipynb - ../notebooks/dispersion_analysis/parachute_drop_from_helicopter.ipynb - ../notebooks/topography_usage.ipynb - ../notebooks/utilities_usage.ipynb - ../notebooks/compare_flights_usage.ipynb - ../notebooks/deployable_payload_example.ipynb - ../matlab/matlab.rst + Introduction + Environment + Motors + Dispersion Analysis + Miscellaneous diff --git a/docs/user/intro.rst b/docs/user/intro.rst new file mode 100644 index 000000000..be64cfab4 --- /dev/null +++ b/docs/user/intro.rst @@ -0,0 +1,10 @@ +Introduction to RocketPy +======================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + requirements.rst + installation.rst + ../notebooks/getting_started.ipynb \ No newline at end of file diff --git a/docs/user/misc.rst b/docs/user/misc.rst new file mode 100644 index 000000000..7e52b25c5 --- /dev/null +++ b/docs/user/misc.rst @@ -0,0 +1,11 @@ +Miscellaneous +============= + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + ../notebooks/utilities_usage.ipynb + ../notebooks/compare_flights_usage.ipynb + ../notebooks/deployable_payload_example.ipynb + ../matlab/matlab.rst \ No newline at end of file diff --git a/docs/user/motors.rst b/docs/user/motors.rst new file mode 100644 index 000000000..14f236fe4 --- /dev/null +++ b/docs/user/motors.rst @@ -0,0 +1,11 @@ +Motors +====== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + ../notebooks/solid_motor_class_usage.ipynb + ../notebooks/tank_class_usage.ipynb + ../notebooks/example_liquid.ipynb + ../notebooks/example_hybrid.ipynb \ No newline at end of file From 40c3e86d2f50252f01999c0784001192e4b4f526 Mon Sep 17 00:00:00 2001 From: Guilherme Date: Sat, 1 Jul 2023 19:56:58 +0200 Subject: [PATCH 7/7] DOC: update titles in notebooks. --- .../deployable_payload_example.ipynb | 6 +- .../dispersion_analysis.ipynb | 2408 +++++++---------- .../parachute_drop_from_helicopter.ipynb | 2147 ++++++--------- docs/notebooks/example_liquid.ipynb | 2 +- 4 files changed, 1792 insertions(+), 2771 deletions(-) diff --git a/docs/notebooks/deployable_payload_example.ipynb b/docs/notebooks/deployable_payload_example.ipynb index 36031d101..0afe84b96 100644 --- a/docs/notebooks/deployable_payload_example.ipynb +++ b/docs/notebooks/deployable_payload_example.ipynb @@ -5,7 +5,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Deployable Payload Flight Simulation Example" + "# Deployable Payload" ] }, { @@ -37,8 +37,8 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install rocketpy netCDF4\n", - "!git clone https://github.com/RocketPy-Team/RocketPy.git" + "%pip install rocketpy netCDF4\n", + "%git clone https://github.com/RocketPy-Team/RocketPy.git" ] }, { diff --git a/docs/notebooks/dispersion_analysis/dispersion_analysis.ipynb b/docs/notebooks/dispersion_analysis/dispersion_analysis.ipynb index 90d1f1cd0..82b4e2505 100644 --- a/docs/notebooks/dispersion_analysis/dispersion_analysis.ipynb +++ b/docs/notebooks/dispersion_analysis/dispersion_analysis.ipynb @@ -1,32 +1,73 @@ { - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "V0OcBOvipOP8" - }, - "source": [ - "# Monte Carlo Dispersion Analysis using RocketPy\n", - "\n", - "This is an advanced use of RocketPy. This notebook wraps RocketPy's methods to run a Monte Carlo analysis and predict probability distributions of the rocket's landing point, apogee and other relevant information.\n", - "\n", - "The main output is a map very similar to the one below.\n", - "\n", - "![Landing point dispersion elipses](https://github.com/RocketPy-Team/RocketPy/raw/master/docs/notebooks/dispersion_analysis/dispersion_analysis_outputs/valetudo_rocket_v0.svg)\n", - "\n", - "This jupyter notebook presents the Monte Carlo analysis performed for the flight of Valetudo, one of the most famous rockets made by Projeto Jupiter. Valetudo has a diameter of $80$ mm and height of $2.4$ m. It was built for the first time to be launched at Latin American Space Challenge (LASC) 2019. Indeed, Valetudo came to be launched in 2019 on August 10th by 5:56 pm (local time), propelled by a class K motor called 'Keron', a solid motor completely designed and built by Projeto Jupiter. The rocket crossed the sky and reached an $860$ m apogee, descending safely by the drogue parachute called \"Charmander\" and landing with an 18.5 m/s terminal velocity. \n", - "\n", - "We hope you enjoy the flight(s) in this notebook just like everyone in LASC19 did it in real-time!" - ] + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "V0OcBOvipOP8" + }, + "source": [ + "# Monte Carlo simulations\n", + "\n", + "This is an advanced use of RocketPy. This notebook wraps RocketPy's methods to run a Monte Carlo analysis and predict probability distributions of the rocket's landing point, apogee and other relevant information.\n", + "\n", + "The main output is a map very similar to the one below.\n", + "\n", + "![Landing point dispersion elipses](https://github.com/RocketPy-Team/RocketPy/raw/master/docs/notebooks/dispersion_analysis/dispersion_analysis_outputs/valetudo_rocket_v0.svg)\n", + "\n", + "This jupyter notebook presents the Monte Carlo analysis performed for the flight of Valetudo, one of the most famous rockets made by Projeto Jupiter. Valetudo has a diameter of $80$ mm and height of $2.4$ m. It was built for the first time to be launched at Latin American Space Challenge (LASC) 2019. Indeed, Valetudo came to be launched in 2019 on August 10th by 5:56 pm (local time), propelled by a class K motor called 'Keron', a solid motor completely designed and built by Projeto Jupiter. The rocket crossed the sky and reached an $860$ m apogee, descending safely by the drogue parachute called \"Charmander\" and landing with an 18.5 m/s terminal velocity. \n", + "\n", + "We hope you enjoy the flight(s) in this notebook just like everyone in LASC19 did it in real-time!" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Clone repository if using Google Colab\n", + "\n", + "If you are running this using Binder, or you are running locally with the necessary files, you do not need to run this.\n", + "On the other hand, if you are running on Google Colab, make sure to run the cell below to clone the repository and download the necessary files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%git clone https://github.com/giovaniceotto/RocketPy.git\n", + "import os\n", + "\n", + "os.chdir(\"RocketPy/docs/notebooks/dispersion_analysis\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "Um2fvNlQpTAH" + }, + "source": [ + "## Install and Load Necessary Libraries\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, "id": "JJNfsYrwpXGJ", "outputId": "e2c4e1ef-4720-40ae-abd1-4d2a599bedd4" }, "outputs": [], "source": [ - "!pip install netCDF4\n", - "!pip install rocketpy" + "%pip install netCDF4\n", + "%pip install rocketpy" ] }, { @@ -107,7 +148,7 @@ "source": [ "analysis_parameters = {\n", " # Mass Details\n", - " \"rocket_mass\": (\n", + " \"rocketMass\": (\n", " 8.257,\n", " 0.001,\n", " ), # Rocket's dry mass (kg) and its uncertainty (standard deviation)\n", @@ -120,19 +161,19 @@ " 6 / 1000,\n", " 1 / 1000,\n", " ), # Motor's grain separation (axial distance between two grains) (m)\n", - " \"grain_density\": (1707, 50), # Motor's grain density (kg/m^3)\n", - " \"grain_outer_radius\": (21.4 / 1000, 0.375 / 1000), # Motor's grain outer radius (m)\n", - " \"grain_initial_inner_radius\": (\n", + " \"grainDensity\": (1707, 50), # Motor's grain density (kg/m^3)\n", + " \"grainOuterRadius\": (21.4 / 1000, 0.375 / 1000), # Motor's grain outer radius (m)\n", + " \"grainInitialInnerRadius\": (\n", " 9.65 / 1000,\n", " 0.375 / 1000,\n", " ), # Motor's grain inner radius (m)\n", - " \"grain_initial_height\": (120 / 1000, 1 / 1000), # Motor's grain height (m)\n", + " \"grainInitialHeight\": (120 / 1000, 1 / 1000), # Motor's grain height (m)\n", " # Aerodynamic Details - run help(Rocket) for more information\n", - " \"inertia_i\": (\n", + " \"inertiaI\": (\n", " 3.675,\n", " 0.03675,\n", " ), # Rocket's inertia moment perpendicular to its axis (kg*m^2)\n", - " \"inertia_z\": (\n", + " \"inertiaZ\": (\n", " 0.007,\n", " 0.00007,\n", " ), # Rocket's inertia moment relative to its axis (kg*m^2)\n", @@ -145,11 +186,11 @@ " -0.571,\n", " 0.001,\n", " ), # Distance between rocket's center of dry mass and and center of propellant mass (m) (negative)\n", - " \"power_off_drag\": (\n", + " \"powerOffDrag\": (\n", " 0.9081 / 1.05,\n", " 0.033,\n", " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", - " \"power_on_drag\": (\n", + " \"powerOnDrag\": (\n", " 0.9081 / 1.05,\n", " 0.033,\n", " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", @@ -264,19 +305,19 @@ " \"outOfRailTime\": flight_data.outOfRailTime,\n", " \"outOfRailVelocity\": flight_data.outOfRailVelocity,\n", " \"apogeeTime\": flight_data.apogeeTime,\n", - " \"apogeeAltitude\": flight_data.apogee - env.elevation,\n", + " \"apogeeAltitude\": flight_data.apogee - Env.elevation,\n", " \"apogeeX\": flight_data.apogeeX,\n", " \"apogeeY\": flight_data.apogeeY,\n", " \"impactTime\": flight_data.tFinal,\n", " \"impactX\": flight_data.xImpact,\n", " \"impactY\": flight_data.yImpact,\n", " \"impactVelocity\": flight_data.impactVelocity,\n", - " \"initialStaticMargin\": flight_data.rocket.static_margin(0),\n", - " \"outOfRailStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.outOfRailTime\n", + " \"initialStaticMargin\": flight_data.rocket.staticMargin(0),\n", + " \"outOfRailStaticMargin\": flight_data.rocket.staticMargin(\n", + " TestFlight.outOfRailTime\n", " ),\n", - " \"finalStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.rocket.motor.burn_out_time\n", + " \"finalStaticMargin\": flight_data.rocket.staticMargin(\n", + " TestFlight.rocket.motor.burnOutTime\n", " ),\n", " \"numberOfEvents\": len(flight_data.parachuteEvents),\n", " \"executionTime\": exec_time,\n", @@ -372,19 +413,19 @@ "initial_cpu_time = process_time()\n", "\n", "# Define basic Environment object\n", - "env = Environment(\n", + "Env = Environment(\n", " date=(2019, 8, 10, 21), latitude=-23.363611, longitude=-48.011389\n", ")\n", - "env.setElevation(668)\n", - "env.maxExpectedHeight = 1500\n", - "env.set_atmospheric_model(\n", + "Env.setElevation(668)\n", + "Env.maxExpectedHeight = 1500\n", + "Env.setAtmosphericModel(\n", " type=\"Ensemble\",\n", " file=\"dispersion_analysis_inputs/LASC2019_reanalysis.nc\",\n", " dictionary=\"ECMWF\",\n", ")\n", "\n", "# Set up parachutes. This rocket, named Valetudo, only has a drogue chute.\n", - "def drogue_trigger(p, h, y):\n", + "def drogueTrigger(p, h, y):\n", " # Check if rocket is going down, i.e. if it has passed the apogee\n", " vertical_velocity = y[5]\n", " # Return true to activate parachute once the vertical velocity is negative\n", @@ -398,64 +439,64 @@ " i += 1\n", "\n", " # Update environment object\n", - " env.selectEnsembleMember(setting[\"ensembleMember\"])\n", + " Env.selectEnsembleMember(setting[\"ensembleMember\"])\n", "\n", " # Create motor\n", " Keron = SolidMotor(\n", - " thrust_source=\"dispersion_analysis_inputs/thrustCurve.csv\",\n", + " thrustSource=\"dispersion_analysis_inputs/thrustCurve.csv\",\n", " burn_time=5.274,\n", - " reshape_thrust_curve=(setting[\"burn_time\"], setting[\"impulse\"]),\n", + " reshapeThrustCurve=(setting[\"burn_time\"], setting[\"impulse\"]),\n", " nozzle_radius=setting[\"nozzle_radius\"],\n", " throat_radius=setting[\"throat_radius\"],\n", - " grains_center_of_mass_position=setting[\"distanceRocketPropellant\"],\n", - " grain_number=6,\n", + " grainsCenterOfMassPosition=setting[\"distanceRocketPropellant\"],\n", + " grainNumber=6,\n", " grain_separation=setting[\"grain_separation\"],\n", - " grain_density=setting[\"grain_density\"],\n", - " grain_outer_radius=setting[\"grain_outer_radius\"],\n", - " grain_initial_inner_radius=setting[\"grain_initial_inner_radius\"],\n", - " grain_initial_height=setting[\"grain_initial_height\"],\n", - " interpolation_method=\"linear\",\n", - " nozzle_position=setting[\"distanceRocketNozzle\"],\n", - " coordinate_system_orientation=\"nozzle_to_combustion_chamber\",\n", + " grainDensity=setting[\"grainDensity\"],\n", + " grainOuterRadius=setting[\"grainOuterRadius\"],\n", + " grainInitialInnerRadius=setting[\"grainInitialInnerRadius\"],\n", + " grainInitialHeight=setting[\"grainInitialHeight\"],\n", + " interpolationMethod=\"linear\",\n", + " nozzlePosition=setting[\"distanceRocketNozzle\"],\n", + " coordinateSystemOrientation=\"nozzleToCombustionChamber\",\n", " )\n", " # Create rocket\n", " Valetudo = Rocket(\n", " radius=setting[\"radius\"],\n", - " mass=setting[\"rocket_mass\"],\n", - " inertia_i=setting[\"inertia_i\"],\n", - " inertia_z=setting[\"inertia_z\"],\n", - " power_off_drag=\"dispersion_analysis_inputs/Cd_PowerOff.csv\",\n", - " power_on_drag=\"dispersion_analysis_inputs/Cd_PowerOn.csv\",\n", - " center_of_dry_mass_position=0,\n", - " coordinate_system_orientation=\"tail_to_nose\",\n", + " mass=setting[\"rocketMass\"],\n", + " inertiaI=setting[\"inertiaI\"],\n", + " inertiaZ=setting[\"inertiaZ\"],\n", + " powerOffDrag=\"dispersion_analysis_inputs/Cd_PowerOff.csv\",\n", + " powerOnDrag=\"dispersion_analysis_inputs/Cd_PowerOn.csv\",\n", + " centerOfDryMassPosition=0,\n", + " coordinateSystemOrientation=\"tailToNose\",\n", " )\n", " Valetudo.setRailButtons(0.224, -0.93, 30)\n", "\n", - " Valetudo.add_motor(Keron, position=setting[\"distanceRocketNozzle\"])\n", + " Valetudo.addMotor(Keron, position=setting[\"distanceRocketNozzle\"])\n", "\n", " # Edit rocket drag\n", - " Valetudo.power_off_drag *= setting[\"power_off_drag\"]\n", - " Valetudo.power_on_drag *= setting[\"power_on_drag\"]\n", + " Valetudo.powerOffDrag *= setting[\"powerOffDrag\"]\n", + " Valetudo.powerOnDrag *= setting[\"powerOnDrag\"]\n", " # Add rocket nose, fins and tail\n", - " NoseCone = Valetudo.add_nose(\n", + " NoseCone = Valetudo.addNose(\n", " length=setting[\"noseLength\"],\n", " kind=\"vonKarman\",\n", " position=setting[\"noseDistanceToCM\"] + setting[\"noseLength\"],\n", " )\n", - " fin_set = Valetudo.add_trapezoidal_fins(\n", + " FinSet = Valetudo.addTrapezoidalFins(\n", " n=3,\n", " span=setting[\"finSpan\"],\n", " rootChord=setting[\"finRootChord\"],\n", - " tip_chord=setting[\"finTipChord\"],\n", + " tipChord=setting[\"finTipChord\"],\n", " position=setting[\"finDistanceToCM\"],\n", " cantAngle=0,\n", " airfoil=None,\n", " )\n", " # Add parachute\n", - " Drogue = Valetudo.add_parachute(\n", + " Drogue = Valetudo.addParachute(\n", " \"Drogue\",\n", " CdS=setting[\"CdSDrogue\"],\n", - " trigger=drogue_trigger,\n", + " trigger=drogueTrigger,\n", " samplingRate=105,\n", " lag=setting[\"lag_rec\"] + setting[\"lag_se\"],\n", " noise=(0, 8.3, 0.5),\n", @@ -463,15 +504,15 @@ "\n", " # Run trajectory simulation\n", " try:\n", - " test_flight = Flight(\n", + " TestFlight = Flight(\n", " rocket=Valetudo,\n", - " environment=env,\n", + " environment=Env,\n", " railLength=setting[\"railLength\"],\n", " inclination=setting[\"inclination\"],\n", " heading=setting[\"heading\"],\n", " maxTime=600,\n", " )\n", - " export_flight_data(setting, test_flight, process_time() - start_time)\n", + " export_flight_data(setting, TestFlight, process_time() - start_time)\n", " except Exception as E:\n", " print(E)\n", " export_flight_error(setting)\n", @@ -525,1396 +566,873 @@ "colab": { "base_uri": "https://localhost:8080/" }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "Um2fvNlQpTAH" - }, - "source": [ - "## Install and Load Necessary Libraries\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "JJNfsYrwpXGJ", - "outputId": "e2c4e1ef-4720-40ae-abd1-4d2a599bedd4" - }, - "outputs": [], - "source": [ - "!pip install netCDF4\n", - "!pip install rocketpy" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "rNY7u8fApOP_" - }, - "outputs": [], - "source": [ - "from datetime import datetime\n", - "from time import process_time, perf_counter, time\n", - "import glob\n", - "\n", - "from rocketpy import Environment, SolidMotor, Rocket, Flight, Function\n", - "\n", - "import numpy as np\n", - "from numpy.random import normal, uniform, choice\n", - "from IPython.display import display" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we import matplotlib to produce awesome looking plots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "0uEmvBIt5Ltg" - }, - "outputs": [], - "source": [ - "%config InlineBackend.figure_formats = ['svg']\n", - "import matplotlib as mpl\n", - "import matplotlib.pyplot as plt\n", - "\n", - "%matplotlib inline\n", - "mpl.rcParams[\"figure.figsize\"] = [8, 5]\n", - "mpl.rcParams[\"figure.dpi\"] = 120\n", - "mpl.rcParams[\"font.size\"] = 14\n", - "mpl.rcParams[\"legend.fontsize\"] = 14\n", - "mpl.rcParams[\"figure.titlesize\"] = 14" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "4ksmBqU7pOQC" - }, - "source": [ - "## Defining Analysis Parameters\n", - "\n", - "The analysis parameters are a collection of expected values (and their uncertainties, or standard deviation) that completely defines a rocket flight.\n", - "As an assumption, the parameters which define the flight can behave in 3 different ways:\n", - " - the parameter is a completely known and has a constant value (i.e. number of fins)\n", - " - the parameter can assume certain discrete values with uniform distribution (i.e. the member of an ensemble forecast, which might be any integer from 0 to 9)\n", - " - the parameter is best represented by a normal (gaussian) distribution with a defined expected value and standard deviation\n", - "\n", - "We implement this using a dictionary, where the key is the name of the parameter and the value is either a tuple or a list, depending on the behaviour of the parameter:\n", - " - if the parameter is know, its value is represented as a list with a single entry (i.e. `\"number_of_fins: [4]\"`)\n", - " - if the parameter can assume certain discrete values with uniform distribution, its values are represented by a list of possible choices (i.e. `\"member_of_ensemble_forecast: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\"`)\n", - " - if the parameter is best represented by a normal (gaussian) distribution, its value is a tuple with the expected value and its standard deviation (i.e. `\"rocket_mass\": (100, 2)`, where 100 kg is the expected mass, with uncertainty of plus or minus 2 kg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "fwoCdOgKpOQD" - }, - "outputs": [], - "source": [ - "analysis_parameters = {\n", - " # Mass Details\n", - " \"rocket_mass\": (\n", - " 8.257,\n", - " 0.001,\n", - " ), # Rocket's dry mass (kg) and its uncertainty (standard deviation)\n", - " # Propulsion Details - run help(SolidMotor) for more information\n", - " \"impulse\": (1415.15, 35.3), # Motor total impulse (N*s)\n", - " \"burn_time\": (5.274, 1), # Motor burn out time (s)\n", - " \"nozzle_radius\": (21.642 / 1000, 0.5 / 1000), # Motor's nozzle radius (m)\n", - " \"throat_radius\": (8 / 1000, 0.5 / 1000), # Motor's nozzle throat radius (m)\n", - " \"grain_separation\": (\n", - " 6 / 1000,\n", - " 1 / 1000,\n", - " ), # Motor's grain separation (axial distance between two grains) (m)\n", - " \"grain_density\": (1707, 50), # Motor's grain density (kg/m^3)\n", - " \"grain_outer_radius\": (21.4 / 1000, 0.375 / 1000), # Motor's grain outer radius (m)\n", - " \"grain_initial_inner_radius\": (\n", - " 9.65 / 1000,\n", - " 0.375 / 1000,\n", - " ), # Motor's grain inner radius (m)\n", - " \"grain_initial_height\": (120 / 1000, 1 / 1000), # Motor's grain height (m)\n", - " # Aerodynamic Details - run help(Rocket) for more information\n", - " \"inertia_i\": (\n", - " 3.675,\n", - " 0.03675,\n", - " ), # Rocket's inertia moment perpendicular to its axis (kg*m^2)\n", - " \"inertia_z\": (\n", - " 0.007,\n", - " 0.00007,\n", - " ), # Rocket's inertia moment relative to its axis (kg*m^2)\n", - " \"radius\": (40.45 / 1000, 0.001), # Rocket's radius (kg*m^2)\n", - " \"distance_rocket_nozzle\": (\n", - " -1.024,\n", - " 0.001,\n", - " ), # Distance between rocket's center of dry mass and nozzle exit plane (m) (negative)\n", - " \"distanceRocketPropellant\": (\n", - " -0.571,\n", - " 0.001,\n", - " ), # Distance between rocket's center of dry mass and and center of propellant mass (m) (negative)\n", - " \"power_off_drag\": (\n", - " 0.9081 / 1.05,\n", - " 0.033,\n", - " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", - " \"power_on_drag\": (\n", - " 0.9081 / 1.05,\n", - " 0.033,\n", - " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", - " \"nose_length\": (0.274, 0.001), # Rocket's nose cone length (m)\n", - " \"noseDistanceToCM\": (\n", - " 1.134,\n", - " 0.001,\n", - " ), # Axial distance between rocket's center of dry mass and nearest point in its nose cone (m)\n", - " \"finSpan\": (0.077, 0.0005), # Fin span (m)\n", - " \"finRootChord\": (0.058, 0.0005), # Fin root chord (m)\n", - " \"finTipChord\": (0.018, 0.0005), # Fin tip chord (m)\n", - " \"finDistanceToCM\": (\n", - " -0.906,\n", - " 0.001,\n", - " ), # Axial distance between rocket's center of dry mass and nearest point in its fin (m)\n", - " # Launch and Environment Details - run help(Environment) and help(Flight) for more information\n", - " \"inclination\": (\n", - " 84.7,\n", - " 1,\n", - " ), # Launch rail inclination angle relative to the horizontal plane (degrees)\n", - " \"heading\": (53, 2), # Launch rail heading relative to north (degrees)\n", - " \"rail_length\": (5.7, 0.0005), # Launch rail length (m)\n", - " \"ensembleMember\": list(range(10)), # Members of the ensemble forecast to be used\n", - " # Parachute Details - run help(Rocket) for more information\n", - " \"CdSDrogue\": (\n", - " 0.349 * 1.3,\n", - " 0.07,\n", - " ), # Drag coefficient times reference area for the drogue chute (m^2)\n", - " \"lag_rec\": (\n", - " 1,\n", - " 0.5,\n", - " ), # Time delay between parachute ejection signal is detected and parachute is inflated (s)\n", - " # Electronic Systems Details - run help(Rocket) for more information\n", - " \"lag_se\": (\n", - " 0.73,\n", - " 0.16,\n", - " ), # Time delay between sensor signal is received and ejection signal is fired (s)\n", - "}" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "EJCbP69TpOQG" - }, - "source": [ - "## Creating a Flight Settings Generator\n", - "\n", - "Now, we create a generator function which will yield all the necessary inputs for a single flight simulation. Each generated input will be randomly generated according to the `analysis_parameters` dicitionary set up above.\n", - "\n", - "This is just a helper function to make the code clearer." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "5XCL9JaIpOQH" - }, - "outputs": [], - "source": [ - "def flight_settings(analysis_parameters, total_number):\n", - " i = 0\n", - " while i < total_number:\n", - " # Generate a flight setting\n", - " flight_setting = {}\n", - " for parameter_key, parameter_value in analysis_parameters.items():\n", - " if type(parameter_value) is tuple:\n", - " flight_setting[parameter_key] = normal(*parameter_value)\n", - " else:\n", - " flight_setting[parameter_key] = choice(parameter_value)\n", - "\n", - " # Skip if certain values are negative, which happens due to the normal curve but isnt realistic\n", - " if flight_setting[\"lag_rec\"] < 0 or flight_setting[\"lag_se\"] < 0:\n", - " continue\n", - "\n", - " # Update counter\n", - " i += 1\n", - " # Yield a flight setting\n", - " yield flight_setting" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "FtdRXCVHpOQO" - }, - "source": [ - "## Creating an Export Function\n", - "\n", - "Monte Carlo analyses usually contain data from thousands or tens of thousands of simulations. They can easily take hours to run. Therefore, it is very important to save our outputs to a file during the analysis. This way, if something happens, we do not lose our progress.\n", - "\n", - "These next functions take care of that. They export the simulation data to three different files:\n", - "- `dispersion_input_file`: A file where each line is a json converted dictionary of flight setting inputs to run a single trajectory simulation;\n", - "- `dispersion_output_file`: A file where each line is a json converted dictionary containing the main outputs of a single simulation, such as apogee altitute and maximum velocity;\n", - "- `dispersion_error_file`: A file to store the inputs of simulations which raised errors. This can help us debug these simulations later on." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "1eC2p3jEpOQO" - }, - "outputs": [], - "source": [ - "def export_flight_data(flight_setting, flight_data, exec_time):\n", - " # Generate flight results\n", - " flight_result = {\n", - " \"out_of_rail_time\": flight_data.out_of_rail_time,\n", - " \"outOfRailVelocity\": flight_data.outOfRailVelocity,\n", - " \"apogeeTime\": flight_data.apogeeTime,\n", - " \"apogeeAltitude\": flight_data.apogee - env.elevation,\n", - " \"apogeeX\": flight_data.apogeeX,\n", - " \"apogeeY\": flight_data.apogeeY,\n", - " \"impactTime\": flight_data.tFinal,\n", - " \"impactX\": flight_data.xImpact,\n", - " \"impactY\": flight_data.yImpact,\n", - " \"impactVelocity\": flight_data.impactVelocity,\n", - " \"initialStaticMargin\": flight_data.rocket.static_margin(0),\n", - " \"outOfRailStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.out_of_rail_time\n", - " ),\n", - " \"finalStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.rocket.motor.burn_out_time\n", - " ),\n", - " \"numberOfEvents\": len(flight_data.parachute_events),\n", - " \"executionTime\": exec_time,\n", - " }\n", - "\n", - " # Calculate maximum reached velocity\n", - " sol = np.array(flight_data.solution)\n", - " flight_data.vx = Function(\n", - " sol[:, [0, 4]], \"Time (s)\", \"Vx (m/s)\", \"linear\", extrapolation=\"natural\"\n", - " )\n", - " flight_data.vy = Function(\n", - " sol[:, [0, 5]], \"Time (s)\", \"Vy (m/s)\", \"linear\", extrapolation=\"natural\"\n", - " )\n", - " flight_data.vz = Function(\n", - " sol[:, [0, 6]], \"Time (s)\", \"Vz (m/s)\", \"linear\", extrapolation=\"natural\"\n", - " )\n", - " flight_data.v = (\n", - " flight_data.vx**2 + flight_data.vy**2 + flight_data.vz**2\n", - " ) ** 0.5\n", - " flight_data.maxVel = np.amax(flight_data.v.source[:, 1])\n", - " flight_result[\"maxVelocity\"] = flight_data.maxVel\n", - "\n", - " # Take care of parachute results\n", - " if len(flight_data.parachute_events) > 0:\n", - " flight_result[\"drogue_triggerTime\"] = flight_data.parachute_events[0][0]\n", - " flight_result[\"drogueInflatedTime\"] = (\n", - " flight_data.parachute_events[0][0] + flight_data.parachute_events[0][1].lag\n", - " )\n", - " flight_result[\"drogueInflatedVelocity\"] = flight_data.v(\n", - " flight_data.parachute_events[0][0] + flight_data.parachute_events[0][1].lag\n", - " )\n", - " else:\n", - " flight_result[\"drogue_triggerTime\"] = 0\n", - " flight_result[\"drogueInflatedTime\"] = 0\n", - " flight_result[\"drogueInflatedVelocity\"] = 0\n", - "\n", - " # Write flight setting and results to file\n", - " dispersion_input_file.write(str(flight_setting) + \"\\n\")\n", - " dispersion_output_file.write(str(flight_result) + \"\\n\")\n", - "\n", - "\n", - "def export_flight_error(flight_setting):\n", - " dispersion_error_file.write(str(flight_setting) + \"\\n\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "GX6pB4Y7pOQQ" - }, - "source": [ - "## Simulating Each Flight Setting\n", - "\n", - "Finally, we can start running some simulations!\n", - "\n", - "We start by defining the file name we want to use. Then, we specifiy how many simulations we would like to run by setting the `number_of_simulations` variable.\n", - "\n", - "It is good practice to run something in the order of 100 simulations first, to check for any possible errors in the code. Once we are confident that everything is working well, we increase the number of simulations to something in the range of 5000 to 50000.\n", - "\n", - "We will loop throught all flight settings, creating the environment, rocket and motor classes with the data of the analysis parameters.\n", - "For the power off and on drag and thrust curve user should have in hands the .csv (or .eng for comercial motor's thrust curve).\n", - "\n", - "**Tip**: A better practice is openning the files in \"append\" mode, this way we can acumulate our simulations. To do this, just change the 'a' (write) argument of the `open` function in the third, fourth and fifth line of code to `a` (append)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - }, - "id": "GILiaO30pOQS", - "outputId": "5a2ae15d-5c16-4ae0-f28b-165730d2419d" - }, - "outputs": [], - "source": [ - "# Basic analysis info\n", - "filename = \"dispersion_analysis_outputs/valetudo_rocket_v0\"\n", - "number_of_simulations = 20000\n", - "\n", - "# Create data files for inputs, outputs and error logging\n", - "dispersion_error_file = open(str(filename) + \".disp_errors.txt\", \"w\")\n", - "dispersion_input_file = open(str(filename) + \".disp_inputs.txt\", \"w\")\n", - "dispersion_output_file = open(str(filename) + \".disp_outputs.txt\", \"w\")\n", - "\n", - "# Initialize counter and timer\n", - "i = 0\n", - "\n", - "initial_wall_time = time()\n", - "initial_cpu_time = process_time()\n", - "\n", - "# Define basic Environment object\n", - "env = Environment(date=(2019, 8, 10, 21), latitude=-23.363611, longitude=-48.011389)\n", - "env.setElevation(668)\n", - "env.maxExpectedHeight = 1500\n", - "env.set_atmospheric_model(\n", - " type=\"Ensemble\",\n", - " file=\"dispersion_analysis_inputs/LASC2019_reanalysis.nc\",\n", - " dictionary=\"ECMWF\",\n", - ")\n", - "\n", - "\n", - "# Set up parachutes. This rocket, named Valetudo, only has a drogue chute.\n", - "def drogue_trigger(p, h, y):\n", - " # Check if rocket is going down, i.e. if it has passed the apogee\n", - " vertical_velocity = y[5]\n", - " # Return true to activate parachute once the vertical velocity is negative\n", - " return True if vertical_velocity < 0 else False\n", - "\n", - "\n", - "# Iterate over flight settings\n", - "out = display(\"Starting\", display_id=True)\n", - "for setting in flight_settings(analysis_parameters, number_of_simulations):\n", - " start_time = process_time()\n", - " i += 1\n", - "\n", - " # Update environment object\n", - " env.selectEnsembleMember(setting[\"ensembleMember\"])\n", - "\n", - " # Create motor\n", - " Keron = SolidMotor(\n", - " thrust_source=\"dispersion_analysis_inputs/thrustCurve.csv\",\n", - " burn_time=5.274,\n", - " reshape_thrust_curve=(setting[\"burn_time\"], setting[\"impulse\"]),\n", - " nozzle_radius=setting[\"nozzle_radius\"],\n", - " throat_radius=setting[\"throat_radius\"],\n", - " grains_center_of_mass_position=setting[\"distanceRocketPropellant\"],\n", - " grain_number=6,\n", - " grain_separation=setting[\"grain_separation\"],\n", - " grain_density=setting[\"grain_density\"],\n", - " grain_outer_radius=setting[\"grain_outer_radius\"],\n", - " grain_initial_inner_radius=setting[\"grain_initial_inner_radius\"],\n", - " grain_initial_height=setting[\"grain_initial_height\"],\n", - " interpolation_method=\"linear\",\n", - " nozzle_position=setting[\"distance_rocket_nozzle\"],\n", - " coordinate_system_orientation=\"nozzle_to_combustion_chamber\",\n", - " )\n", - " # Create rocket\n", - " Valetudo = Rocket(\n", - " radius=setting[\"radius\"],\n", - " mass=setting[\"rocket_mass\"],\n", - " inertia_i=setting[\"inertia_i\"],\n", - " inertia_z=setting[\"inertia_z\"],\n", - " power_off_drag=\"dispersion_analysis_inputs/Cd_PowerOff.csv\",\n", - " power_on_drag=\"dispersion_analysis_inputs/Cd_PowerOn.csv\",\n", - " center_of_dry_mass_position=0,\n", - " coordinate_system_orientation=\"tail_to_nose\",\n", - " )\n", - " Valetudo.set_rail_buttons(0.224, -0.93, 30)\n", - "\n", - " Valetudo.add_motor(Keron, position=setting[\"distance_rocket_nozzle\"])\n", - "\n", - " # Edit rocket drag\n", - " Valetudo.power_off_drag *= setting[\"power_off_drag\"]\n", - " Valetudo.power_on_drag *= setting[\"power_on_drag\"]\n", - " # Add rocket nose, fins and tail\n", - " NoseCone = Valetudo.add_nose(\n", - " length=setting[\"nose_length\"],\n", - " kind=\"vonKarman\",\n", - " position=setting[\"noseDistanceToCM\"] + setting[\"nose_length\"],\n", - " )\n", - " fin_set = Valetudo.add_trapezoidal_fins(\n", - " n=3,\n", - " span=setting[\"finSpan\"],\n", - " root_chord=setting[\"finRootChord\"],\n", - " tip_chord=setting[\"finTipChord\"],\n", - " position=setting[\"finDistanceToCM\"],\n", - " cant_angle=0,\n", - " airfoil=None,\n", - " )\n", - " # Add parachute\n", - " Drogue = Valetudo.add_parachute(\n", - " \"Drogue\",\n", - " cd_s=setting[\"CdSDrogue\"],\n", - " trigger=drogue_trigger,\n", - " sampling_rate=105,\n", - " lag=setting[\"lag_rec\"] + setting[\"lag_se\"],\n", - " noise=(0, 8.3, 0.5),\n", - " )\n", - "\n", - " # Run trajectory simulation\n", - " try:\n", - " test_flight = Flight(\n", - " rocket=Valetudo,\n", - " environment=env,\n", - " rail_length=setting[\"rail_length\"],\n", - " inclination=setting[\"inclination\"],\n", - " heading=setting[\"heading\"],\n", - " maxTime=600,\n", - " )\n", - " export_flight_data(setting, test_flight, process_time() - start_time)\n", - " except Exception as E:\n", - " print(E)\n", - " export_flight_error(setting)\n", - "\n", - " # Register time\n", - " out.update(\n", - " f\"Curent iteration: {i:06d} | Average Time per Iteration: {(process_time() - initial_cpu_time)/i:2.6f} s\"\n", - " )\n", - "\n", - "# Done\n", - "\n", - "## Print and save total time\n", - "final_string = f\"Completed {i} iterations successfully. Total CPU time: {process_time() - initial_cpu_time} s. Total wall time: {time() - initial_wall_time} s\"\n", - "out.update(final_string)\n", - "dispersion_input_file.write(final_string + \"\\n\")\n", - "dispersion_output_file.write(final_string + \"\\n\")\n", - "dispersion_error_file.write(final_string + \"\\n\")\n", - "\n", - "## Close files\n", - "dispersion_input_file.close()\n", - "dispersion_output_file.close()\n", - "dispersion_error_file.close()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Post-processing Monte Carlo Dispersion Results\n", - "\n", - "Now that we have finish running thousands of simulations, it is time to process the results and get some nice graphs out of them! " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "X8ewOccUpOQb" - }, - "source": [ - "### Importing Dispersion Analysis Saved Data\n", - "\n", - "We start by loading the file which stores the outputs." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "-7qgTJzRpOQb", - "outputId": "76d2cecd-a09f-429f-cca2-f4e03e39d49e" - }, - "outputs": [], - "source": [ - "filename = \"dispersion_analysis_outputs/valetudo_rocket_v0\"\n", - "\n", - "# Initialize variable to store all results\n", - "dispersion_general_results = []\n", - "\n", - "dispersion_results = {\n", - " \"out_of_rail_time\": [],\n", - " \"outOfRailVelocity\": [],\n", - " \"apogeeTime\": [],\n", - " \"apogeeAltitude\": [],\n", - " \"apogeeX\": [],\n", - " \"apogeeY\": [],\n", - " \"impactTime\": [],\n", - " \"impactX\": [],\n", - " \"impactY\": [],\n", - " \"impactVelocity\": [],\n", - " \"initialStaticMargin\": [],\n", - " \"outOfRailStaticMargin\": [],\n", - " \"finalStaticMargin\": [],\n", - " \"numberOfEvents\": [],\n", - " \"maxVelocity\": [],\n", - " \"drogue_triggerTime\": [],\n", - " \"drogueInflatedTime\": [],\n", - " \"drogueInflatedVelocity\": [],\n", - " \"executionTime\": [],\n", - "}\n", - "\n", - "# Get all dispersion results\n", - "# Get file\n", - "dispersion_output_file = open(str(filename) + \".disp_outputs.txt\", \"r+\")\n", - "\n", - "# Read each line of the file and convert to dict\n", - "for line in dispersion_output_file:\n", - " # Skip comments lines\n", - " if line[0] != \"{\":\n", - " continue\n", - " # Eval results and store them\n", - " flight_result = eval(line)\n", - " dispersion_general_results.append(flight_result)\n", - " for parameter_key, parameter_value in flight_result.items():\n", - " dispersion_results[parameter_key].append(parameter_value)\n", - "\n", - "# Close data file\n", - "dispersion_output_file.close()\n", - "\n", - "# Print number of flights simulated\n", - "N = len(dispersion_general_results)\n", - "print(\"Number of simulations: \", N)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "ioeUkzPipOQe" - }, - "source": [ - "## Dispersion Results\n", - "\n", - "Now, we plot the histogram for every single output. This shows how are outputs behave. Valuable statistical data can be calculated based on them." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "QDy8KaJ8pOQg" - }, - "source": [ - "### Out of Rail Time" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "1JQSzd5cpOQh", - "outputId": "455abcdf-9dd7-4689-9523-50154c7fb302" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Out of Rail Time - Mean Value: {np.mean(dispersion_results[\"out_of_rail_time\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Out of Rail Time - Standard Deviation: {np.std(dispersion_results[\"out_of_rail_time\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"out_of_rail_time\"], bins=int(N**0.5))\n", - "plt.title(\"Out of Rail Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()\n", - "\n", - "# You can also use Plotly instead of Matplotlib if you wish!\n", - "# import plotly.express as px\n", - "# fig1 = px.histogram(\n", - "# x=dispersion_results[\"out_of_rail_time\"],\n", - "# title='Out of Rail Time',\n", - "# nbins=int(N**0.5)\n", - "# )\n", - "# fig1.update_layout(\n", - "# xaxis_title_text='Time (s)',\n", - "# yaxis_title_text='Number of occurences'\n", - "# )" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "-9u9RIaqpOQl" - }, - "source": [ - "### Out of Rail Velocity" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "jE23vILMpOQm", - "outputId": "aa04f5a4-26f2-47e8-831a-41d3e76b616f" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Out of Rail Velocity - Mean Value: {np.mean(dispersion_results[\"outOfRailVelocity\"]):0.3f} m/s'\n", - ")\n", - "print(\n", - " f'Out of Rail Velocity - Standard Deviation: {np.std(dispersion_results[\"outOfRailVelocity\"]):0.3f} m/s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"outOfRailVelocity\"], bins=int(N**0.5))\n", - "plt.title(\"Out of Rail Velocity\")\n", - "plt.xlabel(\"Velocity (m/s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "tExJzLhDpOQp" - }, - "source": [ - "### Apogee Time" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "l8zjT_VjpOQq", - "outputId": "1c15fe12-afae-4035-f085-7d82e61d24d9" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee Time - Mean Value: {np.mean(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Apogee Time - Standard Deviation: {np.std(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeTime\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "erNB46vApOQt" - }, - "source": [ - "### Apogee Altitude" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "gWWMoOClpOQv", - "outputId": "88f2cf05-142c-4bb1-ce64-9879696107a7" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee Altitude - Mean Value: {np.mean(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Apogee Altitude - Standard Deviation: {np.std(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeAltitude\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee Altitude\")\n", - "plt.xlabel(\"Altitude (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()\n", - "\n", - "# Real measured apogee for Valetudo = 860 m" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "7bBvFJ5xpOQ1" - }, - "source": [ - "### Apogee X Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "nGdsF9VppOQ3", - "outputId": "b4f0a3aa-afa1-4942-91b8-8ad61d263244" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee X Position - Mean Value: {np.mean(dispersion_results[\"apogeeX\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Apogee X Position - Standard Deviation: {np.std(dispersion_results[\"apogeeX\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeX\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee X Position\")\n", - "plt.xlabel(\"Apogee X Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "-LtYxB0lpOQ8" - }, - "source": [ - "### Apogee Y Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "ocq6GmeNpOQ8", - "outputId": "f3a45339-c0a6-4819-bd03-60f7fe6df963" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee Y Position - Mean Value: {np.mean(dispersion_results[\"apogeeY\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Apogee Y Position - Standard Deviation: {np.std(dispersion_results[\"apogeeY\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeY\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee Y Position\")\n", - "plt.xlabel(\"Apogee Y Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "ifuJX7jYpORB" - }, - "source": [ - "### Impact Time" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "52j6t5-MpORB", - "outputId": "9cba31b1-c731-402f-b138-df5c72521408" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact Time - Mean Value: {np.mean(dispersion_results[\"impactTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Impact Time - Standard Deviation: {np.std(dispersion_results[\"impactTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactTime\"], bins=int(N**0.5))\n", - "plt.title(\"Impact Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "mYD4EQ5spORE" - }, - "source": [ - "### Impact X Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "uzL8-1UGpORF", - "outputId": "5c74f8d1-b909-44cf-a5c9-2f1b5e9dda1d" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact X Position - Mean Value: {np.mean(dispersion_results[\"impactX\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Impact X Position - Standard Deviation: {np.std(dispersion_results[\"impactX\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactX\"], bins=int(N**0.5))\n", - "plt.title(\"Impact X Position\")\n", - "plt.xlabel(\"Impact X Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "ajI4vr7QpORL" - }, - "source": [ - "### Impact Y Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "Q-ghmNVopORM", - "outputId": "cd0c81a8-a3fc-4710-cadf-a20cf0882bec" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact Y Position - Mean Value: {np.mean(dispersion_results[\"impactY\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Impact Y Position - Standard Deviation: {np.std(dispersion_results[\"impactY\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactY\"], bins=int(N**0.5))\n", - "plt.title(\"Impact Y Position\")\n", - "plt.xlabel(\"Impact Y Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "H7_H_eeXpORP" - }, - "source": [ - "### Impact Velocity" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "Ryx7KEEVpORP", - "outputId": "90cdcf97-affc-4f09-ed2a-9b854257a8a0" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact Velocity - Mean Value: {np.mean(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", - ")\n", - "print(\n", - " f'Impact Velocity - Standard Deviation: {np.std(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactVelocity\"], bins=int(N**0.5))\n", - "plt.title(\"Impact Velocity\")\n", - "# plt.grid()\n", - "plt.xlim(-35, 0)\n", - "plt.xlabel(\"Velocity (m/s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "-7qgTJzRpOQb", + "outputId": "76d2cecd-a09f-429f-cca2-f4e03e39d49e" + }, + "outputs": [], + "source": [ + "filename = \"dispersion_analysis_outputs/valetudo_rocket_v0\"\n", + "\n", + "# Initialize variable to store all results\n", + "dispersion_general_results = []\n", + "\n", + "dispersion_results = {\n", + " \"outOfRailTime\": [],\n", + " \"outOfRailVelocity\": [],\n", + " \"apogeeTime\": [],\n", + " \"apogeeAltitude\": [],\n", + " \"apogeeX\": [],\n", + " \"apogeeY\": [],\n", + " \"impactTime\": [],\n", + " \"impactX\": [],\n", + " \"impactY\": [],\n", + " \"impactVelocity\": [],\n", + " \"initialStaticMargin\": [],\n", + " \"outOfRailStaticMargin\": [],\n", + " \"finalStaticMargin\": [],\n", + " \"numberOfEvents\": [],\n", + " \"maxVelocity\": [],\n", + " \"drogueTriggerTime\": [],\n", + " \"drogueInflatedTime\": [],\n", + " \"drogueInflatedVelocity\": [],\n", + " \"executionTime\": [],\n", + "}\n", + "\n", + "# Get all dispersion results\n", + "# Get file\n", + "dispersion_output_file = open(str(filename) + \".disp_outputs.txt\", \"r+\")\n", + "\n", + "# Read each line of the file and convert to dict\n", + "for line in dispersion_output_file:\n", + " # Skip comments lines\n", + " if line[0] != \"{\":\n", + " continue\n", + " # Eval results and store them\n", + " flight_result = eval(line)\n", + " dispersion_general_results.append(flight_result)\n", + " for parameter_key, parameter_value in flight_result.items():\n", + " dispersion_results[parameter_key].append(parameter_value)\n", + "\n", + "# Close data file\n", + "dispersion_output_file.close()\n", + "\n", + "# Print number of flights simulated\n", + "N = len(dispersion_general_results)\n", + "print(\"Number of simulations: \", N)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ioeUkzPipOQe" + }, + "source": [ + "## Dispersion Results\n", + "\n", + "Now, we plot the histogram for every single output. This shows how are outputs behave. Valuable statistical data can be calculated based on them." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "QDy8KaJ8pOQg" + }, + "source": [ + "### Out of Rail Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "9m19OV9upORS" - }, - "source": [ - "### Static Margin" - ] + "id": "1JQSzd5cpOQh", + "outputId": "455abcdf-9dd7-4689-9523-50154c7fb302" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Out of Rail Time - Mean Value: {np.mean(dispersion_results[\"outOfRailTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Out of Rail Time - Standard Deviation: {np.std(dispersion_results[\"outOfRailTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"outOfRailTime\"], bins=int(N**0.5))\n", + "plt.title(\"Out of Rail Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n", + "\n", + "# You can also use Plotly instead of Matplotlib if you wish!\n", + "# import plotly.express as px\n", + "# fig1 = px.histogram(\n", + "# x=dispersion_results[\"outOfRailTime\"],\n", + "# title='Out of Rail Time',\n", + "# nbins=int(N**0.5)\n", + "# )\n", + "# fig1.update_layout(\n", + "# xaxis_title_text='Time (s)',\n", + "# yaxis_title_text='Number of occurences'\n", + "# )\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "-9u9RIaqpOQl" + }, + "source": [ + "### Out of Rail Velocity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 675 - }, - "id": "a2Tpo9hjpORT", - "outputId": "94129858-cd6b-4af6-8f88-66923455a566" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Initial Static Margin - Mean Value: {np.mean(dispersion_results[\"initialStaticMargin\"]):0.3f} c'\n", - ")\n", - "print(\n", - " f'Initial Static Margin - Standard Deviation: {np.std(dispersion_results[\"initialStaticMargin\"]):0.3f} c'\n", - ")\n", - "\n", - "print(\n", - " f'Out of Rail Static Margin - Mean Value: {np.mean(dispersion_results[\"outOfRailStaticMargin\"]):0.3f} c'\n", - ")\n", - "print(\n", - " f'Out of Rail Static Margin - Standard Deviation: {np.std(dispersion_results[\"outOfRailStaticMargin\"]):0.3f} c'\n", - ")\n", - "\n", - "print(\n", - " f'Final Static Margin - Mean Value: {np.mean(dispersion_results[\"finalStaticMargin\"]):0.3f} c'\n", - ")\n", - "print(\n", - " f'Final Static Margin - Standard Deviation: {np.std(dispersion_results[\"finalStaticMargin\"]):0.3f} c'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"initialStaticMargin\"], label=\"Initial\", bins=int(N**0.5))\n", - "plt.hist(\n", - " dispersion_results[\"outOfRailStaticMargin\"], label=\"Out of Rail\", bins=int(N**0.5)\n", - ")\n", - "plt.hist(dispersion_results[\"finalStaticMargin\"], label=\"Final\", bins=int(N**0.5))\n", - "plt.legend()\n", - "plt.title(\"Static Margin\")\n", - "plt.xlabel(\"Static Margin (c)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "jE23vILMpOQm", + "outputId": "aa04f5a4-26f2-47e8-831a-41d3e76b616f" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Out of Rail Velocity - Mean Value: {np.mean(dispersion_results[\"outOfRailVelocity\"]):0.3f} m/s'\n", + ")\n", + "print(\n", + " f'Out of Rail Velocity - Standard Deviation: {np.std(dispersion_results[\"outOfRailVelocity\"]):0.3f} m/s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"outOfRailVelocity\"], bins=int(N**0.5))\n", + "plt.title(\"Out of Rail Velocity\")\n", + "plt.xlabel(\"Velocity (m/s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "tExJzLhDpOQp" + }, + "source": [ + "### Apogee Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "mQzQELcJpORX" - }, - "source": [ - "### Maximum Velocity" - ] + "id": "l8zjT_VjpOQq", + "outputId": "1c15fe12-afae-4035-f085-7d82e61d24d9" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee Time - Mean Value: {np.mean(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Apogee Time - Standard Deviation: {np.std(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeTime\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "erNB46vApOQt" + }, + "source": [ + "### Apogee Altitude" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "nOu1O8MXpORY", - "outputId": "7510aec8-7b73-4751-f033-8367cd0c9bdc" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Maximum Velocity - Mean Value: {np.mean(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", - ")\n", - "print(\n", - " f'Maximum Velocity - Standard Deviation: {np.std(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"maxVelocity\"], bins=int(N**0.5))\n", - "plt.title(\"Maximum Velocity\")\n", - "plt.xlabel(\"Velocity (m/s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "gWWMoOClpOQv", + "outputId": "88f2cf05-142c-4bb1-ce64-9879696107a7" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee Altitude - Mean Value: {np.mean(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Apogee Altitude - Standard Deviation: {np.std(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeAltitude\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee Altitude\")\n", + "plt.xlabel(\"Altitude (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n", + "\n", + "# Real measured apogee for Valetudo = 860 m\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "7bBvFJ5xpOQ1" + }, + "source": [ + "### Apogee X Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "7MUVLAM-pORb" - }, - "source": [ - "### Number of Parachute Events\n", - "\n", - "This is usefull to check if the parachute was triggered in every flight." - ] + "id": "nGdsF9VppOQ3", + "outputId": "b4f0a3aa-afa1-4942-91b8-8ad61d263244" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee X Position - Mean Value: {np.mean(dispersion_results[\"apogeeX\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Apogee X Position - Standard Deviation: {np.std(dispersion_results[\"apogeeX\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeX\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee X Position\")\n", + "plt.xlabel(\"Apogee X Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "-LtYxB0lpOQ8" + }, + "source": [ + "### Apogee Y Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "yhcWi2kCpORb", - "outputId": "dee54569-8213-46cc-e287-9fffd2b8e43c" - }, - "outputs": [], - "source": [ - "plt.figure()\n", - "plt.hist(dispersion_results[\"numberOfEvents\"])\n", - "plt.title(\"Parachute Events\")\n", - "plt.xlabel(\"Number of Parachute Events\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "ocq6GmeNpOQ8", + "outputId": "f3a45339-c0a6-4819-bd03-60f7fe6df963" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee Y Position - Mean Value: {np.mean(dispersion_results[\"apogeeY\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Apogee Y Position - Standard Deviation: {np.std(dispersion_results[\"apogeeY\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeY\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee Y Position\")\n", + "plt.xlabel(\"Apogee Y Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ifuJX7jYpORB" + }, + "source": [ + "### Impact Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "4LpDYGpfpORf" - }, - "source": [ - "### Drogue Parachute Trigger Time" - ] + "id": "52j6t5-MpORB", + "outputId": "9cba31b1-c731-402f-b138-df5c72521408" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact Time - Mean Value: {np.mean(dispersion_results[\"impactTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Impact Time - Standard Deviation: {np.std(dispersion_results[\"impactTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactTime\"], bins=int(N**0.5))\n", + "plt.title(\"Impact Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "mYD4EQ5spORE" + }, + "source": [ + "### Impact X Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "lvCksZG8pORf", - "outputId": "3efd19ed-11e9-41d1-8e66-04da384665ce" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Drogue Parachute Trigger Time - Mean Value: {np.mean(dispersion_results[\"drogue_triggerTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Drogue Parachute Trigger Time - Standard Deviation: {np.std(dispersion_results[\"drogue_triggerTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"drogue_triggerTime\"], bins=int(N**0.5))\n", - "plt.title(\"Drogue Parachute Trigger Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "uzL8-1UGpORF", + "outputId": "5c74f8d1-b909-44cf-a5c9-2f1b5e9dda1d" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact X Position - Mean Value: {np.mean(dispersion_results[\"impactX\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Impact X Position - Standard Deviation: {np.std(dispersion_results[\"impactX\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactX\"], bins=int(N**0.5))\n", + "plt.title(\"Impact X Position\")\n", + "plt.xlabel(\"Impact X Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ajI4vr7QpORL" + }, + "source": [ + "### Impact Y Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "nKSzDWi7pORi" - }, - "source": [ - "### Drogue Parachute Fully Inflated Time" - ] + "id": "Q-ghmNVopORM", + "outputId": "cd0c81a8-a3fc-4710-cadf-a20cf0882bec" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact Y Position - Mean Value: {np.mean(dispersion_results[\"impactY\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Impact Y Position - Standard Deviation: {np.std(dispersion_results[\"impactY\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactY\"], bins=int(N**0.5))\n", + "plt.title(\"Impact Y Position\")\n", + "plt.xlabel(\"Impact Y Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "H7_H_eeXpORP" + }, + "source": [ + "### Impact Velocity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "KCYKVFYXpORj", - "outputId": "8ae49853-0f08-4bf6-9bd8-91a7c9a9448d" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Drogue Parachute Fully Inflated Time - Mean Value: {np.mean(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Drogue Parachute Fully Inflated Time - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"drogueInflatedTime\"], bins=int(N**0.5))\n", - "plt.title(\"Drogue Parachute Fully Inflated Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "Ryx7KEEVpORP", + "outputId": "90cdcf97-affc-4f09-ed2a-9b854257a8a0" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact Velocity - Mean Value: {np.mean(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", + ")\n", + "print(\n", + " f'Impact Velocity - Standard Deviation: {np.std(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactVelocity\"], bins=int(N**0.5))\n", + "plt.title(\"Impact Velocity\")\n", + "# plt.grid()\n", + "plt.xlim(-35, 0)\n", + "plt.xlabel(\"Velocity (m/s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "9m19OV9upORS" + }, + "source": [ + "### Static Margin" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 675 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "BvMCGZYHpORn" - }, - "source": [ - "### Drogue Parachute Fully Inflated Velocity" - ] + "id": "a2Tpo9hjpORT", + "outputId": "94129858-cd6b-4af6-8f88-66923455a566" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Initial Static Margin - Mean Value: {np.mean(dispersion_results[\"initialStaticMargin\"]):0.3f} c'\n", + ")\n", + "print(\n", + " f'Initial Static Margin - Standard Deviation: {np.std(dispersion_results[\"initialStaticMargin\"]):0.3f} c'\n", + ")\n", + "\n", + "print(\n", + " f'Out of Rail Static Margin - Mean Value: {np.mean(dispersion_results[\"outOfRailStaticMargin\"]):0.3f} c'\n", + ")\n", + "print(\n", + " f'Out of Rail Static Margin - Standard Deviation: {np.std(dispersion_results[\"outOfRailStaticMargin\"]):0.3f} c'\n", + ")\n", + "\n", + "print(\n", + " f'Final Static Margin - Mean Value: {np.mean(dispersion_results[\"finalStaticMargin\"]):0.3f} c'\n", + ")\n", + "print(\n", + " f'Final Static Margin - Standard Deviation: {np.std(dispersion_results[\"finalStaticMargin\"]):0.3f} c'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"initialStaticMargin\"], label=\"Initial\", bins=int(N**0.5))\n", + "plt.hist(\n", + " dispersion_results[\"outOfRailStaticMargin\"], label=\"Out of Rail\", bins=int(N**0.5)\n", + ")\n", + "plt.hist(dispersion_results[\"finalStaticMargin\"], label=\"Final\", bins=int(N**0.5))\n", + "plt.legend()\n", + "plt.title(\"Static Margin\")\n", + "plt.xlabel(\"Static Margin (c)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "mQzQELcJpORX" + }, + "source": [ + "### Maximum Velocity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "KxrpPUzqpORn", - "outputId": "9c102bdb-b805-4aa1-b3a2-1ac329c76976" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Drogue Parachute Fully Inflated Velocity - Mean Value: {np.mean(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", - ")\n", - "print(\n", - " f'Drogue Parachute Fully Inflated Velocity - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"drogueInflatedVelocity\"], bins=int(N**0.5))\n", - "plt.title(\"Drogue Parachute Fully Inflated Velocity\")\n", - "plt.xlabel(\"Velocity m/s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "nOu1O8MXpORY", + "outputId": "7510aec8-7b73-4751-f033-8367cd0c9bdc" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Maximum Velocity - Mean Value: {np.mean(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", + ")\n", + "print(\n", + " f'Maximum Velocity - Standard Deviation: {np.std(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"maxVelocity\"], bins=int(N**0.5))\n", + "plt.title(\"Maximum Velocity\")\n", + "plt.xlabel(\"Velocity (m/s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "7MUVLAM-pORb" + }, + "source": [ + "### Number of Parachute Events\n", + "\n", + "This is usefull to check if the parachute was triggered in every flight." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "TlWXtnKMrlMI" - }, - "source": [ - "### Error Ellipses\n" - ] + "id": "yhcWi2kCpORb", + "outputId": "dee54569-8213-46cc-e287-9fffd2b8e43c" + }, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.hist(dispersion_results[\"numberOfEvents\"])\n", + "plt.title(\"Parachute Events\")\n", + "plt.xlabel(\"Number of Parachute Events\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "4LpDYGpfpORf" + }, + "source": [ + "### Drogue Parachute Trigger Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "cellView": "both", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 837 - }, - "id": "DZRrk_bIr3iG", - "outputId": "b4a5a583-7f53-473a-bec2-2636cdf28a7c" - }, - "outputs": [], - "source": [ - "# Import libraries\n", - "from imageio import imread\n", - "from matplotlib.patches import Ellipse\n", - "\n", - "# Import background map\n", - "img = imread(\"dispersion_analysis_inputs/Valetudo_basemap_final.jpg\")\n", - "\n", - "# Retrieve dispersion data por apogee and impact XY position\n", - "apogeeX = np.array(dispersion_results[\"apogeeX\"])\n", - "apogeeY = np.array(dispersion_results[\"apogeeY\"])\n", - "impactX = np.array(dispersion_results[\"impactX\"])\n", - "impactY = np.array(dispersion_results[\"impactY\"])\n", - "\n", - "\n", - "# Define function to calculate eigen values\n", - "def eigsorted(cov):\n", - " vals, vecs = np.linalg.eigh(cov)\n", - " order = vals.argsort()[::-1]\n", - " return vals[order], vecs[:, order]\n", - "\n", - "\n", - "# Create plot figure\n", - "plt.figure(num=None, figsize=(8, 6), dpi=150, facecolor=\"w\", edgecolor=\"k\")\n", - "ax = plt.subplot(111)\n", - "\n", - "# Calculate error ellipses for impact\n", - "impactCov = np.cov(impactX, impactY)\n", - "impactVals, impactVecs = eigsorted(impactCov)\n", - "impactTheta = np.degrees(np.arctan2(*impactVecs[:, 0][::-1]))\n", - "impactW, impactH = 2 * np.sqrt(impactVals)\n", - "\n", - "# Draw error ellipses for impact\n", - "impact_ellipses = []\n", - "for j in [1, 2, 3]:\n", - " impactEll = Ellipse(\n", - " xy=(np.mean(impactX), np.mean(impactY)),\n", - " width=impactW * j,\n", - " height=impactH * j,\n", - " angle=impactTheta,\n", - " color=\"black\",\n", - " )\n", - " impactEll.set_facecolor((0, 0, 1, 0.2))\n", - " impact_ellipses.append(impactEll)\n", - " ax.add_artist(impactEll)\n", - "\n", - "# Calculate error ellipses for apogee\n", - "apogeeCov = np.cov(apogeeX, apogeeY)\n", - "apogeeVals, apogeeVecs = eigsorted(apogeeCov)\n", - "apogeeTheta = np.degrees(np.arctan2(*apogeeVecs[:, 0][::-1]))\n", - "apogeeW, apogeeH = 2 * np.sqrt(apogeeVals)\n", - "\n", - "# Draw error ellipses for apogee\n", - "for j in [1, 2, 3]:\n", - " apogeeEll = Ellipse(\n", - " xy=(np.mean(apogeeX), np.mean(apogeeY)),\n", - " width=apogeeW * j,\n", - " height=apogeeH * j,\n", - " angle=apogeeTheta,\n", - " color=\"black\",\n", - " )\n", - " apogeeEll.set_facecolor((0, 1, 0, 0.2))\n", - " ax.add_artist(apogeeEll)\n", - "\n", - "# Draw launch point\n", - "plt.scatter(0, 0, s=30, marker=\"*\", color=\"black\", label=\"Launch Point\")\n", - "# Draw apogee points\n", - "plt.scatter(apogeeX, apogeeY, s=5, marker=\"^\", color=\"green\", label=\"Simulated Apogee\")\n", - "# Draw impact points\n", - "plt.scatter(\n", - " impactX, impactY, s=5, marker=\"v\", color=\"blue\", label=\"Simulated Landing Point\"\n", - ")\n", - "# Draw real landing point\n", - "plt.scatter(\n", - " 411.89, -61.07, s=20, marker=\"X\", color=\"red\", label=\"Measured Landing Point\"\n", - ")\n", - "\n", - "plt.legend()\n", - "\n", - "# Add title and labels to plot\n", - "ax.set_title(\n", - " \"1$\\sigma$, 2$\\sigma$ and 3$\\sigma$ Dispersion Ellipses: Apogee and Lading Points\"\n", - ")\n", - "ax.set_ylabel(\"North (m)\")\n", - "ax.set_xlabel(\"East (m)\")\n", - "\n", - "# Add background image to plot\n", - "# You can translate the basemap by changing dx and dy (in meters)\n", - "dx = 0\n", - "dy = 0\n", - "plt.imshow(img, zorder=0, extent=[-1000 - dx, 1000 - dx, -1000 - dy, 1000 - dy])\n", - "plt.axhline(0, color=\"black\", linewidth=0.5)\n", - "plt.axvline(0, color=\"black\", linewidth=0.5)\n", - "plt.xlim(-100, 700)\n", - "plt.ylim(-300, 300)\n", - "\n", - "# Save plot and show result\n", - "plt.savefig(str(filename) + \".pdf\", bbox_inches=\"tight\", pad_inches=0)\n", - "plt.savefig(str(filename) + \".svg\", bbox_inches=\"tight\", pad_inches=0)\n", - "plt.show()" - ] - } - ], - "metadata": { + "id": "lvCksZG8pORf", + "outputId": "3efd19ed-11e9-41d1-8e66-04da384665ce" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Drogue Parachute Trigger Time - Mean Value: {np.mean(dispersion_results[\"drogueTriggerTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Drogue Parachute Trigger Time - Standard Deviation: {np.std(dispersion_results[\"drogueTriggerTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"drogueTriggerTime\"], bins=int(N**0.5))\n", + "plt.title(\"Drogue Parachute Trigger Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "nKSzDWi7pORi" + }, + "source": [ + "### Drogue Parachute Fully Inflated Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { "colab": { - "collapsed_sections": [ - "au88RN0P-bVl", - "-9u9RIaqpOQl", - "tExJzLhDpOQp", - "ifuJX7jYpORB", - "mYD4EQ5spORE", - "ajI4vr7QpORL", - "9m19OV9upORS", - "mQzQELcJpORX", - "7MUVLAM-pORb", - "4LpDYGpfpORf", - "nKSzDWi7pORi", - "BvMCGZYHpORn", - "LhPQQlpHpORq", - "5MvfiSQZvwPK" - ], - "name": "Valetudo_Monte_Carlo_Dispersion_Analysis.ipynb", - "provenance": [], - "toc_visible": true + "base_uri": "https://localhost:8080/", + "height": 607 }, - "kernelspec": { - "display_name": "Python 3.10.5 64-bit", - "language": "python", - "name": "python3" + "id": "KCYKVFYXpORj", + "outputId": "8ae49853-0f08-4bf6-9bd8-91a7c9a9448d" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Drogue Parachute Fully Inflated Time - Mean Value: {np.mean(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Drogue Parachute Fully Inflated Time - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"drogueInflatedTime\"], bins=int(N**0.5))\n", + "plt.title(\"Drogue Parachute Fully Inflated Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "BvMCGZYHpORn" + }, + "source": [ + "### Drogue Parachute Fully Inflated Velocity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - "language_info": { - "name": "python", - "version": "3.10.5" + "id": "KxrpPUzqpORn", + "outputId": "9c102bdb-b805-4aa1-b3a2-1ac329c76976" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Drogue Parachute Fully Inflated Velocity - Mean Value: {np.mean(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", + ")\n", + "print(\n", + " f'Drogue Parachute Fully Inflated Velocity - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"drogueInflatedVelocity\"], bins=int(N**0.5))\n", + "plt.title(\"Drogue Parachute Fully Inflated Velocity\")\n", + "plt.xlabel(\"Velocity m/s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "TlWXtnKMrlMI" + }, + "source": [ + "### Error Ellipses\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "both", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 837 }, - "vscode": { - "interpreter": { - "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" - } - } + "id": "DZRrk_bIr3iG", + "outputId": "b4a5a583-7f53-473a-bec2-2636cdf28a7c" + }, + "outputs": [], + "source": [ + "# Import libraries\n", + "from imageio import imread\n", + "from matplotlib.patches import Ellipse\n", + "\n", + "# Import background map\n", + "img = imread(\"dispersion_analysis_inputs/Valetudo_basemap_final.jpg\")\n", + "\n", + "# Retrieve dispersion data por apogee and impact XY position\n", + "apogeeX = np.array(dispersion_results[\"apogeeX\"])\n", + "apogeeY = np.array(dispersion_results[\"apogeeY\"])\n", + "impactX = np.array(dispersion_results[\"impactX\"])\n", + "impactY = np.array(dispersion_results[\"impactY\"])\n", + "\n", + "# Define function to calculate eigen values\n", + "def eigsorted(cov):\n", + " vals, vecs = np.linalg.eigh(cov)\n", + " order = vals.argsort()[::-1]\n", + " return vals[order], vecs[:, order]\n", + "\n", + "\n", + "# Create plot figure\n", + "plt.figure(num=None, figsize=(8, 6), dpi=150, facecolor=\"w\", edgecolor=\"k\")\n", + "ax = plt.subplot(111)\n", + "\n", + "# Calculate error ellipses for impact\n", + "impactCov = np.cov(impactX, impactY)\n", + "impactVals, impactVecs = eigsorted(impactCov)\n", + "impactTheta = np.degrees(np.arctan2(*impactVecs[:, 0][::-1]))\n", + "impactW, impactH = 2 * np.sqrt(impactVals)\n", + "\n", + "# Draw error ellipses for impact\n", + "impact_ellipses = []\n", + "for j in [1, 2, 3]:\n", + " impactEll = Ellipse(\n", + " xy=(np.mean(impactX), np.mean(impactY)),\n", + " width=impactW * j,\n", + " height=impactH * j,\n", + " angle=impactTheta,\n", + " color=\"black\",\n", + " )\n", + " impactEll.set_facecolor((0, 0, 1, 0.2))\n", + " impact_ellipses.append(impactEll)\n", + " ax.add_artist(impactEll)\n", + "\n", + "# Calculate error ellipses for apogee\n", + "apogeeCov = np.cov(apogeeX, apogeeY)\n", + "apogeeVals, apogeeVecs = eigsorted(apogeeCov)\n", + "apogeeTheta = np.degrees(np.arctan2(*apogeeVecs[:, 0][::-1]))\n", + "apogeeW, apogeeH = 2 * np.sqrt(apogeeVals)\n", + "\n", + "# Draw error ellipses for apogee\n", + "for j in [1, 2, 3]:\n", + " apogeeEll = Ellipse(\n", + " xy=(np.mean(apogeeX), np.mean(apogeeY)),\n", + " width=apogeeW * j,\n", + " height=apogeeH * j,\n", + " angle=apogeeTheta,\n", + " color=\"black\",\n", + " )\n", + " apogeeEll.set_facecolor((0, 1, 0, 0.2))\n", + " ax.add_artist(apogeeEll)\n", + "\n", + "# Draw launch point\n", + "plt.scatter(0, 0, s=30, marker=\"*\", color=\"black\", label=\"Launch Point\")\n", + "# Draw apogee points\n", + "plt.scatter(apogeeX, apogeeY, s=5, marker=\"^\", color=\"green\", label=\"Simulated Apogee\")\n", + "# Draw impact points\n", + "plt.scatter(\n", + " impactX, impactY, s=5, marker=\"v\", color=\"blue\", label=\"Simulated Landing Point\"\n", + ")\n", + "# Draw real landing point\n", + "plt.scatter(\n", + " 411.89, -61.07, s=20, marker=\"X\", color=\"red\", label=\"Measured Landing Point\"\n", + ")\n", + "\n", + "plt.legend()\n", + "\n", + "# Add title and labels to plot\n", + "ax.set_title(\n", + " \"1$\\sigma$, 2$\\sigma$ and 3$\\sigma$ Dispersion Ellipses: Apogee and Lading Points\"\n", + ")\n", + "ax.set_ylabel(\"North (m)\")\n", + "ax.set_xlabel(\"East (m)\")\n", + "\n", + "# Add background image to plot\n", + "# You can translate the basemap by changing dx and dy (in meters)\n", + "dx = 0\n", + "dy = 0\n", + "plt.imshow(img, zorder=0, extent=[-1000 - dx, 1000 - dx, -1000 - dy, 1000 - dy])\n", + "plt.axhline(0, color=\"black\", linewidth=0.5)\n", + "plt.axvline(0, color=\"black\", linewidth=0.5)\n", + "plt.xlim(-100, 700)\n", + "plt.ylim(-300, 300)\n", + "\n", + "# Save plot and show result\n", + "plt.savefig(str(filename) + \".pdf\", bbox_inches=\"tight\", pad_inches=0)\n", + "plt.savefig(str(filename) + \".svg\", bbox_inches=\"tight\", pad_inches=0)\n", + "plt.show()\n" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + "au88RN0P-bVl", + "-9u9RIaqpOQl", + "tExJzLhDpOQp", + "ifuJX7jYpORB", + "mYD4EQ5spORE", + "ajI4vr7QpORL", + "9m19OV9upORS", + "mQzQELcJpORX", + "7MUVLAM-pORb", + "4LpDYGpfpORf", + "nKSzDWi7pORi", + "BvMCGZYHpORn", + "LhPQQlpHpORq", + "5MvfiSQZvwPK" + ], + "name": "Valetudo_Monte_Carlo_Dispersion_Analysis.ipynb", + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3.10.5 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.10.5" }, - "nbformat": 4, - "nbformat_minor": 2 + "vscode": { + "interpreter": { + "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 } diff --git a/docs/notebooks/dispersion_analysis/parachute_drop_from_helicopter.ipynb b/docs/notebooks/dispersion_analysis/parachute_drop_from_helicopter.ipynb index 49b5d79cf..91b48a0f8 100644 --- a/docs/notebooks/dispersion_analysis/parachute_drop_from_helicopter.ipynb +++ b/docs/notebooks/dispersion_analysis/parachute_drop_from_helicopter.ipynb @@ -1,24 +1,67 @@ { - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "V0OcBOvipOP8" - }, - "source": [ - "# Monte Carlo Dispersion Analysis of a Parachute Drop from Helicopter using RocketPy\n", - "\n", - "This is an advanced use of RocketPy. This notebook wraps RocketPy's methods to run a Monte Carlo analysis and predict probability distributions of the rocket's landing point if realeased from a helicopter. This is a common test used to validate the parachute system before a rocket launch." - ] + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "V0OcBOvipOP8" + }, + "source": [ + "# Parachute Drop from Helicopter\n", + "\n", + "A Monte Carlo Dispersion Analysis of a Parachute Drop from Helicopter using RocketPy\n", + "\n", + "This is an advanced use of RocketPy. This notebook wraps RocketPy's methods to run a Monte Carlo analysis and predict probability distributions of the rocket's landing point if realeased from a helicopter. This is a common test used to validate the parachute system before a rocket launch." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Clone repository if using Google Colab\n", + "\n", + "If you are running this using Binder, or you are running locally with the necessary files, you do not need to run this.\n", + "On the other hand, if you are running on Google Colab, make sure to run the cell below to clone the repository and download the necessary files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%git clone https://github.com/giovaniceotto/RocketPy.git\n", + "import os\n", + "\n", + "os.chdir(\"RocketPy/docs/notebooks/dispersion_analysis\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "Um2fvNlQpTAH" + }, + "source": [ + "## Install and Load Necessary Libraries\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, "id": "JJNfsYrwpXGJ", "outputId": "e2c4e1ef-4720-40ae-abd1-4d2a599bedd4" }, "outputs": [], "source": [ - "!pip install netCDF4\n", - "!pip install rocketpy" + "%pip install netCDF4\n", + "%pip install rocketpy" ] }, { @@ -29,15 +72,15 @@ }, "outputs": [], "source": [ - "from datetime import datetime\n", - "from time import process_time, perf_counter, time\n", "import glob\n", - "\n", - "from rocketpy import Environment, SolidMotor, Rocket, Flight, Function\n", + "from datetime import datetime\n", + "from time import perf_counter, process_time, time\n", "\n", "import numpy as np\n", - "from numpy.random import normal, uniform, choice\n", - "from IPython.display import display\n" + "from IPython.display import display\n", + "from numpy.random import choice, normal, uniform\n", + "\n", + "from rocketpy import Environment, Flight, Function, Rocket, SolidMotor\n" ] }, { @@ -99,7 +142,7 @@ "source": [ "analysis_parameters = {\n", " # Mass Details\n", - " \"rocket_mass\": (\n", + " \"rocketMass\": (\n", " 8.257,\n", " 0.001,\n", " ), # Rocket's dry mass (kg) and its uncertainty (standard deviation)\n", @@ -112,19 +155,19 @@ " 6 / 1000,\n", " 1 / 1000,\n", " ), # Motor's grain separation (axial distance between two grains) (m)\n", - " \"grain_density\": [1e-8], # Motor's grain density (kg/m^3)\n", - " \"grain_outer_radius\": (21.4 / 1000, 0.375 / 1000), # Motor's grain outer radius (m)\n", - " \"grain_initial_inner_radius\": (\n", + " \"grainDensity\": [1e-8], # Motor's grain density (kg/m^3)\n", + " \"grainOuterRadius\": (21.4 / 1000, 0.375 / 1000), # Motor's grain outer radius (m)\n", + " \"grainInitialInnerRadius\": (\n", " 9.65 / 1000,\n", " 0.375 / 1000,\n", " ), # Motor's grain inner radius (m)\n", - " \"grain_initial_height\": (120 / 1000, 1 / 1000), # Motor's grain height (m)\n", + " \"grainInitialHeight\": (120 / 1000, 1 / 1000), # Motor's grain height (m)\n", " # Aerodynamic Details - run help(Rocket) for more information\n", - " \"inertia_i\": (\n", + " \"inertiaI\": (\n", " 3.675,\n", " 0.03675,\n", " ), # Rocket's inertia moment perpendicular to its axis (kg*m^2)\n", - " \"inertia_z\": (\n", + " \"inertiaZ\": (\n", " 0.007,\n", " 0.00007,\n", " ), # Rocket's inertia moment relative to its axis (kg*m^2)\n", @@ -137,11 +180,11 @@ " -0.571,\n", " 0.001,\n", " ), # Distance between rocket's center of dry mass and and center of propellant mass (m) (negative)\n", - " \"power_off_drag\": (\n", + " \"powerOffDrag\": (\n", " 0.9081 / 1.05,\n", " 0.033,\n", " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", - " \"power_on_drag\": (\n", + " \"powerOnDrag\": (\n", " 0.9081 / 1.05,\n", " 0.033,\n", " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", @@ -256,19 +299,19 @@ " \"outOfRailTime\": flight_data.outOfRailTime,\n", " \"outOfRailVelocity\": flight_data.outOfRailVelocity,\n", " \"apogeeTime\": flight_data.apogeeTime,\n", - " \"apogeeAltitude\": flight_data.apogee - env.elevation,\n", + " \"apogeeAltitude\": flight_data.apogee - Env.elevation,\n", " \"apogeeX\": flight_data.apogeeX,\n", " \"apogeeY\": flight_data.apogeeY,\n", " \"impactTime\": flight_data.tFinal,\n", " \"impactX\": flight_data.xImpact,\n", " \"impactY\": flight_data.yImpact,\n", " \"impactVelocity\": flight_data.impactVelocity,\n", - " \"initialStaticMargin\": flight_data.rocket.static_margin(0),\n", - " \"outOfRailStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.outOfRailTime\n", + " \"initialStaticMargin\": flight_data.rocket.staticMargin(0),\n", + " \"outOfRailStaticMargin\": flight_data.rocket.staticMargin(\n", + " TestFlight.outOfRailTime\n", " ),\n", - " \"finalStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.rocket.motor.burn_out_time\n", + " \"finalStaticMargin\": flight_data.rocket.staticMargin(\n", + " TestFlight.rocket.motor.burnOutTime\n", " ),\n", " \"numberOfEvents\": len(flight_data.parachuteEvents),\n", " \"executionTime\": exec_time,\n", @@ -364,19 +407,19 @@ "initial_cpu_time = process_time()\n", "\n", "# Define basic Environment object\n", - "env = Environment(\n", + "Env = Environment(\n", " date=(2019, 8, 10, 21), latitude=-23.363611, longitude=-48.011389\n", ")\n", - "env.setElevation(668)\n", - "env.maxExpectedHeight = 1500\n", - "env.set_atmospheric_model(\n", + "Env.setElevation(668)\n", + "Env.maxExpectedHeight = 1500\n", + "Env.setAtmosphericModel(\n", " type=\"Ensemble\",\n", " file=\"dispersion_analysis_inputs/LASC2019_reanalysis.nc\",\n", " dictionary=\"ECMWF\",\n", ")\n", "\n", "# Set up parachutes. This rocket, named Valetudo, only has a drogue chute.\n", - "def drogue_trigger(p, h, y):\n", + "def drogueTrigger(p, h, y):\n", " # Check if rocket is going down, i.e. if it has passed the apogee\n", " vertical_velocity = y[5]\n", " # Return true to activate parachute once the vertical velocity is negative\n", @@ -390,65 +433,65 @@ " i += 1\n", "\n", " # Update environment object\n", - " env.selectEnsembleMember(setting[\"ensembleMember\"])\n", + " Env.selectEnsembleMember(setting[\"ensembleMember\"])\n", "\n", " # Create motor\n", " Keron = SolidMotor(\n", - " thrust_source=\"dispersion_analysis_inputs/thrustCurve.csv\",\n", + " thrustSource=\"dispersion_analysis_inputs/thrustCurve.csv\",\n", " burn_time=5.274,\n", - " reshape_thrust_curve=(setting[\"burn_time\"], setting[\"impulse\"]),\n", + " reshapeThrustCurve=(setting[\"burn_time\"], setting[\"impulse\"]),\n", " nozzle_radius=setting[\"nozzle_radius\"],\n", " throat_radius=setting[\"throat_radius\"],\n", - " grains_center_of_mass_position=setting[\"distanceRocketPropellant\"],\n", - " grain_number=6,\n", + " grainsCenterOfMassPosition=setting[\"distanceRocketPropellant\"],\n", + " grainNumber=6,\n", " grain_separation=setting[\"grain_separation\"],\n", - " grain_density=setting[\"grain_density\"],\n", - " grain_outer_radius=setting[\"grain_outer_radius\"],\n", - " grain_initial_inner_radius=setting[\"grain_initial_inner_radius\"],\n", - " grain_initial_height=setting[\"grain_initial_height\"],\n", - " interpolation_method=\"linear\",\n", - " nozzle_position=setting[\"distanceRocketNozzle\"],\n", - " coordinate_system_orientation=\"nozzle_to_combustion_chamber\",\n", + " grainDensity=setting[\"grainDensity\"],\n", + " grainOuterRadius=setting[\"grainOuterRadius\"],\n", + " grainInitialInnerRadius=setting[\"grainInitialInnerRadius\"],\n", + " grainInitialHeight=setting[\"grainInitialHeight\"],\n", + " interpolationMethod=\"linear\",\n", + " nozzlePosition=setting[\"distanceRocketNozzle\"],\n", + " coordinateSystemOrientation=\"nozzleToCombustionChamber\",\n", " )\n", "\n", " # Create rocket\n", " Valetudo = Rocket(\n", " radius=setting[\"radius\"],\n", - " mass=setting[\"rocket_mass\"],\n", - " inertia_i=setting[\"inertia_i\"],\n", - " inertia_z=setting[\"inertia_z\"],\n", - " power_off_drag=\"dispersion_analysis_inputs/Cd_PowerOff.csv\",\n", - " power_on_drag=\"dispersion_analysis_inputs/Cd_PowerOn.csv\",\n", - " center_of_dry_mass_position=0,\n", - " coordinate_system_orientation=\"tail_to_nose\",\n", + " mass=setting[\"rocketMass\"],\n", + " inertiaI=setting[\"inertiaI\"],\n", + " inertiaZ=setting[\"inertiaZ\"],\n", + " powerOffDrag=\"dispersion_analysis_inputs/Cd_PowerOff.csv\",\n", + " powerOnDrag=\"dispersion_analysis_inputs/Cd_PowerOn.csv\",\n", + " centerOfDryMassPosition=0,\n", + " coordinateSystemOrientation=\"tailToNose\",\n", " )\n", " Valetudo.setRailButtons(0.224, -0.93, 30)\n", "\n", - " Valetudo.add_motor(Keron, position=setting[\"distanceRocketNozzle\"])\n", + " Valetudo.addMotor(Keron, position=setting[\"distanceRocketNozzle\"])\n", "\n", " # Edit rocket drag\n", - " Valetudo.power_off_drag *= setting[\"power_off_drag\"]\n", - " Valetudo.power_on_drag *= setting[\"power_on_drag\"]\n", + " Valetudo.powerOffDrag *= setting[\"powerOffDrag\"]\n", + " Valetudo.powerOnDrag *= setting[\"powerOnDrag\"]\n", " # Add rocket nose, fins and tail\n", - " NoseCone = Valetudo.add_nose(\n", + " NoseCone = Valetudo.addNose(\n", " length=setting[\"noseLength\"],\n", " kind=\"vonKarman\",\n", " position=setting[\"noseDistanceToCM\"] + setting[\"noseLength\"],\n", " )\n", - " fin_set = Valetudo.add_trapezoidal_fins(\n", + " FinSet = Valetudo.addTrapezoidalFins(\n", " n=3,\n", " span=setting[\"finSpan\"],\n", " rootChord=setting[\"finRootChord\"],\n", - " tip_chord=setting[\"finTipChord\"],\n", + " tipChord=setting[\"finTipChord\"],\n", " position=setting[\"finDistanceToCM\"],\n", " cantAngle=0,\n", " airfoil=None,\n", " )\n", " # Add parachute\n", - " Drogue = Valetudo.add_parachute(\n", + " Drogue = Valetudo.addParachute(\n", " \"Drogue\",\n", " CdS=setting[\"CdSDrogue\"],\n", - " trigger=drogue_trigger,\n", + " trigger=drogueTrigger,\n", " samplingRate=105,\n", " lag=setting[\"lag_rec\"] + setting[\"lag_se\"],\n", " noise=(0, 8.3, 0.5),\n", @@ -456,9 +499,9 @@ "\n", " # Run trajectory simulation\n", " try:\n", - " test_flight = Flight(\n", + " TestFlight = Flight(\n", " rocket=Valetudo,\n", - " environment=env,\n", + " environment=Env,\n", " railLength=setting[\"railLength\"],\n", " inclination=setting[\"inclination\"],\n", " heading=setting[\"heading\"],\n", @@ -467,7 +510,7 @@ " 0.0,\n", " 0.0,\n", " 0.0,\n", - " 800 + env.elevation,\n", + " 800 + Env.elevation,\n", " 10.0,\n", " 10.0,\n", " 1.0,\n", @@ -480,7 +523,7 @@ " 0.0,\n", " ],\n", " )\n", - " export_flight_data(setting, test_flight, process_time() - start_time)\n", + " export_flight_data(setting, TestFlight, process_time() - start_time)\n", " except Exception as E:\n", " print(E)\n", " export_flight_error(setting)\n", @@ -534,1271 +577,731 @@ "colab": { "base_uri": "https://localhost:8080/" }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "Um2fvNlQpTAH" - }, - "source": [ - "## Install and Load Necessary Libraries\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "JJNfsYrwpXGJ", - "outputId": "e2c4e1ef-4720-40ae-abd1-4d2a599bedd4" - }, - "outputs": [], - "source": [ - "!pip install netCDF4\n", - "!pip install rocketpy" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "rNY7u8fApOP_" - }, - "outputs": [], - "source": [ - "from datetime import datetime\n", - "from time import process_time, perf_counter, time\n", - "import glob\n", - "\n", - "from rocketpy import Environment, SolidMotor, Rocket, Flight, Function\n", - "\n", - "import numpy as np\n", - "from numpy.random import normal, uniform, choice\n", - "from IPython.display import display" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we import matplotlib to produce awesome looking plots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "0uEmvBIt5Ltg" - }, - "outputs": [], - "source": [ - "%config InlineBackend.figure_formats = ['svg']\n", - "import matplotlib as mpl\n", - "import matplotlib.pyplot as plt\n", - "\n", - "%matplotlib inline\n", - "mpl.rcParams[\"figure.figsize\"] = [8, 5]\n", - "mpl.rcParams[\"figure.dpi\"] = 120\n", - "mpl.rcParams[\"font.size\"] = 14\n", - "mpl.rcParams[\"legend.fontsize\"] = 14\n", - "mpl.rcParams[\"figure.titlesize\"] = 14" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "4ksmBqU7pOQC" - }, - "source": [ - "## Defining Analysis Parameters\n", - "\n", - "The analysis parameters are a collection of expected values (and their uncertainties, or standard deviation) that completely defines a rocket flight.\n", - "As an assumption, the parameters which define the flight can behave in 3 different ways:\n", - " - the parameter is a completely known and has a constant value (i.e. number of fins)\n", - " - the parameter can assume certain discrete values with uniform distribution (i.e. the member of an ensemble forecast, which might be any integer from 0 to 9)\n", - " - the parameter is best represented by a normal (gaussian) distribution with a defined expected value and standard deviation\n", - "\n", - "We implement this using a dictionary, where the key is the name of the parameter and the value is either a tuple or a list, depending on the behaviour of the parameter:\n", - " - if the parameter is know, its value is represented as a list with a single entry (i.e. `\"number_of_fins: [4]\"`)\n", - " - if the parameter can assume certain discrete values with uniform distribution, its values are represented by a list of possible choices (i.e. `\"member_of_ensemble_forecast: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\"`)\n", - " - if the parameter is best represented by a normal (gaussian) distribution, its value is a tuple with the expected value and its standard deviation (i.e. `\"rocket_mass\": (100, 2)`, where 100 kg is the expected mass, with uncertainty of plus or minus 2 kg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "fwoCdOgKpOQD" - }, - "outputs": [], - "source": [ - "analysis_parameters = {\n", - " # Mass Details\n", - " \"rocket_mass\": (\n", - " 8.257,\n", - " 0.001,\n", - " ), # Rocket's dry mass (kg) and its uncertainty (standard deviation)\n", - " # Propulsion Details - run help(SolidMotor) for more information\n", - " \"impulse\": [1e-8], # Motor total impulse (N*s)\n", - " \"burn_time\": [1e-8], # Motor burn out time (s)\n", - " \"nozzle_radius\": (21.642 / 1000, 0.5 / 1000), # Motor's nozzle radius (m)\n", - " \"throat_radius\": (8 / 1000, 0.5 / 1000), # Motor's nozzle throat radius (m)\n", - " \"grain_separation\": (\n", - " 6 / 1000,\n", - " 1 / 1000,\n", - " ), # Motor's grain separation (axial distance between two grains) (m)\n", - " \"grain_density\": [1e-8], # Motor's grain density (kg/m^3)\n", - " \"grain_outer_radius\": (21.4 / 1000, 0.375 / 1000), # Motor's grain outer radius (m)\n", - " \"grain_initial_inner_radius\": (\n", - " 9.65 / 1000,\n", - " 0.375 / 1000,\n", - " ), # Motor's grain inner radius (m)\n", - " \"grain_initial_height\": (120 / 1000, 1 / 1000), # Motor's grain height (m)\n", - " # Aerodynamic Details - run help(Rocket) for more information\n", - " \"inertia_i\": (\n", - " 3.675,\n", - " 0.03675,\n", - " ), # Rocket's inertia moment perpendicular to its axis (kg*m^2)\n", - " \"inertia_z\": (\n", - " 0.007,\n", - " 0.00007,\n", - " ), # Rocket's inertia moment relative to its axis (kg*m^2)\n", - " \"radius\": (40.45 / 1000, 0.001), # Rocket's radius (kg*m^2)\n", - " \"distance_rocket_nozzle\": (\n", - " -1.024,\n", - " 0.001,\n", - " ), # Distance between rocket's center of dry mass and nozzle exit plane (m) (negative)\n", - " \"distanceRocketPropellant\": (\n", - " -0.571,\n", - " 0.001,\n", - " ), # Distance between rocket's center of dry mass and and center of propellant mass (m) (negative)\n", - " \"power_off_drag\": (\n", - " 0.9081 / 1.05,\n", - " 0.033,\n", - " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", - " \"power_on_drag\": (\n", - " 0.9081 / 1.05,\n", - " 0.033,\n", - " ), # Multiplier for rocket's drag curve. Usually has a mean value of 1 and a uncertainty of 5% to 10%\n", - " \"nose_length\": (0.274, 0.001), # Rocket's nose cone length (m)\n", - " \"noseDistanceToCM\": (\n", - " 1.134,\n", - " 0.001,\n", - " ), # Axial distance between rocket's center of dry mass and nearest point in its nose cone (m)\n", - " \"finSpan\": (0.077, 0.0005), # Fin span (m)\n", - " \"finRootChord\": (0.058, 0.0005), # Fin root chord (m)\n", - " \"finTipChord\": (0.018, 0.0005), # Fin tip chord (m)\n", - " \"finDistanceToCM\": (\n", - " -0.906,\n", - " 0.001,\n", - " ), # Axial distance between rocket's center of dry mass and nearest point in its fin (m)\n", - " # Launch and Environment Details - run help(Environment) and help(Flight) for more information\n", - " \"inclination\": (\n", - " 84.7,\n", - " 1,\n", - " ), # Launch rail inclination angle relative to the horizontal plane (degrees)\n", - " \"heading\": (53, 2), # Launch rail heading relative to north (degrees)\n", - " \"rail_length\": (5.7, 0.0005), # Launch rail length (m)\n", - " \"ensembleMember\": [4], # Members of the ensemble forecast to be used\n", - " # Parachute Details - run help(Rocket) for more information\n", - " \"CdSDrogue\": (\n", - " 0.349 * 1.3,\n", - " 0.07,\n", - " ), # Drag coefficient times reference area for the drogue chute (m^2)\n", - " \"lag_rec\": (\n", - " 1,\n", - " 0.5,\n", - " ), # Time delay between parachute ejection signal is detected and parachute is inflated (s)\n", - " # Electronic Systems Details - run help(Rocket) for more information\n", - " \"lag_se\": (\n", - " 0.73,\n", - " 1.0,\n", - " ), # Time delay between sensor signal is received and ejection signal is fired (s)\n", - "}" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "EJCbP69TpOQG" - }, - "source": [ - "## Creating a Flight Settings Generator\n", - "\n", - "Now, we create a generator function which will yield all the necessary inputs for a single flight simulation. Each generated input will be randomly generated according to the `analysis_parameters` dicitionary set up above.\n", - "\n", - "This is just a helper function to make the code clearer." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "5XCL9JaIpOQH" - }, - "outputs": [], - "source": [ - "def flight_settings(analysis_parameters, total_number):\n", - " i = 0\n", - " while i < total_number:\n", - " # Generate a flight setting\n", - " flight_setting = {}\n", - " for parameter_key, parameter_value in analysis_parameters.items():\n", - " if type(parameter_value) is tuple:\n", - " flight_setting[parameter_key] = normal(*parameter_value)\n", - " else:\n", - " flight_setting[parameter_key] = choice(parameter_value)\n", - "\n", - " # Skip if certain values are negative, which happens due to the normal curve but isnt realistic\n", - " if flight_setting[\"lag_rec\"] < 0 or flight_setting[\"lag_se\"] < 0:\n", - " continue\n", - "\n", - " # Update counter\n", - " i += 1\n", - " # Yield a flight setting\n", - " yield flight_setting" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "FtdRXCVHpOQO" - }, - "source": [ - "## Creating an Export Function\n", - "\n", - "Monte Carlo analyses usually contain data from thousands or tens of thousands of simulations. They can easily take hours to run. Therefore, it is very important to save our outputs to a file during the analysis. This way, if something happens, we do not lose our progress.\n", - "\n", - "These next functions take care of that. They export the simulation data to three different files:\n", - "- `dispersion_input_file`: A file where each line is a json converted dictionary of flight setting inputs to run a single trajectory simulation;\n", - "- `dispersion_output_file`: A file where each line is a json converted dictionary containing the main outputs of a single simulation, such as apogee altitute and maximum velocity;\n", - "- `dispersion_error_file`: A file to store the inputs of simulations which raised errors. This can help us debug these simulations later on." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "1eC2p3jEpOQO" - }, - "outputs": [], - "source": [ - "def export_flight_data(flight_setting, flight_data, exec_time):\n", - " # Generate flight results\n", - " flight_result = {\n", - " \"out_of_rail_time\": flight_data.out_of_rail_time,\n", - " \"outOfRailVelocity\": flight_data.outOfRailVelocity,\n", - " \"apogeeTime\": flight_data.apogeeTime,\n", - " \"apogeeAltitude\": flight_data.apogee - env.elevation,\n", - " \"apogeeX\": flight_data.apogeeX,\n", - " \"apogeeY\": flight_data.apogeeY,\n", - " \"impactTime\": flight_data.tFinal,\n", - " \"impactX\": flight_data.xImpact,\n", - " \"impactY\": flight_data.yImpact,\n", - " \"impactVelocity\": flight_data.impactVelocity,\n", - " \"initialStaticMargin\": flight_data.rocket.static_margin(0),\n", - " \"outOfRailStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.out_of_rail_time\n", - " ),\n", - " \"finalStaticMargin\": flight_data.rocket.static_margin(\n", - " test_flight.rocket.motor.burn_out_time\n", - " ),\n", - " \"numberOfEvents\": len(flight_data.parachute_events),\n", - " \"executionTime\": exec_time,\n", - " }\n", - "\n", - " # Calculate maximum reached velocity\n", - " sol = np.array(flight_data.solution)\n", - " flight_data.vx = Function(\n", - " sol[:, [0, 4]], \"Time (s)\", \"Vx (m/s)\", \"linear\", extrapolation=\"natural\"\n", - " )\n", - " flight_data.vy = Function(\n", - " sol[:, [0, 5]], \"Time (s)\", \"Vy (m/s)\", \"linear\", extrapolation=\"natural\"\n", - " )\n", - " flight_data.vz = Function(\n", - " sol[:, [0, 6]], \"Time (s)\", \"Vz (m/s)\", \"linear\", extrapolation=\"natural\"\n", - " )\n", - " flight_data.v = (\n", - " flight_data.vx**2 + flight_data.vy**2 + flight_data.vz**2\n", - " ) ** 0.5\n", - " flight_data.maxVel = np.amax(flight_data.v.source[:, 1])\n", - " flight_result[\"maxVelocity\"] = flight_data.maxVel\n", - "\n", - " # Take care of parachute results\n", - " if len(flight_data.parachute_events) > 0:\n", - " flight_result[\"drogue_triggerTime\"] = flight_data.parachute_events[0][0]\n", - " flight_result[\"drogueInflatedTime\"] = (\n", - " flight_data.parachute_events[0][0] + flight_data.parachute_events[0][1].lag\n", - " )\n", - " flight_result[\"drogueInflatedVelocity\"] = flight_data.v(\n", - " flight_data.parachute_events[0][0] + flight_data.parachute_events[0][1].lag\n", - " )\n", - " else:\n", - " flight_result[\"drogue_triggerTime\"] = 0\n", - " flight_result[\"drogueInflatedTime\"] = 0\n", - " flight_result[\"drogueInflatedVelocity\"] = 0\n", - "\n", - " # Write flight setting and results to file\n", - " dispersion_input_file.write(str(flight_setting) + \"\\n\")\n", - " dispersion_output_file.write(str(flight_result) + \"\\n\")\n", - "\n", - "\n", - "def export_flight_error(flight_setting):\n", - " dispersion_error_file.write(str(flight_setting) + \"\\n\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "GX6pB4Y7pOQQ" - }, - "source": [ - "## Simulating Each Flight Setting\n", - "\n", - "Finally, we can start running some simulations!\n", - "\n", - "We start by defining the file name we want to use. Then, we specifiy how many simulations we would like to run by setting the `number_of_simulations` variable.\n", - "\n", - "It is good practice to run something in the order of 100 simulations first, to check for any possible errors in the code. Once we are confident that everything is working well, we increase the number of simulations to something in the range of 5000 to 50000.\n", - "\n", - "We will loop throught all flight settings, creating the environment, rocket and motor classes with the data of the analysis parameters.\n", - "For the power off and on drag and thrust curve user should have in hands the .csv (or .eng for comercial motor's thrust curve).\n", - "\n", - "**Tip**: A better practice is openning the files in \"append\" mode, this way we can acumulate our simulations. To do this, just change the 'a' (write) argument of the `open` function in the third, fourth and fifth line of code to `a` (append)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - }, - "id": "GILiaO30pOQS", - "outputId": "5a2ae15d-5c16-4ae0-f28b-165730d2419d" - }, - "outputs": [], - "source": [ - "# Basic analysis info\n", - "filename = \"dispersion_analysis_outputs/parachute_drop_from_helicopter\"\n", - "number_of_simulations = 4000\n", - "\n", - "# Create data files for inputs, outputs and error logging\n", - "dispersion_error_file = open(str(filename) + \".disp_errors.txt\", \"w\")\n", - "dispersion_input_file = open(str(filename) + \".disp_inputs.txt\", \"w\")\n", - "dispersion_output_file = open(str(filename) + \".disp_outputs.txt\", \"w\")\n", - "\n", - "# Initialize counter and timer\n", - "i = 0\n", - "\n", - "initial_wall_time = time()\n", - "initial_cpu_time = process_time()\n", - "\n", - "# Define basic Environment object\n", - "env = Environment(date=(2019, 8, 10, 21), latitude=-23.363611, longitude=-48.011389)\n", - "env.setElevation(668)\n", - "env.maxExpectedHeight = 1500\n", - "env.set_atmospheric_model(\n", - " type=\"Ensemble\",\n", - " file=\"dispersion_analysis_inputs/LASC2019_reanalysis.nc\",\n", - " dictionary=\"ECMWF\",\n", - ")\n", - "\n", - "\n", - "# Set up parachutes. This rocket, named Valetudo, only has a drogue chute.\n", - "def drogue_trigger(p, h, y):\n", - " # Check if rocket is going down, i.e. if it has passed the apogee\n", - " vertical_velocity = y[5]\n", - " # Return true to activate parachute once the vertical velocity is negative\n", - " return True if vertical_velocity < 0 else False\n", - "\n", - "\n", - "# Iterate over flight settings\n", - "out = display(\"Starting\", display_id=True)\n", - "for setting in flight_settings(analysis_parameters, number_of_simulations):\n", - " start_time = process_time()\n", - " i += 1\n", - "\n", - " # Update environment object\n", - " env.selectEnsembleMember(setting[\"ensembleMember\"])\n", - "\n", - " # Create motor\n", - " Keron = SolidMotor(\n", - " thrust_source=\"dispersion_analysis_inputs/thrustCurve.csv\",\n", - " burn_time=5.274,\n", - " reshape_thrust_curve=(setting[\"burn_time\"], setting[\"impulse\"]),\n", - " nozzle_radius=setting[\"nozzle_radius\"],\n", - " throat_radius=setting[\"throat_radius\"],\n", - " grains_center_of_mass_position=setting[\"distanceRocketPropellant\"],\n", - " grain_number=6,\n", - " grain_separation=setting[\"grain_separation\"],\n", - " grain_density=setting[\"grain_density\"],\n", - " grain_outer_radius=setting[\"grain_outer_radius\"],\n", - " grain_initial_inner_radius=setting[\"grain_initial_inner_radius\"],\n", - " grain_initial_height=setting[\"grain_initial_height\"],\n", - " interpolation_method=\"linear\",\n", - " nozzle_position=setting[\"distance_rocket_nozzle\"],\n", - " coordinate_system_orientation=\"nozzle_to_combustion_chamber\",\n", - " )\n", - "\n", - " # Create rocket\n", - " Valetudo = Rocket(\n", - " radius=setting[\"radius\"],\n", - " mass=setting[\"rocket_mass\"],\n", - " inertia_i=setting[\"inertia_i\"],\n", - " inertia_z=setting[\"inertia_z\"],\n", - " power_off_drag=\"dispersion_analysis_inputs/Cd_PowerOff.csv\",\n", - " power_on_drag=\"dispersion_analysis_inputs/Cd_PowerOn.csv\",\n", - " center_of_dry_mass_position=0,\n", - " coordinate_system_orientation=\"tail_to_nose\",\n", - " )\n", - " Valetudo.set_rail_buttons(0.224, -0.93, 30)\n", - "\n", - " Valetudo.add_motor(Keron, position=setting[\"distance_rocket_nozzle\"])\n", - "\n", - " # Edit rocket drag\n", - " Valetudo.power_off_drag *= setting[\"power_off_drag\"]\n", - " Valetudo.power_on_drag *= setting[\"power_on_drag\"]\n", - " # Add rocket nose, fins and tail\n", - " NoseCone = Valetudo.add_nose(\n", - " length=setting[\"nose_length\"],\n", - " kind=\"vonKarman\",\n", - " position=setting[\"noseDistanceToCM\"] + setting[\"nose_length\"],\n", - " )\n", - " fin_set = Valetudo.add_trapezoidal_fins(\n", - " n=3,\n", - " span=setting[\"finSpan\"],\n", - " root_chord=setting[\"finRootChord\"],\n", - " tip_chord=setting[\"finTipChord\"],\n", - " position=setting[\"finDistanceToCM\"],\n", - " cant_angle=0,\n", - " airfoil=None,\n", - " )\n", - " # Add parachute\n", - " Drogue = Valetudo.add_parachute(\n", - " \"Drogue\",\n", - " cd_s=setting[\"CdSDrogue\"],\n", - " trigger=drogue_trigger,\n", - " sampling_rate=105,\n", - " lag=setting[\"lag_rec\"] + setting[\"lag_se\"],\n", - " noise=(0, 8.3, 0.5),\n", - " )\n", - "\n", - " # Run trajectory simulation\n", - " try:\n", - " test_flight = Flight(\n", - " rocket=Valetudo,\n", - " environment=env,\n", - " rail_length=setting[\"rail_length\"],\n", - " inclination=setting[\"inclination\"],\n", - " heading=setting[\"heading\"],\n", - " maxTime=600,\n", - " initialSolution=[\n", - " 0.0,\n", - " 0.0,\n", - " 0.0,\n", - " 800 + env.elevation,\n", - " 10.0,\n", - " 10.0,\n", - " 1.0,\n", - " 1.0,\n", - " 0.0,\n", - " 0.0,\n", - " 0.0,\n", - " 0.0,\n", - " 0.0,\n", - " 0.0,\n", - " ],\n", - " )\n", - " export_flight_data(setting, test_flight, process_time() - start_time)\n", - " except Exception as E:\n", - " print(E)\n", - " export_flight_error(setting)\n", - "\n", - " # Register time\n", - " out.update(\n", - " f\"Curent iteration: {i:06d} | Average Time per Iteration: {(process_time() - initial_cpu_time)/i:2.6f} s\"\n", - " )\n", - "\n", - "# Done\n", - "\n", - "## Print and save total time\n", - "final_string = f\"Completed {i} iterations successfully. Total CPU time: {process_time() - initial_cpu_time} s. Total wall time: {time() - initial_wall_time} s\"\n", - "out.update(final_string)\n", - "dispersion_input_file.write(final_string + \"\\n\")\n", - "dispersion_output_file.write(final_string + \"\\n\")\n", - "dispersion_error_file.write(final_string + \"\\n\")\n", - "\n", - "## Close files\n", - "dispersion_input_file.close()\n", - "dispersion_output_file.close()\n", - "dispersion_error_file.close()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Post-processing Monte Carlo Dispersion Results\n", - "\n", - "Now that we have finish running thousands of simulations, it is time to process the results and get some nice graphs out of them! " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "X8ewOccUpOQb" - }, - "source": [ - "## Importing Dispersion Analysis Saved Data\n", - "\n", - "We start by loading the file which stores the outputs." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "-7qgTJzRpOQb", - "outputId": "76d2cecd-a09f-429f-cca2-f4e03e39d49e" - }, - "outputs": [], - "source": [ - "filename = \"dispersion_analysis_outputs/parachute_drop_from_helicopter\"\n", - "\n", - "# Initialize variable to store all results\n", - "dispersion_general_results = []\n", - "\n", - "dispersion_results = {\n", - " \"out_of_rail_time\": [],\n", - " \"outOfRailVelocity\": [],\n", - " \"apogeeTime\": [],\n", - " \"apogeeAltitude\": [],\n", - " \"apogeeX\": [],\n", - " \"apogeeY\": [],\n", - " \"impactTime\": [],\n", - " \"impactX\": [],\n", - " \"impactY\": [],\n", - " \"impactVelocity\": [],\n", - " \"initialStaticMargin\": [],\n", - " \"outOfRailStaticMargin\": [],\n", - " \"finalStaticMargin\": [],\n", - " \"numberOfEvents\": [],\n", - " \"maxVelocity\": [],\n", - " \"drogue_triggerTime\": [],\n", - " \"drogueInflatedTime\": [],\n", - " \"drogueInflatedVelocity\": [],\n", - " \"executionTime\": [],\n", - "}\n", - "\n", - "# Get all dispersion results\n", - "# Get file\n", - "dispersion_output_file = open(str(filename) + \".disp_outputs.txt\", \"r+\")\n", - "\n", - "# Read each line of the file and convert to dict\n", - "for line in dispersion_output_file:\n", - " # Skip comments lines\n", - " if line[0] != \"{\":\n", - " continue\n", - " # Eval results and store them\n", - " flight_result = eval(line)\n", - " dispersion_general_results.append(flight_result)\n", - " for parameter_key, parameter_value in flight_result.items():\n", - " dispersion_results[parameter_key].append(parameter_value)\n", - "\n", - "# Close data file\n", - "dispersion_output_file.close()\n", - "\n", - "# Print number of flights simulated\n", - "N = len(dispersion_general_results)\n", - "print(\"Number of simulations: \", N)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "ioeUkzPipOQe" - }, - "source": [ - "## Dispersion Results\n", - "\n", - "Now, we plot the histogram for every single output. This shows how are outputs behave. Valuable statistical data can be calculated based on them." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "tExJzLhDpOQp" - }, - "source": [ - "### Apogee Time" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "l8zjT_VjpOQq", - "outputId": "1c15fe12-afae-4035-f085-7d82e61d24d9" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee Time - Mean Value: {np.mean(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Apogee Time - Standard Deviation: {np.std(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeTime\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "erNB46vApOQt" - }, - "source": [ - "### Apogee Altitude" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "gWWMoOClpOQv", - "outputId": "88f2cf05-142c-4bb1-ce64-9879696107a7" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee Altitude - Mean Value: {np.mean(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Apogee Altitude - Standard Deviation: {np.std(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeAltitude\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee Altitude\")\n", - "plt.xlabel(\"Altitude (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()\n", - "\n", - "# Real measured apogee for Valetudo = 860 m" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "7bBvFJ5xpOQ1" - }, - "source": [ - "### Apogee X Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "nGdsF9VppOQ3", - "outputId": "b4f0a3aa-afa1-4942-91b8-8ad61d263244" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee X Position - Mean Value: {np.mean(dispersion_results[\"apogeeX\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Apogee X Position - Standard Deviation: {np.std(dispersion_results[\"apogeeX\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeX\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee X Position\")\n", - "plt.xlabel(\"Apogee X Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "-LtYxB0lpOQ8" - }, - "source": [ - "### Apogee Y Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "ocq6GmeNpOQ8", - "outputId": "f3a45339-c0a6-4819-bd03-60f7fe6df963" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Apogee Y Position - Mean Value: {np.mean(dispersion_results[\"apogeeY\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Apogee Y Position - Standard Deviation: {np.std(dispersion_results[\"apogeeY\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"apogeeY\"], bins=int(N**0.5))\n", - "plt.title(\"Apogee Y Position\")\n", - "plt.xlabel(\"Apogee Y Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "ifuJX7jYpORB" - }, - "source": [ - "### Impact Time" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "52j6t5-MpORB", - "outputId": "9cba31b1-c731-402f-b138-df5c72521408" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact Time - Mean Value: {np.mean(dispersion_results[\"impactTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Impact Time - Standard Deviation: {np.std(dispersion_results[\"impactTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactTime\"], bins=int(N**0.5))\n", - "plt.title(\"Impact Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "mYD4EQ5spORE" - }, - "source": [ - "### Impact X Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "uzL8-1UGpORF", - "outputId": "5c74f8d1-b909-44cf-a5c9-2f1b5e9dda1d" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact X Position - Mean Value: {np.mean(dispersion_results[\"impactX\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Impact X Position - Standard Deviation: {np.std(dispersion_results[\"impactX\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactX\"], bins=int(N**0.5))\n", - "plt.title(\"Impact X Position\")\n", - "plt.xlabel(\"Impact X Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "ajI4vr7QpORL" - }, - "source": [ - "### Impact Y Position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "Q-ghmNVopORM", - "outputId": "cd0c81a8-a3fc-4710-cadf-a20cf0882bec" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact Y Position - Mean Value: {np.mean(dispersion_results[\"impactY\"]):0.3f} m'\n", - ")\n", - "print(\n", - " f'Impact Y Position - Standard Deviation: {np.std(dispersion_results[\"impactY\"]):0.3f} m'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactY\"], bins=int(N**0.5))\n", - "plt.title(\"Impact Y Position\")\n", - "plt.xlabel(\"Impact Y Position (m)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "H7_H_eeXpORP" - }, - "source": [ - "### Impact Velocity" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "Ryx7KEEVpORP", - "outputId": "90cdcf97-affc-4f09-ed2a-9b854257a8a0" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Impact Velocity - Mean Value: {np.mean(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", - ")\n", - "print(\n", - " f'Impact Velocity - Standard Deviation: {np.std(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"impactVelocity\"], bins=int(N**0.5))\n", - "plt.title(\"Impact Velocity\")\n", - "# plt.grid()\n", - "plt.xlim(-35, 0)\n", - "plt.xlabel(\"Velocity (m/s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "mQzQELcJpORX" - }, - "source": [ - "### Maximum Velocity" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "nOu1O8MXpORY", - "outputId": "7510aec8-7b73-4751-f033-8367cd0c9bdc" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Maximum Velocity - Mean Value: {np.mean(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", - ")\n", - "print(\n", - " f'Maximum Velocity - Standard Deviation: {np.std(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"maxVelocity\"], bins=int(N**0.5))\n", - "plt.title(\"Maximum Velocity\")\n", - "plt.xlabel(\"Velocity (m/s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "-7qgTJzRpOQb", + "outputId": "76d2cecd-a09f-429f-cca2-f4e03e39d49e" + }, + "outputs": [], + "source": [ + "filename = \"dispersion_analysis_outputs/parachute_drop_from_helicopter\"\n", + "\n", + "# Initialize variable to store all results\n", + "dispersion_general_results = []\n", + "\n", + "dispersion_results = {\n", + " \"outOfRailTime\": [],\n", + " \"outOfRailVelocity\": [],\n", + " \"apogeeTime\": [],\n", + " \"apogeeAltitude\": [],\n", + " \"apogeeX\": [],\n", + " \"apogeeY\": [],\n", + " \"impactTime\": [],\n", + " \"impactX\": [],\n", + " \"impactY\": [],\n", + " \"impactVelocity\": [],\n", + " \"initialStaticMargin\": [],\n", + " \"outOfRailStaticMargin\": [],\n", + " \"finalStaticMargin\": [],\n", + " \"numberOfEvents\": [],\n", + " \"maxVelocity\": [],\n", + " \"drogueTriggerTime\": [],\n", + " \"drogueInflatedTime\": [],\n", + " \"drogueInflatedVelocity\": [],\n", + " \"executionTime\": [],\n", + "}\n", + "\n", + "# Get all dispersion results\n", + "# Get file\n", + "dispersion_output_file = open(str(filename) + \".disp_outputs.txt\", \"r+\")\n", + "\n", + "# Read each line of the file and convert to dict\n", + "for line in dispersion_output_file:\n", + " # Skip comments lines\n", + " if line[0] != \"{\":\n", + " continue\n", + " # Eval results and store them\n", + " flight_result = eval(line)\n", + " dispersion_general_results.append(flight_result)\n", + " for parameter_key, parameter_value in flight_result.items():\n", + " dispersion_results[parameter_key].append(parameter_value)\n", + "\n", + "# Close data file\n", + "dispersion_output_file.close()\n", + "\n", + "# Print number of flights simulated\n", + "N = len(dispersion_general_results)\n", + "print(\"Number of simulations: \", N)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ioeUkzPipOQe" + }, + "source": [ + "## Dispersion Results\n", + "\n", + "Now, we plot the histogram for every single output. This shows how are outputs behave. Valuable statistical data can be calculated based on them." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "tExJzLhDpOQp" + }, + "source": [ + "### Apogee Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "7MUVLAM-pORb" - }, - "source": [ - "### Number of Parachute Events\n", - "\n", - "This is usefull to check if the parachute was triggered in every flight." - ] + "id": "l8zjT_VjpOQq", + "outputId": "1c15fe12-afae-4035-f085-7d82e61d24d9" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee Time - Mean Value: {np.mean(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Apogee Time - Standard Deviation: {np.std(dispersion_results[\"apogeeTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeTime\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "erNB46vApOQt" + }, + "source": [ + "### Apogee Altitude" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "yhcWi2kCpORb", - "outputId": "dee54569-8213-46cc-e287-9fffd2b8e43c" - }, - "outputs": [], - "source": [ - "plt.figure()\n", - "plt.hist(dispersion_results[\"numberOfEvents\"])\n", - "plt.title(\"Parachute Events\")\n", - "plt.xlabel(\"Number of Parachute Events\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "gWWMoOClpOQv", + "outputId": "88f2cf05-142c-4bb1-ce64-9879696107a7" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee Altitude - Mean Value: {np.mean(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Apogee Altitude - Standard Deviation: {np.std(dispersion_results[\"apogeeAltitude\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeAltitude\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee Altitude\")\n", + "plt.xlabel(\"Altitude (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n", + "\n", + "# Real measured apogee for Valetudo = 860 m\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "7bBvFJ5xpOQ1" + }, + "source": [ + "### Apogee X Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "4LpDYGpfpORf" - }, - "source": [ - "### Drogue Parachute Trigger Time" - ] + "id": "nGdsF9VppOQ3", + "outputId": "b4f0a3aa-afa1-4942-91b8-8ad61d263244" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee X Position - Mean Value: {np.mean(dispersion_results[\"apogeeX\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Apogee X Position - Standard Deviation: {np.std(dispersion_results[\"apogeeX\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeX\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee X Position\")\n", + "plt.xlabel(\"Apogee X Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "-LtYxB0lpOQ8" + }, + "source": [ + "### Apogee Y Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "lvCksZG8pORf", - "outputId": "3efd19ed-11e9-41d1-8e66-04da384665ce" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Drogue Parachute Trigger Time - Mean Value: {np.mean(dispersion_results[\"drogue_triggerTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Drogue Parachute Trigger Time - Standard Deviation: {np.std(dispersion_results[\"drogue_triggerTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"drogue_triggerTime\"], bins=int(N**0.5))\n", - "plt.title(\"Drogue Parachute Trigger Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "ocq6GmeNpOQ8", + "outputId": "f3a45339-c0a6-4819-bd03-60f7fe6df963" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Apogee Y Position - Mean Value: {np.mean(dispersion_results[\"apogeeY\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Apogee Y Position - Standard Deviation: {np.std(dispersion_results[\"apogeeY\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"apogeeY\"], bins=int(N**0.5))\n", + "plt.title(\"Apogee Y Position\")\n", + "plt.xlabel(\"Apogee Y Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ifuJX7jYpORB" + }, + "source": [ + "### Impact Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "nKSzDWi7pORi" - }, - "source": [ - "### Drogue Parachute Fully Inflated Time" - ] + "id": "52j6t5-MpORB", + "outputId": "9cba31b1-c731-402f-b138-df5c72521408" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact Time - Mean Value: {np.mean(dispersion_results[\"impactTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Impact Time - Standard Deviation: {np.std(dispersion_results[\"impactTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactTime\"], bins=int(N**0.5))\n", + "plt.title(\"Impact Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "mYD4EQ5spORE" + }, + "source": [ + "### Impact X Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "KCYKVFYXpORj", - "outputId": "8ae49853-0f08-4bf6-9bd8-91a7c9a9448d" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Drogue Parachute Fully Inflated Time - Mean Value: {np.mean(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", - ")\n", - "print(\n", - " f'Drogue Parachute Fully Inflated Time - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"drogueInflatedTime\"], bins=int(N**0.5))\n", - "plt.title(\"Drogue Parachute Fully Inflated Time\")\n", - "plt.xlabel(\"Time (s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "uzL8-1UGpORF", + "outputId": "5c74f8d1-b909-44cf-a5c9-2f1b5e9dda1d" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact X Position - Mean Value: {np.mean(dispersion_results[\"impactX\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Impact X Position - Standard Deviation: {np.std(dispersion_results[\"impactX\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactX\"], bins=int(N**0.5))\n", + "plt.title(\"Impact X Position\")\n", + "plt.xlabel(\"Impact X Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ajI4vr7QpORL" + }, + "source": [ + "### Impact Y Position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "BvMCGZYHpORn" - }, - "source": [ - "### Drogue Parachute Fully Inflated Velocity" - ] + "id": "Q-ghmNVopORM", + "outputId": "cd0c81a8-a3fc-4710-cadf-a20cf0882bec" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact Y Position - Mean Value: {np.mean(dispersion_results[\"impactY\"]):0.3f} m'\n", + ")\n", + "print(\n", + " f'Impact Y Position - Standard Deviation: {np.std(dispersion_results[\"impactY\"]):0.3f} m'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactY\"], bins=int(N**0.5))\n", + "plt.title(\"Impact Y Position\")\n", + "plt.xlabel(\"Impact Y Position (m)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "H7_H_eeXpORP" + }, + "source": [ + "### Impact Velocity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 607 - }, - "id": "KxrpPUzqpORn", - "outputId": "9c102bdb-b805-4aa1-b3a2-1ac329c76976" - }, - "outputs": [], - "source": [ - "print(\n", - " f'Drogue Parachute Fully Inflated Velocity - Mean Value: {np.mean(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", - ")\n", - "print(\n", - " f'Drogue Parachute Fully Inflated Velocity - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", - ")\n", - "\n", - "plt.figure()\n", - "plt.hist(dispersion_results[\"drogueInflatedVelocity\"], bins=int(N**0.5))\n", - "plt.title(\"Drogue Parachute Fully Inflated Velocity\")\n", - "plt.xlabel(\"Velocity m/s)\")\n", - "plt.ylabel(\"Number of Occurences\")\n", - "plt.show()" - ] + "id": "Ryx7KEEVpORP", + "outputId": "90cdcf97-affc-4f09-ed2a-9b854257a8a0" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Impact Velocity - Mean Value: {np.mean(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", + ")\n", + "print(\n", + " f'Impact Velocity - Standard Deviation: {np.std(dispersion_results[\"impactVelocity\"]):0.3f} m/s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"impactVelocity\"], bins=int(N**0.5))\n", + "plt.title(\"Impact Velocity\")\n", + "# plt.grid()\n", + "plt.xlim(-35, 0)\n", + "plt.xlabel(\"Velocity (m/s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "mQzQELcJpORX" + }, + "source": [ + "### Maximum Velocity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "TlWXtnKMrlMI" - }, - "source": [ - "### Error Ellipses\n" - ] + "id": "nOu1O8MXpORY", + "outputId": "7510aec8-7b73-4751-f033-8367cd0c9bdc" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Maximum Velocity - Mean Value: {np.mean(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", + ")\n", + "print(\n", + " f'Maximum Velocity - Standard Deviation: {np.std(dispersion_results[\"maxVelocity\"]):0.3f} m/s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"maxVelocity\"], bins=int(N**0.5))\n", + "plt.title(\"Maximum Velocity\")\n", + "plt.xlabel(\"Velocity (m/s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "7MUVLAM-pORb" + }, + "source": [ + "### Number of Parachute Events\n", + "\n", + "This is usefull to check if the parachute was triggered in every flight." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "cellView": "both", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 837 - }, - "id": "DZRrk_bIr3iG", - "outputId": "b4a5a583-7f53-473a-bec2-2636cdf28a7c" - }, - "outputs": [], - "source": [ - "# Import libraries\n", - "from imageio import imread\n", - "from matplotlib.patches import Ellipse\n", - "\n", - "# Import background map\n", - "img = imread(\"dispersion_analysis_inputs/Valetudo_basemap_final.jpg\")\n", - "\n", - "# Retrieve dispersion data por apogee and impact XY position\n", - "apogeeX = np.array(dispersion_results[\"apogeeX\"])\n", - "apogeeY = np.array(dispersion_results[\"apogeeY\"])\n", - "impactX = np.array(dispersion_results[\"impactX\"])\n", - "impactY = np.array(dispersion_results[\"impactY\"])\n", - "\n", - "\n", - "# Define function to calculate eigen values\n", - "def eigsorted(cov):\n", - " vals, vecs = np.linalg.eigh(cov)\n", - " order = vals.argsort()[::-1]\n", - " return vals[order], vecs[:, order]\n", - "\n", - "\n", - "# Create plot figure\n", - "plt.figure(num=None, figsize=(8, 6), dpi=150, facecolor=\"w\", edgecolor=\"k\")\n", - "ax = plt.subplot(111)\n", - "\n", - "# Calculate error ellipses for impact\n", - "impactCov = np.cov(impactX, impactY)\n", - "impactVals, impactVecs = eigsorted(impactCov)\n", - "impactTheta = np.degrees(np.arctan2(*impactVecs[:, 0][::-1]))\n", - "impactW, impactH = 2 * np.sqrt(impactVals)\n", - "\n", - "# Draw error ellipses for impact\n", - "impact_ellipses = []\n", - "for j in [1, 2, 3]:\n", - " impactEll = Ellipse(\n", - " xy=(np.mean(impactX), np.mean(impactY)),\n", - " width=impactW * j,\n", - " height=impactH * j,\n", - " angle=impactTheta,\n", - " color=\"black\",\n", - " )\n", - " impactEll.set_facecolor((0, 0, 1, 0.2))\n", - " impact_ellipses.append(impactEll)\n", - " ax.add_artist(impactEll)\n", - "\n", - "# Calculate error ellipses for apogee\n", - "apogeeCov = np.cov(apogeeX, apogeeY)\n", - "apogeeVals, apogeeVecs = eigsorted(apogeeCov)\n", - "apogeeTheta = np.degrees(np.arctan2(*apogeeVecs[:, 0][::-1]))\n", - "apogeeW, apogeeH = 2 * np.sqrt(apogeeVals)\n", - "\n", - "# Draw error ellipses for apogee\n", - "for j in [1, 2, 3]:\n", - " apogeeEll = Ellipse(\n", - " xy=(np.mean(apogeeX), np.mean(apogeeY)),\n", - " width=apogeeW * j,\n", - " height=apogeeH * j,\n", - " angle=apogeeTheta,\n", - " color=\"black\",\n", - " )\n", - " apogeeEll.set_facecolor((0, 1, 0, 0.2))\n", - " ax.add_artist(apogeeEll)\n", - "\n", - "# Draw launch point\n", - "plt.scatter(0, 0, s=30, marker=\"*\", color=\"black\", label=\"Launch Point\")\n", - "# Draw apogee points\n", - "plt.scatter(apogeeX, apogeeY, s=5, marker=\"^\", color=\"green\", label=\"Simulated Apogee\")\n", - "# Draw impact points\n", - "plt.scatter(\n", - " impactX, impactY, s=5, marker=\"v\", color=\"blue\", label=\"Simulated Landing Point\"\n", - ")\n", - "\n", - "plt.legend()\n", - "\n", - "# Add title and labels to plot\n", - "ax.set_title(\n", - " \"1$\\sigma$, 2$\\sigma$ and 3$\\sigma$ Dispersion Ellipses: Apogee and Lading Points\"\n", - ")\n", - "ax.set_ylabel(\"North (m)\")\n", - "ax.set_xlabel(\"East (m)\")\n", - "\n", - "# Add background image to plot\n", - "# You can translate the basemap by changing dx and dy (in meters)\n", - "dx = 0\n", - "dy = 0\n", - "plt.imshow(img, zorder=0, extent=[-1000 - dx, 1000 - dx, -1000 - dy, 1000 - dy])\n", - "plt.axhline(0, color=\"black\", linewidth=0.5)\n", - "plt.axvline(0, color=\"black\", linewidth=0.5)\n", - "plt.xlim(100, 400)\n", - "plt.ylim(-200, 50)\n", - "\n", - "# Save plot and show result\n", - "plt.savefig(str(filename) + \".pdf\", bbox_inches=\"tight\", pad_inches=0)\n", - "plt.savefig(str(filename) + \".svg\", bbox_inches=\"tight\", pad_inches=0)\n", - "plt.show()" - ] + "id": "yhcWi2kCpORb", + "outputId": "dee54569-8213-46cc-e287-9fffd2b8e43c" + }, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.hist(dispersion_results[\"numberOfEvents\"])\n", + "plt.title(\"Parachute Events\")\n", + "plt.xlabel(\"Number of Parachute Events\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "4LpDYGpfpORf" + }, + "source": [ + "### Drogue Parachute Trigger Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { + "id": "lvCksZG8pORf", + "outputId": "3efd19ed-11e9-41d1-8e66-04da384665ce" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Drogue Parachute Trigger Time - Mean Value: {np.mean(dispersion_results[\"drogueTriggerTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Drogue Parachute Trigger Time - Standard Deviation: {np.std(dispersion_results[\"drogueTriggerTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"drogueTriggerTime\"], bins=int(N**0.5))\n", + "plt.title(\"Drogue Parachute Trigger Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "nKSzDWi7pORi" + }, + "source": [ + "### Drogue Parachute Fully Inflated Time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { "colab": { - "collapsed_sections": [ - "au88RN0P-bVl", - "-9u9RIaqpOQl", - "tExJzLhDpOQp", - "ifuJX7jYpORB", - "mYD4EQ5spORE", - "ajI4vr7QpORL", - "9m19OV9upORS", - "mQzQELcJpORX", - "7MUVLAM-pORb", - "4LpDYGpfpORf", - "nKSzDWi7pORi", - "BvMCGZYHpORn", - "LhPQQlpHpORq", - "5MvfiSQZvwPK" - ], - "name": "Valetudo_Monte_Carlo_Dispersion_Analysis.ipynb", - "provenance": [], - "toc_visible": true + "base_uri": "https://localhost:8080/", + "height": 607 }, - "kernelspec": { - "display_name": "Python 3.10.5 64-bit", - "language": "python", - "name": "python3" + "id": "KCYKVFYXpORj", + "outputId": "8ae49853-0f08-4bf6-9bd8-91a7c9a9448d" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Drogue Parachute Fully Inflated Time - Mean Value: {np.mean(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", + ")\n", + "print(\n", + " f'Drogue Parachute Fully Inflated Time - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedTime\"]):0.3f} s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"drogueInflatedTime\"], bins=int(N**0.5))\n", + "plt.title(\"Drogue Parachute Fully Inflated Time\")\n", + "plt.xlabel(\"Time (s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "BvMCGZYHpORn" + }, + "source": [ + "### Drogue Parachute Fully Inflated Velocity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 607 }, - "language_info": { - "name": "python", - "version": "3.10.5" + "id": "KxrpPUzqpORn", + "outputId": "9c102bdb-b805-4aa1-b3a2-1ac329c76976" + }, + "outputs": [], + "source": [ + "print(\n", + " f'Drogue Parachute Fully Inflated Velocity - Mean Value: {np.mean(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", + ")\n", + "print(\n", + " f'Drogue Parachute Fully Inflated Velocity - Standard Deviation: {np.std(dispersion_results[\"drogueInflatedVelocity\"]):0.3f} m/s'\n", + ")\n", + "\n", + "plt.figure()\n", + "plt.hist(dispersion_results[\"drogueInflatedVelocity\"], bins=int(N**0.5))\n", + "plt.title(\"Drogue Parachute Fully Inflated Velocity\")\n", + "plt.xlabel(\"Velocity m/s)\")\n", + "plt.ylabel(\"Number of Occurences\")\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "TlWXtnKMrlMI" + }, + "source": [ + "### Error Ellipses\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "both", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 837 }, - "vscode": { - "interpreter": { - "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" - } - } + "id": "DZRrk_bIr3iG", + "outputId": "b4a5a583-7f53-473a-bec2-2636cdf28a7c" + }, + "outputs": [], + "source": [ + "# Import libraries\n", + "from imageio import imread\n", + "from matplotlib.patches import Ellipse\n", + "\n", + "# Import background map\n", + "img = imread(\"dispersion_analysis_inputs/Valetudo_basemap_final.jpg\")\n", + "\n", + "# Retrieve dispersion data por apogee and impact XY position\n", + "apogeeX = np.array(dispersion_results[\"apogeeX\"])\n", + "apogeeY = np.array(dispersion_results[\"apogeeY\"])\n", + "impactX = np.array(dispersion_results[\"impactX\"])\n", + "impactY = np.array(dispersion_results[\"impactY\"])\n", + "\n", + "# Define function to calculate eigen values\n", + "def eigsorted(cov):\n", + " vals, vecs = np.linalg.eigh(cov)\n", + " order = vals.argsort()[::-1]\n", + " return vals[order], vecs[:, order]\n", + "\n", + "\n", + "# Create plot figure\n", + "plt.figure(num=None, figsize=(8, 6), dpi=150, facecolor=\"w\", edgecolor=\"k\")\n", + "ax = plt.subplot(111)\n", + "\n", + "# Calculate error ellipses for impact\n", + "impactCov = np.cov(impactX, impactY)\n", + "impactVals, impactVecs = eigsorted(impactCov)\n", + "impactTheta = np.degrees(np.arctan2(*impactVecs[:, 0][::-1]))\n", + "impactW, impactH = 2 * np.sqrt(impactVals)\n", + "\n", + "# Draw error ellipses for impact\n", + "impact_ellipses = []\n", + "for j in [1, 2, 3]:\n", + " impactEll = Ellipse(\n", + " xy=(np.mean(impactX), np.mean(impactY)),\n", + " width=impactW * j,\n", + " height=impactH * j,\n", + " angle=impactTheta,\n", + " color=\"black\",\n", + " )\n", + " impactEll.set_facecolor((0, 0, 1, 0.2))\n", + " impact_ellipses.append(impactEll)\n", + " ax.add_artist(impactEll)\n", + "\n", + "# Calculate error ellipses for apogee\n", + "apogeeCov = np.cov(apogeeX, apogeeY)\n", + "apogeeVals, apogeeVecs = eigsorted(apogeeCov)\n", + "apogeeTheta = np.degrees(np.arctan2(*apogeeVecs[:, 0][::-1]))\n", + "apogeeW, apogeeH = 2 * np.sqrt(apogeeVals)\n", + "\n", + "# Draw error ellipses for apogee\n", + "for j in [1, 2, 3]:\n", + " apogeeEll = Ellipse(\n", + " xy=(np.mean(apogeeX), np.mean(apogeeY)),\n", + " width=apogeeW * j,\n", + " height=apogeeH * j,\n", + " angle=apogeeTheta,\n", + " color=\"black\",\n", + " )\n", + " apogeeEll.set_facecolor((0, 1, 0, 0.2))\n", + " ax.add_artist(apogeeEll)\n", + "\n", + "# Draw launch point\n", + "plt.scatter(0, 0, s=30, marker=\"*\", color=\"black\", label=\"Launch Point\")\n", + "# Draw apogee points\n", + "plt.scatter(apogeeX, apogeeY, s=5, marker=\"^\", color=\"green\", label=\"Simulated Apogee\")\n", + "# Draw impact points\n", + "plt.scatter(\n", + " impactX, impactY, s=5, marker=\"v\", color=\"blue\", label=\"Simulated Landing Point\"\n", + ")\n", + "\n", + "plt.legend()\n", + "\n", + "# Add title and labels to plot\n", + "ax.set_title(\n", + " \"1$\\sigma$, 2$\\sigma$ and 3$\\sigma$ Dispersion Ellipses: Apogee and Lading Points\"\n", + ")\n", + "ax.set_ylabel(\"North (m)\")\n", + "ax.set_xlabel(\"East (m)\")\n", + "\n", + "# Add background image to plot\n", + "# You can translate the basemap by changing dx and dy (in meters)\n", + "dx = 0\n", + "dy = 0\n", + "plt.imshow(img, zorder=0, extent=[-1000 - dx, 1000 - dx, -1000 - dy, 1000 - dy])\n", + "plt.axhline(0, color=\"black\", linewidth=0.5)\n", + "plt.axvline(0, color=\"black\", linewidth=0.5)\n", + "plt.xlim(100, 400)\n", + "plt.ylim(-200, 50)\n", + "\n", + "# Save plot and show result\n", + "plt.savefig(str(filename) + \".pdf\", bbox_inches=\"tight\", pad_inches=0)\n", + "plt.savefig(str(filename) + \".svg\", bbox_inches=\"tight\", pad_inches=0)\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + "au88RN0P-bVl", + "-9u9RIaqpOQl", + "tExJzLhDpOQp", + "ifuJX7jYpORB", + "mYD4EQ5spORE", + "ajI4vr7QpORL", + "9m19OV9upORS", + "mQzQELcJpORX", + "7MUVLAM-pORb", + "4LpDYGpfpORf", + "nKSzDWi7pORi", + "BvMCGZYHpORn", + "LhPQQlpHpORq", + "5MvfiSQZvwPK" + ], + "name": "Valetudo_Monte_Carlo_Dispersion_Analysis.ipynb", + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3.10.5 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.10.5" }, - "nbformat": 4, - "nbformat_minor": 2 + "vscode": { + "interpreter": { + "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 } diff --git a/docs/notebooks/example_liquid.ipynb b/docs/notebooks/example_liquid.ipynb index ef4dba2a2..ce36209c1 100644 --- a/docs/notebooks/example_liquid.ipynb +++ b/docs/notebooks/example_liquid.ipynb @@ -19,7 +19,7 @@ "number of possible errors can be higher than other classes of the library.\n", "\n", "We encourage you to check the documentation of the class.\n", - "In case you have any doubt, please contact us at [rocketpy.org](rocketpy.org)\n" + "In case you have any doubt, please contact us at [rocketpy.org]([rocketpy.org](https://github.com/RocketPy-Team/RocketPy/))\n" ] }, {