# this line makes figures interactive in Jupyter notebooks
%matplotlib inline
from matplotlib import pyplot as pltNotebook Cell
# these lines are only for helping improve the display
import matplotlib_inline.backend_inline
matplotlib_inline.backend_inline.set_matplotlib_formats('pdf', 'png')
plt.rcParams['figure.dpi']= 300
plt.rcParams['savefig.dpi'] = 300
plt.rcParams['mathtext.fontset'] = 'cm'Thrust¶
In the last module, the expression for thrust from a rocket (or any propulsion system relying on an exhaust jet) was given. Let’s now derive that, by considering a rocket undergoing a static test fire (where it is held in place by a test stand that counteracts the thrust force).
Let’s draw a control surface just around the rocket, with the exhaust jet crossing the boundary at the exit of hte nozzle, and apply conservation of momentum in the horizontal direction:
where the reaction force imparted by the test stand (to hold the rocket in place) is the same as the thrust force: . Then, for thrust, we have:
where refers to the momentum flux thrust and refers to the pressure thrust terms. If , or the nozzle is overexpanded, then the pressure thrust is negative and reduces the overall thrust. Typically, though, nozzles are designed such that .
In the vacuum of space (or near-vacuum),
Effective exhaust velocity¶
The effective exhaust velocity, , is defined as the actual thrust divided by the mass flow rate:
This allows us to express thrust as
and we can relate effective exhaust velocity to specific impulse:
The rocket equation¶
We now have an expression for thrust of a rocket, considering static firing on a test stand. What about a rocket in motion, which is continuously exhausting propellant mass to generate thrust? If we apply Netwon’s second law, we can obtain the Tsiolkovsky rocket equation.
Consider a rocket in motion in some arbitrary flight direction, where we assume
thrust in the direction of flight (no thrust vectoring)
steady thrust, and
no lift generated by the rocket body.
Applying Newton’s second law:
where the subscript indicates in the direction of flight, and
where the subscript indicates in the direction normal to flight. Now, let’s insert our expression for thrust into Equation (7), and recall that the rate of change of the rocket’s mass is related to the mass flow rate of exhausting propellant: :
We can integrate this from time to any time , or the burnout time when the rocket stops thrusting and no longer exhausts propellant:
or, to obtain Tsiolkovsky’s rocket equation:
where refers to the initial vehicle mass, refers to the final vehicle mass at time , and in general drag force, gravity, and flight direction may vary with time: , , and .
If we neglect the gravity and drag terms, we can simplify:
and, we can define the rocket mass ratio ( or MR):
In addition, recalling the definition of effective exhaust velocity :
which is the famous form of the rocket equation. This relates specific impulse of the propulsion system (which comes from propellant choice), mass ratio of the rocket, and the resulting total change in velocity, which is driven by mission requirements.
Example: Numerical integration of vertical launch¶
Determine the burnout velocity and maximum height achieved by launching the German V-2 rocket, assuming a vertical launch. Take into account drag, the variation of atmospheric density with altitude, and the variation of gravity with altitude. Use a forward difference numerical scheme (i.e., forward Euler) to solve the system of equations.
Given data:
specific impulse: = 250 sec
initial mass: = 12700 kg
propellant mass: = 8610 kg
burn time: = 60 sec
maximum body diameter: = 5 feet 4 inches (5.333 ft)
height: = 46 feet
Figure 1 shows how the coefficients of lift and drag vary with Mach number and angle of attack.

