Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Phugoid Motion

In the first module of “Practical Numerical Methods” we study problems modeled by ordinary differential equations.

Our motivating problem is the phugoid model of glider flight. In this first lesson, we discuss some background, explain the physics, and work out the mathematical model.

We first consider the idealized model with no drag, resulting in a simple harmonic motion. We can plot some interesting trajectories of a glider under phugoid oscillations. In the next lesson, you’ll learn to numerically integrate the differential equation using Euler’s method.

The term phugoid in aeronautics refers to a motion pattern where an aircraft oscillates up and down —nose-up and climb, then nose-down and descend— around an equilibrium trajectory. The aircraft oscillates in altitude, speed and pitch, with only small (neglected) variations in the angle of attack, as it repeatedly exchanges kinetic and potential energy Sinha & Ananthkrishnan, 2013, chap. 5.

A low-amplitude phugoid motion can be just a nuisance, as the aircraft does not exceed the stall angle of attack and nothing bad happens. But the mode can also be unstable leading to a stall or even a loop.

Look at this video of a simulator showing a Cessna single-engine airplane in phugoid motion:

from IPython.display import YouTubeVideo
YouTubeVideo('ysdU4mnRYdM')

That doesn’t look too good! What’s happening?

It can get a lot worse when an aircraft enters one of these modes that is unstable. A famous example is that of NASA’s Helios Solar Powered Aircraft prototype, which broke up in mid air due to extreme phugoid oscillations.

Helios was a proof-of-concept solar electric-powered flying wing that broke the world altitude record for a non-rocket-powered aircraft in August 2001. But in June 26, 2003, it broke something else. The aircraft entered phugoid motion after encountering turbulence near the Hawaiian Island of Kauai. The high speed reached in the oscillations exceeded the design limits, and it ended up wrecked in the Pacific Ocean. Luckily, the Helios was remotely operated, and nobody got hurt.

The physics of phugoids

In a phugoid oscillation the aircraft pitches up and down, as it decelerates and accelerates. The trajectory might look like a sinusoid, as shown in Figure 1. The assumption is that the forward velocity of the aircraft, vv, varies in such a way that the angle of attack remains (nearly) constant, which means that we can assume a constant lift coefficient.

A sinusoidal trajectory showing an aircraft oscillating above and below a central flight path

Figure 1:Trajectory of an aircraft in phugoid motion.

In the descending portion of the trajectory, the aircraft’s velocity increases as it proceeds from a peak to the minimum height—gaining kinetic energy at the expense of potential energy. The contrary happens in the upward segment, as its velocity decreases there.

We measure the pitch angle (between the aircraft’s longitudinal axis and the horizontal) as positive when the aircraft’s nose is pointing up. In the portion of the trajectory below the center-line, where it curves upwards, the pitch angle θ\theta is increasing: θ˙>0\dot{\theta}>0. And where the trajectory curves down, the pitch angle is decreasing: θ˙<0\dot{\theta}<0, as shown in Figure 1.

Let’s review the forces affecting an aircraft in a downward glide. In Figure 2, we show the flight path, the forces on the glider (no thrust), and the glide angle or flight path angle, γ\gamma, between the flight path and the horizontal.

Lift, drag, and weight acting on a glider along a descending flight path

Figure 2:Forces on a glider.

The force of lift, LL —created by the airflow around the wings— is perpendicular to the trajectory, and the force of drag, DD, is parallel to the trajectory. Both forces are expressed in terms of coefficients of lift and drag, CLC_L and CDC_D, respectively, that depend on the wing design and angle of attack: the angle between the wing chord and the flight path.

If you are not familiar with airplane aerodynamics, you might be getting confused with some terms here ... and all those angles! But be patient and look things up, if you need to. We’re giving you a quick summary here.

Lift and drag are proportional to a surface area, SS, and to the dynamic pressure: 1/2ρv21/2 \rho v^2, where ρ\rho is the density of air, and vv the forward velocity of the aircraft. The equations for lift and drag are:

L=CLS×12ρv2L = C_L S \times \frac{1}{2} \rho v^2
D=CDS×12ρv2D = C_D S \times \frac{1}{2} \rho v^2

When the glider is in equilibrium, the forces balance each other. We can equate the forces in the directions perpendicular and parallel to the trajectory, as follows:

