NAME
Astro::Coord::ECI::TLE::Iridium - Compute behavior of Iridium satellites
SYNOPSIS
The following is a semi-brief script to calculate Iridium flares. You will need to substitute your own location where indicated.
use Astro::SpaceTrack;
use Astro::Coord::ECI;
use Astro::Coord::ECI::TLE;
use Astro::Coord::ECI::Utils qw{deg2rad rad2deg};
# 1600 Pennsylvania Avenue, Washington DC, USA
my $your_north_latitude_in_degrees = 38.898748;
my $your_east_longitude_in_degrees = -77.037684;
my $your_height_above_sea_level_in_meters = 16.68;
# Create object representing the observers' location.
# Note that the input to geodetic() is latitude north
# and longitude west, in RADIANS, and height above sea
# level in KILOMETERS.
my $loc = Astro::Coord::ECI->geodetic (
deg2rad ($your_north_latitude_in_degrees),
deg2rad ($your_east_longitude_in_degrees),
$your_height_above_sea_level_in_meters/1000);
# Get all the Iridium data from Celestrak; it is direct-
# fetched, so no password is needed.
my $st = Astro::SpaceTrack->new (direct => 1);
my $data = $st->celestrak ('iridium');
$data->is_success or die $data->status_line;
# Parse the fetched data, yielding Iridium objects.
my @sats = Astro::Coord::ECI::TLE->parse ($data->content);
# We want flares for the next 2 days. In order to try to
# duplicate http://www.heavens-above.com/ as closely as
# possible, we throw away daytime flares dimmer than -6,
# and nighttime flares dimmer than -1. We also calculate
# flares for spares, and assume night is any time the Sun
# is below the horizon.
my $start = time ();
my $finish = $start + 2 * 86400;
my @flares;
my %mag_limit = (am => -1, day => -6, pm => -1);
foreach my $irid (@sats) {
$irid->can_flare (1) or next;
$irid->set (twilight => 0);
foreach my $flare ($irid->flare ($loc, $start, $finish)) {
$flare->{magnitude} <= $mag_limit{$flare->{type}}
and push @flares, $flare;
}
}
print <<eod;
Date/Time Satellite Elevation Azimuth Magnitude
eod
foreach my $flare (sort {$a->{time} <=> $b->{time}} @flares) {
# If we wanted to make use of the Iridium object that
# produced the flare (e.g. to get apparant equatorial
# coordinates) we would need to set the time first.
## $flare->{body}->universal ($flare->{time});
# The returned angles are in radians, so we need to
# convert back to degrees.
printf "%s %-15s %9.1f %9.1f %5.1f\n",
scalar localtime $flare->{time},
$flare->{body}->get ('name'),
rad2deg ($flare->{elevation}),
rad2deg ($flare->{azimuth}),
$flare->{magnitude};
}
DESCRIPTION
This class is a subclass of Astro::Coord::ECI::TLE, representing Iridium satellites. The Astro::Coord::ECI::TLE->parse method makes use of built-in data to determine which satellites to rebless into this class, based on the object's NORAD SATCAT ID. This internal data can be modified using the Astro::Coord::ECI::TLE->status method to correct errors or for historical research. It is also possible to get an Iridium object by calling $tle->rebless (iridium => {status => $status}) directly.
What this subclass adds is the ability to generate information on Iridium flares (or glints, as they are also called). Members of this class are considered capable of generating flares based on their status, as follows:
0 => in service
1 => spare (may or may not flare)
2 => failed - no predictable flares.
Celestrak-style statuses ('+', 'S', and '-' respectively) are accepted on input. See Astro::SpaceTrack method iridium_status for a way to get current Iridium constellation status.
Methods
This class adds the following public methods:
- $tle->after_reblessing (\%attribs);
-
This method supports reblessing into a subclass, with the argument representing attributes that the subclass may wish to set. It is called by rebless() and should not be called by the user.
At this level of the inheritance hierarchy, it sets the status of the object from the {status} key of the given hash. If this key is absent, the object is assumed capable of generating flares.
- $tle->before_reblessing ()
-
This method supports reblessing into a subclass. It is intended to do any cleanup the old class needs before reblessing into the new class. It is called by rebless(), and should not be called by the user.
At this level of the inheritance hierarchy, it removes the status attribute.
- $tle->can_flare ($spare);
-
This method returns true (in the Perl sense) if the object is capable of producing flares, and false otherwise. If the optional $spare argument is true, spares are considered capable of flaring, otherwise not.
- @flares = $tle->flare ($sta, $start, $end);
-
This method returns the list of flares produced by the given Iridium satellite at the given station between the given start time and the given end time. This list may be empty. If called in scalar context you get the number of flares.
Each flare is represented by a reference to an anonymous hash, with elements as follows:
angle => Mirror angle, radians appulse => information about the position of the Sun angle => distance from Sun to flare, radians body => reference to the Sun object area => Projected MMA area, square radians azimuth => Azimuth of flare, radians body => Reference to object producing flare center => information about the center of the flare body => location of the center of the flare magnitude => estimated magnitude at the center elevation => Elevation of flare, radians magnitude => Estimated magnitude mma => Flaring mma (0, 1, or 2) range => Range to flare, kilometers specular => True if specular reflection station => reference to the observer's location status => '' type => Type of flare (see notes) time => Time of flare virtual_image => Location of virtual image
Note that:
* The time of the object passed in the {body} element is not necessarily set to the time of the flare.
* The {center}{body} element contains an Astro::Coord::ECI object set to the location of the center of the flare at the given time. The center is defined as the intersection of the plane of the observer's horizon with the line from the virtual image of the illuminating body through the flaring satellite.
* The {mma} element indicates which Main Mission Antenna generated the flare. The antennae are numbered clockwise (looking down on the vehicle) from the front, so 0, 1, and 2 correspond to Heavens Above's 'Front', 'Right', and 'Left' respectively.
* The {specular} element is actually the limb darkening factor if applicable. Otherwise, it is 1 if the reflection is specular, and 0 if not.
* The {status} key is reserved for an explanation of why there is no flare. When the hash is generated by the flare() method, this key will always be false (in the Perl sense).
* The {type} element contains 'day' if the flare occurs between the beginning of twilight in the morning and the end of twilight in the evening, 'am' if the flare is after midnight but not during the day, and 'pm' if the flare is before midnight but not during the day.
* The {virtual_image} element is an Astro::Coord::ECI object representing the location of the virtual image of the illuminator at the time of the flare.
Why does this software produce different results than http://www.heavens-above.com/?
The short answer is "I don't know, because I don't know how Heavens Above gets their answers."
In a little more detail, there appear to be several things going on:
First, there appears to be no standard reference for how to calculate the magnitude of a flare. This module calculates specular reflections as though the sky were opaque, and the flaring Main Mission Antenna were a window through to the virtual image of the Sun. Limb darkening is taken into account, as is atmospheric extinction. Non-specular flares are calculated by a fairly arbitrary equation whose coefficients were fitted to visual flare magnitude estimates collected by Ron Lee and made available on the Web by Randy John as part of his skysat web site at http://home.comcast.net/~skysat/. Atmospheric extinction is also taken into account for the non-specular flares. Atmospheric extinction is calculated according to the article by Daniel W. Green in the July 1992 issue of "International Comet Quarterly", and available at http://www.cfa.harvard.edu/icq/ICQExtinct.html. Because Heavens Above does not display flares dimmer than a certain magnitude (-6 for day flares, and apparently 0 for night flares), it may not display a flare that this code predicts. I have no information how Heavens Above calculates magnitudes, but I find that this class gives estimates about a magnitude brighter than Heavens Above at the dim end of the scale.
Second, I suspect that the positions and velocities calculated by Astro::Coord::ECI::TLE differ slightly from those used by Heavens Above. I do not know this, because I do not know what positions Heavens Above uses, but there are slight differences among the results of all the orbital propagation models I have looked at. All I can say about the accuracy of Astro::Coord::ECI::TLE is that it duplicates the test data given in "Spacetrack Report Number Three". But small differences are important -- 0.1 degree at the satellite can make the difference between seeing and not seeing a flare, and smaller differences can affect the magnitude predictions, especially if they make the difference between predicting a specular or non-specular flare. Occasionally I find that I get very different results than Heavens Above, even when using orbital data published on that web site.
Third, Heavens Above issues predictions on satellites that my source says are spares. I have skipped the spares by default because I do not know that their attitudes are maintained to the requisite precision, though perhaps they would be, to demonstrate that the spares are functional. This software currently uses the Iridium status from Celestrak (http://celestrak.com/SpaceTrack/query/iridium.txt), since it represents one-stop shopping, and Dr. Kelso has expressed the intent to check with Iridium Satellite LLC monthly for status. Mike McCants' "Status of Iridium Payloads" at http://users2.ev1.net/~mmccants/tles/iridium.html notes that flares may be unreliable for spares, so can_flare () returns false for them. If this is not what you want, call can_flare with a true value (e.g. can_flare(1)).
Fourth, the Heavens Above definition of 'daytime' differs from mine. Heavens Above does not document what their definition is, at least not that I have found. My definition of daytime includes twilight, which by default means the center of the Sun is less than 6 degrees below the horizon. I know that, using that definition, this software classifies some flares as daytime flares which Heavens Above classifies as nighttime flares. It appears to me that Heavens Above considers it night whenever the Sun is below the horizon.
Fifth, the orbital elements used to make the prediction can differ. I have occasionally seen Heavens Above using elements a day old, versus the ones available from Space Track, and seen this difference make a difference of six or eight seconds in the time of the flare.
Sixth, this method takes no account of the decrease in magnitude that would result from the Sun being extremely close to the horizon as seen from the flaring satellite. I do not know whether Heavens Above does this or not, but I have seen an instance where this code predicted a flare but Heavens Above did not, where the observed flare was much dimmer than this code predicted, and reddened. Subsequent calculations put the Sun 0.1 degrees above the horizon as seen from the satellite.
NOTE that the algorithm used to calculate flares does not work at latitudes beyond 85 degrees north or south, nor does it work for any location that is not fixed to the Earth's surface. This may be fixed in a future release. The chances of it being fixed in a future release will be enhanced if someone claims to actually need it. This someone will be invited to help test the new code.
NOTE also that as of version 0.002_01 of this class, the 'backdate' attribute determines whether a set of orbital elements can be used for computations of flares before the epoch of the elements. If 'backdate' is false and the start time passed to flare() is earlier than the epoch, the start time is silently moved forward to the epoch. The initial version of this functionality raised an exception if this adjustment placed the start time after the end time, but as of version 0.003_01 of this class, you simply get no flares if this happens.
- $value = $tle->get ($name);
-
This method returns the value of the given attribute. Attributes other than 'status' are delegated to the parent.
- @data = $tle->reflection ($station, $time)
-
This method returns a list of references to hashes containing the same data as returned for a flare, calculated for the given observer and time for all Main Mission Antennae. Note the following differences from the flare() hash:
If the hash contains a 'status' key which is true (in the Perl sense), no reflection occurred, and the content of the key is a message saying why not. If the 'mma' key exists in addition to the 'status' key, the failure applies only to that MMA, and other MMAs may possibly generate a reflection. If the 'mma' key does not exist, then the satellite is either not illuminated or below the horizon for the given observer, and the @data list will contain only a single entry.
Other than (maybe) 'mma', no other keys should be assumed to exist if the 'status' key is true.
If called in scalar context, a reference to the \@data list is returned.
- $tle->set ($name => $value ...)
-
This method sets the value of the given attribute (or attributes). Attributes other than 'status' are delegated to the parent.
Attributes
This class adds the following attributes:
- am (boolean)
-
If true, the flare() method returns flares that occur between midnight and morning twilight. If false, such flares are ignored.
The default is 1 (i.e. true).
- day (boolean)
-
If true, the flare() method returns flares that occur between morning twilight and evening twilight. If false, such flares are ignored.
The default is 1 (i.e. true).
- extinction (boolean)
-
If true, flare magnitude calculations will take atmospheric extinction into account. If false, they will not. The observer who wishes to compare forecast magnitudes to nearby stars may wish to set this to some value Perl considers false (e.g. undef).
The default is 1 (i.e. true).
- pm (boolean)
-
If true, the flare() method returns flares that occur between evening twilight and midnight. If false, such flares are ignored.
The default is 1 (i.e. true).
- status (integer)
-
This attribute determines whether the Iridium satellite is considered able to produce predictable flares. The possible values are:
0 => in service; 1 => spare, or maneuvering; 2 => out of service, tumbling, et cetera.
By default, the can_flare() method returns true only if the status is 0. But if given a true argument (e.g. can_flare(1)) it will also return true if the status is 1.
When setting this attribute, both T. S. Kelso and Mike McCants style strings are accepted. That is:
'+' or '' will be considered 0; 'S' or '?' will be considered 1; anything else will be considered 2.
Technically, the default is 0. But if the object is manufactured by Astro::Coord::ECI::TLE->parse(), the status will be set based on the internal status table in Astro::Coord::ECI::TLE.
ACKNOWLEDGMENTS
The author wishes to acknowledge the following people, without whose work this module would never have existed:
Ron Lee and the members of his team who collected Iridium magnitude data.
Randy John, the author of SKYSAT (http://home.comcast.net/~skysat/), whose Turbo Pascal implementation of the geometry calculation (at http://home.comcast.net/~skysat/algo.txt provided the basic mechanism for my own geometry calculation, and who made Ron Lee's data available on the SKYSAT web site.
The contributors to the Visual Satellite Observer's Home Page (http://www.satobs.org/satintro.html), particularly the Iridium Flares page (http://www.satobs.org/iridium.html), which provided the background for the entire Iridium flare effort.
BUGS
Bugs can be reported to the author by mail, or through http://rt.cpan.org/.
AUTHOR
Thomas R. Wyant, III (wyant at cpan dot org)
COPYRIGHT AND LICENSE
Copyright (C) 2005-2010, 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.