download
raw
4.51 kB
"""
Implementation of the functions to compute and plot the flight path of the
phugoid using Lanchester's mode.
The implementation uses the sign convention and formula provided by
Milne-Thomson (1958).
"""
import numpy
from matplotlib import pyplot
# Ignore over/underflow errors that pop up in the `radius_of_curvature`
# function.
# (See http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html
# for more explanations.)
numpy.seterr(all='ignore')
def radius_of_curvature(z, zt, C):
"""
Returns the radius of curvature of the flight path at any point.
Parameters
----------
z : float
Current depth below the reference horizontal line.
zt : float
Initial depth below the reference horizontal line.
C : float
Constant of integration.
Returns
-------
radius : float
Radius of curvature.
"""
return zt / (1 / 3 - C / 2 * (zt / z)**1.5)
def rotate(coords, center=(0.0, 0.0), angle=0.0, mode='degrees'):
"""
Rotates a point or an array of points
by a given angle around a given center point.
Parameters
----------
coords :tuple
Current x and z positions of the point(s)
as a tuple of two floats or a tuple of two 1D arrays of floats.
center : tuple, optional
Center of rotation (x, z) as a tuple of two floats;
default: (0.0, 0.0).
angle : float, optional
Angle of rotation;
default: 0.0.
mode : string, optional
Set if angle given in degrees or radians;
choices: ['degrees', 'radians'];
default: 'degrees'.
Returns
-------
x_new : float or numpy.ndarray
x position of the rotated point(s)
as a single float or a 1D array of floats.
z_new : float or numpy.ndarray
z position of the rotated point(s)
as a single float or a 1D array of floats.
"""
x, z = coords
xc, zc = center
if mode == 'degrees':
angle = numpy.radians(angle)
x_new = xc + (x - xc) * numpy.cos(angle) + (z - zc) * numpy.sin(angle)
z_new = zc - (x - xc) * numpy.sin(angle) + (z - zc) * numpy.cos(angle)
return x_new, z_new
def plot_flight_path(zt, z0, theta0, N=1000):
"""
Plots the flight path of the glider.
Parameters
----------
zt : float
Trim height of the glider.
z0 : float
Initial height of the glider.
theta0 : float
Initial orientation of the glider (in degrees).
N : integer, optional
Number of points used to discretize the path;
default: 1000.
"""
# Convert initial angle to radians.
theta0 = numpy.radians(theta0)
# Create arrays to store the coordinates of the flight path.
x, z = numpy.zeros(N), numpy.zeros(N)
# Set initial conditions.
x[0], z[0], theta = 0.0, z0, theta0
# Calculate the constant of integration C.
C = (numpy.cos(theta) - 1 / 3 * z[0] / zt) * (z[0] / zt)**0.5
# Set incremental distance along the flight path.
ds = 1.0
# Calculate coordinates along the path.
for i in range(1, N):
# We use a minus sign for the second coordinate of the normal vector
# because the z-axis points downwards.
normal = numpy.array([+ numpy.cos(theta + numpy.pi / 2.0),
- numpy.sin(theta + numpy.pi / 2.0)])
# Get curvature radius and compute center of rotation.
R = radius_of_curvature(z[i - 1], zt, C)
center = numpy.array([x[i - 1], z[i - 1]]) + R * normal
# Set angular increment.
dtheta = ds / R
# Calculate new position and update angle.
x[i], z[i] = rotate((x[i - 1], z[i - 1]),
center=center, angle=dtheta, mode='radians')
theta += dtheta
# Set the font family and size to use for Matplotlib figures.
pyplot.rcParams['font.family'] = 'serif'
pyplot.rcParams['font.size'] = 16
# Create Matplotlib figure.
fig, ax = pyplot.subplots(figsize=(9.0, 4.0))
ax.grid()
ax.set_title(f'Flight path for $C={C:.3f}$\n' +
rf'($z_t={zt:.1f}$, $z_0={z0:.1f}$, ' +
rf'$\theta_0={numpy.degrees(theta0):.1f}^o$)')
ax.set_xlabel(r'$x$')
ax.set_ylabel(r'$z$')
ax.plot(x, -z, linestyle='-', linewidth=2.0)
ax.set_aspect('equal', adjustable='box')
pyplot.show()

Xet Storage Details

Size:
4.51 kB
·
Xet hash:
736ac20a51ce52ca0a75f207ec9ed0ef1381d1ad6a73fb7968aa740435ef196f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.