L=WcosγandD=WsinγL = W \cos \gamma \quad \text{and} \quad D = W \sin \gamma

where WW represents the weight of the glider.

In the figure, we’ve drawn the angle γ\gamma as the glide angle, formed between the direction of motion and the horizontal. We are not bothered with the sign of the angle, because we draw a free-body diagram and take the direction of the forces into account in writing our balance equations. But later on, we will need to be careful with the sign of the angles. It can cause you a real headache to keep this straight, so be patient!

Below, we will develop the mathematical model step-by-step. But before, a short glimpse of the history.

Lanchester’s Aerodonetics

“Phugoid theory” was first described by the British engineer Frederick W. Lanchester in Aerodonetics Lanchester, 1908. The book is now in the public domain, so you can read or download it from the Internet Archive.

Lanchester defines phugoid theory as the study of longitudinal stability of a flying machine (aerodone). He first considered the simplification where drag and moment of inertia are neglected. Then he included these effects, obtaining an equation of stability. In addition to describing many experiments by himself and others, Lanchester also reports on “numerical work ... done by the aid of an ordinary 25-cm slide rule” Lanchester, 1908. Go figure!

Ideal case of zero drag

In this section, we follow the derivation given by Milne-Thomson (1966, sec. 18.5), which we find a little bit easier than that of the original in “Aerodonetics.”

An aircraft flying in steady, straight horizontal flight has a lift equal to its weight. The velocity in this condition is sometimes called trim velocity (“trim” is what pilots do to set the controls to just stay in a steady flight). Let’s use vtv_t for the trim velocity, and from L=WL=W deduce that:

W=CLS×12ρvt2W = C_L S \times\frac{1}{2} \rho v_t^2

The weight WW is constant for the aircraft, but the lift at any other flight condition depends on the flight speed, vv. We can use the expression for the weight in terms of vtv_t to obtain the ratio L/WL/W at any other flight velocity, as follows:

LW=v2vt2\frac{L}{W}= \frac{v^2}{v_t^2}

Imagine that the aircraft experienced a little upset, a wind gust, and it finds itself off the “trim” level, in a curved path with an instantaneous angle θ\theta. In Figure 3, we exaggerate the curved trajectory of flight to help you visualize what we’ll do next. The angle θ\theta (using the same name as Milne-Thompson) is between the trajectory and the horizontal, positive up.

Curved upward trajectory of an aircraft with lift and weight vectors

Figure 3:Curved trajectory of an aircraft climbing with no drag.

Free-body diagram showing lift, weight, and normal and tangential directions

Figure 4:Free-body diagram of the aircraft trajectory.

From Figure 4, we can see that

L+W=ma=mv2Rn^+mdvdtt^\vec{L} + \vec{W} = m\vec{a} = \frac{mv^2}{R}\hat{n} + m \frac{dv}{dt}\hat{t}

where v2R\frac{v^2}{R} is the centripetal acceleration and RR is the radius of curvature of the trajectory. If we decompose the lift and weight into their normal and tangential components we get

Ln^+Wnn^+Wtt^=mv2Rn^+mdvdtt^L\hat{n} + W_n\hat{n} + W_t\hat{t} = \frac{mv^2}{R}\hat{n} + m \frac{dv}{dt}\hat{t}

The component of the weight in the normal direction (WnW_n) is

Wn=WcosθW_n = -W \cos \theta

If we then consider that all of the components in n^\hat{n} must balance out, we arrive at

LWcosθ=mv2RL - W \cos \theta = \frac{mv^2}{R}

We can rewrite this as

LWcosθ=Wgv2RL- W \cos \theta = \frac{W}{g} \frac{v^2}{R}

where gg is the acceleration due to gravity. Rearrange this by dividing the equation by the weight, and use the expression we found for L/WL/W, above. The following equation results:

v2vt2cosθ=v2gR\frac{v^2}{v_t^2}-\cos \theta = \frac{v^2}{g R}

Recall that we simplified the problem assuming that there is no friction, which means that the total energy is constant (the lift does no work). If zz represents the depth below a reference horizontal line, the energy per unit mass is (kinetic plus potential energy):

12v2gz=constant\frac{1}{2}v^2-g z = \text{constant}

