diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml
new file mode 100644
index 0000000..b1719dc
--- /dev/null
+++ b/.github/workflows/publish-to-pypi.yml
@@ -0,0 +1,33 @@
+# This workflow will upload a Python Package using Twine when a release is created
+# For more information see: https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
+
+name: Publish New Version to PyPI
+
+on:
+ release:
+ types: [published]
+
+permissions:
+ contents: read
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python
+ uses: actions/setup-python@v3
+ with:
+ python-version: "3.9"
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install build
+ - name: Build package
+ run: python -m build
+ - name: Publish package
+ uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
+ with:
+ user: __token__
+ password: ${{ secrets.PYPI_API_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/test-pytest.yaml b/.github/workflows/test-pytest.yaml
index a76cbc1..d167652 100644
--- a/.github/workflows/test-pytest.yaml
+++ b/.github/workflows/test-pytest.yaml
@@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
- python-version: [3.8, 3.12]
+ python-version: [3.9, 3.12]
env:
OS: ${{ matrix.os }}
PYTHON: ${{ matrix.python-version }}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4a6e122
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+lint: isort black
+
+isort:
+ isort .
+
+black:
+ black .
+
+pylint:
+ pylint rocketserializer/ --output="pylint_report.txt"
+
+tests:
+ pytest
+
+# tests-unit:
+
+# tests-acceptance:
+
+# tests-integration:
+
diff --git a/README.md b/README.md
index 3db3c9f..c6114e4 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,43 @@
+
+
+
+
+[![Documentation Status](https://readthedocs.org/projects/rocketpyalpha/badge/?version=latest)](https://docs.rocketpy.org/en/latest/?badge=latest)
+[![Chat on Discord](https://img.shields.io/discord/765037887016140840?logo=discord)](https://discord.gg/b6xYnNh)
+[![Sponsor RocketPy](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/RocketPy-Team)
+[![Instagram](https://img.shields.io/badge/Instagram-E4405F?style=flat&logo=instagram&logoColor=white)](https://www.instagram.com/rocketpyteam)
+[![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=flat&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/rocketpy)
+
+
+
# Rocket Serializer
-Rocket Serializer is a Python library that provides serialization capabilities
-for OpenRocket files. It allows you to read OpenRocket files using a simple and
-intuitive command line interface.
+`rocketserializer` is a Python library that provides serialization capabilities
+for OpenRocket files. It allows you to read OpenRocket files (.ork) using a
+simple and intuitive command line interface. After serializing the file, you
+can use the data to create your RocketPy simulation.
+
+## Example
+
+
## Installation
-You can install Rocket Serializer using pip:
+You can install `rocketserializer` using pip:
```shell
-pip install rocket-serializer
+pip install rocketserializer
```
## Requirements
### Java
-You need Java to be installed on your system to use Rocket Serializer.
+You need Java to be installed on your system to use `rocketserializer`.
We recommend downloading Java 17, which is required to run OpenRocket-23.09.
https://www.oracle.com/java/technologies/downloads/
@@ -33,77 +54,89 @@ correct java version to run the jar file.
### Python Packages
-Once you download the package `rocket-serializer`, the following dependencies
+Once you download the `rocketserializer` package, the following dependencies
will be automatically installed:
- bs4
-- click
+- click>=8.0.0
- lxml
- numpy
-- orhelper
+- orhelper==0.1.3
- pyyaml
-- rocketpy
-- nbformat
+- rocketpy>=1.1.0
+- nbformat>=5.2.0
## Usage - command line interface
-To use Rocket Serializer, you just need to use the cli option of the library.
-Here's an example:
+The `rocketserializer` package will automatically install 2 command-line-interface (cli)
+options, here's an example:
+
+### Serialization
+
+To create a `parameters.json` file from an OpenRocket file, use the following command:
+
+```bash
+ork2json --filepath your_rocket.ork
+```
+
+Or, for a more verbose output, you can use the following command:
```bash
-rocket-serializer ork2json --filepath path/to/input.ork --output path/to/output
+ork2json --filepath your_rocket.ork --verbose True
```
The options are the following:
- `--filepath`: The .ork file to be serialized.
-- `--output` : Path to the output folder. If not set, the output will be saved in the same folder os the filepath.
-- `--eng` : Path to the engine file. If not set, the library will get the thrust curve from the OpenRocket file.
+- `--output` : Path to the output folder. If not set, the output will be saved in the same folder as the `filepath`.
- `--ork_jar` : Specify the path to the OpenRocket jar file. If not set, the library will try to find the jar file in the current directory.
+- `--encoding` : The encoding of the .ork file. By default, it is set to `utf-8`.
- `--verbose` : If you want to see the progress of the serialization, set this option to True. By default, it is set to False.
+Only the `--filepath` option is mandatory.
+
+### Creating a simulation notebook
+
+```bash
+ork2notebook --filepath your_rocket.ork
+```
+
+The options are pretty much the same as the serialization command!
+
### Limitations
This code won't work for your rocket if it has any of the following features:
-- Your file wasn't saved in English
-- Your file doesn't contain simulation data
-- Your rocket has more than one stage
-- Your rocket has more than one engine
-- Your rocket has more than one nosecone
+- Your .ork file must be saved in English
+- Your .ork file must be saved with at least 1 simulation data
+- Only one single stage is supported
+- Only a single motor is supported
+- Only a single nose cone is supported
-### Deserialization
+## Roadmap
-Still to be done.
+- 2024 June : First public release, start receiving feedback from the community.
-## License
-
-This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
+Before the first public release, we will listen to the community's feedback before defining the roadmap for the next releases.
## Contact
-For any inquiries or feedback, please email us at [rocketpyteam@gmail.com](mailto:rocketpyteam@gmail.com).
If you find any bug or if you want to request new features, please open an issue
on GitHub.
-
-## Contributors
-
-This project is maintained by the RocketPy Team, a group of students and
-software developers from all over the world.. The main contributors to this
-project are:
-
-- Patrick Sampaio Brandão
-- Franz Masatoshi Yuri
-- Guilherme Fernandes Alves
+In case you don't have a GitHub account, you can reach out to us on RocketPy's
+Discord server.
## How to Contribute
The 3 main ways of contributing to this project are:
-1. Reporting bugs and suggesting new features by opening issues on GitHub.
-2. Submitting .ork files that can be used to test the library.
-3. Developing new features and fixing bugs by opening pull requests on GitHub.
-
-## More Information
-
-For more information, please visit the [RocketPy Team GitHub repository](https://github.com/RocketPy-Team/OpenRocketSerializer).
\ No newline at end of file
+1. **Reporting bugs and suggesting new features.**
+ - Use GitHub, preferably, to report bugs and suggest new features.
+ - In case you don't have a GitHub account, you can reach out to us on RocketPy's Discord server
+2. **Sharing .ork files that can be used to test the library.**
+ - If you have a .ork file that is not working with the library, please share it with us.
+ - If you have a .ork file that is working with the library, please share it with us.
+ - If you allow us to use and share your .ork file, we can add it to the test suite.
+3. **Developing new features and fixing bugs thorough pull requests on GitHub.**
+ - If you want to develop new features, you are more than welcome to do so.
+ - Please reach out to the maintainers to discuss the new feature before starting the development.
diff --git a/examples/EPFL--BellaLui--2020/parameters.json b/examples/EPFL--BellaLui--2020/parameters.json
index 90f819a..581e7a9 100644
--- a/examples/EPFL--BellaLui--2020/parameters.json
+++ b/examples/EPFL--BellaLui--2020/parameters.json
@@ -42,7 +42,7 @@
"nozzle_radius": 0.02025,
"position": 2.3379117844381234,
"throat_radius": 0.0135,
- "thrust_source": "examples/EPFL--BellaLui--2020/thrust_source.csv"
+ "thrust_source": "examples\\EPFL--BellaLui--2020\\thrust_source.csv"
},
"nosecones": {
"base_radius": 0.078,
@@ -56,7 +56,7 @@
"rocket": {
"center_of_mass_without_propellant": 1.559,
"coordinate_system_orientation": "nose_to_tail",
- "drag_curve": "examples/EPFL--BellaLui--2020/drag_curve.csv",
+ "drag_curve": "examples\\EPFL--BellaLui--2020\\drag_curve.csv",
"inertia": [
0.096246,
0.096246,
@@ -66,13 +66,17 @@
"radius": 0.078
},
"stored_results": {
+ "burnout_stability_margin": 3.1703,
"flight_time": 92.782,
"ground_hit_velocity": 26.142,
"launch_rod_velocity": 14.728,
"max_acceleration": 122.07,
"max_altitude": 1190.0,
"max_mach": 0.5587,
+ "max_stability_margin": 4.8193,
+ "max_thrust": 1287.5,
"max_velocity": 189.56,
+ "min_stability_margin": 0.85185,
"time_to_apogee": 14.851
},
"tails": {
diff --git a/examples/EPFL--BellaLui--2020/simulation.ipynb b/examples/EPFL--BellaLui--2020/simulation.ipynb
index 1660038..c1f19e3 100644
--- a/examples/EPFL--BellaLui--2020/simulation.ipynb
+++ b/examples/EPFL--BellaLui--2020/simulation.ipynb
@@ -2,18 +2,18 @@
"cells": [
{
"cell_type": "markdown",
- "id": "a3fc4625",
+ "id": "f005eb6a",
"metadata": {},
"source": [
"# RocketPy Simulation\n",
"This notebook was generated using Rocket-Serializer, a RocketPy tool to convert simulation files to RocketPy simulations\n",
- "The notebook was generated using the following parameters file: `examples/EPFL--BellaLui--2020/parameters.json`\n"
+ "The notebook was generated using the following parameters file: `examples\\EPFL--BellaLui--2020\\parameters.json`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "e4523278",
+ "id": "aabca30d",
"metadata": {},
"outputs": [],
"source": [
@@ -23,7 +23,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "aaa54a4f",
+ "id": "8c096d20",
"metadata": {},
"outputs": [],
"source": [
@@ -37,13 +37,14 @@
" RailButtons,\n",
" NoseCone,\n",
" Tail,\n",
+ " Parachute,\n",
")\n",
"import datetime"
]
},
{
"cell_type": "markdown",
- "id": "4ea6e841",
+ "id": "79c66390",
"metadata": {},
"source": [
"## Environment\n"
@@ -52,7 +53,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "872c6900",
+ "id": "68249450",
"metadata": {},
"outputs": [],
"source": [
@@ -63,7 +64,7 @@
},
{
"cell_type": "markdown",
- "id": "fe7a574d",
+ "id": "ea8b72ba",
"metadata": {},
"source": [
"Optionally, you can set the date and atmospheric model\n"
@@ -72,19 +73,19 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "0a2464ab",
+ "id": "8e14bafd",
"metadata": {},
"outputs": [],
"source": [
"tomorrow = datetime.date.today() + datetime.timedelta(days=1)\n",
"env.set_date((tomorrow.year, tomorrow.month, tomorrow.day, 12))\n",
- "env.set_atmospheric_model(type=\"Forecast\", file=\"GFS\")"
+ "# env.set_atmospheric_model(type='Forecast', file='GFS')"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "66270f13",
+ "id": "71f7b50d",
"metadata": {},
"outputs": [],
"source": [
@@ -93,18 +94,17 @@
},
{
"cell_type": "markdown",
- "id": "b32cb965",
+ "id": "aaa2f283",
"metadata": {},
"source": [
"## Motor\n",
- "Currently, only Solid Motors are supported by Rocket-Serializer\n",
- "If you want to use a Liquid or Hybrid motor, please use rocketpy directly.\n"
+ "Currently, only Solid Motors are supported by Rocket-Serializer. If you want to use a Liquid/Hybrid motor, please use rocketpy directly.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "40f12bdb",
+ "id": "55c09700",
"metadata": {},
"outputs": [],
"source": [
@@ -132,7 +132,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "5ddccb7a",
+ "id": "b669f16e",
"metadata": {},
"outputs": [],
"source": [
@@ -141,7 +141,7 @@
},
{
"cell_type": "markdown",
- "id": "2c5dd997",
+ "id": "797d41f0",
"metadata": {},
"source": [
"## Rocket\n",
@@ -151,7 +151,7 @@
},
{
"cell_type": "markdown",
- "id": "bf12dbd5",
+ "id": "79940005",
"metadata": {},
"source": [
"### Nosecones\n"
@@ -160,7 +160,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "33737f2b",
+ "id": "f418e7bc",
"metadata": {},
"outputs": [],
"source": [
@@ -175,7 +175,7 @@
},
{
"cell_type": "markdown",
- "id": "7e34c003",
+ "id": "4114cbf9",
"metadata": {},
"source": [
"### Fins\n",
@@ -185,7 +185,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "45c5d954",
+ "id": "228b4ecf",
"metadata": {},
"outputs": [],
"source": [
@@ -195,7 +195,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "32bc0a35",
+ "id": "e152d86e",
"metadata": {},
"outputs": [],
"source": [
@@ -214,7 +214,7 @@
},
{
"cell_type": "markdown",
- "id": "2c72a736",
+ "id": "5504ae68",
"metadata": {},
"source": [
"### Transitions (Tails)\n",
@@ -224,7 +224,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "2d4dfc7a",
+ "id": "e82433c8",
"metadata": {},
"outputs": [],
"source": [
@@ -234,7 +234,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "118734c1",
+ "id": "032ec2d1",
"metadata": {},
"outputs": [],
"source": [
@@ -247,10 +247,29 @@
")"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "5f7725bb",
+ "metadata": {},
+ "source": [
+ "### Parachutes\n",
+ "As rocketpy allows for multiple parachutes, we will create a dictionary with all the parachutes and then add them to the rocket\n"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
- "id": "40904de8",
+ "id": "f44d9da1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "parachutes = {}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "99bc0d5c",
"metadata": {},
"outputs": [],
"source": [
@@ -267,7 +286,7 @@
},
{
"cell_type": "markdown",
- "id": "d540e3c7",
+ "id": "e3db68a9",
"metadata": {},
"source": [
"### Adding surfaces to the rocket\n",
@@ -277,7 +296,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "9e0f928d",
+ "id": "61eb8c7a",
"metadata": {},
"outputs": [],
"source": [
@@ -289,17 +308,35 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "a26623e7",
+ "id": "b8171b77",
"metadata": {},
"outputs": [],
"source": [
"rocket.add_motor(motor, position=2.3379117844381234)"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "fd38e425",
+ "metadata": {},
+ "source": [
+ "Adding parachutes to the rocket\n"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
- "id": "df404e2c",
+ "id": "0f64b4a1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "rocket.parachutes = list(parachutes.values())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7573e3ab",
"metadata": {},
"outputs": [],
"source": [
@@ -309,7 +346,7 @@
},
{
"cell_type": "markdown",
- "id": "e6784efc",
+ "id": "a1f58326",
"metadata": {},
"source": [
"## Flight\n",
@@ -319,7 +356,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "9a126283",
+ "id": "cc119eea",
"metadata": {},
"outputs": [],
"source": [
@@ -337,12 +374,140 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "35ab0abd",
+ "id": "233d04da",
"metadata": {},
"outputs": [],
"source": [
"flight.all_info()"
]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0e1989a",
+ "metadata": {},
+ "source": [
+ "## Compare Results\n",
+ "We will now compare the results of the simulation with the parameters used to create it. Let's go!\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7a67ce4e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "### OpenRocket vs RocketPy Parameters\n",
+ "time_to_apogee_ork = 14.851\n",
+ "time_to_apogee_rpy = flight.apogee_time\n",
+ "print(f\"Time to apogee (OpenRocket): {time_to_apogee_ork:.3f} s\")\n",
+ "print(f\"Time to apogee (RocketPy): {time_to_apogee_rpy:.3f} s\")\n",
+ "apogee_difference = time_to_apogee_rpy - time_to_apogee_ork\n",
+ "error = abs((apogee_difference) / time_to_apogee_rpy) * 100\n",
+ "print(f\"Time to apogee difference: {error:.3f} %\")\n",
+ "\n",
+ "flight_time_ork = 92.782\n",
+ "flight_time_rpy = flight.t_final\n",
+ "print(f\"Flight time (OpenRocket): {flight_time_ork:.3f} s\")\n",
+ "print(f\"Flight time (RocketPy): {flight_time_rpy:.3f} s\")\n",
+ "flight_time_difference = flight_time_rpy - flight_time_ork\n",
+ "error_flight_time = abs((flight_time_difference) / flight_time_rpy) * 100\n",
+ "print(f\"Flight time difference: {error_flight_time:.3f} %\")\n",
+ "\n",
+ "ground_hit_velocity_ork = 26.142\n",
+ "ground_hit_velocity_rpy = flight.impact_velocity\n",
+ "print(f\"Ground hit velocity (OpenRocket): {ground_hit_velocity_ork:.3f} m/s\")\n",
+ "print(f\"Ground hit velocity (RocketPy): {ground_hit_velocity_rpy:.3f} m/s\")\n",
+ "ground_hit_velocity_difference = ground_hit_velocity_rpy - ground_hit_velocity_ork\n",
+ "error_ground_hit_velocity = (\n",
+ " abs((ground_hit_velocity_difference) / ground_hit_velocity_rpy) * 100\n",
+ ")\n",
+ "print(f\"Ground hit velocity difference: {error_ground_hit_velocity:.3f} %\")\n",
+ "\n",
+ "launch_rod_velocity_ork = 14.728\n",
+ "launch_rod_velocity_rpy = flight.out_of_rail_velocity\n",
+ "print(f\"Launch rod velocity (OpenRocket): {launch_rod_velocity_ork:.3f} m/s\")\n",
+ "print(f\"Launch rod velocity (RocketPy): {launch_rod_velocity_rpy:.3f} m/s\")\n",
+ "launch_rod_velocity_difference = launch_rod_velocity_rpy - launch_rod_velocity_ork\n",
+ "error_launch_rod_velocity = (\n",
+ " abs((launch_rod_velocity_difference) / launch_rod_velocity_rpy) * 100\n",
+ ")\n",
+ "print(f\"Launch rod velocity difference: {error_launch_rod_velocity:.3f} %\")\n",
+ "\n",
+ "max_acceleration_ork = 122.07\n",
+ "max_acceleration_rpy = flight.max_acceleration\n",
+ "print(f\"Max acceleration (OpenRocket): {max_acceleration_ork:.3f} m/s²\")\n",
+ "print(f\"Max acceleration (RocketPy): {max_acceleration_rpy:.3f} m/s²\")\n",
+ "max_acceleration_difference = max_acceleration_rpy - max_acceleration_ork\n",
+ "error_max_acceleration = abs((max_acceleration_difference) / max_acceleration_rpy) * 100\n",
+ "print(f\"Max acceleration difference: {error_max_acceleration:.3f} %\")\n",
+ "\n",
+ "max_altitude_ork = 1190.0\n",
+ "max_altitude_rpy = flight.apogee - flight.env.elevation\n",
+ "print(f\"Max altitude (OpenRocket): {max_altitude_ork:.3f} m\")\n",
+ "print(f\"Max altitude (RocketPy): {max_altitude_rpy:.3f} m\")\n",
+ "max_altitude_difference = max_altitude_rpy - max_altitude_ork\n",
+ "error_max_altitude = abs((max_altitude_difference) / max_altitude_rpy) * 100\n",
+ "print(f\"Max altitude difference: {error_max_altitude:.3f} %\")\n",
+ "\n",
+ "max_mach_ork = 0.5587\n",
+ "max_mach_rpy = flight.max_mach_number\n",
+ "print(f\"Max Mach (OpenRocket): {max_mach_ork:.3f}\")\n",
+ "print(f\"Max Mach (RocketPy): {max_mach_rpy:.3f}\")\n",
+ "max_mach_difference = max_mach_rpy - max_mach_ork\n",
+ "error_max_mach = abs((max_mach_difference) / max_mach_rpy) * 100\n",
+ "print(f\"Max Mach difference: {error_max_mach:.3f} %\")\n",
+ "\n",
+ "max_velocity_ork = 189.56\n",
+ "max_velocity_rpy = flight.max_speed\n",
+ "print(f\"Max velocity (OpenRocket): {max_velocity_ork:.3f} m/s\")\n",
+ "print(f\"Max velocity (RocketPy): {max_velocity_rpy:.3f} m/s\")\n",
+ "max_velocity_difference = max_velocity_rpy - max_velocity_ork\n",
+ "error_max_velocity = abs((max_velocity_difference) / max_velocity_rpy) * 100\n",
+ "print(f\"Max velocity difference: {error_max_velocity:.3f} %\")\n",
+ "\n",
+ "max_thrust_ork = 1287.5\n",
+ "max_thrust_rpy = flight.rocket.motor.thrust.max\n",
+ "print(f\"Max thrust (OpenRocket): {max_thrust_ork:.3f} N\")\n",
+ "print(f\"Max thrust (RocketPy): {max_thrust_rpy:.3f} N\")\n",
+ "max_thrust_difference = max_thrust_rpy - max_thrust_ork\n",
+ "error_max_thrust = abs((max_thrust_difference) / max_thrust_rpy) * 100\n",
+ "print(f\"Max thrust difference: {error_max_thrust:.3f} %\")\n",
+ "\n",
+ "burnout_stability_margin_ork = 3.1703\n",
+ "burnout_stability_margin_rpy = flight.stability_margin(\n",
+ " flight.rocket.motor.burn_out_time\n",
+ ")\n",
+ "print(f\"Burnout stability margin (OpenRocket): {burnout_stability_margin_ork:.3f}\")\n",
+ "print(f\"Burnout stability margin (RocketPy): {burnout_stability_margin_rpy:.3f}\")\n",
+ "burnout_stability_margin_difference = (\n",
+ " burnout_stability_margin_rpy - burnout_stability_margin_ork\n",
+ ")\n",
+ "error_burnout_stability_margin = (\n",
+ " abs((burnout_stability_margin_difference) / burnout_stability_margin_rpy) * 100\n",
+ ")\n",
+ "print(f\"Burnout stability margin difference: {error_burnout_stability_margin:.3f} %\")\n",
+ "\n",
+ "max_stability_margin_ork = 4.8193\n",
+ "max_stability_margin_rpy = flight.max_stability_margin\n",
+ "print(f\"Max stability margin (OpenRocket): {max_stability_margin_ork:.3f}\")\n",
+ "print(f\"Max stability margin (RocketPy): {max_stability_margin_rpy:.3f}\")\n",
+ "max_stability_margin_difference = max_stability_margin_rpy - max_stability_margin_ork\n",
+ "error_max_stability_margin = (\n",
+ " abs((max_stability_margin_difference) / max_stability_margin_rpy) * 100\n",
+ ")\n",
+ "print(f\"Max stability margin difference: {error_max_stability_margin:.3f} %\")\n",
+ "\n",
+ "min_stability_margin_ork = 0.85185\n",
+ "min_stability_margin_rpy = flight.min_stability_margin\n",
+ "print(f\"Min stability margin (OpenRocket): {min_stability_margin_ork:.3f}\")\n",
+ "print(f\"Min stability margin (RocketPy): {min_stability_margin_rpy:.3f}\")\n",
+ "min_stability_margin_difference = min_stability_margin_rpy - min_stability_margin_ork\n",
+ "error_min_stability_margin = (\n",
+ " abs((min_stability_margin_difference) / min_stability_margin_rpy) * 100\n",
+ ")\n",
+ "print(f\"Min stability margin difference: {error_min_stability_margin:.3f} %\")"
+ ]
}
],
"metadata": {},
diff --git a/examples/NDRT--Rocket--2020/parameters.json b/examples/NDRT--Rocket--2020/parameters.json
index 2d34c2b..0a3e057 100644
--- a/examples/NDRT--Rocket--2020/parameters.json
+++ b/examples/NDRT--Rocket--2020/parameters.json
@@ -1,4 +1,5 @@
{
+ "elliptical_fins": {},
"environment": {
"base_pressure": null,
"base_temperature": null,
@@ -84,13 +85,17 @@
"radius": 0.1016
},
"stored_results": {
+ "burnout_stability_margin": 3.7288,
"flight_time": 86.725,
"ground_hit_velocity": 4.7426,
"launch_rod_velocity": 17.993,
"max_acceleration": 67.386,
"max_altitude": 1085.9,
"max_mach": 0.42789,
+ "max_stability_margin": 3.7685,
+ "max_thrust": 1785.0,
"max_velocity": 145.01,
+ "min_stability_margin": 1.2489,
"time_to_apogee": 15.761
},
"tails": {
diff --git a/examples/NDRT--Rocket--2020/simulation.ipynb b/examples/NDRT--Rocket--2020/simulation.ipynb
index f1c2510..cab35f8 100644
--- a/examples/NDRT--Rocket--2020/simulation.ipynb
+++ b/examples/NDRT--Rocket--2020/simulation.ipynb
@@ -2,18 +2,18 @@
"cells": [
{
"cell_type": "markdown",
- "id": "73649456",
+ "id": "8850fad0",
"metadata": {},
"source": [
"# RocketPy Simulation\n",
"This notebook was generated using Rocket-Serializer, a RocketPy tool to convert simulation files to RocketPy simulations\n",
- "The notebook was generated using the following parameters file: `examples/NDRT--Rocket--2020/parameters.json`\n"
+ "The notebook was generated using the following parameters file: `examples\\NDRT--Rocket--2020\\parameters.json`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "4160e107",
+ "id": "7a15d57b",
"metadata": {},
"outputs": [],
"source": [
@@ -23,7 +23,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "f9588fa3",
+ "id": "f81bca53",
"metadata": {},
"outputs": [],
"source": [
@@ -33,16 +33,18 @@
" Rocket,\n",
" Flight,\n",
" TrapezoidalFins,\n",
+ " EllipticalFins,\n",
" RailButtons,\n",
" NoseCone,\n",
" Tail,\n",
+ " Parachute,\n",
")\n",
"import datetime"
]
},
{
"cell_type": "markdown",
- "id": "c8b00a08",
+ "id": "aca90c10",
"metadata": {},
"source": [
"## Environment\n"
@@ -51,7 +53,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "84016cc8",
+ "id": "07414b55",
"metadata": {},
"outputs": [],
"source": [
@@ -62,7 +64,7 @@
},
{
"cell_type": "markdown",
- "id": "e9ba5e6c",
+ "id": "21c300d4",
"metadata": {},
"source": [
"Optionally, you can set the date and atmospheric model\n"
@@ -71,19 +73,19 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "1f1c978f",
+ "id": "e0f983b5",
"metadata": {},
"outputs": [],
"source": [
"tomorrow = datetime.date.today() + datetime.timedelta(days=1)\n",
"env.set_date((tomorrow.year, tomorrow.month, tomorrow.day, 12))\n",
- "env.set_atmospheric_model(type=\"Forecast\", file=\"GFS\")"
+ "# env.set_atmospheric_model(type='Forecast', file='GFS')"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "d2c7c4a8",
+ "id": "91625017",
"metadata": {},
"outputs": [],
"source": [
@@ -92,18 +94,17 @@
},
{
"cell_type": "markdown",
- "id": "e4712496",
+ "id": "32e5b938",
"metadata": {},
"source": [
"## Motor\n",
- "Currently, only Solid Motors are supported by Rocket-Serializer\n",
- "If you want to use a Liquid or Hybrid motor, please use rocketpy directly.\n"
+ "Currently, only Solid Motors are supported by Rocket-Serializer. If you want to use a Liquid/Hybrid motor, please use rocketpy directly.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "7303fe66",
+ "id": "c048ae83",
"metadata": {},
"outputs": [],
"source": [
@@ -131,7 +132,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "1d4de914",
+ "id": "f6c2309e",
"metadata": {},
"outputs": [],
"source": [
@@ -140,7 +141,7 @@
},
{
"cell_type": "markdown",
- "id": "88365a2f",
+ "id": "22e08a67",
"metadata": {},
"source": [
"## Rocket\n",
@@ -150,7 +151,7 @@
},
{
"cell_type": "markdown",
- "id": "16c74786",
+ "id": "a11965e0",
"metadata": {},
"source": [
"### Nosecones\n"
@@ -159,7 +160,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "b027c306",
+ "id": "dd969011",
"metadata": {},
"outputs": [],
"source": [
@@ -174,7 +175,7 @@
},
{
"cell_type": "markdown",
- "id": "6b49767b",
+ "id": "575a49f5",
"metadata": {},
"source": [
"### Fins\n",
@@ -184,7 +185,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "bcdd3f39",
+ "id": "5e389821",
"metadata": {},
"outputs": [],
"source": [
@@ -194,7 +195,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "a7a104cc",
+ "id": "aac765a3",
"metadata": {},
"outputs": [],
"source": [
@@ -213,7 +214,7 @@
},
{
"cell_type": "markdown",
- "id": "e8bde053",
+ "id": "bb0c1f8c",
"metadata": {},
"source": [
"### Transitions (Tails)\n",
@@ -223,7 +224,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "a88dd483",
+ "id": "0d0bfa9f",
"metadata": {},
"outputs": [],
"source": [
@@ -233,7 +234,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "31fcb9e1",
+ "id": "1304e86a",
"metadata": {},
"outputs": [],
"source": [
@@ -246,10 +247,59 @@
")"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "1f608fa5",
+ "metadata": {},
+ "source": [
+ "### Parachutes\n",
+ "As rocketpy allows for multiple parachutes, we will create a dictionary with all the parachutes and then add them to the rocket\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e5f9a9f8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "parachutes = {}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "aca8a9e1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "parachutes[0] = Parachute(\n",
+ " name=\"Iris120Comp\",\n",
+ " cd_s=16.052,\n",
+ " trigger=182.880,\n",
+ " sampling_rate=100,\n",
+ ")"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
- "id": "9c489fab",
+ "id": "3e456b94",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "parachutes[1] = Parachute(\n",
+ " name=\"Drogue Parachute\",\n",
+ " cd_s=0.438,\n",
+ " trigger=\"apogee\",\n",
+ " sampling_rate=100,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8b5210e0",
"metadata": {},
"outputs": [],
"source": [
@@ -266,7 +316,7 @@
},
{
"cell_type": "markdown",
- "id": "f6ef9ca6",
+ "id": "6ee65aa8",
"metadata": {},
"source": [
"### Adding surfaces to the rocket\n",
@@ -276,7 +326,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "0d487990",
+ "id": "a8561efb",
"metadata": {},
"outputs": [],
"source": [
@@ -289,17 +339,35 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "d57554cd",
+ "id": "bd484fb1",
"metadata": {},
"outputs": [],
"source": [
"rocket.add_motor(motor, position=3.079819999999998)"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "60c38014",
+ "metadata": {},
+ "source": [
+ "Adding parachutes to the rocket\n"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
- "id": "e8e7472b",
+ "id": "a8e32996",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "rocket.parachutes = list(parachutes.values())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "03592001",
"metadata": {},
"outputs": [],
"source": [
@@ -309,7 +377,7 @@
},
{
"cell_type": "markdown",
- "id": "524a3720",
+ "id": "6d154473",
"metadata": {},
"source": [
"## Flight\n",
@@ -319,7 +387,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "b27cac03",
+ "id": "c268cee0",
"metadata": {},
"outputs": [],
"source": [
@@ -337,12 +405,140 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "c8a92813",
+ "id": "0cc33a11",
"metadata": {},
"outputs": [],
"source": [
"flight.all_info()"
]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "48a5de0c",
+ "metadata": {},
+ "source": [
+ "## Compare Results\n",
+ "We will now compare the results of the simulation with the parameters used to create it. Let's go!\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4dbfbd13",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "### OpenRocket vs RocketPy Parameters\n",
+ "time_to_apogee_ork = 15.761\n",
+ "time_to_apogee_rpy = flight.apogee_time\n",
+ "print(f\"Time to apogee (OpenRocket): {time_to_apogee_ork:.3f} s\")\n",
+ "print(f\"Time to apogee (RocketPy): {time_to_apogee_rpy:.3f} s\")\n",
+ "apogee_difference = time_to_apogee_rpy - time_to_apogee_ork\n",
+ "error = abs((apogee_difference) / time_to_apogee_rpy) * 100\n",
+ "print(f\"Time to apogee difference: {error:.3f} %\")\n",
+ "\n",
+ "flight_time_ork = 86.725\n",
+ "flight_time_rpy = flight.t_final\n",
+ "print(f\"Flight time (OpenRocket): {flight_time_ork:.3f} s\")\n",
+ "print(f\"Flight time (RocketPy): {flight_time_rpy:.3f} s\")\n",
+ "flight_time_difference = flight_time_rpy - flight_time_ork\n",
+ "error_flight_time = abs((flight_time_difference) / flight_time_rpy) * 100\n",
+ "print(f\"Flight time difference: {error_flight_time:.3f} %\")\n",
+ "\n",
+ "ground_hit_velocity_ork = 4.7426\n",
+ "ground_hit_velocity_rpy = flight.impact_velocity\n",
+ "print(f\"Ground hit velocity (OpenRocket): {ground_hit_velocity_ork:.3f} m/s\")\n",
+ "print(f\"Ground hit velocity (RocketPy): {ground_hit_velocity_rpy:.3f} m/s\")\n",
+ "ground_hit_velocity_difference = ground_hit_velocity_rpy - ground_hit_velocity_ork\n",
+ "error_ground_hit_velocity = (\n",
+ " abs((ground_hit_velocity_difference) / ground_hit_velocity_rpy) * 100\n",
+ ")\n",
+ "print(f\"Ground hit velocity difference: {error_ground_hit_velocity:.3f} %\")\n",
+ "\n",
+ "launch_rod_velocity_ork = 17.993\n",
+ "launch_rod_velocity_rpy = flight.out_of_rail_velocity\n",
+ "print(f\"Launch rod velocity (OpenRocket): {launch_rod_velocity_ork:.3f} m/s\")\n",
+ "print(f\"Launch rod velocity (RocketPy): {launch_rod_velocity_rpy:.3f} m/s\")\n",
+ "launch_rod_velocity_difference = launch_rod_velocity_rpy - launch_rod_velocity_ork\n",
+ "error_launch_rod_velocity = (\n",
+ " abs((launch_rod_velocity_difference) / launch_rod_velocity_rpy) * 100\n",
+ ")\n",
+ "print(f\"Launch rod velocity difference: {error_launch_rod_velocity:.3f} %\")\n",
+ "\n",
+ "max_acceleration_ork = 67.386\n",
+ "max_acceleration_rpy = flight.max_acceleration\n",
+ "print(f\"Max acceleration (OpenRocket): {max_acceleration_ork:.3f} m/s²\")\n",
+ "print(f\"Max acceleration (RocketPy): {max_acceleration_rpy:.3f} m/s²\")\n",
+ "max_acceleration_difference = max_acceleration_rpy - max_acceleration_ork\n",
+ "error_max_acceleration = abs((max_acceleration_difference) / max_acceleration_rpy) * 100\n",
+ "print(f\"Max acceleration difference: {error_max_acceleration:.3f} %\")\n",
+ "\n",
+ "max_altitude_ork = 1085.9\n",
+ "max_altitude_rpy = flight.apogee - flight.env.elevation\n",
+ "print(f\"Max altitude (OpenRocket): {max_altitude_ork:.3f} m\")\n",
+ "print(f\"Max altitude (RocketPy): {max_altitude_rpy:.3f} m\")\n",
+ "max_altitude_difference = max_altitude_rpy - max_altitude_ork\n",
+ "error_max_altitude = abs((max_altitude_difference) / max_altitude_rpy) * 100\n",
+ "print(f\"Max altitude difference: {error_max_altitude:.3f} %\")\n",
+ "\n",
+ "max_mach_ork = 0.42789\n",
+ "max_mach_rpy = flight.max_mach_number\n",
+ "print(f\"Max Mach (OpenRocket): {max_mach_ork:.3f}\")\n",
+ "print(f\"Max Mach (RocketPy): {max_mach_rpy:.3f}\")\n",
+ "max_mach_difference = max_mach_rpy - max_mach_ork\n",
+ "error_max_mach = abs((max_mach_difference) / max_mach_rpy) * 100\n",
+ "print(f\"Max Mach difference: {error_max_mach:.3f} %\")\n",
+ "\n",
+ "max_velocity_ork = 145.01\n",
+ "max_velocity_rpy = flight.max_speed\n",
+ "print(f\"Max velocity (OpenRocket): {max_velocity_ork:.3f} m/s\")\n",
+ "print(f\"Max velocity (RocketPy): {max_velocity_rpy:.3f} m/s\")\n",
+ "max_velocity_difference = max_velocity_rpy - max_velocity_ork\n",
+ "error_max_velocity = abs((max_velocity_difference) / max_velocity_rpy) * 100\n",
+ "print(f\"Max velocity difference: {error_max_velocity:.3f} %\")\n",
+ "\n",
+ "max_thrust_ork = 1785.0\n",
+ "max_thrust_rpy = flight.rocket.motor.thrust.max\n",
+ "print(f\"Max thrust (OpenRocket): {max_thrust_ork:.3f} N\")\n",
+ "print(f\"Max thrust (RocketPy): {max_thrust_rpy:.3f} N\")\n",
+ "max_thrust_difference = max_thrust_rpy - max_thrust_ork\n",
+ "error_max_thrust = abs((max_thrust_difference) / max_thrust_rpy) * 100\n",
+ "print(f\"Max thrust difference: {error_max_thrust:.3f} %\")\n",
+ "\n",
+ "burnout_stability_margin_ork = 3.7288\n",
+ "burnout_stability_margin_rpy = flight.stability_margin(\n",
+ " flight.rocket.motor.burn_out_time\n",
+ ")\n",
+ "print(f\"Burnout stability margin (OpenRocket): {burnout_stability_margin_ork:.3f}\")\n",
+ "print(f\"Burnout stability margin (RocketPy): {burnout_stability_margin_rpy:.3f}\")\n",
+ "burnout_stability_margin_difference = (\n",
+ " burnout_stability_margin_rpy - burnout_stability_margin_ork\n",
+ ")\n",
+ "error_burnout_stability_margin = (\n",
+ " abs((burnout_stability_margin_difference) / burnout_stability_margin_rpy) * 100\n",
+ ")\n",
+ "print(f\"Burnout stability margin difference: {error_burnout_stability_margin:.3f} %\")\n",
+ "\n",
+ "max_stability_margin_ork = 3.7685\n",
+ "max_stability_margin_rpy = flight.max_stability_margin\n",
+ "print(f\"Max stability margin (OpenRocket): {max_stability_margin_ork:.3f}\")\n",
+ "print(f\"Max stability margin (RocketPy): {max_stability_margin_rpy:.3f}\")\n",
+ "max_stability_margin_difference = max_stability_margin_rpy - max_stability_margin_ork\n",
+ "error_max_stability_margin = (\n",
+ " abs((max_stability_margin_difference) / max_stability_margin_rpy) * 100\n",
+ ")\n",
+ "print(f\"Max stability margin difference: {error_max_stability_margin:.3f} %\")\n",
+ "\n",
+ "min_stability_margin_ork = 1.2489\n",
+ "min_stability_margin_rpy = flight.min_stability_margin\n",
+ "print(f\"Min stability margin (OpenRocket): {min_stability_margin_ork:.3f}\")\n",
+ "print(f\"Min stability margin (RocketPy): {min_stability_margin_rpy:.3f}\")\n",
+ "min_stability_margin_difference = min_stability_margin_rpy - min_stability_margin_ork\n",
+ "error_min_stability_margin = (\n",
+ " abs((min_stability_margin_difference) / min_stability_margin_rpy) * 100\n",
+ ")\n",
+ "print(f\"Min stability margin difference: {error_min_stability_margin:.3f} %\")"
+ ]
}
],
"metadata": {},
diff --git a/examples/ProjetoJupiter--Valetudo--2019/parameters.json b/examples/ProjetoJupiter--Valetudo--2019/parameters.json
index 84168b8..32877a7 100644
--- a/examples/ProjetoJupiter--Valetudo--2019/parameters.json
+++ b/examples/ProjetoJupiter--Valetudo--2019/parameters.json
@@ -1,4 +1,5 @@
{
+ "elliptical_fins": {},
"environment": {
"base_pressure": 94311.0,
"base_temperature": 300.76,
@@ -41,7 +42,7 @@
"nozzle_radius": 0.01605,
"position": 2.052896709219859,
"throat_radius": 0.0107,
- "thrust_source": "examples\\ProjetoJupiter--Valetudo--2019\\thrust_source.csv"
+ "thrust_source": "examples/ProjetoJupiter--Valetudo--2019/thrust_source.csv"
},
"nosecones": {
"base_radius": 0.04045000000000001,
@@ -71,7 +72,7 @@
"rocket": {
"center_of_mass_without_propellant": 1.4023,
"coordinate_system_orientation": "nose_to_tail",
- "drag_curve": "examples\\ProjetoJupiter--Valetudo--2019\\drag_curve.csv",
+ "drag_curve": "examples/ProjetoJupiter--Valetudo--2019/drag_curve.csv",
"inertia": [
0.01467,
0.01467,
@@ -81,13 +82,17 @@
"radius": 0.04045000000000001
},
"stored_results": {
+ "burnout_stability_margin": 2.4363,
"flight_time": 64.161,
"ground_hit_velocity": 18.146,
"launch_rod_velocity": 26.397,
"max_acceleration": 108.52,
"max_altitude": 882.42,
"max_mach": 0.36177,
+ "max_stability_margin": 3.2714,
+ "max_thrust": 1067.7,
"max_velocity": 125.47,
+ "min_stability_margin": 0.0,
"time_to_apogee": 14.65
},
"tails": {},
diff --git a/examples/ProjetoJupiter--Valetudo--2019/simulation.ipynb b/examples/ProjetoJupiter--Valetudo--2019/simulation.ipynb
index 8b1cfbd..ec0a2a0 100644
--- a/examples/ProjetoJupiter--Valetudo--2019/simulation.ipynb
+++ b/examples/ProjetoJupiter--Valetudo--2019/simulation.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "77bcf90f",
+ "id": "121cfafa",
"metadata": {},
"source": [
"# RocketPy Simulation\n",
@@ -12,18 +12,27 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "69fccecc",
+ "execution_count": 23,
+ "id": "1a02ee31",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/bin/bash: line 1: =2.0: No such file or directory\n",
+ "Note: you may need to restart the kernel to use updated packages.\n"
+ ]
+ }
+ ],
"source": [
"%pip install rocketpy<=2.0"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "c4257f96",
+ "execution_count": 24,
+ "id": "20ba7738",
"metadata": {},
"outputs": [],
"source": [
@@ -33,16 +42,18 @@
" Rocket,\n",
" Flight,\n",
" TrapezoidalFins,\n",
+ " EllipticalFins,\n",
" RailButtons,\n",
" NoseCone,\n",
" Tail,\n",
+ " Parachute,\n",
")\n",
"import datetime"
]
},
{
"cell_type": "markdown",
- "id": "bba3ba76",
+ "id": "a4e13ebd",
"metadata": {},
"source": [
"## Environment\n"
@@ -50,8 +61,8 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "ddd7a564",
+ "execution_count": 25,
+ "id": "7da57495",
"metadata": {},
"outputs": [],
"source": [
@@ -62,7 +73,7 @@
},
{
"cell_type": "markdown",
- "id": "de710db1",
+ "id": "70f3fd1e",
"metadata": {},
"source": [
"Optionally, you can set the date and atmospheric model\n"
@@ -70,40 +81,120 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "b8bc3e1f",
+ "execution_count": 26,
+ "id": "b8914b0d",
"metadata": {},
"outputs": [],
"source": [
"tomorrow = datetime.date.today() + datetime.timedelta(days=1)\n",
"env.set_date((tomorrow.year, tomorrow.month, tomorrow.day, 12))\n",
- "env.set_atmospheric_model(type=\"Forecast\", file=\"GFS\")"
+ "# env.set_atmospheric_model(type='Forecast', file='GFS')"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "6739d306",
+ "execution_count": 27,
+ "id": "bdfc2eb3",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Gravity Details\n",
+ "\n",
+ "Acceleration of gravity at surface level: 9.7783 m/s²\n",
+ "Acceleration of gravity at 80.000 km (ASL): 9.5379 m/s²\n",
+ "\n",
+ "\n",
+ "Launch Site Details\n",
+ "\n",
+ "Launch Date: 2024-06-16 12:00:00 UTC\n",
+ "Launch Site Latitude: -23.36418°\n",
+ "Launch Site Longitude: -48.00000°\n",
+ "Reference Datum: SIRGAS2000\n",
+ "Launch Site UTM coordinates: 166021.44 W|E 0.00 N\n",
+ "Launch Site UTM zone: 31N\n",
+ "Launch Site Surface Elevation: 668.0 m\n",
+ "\n",
+ "\n",
+ "Atmospheric Model Details\n",
+ "\n",
+ "Atmospheric Model Type: standard_atmosphere\n",
+ "standard_atmosphere Maximum Height: 80.000 km\n",
+ "\n",
+ "\n",
+ "Surface Atmospheric Conditions\n",
+ "\n",
+ "Surface Wind Speed: 0.00 m/s\n",
+ "Surface Wind Direction: 0.00°\n",
+ "Surface Wind Heading: 0.00°\n",
+ "Surface Pressure: 935.54 hPa\n",
+ "Surface Temperature: 283.82 K\n",
+ "Surface Air Density: 1.148 kg/m³\n",
+ "Surface Speed of Sound: 337.55 m/s\n",
+ "\n",
+ "\n",
+ "Earth Model Details\n",
+ "\n",
+ "Earth Radius at Launch site: 6378.14 km\n",
+ "Semi-major Axis: 6378.14 km\n",
+ "Semi-minor Axis: 6356.75 km\n",
+ "Flattening: 0.0034\n",
+ "\n",
+ "\n",
+ "\n",
+ "Gravity Model Plots\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ "