{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "nvAT8wcRNVEk"
},
"source": [
"# Getting Started - RocketPy in Colab\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "8gCWjpEyPNp1"
},
"source": [
"We start by setting up our environment. To run this notebook, we will need:\n",
"\n",
"- RocketPy\n",
"- Data files (we will download RocketPy's data from github)\n",
"\n",
"Therefore, let's run the following lines of code:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "zwDDabtpNc6Z"
},
"outputs": [],
"source": [
"!pip install rocketpy\n",
"!curl -o NACA0012-radians.csv https://raw.githubusercontent.com/RocketPy-Team/RocketPy/master/data/calisto/NACA0012-radians.csv\n",
"!curl -o Cesaroni_M1670.eng https://raw.githubusercontent.com/RocketPy-Team/RocketPy/master/data/motors/Cesaroni_M1670.eng\n",
"!curl -o powerOffDragCurve.csv https://raw.githubusercontent.com/RocketPy-Team/RocketPy/master/data/calisto/powerOffDragCurve.csv\n",
"!curl -o powerOnDragCurve.csv https://raw.githubusercontent.com/RocketPy-Team/RocketPy/master/data/calisto/powerOnDragCurve.csv"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "55zcnvqdNVEo"
},
"source": [
"Now we can start!\n",
"\n",
"Here we go through a simplified rocket trajectory simulation to get you started. Let's start by importing the rocketpy module.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "XGK9M8ecNVEp"
},
"outputs": [],
"source": [
"from rocketpy import Environment, SolidMotor, Rocket, Flight"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "ImgkhEkZNVE8"
},
"source": [
"It is recommended to run the following line to make matplotlib plots which will be shown later interactive and higher quality.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "uRa566HoNVE9"
},
"outputs": [],
"source": [
"%config InlineBackend.figure_formats = ['svg']\n",
"%matplotlib inline"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "sSeqramENVFB"
},
"source": [
"## Setting Up a Simulation\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "Vm4ZHAnnNVFC"
},
"source": [
"### Creating an Environment for Spaceport America\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"The `Environment` class is used to define the atmosphere, the winds, and the gravity models.\n",
"\n",
"You can find more information about the `Environment` class in the [Environment Class Usage Docs](https://docs.rocketpy.org/en/latest/notebooks/environment/environment_class_usage.html)."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "d7mooAZONVFD"
},
"outputs": [],
"source": [
"env = Environment(latitude=32.990254, longitude=-106.974998, elevation=1400)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "Fz8Ha6usNVFH"
},
"source": [
"To get weather data from the GFS forecast, available online, we run the following lines.\n",
"\n",
"First, we set tomorrow's date.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "5kl-Je8dNVFI"
},
"outputs": [],
"source": [
"import datetime\n",
"\n",
"tomorrow = datetime.date.today() + datetime.timedelta(days=1)\n",
"\n",
"env.set_date(\n",
" (tomorrow.year, tomorrow.month, tomorrow.day, 12)\n",
") # Hour given in UTC time"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "or5MLF9gNVFM"
},
"source": [
"Then, we tell env to use a GFS forecast to get the atmospheric conditions for flight.\n",
"\n",
"Don't mind the warning, it just means that not all variables, such as wind speed or atmospheric temperature, are available at all altitudes given by the forecast.\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "g73fa7DWNVFN"
},
"outputs": [],
"source": [
"env.set_atmospheric_model(type=\"Forecast\", file=\"GFS\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "wSnZQuRYNVFS"
},
"source": [
"We can see what the weather will look like by calling the info method!\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "H_AMjVTjNVFT"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Gravity Details\n",
"\n",
"Acceleration of Gravity at Lauch Site: 9.79111266229703 m/s²\n",
"\n",
"\n",
"Launch Site Details\n",
"\n",
"Launch Date: 2023-08-11 12:00:00 UTC\n",
"Launch Site Latitude: 32.99025°\n",
"Launch Site Longitude: -106.97500°\n",
"Reference Datum: SIRGAS2000\n",
"Launch Site UTM coordinates: 315468.64 W 3651938.65 N\n",
"Launch Site UTM zone: 13S\n",
"Launch Site Surface Elevation: 1471.5 m\n",
"\n",
"\n",
"Atmospheric Model Details\n",
"\n",
"Atmospheric Model Type: Forecast\n",
"Forecast Maximum Height: 79.504 km\n",
"Forecast Time Period: From 2023-08-10 18:00:00 to 2023-08-26 18:00:00 UTC\n",
"Forecast Hour Interval: 3 hrs\n",
"Forecast Latitude Range: From -90.0 ° To 90.0 °\n",
"Forecast Longitude Range: From 0.0 ° To 359.75 °\n",
"\n",
"\n",
"Surface Atmospheric Conditions\n",
"\n",
"Surface Wind Speed: 3.88 m/s\n",
"Surface Wind Direction: 160.03°\n",
"Surface Wind Heading: 340.03°\n",
"Surface Pressure: 854.13 hPa\n",
"Surface Temperature: 296.19 K\n",
"Surface Air Density: 1.005 kg/m³\n",
"Surface Speed of Sound: 345.01 m/s\n",
"\n",
"\n",
"Atmospheric Model Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"env.info()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "Aksbs-pMNVFW"
},
"source": [
"### Creating a Motor\n",
"\n",
"A solid rocket motor is used in this case. To create a motor, the SolidMotor class is used and the required arguments are given.\n",
"\n",
"The SolidMotor class requires the user to have a thrust curve ready. This can come either from a .eng file for a commercial motor, such as below, or a .csv file from a static test measurement.\n",
"\n",
"Besides the thrust curve, other parameters such as grain properties and nozzle dimensions must also be given.\n",
"\n",
"See [Solid Motor Class Usage Docs](https://docs.rocketpy.org/en/latest/user/motors/solidmotor.html) for more information.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "Vx1dZObwNVFX"
},
"outputs": [],
"source": [
"Pro75M1670 = SolidMotor(\n",
" thrust_source=\"Cesaroni_M1670.eng\",\n",
" dry_mass=1.815,\n",
" dry_inertia=(0.125, 0.125, 0.002),\n",
" nozzle_radius=33 / 1000,\n",
" grain_number=5,\n",
" grain_density=1815,\n",
" grain_outer_radius=33 / 1000,\n",
" grain_initial_inner_radius=15 / 1000,\n",
" grain_initial_height=120 / 1000,\n",
" grain_separation=5 / 1000,\n",
" grains_center_of_mass_position=0.397,\n",
" center_of_dry_mass_position=0.317,\n",
" nozzle_position=0,\n",
" burn_time=3.9,\n",
" throat_radius=11 / 1000,\n",
" coordinate_system_orientation=\"nozzle_to_combustion_chamber\",\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "E1LJDIa0NVFa"
},
"source": [
"**Pay special attention to *position* related parameters:**\n",
"More details on [Positions and Coordinate Systems](https://docs.rocketpy.org/en/latest/user/positions.html)\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"To see what our thrust curve looks like, along with other import properties, we invoke the info method yet again. You may try the all_info method if you want more information all at once!\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "vjyPT7GVNVFb"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Nozzle Details\n",
"Nozzle Radius: 0.033 m\n",
"Nozzle Throat Radius: 0.011 m\n",
"\n",
"Grain Details\n",
"Number of Grains: 5\n",
"Grain Spacing: 0.005 m\n",
"Grain Density: 1815 kg/m3\n",
"Grain Outer Radius: 0.033 m\n",
"Grain Inner Radius: 0.015 m\n",
"Grain Height: 0.12 m\n",
"Grain Volume: 0.000 m3\n",
"Grain Mass: 0.591 kg\n",
"\n",
"Motor Details\n",
"Total Burning Time: 3.9 s\n",
"Total Propellant Mass: 2.956 kg\n",
"Average Propellant Exhaust Velocity: 2038.745 m/s\n",
"Average Thrust: 1545.218 N\n",
"Maximum Thrust: 2200.0 N at 0.15 s after ignition.\n",
"Total Impulse: 6026.350 Ns\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"Pro75M1670.info()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "kN7y1EwLNVFf"
},
"source": [
"### Creating a Rocket\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "_Ee-0vb5NVFg"
},
"source": [
"A rocket is composed of several components. Namely, we must have a motor (good thing we have the Pro75M1670 ready), a couple of aerodynamic surfaces (nose cone, fins and tail) and parachutes (if we are not launching a missile).\n",
"\n",
"You can find more information about the `Rocket` class in the [Rocket Class Usage Docs](https://docs.rocketpy.org/en/latest/user/rocket.html).\n",
"\n",
"Let's start by initializing our rocket, named Calisto, entering inertia properties, some dimensions and drag curves.\n",
"\n",
"**Pay special attention to *position* related parameters:**\n",
"More details on [Positions and Coordinate Systems](https://docs.rocketpy.org/en/latest/user/positions.html)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "D1fyK8u_NVFh"
},
"outputs": [],
"source": [
"calisto = Rocket(\n",
" radius=127 / 2000,\n",
" mass=14.426,\n",
" inertia=(6.321, 6.321, 0.034),\n",
" power_off_drag=\"powerOffDragCurve.csv\",\n",
" power_on_drag=\"powerOnDragCurve.csv\",\n",
" center_of_mass_without_motor=0,\n",
" coordinate_system_orientation=\"tail_to_nose\",\n",
")\n",
"\n",
"rail_buttons = calisto.set_rail_buttons(\n",
" upper_button_position=0.0818,\n",
" lower_button_position=-0.618,\n",
" angular_position=45,\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"To add the motor to our rocket we need only inform what motor we are adding (Pro75M1670) and inform the position, in meters, of the motor's nozzle exit area relative to the previously defined coordinate system.\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"calisto.add_motor(Pro75M1670, position=-1.255)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "CfOfqmroNVFk"
},
"source": [
"#### Adding Aerodynamic Surfaces\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "LuUdEmWhNVFl"
},
"source": [
"Now we define the aerodynamic surfaces. They are really straight forward with special attention needed only for the position values. Here is a quick guide:\n",
"\n",
"- The positions given **must** be relative to the same coordinate system as the rockets;\n",
"- Position of the Nosecone refers to the tip of the nose;\n",
"- Position of fins refers to the point belonging to the root chord which is highest in the rocket coordinate system;\n",
"- Position of the tail the point belonging to the tail which is highest in the rocket coordinate system.\n",
"\n",
"See more details in [Positions and Coordinate Systems](https://docs.rocketpy.org/en/latest/user/positions.html)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "AQbv244VNVFm"
},
"outputs": [],
"source": [
"nose_cone = calisto.add_nose(length=0.55829, kind=\"vonKarman\", position=1.278)\n",
"\n",
"fin_set = calisto.add_trapezoidal_fins(\n",
" n=4,\n",
" root_chord=0.120,\n",
" tip_chord=0.060,\n",
" span=0.110,\n",
" position=-1.04956,\n",
" cant_angle=0.5,\n",
" airfoil=(\"NACA0012-radians.csv\", \"radians\"),\n",
")\n",
"\n",
"tail = calisto.add_tail(\n",
" top_radius=0.0635, bottom_radius=0.0435, length=0.060, position=-1.194656\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"To see all information regarding the rocket we just defined we run:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Inertia Details\n",
"\n",
"Rocket Mass: 14.426 kg\n",
"Rocket Dry Mass: 16.241 kg (With Motor)\n",
"Rocket Mass: 19.197 kg (With Propellant)\n",
"Rocket Inertia (with motor, but without propellant) 11: 7.864 kg*m2\n",
"Rocket Inertia (with motor, but without propellant) 22: 7.864 kg*m2\n",
"Rocket Inertia (with motor, but without propellant) 33: 0.036 kg*m2\n",
"Rocket Inertia (with motor, but without propellant) 12: 0.000 kg*m2\n",
"Rocket Inertia (with motor, but without propellant) 13: 0.000 kg*m2\n",
"Rocket Inertia (with motor, but without propellant) 23: 0.000 kg*m2\n",
"\n",
"\n",
"Geometrical Parameters\n",
"\n",
"Rocket Maximum Radius: 0.0635 m\n",
"Rocket Frontal Area: 0.012668 m2\n",
"\n",
"Rocket Distances\n",
"Rocket Center of Dry Mass - Center of Mass withour Motor: 0.105 m\n",
"Rocket Center of Dry Mass - Nozzle Exit Distance: 1.150 m\n",
"Rocket Center of Dry Mass - Center of Propellant Mass: 0.753 m\n",
"Rocket Center of Mass - Rocket Loaded Center of Mass: 0.116 m\n",
"\n",
"\n",
"Aerodynamics Lift Coefficient Derivatives\n",
"\n",
"Nosecone Lift Coefficient Derivative: 2.000/rad\n",
"Fins Lift Coefficient Derivative: 6.280/rad\n",
"Tail Lift Coefficient Derivative: -1.061/rad\n",
"\n",
"Aerodynamics Center of Pressure\n",
"\n",
"Nosecone Center of Pressure to CM: 0.999 m\n",
"Fins Center of Pressure to CM: -1.100 m\n",
"Tail Center of Pressure to CM: -1.223 m\n",
"Distance - Center of Pressure to Center of Dry Mass: 0.279 m\n",
"Initial Static Margin: 2.199 c\n",
"Final Static Margin: 3.112 c\n",
"\n",
"\n",
"\n",
"Mass Plots\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Aerodynamics Plots\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"calisto.all_info()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "D8oKc7s2NVFp"
},
"source": [
"#### Adding Parachutes\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "IxAX61ZENVFq"
},
"source": [
"Finally, we have parachutes! Calisto will have two parachutes, Drogue and Main. The Drogue parachute will open at apogee while the Main parachute will open at 800m above ground level\n",
"\n",
"For more details see [Adding Parachutes](https://docs.rocketpy.org/en/latest/user/rocket.html#adding-parachutes)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "f0PmLcF8NVFr"
},
"outputs": [],
"source": [
"Main = calisto.add_parachute(\n",
" \"Main\",\n",
" cd_s=10.0,\n",
" trigger=800,\n",
" sampling_rate=105,\n",
" lag=1.5,\n",
" noise=(0, 8.3, 0.5),\n",
")\n",
"\n",
"Drogue = calisto.add_parachute(\n",
" \"Drogue\",\n",
" cd_s=1.0,\n",
" trigger=\"apogee\",\n",
" sampling_rate=105,\n",
" lag=1.5,\n",
" noise=(0, 8.3, 0.5),\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "xIoXe33FNVFv"
},
"source": [
"Just be careful if you run this last cell multiple times! If you do so, your rocket will end up with lots of parachutes which activate together, which may cause problems during the flight simulation. We advise you to re-run all cells which define our rocket before running this, preventing unwanted old parachutes. Alternatively, you can run the following lines to remove parachutes.\n",
"\n",
"```python\n",
"Calisto.parachutes.remove(Drogue)\n",
"Calisto.parachutes.remove(Main)\n",
"```\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "4PR0fgSbNVFw"
},
"source": [
"## Simulating a Flight\n",
"\n",
"Simulating a flight trajectory is as simple as initializing a Flight class object givin the rocket and environnement set up above as inputs. The launch rail inclination and heading are also given here.\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "v__Ud2p2NVFx"
},
"outputs": [],
"source": [
"test_flight = Flight(\n",
" rocket=calisto, environment=env, rail_length=5.2, inclination=85, heading=0\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "8SjrGQqzNVF0"
},
"source": [
"## Analyzing the Results\n",
"\n",
"RocketPy gives you many plots, thats for sure! They are divided into sections to keep them organized. Alternatively, see the Flight class documentation to see how to get plots for specific variables only, instead of all of them at once.\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "Hh4A_RQzNVF0",
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Initial Conditions\n",
"\n",
"Position - x: 0.00 m | y: 0.00 m | z: 1471.47 m\n",
"Velocity - Vx: 0.00 m/s | Vy: 0.00 m/s | Vz: 0.00 m/s\n",
"Attitude - e0: 0.999 | e1: -0.044 | e2: -0.000 | e3: 0.000\n",
"Euler Angles - Spin φ : 0.00° | Nutation θ: -5.00° | Precession ψ: 0.00°\n",
"Angular Velocity - ω1: 0.00 rad/s | ω2: 0.00 rad/s| ω3: 0.00 rad/s\n",
"\n",
"\n",
"Surface Wind Conditions\n",
"\n",
"Frontal Surface Wind Speed: 3.65 m/s\n",
"Lateral Surface Wind Speed: 1.32 m/s\n",
"\n",
"\n",
"Launch Rail\n",
"\n",
"Launch Rail Length: 5.2 m\n",
"Launch Rail Inclination: 85.00°\n",
"Launch Rail Heading: 0.00°\n",
"\n",
"\n",
"Rail Departure State\n",
"\n",
"Rail Departure Time: 0.372 s\n",
"Rail Departure Velocity: 26.567 m/s\n",
"Rail Departure Static Margin: 2.273 c\n",
"Rail Departure Angle of Attack: 8.397°\n",
"Rail Departure Thrust-Weight Ratio: 10.165\n",
"Rail Departure Reynolds Number: 1.851e+05\n",
"\n",
"\n",
"Burn out State\n",
"\n",
"Burn out time: 3.900 s\n",
"Altitude at burn out: 660.807 m (AGL)\n",
"Rocket velocity at burn out: 281.091 m/s\n",
"Freestream velocity at burn out: 281.084 m/s\n",
"Mach Number at burn out: 0.819\n",
"Kinetic energy at burn out: 6.416e+05 J\n",
"\n",
"\n",
"Apogee State\n",
"\n",
"Apogee Altitude: 4870.291 m (ASL) | 3398.825 m (AGL)\n",
"Apogee Time: 26.279 s\n",
"Apogee Freestream Speed: 8.861 m/s\n",
"\n",
"\n",
"Parachute Events\n",
"\n",
"Drogue Ejection Triggered at: 26.286 s\n",
"Drogue Parachute Inflated at: 27.786 s\n",
"Drogue Parachute Inflated with Freestream Speed of: 16.645 m/s\n",
"Drogue Parachute Inflated at Height of: 3387.954 m (AGL)\n",
"Main Ejection Triggered at: 167.771 s\n",
"Main Parachute Inflated at: 169.271 s\n",
"Main Parachute Inflated with Freestream Speed of: 17.450 m/s\n",
"Main Parachute Inflated at Height of: 775.070 m (AGL)\n",
"\n",
"\n",
"Impact Conditions\n",
"\n",
"X Impact: 288.327 m\n",
"Y Impact: 552.624 m\n",
"Time of Impact: 311.817 s\n",
"Velocity at Impact: -5.306 m/s\n",
"\n",
"\n",
"Maximum Values\n",
"\n",
"Maximum Speed: 286.856 m/s at 3.39 s\n",
"Maximum Mach Number: 0.835 Mach at 3.39 s\n",
"Maximum Reynolds Number: 1.917e+06 at 3.33 s\n",
"Maximum Dynamic Pressure: 3.930e+04 Pa at 3.35 s\n",
"Maximum Acceleration: 105.253 m/s² at 0.15 s\n",
"Maximum Gs: 10.750 g at 0.15 s\n",
"Maximum Upper Rail Button Normal Force: 1.378 N\n",
"Maximum Upper Rail Button Shear Force: 2.951 N\n",
"Maximum Lower Rail Button Normal Force: 0.627 N\n",
"Maximum Lower Rail Button Shear Force: 1.345 N\n",
"\n",
"\n",
"Numerical Integration Settings\n",
"\n",
"Maximum Allowed Flight Time: 600.000000 s\n",
"Maximum Allowed Time Step: inf s\n",
"Minimum Allowed Time Step: 0.000000e+00 s\n",
"Relative Error Tolerance: 1e-06\n",
"Absolute Error Tolerance: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 1e-06, 1e-06, 1e-06, 1e-06, 0.001, 0.001, 0.001]\n",
"Allow Event Overshoot: True\n",
"Terminate Simulation on Apogee: False\n",
"Number of Time Steps Used: 707\n",
"Number of Derivative Functions Evaluation: 2196\n",
"Average Function Evaluations per Time Step: 3.106082\n",
"\n",
"\n",
"\n",
"Trajectory 3d Plot\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Trajectory Kinematic Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Angular Position Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Path, Attitude and Lateral Attitude Angle plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Trajectory Angular Velocity and Acceleration Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Aerodynamic Forces Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Rail Buttons Forces Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Trajectory Energy Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Trajectory Fluid Mechanics Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Trajectory Stability and Control Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Rocket and Parachute Pressure Plots\n",
"\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Parachute: Main\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Parachute: Drogue\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"test_flight.all_info()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Export Flight Trajectory to a .kml file so it can be opened on Google Earth\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"File trajectory.kml saved with success!\n"
]
}
],
"source": [
"test_flight.export_kml(\n",
" file_name=\"trajectory.kml\",\n",
" extrude=True,\n",
" altitude_mode=\"relative_to_ground\",\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "Aun9D2OINVF4"
},
"source": [
"## Using Simulation for Design\n",
"\n",
"Here, we go through a couple of examples which make use of RocketPy in cool ways to help us design our rocket.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Apogee as a Function of Mass\n",
"\n",
"This one is a classic one! We always need to know how much our rocket's apogee will change when our payload gets heavier.\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'Function from R1 to R1 : (Rocket Dry Mass (kg)) → (Estimated Apogee AGL (m))'"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from rocketpy.utilities import apogee_by_mass\n",
"\n",
"apogee_by_mass(flight=test_flight, min_mass=5, max_mass=20, points=10, plot=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Out of Rail Speed as a Function of Mass\n",
"\n",
"Lets make a really important plot. Out of rail speed is the speed our rocket has when it is leaving the launch rail. This is crucial to make sure it can fly safely after leaving the rail. A common rule of thumb is that our rocket's out of rail speed should be 4 times the wind speed so that it does not stall and become unstable.\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'Function from R1 to R1 : (Rocket Dry Mass (kg)) → (Liftoff Speed (m/s))'"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from rocketpy.utilities import liftoff_speed_by_mass\n",
"\n",
"liftoff_speed_by_mass(flight=test_flight, min_mass=5, max_mass=20, points=10, plot=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Dynamic Stability Analysis\n",
"\n",
"Ever wondered how static stability translates into dynamic stability? Different static margins result in different dynamic behavior, which also depends on the rocket's rotational inertial.\n",
"\n",
"Let's make use of RocketPy's helper class called Function to explore how the dynamic stability of Calisto varies if we change the fins span by a certain factor.\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Simulating Rocket with Static Margin of 0.113->0.846 c\n",
"Simulation Completed at Time: 5.0000 s\n",
"Simulating Rocket with Static Margin of 1.064->1.796 c\n",
"Simulation Completed at Time: 5.0000 s\n",
"Simulating Rocket with Static Margin of 2.014->2.747 c\n",
"Simulation Completed at Time: 5.0000 s\n",
"Simulating Rocket with Static Margin of 2.964->3.697 c\n",
"Simulation Completed at Time: 5.0000 s\n",
"Simulating Rocket with Static Margin of 3.914->4.647 c\n",
"Simulation Completed at Time: 5.0000 s\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Helper class\n",
"from rocketpy import Function\n",
"import copy\n",
"\n",
"# Prepare a copy of the rocket\n",
"calisto2 = copy.deepcopy(calisto)\n",
"\n",
"# Prepare Environment Class\n",
"custom_env = Environment()\n",
"custom_env.set_atmospheric_model(type=\"custom_atmosphere\", wind_v=-5)\n",
"\n",
"# Simulate Different Static Margins by Varying Fin Position\n",
"simulation_results = []\n",
"\n",
"for factor in [-0.5, -0.2, 0.1, 0.4, 0.7]:\n",
" # Modify rocket fin set by removing previous one and adding new one\n",
" calisto2.aerodynamic_surfaces.pop(-1)\n",
"\n",
" fin_set = calisto2.add_trapezoidal_fins(\n",
" n=4,\n",
" root_chord=0.120,\n",
" tip_chord=0.040,\n",
" span=0.100,\n",
" position=-1.04956 * factor,\n",
" )\n",
" # Simulate\n",
" print(\n",
" \"Simulating Rocket with Static Margin of {:1.3f}->{:1.3f} c\".format(\n",
" calisto2.static_margin(0),\n",
" calisto2.static_margin(calisto2.motor.burn_out_time),\n",
" )\n",
" )\n",
" test_flight = Flight(\n",
" rocket=calisto2,\n",
" environment=custom_env,\n",
" rail_length=5.2,\n",
" inclination=90,\n",
" heading=0,\n",
" max_time_step=0.01,\n",
" max_time=5,\n",
" terminate_on_apogee=True,\n",
" verbose=True,\n",
" )\n",
" # Store Results\n",
" static_margin_at_ignition = calisto2.static_margin(0)\n",
" static_margin_at_out_of_rail = calisto2.static_margin(test_flight.out_of_rail_time)\n",
" static_margin_at_steady_state = calisto2.static_margin(test_flight.t_final)\n",
" simulation_results += [\n",
" (\n",
" test_flight.attitude_angle,\n",
" \"{:1.2f} c | {:1.2f} c | {:1.2f} c\".format(\n",
" static_margin_at_ignition,\n",
" static_margin_at_out_of_rail,\n",
" static_margin_at_steady_state,\n",
" ),\n",
" )\n",
" ]\n",
"\n",
"Function.compare_plots(\n",
" simulation_results,\n",
" lower=0,\n",
" upper=1.5,\n",
" xlabel=\"Time (s)\",\n",
" ylabel=\"Attitude Angle (deg)\",\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Characteristic Frequency Calculation\n",
"\n",
"Here we analyse the characteristic frequency of oscillation of our rocket just as it leaves the launch rail. Note that when we ran test_flight.all_info(), one of the plots already showed us the frequency spectrum of our flight. Here, however, we have more control of what we are plotting.\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Simulate first 5 seconds of Flight\n",
"flight = Flight(\n",
" rocket=calisto,\n",
" environment=env,\n",
" rail_length=5.2,\n",
" inclination=90,\n",
" heading=0,\n",
" max_time_step=0.01,\n",
" max_time=5,\n",
")\n",
"\n",
"# Perform a Fourier Analysis\n",
"Fs = 100.0\n",
"# sampling rate\n",
"Ts = 1.0 / Fs\n",
"# sampling interval\n",
"t = np.arange(1, 400, Ts) # time vector\n",
"ff = 5\n",
"# frequency of the signal\n",
"y = flight.attitude_angle(t) - np.mean(flight.attitude_angle(t))\n",
"n = len(y) # length of the signal\n",
"k = np.arange(n)\n",
"T = n / Fs\n",
"frq = k / T # two sides frequency range\n",
"frq = frq[range(n // 2)] # one side frequency range\n",
"Y = np.fft.fft(y) / n # fft computing and normalization\n",
"Y = Y[range(n // 2)]\n",
"\n",
"# Create the plot\n",
"fig, ax = plt.subplots(2, 1)\n",
"ax[0].plot(t, y)\n",
"ax[0].set_xlabel(\"Time\")\n",
"ax[0].set_ylabel(\"Signal\")\n",
"ax[0].set_xlim((0, 5))\n",
"ax[0].grid()\n",
"ax[1].plot(frq, abs(Y), \"r\") # plotting the spectrum\n",
"ax[1].set_xlabel(\"Freq (Hz)\")\n",
"ax[1].set_ylabel(\"|Y(freq)|\")\n",
"ax[1].set_xlim((0, 5))\n",
"ax[1].grid()\n",
"plt.subplots_adjust(hspace=0.5)\n",
"plt.show()"
]
}
],
"metadata": {
"colab": {
"name": "getting_started.ipynb",
"provenance": [],
"toc_visible": true
},
"hide_input": false,
"kernelspec": {
"display_name": "Python 3.10.0 ('rocketpy_dev')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.5"
},
"vscode": {
"interpreter": {
"hash": "18e93d5347af13ace37d47ea4e2a2ad720f0331bd9cb28f9983f5585f4dfaa5c"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}