To get rid of that pesky constant, we can choose the reference horizontal line at the level that makes the constant energy equal to zero, so v2=2gzv^2 = 2 g z. That helps us re-write the phugoid equation in terms of zz as follows:

zztcosθ=2zR\frac{z}{z_t}-\cos \theta = \frac{2z}{R}

Let dsds represent a small arc-length of the trajectory. We can write

1R=dθdsandsinθ=dzds\frac{1}{R} = \frac{d\theta}{ds} \quad \text{and}\quad \sin\theta = -\frac{dz}{ds}

Employing the chain rule of calculus,

1R=dθds=dzdsdθdz=sinθdθdz\frac{1}{R} = \frac{d\theta}{ds} = \frac{dz}{ds}\frac{d\theta}{dz} = -\sin \theta\frac{d\theta}{dz}

Multiply the phugoid equation by 12z\frac{1}{2\sqrt{z}} to get:

z2ztcosθ2z=zR\frac{\sqrt{z}}{2z_t} - \frac{\cos\theta}{2\sqrt{z}} = \frac{\sqrt{z}}{R}

Substituting for 1/R1/R on the right hand side and bringing the cosine term over to the right, we get:

z2zt=cosθ2zzsinθdθdz\frac{\sqrt{z}}{2z_t} = \frac{\cos \theta}{2 \sqrt{z}} - \sqrt{z} \sin \theta \frac{d\theta}{dz}

The right-hand-side is an exact derivative! We can rewrite it as:

ddz(zcosθ)=z2zt\frac{d}{dz} \left(\sqrt{z}\cos\theta \right) = \frac{\sqrt{z}}{2z_t}

Integrating this equation, we add an arbitrary constant, chosen as CztC\sqrt{z_t} which (after dividing through by z\sqrt{z}) gives:

cosθ=13zzt+Cztz\cos \theta = \frac{1}{3}\frac{z}{z_t} + C\sqrt{\frac{z_t}{z}}

Taking the derivative of both sides of Equation 19 and applying the relation in Equation 15 yields:

ztR=13C2zt3z3\frac{z_t}{R} = \frac{1}{3} - \frac{C}{2}\sqrt{\frac{z_t^3}{z^3}}

Phugoid Curves

Equation 19 is nonlinear, so we are hard-pressed to write a clean expression for the complete path z(x)z(x). Lanchester said that he was unable to “reduce this expression to a form suitable for co-ordinate plotting.” Instead, he devised what he called the “trammel” method. His explanation begins on page 48 of Aerodonetics Lanchester, 1908, p. 48.

Lanchester used Equation 19 to calculate the integration constant CC and Equation 20 to calculate the local radius of curvature RR, then constructed the trajectory as a succession of small circular arcs—by hand.

We will now reproduce that process computationally. We will use this exercise explicitly as a Python refresher while we explore the simplest, zero-drag phugoid model.

If your Python is rusty, take time with the reminders and reconstruct one small step at a time in your own notebook. If you are already an experienced programmer, focus on how the mathematics becomes a small set of explicit functions, how computation is separated from plotting, and where we check the model’s domain instead of hiding numerical warnings.

The computational idea is simple: start from an initial point and angle, take a short step of arc length dsds, calculate the local circle from RR, rotate the point around that circle, and repeat.

Computational interlude: Python refresher

We need two widely used scientific-Python packages: NumPy for numerical functions and arrays, and Matplotlib for plotting.

import numpy as np
import matplotlib.pyplot as plt

Translate the equations into functions

First, solve Equation 19 for CC at a known point (z,θ)(z,\theta):

C=(cosθz3zt)zzt.C = \left(\cos\theta - \frac{z}{3z_t}\right)\sqrt{\frac{z}{z_t}}.

Equation 20 gives the corresponding signed radius of curvature:

R=zt13C2(ztz)3/2.R = \frac{z_t}{\frac{1}{3} - \frac{C}{2}\left(\frac{z_t}{z}\right)^{3/2}}.

The next cell translates those equations almost literally.

Both zz and ztz_t represent positive depths. We check that assumption explicitly. A zero denominator in the second equation means a straight path with infinite radius, represented by np.inf.

