Time Space Position Information (Tspi) Data Reduction
Time Space Position Information (Tspi) Data Reduction
Peter P. Eiserloh
Code 525300D
Data Production Branch
Electronic Combat Range
Naval Air Warfare Center
China Lake, CA 93555
ABSTRACT
Flight testing of aircraft, and the accuracy of airborne sensors requires a source
of truth data which can be compared against the on-board data. This Time Space
and Position Information (TSPI) data needs to be post-processed and merged
with the aircraft data.
This paper describes some of the issues and techniques used to perform this data
merging. In particular, details of the coordinate transfer from the TSPI reference
point to the aircraft is discussed, along with the format of various TSPI files.
2
Contents
Table of Contents i
PREFACE v
ACKNOWLEDGMENTS vii
1 Introduction 1
1.1 The Basic Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 The World Geodetic System - 84 (WGS–84) . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Heights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 Coordinate Transforms 7
2.1 ENU –VICE– NED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 CDU2NED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 RAE2NED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 LLH2EFG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.5 EFG2LLH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.5.1 LONGITUDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.5.2 LATITUDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5.3 HEIGHT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.6 NED2EFG Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.6.1 Deriving the NED TO EFG Rotation Matrix . . . . . . . . . . . . . . . . . . . . . . 13
2.6.2 Testing the NED TO EFG Rotation Matrix . . . . . . . . . . . . . . . . . . . . . . 15
2.6.3 The RIPS Rotation Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.7 EFG2NED Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
i
ii CONTENTS
5 FILE FORMATS 23
5.1 INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.2 COMMON TEST DATA FORMAT (CTDF) . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.2.1 RATIONAL & OVERVIEW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.2.2 General Information Record (G) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5.2.3 Parameter Identification Record (P) . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5.2.4 Data Record (D) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5.2.5 End of Run Record (E) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5.2.6 End of Data Record (X) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.2.7 Status Record (S) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.2.8 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.2.9 SAMPLE DATA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.3 TSPI on the Mux Bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
6 Data Manipulation 29
6.1 TIME WINDOW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6.2 SMOOTHING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6.2.1 Least Squares Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
6.2.2 A Parabolic Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.3 Changing Time Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.4 Linear Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.5 Data Editing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.6 Error Corrections and Biasing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
A Derivations 37
A.1 Geocentric G From Latitude . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
A.2 EARTH RADIUS OF CURVATURE DERIVATIONS . . . . . . . . . . . . . . . . . . . . . 37
A.2.1 Radius of Curvature in the Prime Vertical (East-West direction) . . . . . . . . . . . 38
A.2.2 Radius of Curvature in the Meridian (North–South direction) . . . . . . . . . . . . . 40
B Coordinate Transformations 43
B.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
B.1.1 Viewed as Coordinate Transforms . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
B.1.2 Composite Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
B.1.3 Homogeneous Coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
B.1.4 Orthogonality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
B.2 Selected List of Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
B.2.1 Translations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
B.2.2 Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
B.2.3 Rotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
B.2.4 Rotations in Three Dimensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
B.3 More on Composite Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
C The Geoid 51
C.0.1 The Geoidal Separation atChina Lake . . . . . . . . . . . . . . . . . . . . . . . . .
52
C.1 GEOID–84 HEIGHT TABLES . . . . . . . . . . . . . . . . . . . . . . . . . . 52
D SOURCE CODE 55
D.1 xfit.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
D.2 xfit.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
D.3 xform.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
D.4 xform.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
CONTENTS iii
D.5 geoid.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
D.6 geoid.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
GLOSSARY 79
BIBLIOGRAPHY 81
COLOPHON 83
INDEX 84
iv CONTENTS
PREFACE
This document started out as a collection of notes of the algorithms that I use for TSPI data reduction, and file
formats. Over time people have seen it and have asked for copies. Now I am in the process (time permitting)
of polishing it for greater distribution.
These are DRAFT copies, and I am sure that problems still exist. So, please send any comments to me,
so that I can improve it.
Chapter-1 introduces the problem of a curved earth, and the requirement for doing coordinate transforma-
tions. The World Geodetic System 84 (WGS–84) is discussed.
Chapter-2 discusses various coordinate transformations.
Chapter-3 discusses how to use those coordinate transformations in a set of sequences with direct applica-
tion towards TSPI data reduction.
Chapter-4 describes some subtle problems that have occurred to both myself, and others over time.
Chapter-5 discusses some of the file formats used to store TSPI information, including the Common TSPI
Data Format (CTDF).
Chapter-6 discusses manipulating the data, such as smoothing, interpolation, and similar topics.
Appendices provide derivations of some of the equations, background data on coordinate transformations,
the geoid height tables, and source code.
I many respects, this document will never be finished, there will always be something new to learn.
Any source code you see here is part of the data reduction tools available at http://eiserloh.chinalake.-
navy.mil/. This site is within a firewall and is only visible within China Lake. Alternatively, you can get this
from http://www.eiserloh.org/.
I am in the process of moving the document from a proprietary word processing document format to
LATEX. LATEX is a set of macros for the TEX typesetting software, which is both open source, and free.
v
vi PREFACE
ACKNOWLEDGMENTS
I thank the people who have helped me find the information collected here, and those who reviewed earlier
versions of this document.
Dr. Dan Price the first person other than myself to read this document. He also supplied the original
source code for earlier versions of the software that we use to analyze our flight data.
Andy Borman for pointing out certain topics that were covered in a confusing manner, so that they are
now discussed much clearer. Andy also reminded me that commonly used terms in the literature are used
incorrectly. I now explicitly state that I use the mathematical terminology vice common usage (spheroid vice
ellipsoid).
Dr. Floyd Hall for finding the original documentation on the Bowring method, in addition to being my
source for many of the algorithms, documentation, and other data.
A number of other people have helped to review this document, and I appreciate those inputs.
vii
viii ACKNOWLEDGMENTS
Chapter 1
Introduction
1
2 CHAPTER 1. INTRODUCTION
WGS–66, and the original WGS–60. WGS60 was the first datum to define a spheroid with its origin at the
earth’s center; previous datum were tailored such that the spheroid’s surface was a better match to the geoid
(see Appendix C) over a particular area. The tailored spheroid used in North America was NADS–27. Since
these datum were tailored for specific locations they worked very poorly in other locations. The WGS series
of datum are designed to be used anywhere in the world.
It is important to ensure that everyone uses the proper datum, or else we could end up placing bombs 600
feet short of our intended target. This happened over Libya in the late 1980s where the intelligence sources
used one datum, but the aircraft used a different one.
If the earth were flat comparing TSPI data to aircraft data would be very easy, but the earth is round. Even
if it were a sphere it would not be very difficult, but the earth is shaped like a squashed ball. The rotation of
the earth produces inertial forces (centrifugal) so the equator bulges out, and the poles are sucked in toward
the center. This produces an oblate spheroid.
A spheroid is a surface of revolution defined by rotating an ellipse about one of it’s axes (Note this is
not the same as an ellipsoid, which has three separate axes). There are two kinds of spheroids, oblate, and
prolate. An oblate spheroid is wider than it is tall (the rotated ellipse’s semi–major axis is the equator). A
prolate spheroid is taller than it is wide (the rotated ellipse’s semi–minor axis is the equator).
The World Geodetic System 84 (WGS–84) defines the earth model as an oblate spheroid. Common usage
in the literature calls this the WGS–84 ellipsoid, but in standard mathematical terminology it is a spheroid.
The parameters of the WGS–84 spheroid are specified in table 1.1.
The geodetic coordinates (latitude , longitude , and geodetic height h) are based upon gravitational
potentials, and are not referenced to the center of the earth. This means that the down vector does not in
general intersect the center of the earth (see Figure 1.4).
The latitude is not the angle from the center of the earth, but rather the angle of the normal line from
the point on the surface to the intersection with the plane of the equator. The longitude is the angle along
the equator (about the earth’s axis of rotation) from the prime meridian (through Greenwich England). The
geodetic height is usually referenced to mean sea level (i.e., orthometric height). Many times it will be
referenced to the spheroid (the spheroidal height).
The earth centered, earth fixed coordinate (ECEF) system is defined by the three axes EFG (see figure
1.2). The EFG geocentric coordinate system is the master coordinate system that we use for most coordinate
transformations. This is a right-handed orthogonal coordinate system whose origin is the center of the earth,
and whose axes are fixed to points on the earth. This is not an inertial coordinate system, since the earth
rotates about its axis.
The G–axis points from the center of the earth to the north pole (along the axis of rotation). The E-axis
points from the center of the earth to the equator at the prime meridian (the zero longitude line which goes
through Greenwich England). The F–axis is derived from the E, and G axes to be orthogonal, it ends up
pointing into the Indian Ocean at the equator.
If we cut a slice through the spheroid along a meridian line we form an ellipse (see Figure 1.3). At any
point on this ellipse is a tangent line (horizon), and a perpendicular (down vector). The down vector (see
Figure 1.4) does not intersect the center of the ellipse, but it does intersect the equatorial plane at an angle
4 CHAPTER 1. INTRODUCTION
E
Figure 1.2: Geocentric System (EFG)
(the latitude).
Okay, we simplified things somewhat. Actually, the earth is bumpy, caused by geologic structures within
the surface of the earth. The geoid is the gravitational equi-potential surface corresponding to the mean sea
level (MSL). There are differences in the composition of the crust of the earth. This bumpiness causes mean
sea level to deviate from a spheroid. The WGS–84 spheroid was calculated to best approximate the geoid.
Some locations have heavy deposits and the water tends to collect over these, raising the mean sea level
above the spheroid over these areas. In other locations the deposits within the crust is not so heavy, so the
mean sea level is lower. These areas of the globe usually contain land masses such as continents. When
averaged over the entire earth, the geoidal separation from the WGS–84 spheroid is zero. At any particular
point, the geoid will in general be either a positive or a negative offset from the spheroid. The WGS–84
earth model attempts to give the best approximation of its spheroid’s surface to the geoid. The difference
between the geoid and the WGS–84 spheroid (the geodetic separation) is empirically described by tables.
This geodetic separation of mean sea level from the spheroid has to be empirically measured. This has been
measured by the defense mapping agency, and is available in appendix C (The Geoid).
If you are given a height referenced to mean sea level (MSL), then you need to determine the geoid
separation at that position, and convert the height to a spheroidal height before you do any coordinate trans-
formations into the EFG coordinate system. In practice, the geoidal separation is small enough compared to
the size of the earth that one can ignore it.
Here at China Lake the geoid separation is about feet (see page 52). Sea Level is 94 feet below the
spheroid at this latitude/longitude.
1.2.1 Heights
Geoidal Height
Orthometric Height
Geocentric Height
Spheroidal Height
Topocentric Height
1.2. THE WORLD GEODETIC SYSTEM - 84 (WGS–84) 5
x P
N
y
b φ
a X
Coordinate Transforms
(2.2)
2.2 CDU2NED
When an aircraft makes a bombing run, it is on a particular flight line (usually not true north). The flight
line is described as an angle from true north towards the flight line. The resulting coordinates will be rotated
from true north by this rotation angle, and it defines a new coordinate system. This coordinate system is in
CROSS–RANGE, DOWN–RANGE, and UP (CDU). A simple two dimensional rotation will transform from
CDU to ENU coordinates, and then from ENU to NED. The inverse can also be performed, (NED to CDU).
In the example below the tip of the bomb symbol is +100 feet off range, and +200 feet down range. The
flight line angle is about 40 degrees counter–clockwise (or negative 40 degrees).
We rotate the vector (100, 200, 0) by a rotation matrix of an angle equal to the negative of the flight line.
$
! "#
&% (2.3)
'( $
! "#
&% (2.4)
We can modify this matrix to create a rotation matrix which includes the ENU to NED transformation.
This looks a little different from a normal rotation matrix because it is also switching the order of the axis
(see above).
7
8 CHAPTER 2. COORDINATE TRANSFORMS
! " #
$
"#
&% (2.5)
"#
2.3 RAE2NED
When a sensor such as the Alrite Laser measures the position of it’s target, it measures the slant range (R),
azimuth angle( ), and elevation angle ( ) to the target. This coordinate system is called RAE. Here we define
as the azimuth angle from the north axis towards the east axis, and as the elevation angle from the horizontal
up towards the line of sight (i.e., down is negative).
We want the target vector in the right-handed orthogonal NED coordinate system. Depending upon the
source of TSPI this may already be done, if not then we will have to do it.
"#
"#
(2.6)
(2.7)
(2.8)
U
R
ε
δ N
E
Figure 2.2: An RAE vector (Polar coordinates)
G
N
φ
F
λ
E
Figure 2.3: A Simplified Polar Coordinate System
ground distance,
Here, I use the calculated value of R while calculating the elevation angle. I could have calculated the
and used arctan2() instead of arcsin(), but the above method saves a couple
steps.
2.4 LLH2EFG
The Geodetic to Geocentric coordinate transform is called llh2efg. A location specified in geodetic coordi-
nates (latitude , longitude , and height h) can be converted to geocentric coordinates (EFG).
The latitude , longitude , and height h, of the TSPI reference point is converted to the EFG geocentric
coordinate system as follows (see appendix A.1 on page 37).
"# "
" #
(2.12)
(2.13)
(2.14)
Where:
10 CHAPTER 2. COORDINATE TRANSFORMS
x P
N
y
φ
X
is the latitude,
is the longitude,
N is the radius of curvature in the prime vertical (see appendix A.2.1 on page 38, for the derivation)
! (2.15)
2.5 EFG2LLH
The transformation efg2llh which goes from geocentric (EFG) to geodetic (LLH) coordinates is probably the
most complex of the coordinate system transformations. In particular, determining the latitude is the most
difficult one of all. The longitude is the easiest.
In the past we used a few ad-hoc methods of calculating the latitude, usually iterative approaches. The
modern method is called the “Bowring Method”, which was first published in 1976 [BOWRING-1976].
Bowring’s method is independent of the particular earth model. We of course will be using WGS–84, al-
though the algorithm could use any other such as NADS–27.
In the following discussion we will first determine the longitude, then latitude, and finally the height
above the spheroid. Since the orthometric height is referenced to MSL, we will need to apply the geoidal
separation at that latitude/longitude (see Appendix C).
2.5.1 LONGITUDE
The simplest of the geodetic coordinates to calculate is the longitude, since it is not affected by the eccentricity
of the earth.
The longitude shows how far East/West we are from the prime meridian. The tangent of the longitude is
directly formed using the geocentric components.
(2.16)
2.5. EFG2LLH 11
XE
XF
λ
G
P
x h
N g
φ X
C θ
Where Arctan2(y, x) will generate the correct quadrant. If the function arctan2() is not available but
arctan() is then you have to determine the correct quadrant yourself.
2.5.2 LATITUDE
The Bowring method can be considered to be a direct solution, but is in reality an iterative one. It is simply
that the first iteration is so good, that a second one is superfluous. The second iteration causes such a small
correction that we can usually ignore it.
According to Bowring, the worst error would be of latitude (or about 2 inches). This largest error
occurs at a spheroidal height twice the distance of the semi-major axis (H=2a), or about 8 thousand miles of
altitude. At earth-bound altitudes (-5 to +10 K meters) this error is much smaller.
Bowring’s method uses the North-South radius of curvature R instead of the usual East-West radius of
curvature N. This uses a point not on the polar axis (whereas the older iterative method’s radius of curvature
terminates on the polar axis).
First, we introduce a new variable to indicate the distance from the axis of rotation to the point in ques-
tion. This effectively bisects the spheroid forming an ellipse along the meridian (longitudinal) line through
the point.
12 CHAPTER 2. COORDINATE TRANSFORMS
(2.17)
We provide an initial estimate . This corresponds to rescaling the ellipse back into a circle, then using
the tangent function.
(2.18)
The normal line with the length of the North-South radius of curvature R terminates at the point “C”: (see
figure 2.6).
The angle from this point to the point (X, G) has the tangent:
!
(2.19)
Giving a latitude of:
"# (2.20)
If you wanted to iterate this you would feed the first iterations back into the .
2.5.3 HEIGHT
We will attack the height problem via two routes. Both start from the original transformation (see equations
2.12, 2.13, and 2.14), and the distance from the axis of rotation X (eq. 2.17). We then merge the two
approaches into one equation.
For the first route, we remove eq’s 2.12, and 2.13 dependency on the longitude by using the distance from
the axis of rotation to the point (collapsing the E, and F components into X). Then simply solve for the height
h.
"#
(2.21)
(2.22)
" "#
(2.23)
(2.24)
; where
(fails at the poles) (2.25)
(2.26)
(2.27)
! "#
; where $
(fails on the equator) (2.28)
These two approaches fail at different places. We can merge them into one equation which works for all
latitudes. Starting with eq. (2.25) we multiply by . We similarly multiply eq. (2.28) by
.
"# !
2.6. NED2EFG ROTATION 13
" "
!
(2.29)
(2.30)
"#
Now we add the two equations and simplify.
"# !
"#
!
!
!
"#
!
And, using eq. (2.15) we can remove N by reintroducing the semi-major axis of the earth.
"
(2.31)
!
! (2.33)
1. The first rotation is about the east–axis (y–axis), and rotates the north axis to align with the G–axis
(it also aligns the down–axis to the equatorial plane). This is effectively moving the vector from the
north towards the down–axis. This first rotation is a negative rotation with magnitude of the latitude
(negative of the latitude).
"
(2.34)
"
"#
(2.35)
(2.36)
2. The second rotation is about the north–axis (x–axis), and moves the east axis to align with the F–
axis. This is effectively moving the vector from the east–axis towards the down–axis (this is a positive
rotation by an amount of the longitude).
"
"#
(2.37)
3. The third and final rotation aligns all three axes N, E, and D to the geocentric axes E, F, and G respec-
tively. This rotation is about the current east axis (the y–axis). This is equivalent to moving
a vector
from the north–axis towards the down axis. This is a negative 90 degree rotation (i.e. - ).
!
! "#
(2.38)
(2.39)
We ensure that each rotation matrix is applied to the vector in the order specified above. Each rotation
matrix is prepended to the previous matrices.
(2.40)
G
G
N
E
D
F
F N
E
D
E
E
G G
F E F
N
N
D
E E E
Figure 2.9: Rotated about the North by its Longi- Figure 2.10: Final Rotation to the EFG Coordinate
tude System
where:
(2.41)
Which are expanded and matrix multiplied to give:
"
!
' "# !
!
! "#
And, finally:
" # ! " #
!
! (2.44)
=0, =0
A local NED vector [1, 2, 3] at ( = 0, = 0) should map to EFG [-3, 2, 1].
'
(2.45)
=0, =90
A local NED vector [1, 2, 3] at ( = 0, = 90) should map to EFG [-2, -3, 1].
(2.46)
16 CHAPTER 2. COORDINATE TRANSFORMS
=90, =0
A local NED vector [1, 2, 3] at ( = 90, = 0) should map to EFG [-1, 2, -3].
(2.47)
2.6.3 The RIPS Rotation Matrix
The rotation matrix used by the RIPS software is different than the above matrix because RIPS uses vectors
in ENU (east, north, up) rather than NED. This rotation matrix is documented in (JAMES-1990). We show
that this corresponds to the rotation matrix we derived earlier, by multiplying eq. (2.33) by the NED to ENU
matrix eq. (2.1).
"#
"# " !
" (2.48)
(2.49)
(2.50)
In general an inverse matrix is not the same as it’s transpose, but the primitive rotation matrices are anti-
symmetric. The inverse of an anti-symmetric matrix is its transpose. If two anti-symmetric matrices are
multiplied then their inverse will also be it’s transpose.
Note: We can’t just use the negative angle in these matrices, because negative angles mean the other
hemisphere. This becomes especially important when you include the geoid separation in calculating the
height.
(2.51)
Chapter 3
local NED coordinate system.
"" ##
" !# (3.1)
(3.2)
(3.3)
"# " #
"# (3.4)
(3.5)
(3.6)
(3.7)
(3.8)
Alternatively we could have rotated the vector into the second point local NED system.
17
18 CHAPTER 3. USING THE COORDINATE TRANSFORMS
1. Calculate the aircraft’s geodetic coordinates using one of the techniques outlined above.
2. Rotate the target vector from the origins NED into the aircraft’s NED.
3. Negate the vector to get the vector from aircraft to the origin.
1. Calculate the target’s geocentric (EFG) coordinates from it’s geodetic coordinates using one of the
techniques outlined above.
2. Calculate the aircraft’s geocentric (EFG) coordinates using one of the techniques outlined above.
3. Subtract the A/C EFG vector from the target’s EFG vector to give the A/C to target EFG vector.
1. Calculate the shooter’s geodetic coordinates using one of the techniques outlined above.
3. Subtract the shooter’s EFG vector from the target’s EFG vector to get the EFG vector from the shooter
to the target.
LIST OF DELTAS
1. Aircraft Position (latitude, longitude, altitude)
2. Aircraft Velocities
3. Target Slant Range
4. Target Velocities
5. Target Accelerations
The first set of deltas requires simple subtraction. The interesting delta is the position in CDU.
1. time
2. altitude,
3. airspeed,
4. ground track,
5. flight path angle,
6. cross range, and
7. down range.
20 CHAPTER 3. USING THE COORDINATE TRANSFORMS
Chapter 4
21
22 CHAPTER 4. ISSUES AND GOTCHAS
h’
h
φ φ
X
Sensor Accuracy
NIKE feet
ALRITE feet
ARDS-GPS (NAV) feet
ARDS-GPS (Method 3) feet
among other things the level of quality (LOQ) of its data. The Method–3 solution uses post processing to
calculate the position using filtering, and taking into account the LOQ, in addition it can merge the positions
of both ARDS pods. The Method–3 solution allows a particular pod to have a position jump detected and
handled by using either the other pods data, or filtered position used.
In addition, on some aircraft which have a GPS sensor such as a MAGR integrated with the aircraft’s
Inertial Navigation Set (INS) , we can use the aircraft’s own idea of its position from the INS. This may seem
like a circular argument, but not really. We want to compare the TSPI vice aircraft sensor’s idea of the vector
from the aircraft’s position to the target.
For example, if the sensor is the airborne radar in the aircraft and the target is a surveyed point on the
ground, then the radar will measure a vector to the target. We can then calculate a vector using the GPS
aided INS position and the coordinates of the target. This is obviously not as conceptually simple as using an
external sensor to measure the aircraft’s position, but in a pinch this may work.
Note: The GPS aided INS accuracy is not going to be as good as the Method–3 solution. I have heard
people say the position can be as bad as 50 feet, but is usually better.
Note: The AV–8B aircraft has wings that have pronounced wing flexure and vibration. This makes it very
difficult for the GPS receiver in the ARDS pod to achieve lock–on. In addition, the AV–8B does not have
wingtip stations, so a pod would have to be mounted on one of the pylons (under the wing). The wing will
mask the reception GPS satellite signals.
Chapter 5
FILE FORMATS
5.1 INTRODUCTION
This chapter will discuss some of the various file formats used to contain TSPI data. First we discuss a simple
the format that was used in the past by us internally, then we discuss the format of the data we receive as
raw data from various sources. Lastly we speculate on a format, that could be used in the future, but is today
simply a pipe dream.
The RCC Integration and Processing System (RIPS) data format is an obsolete format, that has been
superseded by the Common Test Data Format (CTDF). If the user needs to use this file format, please request
the document “Range Control Center Integration and Processing System (RIPS) Data Product Definition”
from the Range Control Complex. Alternatively, you can ask us for some general information. The RIPS
format is no longer used, and will not be discussed any further.
00012Asample
Each logical block is identified with a type character in the sixth byte. This allows logical blocks to
contain different records of data. Version 1 of the CTDF defines 6 different records.
23
24 CHAPTER 5. FILE FORMATS
TYPE
STRING = ARRAY OF CHAR;
G_Rec = RECORD (* variable length *)
len : STRING[5];
type : "G";
gh_version : STRING[12];
gh_test_range : STRING[30];
gh_flt_date : STRING[8];
gh_num_tspi_srcs : STRING[3];
gh_tspi_srcs : ARRAY [N] OF TspiSrcRec;
gh_num_ref_pts : STRING[2];
gh_ref_pts : ARRAY [M] OF RefPtRec;
END;
number (from the G record), and inter–track number. Parameters also support inter-track data to measure
the difference between two different tracks (normally set to zero). A reference point type is also defined to
identify if this is a primary or secondary. Each Range facility may have different parameter names, and so
data reduction software will still have to be tailored to the particular range activity.
5.2.8 Parameters
The parameters defined in the parameter record describe the data that will be recorded within the data records.
The test engineer may define any parameters of interest to be computed and stored in the data records. The
most common will be the position:
“X POS FT”, “Y POS FT”, “Z POS FT”
Here the (X, Y, Z) position is referenced to the reference point and its flight line rotation angle. The X,
and Y axis need to be rotated to give ENU coordinate system.
Alternatively the test engineer may have selected the ENU coordinate system.
“EAST POS FT”, “NORTH POS FT”, and “UP POS FT”
In addition, the test engineer may also have requested that the velocities be computed.
“X VEL”, “Y VEL”, and “Z VEL”
A parameter that is very important, but in many cases gets overlooked is the validity of the track. When
the TSPI sensor looses track of the target, we need to know.
The bottom line is that any set of parameters can be stored within the CTDF file. We need to standardize
on the set of parameter names.
000400 : 3a30 302e 3135 3030 3030 2050 2020 2020 : :00.150000 P
000410 : 2020 202d 3030 3033 3939 332e 3738 3434 : -0003993.7844
Data Manipulation
6.2 SMOOTHING
To filter noisy data we approximate the data with a function . This function is a model of the
dynamics of the objects whose data we are filtering, so we must choose the type of function appropriate to
29
30 CHAPTER 6. DATA MANIPULATION
that model. The coefficients to be used in the function are chosen to minimize the overall error, they are
optimized for the data set being smoothed.
A Linear Filter
One of the simplest functions is the straight line.
(6.1)
We
need
to determine the parameters , and so that when is fitted through the given points
,
...,
so that the sum of the squares of the distances of those points from the straight line is a minimum,
where the distance is measured
Each data point
in the vertical direction (the y-direction).
has a corresponding point on the smoothed function
. When
is a line,
then for each we can evaluate
(6.2)
Instead of using the absolute value, we use the square of the distance as the error function . All the errors
for each point are summed. The error function is the sum of all the squared distances.
6.2. SMOOTHING 31
} d=yk−(a−bxk)
(xk,yk)
(6.3)
Where depends on and . A necessary
condition for to be an extrema (here a minimum) is that its
partial derivatives with respect to , and be zero:
(6.4)
(6.5)
where we sum over from 1 to .
Thus, we find the “normal equations” for our problem:
(6.6)
(6.7)
These “normal
equations” are unique for each type of function that we are modeling. We calculate
the statistics
( , and all the s) then solve the system of linear
equations. We determine the
coefficients ,
and using Gauss–Jordan elimination. The coefficients , and are the coefficients of .
The last step is to calculate the resulting error function. The smaller the better. A test to ensure that the
error stays below some threshold is a good idea.
Example 1 (Linear Fit) Here is a small data set, which we wish to model with a linear function.
We calculate:
32 CHAPTER 6. DATA MANIPULATION
Or when expressed as augmented matrices we solve this set of linear equations using Gauss–Jordan
elimination .
, and we obtain the line:
The solution is ,
Now to find the Root Sum Square (RSS) error of this estimate:
i
We need
, ...,
to determine
the parameters a, b, and c so that when f(x) is fitted through the given points
so that the sum of the squares of the distances of those points from the parabola is a
minimum.
When
is a quadratic, then for each
we can evaluate
(6.9)
Hence its distance
from
is
(6.10)
6.2. SMOOTHING 33
The error function is the sum of all the squared distances.
(6.11)
We minimize the error function by calculating the partial derivatives with respect to , , and , then set
them to zero.
(6.12)
(6.13)
(6.14)
(6.15)
(6.16)
(6.17)
From here the process is the same, collect the statistics, put them into the “normal equations”, solve this
system of linear equations using Gauss–Jordan elimination.
1 -1.0 1.000
2 -0.1 1.099
3 0.2 0.808
4 1.0 1.000
34 CHAPTER 6. DATA MANIPULATION
The “normal equations” for this data set then become the following system of linear equations:
We use Gauss–Jordan elimination to solve the above set of simultaneous equations.
The solution is a = 0.95572, b = -0.02155, and c = 0.04208, so we obtain the parabola:
Now to find the error of this estimate:
(6.18)
i
y2
y
y1
x1 x x2
is a quadratic function just like the parabolic filters gives us. The coefficients from the parabolic filter
have the following correspondence:
(6.20)
(6.21)
(6.22)
We differentiate the kinematic equation to get velocity and acceleration.
position X
velocity V
acceleration A
(6.23)
Derivations
!
The second contribution is the height above the spheroid. From fig A.1 it is readily apparent that the
contribution from the height is:
(A.6)
Now combining the two contributions:
! (A.7)
! (A.8)
(A.9)
37
38 APPENDIX A. DERIVATIONS
h
P
x
G2
N
G1
φ
X
b
a
(A.10)
The deviation of an ellipse from a circle is the eccentricity “e”, given by:
(A.11)
from the surface to the intersection with the axis of rotation. Note: that the line normal to the surface does
not intersect the origin of the spheroid except when the point is at one of the poles, or on the equator.
We get the tangent line’s slope of the surface at point using the derivative of eq. (A.12).
A.2. EARTH RADIUS OF CURVATURE DERIVATIONS 39
x P
N
y
φ
X
(A.13)
(A.14)
(A.15)
The line is perpendicular to the tangent line at . To get the slope of the line we use the negative
reciprocal of the tangent line’s slope. the slope of the line is also the tangent of the angle cutting through
the x-axis.
(A.16)
Solving for yields: (A.17)
Now we substitute eq. (A.17) back into eq. (A.12) and solving for .
(A.18)
(A.19)
(A.20)
(A.21)
(A.22)
"
(A.23)
"# ! (A.24)
40 APPENDIX A. DERIVATIONS
∆s
P
X
τ τ+∆τ
! (A.26)
This is the radius of curvature in the east–west direction at the latitude . It corresponds to the distance
from the point to the point somewhere on the axis of rotation.
(A.28)
The radius of curvature is the reciprocal of the curvature:
(A.29)
Now since,
(A.30)
A.2. EARTH RADIUS OF CURVATURE DERIVATIONS 41
Differentiating with respect to yields
(A.31)
Now since,
(A.32)
We can divide them to yield,
(A.33)
Now, since the radius of curvature is the reciprocal of the curvature, we can express the radius of curvature
as:
(A.34)
The normal line is perpendicular to the tangent line. So, we take the negative reciprocal of the slope of
the normal line, the expression for the first and second derivatives of y with respect to x can also be written
as:
(A.36) "
and "
(A.37)
Where is the geodetic latitude as shown in figure A.3. Now we remember eqs. (A.17), and (A.26).
!
Finally,
!
(A.41)
Or, alternatively:
(A.42)
can be visualized a the radius
of a circle that best matches the earth’s surface along the meridian line at
that specified latitude. Whereas , the radius of curvature in the East–West direction, always terminates on
the Earth’s axis of rotation, the radius of curvature in the North–South direction usually terminates short
of it ( is less than ).
Appendix B
Coordinate Transformations
B.1 Introduction
There are three basic transformations, translation, scaling, and rotations which can be applied to a vector.
Although rotations are the transformation that we are primarily interested in, we will take a brief look at
the other ones. Translation is just adding an offset to the vector. Scaling modifies the length of the vector.
Rotation is a function which maintains the length of the vector, but changes their orientation referenced to
the axes (or alternatively can be though of as rotating the axes). These are all applied to a vector by a matrix
multiply. All these transformations can be thought of as changing coordinate systems.
Transformations are applied by performing a matrix multiply to the vector. Because matrix multiplies are
not commutative we must specify on which side of the multiply is the matrix and which is the vector. We
will then define one as the conventional method. Note: In the following discussion the vector X is a column
vector.
(B.1)
(B.2)
We will pick eq. (B.1) as the conventional order of matrix multiplication. Here the transformation matrix
occurs to the left of the vector being transformed.
Note: For the case of orthonormal matrices, A is related to B by a simple transpose.
∆V
V1
V2
43
44 APPENDIX B. COORDINATE TRANSFORMATIONS
V1
V1
V2
θ
V1
V2
V1
θ V2
Y
Y’
θ V X’
θ X
a vector V rotated by an angle of negative theta
( ) into vector
. This can also be thought of as changing
from one coordinate system to another , (see figure B.6)
Composite matrices are especially useful when a large number of vectors need the same transformation.
(B.3)
(B.4)
For most coordinate transformations of interest (i.e. rotations) we do NOT need to use homogeneous
coordinates.
B.1.4 Orthogonality
When two vectors are orthogonal their inner products (dot products) are zero (they are perpendicular to each
other). A set of basis vectors which spans a vector space is usually chosen to be orthogonal, because they
are linearly independent. A coefficient in front of one basis can be changed without effecting the other basis
coefficients.
A matrix can also be orthogonal. These have the special property that the transpose of a matrix is also
it’s inverse. A matrix is orthogonal if and only if the columns of the matrix form an orthonormal basis. See
[Cullen-72] page 158. Pure rotation matrices are orthogonal. For example the following rotation matrix is
orthogonal,
(B.5)
because the columns of the matrix form an orthonormal basis (inner-products are zero).
(B.6)
(B.7)
(B.8)
This means that the inverse of a rotation matrix is very easy the generate, just take the transpose of it.
#
(B.9)
B.2.1 Translations
A translation applies an offset to a vector by performing a vector addition. This can easily be extended to a
three dimensional vector, and translation.
(B.10)
(B.11)
(B.12)
B.2.2 Scaling
A scaling operation modifies the length of the vector. Each component is modified separately from the others.
This Scaling matrix is symmetric.
(B.13)
B.2.3 Rotations
A rotation is performed about an axis. The simplest case is a two-dimensional vector
rotated about an
imaginary z–axis by an angle .
(B.14)
(B.15)
(B.16)
(B.17)
(B.18)
Note that the order of the matrix multiply determines the location of the negative . The inverse
transform of the rotation is R(-
). Pure rotation matrices are orthogonal, so the inverse of a rotation
matrix is simply its transpose.
β
γ
Y
The Primitive 3D Rotation Matrices are listed in order XYZ which forms a right handed coordinate
system. Positive angles are shown in figure B.7.
"#
"
(B.20)
(B.21)
convert from NED to EFG.
(B.22)
B.3. MORE ON COMPOSITE MATRICES 49
"#
!
! (B.23)
The Geoid
The earth’s surface can only be approximated by a spheroid, because the earth is “bumpy”. The geoid is
a gravitationally equi-potential surface which approximates the mean sea level. The geoid differs from the
spheroid due to gravitational variances at different latitudes, and longitudes. Only with the advent of satellites
orbiting the earth have we been able to accurately measure the position of the geoid. The geoid is described
by a table of geoid separations at different positions over the surface of the earth.
The GEOID–84 geoidal separation is the difference between the local mean sea level and the WGS–84
spheroid. The geoid has to be empirically measured,
it can be described by entries in a table (see below).
The official geoid table contains entries for each of latitude, and longitude, this used to be classified. It
is now available from the National Imagery and Mapping Agency (NIMA) at “http://www.nima.mil/”. We
supply a table in this appendix which has entries every 10 degrees. Here at China Lake the geoid is about
-28.9 meters (the geoid is 94 feet below the spheroid). The continental United States has a negative geoid
value, meaning that the geoid is below the spheroid defined by WGS–84.
The GEOID–84 was defined at the same time as the WGS–84, before the GPS/NAVSTAR satellite con-
stellation was deployed. Using the more accurate results of GPS a new geoid model was developed called
GEOID–90, which basically refines the GEOID–84 numbers with decimal points. The GEOID–90
data base
is about 3 MB in binary, and is not included here. Rather the GEOID–84 in the form of a by grid is
provided and a method of interpolation which should be accurate enough for our purpose.
The documentation that comes from DMA describes a spherical harmonic method of interpolation. This
is very complicated. NIMA provides a much simpler (and faster) method (bi–linear interpolation). This is
the method I use.
A bi–linear interpolation of the geoid tables may be performed to derive the geoid separation at any given
latitude/longitude. Now we could perform this interpolation for every position of the aircraft, but this is not
necessary. Since the geoid does not change radically within miles we can determine the geoid for the
local area, and use that for the entire area.
For example The airfield’s cold–line at China Lake is located at
LAT 35 41 18 35.688333
LONG -117 40 50 -117.680556
ELEV (ft) 2210
The surrounding geoid values (in meters) are:
Ocean
Land
Figure C.1: The geoidal separation is the difference between the mean sea level and the spheroid.
51
52 APPENDIX C. THE GEOID
longitude
latitude
[deg.]
Where the geoid values form an array:
-21 -16
-42 -29
Here we want
and we are given
,
,
, and
. The
bi-linear interpolation formula has the form:
(C.1)
where:
(C.2)
(C.3)
(C.4)
(C.5)
(C.6)
(C.7)
(C.8)
(C.10)
(C.11)
(C.12)
(C.13)
(C.14)
The geoid value of -28.09 meters is very close to the actual measured value of -28.9 meters (-94.8 feet)
used at the L20 surveyed point.
Here at China Lake the geoid (i.e., sea level) is 94 feet below the spheroid. Ground altitude (2200 MSL)
is only 2106 feet above the spheroid.
Latitude
Longitude
Latitude
Longitude
54 APPENDIX C. THE GEOID
SOURCE CODE
D.1 xfit.h
#ifndef XFIT_H
#define XFIT_H
/* ----------------------------------------------------------------
FILE = xfit.h
AUTHOR = Peter P. Eiserloh
SYSTEM = Linux 2.2.4, libc-6.0.7 (glibc-2.0.7)
COMPILER = GCC-2.7.2
PROJECT = AV-8B DATA REDUCTION TOOLS (DRTOOLS)
PURPOSE = Parabolic smoothing in the least squares sense.
-------------------------------------------------------------------
VERSION HISTORY:
3 (14-Jul-1999) PPE, Added xfit1().
2 (29-Mar-1999) PPE, Implemented normalize_matrix().
1 (26-Mar-1999) PPE, Original
---------------------------------------------------------------- */
#include <libdr/lists.h>
struct position_record {
double time;
double x, y, z;
};
struct state_vector_record {
double time;
double x, y, z;
double vx, vy, vz;
double ax, ay, az;
};
55
56 APPENDIX D. SOURCE CODE
/* ====================================================== */
/* -----------------------------------------------------------
xfit - fit a parabolic curve to a position vector [pos_list],
to create a vector of state vectors (RETURN). The elements of
the returned state vectors will be evaluated at the times
contained in the [time_list] with locality [twindow]. The
time window [twindow] is applied in both directions about
each element of [time_list] to choose the elements of
[pos_list] that will be used in smoothing and getting the
time derivatives (velocity, and acceleration).
Elements corresponding to times not within a region that can
be processed will have the state values set to zero.
If at least two positions are available (one on each side of
the requested time) then the position and velocity will be
estimated, but not the acceleration.
----------------------------------------------------------- */
LIST * xfit(LIST *pos_list, LIST *time_list, double twindow);
#endif
D.2 xfit.c
/* ----------------------------------------------------------------
FILE = xfit.c
AUTHOR = Peter P. Eiserloh
SYSTEM = Linux 2.2.4, libc-6.0.7 (glibc-2.0.7)
COMPILER = GCC-2.7.2
PROJECT = AV-8B DATA REDUCTION TOOLS (DRTOOLS)
PURPOSE = Parabolic smoothing in the least squares sense.
-------------------------------------------------------------------
VERSION HISTORY:
3.10 (20-Jul-2001) PPE,
[1] Ran the code (and comments) through a spell checker.
[2] Added debug output for results of solve_stats().
[3] Changed the use of a matrix element (mat[2][3])
to the corresponding coefficient (c2) in solve_stats().
3.9 (28-Nov-2000) PPE,
[1] Changed all #ifdef DEBUG to #if DEBUG, since DEBUG is
now always defined, but normally set to zero in the main
Makefile.
3.8 (30-May-2000) PPE,
[1] Replaced all the BUGOUTs with #ifdef DEBUG fprintf() #endif.
3.7 (16-Jul-1999) PPE,
D.2. XFIT.C 57
#include <stdio.h>
#include <math.h>
#if 0
#define DEBUG 1
#endif
#if DEBUG
#endif
#include <libdr/drbase.h>
#include <libdr/xfit.h>
#include <libdr/lists.h>
#include <libdr/interpolate.h>
#include <libdr/irig.h>
#define MIN_ELEMENTS 5
#ifndef NULL
# define NULL ((void *) 0)
#endif
#ifndef SECONDS_IN_DAY
# define SECONDS_IN_DAY 86400
#endif
struct statistics {
58 APPENDIX D. SOURCE CODE
int n;
double sx, sx2, sx3, sx4;
double sy, sxy, sx2y;
};
/* ====================================================== */
/* -----------------------------------------------------------
print_stats -
----------------------------------------------------------- */
void print_stats(FILE *f, struct statistics *stats, char *msg) {
fprintf(f, "%s\n", msg);
fprintf(f, " n = %d\n", stats->n);
fprintf(f, " sx = %f\n"
" sx2 = %f\n"
" sx3 = %f\n"
" sx4 = %f\n",
stats->sx, stats->sx2, stats->sx3, stats->sx4);
fprintf(f, " sy = %f\n"
" sxy = %f\n"
" sx2y = %f\n",
stats->sy, stats->sxy, stats->sx2y);
fprintf(f, "\n");
}
/* -----------------------------------------------------------
zero_stats - initialize a statistics record so that we
can accumulate a new set of data into it.
----------------------------------------------------------- */
void zero_stats(struct statistics *st) {
st->n = 0;
st->sx = st->sx2 = st->sx3 = st->sx4 = 0.0;
st->sy = st->sxy = st->sx2y = 0.0;
}
/* -----------------------------------------------------------
accumulate_stats -
----------------------------------------------------------- */
void accumulate_stats(struct statistics *st, double x, double y) {
double z;
#if DEBUG
fprintf(stderr, "accumulate_stats: t = %f, y = %f\n", x, y);
#endif
st->n++; st->sy += y;
z = x; st->sx += z; st->sxy += z * y;
D.2. XFIT.C 59
z *= x; st->sx2 += z; st->sx2y += z * y;
z *= x; st->sx3 += z;
z *= x; st->sx4 += z;
#if DEBUG
print_stats(stderr, st, "partial accumulation of stats");
#endif
}
/* -----------------------------------------------------------
normalize_matrix - Diagonalize the augmented matrix to solve
the system of equations.
--------------------------------------------------------------
Use Gaussian elimination.
----------------------------------------------------------- */
void normalize_matrix(double mat[3][4]) {
int k, j, i;
double x;
/* -----------------------------------------------------------
print_matrix -
----------------------------------------------------------- */
void print_matrix(FILE *f, double mat[3][4]) {
int k, j;
};
fprintf(f, "\n");
};
fprintf(f, "\n");
}
/* -----------------------------------------------------------
solve_stats - evaluate the statistics [st] at the value
of [t] to give the return value. The statistics model a
parabola to a maneuvering target.
The solution consists of position [x], velocity [v], and
acceleration [a].
--------------------------------------------------------------
The statistics form a set of simultaneous equations.
We form an equation by diagonalizing a augmented matrix using
Gaussian elimination. The matrix is built from the statistics,
then diagonalized. The coefficients of the parabola are
are extracted from the diagonalized matrix. The position
velocity, and acceleration are then evaluated.
x = c0 + c1t + c2tˆ2
v = c1 + 2c2t
a = 2c2
This equation is then solved by using the supplied value [x].
----------------------------------------------------------- */
void solve_stats(struct statistics *st, double t,
double *x, double *v, double *a) {
double mat[3][4], c0, c1, c2;
mat[0][0] = st->n;
mat[0][1] = st->sx;
mat[0][2] = st->sx2;
mat[0][3] = st->sy;
mat[1][0] = st->sx;
mat[1][1] = st->sx2;
mat[1][2] = st->sx3;
mat[1][3] = st->sxy;
mat[2][0] = st->sx2;
mat[2][1] = st->sx3;
mat[2][2] = st->sx4;
mat[2][3] = st->sx2y;
#if DEBUG
fprintf(stderr, "matrix loaded with statistics\n");
print_matrix(stderr, mat);
#endif
normalize_matrix(mat);
#if DEBUG
fprintf(stderr, "normalized matrix\n");
D.2. XFIT.C 61
print_matrix(stderr, mat);
#endif
c0 = mat[0][3];
c1 = mat[1][3];
c2 = mat[2][3];
*x = c0 + c1*t + c2*t*t;
*v = c1 + 2*c2*t;
*a = 2*c2;
#if DEBUG
fprintf(stderr, "x = %10.2f, v = %10.3f, a = %10.3f\n", *x, *v, *a);
#endif
}
/* -----------------------------------------------------------
* xfit1 - fit a parabolic curve to a specific time point in
* the position vector, resulting in a single state_vector_record.
* The points from the position vector list [pos_list] used in
* calculating the parabola are within [twindow] seconds from
* [time]. The first time this routine is used on a position
* list, use a [hint] of NULL. On subsequent invocations on
* a position list (and with monotonically incrementing [time])
* use the [hint] provided by the previous invocation.
* This routine creates the state_vector_record, and its node,
* these are then the responsibility of the caller to deallocate.
* ----------------------------------------------------------
* Reduce round off errors by using an offset time rather than
* absolute time.
*
* If at least MIN_ELEMENTS (5) elements are found within
* that window then a least squares fit with a parabolic curve
* is performed within that window. The resulting curve is
* evaluated at the specified time to give the state vector
* which includes (position, velocity, and acceleration).
* NOTE: the specified time is twindow seconds from offset_time.
*
* If not enough elements are found within the time
* window, but two elements are found (one on each side of the
* requested time) then a simple linear interpolation is used
* to get the position, and the difference between the two is
* used as the velocity. The acceleration is set to zero.
*
* If none of the above can be found, all elements are set to
* zero (except for time of course).
* -------------------------------------------------------- */
NODE *xfit1(LIST *pos_list, NODE *hint, double time,
double twindow, struct state_vector_record *state) {
struct statistics st_x, st_y, st_z;
NODE *pos_nd, *left_nd;
struct position_record *pos_rec, *left_pos, *right_pos;
62 APPENDIX D. SOURCE CODE
int k;
int julian_day;
double pos_time, left_time, right_time;
double delta_time, offset_time;
int count=0;
#if DEBUG
fprintf(stderr, "xfit1: time is %f\n", time);
fprintf(stderr, "xfit1: zeroing state\n");
#endif
state->time = time;
state->x = state->y = state->z = 0.0;
state->vx = state->vy = state->vz = 0.0;
state->ax = state->ay = state->az = 0.0;
zero_stats(&st_x);
zero_stats(&st_y);
zero_stats(&st_z);
k = 0;
if (hint) {
pos_nd = hint;
} else {
pos_nd = get_first_node_from_list(pos_list);
};
left_nd = NULL;
left_pos = NULL;
/* --------------------------------------------------
* Traverse the position list, and accumulate the positions
* of the points within the time window around the
* requested time.
* ------------------------------------------------- */
while (pos_nd) {
k++;
#if DEBUG
fprintf(stderr, "xfit1: position record %d\n", k);
#endif
pos_rec = (struct position_record *) pos_nd->data;
#if DEBUG
fprintf(stderr, "xfit1: position record time %15.6f\n",
pos_rec->time);
#endif
if (time < SECONDS_IN_DAY) {
julian_day = pos_rec->time / SECONDS_IN_DAY;
pos_time = pos_rec->time - julian_day * SECONDS_IN_DAY;
} else {
pos_time = pos_rec->time;
};
delta_time = pos_time - time;
D.2. XFIT.C 63
#if DEBUG
fprintf(stderr, "xfit1: pos_time %15.6f\n", pos_time);
fprintf(stderr, "xfit1: delta time %15.6f\n", delta_time);
#endif
#if 1
if ( fabs(delta_time) < twindow ) {
#else
int flag1, flag2, flag3, flag4;
flag1 = (pos_rec->time - twindow) < time;
flag2 = time < (pos_rec->time + twindow);
flag3 = (pos_time_noday-twindow) < time_noday;
flag4 = time_noday < (pos_time_noday+twindow);
if ( (flag1 && flag2) || (flag3 && flag4) ) {
#endif
count++;
/* --- this element is within the time window --- */
#if DEBUG
fprintf(stderr, "xfit1: found position node %d in time window\n",
k);
fprintf(stderr, "xfit1: x = %15.2f\n", pos_rec->x);
fprintf(stderr, "xfit1: y = %15.2f\n", pos_rec->y);
fprintf(stderr, "xfit1: z = %15.2f\n", pos_rec->z);
#endif
if (count == 1) {
left_nd = pos_nd;
left_pos = pos_rec;
left_time = pos_time;
};
if ((pos_time > time) && (!right_pos) ) {
right_pos = pos_rec;
right_time = pos_time;
};
offset_time = pos_time - time;
accumulate_stats(&st_x, offset_time, pos_rec->x);
accumulate_stats(&st_y, offset_time, pos_rec->y);
accumulate_stats(&st_z, offset_time, pos_rec->z);
};
pos_nd = get_next_node(pos_nd);
if (delta_time > twindow) break;
};
/* -----------------------------------------------
* Decide the amount of data to extract given the
* number of elements found within the time window
64 APPENDIX D. SOURCE CODE
* --------------------------------------------- */
#if DEBUG
fprintf(stderr, "xfit1: found %d records in time window\n", st_x.n);
#endif
if (st_x.n >= MIN_ELEMENTS) {
/* ----------------------------------------------
* Use least squares fit
* ---------------------------------------------- */
#if DEBUG
fprintf(stderr, "xfit1: good, enough for full parabola\n");
#endif
solve_stats(&st_x, 0.0,
&state->x, &state->vx, &state->ax);
solve_stats(&st_y, 0.0,
&state->y, &state->vy, &state->ay);
solve_stats(&st_z, 0.0,
&state->z, &state->vz, &state->az);
} else if ((left_time < time) && (time < right_time)) {
/* ----------------------------------------------
* Use linear interpolation
* ---------------------------------------------- */
#if DEBUG
fprintf(stderr, "xfit1: okay, linear interpolation\n");
#endif
state->x = interpolate(0.0, left_time, right_time,
left_pos->x, right_pos->x);
state->vx = (right_pos->x - left_pos->x)
/ (right_time - left_time);
state->ax = 0.0;
state->y = interpolate(0.0, left_time, right_time,
left_pos->y, right_pos->y);
state->vy = (right_pos->y - left_pos->y)
/ (right_time - left_time);
state->ay = 0.0;
state->z = interpolate(0.0, left_time, right_time,
left_pos->z, right_pos->z);
state->vz = (right_pos->z - left_pos->z)
/ (right_time - left_time);
state->az = 0.0;
} else {
#if DEBUG
fprintf(stderr, "xfit1: not enough -> zero\n");
#endif
/* -- leave the state vector nulled out. --- */
};
return left_nd;
}
/* -----------------------------------------------------------
xfit - fit a parabolic curve to a position vector [pos_list],
D.2. XFIT.C 65
----------------------------------------------------------- */
LIST * xfit(LIST *pos_list, LIST *time_list, double twindow) {
LIST *state_list;
NODE *time_nd;
NODE *state_nd;
NODE *hint=NULL;
double time;
struct state_vector_record state;
int j=0;
#if DEBUG
char time_buffer[32]
#endif
#if DEBUG
fprintf(stderr, "xfit: routine entered\n");
fprintf(stderr, "xfit: creating new list\n");
#endif
state_list = new_list();
time_nd = get_first_node_from_list(time_list);
while (time_nd) {
j++;
#if DEBUG
fprintf(stderr, "xfit: examining time element %d\n", j);
#endif
time = *((double *) time_nd->data);
#if DEBUG
fprintf(stderr, "xfit: time is %f (%s)\n", time,
time2str(time_buffer, time));
#endif
#if 1
hint = xfit1(pos_list, hint, time, twindow, &state);
#else
66 APPENDIX D. SOURCE CODE
#if DEBUG
fprintf(stderr, "xfit: routine exiting\n");
#endif
return state_list;
}
D.3 xform.h
#ifndef XFORM_H
#define XFORM_H
/* ----------------------------------------------------------------
FILE = xform.h
AUTHOR = Peter P. Eiserloh
SYSTEM = Linux 2.0.35, libc-6.0.7 (glibc-2.0.7)
COMPILER = GCC-2.7.2
PROJECT = AV-8B DATA REDUCTION TOOLS (HPM-TOOLS)
PURPOSE = Coordinate transformations (WGS-84).
-------------------------------------------------------------------
VERSION HISTORY:
4 (25-Feb-1999) PPE,
[1] Corrected comment for ned2efg(). It is a simple
rotation to the vector, the origins vector is not
applied to the result.
[2] Added cdu2ned().
3 (23-Sep-1998) Added DATUM_NAD27
CWT (23-Sep-1998)
2 (23-Sep-1998) PPE,
[1] Allow different geodetic constants to be used.
[2] Comment the routines, in particular the units.
1 (31-Aug-1998) PPE, Original
---------------------------------------------------------------- */
/* -----------------------------------------------------------------
set_datum - Set the geodetic constants to the specified [datum].
----------------------------------------------------------------- */
D.3. XFORM.H 67
/* -----------------------------------------------------------------
rae2ned - transform the coordinates [rng, azm, elev] (degrees)
to [north, east, down].
----------------------------------------------------------------- */
void rae2ned(double rng, double azm, double elev,
double *north, double *east, double *down);
/* -----------------------------------------------------------------
ned2rae - transform the coordinates [north, east, down] to [rng,
azm, elev] (degrees).
----------------------------------------------------------------- */
void ned2rae( double north, double east, double down,
double *rng, double *azm, double *elev);
/* -----------------------------------------------------------------
cdu2ned - Rotate a local vector in CDU into NED. The [rot_angle] is
the angle from true north to the flight line on which the cross and
down range vectors are based. The up component is simply converted
to a down component.
This same routine can be used as its own inverse, just negate the
rotation angle.
----------------------------------------------------------------- */
void cdu2ned(double rot_angle,
double cross, double downrange, double up,
double *north, double *east, double *down);
/* -----------------------------------------------------------------
llh2efg - transform the coordinate from [latitude, longitude, height]
(degrees, feet) (where the height is referenced to the spheroid) to
geocentric coordinates [e, f, g] (feet).
----------------------------------------------------------------- */
void llh2efg(double latitude, double longitude, double height,
double *e, double *f, double *g);
/* -----------------------------------------------------------------
efg2llh - transform the geocentric coordinates [e, f, g] (feet) to
geodetic coordinates [latitude, longitude, height] (degrees, feet).
----------------------------------------------------------------- */
void efg2llh(double e, double f, double g,
double *latitude, double *longitude, double *height);
68 APPENDIX D. SOURCE CODE
/* -----------------------------------------------------------------
ned2efg - Rotate a vector in local coordinates [north, east, down]
(feet) which has an origin at [org_lat, org_long, org_ht] to a vector
aligned to geocentric axes [e, f, g] (feet).
----------------------------------------------------------------- */
void ned2efg(double north, double east, double down,
double org_lat, double org_long, double org_ht,
double *e, double *f, double *g);
/* -----------------------------------------------------------------
efg2ned - transform a geocentric coordinate [e, f, g] (feet) into
a local coordinate system [north, east, down] (feet) which has
an origin (org_lat, org_long, org_ht).
----------------------------------------------------------------- */
void efg2ned(double e, double f, double g,
double org_lat, double org_long, double org_ht,
double *north, double *east, double *down);
#endif
D.4 xform.c
/* ----------------------------------------------------------------
FILE = xform.c
AUTHOR = Peter P. Eiserloh
SYSTEM = Linux 2.0.35, libc-6.0.7 (glibc-2.0.7)
COMPILER = GCC-2.7.2
PROJECT = AV-8B DATA REDUCTION TOOLS (HPM-TOOLS)
PURPOSE = Coordinate transformations (WGS-84).
-------------------------------------------------------------------
VERSION HISTORY:
2.7 (01-Mar-1999) PPE,
[1] Correct ned2efg(), change the sign of the middle matrix
element.
2.6 (25-Feb-1999) PPE,
[1] Correct comment about ned2efg(); it is a simple rotation,
it does not apply the origins vector.
2.5 (23-Sep-1998) PPE,
[1] Include xform.h, remove datum defines, use the ones from
the header file.
[2] Added NAD27 (Clarke-1886) datum.
CWT (23-Sep-1998)
2.4 (23-Sep-1998) PPE,
[1] Allow different geodetic constants to be used.
[2] Comment the routines, in particular the units.
1.3 (22-Sep-1998) PPE, We require some conversions r2d, d2r, ....
1.2 (15-Sep-1998) PPE, efg2llh() needed an atan() for the latitude.
1.1 (31-Aug-1998) PPE, Original
D.4. XFORM.C 69
---------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <libdr/conversions.h>
#include <libtspi/xform.h>
#if 0
#define HAYFORD_MAJOR_AXIS_METERS 6378388
#define HAYFORD_MINOR_AXIS_METERS 6356912
#define HAYFORD_ECCENT2 0.00672265318716
#endif
/* ============================================================= */
/* -----------------------------------------------------------------
set_datum - Set the geodetic constants to the specified [datum].
Return: 1 when successful, 0 when failed.
----------------------------------------------------------------- */
int set_datum(int datum) {
switch (datum) {
case DATUM_WGS84:
aa = WGS84_MAJOR_AXIS_METERS * METERS2FEET;
bb = WGS84_MINOR_AXIS_METERS * METERS2FEET;
ee = WGS84_ECCENT2;
break;
case DATUM_HAYFORD:
aa = HAYFORD_MAJOR_AXIS_METERS * METERS2FEET;
70 APPENDIX D. SOURCE CODE
bb = HAYFORD_MINOR_AXIS_METERS * METERS2FEET;
ee = HAYFORD_ECCENT2;
break;
case DATUM_NAD27:
aa = NAD27_MAJOR_AXIS_METERS * METERS2FEET;
bb = NAD27_MINOR_AXIS_METERS * METERS2FEET;
ee = NAD27_ECCENT2;
break;
default:
fprintf(stderr, "unknown datum\n");
return 0;
};
return 1;
}
/* -----------------------------------------------------------------
rae2ned - transform the coordinates [rng, azm, elev] (degrees)
to [north, east, down].
----------------------------------------------------------------- */
void rae2ned(double rng, double azm, double elev,
double *north, double *east, double *down) {
double a = azm * DEGREES2RADIANS;
double e = elev * DEGREES2RADIANS;
double saz = sin(a);
double caz = cos(a);
double sel = sin(e);
double cel = cos(e);
/* -----------------------------------------------------------------
ned2rae - transform the coordinates [north, east, down] to [rng,
azm, elev] (degrees).
----------------------------------------------------------------- */
void ned2rae( double north, double east, double down,
double *rng, double *azm, double *elev) {
double a, e;
/* -----------------------------------------------------------------
cdu2ned - Rotate a local vector in CDU into NED. The [rot_angle] is
the angle from true north to the flight line on which the cross and
down range vectors are based. The up component is simply converted
to a down component.
This same routine can be used as its own inverse, just negate the
rotation angle.
----------------------------------------------------------------- */
void cdu2ned(double rot_angle,
double cross, double downrange, double up,
double *north, double *east, double *down) {
double sx, cx;
if (rot_angle == 0.0) {
*north = downrange;
*east = cross;
} else {
sx = sin(rot_angle * DEGREES2RADIANS);
cx = cos(rot_angle * DEGREES2RADIANS);
*north = cx * downrange + sx * cross;
*east = -sx * downrange + cx * cross;
};
*down = -up;
}
/* -----------------------------------------------------------------
PRIVATE radius_primary_vertical - calculate the radius of curvature
of the earth at the specified latitude (radians).
----------------------------------------------------------------- */
double radius_primary_vertical(double latitude) {
double x, x2, denom;
x = sin(latitude);
x2 = 1.0 - ee * x * x;
denom = sqrt(x2);
return (aa / denom);
}
/* -----------------------------------------------------------------
llh2efg - transform the coordinate from [latitude, longitude, height]
(degrees, feet) (where the height is referenced to the spheroid) to
geocentric coordinates [e, f, g] (feet).
----------------------------------------------------------------- */
void llh2efg(double latitude, double longitude, double height,
double *e, double *f, double *g) {
/* -----------------------------------------------------------------
efg2llh - transform the geocentric coordinates [e, f, g] (feet) to
geodetic coordinates [latitude, longitude, height] (degrees, feet).
----------------------------------------------------------------- */
void efg2llh(double e, double f, double g,
double *latitude, double *longitude, double *height) {
double x;
double alpha;
double sa;
double ca;
double lat, lon;
double numer, denom, N;
x = sqrt(e*e + f*f);
alpha = atan(g*aa / (x*bb));
sa = sin(alpha);
ca = cos(alpha);
numer = g + bb*(ee/(1-ee))*sa*sa*sa;
denom = x - aa*ee*ca*ca*ca;
lat = atan(numer / denom);
*latitude = lat * RADIANS2DEGREES;
N = radius_primary_vertical(lat);
sa = sin(lat);
ca = cos(lat);
*height = x*ca + g*sa - N*(1-ee*sa*sa);
}
/* -----------------------------------------------------------------
ned2efg - Rotate a vector in local coordinates [north, east, down]
(feet) which has an origin at [org_lat, org_long, org_ht] to a vector
aligned to geocentric axes [e, f, g] (feet).
D.4. XFORM.C 73
----------------------------------------------------------------- */
void ned2efg(double north, double east, double down,
double org_lat, double org_long, double org_ht,
double *e, double *f, double *g) {
double sphi = sin(org_lat * DEGREES2RADIANS);
double cphi = cos(org_lat * DEGREES2RADIANS);
double slamb = sin(org_long * DEGREES2RADIANS);
double clamb = cos(org_long * DEGREES2RADIANS);
/* -----------------------------------------------------------------
efg2ned - transform a geocentric coordinate [e, f, g] (feet) into
a local coordinate system [north, east, down] (feet) which has
an origin (org_lat, org_long, org_ht).
----------------------------------------------------------------- */
void efg2ned(double e, double f, double g,
double org_lat, double org_long, double org_ht,
double *north, double *east, double *down) {
double sphi = sin(org_lat * DEGREES2RADIANS);
double cphi = cos(org_lat * DEGREES2RADIANS);
double slamb = sin(org_long * DEGREES2RADIANS);
double clamb = cos(org_long * DEGREES2RADIANS);
/* ============================================================
The following routines show some examples of using the above
primitive coordinate transforms.
============================================================ */
/* -----------------------------------------------------------------
ned2ned - Take a vector [n1, e1, d1] in one local coordinate system
[lat1, lon1, ht1] and rotate it to a different local coordinate
system [lat2, lon2, ht2] to give a vector [n2, e2, d2].
----------------------------------------------------------------- */
void ned2ned( double n1, double e1, double d1,
double lat1, double lon1, double ht1,
74 APPENDIX D. SOURCE CODE
/* -----------------------------------------------------------------
orgllh_ned_llh - Given a NED vector from a specified origin determine
the latitude, longitude, and spheroidal height of the tip of the
vector.
--------------------------------------------------------------------
NOTE: If the origin is constant you should get org_e, org_f, and
org_ht outside and use orgefg_ned_llh() for performance reasons.
----------------------------------------------------------------- */
void orgllh_ned_llh(double org_lat, double org_long, double org_ht,
double north, double east, double down,
double *lat, double *lon, double *ht) {
double org_e, org_f, org_g;
double e, f, g;
D.5 geoid.h
#ifndef GEOID_H
#define GEOID_H
/* ----------------------------------------------------------------
FILE = geoid.h
AUTHOR = Peter P. Eiserloh
SYSTEM = Linux 2.0.35, libc-6.0.7 (glibc-2.0.7)
COMPILER = GCC-2.7.2
PROJECT = AV-8B DATA REDUCTION TOOLS (HPM-TOOLS)
PURPOSE = .
-------------------------------------------------------------------
VERSION HISTORY:
1.1 (31-Aug-1998) PPE, Original
---------------------------------------------------------------- */
/* -------------------------------------------------------------
------------------------------------------------------------- */
double get_geoid_value(double latitude, double longitude);
D.6. GEOID.C 75
#endif
D.6 geoid.c
/* ----------------------------------------------------------------
FILE = geoid.c
AUTHOR = Peter P. Eiserloh
SYSTEM = Linux 2.0.35, libc-6.0.7 (glibc-2.0.7)
COMPILER = GCC-2.7.2
PROJECT = AV-8B DATA REDUCTION TOOLS (HPM-TOOLS)
PURPOSE = .
-------------------------------------------------------------------
VERSION HISTORY:
1.1 (31-Aug-1998) PPE, Original
---------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <libtspi/geoid.h>
/* ----------------------------------------------------
The geoid table gives the separation distance of the
WGS-84 spheroid from the geoid (MSL height) in units
of meters.
Each row corresponds to the longitude (0, 10, 20, ..., 170),
and each column to the latitude (90, 80, 70, ..., -90).
---------------------------------------------------- */
double geoid_table[36][19] = {
{13,33,51,47,47,52,36,31,22, 18, 12,17,22,18,25,16,16,-4,-30},
{13,34,43,41,48,48,28,26,23, 12, 13,23,27,26,26,19,16,-1,-30},
{13,28,29,21,42,35,29,15, 2,-13, -2,21,34,31,34,25,17, 1,-30},
{13,23,20,18,28,40,17, 6,-3, -9,-14, 8,29,33,39,30,21, 4,-30},
{13,17,12,14,12,33,12, 1,-7,-28,-25,-9,14,39,45,35,20, 4,-30},
{13,13, 5, 7,-10, -9,-20,-29,-36, -49,-32,-10,15,41,45,35,26,6,-30},
{13, 9, -2, -3,-19,-28,-15,-44,-59, -62,-38,-11,15,30,38,33,26,5,-30},
{13, 4,-10,-22,-33,-39,-40,-61,-90, -89,-60,-20, 7,24,39,30,22,4,-30},
{13, 4,-14,-29,-43,-48,-33,-67,-95,-102,-75,-40,-9,13,28,27,16,2,-30},
/* -- 90 -- */
{13, 1,-12,-32,-42,-59,-34,-59,-63,-63,-63,-47,-25,-2,13,10,10,-6,-30},
{13,-2,-10,-32,-43,-50,-34,-36,-24,-9,-26,-45,-37,-20,-1,-2,-1,-15,-30},
{13,-2,-14,-26,-29,-28,-28,-11,12,33,0,-25,-39,-32,-15,-14,-16,-24,-30},
{13, 0,-12,-15, -2, 3, 7,21,53,58,35, 5,-23,-33,-22,-23,-29,-33,-30},
{13, 2, -6, -2, 17, 23,29,39,60,73,52,23,-14,-27,-22,-30,-36,-40,-30},
{13, 3, -2, 13, 23, 37,43,49,58,74,68,45, 15,-14,-18,-33,-46,-48,-30},
76 APPENDIX D. SOURCE CODE
/* -- 180 -- */
{13,3,2,2,-8,-12,-7,5,13,22,36,51,46,21,-15,-45,-61,-53,-30},
{13,1,2,9,8,-10,-5,10,12,16,22,27,22,6,-18,-43,-60,-54,-30},
{13,-2,1,17,8,-13,-8,7,11,17,11,10,5,1,-18,-37,-61,-55,-30},
{13,-3,-1,10,1,-20,-15,-7,2,13,6,0,-2,-7,-16,-32,-55,-52,-30},
{13,-3,-3,13,-11,-31,-28,-23,-11,1,-1,-9,-8,-12,-17,-30,-49,-48,-30},
{13,-3,-7,1,-19,-34,-40,-39,-28,-12,-8,-11,-13,-12,-15,-26,-44,-42,-30},
{13,-1,-14,-14,-16,-21,-42,-47,-38,-23,-10,-5,-10,-12,-10,-23,-38,-38,-30},
{13,3,-24,-30,-18,-16,-29,-34,-29,-20,-8,-2,-7,-10,-10,-22,-31,-38,-30},
{13,1,-27,-39,-22,-26,-22,-9,-10,-14,-11,-3,-4,-7,-8,-16,-25,-29,-30},
/* -- 270 -- */
{13, 5,-25,-46,-35,-34,-26,-10, 3,-3,-9,-1, 1,-1,-2,-10,-16,-26,-30},
{13, 9,-19,-42,-40,-33,-32,-20, 1,14, 1, 9, 9, 8, 6, -2, -6,-26,-30},
{13,11, 3,-21,-26,-35,-51,-45,-11,10,32,35,32,23,14, 10, 1,-24,-30},
{13,19, 24, 6,-12,-26,-40,-48,-41,-15,4,20,16,15,13, 20, 4,-23,-30},
{13,27, 37, 29, 24, 2,-17,-32,-42,-27,-18,-5, 4,-2, 3,20, 5,-21,-30},
{13,31, 47, 49, 45, 33, 17, -9,-16,-18,-13,-6,-8,-6, 3,21, 4,-19,-30},
{13,34, 60, 65, 63, 59, 31, 17, 3, 3, -9,-5, 4, 6,10,24, 2,-16,-30},
{13,33, 61, 60, 62, 52, 34, 25, 17, 12, 4, 0,12,21,20,22,6,-12,-30},
{13,34, 58, 57, 59, 51, 44, 31, 33, 20, 14,13,15,24,27,17,12,-8,-30}
};
/* -------------------------------------------------------------
------------------------------------------------------------- */
double get_geoid_value(double latitude, double longitude) {
double lat, lat1, lat2;
double lon, lon1, lon2;
int row, col;
double a0, a1, a2, a3;
double n1, n2, n3, n4;
double x, y, z;
#if 0
D.6. GEOID.C 77
return METERS2FEET * z;
}
GLOSSARY
Alrite A laser sensor operated by the range Dept., which can track the aircraft under test.
ARDS Advanced Range Data System: A pod, looking like a sidewinder missile, containing a GPS receiver
that mounts onto a wing station, and which collects GPS data to be used as TSPI data.
CDU Cross Range, Down Range, Up coordinate system. Similar to ENU, but rotated about a flight line.
China Lake The Naval Air Warfare Center - Weapons Division, China Lake. This is one of the US Navy’s
RD&TE laboratories for airborne weapons development.
CTDF Common Test Data Format (previously Common TSPI Data Format).
Datum A reference surface or line used in surveying (i.e., WGS-84, or Clarke 1880 spheroid).
EFG The names (E, F, and G) of the axes of the ECEF coordinate system.
Elevation The angle up from the local horizontal plane. (contrast this with altitude).
Ellipsoid A geometric shape whose plane sections are all ellipses or circles. In the general case an ellipsoid
has three axes (a, b, and c).
EWTES Electronic Warfare Threat Environment Simulation (was Echo Range). This is the EW test range
in South portion of China Lake.
Geodetic A coordinate system defined by the surface of the earth using latitude, longitude, and height, based
upon a chosen datum.
Geoid The gravitational equipotential surface at zero feet MSL, and which is perpendicular to the local
gravity field.
79
80 GLOSSARY
Longitude The angle from the prime meridian at Greenwich England towards the East (i.e., East/West dis-
tance).
LOQ Level of Quality
LSF Least Squares Fit.
MAGR Miniaturized Airborne GPS Receiver
NED North, East, Down local Cartesian coordinate system
NIKE The NIKE Radar is a ground based radar set from the Vietnam war era. Commonly used today as a
source of TSPI data. It usually has a TV camera mounted on the same pedestal as the radar disk, to
give an Electro-Optical track, and verification.
Oblate The shape of a spheroid when the axis of rotation is the semi-minor axis ‘b’. Thus an oblate spheroid
is like a squashed ball.
Orthogonal Perpendicular. A system of independent equations.
Orthometric Height Height above mean sea level, in the direction normal to the local gravitational equipo-
tential surface. (Contrast this with Spheroidal Height)
Prolate The shape of a spheroid where the axis of rotation is the semi-major axis ‘a’. Thus a prolate spheroid
looks like a watermelon.
RAE Range, Azimuth, Elevation coordinate system
RCC Range Command Center, also Range Command Council
RIPS Range Instrumentation Processing System
Spheroid The shape generated by rotating an ellipse about one of its axes. A spheroid can be characterized
as either oblate, or prolate.
Spheroidal Height Height above the spheroid, in the direction normal to the spheroid.
Transformation A mathematical process of changing a vector described in on coordinate system into a
different coordinate system.
TAER Time Azimuth Elevation Range
TSPI Time Space Position Information
WGS World Geodetic System
Bibliography
[DMA-1987] “Distribution of the GPS UE Relevant WGS 84 DATA Base Package” dtd 12 JAN 87.
HQ USAF Space Division, SD/CWNE, Michael J. Ellett, DMA Representative, Direc-
torate of Systems Engineering, NAVSTAR Global Positioning System.
[HEARN-1986] “Computer Graphics”, Donald Hearn, and M. Pauline Baker. Prentice Hall, Englewood
Cliffs, New Jersey 07632. ISBN: 0-13-165382-2
[JAMES-1990] “Baseline Software Program Descriptions” dated January 24, 1990, revised Feb 19,
1990, by Robert James of GMD Systems, for Contract N60530-89-0083 for Naval
Weapons Center, China Lake.
[LAMPREACH-1996] “Definition and Incorporation of the Common TSPI Data Format (CTDF)” MEMO
dated 05/22/96. Jon A. Lampreach (MDA-NAWC) (760) 446-3507
[LANGLEY] “Basic Geodesy for GPS”, Richard B. Langley, GPS World.
[MILBERT-XX] “GPS and Geoid90 - The New Leveling Rod”, by Dennis Milbert (National Geodetic
Survey), GPS World, February 1992
[RCC-1985] “Global Coordinate System”, Range Commanders Council, Data Reduction and Com-
puter Group. Document 151-85 (Revised June 1989)
[RIPS-1985] “RIPS DATA PRODUCTS TAPE SPECIFICATION” dtd 12-Mar-85. Floyd Hall: Code
6251A Range Dept, Test and Evaluation Directorate, Naval Weapons Center CA.
81
82 BIBLIOGRAPHY
COLOPHON
This document was originally written on a Macintosh with Microsoft Word, then ported to Microsoft Win-
dows, again with Microsoft Word. Both the equations and graphics had to be redone during this ‘simple’
re-hosting.
When my main OS transitioned from MS-Windows in its various incarnations to Linux, I could no longer
use MS-Word. I had to either keep a copy of MS-Windows and MS-Word, freeze the document, or port the
document over to some other documentation system. The latter was chosen.
There were a number of options available. Choose a word processor, SGML, HTML, TEX, LATEX, or other
mark-up format.
One of many problems with using a word processor, was determining the changes between revisions. If
this were source code (straight text) the program ‘diff ’ could be run against the document, and its previous
version to generate a complete list of changes.
Another big problem with word processors, especially the proprietary ones such as Word Perfect, was
long term viability. I wanted a system that could build the document twenty or more years from now. This
was most easily satisfied by using the open source software readily available on the Internet.
The SGML document looked to be the best match. It not only could be processed to generate Postscript
(tm), but also LATEX, text, or even HTML.
An initial port was done, but it was disappointing due to problems with the style sheets. Orphan control
was very poor. The headings of paragraphs would in many cases end on a page, with the body starting the next
one. Also the method of equation handling was difficult. The equations were written in TEX and converted
to Encapsulated Postscript (EPS) files, one for each equation. The figures were similarly handled (they were
built with xfig), and saved as EPS files.
TEX, and LATEXwere mature, open source, and came with all Linux distributions. It was available under
most operating systems including other versions of Unix, Mac-OS, MS-Windows, MS-DOS, IBM’s OS/390,
Amiga-DOS, and many others. It provided a consistent output regardless of the particular OS on which it
was currently hosted.
LATEX was a macro language on top of TEX, supplying a structuring for the document. The document files
were text, and could be edited with a simple text editor, diff works on these, as does document configuration
software such as CVS.
Version 0.6.4 of the document was re-hosted using LATEX 2 files. At first, the computer modern fonts
were used, these were the default fonts with both TEX, and LATEX. These looked okay when the output was
only Postscript, but when converted to a Portable Document File (PDF) format it looked horrible, so I changed
the font to the standard Postscript font ‘Times’. This was accomplished by simply using the package ‘times’.
The equations are written in the main text. The figures are created with xfig and exported as EPS files.
These EPS files are then referenced at the appropriate places by the LATEX files. Each chapter, appendix, or
other entity has its own LATEX file. The source code in Appendix D, was imported by simply nesting the
source code within a verbatim environment.
The entire system is managed via a Makefile. Executing make against a target within the Makefile pro-
vides the method of interacting with the system. The commands used to build the document to the output
formats are stored within the Makefile.
83
Index
,8 ECEF, 3
,8 Echo Range, 21, 29, 35
,9 EFG, 9, 16
,9 efg2llh, 10
elevation, 8
A/A, 18 ellipse, 37
Air-to-Air, 1 End of Data Record, 26
air-to-air, 18 End of Run Record, 25
Alrite Laser, 8 ENU, 1, 7, 26
Alrite Lasers, 1 error function, 30
anti-symmetric, 16 error in latitude, 11
arcsin(), 9 extrema, 30
arctan2, 11
arctan2(), 9 filter, 29
ARDS Pods, 1 flight line, 7
ARDS pods, 21, 22 flight line rotation, 2, 26
augmented matrices, 32 FLIR, 2
axes of rotation, 37 FRD, 2
axis of rotation, 40
azimuth, 8 Gauss–Jordan elimination, 30–34
General Information Record, 24
Baker Range, 21 geocentric coordinate system, 9
bi–linear interpolation, 51, 52 geocentric coordinates, 9
Bowring, 10, 11 geocentric height, 21
bowring error, 11
geodetic height, 3, 21
bumpy, 4, 51
geodetic separation, 4
Cartesian, 1 Geoid, 51
CDU, 1 geoid, 4, 51
cdu2ned, 7 GEOID–84, 51
China Lake, 1, 4, 21, 51, 52 GEOID–90, 51
Common Test Data Format, 23 geoidal separation, 4, 10, 51
composite rotation matrix, 13 GPS Pods, 1
Coordinate Transformations, 7 GPS sensor, 22
CTDF, 21, 23 Greenwich England, 3
Ground Moving Target, 1
Data Editing, 36 ground moving target, 18
data editing, 29
Data Record, 25 Height, 12
datum, 2 height, 37
HUD, 2
Earth Model, 3
earth’s surface, 51 Inertial Navigation Set, 2, 22
eccentricity, 38 INS, 2, 22
84
INDEX 85
Parabolic Filter, 32
parabolic fit, 29
parabolic interpolation, 35
Parameter Identification Record, 24
PAX River, 23
perpendicular, 39