Imports
using Plots
plotlyjs()
using Unitful
using DataFrames
using Measurements
using Measurements: value, uncertainty
using CSV
Simulating the performance of a compressed air propulsion system as an alternative to solid rocket motors using Julia.
For Capstone my team was tasked with designing a system capable of moving mining equipment and materials around the surface of the Moon using a propulsive landing. The system had to be tested on Earth with something feasible for our team to build in 2 semesters. One of the first considerations my capstone advisor wanted was to test the feasibility of an air propulsion system instead of the obvious solution that of using solid rocket motors. This document is just napkin math to determine if the system is even feasibly and is not meant to be a rigorous study of an air propulsion system that would easily keep a capstone team busy by itself.
I chose an off-the-shelf paintball gun tank for the pressure vessel. The primary consideration was the incredible pressure to weight ratio, and the fact that it is designed to be bumped around would be necessary for proving the safety of the system further into the project.
The nozzle diameter was changed until the air prop system had a burn time similar to a G18ST rocket motor. The propulsion system’s total impulse is not dependant on the nozzle diameter, so this was just done to make it plot nicely with the rest of the rocket motors since, at this time, it is unknown what the optimal thrust profile is.
These are just universal values for what a typical day would look like during the summer in Northern Arizona. (Çengel and Boles 2015)
The actual simulation is quite simple. The basic idea is that using the current pressure, you can calculate \(\dot{m}\), which allows calculating the Thrust, and then you can subtract the current mass of air in the tank by \(\dot{m}\) and recalculate pressure using the new mass then repeat the whole process.
The bulk of the equations in the simulation came from (Çengel and Boles 2015), while the Thrust and \(v_e\) equations came from (Sutton and Biblarz 2001, eq: 2-14).
\[ T = \dot{m} \cdot v_\text{Exit} + A_\text{Nozzle} \cdot (P - P_\text{Ambient}) \]
The initial pressure difference is 4190.0 ± 300.0 psi, which is massive, so the area of the nozzle significantly alters the thrust profile. The paintball tanks come with pressure regulators, in our case, 800 psi which is still a huge number compared to atmospheric pressure. While the total impulse of the system doesn’t change with different nozzle areas, the peak thrust and burn time vary greatly. One of the benefits of doing air propulsion and the reason it was even considered so seriously is that it should be possible to change the nozzle diameter in flight, allowing thrust to be throttled, making controlled landing easier to control.
t = 0.0u"s";
P = P0 |> u"Pa";
M = V * (P / (R * T)) |> u"kg";
ts = 1u"ms";
df = DataFrame(Thrust=(0 ± 0)u"N", Pressure=P0, Time=0.0u"s", Mass=M);
while M > 0.005u"kg"
# Calculate what is leaving tank
P = minimum([P, Pmax])
ve = sqrt((2 * γ / (γ - 1)) * R * T * (1 - P_amb / P)^((γ - 1) / γ)) |> u"m/s"
ρ = P / (R * T) |> u"kg/m^3"
ṁ = ρ * a_nozzle * ve |> u"kg/s"
Thrust = ṁ * ve + a_nozzle * (P - P_amb) |> u"N"
# Calculate what is still in the tank
M = M - ṁ * ts |> u"kg"
P = (M * R * T) / V |> u"Pa"
t = t + ts
df_step = DataFrame(Thrust=Thrust, Pressure=P, Time=t, Mass=M)
append!(df, df_step)
end
Below in figure 1, the result of the simulation is plotted. Notice the massive error once the tank starts running low. This is because the calculation for pressure has a lot of very uncertain variables. This is primarily due to air being a compressible fluid, making this simulation challenging to do accurately. The thrust being below 0 N might not make intuitive sense, but it’s technically possible for the pressure to compress, leaving the inside of the rocket nozzle with a pressure that’s actually below atmospheric pressure. The effect would likely last a fraction of a second, but the point stands that this simulation is wildly inaccurate and only meant to get an idea of what an air propulsion system is capable of.
thrust_values = df.Thrust .|> ustrip .|> value;
thrust_uncertainties = df.Thrust .|> ustrip .|> uncertainty;
air = DataFrame(Thrust=thrust_values, Uncertainty=thrust_uncertainties, Time=df.Time .|> u"s" .|> ustrip);
plot(df.Time .|> ustrip, thrust_values,
title="Thrust Over Time",
ribbon=(thrust_uncertainties, thrust_uncertainties),
fillalpha=0.2, label="Thrust",
xlabel="Time (s)",
ylabel="Thrust (N)",
)
Air Propulsion Simulation
In Figure 2, the air propulsion simulation is compared to commercially available rocket motors. This early in the project, we have no idea whether short burns or longer burns are ideal for a propulsive landing, so the air propulsion system was compared to a variety of different motors with unique profiles.
f10 = CSV.read("AeroTech_F10.csv", DataFrame);
f15 = CSV.read("Estes_F15.csv", DataFrame);
g8 = CSV.read("AeroTech_G8ST.csv", DataFrame);
plot(air.Time, air.Thrust, label="Air Propulsion", legend=:outertopright);
for (d, l) in [(f10, "F10"), (f15, "F15"), (g8, "G8ST")]
plot!(d[!, "Time (s)"], d[!, "Thrust (N)"], label=l)
end
title!("Propulsion Comparison");
xlabel!("Time (s)");
ylabel!("Thrust (N)")
Rocket Motor Data: (Coker, n.d.)
In the end, the air propulsion system’s performance has a very impressive total impulse and, with more time and resources, could be a serious option for a propulsive landing on Earth. One of the largest abstractions from the Moon mission that the mission here on Earth will have to deal with is the lack of Throttling engines since any propulsion system outside of model rocket motors is well beyond the scope of this Capstone.
After determining that solid model rocket motors are the best option for the current mission scope, the next step is determining what motor to use. There are many great options, and deciding what thrust profile is ideal may have to wait until a Simulink simulation of the landing can be built so that the metrics of each motor can be constrained more. Instead of throttling motors, the current working idea is that thrust vector control may be a way to squeeze a little more control out of a solid rocket motor. Thrust Vector Control will undoubtedly be challenging to control, so another essential piece that needs exploring is whether an LQR controller is feasible or if a PID controller is accurate enough to control our system.
Codebase: https://gitlab.com/lander-team/air-prop-simulation
---
title: "Air Propulsion Simulation"
description: |
Simulating the performance of a compressed air propulsion system as an alternative to solid rocket motors using Julia.
description-meta: |
Simulate air propulsion for lunar mining transport! This project explores using compressed air as an alternative to solid rocket motors. See the Julia simulation results and comparisons with traditional rocket motor performance. Explore the code and learn more about this innovative approach.
repository_url: https://gitlab.com/lander-team/air-prop-simulation
date: 2021-04-01
date-modified: 2024-03-10
categories:
- Julia
- Capstone
- University
- Code
- Aerospace
- Math
creative_commons: CC BY
banner: prop_comp.png
image-alt: A line graph comparing the thrust of different propulsion systems over time. The x-axis represents time in seconds, and the y-axis represents thrust in Newtons. The graph displays the thrust curves for Air Propulsion, F10, F15, and G8ST.
format:
html:
code-tools: true
code-fold: false
execute:
output: false
freeze: true
---
For Capstone my team was tasked with designing a system capable of moving mining equipment and materials around the surface of the Moon using a propulsive landing. The system had to be tested on Earth with something feasible for our team to build in 2 semesters. One of the first considerations my capstone advisor wanted was to test the feasibility of an air propulsion system instead of the obvious solution that of using solid rocket motors. This document is just _napkin math_ to determine if the system is even feasibly and is not meant to be a rigorous study of an air propulsion system that would easily keep a capstone team busy by itself.
```{julia}
#| code-fold: true
#| code-summary: Imports
using Plots
plotlyjs()
using Unitful
using DataFrames
using Measurements
using Measurements: value, uncertainty
using CSV
```
## The Simulation
I chose an off-the-shelf paintball gun tank for the pressure vessel. The primary consideration was the incredible pressure to weight ratio, and the fact that it is designed to be bumped around would be necessary for proving the safety of the system further into the project.
```{julia}
#| code-fold: false
# Tank https://www.amazon.com/Empire-Paintball-BASICS-Pressure-Compressed/dp/B07B6M48SR/
V = (85 ± 5)u"inch^3";
P0 = (4200.0 ± 300)u"psi";
Wtank = (2.3 ± 0.2)u"lb";
Pmax = (250 ± 50)u"psi"; # Max Pressure that can come out the nozzle
```
The nozzle diameter was changed until the air prop system had a _burn time_ similar to a G18ST rocket motor. The propulsion system's total impulse is not dependant on the nozzle diameter, so this was just done to make it plot nicely with the rest of the rocket motors since, at this time, it is unknown what the optimal thrust profile is.
```{julia}
# Params
d_nozzle = ((1 // 18) ± 0.001)u"inch";
a_nozzle = (pi / 4) * d_nozzle^2;
```
These are just universal values for what a typical day would look like during the summer in Northern Arizona. [@cengel_thermodynamics]
```{julia}
# Universal Stuff
P_amb = (1 ± 0.2)u"atm";
γ = 1.4 ± 0.05;
R = 287.05u"J/(kg * K)";
T = (300 ± 20)u"K";
```
The actual simulation is quite simple. The basic idea is that using the current pressure, you can calculate $\dot{m}$, which allows calculating the Thrust, and then you can subtract the current mass of air in the tank by $\dot{m}$ and recalculate pressure using the new mass then repeat the whole process.
The bulk of the equations in the simulation came from [@cengel_thermodynamics], while the Thrust and $v_e$ equations came from [@sutton_rocket_2001, eq: 2-14].
$$ T = \dot{m} \cdot v_\text{Exit} + A_\text{Nozzle} \cdot (P - P_\text{Ambient}) $$
The initial pressure difference is `{julia} P0 - P_amb |> u"psi"`, which is massive, so the area of the nozzle significantly alters the thrust profile. The paintball tanks come with pressure regulators, in our case, 800 psi which is still a huge number compared to atmospheric pressure. While the total impulse of the system doesn't change with different nozzle areas, the peak thrust and _burn time_ vary greatly. One of the benefits of doing air propulsion and the reason it was even considered so seriously is that it should be possible to change the nozzle diameter in flight, allowing thrust to be throttled, making controlled landing easier to control.
```{julia}
t = 0.0u"s";
P = P0 |> u"Pa";
M = V * (P / (R * T)) |> u"kg";
ts = 1u"ms";
df = DataFrame(Thrust=(0 ± 0)u"N", Pressure=P0, Time=0.0u"s", Mass=M);
while M > 0.005u"kg"
# Calculate what is leaving tank
P = minimum([P, Pmax])
ve = sqrt((2 * γ / (γ - 1)) * R * T * (1 - P_amb / P)^((γ - 1) / γ)) |> u"m/s"
ρ = P / (R * T) |> u"kg/m^3"
ṁ = ρ * a_nozzle * ve |> u"kg/s"
Thrust = ṁ * ve + a_nozzle * (P - P_amb) |> u"N"
# Calculate what is still in the tank
M = M - ṁ * ts |> u"kg"
P = (M * R * T) / V |> u"Pa"
t = t + ts
df_step = DataFrame(Thrust=Thrust, Pressure=P, Time=t, Mass=M)
append!(df, df_step)
end
```
## Analysis
Below in figure 1, the result of the simulation is plotted. Notice the massive error once the tank starts running low. This is because the calculation for pressure has a lot of very uncertain variables. This is primarily due to air being a compressible fluid, making this simulation challenging to do accurately. The thrust being below 0 N might not make intuitive sense, but it's technically possible for the pressure to compress, leaving the inside of the rocket nozzle with a pressure that's actually below atmospheric pressure. The effect would likely last a fraction of a second, but the point stands that this simulation is wildly inaccurate and only meant to get an idea of what an air propulsion system is capable of.
```{julia}
#| code-folding: true
#| fig-cap: 'Air Propulsion Simulation'
#| output: true
#| class-output: preview-image
thrust_values = df.Thrust .|> ustrip .|> value;
thrust_uncertainties = df.Thrust .|> ustrip .|> uncertainty;
air = DataFrame(Thrust=thrust_values, Uncertainty=thrust_uncertainties, Time=df.Time .|> u"s" .|> ustrip);
plot(df.Time .|> ustrip, thrust_values,
title="Thrust Over Time",
ribbon=(thrust_uncertainties, thrust_uncertainties),
fillalpha=0.2, label="Thrust",
xlabel="Time (s)",
ylabel="Thrust (N)",
)
```
In Figure 2, the air propulsion simulation is compared to commercially available rocket motors. This early in the project, we have no idea whether short burns or longer burns are ideal for a propulsive landing, so the air propulsion system was compared to a variety of different motors with unique profiles.
```{julia}
#| code-folding: tru
#| fig-cap: "Rocket Motor Data: [@thrustcurve]"
#| output: true
f10 = CSV.read("AeroTech_F10.csv", DataFrame);
f15 = CSV.read("Estes_F15.csv", DataFrame);
g8 = CSV.read("AeroTech_G8ST.csv", DataFrame);
plot(air.Time, air.Thrust, label="Air Propulsion", legend=:outertopright);
for (d, l) in [(f10, "F10"), (f15, "F15"), (g8, "G8ST")]
plot!(d[!, "Time (s)"], d[!, "Thrust (N)"], label=l)
end
title!("Propulsion Comparison");
xlabel!("Time (s)");
ylabel!("Thrust (N)")
```
In the end, the air propulsion system's performance has a very impressive total impulse and, with more time and resources, could be a serious option for a propulsive landing on Earth. One of the largest abstractions from the Moon mission that the mission here on Earth will have to deal with is the lack of Throttling engines since any propulsion system outside of model rocket motors is well beyond the scope of this Capstone.
## Future Work
After determining that solid model rocket motors are the best option for the current mission scope, the next step is determining what motor to use. There are many great options, and deciding what thrust profile is ideal may have to wait until a Simulink simulation of the landing can be built so that the metrics of each motor can be constrained more. Instead of throttling motors, the current working idea is that thrust vector control may be a way to squeeze a little more control out of a solid rocket motor. Thrust Vector Control will undoubtedly be challenging to control, so another essential piece that needs exploring is whether an LQR controller is feasible or if a PID controller is accurate enough to control our system.
Codebase: [https://gitlab.com/lander-team/air-prop-simulation](https://gitlab.com/lander-team/air-prop-simulation)