def integration_constant(z, z_t, theta):
    '''Return the integration constant C; theta is in radians.'''
    if z <= 0.0 or z_t <= 0.0:
        raise ValueError("z and z_t must be positive.")
    return (np.cos(theta) - z / (3.0 * z_t)) * np.sqrt(z / z_t)


def radius_of_curvature(z, z_t, C):
    '''Return the signed local radius of curvature.'''
    if z <= 0.0 or z_t <= 0.0:
        raise ValueError("z and z_t must be positive.")
    denominator = 1.0 / 3.0 - C / 2.0 * (z_t / z)**1.5
    if np.isclose(denominator, 0.0):
        return np.inf
    return z_t / denominator

Let’s evaluate the two functions at one initial condition. Angles may be convenient to specify in degrees, but NumPy’s trigonometric functions expect radians, so we convert at the boundary between user input and computation.

A signed RR records which side of the trajectory contains the center of curvature; its magnitude is the geometric radius.

z_t = 64.0
z_0 = 16.0
theta_0_degrees = 0.0
theta_0 = np.deg2rad(theta_0_degrees)

C = integration_constant(z_0, z_t, theta_0)
R_0 = radius_of_curvature(z_0, z_t, C)

print(f"C = {C:.3f}")
print(f"Initial signed radius R = {R_0:.3f}")
assert 0.0 < C < 2.0 / 3.0

Rotate one point around a local circle

To follow one short circular arc, we rotate the current point (x,z)(x,z) about the center of curvature. The formula below is a standard two-dimensional rotation written for the sign convention used in our diagram.

def rotate_point(x, z, center, angle):
    '''Rotate the point (x, z) about center by angle radians.'''
    x_center, z_center = center
    dx, dz = x - x_center, z - z_center

    x_new = x_center + dx * np.cos(angle) + dz * np.sin(angle)
    z_new = z_center - dx * np.sin(angle) + dz * np.cos(angle)
    return x_new, z_new

March along the trajectory

We now have the pieces needed to imitate Lanchester’s trammel. The function below repeatedly calculates RR, locates the center of curvature, and rotates the current point through the small angle dθ=ds/Rd\theta=ds/R.

Notice two model-aware branches. An infinite radius produces a straight segment. Also, the ideal formula assumes positive depth zz; rather than suppressing warnings after leaving that domain, we stop the trace before zz becomes non-positive.

Read this code carefully and convince yourself that it matches our model.

def trace_phugoid(z_t, z_0, theta_0, n_steps=1000, ds=1.0):
    '''Trace a zero-drag phugoid; theta_0 is supplied in degrees.'''
    if n_steps < 2:
        raise ValueError("n_steps must be at least 2.")

    theta = np.deg2rad(theta_0)
    C = integration_constant(z_0, z_t, theta)
    if C > 2.0 / 3.0 + 1e-12:
        raise ValueError("These initial conditions give C > 2/3.")

    x_values = [0.0]
    z_values = [z_0]

    for _ in range(n_steps - 1):
        x_current, z_current = x_values[-1], z_values[-1]
        R = radius_of_curvature(z_current, z_t, C)

        if np.isinf(R):
            dtheta = 0.0
            x_new = x_current + ds * np.cos(theta)
            z_new = z_current - ds * np.sin(theta)
        else:
            normal = np.array([-np.sin(theta), -np.cos(theta)])
            center = np.array([x_current, z_current]) + R * normal
            dtheta = ds / R
            x_new, z_new = rotate_point(
                x_current, z_current, center, dtheta
            )

        if z_new <= 0.0:
            break

        x_values.append(x_new)
        z_values.append(z_new)
        theta += dtheta

    return np.asarray(x_values), np.asarray(z_values), C

Keep plotting separate from computation

The trajectory function returns numerical data without deciding how it must be displayed. A second, smaller function handles the plot. This separation lets us inspect, test, or reuse the coordinates without producing a figure every time.

Our coordinate zz is depth measured positive downward, so the plot uses z-z to show upward displacement in the familiar direction.

def plot_flight_path(x, z, C):
    '''Plot a previously computed phugoid trajectory.'''
    fig, ax = plt.subplots(figsize=(9.0, 4.0))
    
    ax.plot(x, -z, linewidth=2.0)
    ax.set_title(f"Flight path for C = {C:.3f}")
    ax.set_xlabel(r"$x$")
    ax.set_ylabel(r"$-z$")
    ax.grid()
    ax.set_aspect("equal", adjustable="box")
    return fig, ax

