I. Overview
The science community must be no stranger to superior computing softwares like Matlab. However, some projects are so heavy computationally that compute entirely by yourself is almost unfeasible. For such distinct use cases, using specialized modules will help tremendously cut down costs, time and effort needed.
In this post, I am going to introduce a scientific Python library that is light, versatile, customizable and has high accuracy, used in a fairly special use case: rocket flight simulation.
II. Tutorial
1. Installation
Because this tutorial is intended for new users, I am going to gently hold your hand and guide you step-by-step. But if you find even Internet Explorer to be faster than this guide’s pace, you definitely can skip through sections to whichever part you need.
We are going to use an open source library named RocketPy. For simplicity, I encourage the use of Google Colab to follow along - with all the comfort of a cloud Python environment, the computing resources that are seemingly inexhaustible, and the tab closing incidents that deduct from your salary.
If you chose to use Google Colab, simply enter:
!pip install rocketpy
Then press Ctrl + Enter
. Fundamentally, the bang (!) prefixes any shell command on Google Colab. You have just entered a shell command, then execute it. And if there was no typo, the enjoyable install logs should now be running on your screen:
However, if you don’t want Google to see you toddling around using a new library, or confident that your working machine excels Google’s servers, you can still open up your terminal/command prompt and enter this command:
pip install rocketpy
If you terminal window was dyed in red by errors, you can change the command to:
pip3 install rocketpy
Or:
py -m pip install rocketpy
Furthermore, if you’re currently in the mood of doing different, you can look up how to install from Conda or directly from source code at RocketPy’s official installation guide.
RocketPy team has also thoughtfully prepared a Colab notebook preview, in case you just want to mess around instead of learning it.
2. Import
RocketPy’s Github page has provided a relatively concise chart of how models interact with each other:
Basically, users put the above parameters into RocketPy, then let the black magic does its calculations. Therefore, to begin, we need to import all the above models:
from rocketpy import Environment, Rocket, SolidMotor, Flight
In this example, I want to set simulation time to the next day, so I will also need the datetime
module:
import datetime
3. Configuration
Every model need to be configured separately. For instance, to create an environment object:
Env = Environment(
railLength=5.2,
latitude=32.990254,
longitude=-106.974998,
elevation=1400,
date=(2022, 6, 22, 12) # Tomorrow's date in year, month, day, hour UTC format
)
Env.setAtmosphericModel(type='Forecast', file='GFS')
Slightly more advanced, if you want your environment object to always calculate according to the next day’s parameters:
tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
Env = Environment(
railLength = 5.2,
latitude = 21.2187149,
longitude = 105.8041709,
elevation = 12, # meters
date = (
tomorrow.year,
tomorrow.month,
tomorrow.day,
tomorrow.hour
)
)
Env.setAtmosphericModel(type='Forecast', file='GFS')
It must be simple for users with previous Python experiences to realize that this code is merely creating an object. The data types are also plain floats, and variable names are intelligible.
Next up, since we need a rocket rather than a drill, we must choose a fitting rocket engine model. RocketPy only supports solid rocket motors, not complicated liquid rocket engines. Nevertheless, the RocketPy team has already procured some interesting rocket engine data in the module’s Git repo.
For experimenting purpose, this time we are going to mess with the Cesaroni M3100 engine. First, we need to get the engine’s data, by running the following command:
!wget https://raw.githubusercontent.com/Projeto-Jupiter/RocketPy/master/data/motors/Cesaroni_M3100.eng
Or you can directly download that model here: Cesaroni_M3100.eng.
The next step is to create a complete engine object.
Pro75M3100 = SolidMotor(
thrustSource="Cesaroni_M3100.eng",
burnOut=3.9,
grainNumber=5,
grainSeparation=5/1000,
grainDensity=1815,
grainOuterRadius=33/1000,
grainInitialInnerRadius=15/1000,
grainInitialHeight=120/1000,
nozzleRadius=33/1000,
throatRadius=11/1000,
interpolationMethod='linear'
)
As such, in only half a second we have successfully simulated an engine more completed than BE-4. If you are curious about the engine’s specs, you can use the .info()
method like this:
From rocket engine to a full-fledged rocket in RocketPy is a step as small as Armstrong’s one. For example, if we name our rocket calisto, our rocket object will somewhat resembles this:
calisto = Rocket(
motor=Pro75M3100,
radius=127/2000,
mass=19.197-2.956,
inertiaI=6.60,
inertiaZ=0.0351,
distanceRocketNozzle=-1.255,
distanceRocketPropellant=-0.85704,
powerOffDrag='powerOffDragCurve.csv',
powerOnDrag='powerOnDragCurve.csv'
)
At this point, your program will protest because of lacked csv data files. You can get them using this command:
!wget https://raw.githubusercontent.com/Projeto-Jupiter/RocketPy/master/data/calisto/powerOffDragCurve.csv https://raw.githubusercontent.com/Projeto-Jupiter/RocketPy/master/data/calisto/powerOnDragCurve.csv
Or once again, directly download them here: powerOffDragCurve.csv, powerOnDragCurve.csv.
The next few steps will be similar to what you have always done while playing Kerbal Space Program, starting with rail buttons:
calisto.setRailButtons([0.2, -0.5])
Next is the nose cone:
NoseCone = calisto.addNose(length=0.55829, kind="vonKarman", distanceToCM=0.71971)
Then the fins:
FinSet = calisto.addFins(4, span=0.100, rootChord=0.120, tipChord=0.040, distanceToCM=-1.04956)
And finally, the tail:
Tail = calisto.addTail(topRadius=0.0635, bottomRadius=0.0435, length=0.060, distanceToCM=-1.194656)
The parts for a successful launch has been assembled… I mean, an ICBM launch.
To prevent our simulation from descending into a war simulation, a usually forgotten component in KSP - parachutes - will need to be added.
# Adding parachutes to rocket
def drogueTrigger(p, y):
return True if y[5] < 0 else False
def mainTrigger(p, y):
return True if y[5] < 0 and y[2] < 800 else False
Main = calisto.addParachute('Main', CdS=10.0, trigger=mainTrigger, samplingRate=105, lag=1.5, noise=(0, 8.3, 0.5))
Drogue = calisto.addParachute('Drogue', CdS=1.0, trigger=drogueTrigger, samplingRate=105, lag=1.5, noise=(0, 8.3, 0.5))
At last, our ship is ready to be rolled out from the VAB.
4. Simulation
Our environment and rocket is ready. No need to constantly push schedules back like NASA, we can immediately take off.
Relatively simple, as when creating our rocket, to simulate a flight, we also need an object.
TestFlight = Flight(rocket=calisto, environment=Env, inclination=85, heading=0)
If your above command didn’t produce errors, then your simulated launch has landed. To get data on that simulation, once again we can use the .info()
method:
TestFlight.info()
Lots of information will jump out, for instance:
Surface Wind Conditions
Frontal Surface Wind Speed: -0.57 m/s
Lateral Surface Wind Speed: -1.38 m/s
Rail Departure State
Rail Departure Time: 0.233 s
Rail Departure Velocity: 34.300 m/s
Rail Departure Static Margin: 2.154 c
Rail Departure Angle of Attack: 2.495°
Rail Departure Thrust-Weight Ratio: 17.509
Rail Departure Reynolds Number: 2.654e+05
BurnOut State
BurnOut time: 2.000 s
Altitude at burnOut: 335.521 m (AGL)
Rocket velocity at burnOut: 313.776 m/s
Freestream velocity at burnOut: 313.916 m/s
Mach Number at burnOut: 0.900
Kinetic energy at burnOut: 7.995e+05 J
Apogee
Apogee Altitude: 3328.738 m (ASL) | 3302.197 m (AGL)
Apogee Time: 24.890 s
Apogee Freestream Speed: 22.460 m/s
Events
Drogue Ejection Triggered at: 24.895 s
Drogue Parachute Inflated at: 26.395 s
Drogue Parachute Inflated with Freestream Speed of: 26.660 m/s
Drogue Parachute Inflated at Height of: 3291.269 m (AGL)
Main Ejection Triggered at: 165.171 s
Main Parachute Inflated at: 166.671 s
Main Parachute Inflated with Freestream Speed of: 17.237 m/s
Main Parachute Inflated at Height of: 747.508 m (AGL)
Impact
X Impact: 100.916 m
Y Impact: -250.161 m
Time of Impact: 305.258 s
Velocity at Impact: -5.287 m/s
Maximum Values
Maximum Speed: 314.984 m/s at 1.93 s
Maximum Mach Number: 0.903 Mach at 1.93 s
Maximum Reynolds Number: 2.394e+06 at 1.92 s
Maximum Dynamic Pressure: 5.523e+04 Pa at 1.92 s
Maximum Acceleration: 192.131 m/s² at 0.82 s
Maximum Gs: 19.592 g at 0.82 s
Maximum Upper Rail Button Normal Force: 0.612 N
Maximum Upper Rail Button Shear Force: 0.219 N
Maximum Lower Rail Button Normal Force: 0.219 N
Maximum Lower Rail Button Shear Force: 0.219 N
Finally, if you want to have detailed stats with coherent graphs, you can use the .allInfo()
method:
TestFlight.allInfo()
As you can see, if there’re 3 simplest things in this world, then one of them must be running a RocketPy simulation.
III. Application
Because RocketPy does not support liquid engines, this handy and friendly module is mostly intended to be used for high-power rocketry. With all of that usability and configurability, RocketPy will definitely prove itself useful in interesting rocket launch simulations.