|
|
| |
Astro::Coord::ECI(3) |
User Contributed Perl Documentation |
Astro::Coord::ECI(3) |
Astro::Coord::ECI - Manipulate geocentric coordinates
use Astro::Coord::ECI;
use Astro::Coord::ECI::Sun;
use Astro::Coord::ECI::TLE;
use Astro::Coord::ECI::Utils qw{rad2deg};
# 1600 Pennsylvania Avenue, in radians, radians, and KM
my ($lat, $lon, $elev) = (0.678911227503559,
-1.34456123391096, 0.01668);
# Record the time
my $time = time ();
# Set up observer's location
my $loc = Astro::Coord::ECI->geodetic ($lat, $lon, $elev);
# Uncomment to turn off atmospheric refraction if desired.
# $loc->set( refraction => 0 );
# Instantiate the Sun.
my $sun = Astro::Coord::ECI::Sun->universal ($time);
# Figure out if the Sun is up at the observer's location.
my ($azimuth, $elevation, $range) = $loc->azel ($sun);
print "The Sun is ", rad2deg ($elevation),
" degrees above the horizon.\n";
See the Astro::Coord::ECI::TLE documentation for an example
involving satellite pass prediction.
This module was written to provide a base class for a system to predict
satellite visibility. Its main task is to convert the Earth-Centered Inertial
(ECI) coordinates generated by the NORAD models into other coordinate systems
(e.g. latitude, longitude, and altitude above mean sea level), but a other
functions have accreted to it. In addition, a few support routines have been
exposed for testing, or whatever.
All distances are in kilometers, and all angles are in radians
(including right ascension, which is usually measured in hours).
Times are normal Perl times, whether used as universal or
dynamical time. Universal time is what is usually meant, unless otherwise
stated.
Known subclasses include Astro::Coord::ECI::Moon to predict
the position of the Moon, Astro::Coord::ECI::Star to predict the
position of a star, or anything else that can be considered fixed on the
celestial sphere, Astro::Coord::ECI::Sun to predict the position of
the Sun, Astro::Coord::ECI::TLE to predict the position of a
satellite given the NORAD orbital parameters, and
Astro::Coord::ECI::TLE::Iridium (a subclass of
Astro::Coord::ECI::TLE, and as of 0.099_01 moved to its own package) to
predict Iridium flares.
Note that in version 0.022_01 the velocity code got a
substantial rework, which is still in progress. I am attempting give useful
velocities where they are available, and no velocities at all where they are
not. Unfortunately I have yet to locate any worked problems, so the velocity
code is, in the most literal sense, untested.
In general, locations specified in Earth-fixed coordinates are
considered to share the rotational velocity of the Earth, and locations
specified in inertial coordinates are considered to have undefined
velocities unless a velocity was specified explicitly or produced by the
object's model. This involved a change in the behavior of the eci()
method when velocity was not specified but location was. See the next
paragraph for my excuse.
Caveat user: This class and its subclasses should probably
be considered alpha code, meaning that the public interface may not be
completely stable. I will try not to change it, but given sufficient reason
I will do so. If I do so, I will draw attention to the change in the
documentation.
The following methods should be considered public.
- $coord = Astro::Coord::ECI->new ();
- This method instantiates a coordinate object. Any arguments are passed to
the set() method once the object has been instantiated.
- $angle = $coord->angle ($coord2, $coord3);
- This method calculates the angle between the
$coord2 and $coord3
objects, as seen from $coord. The calculation uses
the law of haversines, and does not take atmospheric refraction into
account. The return is a number of radians between 0 and pi.
The algorithm comes from "Ask Dr. Math" on the Math
Forum,
"https://www.nctm.org/tmf/library/drmath/view/51879.html",
which attributes it to the Geographic Information Systems FAQ,
<http://www.faqs.org/faqs/geography/infosystems-faq/>, which in
turn attributes it to R. W. Sinnott, "Virtues of the
Haversine," Sky and Telescope, volume 68, number 2, 1984, page
159.
Unfortunately, as of early 2021 the National Council of
Teachers of Mathematics restricted the Dr. Math content to their
members, but an annotated and expanded version of the article on
haversines is available at
<https://www.themathdoctors.org/distances-on-earth-2-the-haversine-formula/>.
If you want the original article, you can feed the URL
"http://mathforum.org/library/drmath/view/51879.html"
to the Wayback Machine.
Prior to version 0.011_03 the law of cosines was used, but
this produced errors on extremely small angles. The haversine law was
selected based on Jean Meeus, "Astronomical Algorithms", 2nd
edition, chapter 17 "Angular Separation".
This method ignores the
"station" attribute.
- $which = $coord->attribute ($name);
- This method returns the name of the class that implements the named
attribute, or undef if the attribute name is not valid.
- ($azimuth, $elevation, $range) = $coord->azel( $coord2 );
- This method takes another coordinate object, and computes its azimuth,
elevation, and range in reference to the object doing the computing. The
return is azimuth in radians measured clockwise from North (always
positive), elevation above the horizon in radians (negative if below), and
range in kilometers.
As a side effect, the time of the
$coord object may be set from the
$coord2 object.
Atmospheric refraction is taken into account using the
"correct_for_refraction()" method if
the $coord object's
"refraction" attribute is true. The
invocant's "correct_for_refraction()"
method is the one used; that is, if $coord and
$coord2 have different
"correct_for_refraction()" methods,
the $coord object's method is used.
Note that the
"correct_for_refraction" attribute
defaults to true. For cases where both invocant and argument are
ground-based objects, you should probably set the invocant's
"correct_for_refraction" false before
invoking this method.
This method is implemented in terms of azel_offset().
See that method's documentation for further details.
- ( $azimuth, $elevation, $range ) = $coord->azel();
- This method computes the azimuth, elevation, and range if the
$coord object as seen from the position stored in
the $coord object's
"station" attribute. An exception will
be thrown if the "station" attribute is
not set.
- ($azimuth, $elevation, $range) = $coord->azel_offset($coord2,
$offset);
- This method takes another coordinate object, and computes its azimuth,
elevation, and range in reference to the object doing the computing. The
return is azimuth in radians measured clockwise from North (always
positive), elevation above the horizon in radians (negative if below), and
range in kilometers.
If the optional $offset argument is
provided, the elevation is offset upward by the given fraction of the
radius of the $coord2 object. Thus, an
$offset of 1 specifies
the upper limb of the object, 0 specifies the
center of the object, and "-1"
specifies the lower limb. This offset is applied before atmospheric
refraction.
As a side effect, the time of the
$coord object may be set from the
$coord2 object.
By default, atmospheric refraction is taken into account in
the calculation of elevation, using the
"correct_for_refraction()" method.
This better represents the observed position in the sky when the object
is above the horizon, but produces a gap in the data when the object
passes below the horizon, since I have no refraction equations for rock.
See the "correct_for_refraction()"
documentation for details.
The invocant's
"correct_for_refraction()" method is
the one used; that is, if $coord and
$coord2 have different
"correct_for_refraction()" methods,
the $coord object's method is used.
If you want to ignore atmospheric refraction (and not have a
gap in your data), set the
"refraction" attribute of the
$coord object to any value Perl considers false
(e.g. 0).
The algorithm for position is the author's, but he confesses
to having to refer to T. S. Kelso's "Computers and Satellites"
column in "Satellite Times", November/December 1995, titled
"Orbital Coordinate Systems, Part II" and available at
http://celestrak.com/columns/v02n02/ to get the signs right.
If velocities are available for both bodies involved in the
calculation, they will be returned after the position (i.e. you get a
six-element array back instead of a three-element array). The velocity
of a point specified in Earth-fixed coordinates (e.g. geodetic latitude,
longitude, and altitude) is assumed to be the rotational velocity of the
Earth at that point. The returned velocities are azimuthal velocity in
radians per second (not radians of azimuth, which get smaller as
you go farther away from the Equator), elevational velocity in radians
per second, and velocity in recession in kilometers per second, in that
order.
If velocities are available for both bodies and the
$coord2 object has its
"frequency" attribute set, the
returned array will contain seven elements, with the seventh being the
Doppler shift.
The algorithm for recessional velocity comes from John A.
Magliacane's "Predict" program,
available at <https://www.qsl.net/kd2bd/predict.html>. The
transverse velocity computations are the author's, but use the same
basic approach: vector dot product of the velocity vector with a unit
vector in the appropriate direction, the latter generated by the
appropriate (I hope!) vector cross products.
Velocity conversions to
"azel()" appear to me to be mostly
sane. See A NOTE ON VELOCITIES, below, for details.
If velocities are available and you have provided a
non-zero value for the "frequency"
attribute, you will get the Doppler shift as the seventh element of the
returned array. The caveats about velocity in recession apply to
the Doppler shift as well. The frequency is from the
$coord2 object. Getting the frequency from the
$coord object used to be supported as a
fallback, but now results in an exception.
- ( $azimuth, $elevation, $range ) = $coord->azel_offset( $offset );
- This method computes the azimuth, elevation, and range if the
$coord object as seen from the location stored in
the $coord object's
"station" attribute. The functionality
is as above, except for the fact that in the above version the station is
the invocant, whereas in this version the orbiting body is the invocant.
This version also returns velocities if they are available for
both bodies, and Doppler shift if in addition the
"frequency" attribute of the invocant
is set.
- $coord2 = $coord->clone ();
- This method does a deep clone of an object, producing a different but
identical object.
At the moment, it's really just a wrapper for
Clone::clone.
- $elevation = $coord->correct_for_refraction ($elevation);
- This method corrects the given angular elevation for atmospheric
refraction. This is done only if the elevation has a reasonable chance of
being visible; that is, if the elevation before correction is not more
than two degrees below either the 'horizon' attribute or zero, whichever
is lesser. Sorry for the discontinuity thus introduced, but I did not wish
to carry the refraction calculation too low because I am uncertain about
the behavior of the algorithm, and I do not have a corresponding algorithm
for refraction through magma.
This method can also be called as a class method, in which
case the correction is applied only if the uncorrected elevation is
greater than minus two degrees. It is really only exposed for testing
purposes (hence the cumbersome name). The azel() method calls it
for you if the "refraction" attribute
is true.
The algorithm for atmospheric refraction comes from Thorfinn
Saemundsson's article in "Sky and Telescope", volume 72, page
70 (July 1986) as reported Jean Meeus' "Astronomical
Algorithms", 2nd Edition, chapter 16, page 106, and includes the
adjustment suggested by Meeus.
- $angle = $coord->dip ();
- This method calculates the dip angle of the horizon due to the altitude of
the body, in radians. It will be negative for a location above the surface
of the reference ellipsoid, and positive for a location below the surface.
The algorithm is simple enough to be the author's.
- $coord = $coord->dynamical ($time);
- This method sets the dynamical time represented by the object.
This method can also be called as a class method, in which
case it instantiates the desired object.
The algorithm for converting this to universal time comes from
Jean Meeus' "Astronomical Algorithms", 2nd Edition, Chapter
10, pages 78ff.
- $time = $coord->dynamical ();
- This method returns the dynamical time previously set, or the universal
time previously set, converted to dynamical.
The algorithm comes from Jean Meeus' "Astronomical
Algorithms", 2nd Edition, Chapter 10, pages 78ff.
- $coord = $coord->ecef($x, $y, $z, $xdot, $ydot, $zdot)
- This method sets the coordinates represented by the object in terms of
"Earth-Centered, Earth-fixed (ECEF) coordinates" in kilometers,
with the x axis being latitude 0 longitude 0, the y axis being latitude 0
longitude 90 degrees east, and the z axis being latitude 90 degrees north.
The velocities in kilometers per second are optional, and will default to
zero. ECEF velocities are considered to be relative to the surface of the
Earth; when converting to ECI, the rotational velocity of the Earth will
be added in.
Note that prior to version 0.022_01, the documentation
said that the default velocity was the rotational velocity of the Earth.
This was not correct in ECEF coordinates. The functionality of
the code itself in this respect did not change.
The object itself is returned.
This method can also be called as a class method, in which
case it instantiates the desired object.
- ($x, $y, $z, $xdot, $ydot, $zdot) = $coord->ecef();
- This method returns the object's "Earth-Centered, Earth-fixed (ECEF)
coordinates".
If the original coordinate setting was in an inertial system
(e.g. eci, equatorial, or ecliptic) and the absolute difference
between the current value of 'equinox_dynamical' and the current
dynamical() setting is greater than the value of
$Astro::Coord::ECI::EQUINOX_TOLERANCE, the
coordinates will be precessed to the current dynamical time before
conversion. Yes, this should be done any time the equinox is not the
current time, but for satellite prediction precession by a year or so
does not seem to make much difference in practice. The default value of
$Astro::Coord:ECI::EQUINOX_TOLERANCE is 365
days. Note that if this behavior or the default value of
$EQUINOX_TOLERANCE begins to look like a bug, it
will be changed, and noted in the documentation.
Some velocity conversions involving
"ecef()" appear to me to be mostly
sane. See A NOTE ON VELOCITIES, below, for details.
- $coord = $coord->eci ($x, $y, $z, $xdot, $ydot, $zdot, $time)
- This method sets the coordinates represented by the object in terms of
"Earth-Centered Inertial (ECI) coordinates" in kilometers, time
being universal time, the x axis being 0 hours "Right Ascension"
0 degrees "Declination", y being 6 hours "Right
Ascension" 0 degrees "Declination", and z being 90 degrees
north "Declination". The velocities in kilometers per second are
optional. If omitted, the object will be considered not to have a
velocity. This is a change introduced with version 0.022_01.
Before that, the velocity defaulted to 0.
The time argument is optional if the time represented by the
object has already been set (e.g. by the universal() or
dynamical() methods).
The object itself is returned.
This method can also be called as a class method, in which
case it instantiates the desired object. In this case the time is not
optional.
The algorithm for converting from ECI to geocentric
coordinates and back is based on the description of ECI coordinates in
T. S. Kelso's "Computers and Satellites" column in
"Satellite Times", September/October 1995, titled
"Orbital Coordinate Systems, Part I" and available at
http://celestrak.com/columns/v02n01/.
- ($x, $y, $z, $xdot, $ydot, $zdot) = $coord->eci($time);
- This method returns the "Earth-Centered Inertial (ECI)
coordinates" of the object at the given time. The time argument is
actually optional if the time represented by the object has already been
set.
If you specify a time, the time represented by the object will
be set to that time. The net effect of specifying a time is equivalent
to
($x, $y, $z, $xdot, $ydot, $zdot) = $coord->universal($time)->eci()
If the original coordinate setting was in a non-inertial
system (e.g. ECEF or geodetic), the equinox_dynamical attribute will be
set to the object's dynamical time.
Velocities will be returned if they were originally provided.
This is a change introduced in version 0.022_01. Prior to
that version, velocities were always returned.
Some velocity conversions involving
"eci()" appear to me to be mostly
sane. See A NOTE ON VELOCITIES, below, for details.
- $coord = $coord->ecliptic_cartesian( $X, $Y, $Z, $time );
- This method sets the Cartesian "Ecliptic" coordinates
represented by the object in terms of
"X" (kilometers toward the vernal
equinox), "Y" (90 degrees along the
ecliptic from "X"), and
"Z" (toward ecliptic North). The time is
universal time. The object itself is returned.
The time argument is optional if the time represented by the
object has already been set (e.g. by the universal() or
dynamical() methods).
This method can also be called as a class method, in which
case it instantiates the desired object. In this case the time is not
optional.
Caveat: you can pass in velocities (before the
$time) but they are unsupported, meaning that I
can not at this point say whether they will be transformed sanely, much
less correctly. Caveat programmer.
- ( $X, $Y, $Z) = $coord->ecliptic_cartesian( $time );
- This method returns the Cartesian ecliptic coordinates of the object at
the given time. The time is optional if the time represented by the object
has already been set (e.g. by the universal() or dynamical()
methods).
Caveat: velocities are unsupported by this method. That
means you may (or may not, depending on the coordinates originally set)
get them back, but I have not looked into whether they are actually
correct.
- $coord = $coord->ecliptic ($latitude, $longitude, $range, $time);
- This method sets the "Ecliptic" coordinates represented by the
object in terms of "Ecliptic latitude" and "Ecliptic
longitude" in radians, and the range to the object in kilometers,
time being universal time. The object itself is returned.
The time argument is optional if the time represented by the
object has already been set (e.g. by the universal() or
dynamical() methods).
The latitude should be a number between -PI/2 and PI/2 radians
inclusive. The longitude should be a number between -2*PI and 2*PI
radians inclusive. The increased range (one would expect -PI to PI) is
because in some astronomical usages latitudes outside the range + or -
180 degrees are employed. A warning will be generated if either of these
range checks fails.
This method can also be called as a class method, in which
case it instantiates the desired object. In this case the time is not
optional.
The algorithm for converting from ecliptic latitude and
longitude to right ascension and declination comes from Jean Meeus'
"Astronomical Algorithms", 2nd Edition, Chapter 13, page
93.
- ($latitude, $longitude, $range) = $coord->ecliptic ($time);
- This method returns the ecliptic latitude and longitude of the object at
the given time. The time is optional if the time represented by the object
has already been set (e.g. by the universal() or dynamical()
methods).
Caveat: velocities are not returned by this method.
- $longitude = $coord->ecliptic_longitude();
- This method returns the ecliptic longitude of the body at its current time
setting, in radians. It is really just a convenience method, since it is
equivalent to "( $coord->ecliptic()
)[1]", and in fact that is how it is implemented.
- $seconds = $self->equation_of_time( $time );
- This method returns the equation of time at the given dynamical
time. If the time is "undef", the
invocant's dynamical time is used.
The algorithm is from W. S. Smart's "Text-Book on
Spherical Astronomy", as reported in Jean Meeus' "Astronomical
Algorithms", 2nd Edition, Chapter 28, page 185.
- $coord->equatorial ($rightasc, $declin, $range, $time);
- This method sets the "Equatorial" coordinates represented by the
object (relative to the center of the Earth) in terms of "Right
Ascension" and "Declination" in radians, and the range to
the object in kilometers, time being universal time. The object itself is
returned.
If "equatorial()" is called
in this way, the "station" attribute
will be ignored, for historical reasons.
The right ascension should be a number between 0 and 2*PI
radians inclusive. The declination should be a number between -PI/2 and
PI/2 radians inclusive. A warning will be generated if either of these
range checks fails.
The time argument is optional if the time represented by the
object has already been set (e.g. by the universal() or
dynamical() methods).
This method can also be called as a class method, in which
case it instantiates the desired object. In this case the time is not
optional.
You may optionally pass velocity information in addition to
position information. If you do this, the velocity in right ascension
(in radians per second), declination (ditto), and range (in kilometers
per second in recession) are passed after the position arguments, and
before the $time argument if any.
- ( $rightasc, $declin, $range ) = $coord->equatorial( $time );
- This method returns the "Equatorial" coordinates of the object
at the relative to the center of the Earth. The
"station" attribute is ignored. The time
argument is optional if the time represented by the object has already
been set (e.g. by the universal() or dynamical() methods).
If velocities are available from the object (i.e. if it is an
instance of Astro::Coord::ECI::TLE) the return will contain velocity in
right ascension, declination, and range, the first two being in radians
per second and the third in kilometers per second in recession.
Caveat: these velocities are believed by me to be sane
if they are derived from ECI coordinates. This method does not
support setting velocities. See A NOTE ON VELOCITIES, below, for
details.
- ($rightasc, $declin, $range) = $coord->equatorial( $coord2 );
- This method is retained (for the moment) for historical reasons, but
"equatorial_apparent()" is preferred.
This method returns the apparent equatorial coordinates of the
object represented by $coord2, as seen from the
location represented by $coord.
As a side effect, the time of the
$coord object may be set from the
$coord2 object.
If the "refraction"
attribute of the $coord object is true, the
coordinates will be corrected for atmospheric refraction using the
correct_for_refraction() method.
If velocities are available from both objects (i.e. if both
objects are Astro::Coord::ECI::TLE objects) the return will contain
velocity in right ascension, declination, and range, the first two being
in radians per second and the third in kilometers per second in
recession.
Caveat: these velocities are believed by me not
to be correct.
- ($ra, $decl, $rng) = $coord->equatorial_apparent( $sta );
- This method returns the apparent equatorial coordinates of the
$coord object as seen from the object specified by
the $sta argument, or by the object in the
"station" attribute of the
$coord object if no argument is specified.
This method will return velocities if available, but I have no
idea whether they are correct.
- my ($rasc, $decl, $range, $v_rasc, $v_decl, $v_r) =
$coord->equatorial_unreduced($body);
- This method computes the unreduced equatorial position of the second ECI
object as seen from the first. If the second argument is undefined,
computes the equatorial position of the first object as seen from the
center of the Earth. Unlike the equatorial() method itself, this
method is an accessor only. This method would probably not be exposed
except for the anticipation of the usefulness of
$range and $v_r in
satellite conjunction computations, and the desirability of not taking the
time to make the two atan2() calls that are unneeded in this
application.
The 'unreduced' in the name of the method is intended to refer
to the fact that the $rasc and
$decl are not the right ascension and
declination themselves, but the arguments to atan2() needed to
compute them, and $v_rasc and
$v_decl are in km/sec, rather than being divided
by the range to get radians per second.
This method ignores the 'station'
attribute.
The returned data are:
$rasc is an array reference, which can
be converted to the right ascension in radians by
mod2pi(atan2($rasc->[0], $rasc->[1])).
$decl is an array reference, which can
be converted to the declination in radians by atan2($decl->[0],
$decl->[1]).
$range is the range in kilometers.
$v_rasc is the velocity in the right
ascensional direction in kilometers per second. It can be converted to
radians per second by dividing by $range.
$v_decl is the velocity in the
declinational direction in kilometers per second. It can be converted to
radians per second by dividing by $range.
$v_r is the velocity in recession in
kilometers per second. Negative values indicate that the objects are
approaching.
The velocities are only returned if they are available from
the input objects.
Caveat: these velocities are believed by me not
to be correct.
- $coord = $coord->equinox_dynamical ($value);
- This method sets the value of the equinox_dynamical attribute, and returns
the modified object. If called without an argument, it returns the current
value of the equinox_dynamical attribute.
Yes, it is equivalent to
$coord->set (equinox_dynamical =>
$value) and
$coord->get ('equinox_dynamical'). But there
seems to be a significant performance penalty in the
$self->SUPER::set () needed to get this
attribute set from a subclass. It is possible that more methods like
this will be added, but I do not plan to eliminate the set()
interface.
- $coord = $coord->geocentric($psiprime, $lambda, $rho);
- This method sets the "Geocentric" coordinates represented by the
object in terms of "Geocentric latitude" psiprime and
"Longitude" lambda in radians, and distance from the center of
the Earth rho in kilometers.
The latitude should be a number between -PI/2 and PI/2 radians
inclusive. The longitude should be a number between -2*PI and 2*PI
radians inclusive. The increased range (one would expect -PI to PI) is
because in some astronomical usages latitudes outside the range + or -
180 degrees are employed. A warning will be generated if either of these
range checks fails.
This method can also be called as a class method, in which
case it instantiates the desired object.
This method should not be used with map coordinates
because map latitude is "Geodetic latitude", measured in terms
of the tangent of the reference ellipsoid, whereas geocentric
coordinates are, essentially, spherical coordinates.
The algorithm for conversion between geocentric and ECEF is
the author's.
- ($psiprime, $lambda, $rho) = $coord->geocentric();
- This method returns the "Geocentric latitude",
"Longitude", and distance to the center of the Earth.
- $coord = $coord->geodetic($psi, $lambda, $h, $ellipsoid);
- This method sets the "Geodetic" coordinates represented by the
object in terms of its "Geodetic latitude" psi and
"Longitude" lambda in radians, and its height h above mean sea
level in kilometers.
The latitude should be a number between -PI/2 and PI/2 radians
inclusive. The longitude should be a number between -2*PI and 2*PI
radians inclusive. The increased range (one would expect -PI to PI) is
because in some astronomical usages latitudes outside the range + or -
180 degrees are employed. A warning will be generated if either of these
range checks fails.
The ellipsoid argument is the name of a "Reference
Ellipsoid" known to the class, and is optional. If passed, it will
set the ellipsoid to be used for calculations with this object. If not
passed, the default ellipsoid is used.
This method can also be called as a class method, in which
case it instantiates the desired object.
The conversion from geodetic to geocentric comes from Jean
Meeus' "Astronomical Algorithms", 2nd Edition, Chapter 11,
page 82.
This is the method that should be used with map
coordinates.
- ($psi, $lambda, $h) = $coord->geodetic($ellipsoid);
- This method returns the geodetic latitude, longitude, and height above
mean sea level.
The ellipsoid argument is the name of a "Reference
Ellipsoid" known to the class, and is optional. If not specified,
the most-recently-set ellipsoid will be used.
The conversion from geocentric to geodetic comes from
Kazimierz Borkowski's "Accurate Algorithms to Transform Geocentric
to Geodetic Coordinates", at
http://www.astro.uni.torun.pl/~kb/Papers/geod/Geod-BG.htm. This
is best viewed with Internet Explorer because of its use of Microsoft's
Symbol font.
- $value = $coord->get ($attrib);
- This method returns the named attributes of the object. If called in list
context, you can give more than one attribute name, and it will return all
their values.
If called as a class method, it returns the current default
values.
See "Attributes" for a list of the attributes you
can get.
- @coords = $coord->enu();
- This method reports the coordinates of $coord in
the East-North-Up coordinate system, as seen from the position stored in
the "station" attribute of
$coord.
Velocity conversions to
"enu()" appear to me to be mostly
sane. See A NOTE ON VELOCITIES, below, for details.
- @coords = $coord->neu();
- This method reports the coordinates of $coord2 in
the North-East-Up coordinate system, as seen from the position stored in
the "station" attribute of
$coord. This is a left-handed coordinate
system.
Velocity conversions to
"neu()" appear to me to be mostly
sane. See A NOTE ON VELOCITIES, below, for details.
- @coords = $coord->heliocentric_ecliptic_cartesian()
- This method returns the Heliocentric ecliptic Cartesian position of the
object. You can optionally pass time as an argument; this is equivalent to
@coords = $coord->universal( $time )
->heliocentric_ecliptic_cartesian();
At this time this object is not able to derive Heliocentric
ecliptic Cartesian coordinates from other coordinates (say, ECI).
- $coord->heliocentric_ecliptic_cartesian( $X, $Y, $Z )
- This method sets the object's position in Heliocentric ecliptic Cartesian
coordinates. Velocities may not be set at the moment, though this is
planned. You may also pass an optional time as the last argument.
The invocant is returned.
- @coords = $coord->heliocentric_ecliptic();
- This method returns the Heliocentric ecliptic coordinates of the
object.
- $coord = $coord->local_mean_time ($time);
- This method sets the local mean time of the object. This is not
local standard time, but the universal time plus the longitude of
the object expressed in seconds. Another definition is mean solar time
plus 12 hours (since the solar day begins at noon). You will get an
exception of some sort if the position of the object has not been set, or
if the object represents inertial coordinates, or on any subclass whose
position depends on the time.
- $time = $coord->local_mean_time ()
- This method returns the local mean time of the object. It will raise an
exception if the time has not been set.
Note that this returns the actual local time, not the GMT
equivalent. This means that in formatting for output, you call
strftime $format, gmtime $coord->local_mean_time ();
- $time = $coord->local_time ();
- This method returns the local time (defined as solar time plus 12 hours)
of the given object. There is no way to set the local time.
This is really just a convenience routine - the calculation is
simply the local mean time plus the equation of time at the given
time.
Note that this returns the actual local time, not the GMT
equivalent. This means that in formatting for output, you call
strftime $format, gmtime $coord->local_time ();
- ( $maidenhead_loc, $height ) = $coord->maidenhead( $precision );
- This method returns the location of the object in the Maidenhead Locator
System. Height above the reference ellipsoid is not part of the system,
but is returned anyway, in kilometers. The
$precision is optional, and is an integer greater
than 0.
The default precision is 4, but this can be modified by
setting
$Astro::Coord::ECI::DEFAULT_MAIDENHEAD_PRECISION
to the desired value. For example, if you want the default precision to
be 3 (which it probably should have been in the first place), you can
use
no warnings qw{ once };
local $Astro::Coord::ECI::DEFAULT_MAIDENHEAD_PRECISION = 3;
Note that precisions greater than 4 are not defined by the
standard. This method extends the system by alternating letters (base
24) with digits (base 10), but this is unsupported since the results
will change, possibly without notice, if the standard is extended in a
manner incompatible with this implementation.
Conversion of latitudes and longitudes to Maidenhead Grid is
subject to truncation error, perhaps more so since latitude and
longitude are specified in radians. An attempt has been made to minimize
this by using Perl's stringification of numbers to ensure that something
that looks like 42 is not handled as
41.999999999385. This probably amounts to
shifting some grid squares very slightly to the north-west, but in
practice it seems to give better results for points on the boundaries of
the grid squares.
- $coord->maidenhead( $maidenhead_loc, $height );
- This method sets the geodetic location in the Maidenhead Locator System.
Height above the reference ellipsoid is not part of the system, but is
accepted anyway, in kilometers, defaulting to 0.
The actual location set is the center of the specified grid
square.
Locations longer than 8 characters are not defined by the
standard. This method extends precision by assuming alternate letters
(base 24) and digits (base 10), but this will change, possibly without
notice, if the standard is extended in a manner incompatible with this
implementation.
The object itself is returned, to allow call chaining.
- $value = $coord->mean_angular_velocity();
- This method returns the mean angular velocity of the body in radians per
second. If the $coord object has a period()
method, this method just returns two pi divided by the period. Otherwise
it returns the contents of the angularvelocity attribute.
- $time = $coord->next_azimuth( $body, $azimuth );
- This method returns the next time the given $body
passes the given $azimuth as seen from the given
$coord, calculated to the nearest second. The
start time is the current time setting of the
$body object.
- $time = $coord->next_azimuth( $azimuth );
- This method returns the next time the $coord
object passes the given $azimuth as seen from the
location in the $coord object's
"station" attribute, calculated to the
nearest second. The start time is the current time setting of the
$coord object.
- ($time, $rise) = $coord->next_elevation ($body, $elev, $upper)
- This method calculates the next time the given body passes above or below
the given elevation (in radians) as seen from
$coord. The $elev argument
may be omitted (or passed as undef), and will default to 0. If the
$upper argument is true, the calculation will be
based on the upper limb of the body (as determined from its
"angulardiameter" attribute); if false,
the calculation will be based on the center of the body. The
$upper argument defaults to true if the
$elev argument is zero or positive, and false if
the $elev argument is negative.
The algorithm is successive approximation, and assumes that
the body will be at its highest at meridian passage. It also assumes
that if the body hasn't passed the given elevation in 183 days it never
will. In this case it returns undef in scalar context, or an empty list
in list context.
- ($time, $rise) = $coord->next_elevation( $elev, $upper );
- This method calculates the next time the $coord
object passes above or below the given elevation (in radians) as seen from
the position found in the $coord object's
"station" attribute. The
$elev argument may be omitted (or passed as
undef), and will default to 0. If the $upper
argument is true, the calculation will be based on the upper limb of the
body (as determined from its
"angulardiameter" attribute); if false,
the calculation will be based on the center of the body. The
$upper argument defaults to true if the
$elev argument is zero or positive, and false if
the $elev argument is negative.
The algorithm is successive approximation, and assumes that
the body will be at its highest at meridian passage. It also assumes
that if the body hasn't passed the given elevation in 183 days it never
will. In this case it returns undef in scalar context, or an empty list
in list context.
- ( $time, $above ) = $coord->next_meridian( $body, $want )
- This method calculates the next meridian passage of the given
$body over (or under) the location specified by
the $coord object. The
$body object must be a subclass of
Astro::Coord::ECI.
The optional $want argument should be
specified as true (e.g. 1) if you want the next passage above the
observer, or as false (e.g. 0) if you want the next passage below the
observer. If this argument is omitted or undefined, you get whichever
passage is next.
The start time of the search is the current time setting of
the $coord object.
The returns are the time of the meridian passage, and an
indicator which is true if the passage is above the observer (i.e. local
noon if the $body represents the Sun), or false
if below (i.e. local midnight if the $body
represents the Sun). If called in scalar context, you get the time
only.
The current time of both $coord and
$body objects are left at the returned time.
The algorithm is by successive approximation. It will croak if
the period of the $body is close to synchronous,
and will probably not work well for bodies in highly eccentric orbits.
The calculation is to the nearest second, and the time returned is the
first even second after the body crosses the meridian.
- ( $time, $above ) = $coord->next_meridian( $want )
- This method calculates the next meridian passage of the
$coord object over (or under) the location
specified by the $coord object's
"station" attribute.
The optional $want argument should be
specified as true (e.g. 1) if you want the next passage above the
observer, or as false (e.g. 0) if you want the next passage below the
observer. If this argument is omitted or undefined, you get whichever
passage is next.
The start time of the search is the current time setting of
the $coord object.
The returns are the time of the meridian passage, and an
indicator which is true if the passage is above the observer (i.e. local
noon if the $coord object represents the Sun),
or false if below (i.e. local midnight if the
$coord object represents the Sun). If called in
scalar context, you get the time only.
The current time of both $coord and
its "station" are left at the returned
time.
The algorithm is by successive approximation. It will croak if
the period of the $body is close to synchronous,
and will probably not work well for bodies in highly eccentric orbits.
The calculation is to the nearest second, and the time returned is the
first even second after the body crosses the meridian.
- ( $delta_psi, $delta_epsilon ) = $self->nutation( $time )
- This method calculates the nutation in longitude (delta psi) and obliquity
(delta epsilon) for the given dynamical time. If the time is
unspecified or specified as "undef", the
current dynamical time of the object is used.
The algorithm comes from Jean Meeus' "Astronomical
Algorithms", 2nd Edition, Chapter 22, pages 143ff. Meeus states
that it is good to 0.5 seconds of arc.
- $epsilon = $self->obliquity( $time )
- This method calculates the obliquity of the ecliptic in radians at the
given dynamical time. If the time is unspecified or specified as
"undef", the current dynamical
time of the object is used.
The algorithm comes from Jean Meeus' "Astronomical
Algorithms", 2nd Edition, Chapter 22, pages 143ff. The conversion
from universal to dynamical time comes from chapter 10, equation 10.2 on
page 78.
- $coord = $coord->precess ($time);
- This method is a convenience wrapper for precess_dynamical(). The
functionality is the same except that the time is specified in
universal time.
- $coord = $coord->precess_dynamical ($time);
- This method precesses the coordinates of the object to the given equinox,
specified in dynamical time. The starting equinox is the value of
the 'equinox_dynamical' attribute, or the current time setting if the
'equinox_dynamical' attribute is any false value (i.e. undef, 0, or ''). A
warning will be issued if the value of 'equinox_dynamical' is undef (which
is the default setting) and the object represents inertial coordinates. As
of version 0.013_02, the time setting of the object is
unaffected by this operation.
As a side effect, the value of the 'equinox_dynamical'
attribute will be set to the dynamical time corresponding to the
argument.
As of version 0.061_01, this does nothing to non-inertial
objects -- that is, those whose position was set in Earth-fixed
coordinates.
If the object's 'station' attribute is set, the station is
also precessed.
The object itself is returned.
The algorithm comes from Jean Meeus, "Astronomical
Algorithms", 2nd Edition, Chapter 21, pages 134ff (a.k.a. "the
rigorous method").
- Astro::Coord::ECI->reference_ellipsoid($semi, $flat, $name);
- This class method can be used to define or redefine reference ellipsoids.
Nothing bad will happen if you call this as an object method,
but it still just creates a reference ellipsoid definition -- the object
is unaffected.
It is not an error to redefine an existing ellipsoid.
- ($semi, $flat, $name) =
Astro::Coord::ECI->reference_ellipsoid($name)
- This class method returns the definition of the named reference ellipsoid.
It croaks if there is no such ellipsoid.
You can also call this as an object method, but the
functionality is the same.
The following reference ellipsoids are known to the class
initially:
CLARKE-1866 - 1866.
semimajor => 6378.2064 km, flattening => 1/294.98.
Source: http://www.colorado.edu/geography/gcraft/notes/datum/elist.html
GRS67 - Geodetic Reference System 1967.
semimajor => 6378.160 km, flattening => 1/298.247.
Source: http://www.colorado.edu/geography/gcraft/notes/datum/elist.html
GRS80 - Geodetic Reference System 1980.
semimajor => 6378.137 km, flattening => 1/298.25722210088
(flattening per U.S. Department of Commerce 1989).
Source: http://biology.usgs.gov/fgdc.metadata/version2/spref/horiz/geodet/faq.htm
IAU68 - International Astronomical Union, 1968.
semimajor => 6378.160 km, flattening => 1/298.25.
Source: http://maic.jmu.edu/sic/standards/ellipsoid.htm
IAU76 - International Astronomical Union, 1976.
semimajor => 6378.14 km, flattening => 1 / 298.257.
Source: Jean Meeus, "Astronomical Algorithms", 2nd Edition
NAD83 - North American Datum, 1983.
semimajor => 6378.137 km, flattening => 1/298.257.
Source: http://biology.usgs.gov/fgdc.metadata/version2/spref/horiz/geodet/faq.htm
(NAD83 uses the GRS80 ellipsoid)
sphere - Just in case you were wondering how much difference it
makes (a max of 11 minutes 32.73 seconds of arc, per Jean
Meeus).
semimajor => 6378.137 km (from GRS80), flattening => 0.
WGS72 - World Geodetic System 1972.
semimajor => 6378.135 km, flattening=> 1/298.26.
Source: http://biology.usgs.gov/fgdc.metadata/version2/spref/horiz/geodet/faq.htm
WGS84 - World Geodetic System 1984.
semimajor => 6378.137 km, flattening => 1/1/298.257223563.
Source: http://www.colorado.edu/geography/gcraft/notes/datum/elist.html
Reference ellipsoid names are case-sensitive.
The default model is WGS84.
- $coord->represents ($class);
- This method returns true if the $coord object
represents the given class. It is pretty much like isa (), but if called
on a container class (i.e. Astro::Coord::ECI::TLE::Set), it returns true
based on the class of the members of the set, and dies if the set has no
members.
The $class argument is optional. If
not specified (or undef), it is pretty much like ref
$coord || $coord (i.e.
it returns the class name), but with the delegation behavior described
in the previous paragraph if the $coord object
is a container.
There. This took many more words to explain than it did to
implement.
- $coord->set (name => value ...);
- This method sets various attributes of the object. If called as a class
method, it changes the defaults.
For reasons that seemed good at the time, this method returns
the object it was called on (i.e. $coord in the
above example).
See "Attributes" for a list of the attributes you
can set.
- $coord->universal ($time)
- This method sets the time represented by the object, in universal time
(a.k.a. CUT, a.k.a. Zulu, a.k.a. Greenwich).
This method can also be called as a class method, in which
case it instantiates the desired object.
- $time = $coord->universal ();
- This method returns the universal time previously set.
This class has the following attributes:
- almanac_horizon (radians or string)
- This attribute specifies the horizon used for almanac calculations, as
radians above or below the plans of the observer. It can also be set to
the following string:
* "height" adjusts the
horizon in proportion to the observer's height above sea level. This
assumes a spherical Earth and an unobstructed horizon.
When doing almanac calculations, it is the
"almanac_horizon" of the observer that
is used, not the "almanac_horizon" of
the observed body.
The default is 0.
- angularvelocity (radians per second)
- This attribute represents the angular velocity of the Earth's surface in
radians per second. The initial value is 7.292114992e-5, which according
to Jean Meeus is the value for 1996.5. He cites the International Earth
Rotation Service's Annual Report for 1996 (Published at the Observatoire
de Paris, 1997).
Subclasses may place appropriate values here, or provide a
period() method.
- debug (numeric)
- This attribute turns on debugging output. The only supported value of this
attribute is 0. That is to say, the author makes no guarantees of what
will happen if you set it to some other value, nor does he guarantee that
this behavior will not change from release to release.
The default is 0.
- diameter (numeric, kilometers)
- This attribute exists to support classes/instances which represent
astronomical bodies. It represents the diameter of the body, and is used
by the azel() method when computing the upper limb of the body. It
has nothing to do with the semimajor attribute, which always refers to the
Earth, and is used to calculate the latitude and longitude of the body.
The default is 0.
- edge_of_earths_shadow (numeric, dimensionless)
- This attribute represents the location of the edge of the Earth's shadow
cast by the illuminating body, in terms of the apparent radius of that
body. That is, the edge of the umbra is specified by 1, the middle of the
penumbra by 0, and the edge of the penumbra by -1. It was added for the
benefit of the Astro::Coord::ECI::TLE class, on the same dubious
logic that the "twilight" attribute was
added.
The default is 1.
- ellipsoid (string)
- This attribute represents the name of the reference ellipsoid to use. It
must be set to one of the known ellipsoids. If you set this, flattening
and semimajor will be set also. See the documentation to the
known_ellipsoid() method for the initially-valid names, and how to
add more.
The default is 'WGS84'.
- equinox_dynamical (numeric, dynamical time)
- This attribute represents the time of the "Equinox" to which the
coordinate data are referred. Models implemented by subclasses should set
this to the "Equinox" to which the model is referred. When
setting positions directly the user should also set the desired
equinox_dynamical if conversion between inertial and Earth-fixed
coordinates is of interest. If this is not set, these conversions will use
the current time setting of the object as the "Equinox".
In addition, if you have a position specified in earth-fixed
coordinates and convert it to inertial coordinates, this attribute will
be set to the dynamical time of the object.
Unlike most times in this package, this attribute is
specified in dynamical time. If your equinox is universal
time $uni, set this attribute to
$uni + dynamical_delta ($uni). The
dynamical_delta subroutine is found in Astro::Coord::ECI::Utils.
The default is undef.
- flattening (numeric)
- This attribute represents the flattening factor of the reference
ellipsoid. If you set the ellipsoid attribute, this attribute will be set
to the flattening factor for the named ellipsoid. If you set this
attribute, the ellipsoid attribute will become undefined.
The default is appropriate to the default ellipsoid.
- frequency (numeric, Hertz)
- This attribute represents the frequency on which the body transmits, in
Hertz. If specified, the "azel()" method
will return the Doppler shift if velocities are available.
The default is "undef".
- horizon (numeric, radians)
- This attribute represents the distance the effective horizon is above the
geometric horizon. It was added for the Astro::Coord::ECI::TLE::Iridium
class, on the same dubious logic that the
"twilight" attribute was added.
The default is the equivalent of 20 degrees.
- id (string)
- This is an informational attribute, and its setting (or lack thereof) does
not affect the functioning of the class. Certain subclasses will set this
when they are instantiated. See the subclass documentation for
details.
- inertial (boolean, read-only)
- This attribute returns true (in the Perl sense) if the object was
most-recently set to inertial coordinates (i.e. eci, ecliptic, or
equatorial) and false otherwise. If coordinates have not been set, it is
undefined (and therefore false).
- name (string)
- This is an informational attribute, and its setting (or lack thereof) does
not affect the functioning of the class. Certain subclasses will set this
when they are instantiated. See the subclass documentation for
details.
- refraction (boolean)
- Setting this attribute to a true value includes refraction in the
calculation of the azel() method. If set to a false value,
atmospheric refraction is ignored.
The default is true (well, 1 actually).
- specified (string, read-only)
- This attribute records the coordinate system in which the coordinates of
the object were set.
- semimajor (numeric, kilometers)
- This attribute represents the semimajor axis of the reference ellipsoid.
If you set the ellipsoid attribute, this attribute will be set to the
semimajor axis for the named ellipsoid. If you set this attribute, the
ellipsoid attribute will become undefined.
For subclasses representing bodies other than the Earth, this
attribute will be set appropriately.
The default is appropriate to the default ellipsoid.
- station ( Astro::Coord::ECI object )
- This attribute represents the default observing location for relative
coordinate systems. It must be set to an
"Astro::Coord::ECI" object, or
"undef".
The intent is that all methods which compute positions or
events as seen from a user-specified location should make use of this.
In other words, if you find one that does not, you have found a bug.
Cascading station objects are not supported. That is,
if you have "Astro::Coord::ECI"
objects $a, $b,
$c and so on, if you
$a->set( station => $b ),
then "$b->set( station => $c
)" is not supported, nor is
"$c->set( station => $a )".
Because of the work involved in preventing this in general, I have
decided to rely on just politely recommending that It Is Better Not. But
specific pernicious cases will throw exceptions, and I reserve
the right to do the work and throw exceptions in all cases if it becomes
a problem.
- sun (Astro::Coord::ECI::Sun class or object)
- This attribute represents the Sun. This is typically used to determine
ambient lighting conditions and other Sun-related phenomena. Subclasses
may place more stringent restrictions on this attribute.
- twilight (numeric, radians)
- This attribute represents the elevation of the center of the Sun's disk at
the beginning and end of twilight. This must be a number between -PI/2 and
PI/2 inclusive, or "undef" which sets
the value to the default.
Some of the usual values are:
civil twilight: -6 degrees
nautical twilight: -12 degrees
astronomical twilight: -18 degrees
Note that the documentation at this point used to say
(or at least imply) that the strings 'civil',
'nautical', and
'astronomical' were acceptable. This has never
been the case to my knowledge, so since I have received no bug reports,
I have considered the bug to be in the documentation, and removed the
relevant text as of version 0.051_01.
The default is -6 degrees (or, actually, the equivalent in
radians).
This class is and will remain based on a hash reference.
It is recommended that subclasses store their attributes in a
separate hash hung off the main object in a key named after the subclass.
That is, something like
sub subclass_method {
my ( $self ) = @_;
my $attr = $self->{ ref $self };
...
}
From outside the subclass, these attributes can be made accessible
by overriding "get()" and
"set()".
Subclasses must initialize themselves by overriding the
"new()" method. The override must
call "$class->SUPER::new()", passing it
any arguments that were passed to the override.
The velocities returned by the methods in this class are a work in progress.
Velocities set are always returned. But conversions are more problematic. For
one thing, I have not come across decent worked examples, so I am limited to
sanity checking.
I consider a velocity to be sane if the difference between the
position at time "t" and the position at
time "t + 1" lies between the velocity at
time "t" and the velocity at time
"t + 1".
In order to understand what velocity conversions are sane, you
need to understand how coordinate conversions work internally. I will try to
make this plain with some lame ASCII art, which depicts the relationships
among those coordinate systems where velocity conversion appears to be at
least mostly sane in the above sense of the word:
ecliptic()
equatorial()
^
|
eci()
^
|
v
ecef() geocentric() geodetic()
|
v
neu() -> enu()
|
v
azel()
If the object's position and velocity were set in one set of
units, other units are obtained by following the arrows. The arrows below
ecef() are one-way because it is not currently possible to set a
position in these units. Similarly, the arrow from
"eci()" to
"equatorial()" is one-way because there is
currently no way to set an equatorial velocity. There are no arrows to
"geocentric()",
"geodetic()" and
"ecliptic()" because these conversions do
not support velocities.
Partly because this module straddles the divide between geography and astronomy,
the establishment of terminology and conventions was a thorny and in the end
somewhat arbitrary process. Because of this, documentation of salient terms
and conventions seemed to be in order.
This term refers to the distance of a location above mean sea level.
Altitude input to and output from this module is in
kilometers.
Maps use "elevation" for this quantity, and measure it
in meters. But we're using "Elevation" for something different,
and I needed consistent units.
This term refers to distance around the horizon measured clockwise from North.
Azimuth output from this module is in radians.
Astronomical sources tend to measure from the South, but I chose
the geodetic standard, which seems to be usual in satellite tracking
software.
Declination is the angle a point makes with the plane of the equator projected
onto the sky. North declination is positive, south declination is negative.
Declination input to and output from this module is in
radians.
A dynamical time is defined theoretically by the motion of astronomical bodies.
In practice, it is seen to be related to Atomic Time (a.k.a. TAI) by a
constant.
There are actually two dynamical times of interest: TT
(Terrestrial Time, a.k.a. TDT for Terrestrial Dynamical Time), which is
defined in terms of the geocentric ephemerides of solar system bodies, and
TDB (Barycentric Dynamical Time), which is defined in terms of the
barycentre (a.k.a "center of mass") of the solar system. The two
differ by the relativistic effects of the motions of the bodies in the Solar
system, and are generally less than 2 milliseconds different. So unless you
are doing high-precision work they can be considered identical, as Jean
Meeus does in "Astronomical Algorithms".
For practical purposes, TT = TAI + 32.184 seconds. If I ever get
the gumption to do a re-implementation (or alternate implementation) of time
in terms of the DateTime object, this will be the definition of dynamical
time. Until then, though, formula 10.2 on page 78 of Jean Meeus'
"Astronomical Algorithms" second edition, Chapter 10 (Dynamical
Time and Universal Time) is used.
Compare and contrast this to "Universal time". This
explanation leans heavily on
"http://star-www.rl.ac.uk/star/docs/sun67.htx/node226.html",
which contains a more fulsome but eminently readable explanation.
Unfortunately that link has gone the way of the dodo, and I have been unable
to find an adequate replacement.
This is a Cartesian coodinate system whose origin is the center of the reference
ellipsoid. The X axis passes through 0 degrees "Latitude" and 0
degrees "Longitude". The Y axis passes through 90 degrees east
"Latitude" and 0 degrees "Longitude", and the Z axis
passes through 90 degrees north "Latitude" (a.k.a the North Pole).
All three axes are input to and output from this module in
kilometers.
Also known as "XYZ coordinates", e.g. at
<https://www.ngs.noaa.gov/cgi-bin/xyz_getxyz.prl>
This is the Cartesian coordinate system in which NORAD's models predict the
position of orbiting bodies. The X axis passes through 0 hours "Right
Ascension" and 0 degrees "Declination". The Y axis passes
through 6 hours "Right Ascension" and 0 degrees
"Declination". The Z axis passes through +90 degrees
"Declination" (a.k.a. the North Pole). By implication, these
coordinates are referred to a given "Equinox".
All three axes are input to and output from this module in
kilometers.
The Ecliptic is the plane of the Earth's orbit, projected onto the sky. Ecliptic
coordinates are a spherical coordinate system referred to the ecliptic and
expressed in terms of "Ecliptic latitude" and "Ecliptic
longitude". By implication, Ecliptic coordinates are also referred to a
specific "Equinox".
Ecliptic latitude
Ecliptic longitude is the angular distance of a point above the
plane of the Earth's orbit.
Ecliptic latitude is input to and output from this module in
radians.
Ecliptic longitude
Ecliptic longitude is the angular distance of a point east of the
point where the plane of the Earth's orbit intersects the plane of the
equator. This point is also known as the vernal "Equinox" and the
first point of Ares.
Ecliptic longitude is input to and output from this module in
radians.
This term refers to an angular distance above the horizon.
Elevation output from this module is in radians.
This is the prevailing meaning of the term in satellite tracking.
Astronomers use "altitude" for this quantity, and call the
corresponding coordinate system "altazimuth." But we're using
"Altitude" for something different.
Equatorial coordinates are a spherical coordinate system referred to the plane
of the equator projected onto the sky. Equatorial coordinates are specified in
"Right Ascension" and "Declination", and implicitly
referred to a given "Equinox"
The "Ecliptic", "Equatorial", and "Earth-Centered
Inertial (ECI) coordinates" are defined in terms of the location of the
intersection of the celestial equator with the "Ecliptic". The
actual location of this point changes in time due to precession of the Earth's
axis, so each of these coordinate systems is implicitly qualified by
("referred to" appears to be the usual terminology) the relevant
time. By a process of association of ideas, this time is referred to as the
equinox of the data.
When referring to a coordinate system, this term means that the coordinate
system assumes the Earth is spherical.
Geocentric latitude
Geocentric latitude is the angle that the ray from the center of
the Earth to the location makes with the plane of the equator. North
latitude is positive, south latitude is negative.
Geocentric latitude is input to and output from this module in
radians.
When referring to a coordinate system, this term means that the coordinate
system assumes the Earth is an ellipsoid of revolution (or an oblate spheroid
if you prefer). A number of standard Reference Ellipsoids have been adopted
over the years.
Geodetic latitude
Geodetic latitude is the latitude found on maps. North latitude is
positive, south latitude is negative.
Geodetic latitude is input to and output from this module in
radians.
Technically speaking, Geodetic latitude is the complement of the
angle the plane of the horizon makes with the plane of the equator. In this
software, the plane of the horizon is determined from a "Reference
Ellipsoid".
See either "Ecliptic latitude", "Geocentric latitude" or
"Geodetic latitude". When used without qualification, "Geodetic
latitude" is meant.
When unqualified, this term refers to the angular distance East or West of the
standard meridian. East longitude is positive, West longitude is negative.
Longitude is input to or output from this module in radians.
For "Ecliptic longitude", see that entry.
Jean Meeus reports in "Astronomical Algorithms" that the
International Astronomical Union has waffled on the sign convention. I have
taken the geographic convention.
This term refers to the angle the plane of the equator makes with the plane of
the Earth's orbit.
Obliquity is output from this module in radians.
This term refers to a specific ellipsoid adopted as a model of the shape of the
Earth. It is defined in terms of the equatorial radius in kilometers, and a
dimensionless flattening factor which is used to derive the polar radius, and
defined such that the flattening factor of a sphere is zero.
See the documentation on the reference_ellipsoid() method
for a list of reference ellipsoids known to this class.
This term refers to the angular distance of a point east of the intersection of
the plane of the Earth's orbit with the plane of the equator.
Right Ascension is input to and output from this module in
radians.
In astronomical literature it is usual to report right ascension
in hours, minutes, and seconds, with 60 seconds in a minute, 60 minutes in
an hour, and 24 hours in a circle.
This term can refer to a number of scales, but the two of interest are UTC
(Coordinated Universal Time) and UT1 (Universal Time 1, I presume). The latter
is in effect mean solar time at Greenwich, though its technical definition
differs in detail from GMT (Greenwich Mean Time). The former is a clock-based
time, whose second is the SI second (defined in terms of atomic clocks), but
which is kept within 0.9 seconds of UT1 by the introduction of leap seconds.
These are introduced (typically at midyear or year end) by prior agreement
among the various timekeeping bodies based on observation; there is no formula
for computing when a leap second will be needed, because of irregularities in
the Earth's rotation.
Jean Meeus' "Astronomical Algorithms", second edition,
deals with the relationship between Universal time and "Dynamical
time" in Chapter 10 (pages 77ff). His definition of "Universal
time" seems to refer to UT1, though he does not use the term.
This software considers Universal time to be equivalent to Perl
time. Since we are interested in durations (time since a given epoch, to be
specific), this is technically wrong in most cases, since leap seconds are
not taken into account. But in the case of the bodies modeled by the
Astro::Coord::ECI::TLE object, the epoch is very recent (within a week or
so), so the error introduced is small. It is larger for astronomical
calculations, where the epoch is typically J2000.0, but the angular motions
involved are smaller, so it all evens out. I hope.
Compare and contrast "Dynamical time". This explanation
leans heavily on
"http://star-www.rl.ac.uk/star/docs/sun67.htx/node224.html".
Unfortunately that link has gone the way of the dodo, and I have been unable
to find an adequate replacement.
See "Earth-Centered, Earth-fixed (ECEF) coordinates".
The author wishes to acknowledge and thank the following individuals and
organizations.
Kazimierz Borkowski, whose "Accurate Algorithms to Transform
Geocentric to Geodetic Coordinates", at
<http://www.astro.uni.torun.pl/~kb/Papers/geod/Geod-BG.htm>, was used
for transforming geocentric to geodetic coordinates.
Dominik Brodowski (<https://www.brodo.de/>), whose SGP C-lib
(available at <https://www.brodo.de/space/sgp/>) provided a reference
implementation that I could easily run, and pick apart to help get
Astro::Coord::ECI::TLE working. Dominik based his work on Dr. Kelso's
Pascal implementation.
Felix R. Hoots and Ronald L. Roehric, the authors of
"SPACETRACK REPORT NO. 3 - Models for Propagation of NORAD Element
Sets," which provided the basis for the Astro::Coord::ECI::TLE
module.
T. S. Kelso, who compiled this report and made it available at
<http://celestrak.com/>, whose "Computers and Satellites"
columns in "Satellite Times" magazine were invaluable to an
understanding and implementation of satellite tracking software, whose
support, encouragement, patience, and willingness to provide answers on
arcane topics were a Godsend, who kindly granted permission to use his
azimuth/elevation algorithm, and whose Pascal implementation of the NORAD
tracking algorithms indirectly provided a reference implementation for me to
use during development.
John A. Magliacane, whose open-source
"Predict" program, available at
<https://www.qsl.net/kd2bd/predict.html>, gave me a much-needed leg up
on the velocity calculations in the
"azel()" method.
Jean Meeus, whose book "Astronomical Algorithms" (second
edition) formed the basis for this module and the
Astro::Coord::ECI::Sun, Astro::Coord::ECI::Moon, and
Astro::Coord::ECI::Star modules, and without whom it is impossible to
get far in computational astronomy. Any algorithm not explicitly credited
above is probably due to him.
Dr. Meeus' publisher, Willmann-Bell Inc, which kindly and
patiently answered my intellectual-property questions. Willmann-Bell ceased
to be a separate entity in 2021, but their publications, including Dr.
Meeus' book, are still available through Sky and Telescope's
Willmann-Bell imprint at
<https://shopatsky.com/collections/willmann-bell>.
Goran Gasparovic of MIT, who asked for (and supplied information
for) the ability to display results in apparent equatorial coordinates,
rather than azimuth and elevation.
Dr. Kevin Cornelius of Ouachita Baptist University, whose handout
"Relationships Among Unit Vectors" for his Mathematical Physics
class (PHYS 4053) provided a much surer and more expeditious way to handling
velocity conversion from spherical to Cartesian (and vice versa) than my own
ancient and rickety matrix math.
Functionality involving velocities is untested, and is quite likely to be
wrong.
Support is by the author. Please file bug reports at
<https://rt.cpan.org/Public/Dist/Display.html?Name=Astro-satpass>,
<https://github.com/trwyant/perl-Astro-Coord-ECI/issues>, or in
electronic mail to the author.
The "Astro" package by Chris Phillips. This
contains three function-based modules: Astro::Coord, which provides various
astronomical coordinate conversions, plus the calculation of various ephemeris
variables; Astro::Time contains time and unit conversions, and Astro::Misc
contains various calculations unrelated to position and time.
The Astro-Coords package by Tim Jenness. This contains
various modules to do astronomical calculations, and includes coordinate
conversion and calculation of planetary orbits based on orbital elements.
Requires SLALIB from the Starlink Project. This was once a project of the
Joint Astronomy Centre in the UK, but is no longer. The best link I have for
it at the moment is <http://starlink.eao.hawaii.edu/starlink>.
The Astro::Nova module by Steffen Mueller, which wraps (and
bundles) the libnova celestial mechanics, astrometry and astrodynamics
library found at <http://libnova.sourceforge.net/>.
The <https://www.heavens-above.com/> web site, which does
not use this code, but does provide similar functionality.
Thomas R. Wyant, III (wyant at cpan dot org)
Copyright (C) 2005-2021 by Thomas R. Wyant, III
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl 5.10.0. For more details, see the
full text of the licenses in the directory LICENSES.
This program is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc. |