Figure 1:Variation of coefficients of drag and lift with Mach number and angle of attack, for the German V-2 rocket. Source: Sutton & Biblarz (2016).
Let’s set up the system of ordinary differential equations for velocity (), altitude (), and mass () that describes this problem:
where we obtained the last equation by recognizing that
for steady burning. In the above, is the reference acceleration due to gravity (9.80065 m/s2), is the atmospheric density, is the cross-sectional area of the body, is the drag coefficient, and is the (varying) acceleration due to gravity.
Density and gravity: To move forward, we need to describe how to evaluate density, gravitational acceleration, and the coefficient of drag at any instant in time. The first two are known functions of altitude:
where = 1.225 kg/m3 is the density at sea level, = 10.4 km is the height scale of the exponential fall, = 6378.388 km is the mean radius of Earth, and = 9.80665 m/s2 is the sea-level acceleration due to gravity.
Coefficient of drag¶
Coefficient of drag is more difficult to handle, since it depends on angle of attack and Mach number: . For vertical flight, the angle of attack is zero (), but the Mach number will be changing both as the vehicle speed changes and the atmospheric conditions change with altitude:
Option 1: As a first approximation, we could simply assume a constant value for coefficient of drag. For example, before and after the transonic regime (where Mach number approaches 1), .
Option 2: If we want to more-accurately capture the increase in coefficient of drag as the vehicle approaches a sonic velocity, and then the relaxation when supersonic, we need to capture the dependence of on Mach number.
First, we already have an expression for , but we also need an expression for pressure. We can use a similar exponential approximation:
where = 101325 Pa is the sea-level standard atmospheric pressure and = 8.4 km. With being a reasonable constant, we can now calculate Mach number based on velocity and altitude.
Now, we need to obtain a functional dependence of ; based on Figure 1, we see that the relationship is fairly complex. The “easiest” way to create a function for is to:
Extract data points from the plot manually, using a tool such as WebPlotDigitizer
Perform a spline interpolation on the data points, using a function such as
splinein Matlab orscipy.interpolate.UnivariateSplinein Python.
Let’s see this in action, using data extracted manually from the source figure:
import numpy as np
from scipy.interpolate import UnivariateSpline
data = np.genfromtxt('coefficient-drag.csv', delimiter=',')
coefficient_drag = UnivariateSpline(data[:,0], data[:,1], s=0, ext='const')
mach = np.linspace(0.2, 6, num=200, endpoint=True)
plt.plot(data[:,0], data[:,1], 'o', mach, coefficient_drag(mach), '-')
plt.xlabel('Mach number')
plt.ylabel('Coefficient of drag')
plt.legend(['Data', 'Cubic spline'])
plt.show()In Matlab, the equivalent fit can be done with:
data = readmatrix('coefficient-drag.csv');
plot(data(:,1), data(:,2), 'o'); hold on
coef_drag = spline(data(:,1), data(:,2));
xx = linspace(0.2, 5, 500);
plot(xx, ppval(coef_drag,xx), '-');Now that we have a fully defined system of equations, we need a numerical method to integrate.
We can first use a forward difference scheme, also known as the forward Euler method:
where is the vector of state variables at time , is the time step size, and represents the vector of time derivatives.
To implement, we need to create a function to evaluate the time derivatives, and then specify initial conditions for velocity, altitude, and mass: , , and .
from scipy.integrate import solve_ivp
def vertical_launch(t, y, spec_impulse, mass_prop, time_burn, diameter, coef_drag):
'''Evaluates system of time derivatives for velocity, altitude, and mass.
'''
radius_earth = 6378.388 * 1e3
gravity_ref = 9.80665
density_ref = 1.225
pressure_ref = 101325
gamma = 1.4
height_den = 10400
height_pres = 8400
v = y[0]
h = y[1]
m = y[2]
gravity = gravity_ref * (radius_earth / (radius_earth + h))**2
density = density_ref * np.exp(-h / height_den)
pressure = pressure_ref * np.exp(-h / height_pres)
mach = v / np.sqrt(gamma * pressure / density)
area = np.pi * diameter**2 / 4
drag = 0.5 * density * v**2 * area * coef_drag(mach)
dmdt = -mass_prop / time_burn
dvdt = (-spec_impulse * gravity_ref / m) * dmdt - drag / m - gravity
dhdt = v
return [dvdt, dhdt, dmdt]
# given constants
spec_impulse = 250
mass_initial = 12700
mass_propellant = 8610
time_burn = 60
diameter = 1.626
sol = solve_ivp(
vertical_launch, [0, time_burn], [0, 0, mass_initial], method='RK45',
args=(spec_impulse, mass_propellant, time_burn, diameter, coefficient_drag),
dense_output=True
)time = np.linspace(0, time_burn, 100)
z = sol.sol(time)
fig, axes = plt.subplots(2, 1)
axes[0].plot(time, z[0, :])
axes[0].set_ylabel('Velocity (m/s)')
axes[0].grid(True)
axes[1].plot(time, z[1, :] / 1000)
axes[1].set_ylabel('Altitude (km)')
axes[1].set_xlabel('Time (s)')
axes[1].grid(True)
plt.show()
print(f'Burnout velocity: {z[0,-1]: 5.2f} m/s')
print(f'Burnout altitude: {z[1,-1]/1000: 5.2f} km')Burnout velocity: 1956.11 m/s
Burnout altitude: 44.54 km
In Matlab, the above could be done with:
clear; clc;
g0 = 9.80665;
Re = 6378.388 * 1e3;
Isp = 250;
m0 = 12700;
mp = 8610;
tb = 60;
D = 1.626;
data = readmatrix('coefficient-drag.csv');
plot(data(:,1), data(:,2), 'o'); hold on
coef_drag = spline(data(:,1), data(:,2));
xx = linspace(0.2, 5, 500);
plot(xx, ppval(coef_drag,xx), '-');
f = @(t,z) rocket(t, z, Isp, mp, tb, D, coef_drag);
[T, Z] = ode45(f, [0 tb], [0 0 m0]);
function dzdt = rocket(t, z, Isp, mp, tb, D, coef_drag)
g0 = 9.80665; Re = 6378.388 * 1e3;
mdot = mp / tb;
v = z(1);
h = z(2);
m = z(3);
g = g0 * (Re / (Re + h))^2;
rho0 = 1.225;
p0 = 101325;
Hn = 10400;
Hp = 8400;
gamma = 1.4;
rho = rho0 * exp(-h / Hn);
pres = p0 * exp(-h / Hp);
area = pi * D^2 / 4;
M = v / sqrt(gamma * pres / rho);
C_D = ppval(coef_drag, M);
drag = 0.5 * rho * v^2 * area * C_D;
dzdt = zeros(3,1);
dzdt(3) = -mdot;
dzdt(1) = (-Isp*g0/m)*dzdt(3) - drag/m - g;
dzdt(2) = v;
end- Sutton, G. P., & Biblarz, O. (2016). Rocket Propulsion Elements (9th ed.). John Wiley & Sons.