Explore the family of phugoid curves

Look again at Equation 19. The value of CC organizes the possible paths:

  • C>2/3C>2/3 gives no physical solution because it would require cosθ>1\cos\theta>1.

  • C=2/3C=2/3 gives the horizontal straight path: θ=0\theta=0 and R=R=\infty.

  • 0<C<2/30<C<2/3 gives trochoidal-like paths.

  • C<0C<0 can give paths containing loops.

  • C=0C=0 makes R=3ztR=3z_t, a constant.

First choose conditions that give 0<C<2/30<C<2/3. Before running the cell, predict the sign of the initial curvature and the general shape of the path.

x, z, C = trace_phugoid(z_t=64.0, z_0=16.0, theta_0=0.0)
fig, ax = plot_flight_path(x, z, C)

The calculated value is C0.458C\approx0.458, between 0 and 2/32/3, and the path is trochoidal as predicted.

Now keep the two depths fixed but reverse the initial direction to 180180^\circ. What sign do you predict for CC? What new feature should appear in the path?

x, z, C = trace_phugoid(z_t=64.0, z_0=16.0, theta_0=180.0)
fig, ax = plot_flight_path(x, z, C)

The negative value of CC produces loops. Experiment by changing one input at a time and predicting the result before you run the cell again.

For a more experienced Python programmer, this is also a useful design question: which conditions belong in input validation, which are mathematical limiting cases, and which should eventually become automated tests?

For C=0C=0, Equation 20 reduces to

R=3zt.R=3z_t.

The radius is constant. Setting z0=3ztz_0=3z_t and θ0=0\theta_0=0 forces C=0C=0. Our ideal model is defined only for z>0z>0, so the tracer follows the circular arc until just before it reaches the reference level.

x, z, C = trace_phugoid(z_t=16.0, z_0=48.0, theta_0=0.0)
fig, ax = plot_flight_path(x, z, C)

The result is a quarter-circle arc with radius 48=3zt48=3z_t. We can obtain an almost semicircular path from another configuration where CC is close to zero:

x, z, C = trace_phugoid(z_t=64.0, z_0=16.0, theta_0=-90.0)
fig, ax = plot_flight_path(x, z, C)

We have reproduced trajectories that Lanchester painstakingly constructed by hand with his trammel. Along the way, we refreshed imports, function definitions, assignments, tuples, lists, arrays, loops, conditionals, exceptions, formatted strings, and object-oriented plotting.

More importantly, every code element corresponds to a modeling choice: the sign convention, the domain z>0z>0, the local radius, and the discrete arc-length step. Python is the medium, but the computational argument comes from the model.

Figure 5 reproduces the phugoid curves from von Kármán’s Aerodynamics. He never says how he drew them, but we’re guessing by hand, too. We did pretty well!

A family of looping and cusped phugoid trajectories

Figure 5:Phugoid curves in von Kármán’s Aerodynamics Kármán, 1954, pp. 149–151.

This trammel algorithm marched geometrically along the trajectory in increments of arc length dsds. In the next lesson, we will derive the differential equation for a small perturbation of the horizontal phugoid and march a dynamical state forward in time using Euler’s method. The same computational patterns—state, steps, loops, updates, and inspection—will reappear in a new numerical setting.

References
  1. Sinha, N. K., & Ananthkrishnan, N. (2013). Elementary Flight Dynamics with an Introduction to Bifurcation and Continuation Methods. CRC Press. https://books.google.com/books?id=yXL6AQAAQBAJ
  2. Lanchester, F. W. (1908). Aerodonetics: Constituting the Second Volume of a Complete Work on Aerial Flight. A. Constable. https://archive.org/details/aerodoneticscon02lancgoog
  3. Milne-Thomson, L. M. (1966). Theoretical Aerodynamics (4th ed.). Macmillan. https://books.google.com/books?id=EMfCAgAAQBAJ
  4. von Kármán, T. (1954). Aerodynamics: Selected Topics in the Light of Their Historical Development. Cornell University Press.