Astro:...I::TLE(3pm)
๐ฐ๏ธ Astro::Coord::ECI::TLE (3pm) โ User Contributed Perl Documentation, but make it bestie ๐
okay so this is the manual page for Astro::Coord::ECI::TLE, and it's literally about computing satellite locations with NORAD orbit propagation models. Buckle up, bestie ๐
โจ NAME โจ
Astro::Coord::ECI::TLE โ compute satellite locations using NORAD orbit propagation models. That's the whole vibe: TLE in, where-is-that-satellite out. ๐ฐ๏ธ๐
๐ธ SYNOPSIS ๐ธ
okay so here's a semi-brief script to calculate International Space Station visibility. You will need to substitute your own location where indicated. (Yes, bestie, actually substitute it โ the comments below are giving 1600 Pennsylvania Avenue energy.)
use Astro::SpaceTrack;
use Astro::Coord::ECI;
use Astro::Coord::ECI::TLE;
use Astro::Coord::ECI::TLE::Set;
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 the 'stations' catalog from Celestrak. This includes
# all space stations and related bodies.
# The data are all direct-fetched, so no password is
# needed.
my $st = Astro::SpaceTrack->new( direct => 1 );
my $data = $st->celestrak( 'stations' );
$data->is_success or die $data->status_line;
# Parse the fetched data, yielding TLE objects. Aggregate
# them into Set objects where this is warranted. We grep
# the data because the Celestrak catalog we fetched
# contains other stuff than the International Space
# Station.
my @sats = grep { '25544' eq $_->get( 'id' ) }
Astro::Coord::ECI::TLE::Set->aggregate(
Astro::Coord::ECI::TLE->parse( $data->content() ) );
# We want passes for the next 7 days.
my $start = time ();
my $finish = $start + 7 * 86400;
# Loop through our objects and predict passes. The
# validate() step is usually not needed for data from
# Space Track, but NASA's predicted elements for Space
# Shuttle flights can be funky.
my @passes;
foreach my $tle (@sats) {
$tle->validate($start, $finish) or next;
push @passes, $tle->pass($loc, $start, $finish);
}
print <<eod;
Date/Time Satellite Elevation Azimuth Event
eod
foreach my $pass (sort {$a->{time} <=> $b->{time}} @passes) {
# The returned angles are in radians, so we need to
# convert back to degrees.
#
# Note that unless Scalar::Util::dualvar works, the event output
# will be integers.
print "\n";
foreach my $event (@{$pass->{events}}) {
printf "%s %-15s %9.1f %9.1f %-5s\n",
scalar localtime $event->{time},
$event->{body}->get ('name'),
rad2deg ($event->{elevation}),
rad2deg ($event->{azimuth}),
$event->{event};
}
}
๐ NOTICE ๐
bestie, this is the important-caveat zone. Read it before you go feral with JSON.
- Users of JSON functionality (if any!) should be aware of a potential problem in the way
JSON::XSencodes numbers. The problem basically is that the locale leaks into the encoded JSON, and if the locale uses commas for decimal points the encoded JSON can not be decoded. As I understand the discussion on the associated Perl ticket the problem has always been there, but changes introduced in Perl5.19.8made it more likely to manifest. - Unfortunately the nature of the JSON interface is such that I have no control over the issue, since the workaround needs to be applied at the point the JSON
encode()method is called. See testt/tle_json.tfor the workaround that allows tests to pass in the affected locales. The relevantJSON::XSticket ishttps://rt.cpan.org/Public/Bug/Display.html?id=93307. The relevant Perl ticket ishttps://github.com/perl/perl5/issues/13620. - The
pass_thresholdattribute has undergone a slight change in functionality from version0.046, in which it was introduced. In the new functionality, if thevisibleattribute is true, the satellite must actually be visible above the threshold to be reported. This is actually how the attribute would have worked when introduced if I had thought it through clearly. - Use of the
SATNAMEJSON attribute to represent the common name of the satellite is deprecated in favor of theOBJECT_NAMEattribute, since the latter is what Space Track uses in their TLE data. Beginning with0.053_01, JSON output of TLEs will use the new name. - Beginning with release
0.056_01, loading JSON TLE data which specifiesSATNAMEproduces a warning the first time it happens. As of version0.061there is a warning every time it happens. As of version0.066loading JSON TLE data which specifiesSATNAMEis a fatal error. Six months after this, all code referring toSATNAMEwill be removed, meaning that the key will be silently ignored.
๐ DESCRIPTION ๐
This module implements the orbital propagation models described in "SPACETRACK REPORT NO. 3, Models for Propagation of NORAD Element Sets" and "Revisiting Spacetrack Report #3." See the ACKNOWLEDGMENTS section for details on these reports. ๐โจ
In other words, this module turns the two- or three-line element sets available from such places as https://www.space-track.org/ or http://celestrak.org/ into predictions of where the relevant orbiting bodies will be. Additionally, the pass() method implements an actual visibility prediction system. It's giving orbit math with a glow-up. ๐ซ
The models implemented are:
SGP - fairly simple, only useful for near-earth bodies;
SGP4 - more complex, only useful for near-earth bodies;
SDP4 - corresponds to SGP4, but for deep-space bodies;
SGP8 - more complex still, only for near-earth bodies;
SDP8 - corresponds to SGP8, but for deep-space bodies;
SGP4R - updates and combines SGP4 and SDP4.
All the above models compute ECI coordinates in kilometers, and velocities along the same axes in kilometers per second. ๐ฐ๏ธ๐
There are also some meta-models, with the smarts to run either a near-earth model or the corresponding deep-space model depending on the body the object represents:
model - uses the preferred model (sgp4r);
model4 - runs sgp4 or sdp4;
model4r - runs sgp4r;
model8 - runs sgp8 or sdp8.
In addition, I have on at least one occasion wanted to turn off the automatic calculation of position when the time was set. That is accomplished with this model:
null - does nothing.
The models do not return the coordinates directly, they simply set the coordinates represented by the object (by virtue of being a subclass of Astro::Coord::ECI) and return the object itself. You can then call the appropriate inherited method to get the coordinates of the body in whatever coordinate system is convenient. For example, to find the latitude, longitude, and altitude of a body at a given time, you do:
my ($lat, $long, $alt) = $body->model ($time)->geodetic;
Or, assuming the model attribute is set the way you want it, by:
my ($lat, $long, $alt) = $body->geodetic ($time);
It is also possible to run the desired model (as specified by the model attribute) simply by setting the time represented by the object. lowkey iconic behavior, honestly. ๐ซถ
As of release 0.016, the recommended model to use is SGP4R, which was added in that release. The SGP4R model, described in "Revisiting Spacetrack Report #3" (http://celestrak.org/publications/AIAA/2006-6753/), combines SGP4 and SDP4, and updates them. For the details of the changes, see the report. ๐ฅ
Prior to release 0.016, the recommended model to use was either SGP4 or SDP4, depending on whether the orbital elements are for a near-earth or deep-space body. For the purpose of these models, any body with a period of at least 225 minutes is considered to be a deep-space body. ๐
The NORAD report claims accuracy of 5 or 6 places a day after the epoch of an element set for the original FORTRAN IV, which used (mostly) 8 place single-precision calculations. Perl typically uses many more places, but it does not follow that the models are correspondingly more accurate when implemented in Perl. My understanding is that in general (i.e. disregarding the characteristics of a particular implementation of the models involved) the total error of the predictions (including error in measuring the position of the satellite) runs from a few hundred meters to as much as a kilometer. ๐ญ๐
I have no information on the accuracy claims of SGP4R. ๐คทโโ๏ธ
This module is a computer-assisted translation of the FORTRAN reference implementations in "SPACETRACK REPORT NO. 3" and "Revisiting Spacetrack Report #3." That means, basically, that I ran the FORTRAN through a Perl script that handled the translation of the assignment statements into Perl, and then fixed up the logic by hand. Dominik Borkowski's SGP C-lib was used as a reference implementation for testing purposes, because I didn't have a Pascal compiler, and I have yet to get any model but SGP to run correctly under g77. ๐๐ ๏ธ
๐ ๏ธ Methods ๐ ๏ธ
The following methods should be considered public โ fr fr, they're fair game:
$tle = Astro::Coord::ECI::TLE->new()
This method instantiates an object to represent a NORAD two- or three-line orbital element set. This is a subclass of Astro::Coord::ECI. ๐ฐ๏ธ
Any arguments get passed to the set() method.
It is both anticipated and recommended that you use the parse() method instead of this method to create an object, since the models currently have no code to guard against incomplete data. > โ ๏ธ bestie, incomplete data is not the vibe โ use parse() unless you know what you're doing.
$tle->after_reblessing (\%possible_attributes)
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 it does nothing.
Astro::Coord::ECI::TLE->alias (name => class ...)
This static method adds an alias for a class name, for the benefit of users of the status() method and 'illum' attributes, and ultimately of the rebless() method. It is intended to be used by subclasses to register short names for themselves upon initialization, though of course you can call it yourself as well. ๐
For example, this class calls:
__PACKAGE__->alias (tle => __PACKAGE__);
You can register more than one alias in a single call. Aliases can be deleted by assigning them a false value (e.g. '' or undef). โจ
If called without arguments, it returns the current aliases.
You can actually call this as a normal method, but it still behaves like a static method. iykyk ๐
$kilometers = $tle->apoapsis();
This method returns the apoapsis of the orbit, in kilometers. Since Astro::Coord::ECI::TLE objects always represent bodies orbiting the Earth, this is more usually called apogee. ๐๐ฐ๏ธ
okay so real quick before we keep going โ that number you get back? it's the distance from the center of the Earth, not the altitude. huge difference, bestie, do not mix them up. ๐
โจ $kilometers = $tle->apogee(); โจ
This one is literally just a synonym for apoapsis(). same vibe, different name. ๐
๐ง $tle->before_reblessing ()
ok so this method exists to support reblessing into a subclass. it's the cleanup crew โ it does whatever the old class needs to do before getting reblessed into the new class. it gets called by rebless(), and should not be called by the user. at this level? it does absolutely nothing. iconic minimalism. ๐
๐ $type = $tle->body_type ()
Returns the type of the body as one of the BODY_TYPE_* constants. If the 'object_type' attribute is defined, that's what you get. otherwise it's derived from the common name using an algorithm similar to the one used by the Space Track web site. โ ๏ธ but it will not work if the common name isn't available, or if it doesn't conform to the Space Track naming conventions.
Known or suspected differences from the algorithm described at the bottom of the Satellite Box Score page include:
- The
Astro::Coord::ECI::TLEalgorithm is not case-sensitive. The Space Track algorithm appears to assume all upper-case. - The
Astro::Coord::ECI::TLEalgorithm looks for words (that is, alphanumeric strings delimited by non-alphanumeric characters), whereas the Space Track documentation seems to say it just looks for substrings. However, implementing the documented algorithm literally results in OID 20479'DEBUT (ORIZURU)'being classified as debris, whereas Space Track returns it in response to a query for name'deb'that excludes debris.
The possible returns are:
BODY_TYPE_UNKNOWN => dualvar( 0, 'unknown' )if the value of the"name"attribute isundef, or if it is empty or contains only white space.BODY_TYPE_DEBRIS => dualvar( 1, 'debris' )if the value of the"name"attribute contains one of the words'deb','debris','coolant','shroud', or'westford needles', all checks being case-insensitive.BODY_TYPE_ROCKET_BODY => dualvar( 2, 'rocket body' )if the body is not debris, but the value of the"name"attribute contains one of the strings'r/b','akm'(for'apogee kick motor') or'pkm'(for'perigee kick motor') all checks being case-insensitive.BODY_TYPE_PAYLOAD => dualvar( 3, 'payload' )if the body is not unknown, debris, or a rocket body.
The above constants are not exported by default, but they are exportable either by name or using the ":constants" tag.
If Scalar::Util does not export dualvar(), the constants are defined to be numeric. so the cautious programmer will therefore test them using numeric tests. ๐
๐ $tle->can_flare ()
Returns true if the object is capable of generating flares (i.e. predictable bright flashes) and false otherwise. At this level of the inheritance hierarchy, it always returns false, but subclasses may return true. so likeโฆ maybe. ๐
๐ $elevation = $tle->correct_for_refraction( $elevation )
This override of the superclass' method simply returns the elevation passed to it. atmospheric refraction at orbital altitudes is going to be negligible except extremely close to the horizon, and there's no algorithm for that here. ๐ญ
If something to handle refraction close to the horizon does come up, though, it will appear here. One would expect the refraction right at the limb to be twice that calculated by Thorfinn's algorithm (used in the superclass) because the light travels to the Earth's surface and back out again.
See the Astro::Coord::ECI azel() and azel_offset() documentation for whether this class' correct_for_refraction() method is actually called by those methods. ๐
๐ฆ $value = $tle->ds50($time)
Converts the time to days since 1950 Jan 0, 0 h GMT. The time defaults to the epoch of the data set. This method does not affect the $tle object โ it's exposed for convenience and for testing purposes. ๐งช
It can also be called as a "static" method, i.e. as Astro::Coord::ECI::TLE->ds50 ($time), but in this case the time may not be defaulted, and no attempt has been made to make this a pretty error. soโฆ fair warning. ๐
๐ $value = $tle->get('attribute')
Retrieves the value of the given attribute. See the "Attributes" section for a description of the attributes. that's it, that's the method. ๐
๐ธ $illuminated = $tle->illuminated();
Returns a true value if the body is illuminated, and a false value if it is not. is it lit? yes/no. we love a binary. โจ
โญ @events = $tle->intrinsic_events( $start, $end );
Returns any events that are intrinsic to the $tle object. If optional argument $start is defined, only events occurring at or after that Perl time are returned. Similarly, if optional argument $end is defined, only events occurring before that Perl time are returned.
The return is an array of array references. Each array reference specifies the Perl time of the event and a text description of the event. ๐
At this level of the object hierarchy nothing is returned. Subclasses may override this to add pass() events. The overrides should return anything returned by SUPER::intrinsic_events(...) in addition to anything they return themselves.
The order of the returned events is undefined. don't count on it, bestie. ๐
๐ $deep = $tle->is_deep();
Returns true if the object is in deep space โ meaning that its period is at least 225 minutes (= 13500 seconds). deep space vibes only. ๐
๐ $boolean = $tle->is_model_attribute ($name);
Returns true if the named attribute is an attribute of the model โ i.e. it came from the TLE data and actually affects the model computations. It's really for the benefit of Astro::Coord::ECI::TLE::Set, so that class can determine how its set() method should handle the attribute. teamwork makes the dream work. ๐ซถ
๐ฅ $boolean = $tle->is_valid_model ($model_name);
Returns true if the given name is the name of an orbital model, and false otherwise.
Actually, in the spirit of UNIVERSAL::can, it returns a reference to the code if the model exists, and undef otherwise. so it's true-ish, not just true. got it. ๐
This is really for the benefit of Astro::Coord::ECI::TLE::Set, so it knows it needs to select the correct member object before running the model.
This method can be called as a static method, or even as a subroutine. โจ
๐ $mag = $tle->magnitude( $station );
Returns the magnitude of the body as seen from the given station. If no $station is specified, the object's 'station' attribute is used. If that's not set, an exception is thrown. ๐จ
This is calculated from the 'intrinsic_magnitude' attribute, the distance from the station to the satellite, and the fraction of the satellite illuminated. The formula is from Mike McCants. smart king. ๐
We return "undef" if the 'intrinsic_magnitude' or 'illum' attributes are "undef", or if the illuminating body is below the horizon as seen from the satellite.
After this method returns the time set in the station attribute should be considered undefined. In fact, it will be set to the same time as the invocant if a defined magnitude was returned. But if "undef" was returned, the station's time may not have been changed. so likeโฆ don't trust it afterwards. ๐
Some very desultory investigation of International Space Station magnitude predictions suggests that this method produces magnitude estimates about half a magnitude less bright than Heavens Above. noted. ๐
๐ง Astro::Coord::ECI::TLE->magnitude_table( command => arguments ...)
This method maintains the internal magnitude table, which is used by the parse() method to fill in magnitudes, since they're not normally available from the usual sources. The first argument determines what is done to the status table; subsequent arguments depend on the first argument. Valid commands and arguments are:
magnitude_table( add => $id, $mag )โ adds a magnitude entry to the table, replacing the existing entry for the given OID if any.magnitude_table( adjust => $adjustment )โ maintains a magnitude adjustment to be added to the value in the magnitude table before setting the"intrinsic_magnitude"of an object. If the argument is"undef"the current adjustment is returned; otherwise the argument becomes the new adjustment. Actual magnitude table entries are not modified by this operation; the adjustment is done in theparse()method.magnitude_table( 'clear' )โ clears the magnitude table. bye bye data. ๐งนmagnitude_table( drop => $id )โ removes the given OID from the table if it's there.magnitude_table( magnitude => \%mag )โ replaces the magnitude table with the contents of the given hash. The keys will be normalized to 5 digits.magnitude_table( molczan => $file_name, $mag_offset )โ replaces the magnitude table with the contents of the named Molczan-format file. The$file_nameargument can also be a scalar reference with the scalar containing the data, or an open handle. The$mag_offsetis an adjustment to be added to the magnitudes read from the file, and defaults to 0.magnitude_table( quicksat => $file_name, $mag_offset )โ replaces the magnitude table with the contents of the named Quicksat-format file. The$file_nameargument can also be a scalar reference with the scalar containing the data, or an open handle. The$mag_offsetis an adjustment to be added to the magnitudes read from the file, and defaults to 0. In addition to this value, 0.7 is added to the magnitude before storage to adjust the data from full-phase to half-phase.magnitude_table( show => ... )โ returns an array which is a slice of the magnitude table, which is stored as a hash. In other words, it returns OID/magnitude pairs in no particular order. If any further arguments are passed, they are the OIDs to return. Otherwise all are returned.
Examples of Molczan-format data are contained in mcnames.zip and vsnames.zip available on Mike McCants' web site; these can be fetched using the Astro::SpaceTrack mccants() method. An example of Quicksat-format data is contained in qsmag.zip. See Mike McCants' web site, <https://www.mmccants.org//> for an explanation of the differences. ๐
โ ๏ธ Note that if you have one of the reported pure Perl versions ofScalar::Util, you can not pass open handles to functionality that would otherwise accept them. so check yourScalar::Util, bestie. ๐ญ
๐ซ $time = $tle->max_effective_date(...)
okay so this one hands you back the latest date out of everything you feed it โ all of its arguments plus the effective date sitting on the $tle object, as set in the effective attribute, if that one's actually defined. And if there's no effective date set but the backdate attribute is false? Then it just lowkey uses the object's epoch as the effective date instead. And if you pass it zero arguments and there's no effective date anywhere โ undef, bestie. That's the whole vibe check. ๐ธ
๐ซถ $tle = $tle->members()
literally just returns the object you called it on. that's it. no transformation, no glow-up, no nothing. It exists purely for convenience โ so when you're iterating over a big messy mixture of Astro::Coord::ECI::TLE and Astro::Coord::ECI::TLE::Set objects, you can get back a validated object and keep it moving. main character energy of "I am simply myself." ๐
๐ $tle = $tle->model($time)
This one calculates the position of the body described by the TLE object at the given time, using the preferred model. As of Astro::Coord::ECI::TLE 0.010_10 that preferred model is sgp4r; before that it was sgp4 or sdp4, whichever was appropriate.
The whole intent here is that this method uses whatever model is currently preferred. And if the preferred model ever changes, this method will use the new preferred model the second I:
- Find out about the change;
- Can get the specifications for the new model;
- Can find the time to code up the new model.
no cap, that's the actual criterion. ๐ญ
Also important: you gotta call one of theAstro::Coord::ECImethods (likegeodetic()orequatorial()) to actually retrieve the position you just calculated. This method does the math โ it doesn't hand you the coordinates, bestie.
๐ฆ $tle = $tle->model4 ($time)
Calculates the position of the body described by the TLE object at the given time, using either the SGP4 or SDP4 model, whichever is appropriate for that body. iconic classic behavior.
Same deal as above: call one of theAstro::Coord::ECImethods (e.g.geodetic()orequatorial()) to get the position you just computed.
๐ $tle = $tle->model4r ($time)
Calculates the position of the body described by the TLE object at the given time, using the "Revisiting Spacetrack Report #3" model (sgp4r). It's honestly just a synonym for sgp4r โ which covers both near-earth and deep space bodies โ but it's here for consistency's sake. And if some other model becomes the preferred one later, this method still calls sgp4r. loyal to the end fr fr. ๐
Yep, you already know: call one of theAstro::Coord::ECImethods (e.g.geodetic()orequatorial()) to actually retrieve the position.
โญ $tle = $tle->model8 ($time)
Calculates the position of the body described by the TLE object at the given time, using either the SGP8 or SDP8 model, whichever is appropriate.
And once more, with feeling: call one of theAstro::Coord::ECImethods (e.g.geodetic()orequatorial()) to retrieve the position you just calculated.
๐ $tle = $tle->null ($time)
This method does nothing. absolutely nothing. zero. It is, however, a valid orbital model โ which is the plot twist. So if you call $tle->set (model => 'null'), then no position calculation happens as a side effect of calling $tle->universal ($time). it's giving "I'm here but I'm not doing labor." ๐
๐ @elements = Astro::Coord::ECI::TLE->parse( @data );
This one parses NORAD two- or three-line element sets, JSON element sets, or a mixture of both, and returns a list of Astro::Coord::ECI::TLE objects. The "Attributes" section identifies which attributes get filled in by this method.
Here's how it rolls:
- TLE input gets split into individual lines, and all blank lines and lines beginning with
'#'are eliminated. - The remaining lines are assumed to represent two- or three-line element sets, in so-called external format.
- Internal format โ denoted by a
'G'in column 79 of line 1 of the set, not counting the common name if any โ is not supported, and if such data shows up, an exception gets thrown. yeah. it will simply not be happening. ๐ญ - Input beginning with
"[{"(with optional spaces) is presumed to be NORAD JSON element sets and gets parsed accordingly.
Optionally, the first argument (after the invocant) can be a reference to a hash of default attribute values. Those defaults are preferred over the static values โ but attributes provided by the TLE or JSON input override both. hierarchy, bestie. ๐
๐ฅ @passes = $tle->pass ($station, $start, $end, \@sky)
This method returns passes of the body over the given station between the given start and end times. The \@sky argument is background bodies to compute appulses with (see note 3).
A pass is detected by this method when the body sets. And unless "PASS_VARIANT_TRUNCATE" (see below) is in effect, that means:
- passes are not usefully detected for geosynchronous or near-geosynchronous bodies, and
- passes where the body sets after the
$endtime will not be detected.
so like... know that going in. ๐ซ
All arguments are optional โ here are the defaults:
$station = the 'station' attribute of the invocant
$start = time()
$end = $start + 7 days
\@sky = []
The return is a list of passes, which may absolutely be empty. Each pass is represented by an anonymous hash containing these keys:
{body} => Reference to body making pass;
{time} => Time of pass (culmination);
{events} => [the individual events of the pass].
The individual events are also anonymous hashes, each one containing these keys:
{azimuth} => Azimuth of event in radians (see note 1);
{body} => Reference to body making pass (see note 2);
{appulse} => { # This is present only for PASS_EVENT_APPULSE;
{angle} => minimum separation in radians;
{body} => other body involved in appulse;
}
{elevation} => Elevation of event in radians (see note 1);
{event} => Event code (PASS_EVENT_xxxx);
{illumination} => Illumination at time of event (PASS_EVENT_xxxx);
{range} => Distance to event in kilometers (see note 1);
{station} => Reference to observing station (see note 2);
{time} => Time of event;
The events are coded by these manifest constants โ copy them exactly, don't be cute with them:
PASS_EVENT_NONE => dualvar (0, '');
PASS_EVENT_SHADOWED => dualvar (1, 'shdw');
PASS_EVENT_LIT => dualvar (2, 'lit');
PASS_EVENT_DAY => dualvar (3, 'day');
PASS_EVENT_RISE => dualvar (4, 'rise');
PASS_EVENT_MAX => dualvar (5, 'max');
PASS_EVENT_SET => dualvar (6, 'set');
PASS_EVENT_APPULSE => dualvar (7, 'apls');
PASS_EVENT_START => dualvar( 11, 'start' );
PASS_EVENT_END => dualvar( 12, 'end' );
PASS_EVENT_BRIGHTEST => dualvar( 13, 'brgt' );
The PASS_EVENT_START and PASS_EVENT_END events are not normally generated. You can get them in lieu of whatever events start and end the pass by setting "PASS_VARIANT_START_END" in the pass_variant attribute. Though โ unless you're filtering out non-visible events โ they're just the rise and set events under different names. same behavior, different name tag. ๐
The dualvar function comes from Scalar::Util, and it generates values which are numeric in numeric context and strings in string context. If Scalar::Util cannot be loaded, the numeric values are returned instead. fallback queen. ๐
These manifest constants can be imported using the individual names, or the tags ':constants' or ':all'. They can also be accessed as methods using (e.g.) $tle->PASS_EVENT_LIT, or as static methods using (e.g.) Astro::Coord::ECI::TLE->PASS_EVENT_LIT. so many doors, all valid. ๐ชโจ
Illumination is represented by one of PASS_EVENT_SHADOWED, PASS_EVENT_LIT, or PASS_EVENT_DAY. The first two are calculated based on whether the illuminating body (i.e. the body specified by the 'illum' attribute) is above the horizon; the third is based on whether the Sun is higher than specified by the 'twilight' attribute โ and it trumps the other two (i.e. if it's day, it doesn't matter whether the satellite is illuminated). day is day, periodt. โ๏ธ
Time resolution of the events is typically to the nearest second, except for appulses, which need to be calculated more closely to detect transits. The time reported for the event is the time after the event occurred. For example: the time reported for rise is the earliest time the body is found above the horizon, and the time reported for set is the earliest time the body is found below the horizon. no rounding shenanigans, okay? ๐ค
The operation of this method is affected by the following attributes, in addition to its arguments and the orbital elements associated with the object:
* appulse # Maximum appulse to report
* edge_of_earths_shadow # Used in the calculation of
# whether the satellite is illuminated or in
# shadow.
* geometric # Use geometric horizon for pass rise/set
* horizon # Effective horizon
* interval # Interval for pass() positions, if positive
* lazy_pass_position # {azimuth}, {elevation} and {range}
# are optional if true (see note 1).
* pass_threshold # Minimum elevation satellite must reach
# for the pass to be reportable. If visible
# is true, it must be visible above this
# elevation
* pass_variant # Tweak what pass() returns; currently no
# effect unless 'visible' is true.
* illum # Source of illumination.
* twilight # Distance of illuminator below horizon
* visible # Pass() reports only illuminated passes
๐ธ Note 1
If the "lazy_pass_position" attribute is true, the {azimuth}, {elevation}, and {range} keys may not be present. This attribute gives the event-calculating algorithm permission to omit these if the time of the event can be determined without computing the position of the body. Currently this happens only for events generated in response to setting the "interval" attribute โ but the user should not make this assumption in his or her own code. don't get comfortable, bestie. ๐
Typically you'll only want to set this true if, after calling the pass() method, you're not interested in the azimuth, elevation and range, but instead compute the event positions in some coordinates other than azimuth, elevation, and range. iykyk. ๐
๐ง Note 2
The time set in the various {body} and {station} objects is not guaranteed to be anything in particular. Specifically, it is almost certainly not the time of the event. So if you make use of the {body} object, you'll probably need to set its time to the time of the event before you do so. it's giving "I'm a reference, not a timestamp." ๐
๐ Note 3
The algorithm for computing appulses has been modified slightly in version 0.056_04. This modification only applies to elements of the optional "\@sky" array that represent artificial satellites. ๐กโจ
The problem I'm trying to address is that two satellites in very similar orbits can appear to converge again after their appulse, due to their increasing distance from the observer. If this happens early enough in the pass it can fool the binary search algorithm that determines the appulse time ๐ญ
The revision is to first step across the pass, finding the closest approach of the two bodies. A binary search is then done on a small interval around the closest approach โจ
๐ซ $kilometers = $tle->periapsis();
This method returns the periapsis of the orbit, in kilometers. Since Astro::Coord::ECI::TLE objects always represent bodies orbiting the Earth, this is more usually called perigee ๐ฐ๏ธ
Heads up bestie: this is the distance from the center of the Earth, not the altitude. Don't let anyone tell you otherwise ๐
๐ $kilometers = $tle->perigee();
This method is simply a synonym for periapsis(). Same vibes, different name, no cap ๐
โฑ๏ธ $seconds = $tle->period ($model);
This method returns the orbital period of the object in seconds using the given model. If the model is unspecified (or specified as a false value), the current setting of the 'model' attribute is used.
There are actually only two period calculations available, fr fr:
- If the model is
'sgp4r'(or its equivalents'model'and'model4r'), thesgp4rcalculation will be used. - Otherwise the calculation from the original Space Track Report Number 3 will be used. And "otherwise" includes the case where the model is
'null'.
The difference between using the original and the revised algorithm is minimal ๐ For the objects in the sgp4-ver.tle file provided with the 'Revisiting Spacetrack Report #3' code, the largest is about 50 nanoseconds for OID 23333, which is in a highly eccentric orbit.
The difference between using the various values of gravconst_r with sgp4r is somewhat more pronounced. Among the objects in sgp4-ver.tle the largest difference was about a millisecond, again for OID 23333.
Neither of these differences seems to me significant, but I thought it would be easier to take the model into account than to explain why I did not ๐
A note on subclassing: a body that is not in orbit should return a period of undef ๐ซถ
๐ฆ $tle = $tle->rebless ($class, \%possible_attributes)
This method reblesses a TLE object. The class must be either Astro::Coord::ECI or a subclass thereof, as must the object passed in to be reblessed. If the $tle object has its "reblessable" attribute false, it will not be reblessed, but will be returned unmodified. Before reblessing, the before_reblessing() method is called. After reblessing, the after_reblessing() method is called with the \%possible_attributes hash reference as argument โจ
It is possible to omit the $class argument if the \%possible_attributes argument contains the keys {class} or {type}, taken in that order. If the $class argument is omitted and the \%possible_attributes hash does not have the requisite keys, the $tle object is unmodified ๐ธ
It is also possible to omit both arguments, in which case the object will be reblessed according to the content of the internal status table ๐
For convenience, you can pass an alias instead of the full class name. The following aliases are recognized:
tle => 'Astro::Coord::ECI::TLE'
If you install Astro::Coord::ECI::TLE::Iridium it will define alias
iridium => 'Astro::Coord::ECI::TLE::Iridium'
Other aliases may be defined with the alias() static method.
Note that this method returns the original object (possibly reblessed). It does not under any circumstances manufacture another object. Like, at all. Periodt ๐
๐ $kilometers = $tle->semimajor();
This method calculates the semimajor axis of the orbit, using Kepler's Third Law (Isaac Newton's version) in the form
T ** 2 / a ** 3 = 4 * pi ** 2 / mu
where
T is the orbital period,
a is the semimajor axis of the orbit,
pi is the circle ratio (3.14159 ...), and
mu is the Earth's gravitational constant,
3.986005e5 km ** 3 / sec ** 2
The calculation is carried out using the period implied by the current model โญ
๐ง $kilometers = $tle->semiminor();
This method calculates the semiminor axis of the orbit, using the semimajor axis and the eccentricity, by the equation
b = a * sqrt(1 - e)
where a is the semimajor axis and e is the eccentricity ๐
๐ $tle->set (attribute => value ...)
This method sets the values of the various attributes. The changing of attributes actually used by the orbital models will cause the models to be reinitialized. This happens transparently, and is no big deal ๐ For a description of the attributes, see "Attributes".
Because this is a subclass of Astro::Coord::ECI, any attributes of that class can also be set.
๐ Astro::Coord::ECI::TLE->status (command => arguments ...)
This method maintains the internal status table, which is used by the parse() method to determine which subclass (if any) to bless the created object into. The first argument determines what is done to the status table; subsequent arguments depend on the first argument. Valid commands and arguments are:
status (add => $id, $type => $status, $name, $comment)โ adds an item to the status table or modifies an existing item. The$idis the NORAD ID of the body.- No types are supported out of the box, but if you have installed
Astro::Coord::ECI::TLE::Iridiumthat or'iridium'will work ๐ฅ - The
$statusis0,1,2, or3representing in-service, spare, failed, or decayed respectively. The strings'+'or''will be interpreted as0,'S','s', or'?'as1,'D'as3, and any other non-numeric string as2. The$nameand$commentarguments default to empty. status ('clear')โ clears the status table.status (clear => 'type')โ clears all entries of the given type in the status table. For supported types, see the discussion of'add', above.status (drop => $id)โ removes the given NORAD ID from the status table.status ('show')โ returns a list of list references, representing the'add'commands which would be used to regenerate the status table.
Initially, the status table is populated with the status as of December 3, 2010 ๐
๐ฐ๏ธ $tle = $tle->sgp($time)
This method calculates the position of the body described by the TLE object at the given time, using the SGP model. The universal time of the object is set to $time, and the 'equinox_dynamical' attribute is set to to the current value of the 'epoch_dynamical' attribute.
The result is the original object reference. You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to retrieve the position you just calculated ๐
"Spacetrack Report Number 3" (see "Acknowledgments") says that this model can be used for either near-earth or deep-space orbits, but the reference implementation they provide dies on an attempt to use this model for a deep-space object, and I have followed the reference implementation ๐
๐ซ $tle = $tle->sgp4($time)
This method calculates the position of the body described by the TLE object at the given time, using the SGP4 model. The universal time of the object is set to $time, and the 'equinox_dynamical' attribute is set to the current value of the 'epoch_dynamical' attribute.
The result is the original object reference. See the "DESCRIPTION" heading above for how to retrieve the coordinates you just calculated โจ
"Spacetrack Report Number 3" (see "Acknowledgments") says that this model can be used only for near-earth orbits.
๐ $tle = $tle->sdp4($time)
This method calculates the position of the body described by the TLE object at the given time, using the SDP4 model. The universal time of the object is set to $time, and the 'equinox_dynamical' attribute is set to the current value of the 'epoch_dynamical' attribute.
The result is the original object reference. You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to retrieve the position you just calculated ๐ธ
"Spacetrack Report Number 3" (see "Acknowledgments") says that this model can be used only for deep-space orbits.
โญ $tle = $tle->sgp8($time)
This method calculates the position of the body described by the TLE object at the given time, using the SGP8 model. The universal time of the object is set to $time, and the 'equinox_dynamical' attribute is set to the current value of the 'epoch_dynamical' attribute.
The result is the original object reference. You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to retrieve the position you just calculated ๐
"Spacetrack Report Number 3" (see "Acknowledgments") says that this model can be used only for near-earth orbits.
๐ฆ $tle = $tle->sdp8($time)
This method calculates the position of the body described by the TLE object at the given time, using the SDP8 model. The universal time of the object is set to $time, and the 'equinox_dynamical' attribute is set to the current value of the 'epoch_dynamical' attribute.
The result is the original object reference. You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to retrieve the position you just calculated ๐ง
"Spacetrack Report Number 3" (see "Acknowledgments") says that this model can be used only for near-earth orbits.
๐ $self->time_set();
This method sets the coordinates of the object to whatever is computed by the model specified by the model attribute. The 'equinox_dynamical' attribute is set to the current value of the 'epoch_dynamical' attribute.
Although there is no reason this method can not be called directly, it exists to take advantage of the hook in the Astro::Coord::ECI object, to allow the position of the body to be computed when the time of the object is set ๐
๐ฅ $tle = $tle->sgp4r($time)
This method calculates the position of the body described by the TLE object at the given time, using the revised SGP4 model. The universal time of the object is set to $time, and the 'equinox_dynamical' attribute is set to the current value of the 'epoch_dynamical' attribute.
The result is the original object reference. See the "DESCRIPTION" heading above for how to retrieve the coordinates you just calculated ๐
So the tea on this model: the algorithm comes from "Revisiting Spacetrack Report Number 3" (peep ACKNOWLEDGMENTS ๐). That report is lowkey like "this is a correction and extension of SGP4, we merged it with SDP4, and we're just gonna call the whole thing SGP4." And I appended the "r" (for 'revised' or 'revisited', pick your fighter) because I kept the original algorithm around too. Both can stay, it's fine, they're both icons.
โ ๏ธ Note well, bestie: this algorithm depends on the setting of the gravconst_r attribute. The default setting of that attribute in this module is 84, but the test data that ships with "Revisiting Spacetrack Report #3" uses 72. So yeah, don't get caught out there.
This algorithm is also (currently) the only one that returns a useful value in the model_error attribute, like so:
0 = success
1 = mean eccentricity < 0 or > 1, or a < .95
2 = mean motion < 0.0
3 = instantaneous eccentricity < 0 or > 1
4 = semi-latus rectum < 0
5 = epoch elements are sub-orbital
6 = satellite has decayed
These errors are dualvars if your Scalar::Util supports these ๐ซถ. That is, they are interpreted as numbers in numeric context and the corresponding string in string context. The string is generally the explanation, except for 0, which is '' in string context. If your Scalar::Util does not support dualvar, the numeric value is returned. Periodt.
Currently, errors 1 through 4 cause an explicit exception to be thrown after setting the model_error attribute. Exceptions will also be thrown if the TLE eccentricity is negative or greater than one, or the TLE mean motion is negative. Like, it's throwing hands ๐ญ.
Errors 5 and 6 look more like informational errors to me, ngl. Error 5 indicates that the perigee is less than the radius of the earth. This could very well happen if the TLE represents a coasting arc of a spacecraft being launched or preparing for re-entry. Error 6 means the actual computed position was underground ๐. Maybe this should be an exception, though I have never needed this kind of exception previously.
Note that this first release of the 'Revisiting Spacetrack Report #3' functionality should be considered alpha code. That is to say, I may need to change the way it behaves, especially in the matter of what is an exception and what is not. So don't come for me if the vibes shift.
$text = $tle->tle_verbose(...);
This method returns a verbose version of the TLE data, with one data field per line, labeled. The optional arguments are key-value pairs affecting the formatting of the output. The only key implemented at the moment is
date_formatโ specifies thestrftime()format used for dates (default:'%d-%b-%Y %H:%M:%S').
$hash_ref = $tle->TO_JSON();
Despite its name, this method does not convert the object to JSON ๐. What it does instead is return a reference to a hash that the JSON class will use to encode the object into JSON. The possible keys are, to the extent possible, those used by the Space Track REST interface.
In order to get JSON to use this hook you need to instantiate a JSON object and turn on the conversion of blessed objects, like so:
my $json = JSON->new()->convert_blessed( 1 );
print $json->encode( $tle );
The returned keys are a mish-mash of the keys returned by the Space Track "satcat" and "tle" classes, plus others that are not maintained by Space Track. Since the Space Track keys are all upper case, I have made the non-Space Track keys all lower case.
At this point I am not going to document the keys returned by this method, but they are generally self-explanatory. I find the most cryptic one is "{INTLDES}", which is the International Launch Designator, encoded with a four-digit year. That's the one that makes you go "huh?" the longest, iykyk.
$valid = $tle->validate($options, $time ...);
This method checks to see if the currently-selected model can be run successfully. If so, it returns 1; if not, it returns 0.
The $options argument is itself optional. If passed, it is a reference to a hash of option names and values. At the moment the only option used is
quiet => 1โ to suppress output toSTDERR.
If the "quiet" option is not specified, or is specified as a false value, validation failures will produce output to STDERR. Noisy fail, we love to see it.
Each $time argument is adjusted by passing it through $tle->max_effective_date, and the distinct adjusted times are sorted into ascending order. The currently-selected model is run at each of the times thus computed. The return is 0 if any run fails, or 1 if they all succeed. Slay, all-or-nothing.
If there are no $time arguments, the model is run at the effective date if that is specified, or the epoch if the effective date is not specified.
Attributes
This class has the following additional public attributes. The description gives the data type. It may also give one of the following if applicable:
parseโ if the attribute is set by theparse()method;read-onlyโ if the attribute is read-only;staticโ if the attribute may be set on the class as well as an object.
Note that the orbital elements provided by NORAD are tweaked for use by the models implemented by this class. If you plug them in to the same-named parameters of other models, your mileage may vary significantly. Fr fr, don't do it and then @ me.
appulse (numeric, static)
This attribute contains the angle of the widest appulse to be reported by the pass() method, in radians.
The default is equivalent to 10 degrees.
argumentofperigee (numeric, parse)
This attribute contains the argument of perigee (angular distance from ascending node to perigee) of the orbit, in radians.
ascendingnode (numeric, parse)
This attribute contains the right ascension of the ascending node of the orbit at the epoch, in radians.
backdate (boolean, static)
This attribute determines whether the pass() method will go back before the epoch of the data. If false, the pass() method will silently adjust its start time forward. If this places the start time after the end time, an empty list is returned.
Note that this is a change from the behavior of Astro::Coord::ECI::TLE version 0.010, which threw an exception if the backdate adjustment placed the start time after the end time. Glow-up behavior change, honestly ๐
.
The default is 1 (i.e. true).
bstardrag (numeric, parse)
This attribute contains the B* drag term, decoded into a number.
classification (string, parse)
This attribute contains the security classification. You should expect to see only the value 'U', for 'Unclassified.' Iconic, consistent, no drama.
ds50 (numeric, readonly, parse)
This attribute contains the "epoch", in days since 1950. Setting the "epoch" also modifies this attribute.
eccentricity (numeric, parse)
This attribute contains the orbital eccentricity, with the implied decimal point inserted.
effective (numeric, parse)
This attribute contains the effective date of the TLE, as a Perl time in seconds since the epoch. As a convenience, it can be set in the format used by NASA to specify this, as year/day/hour:minute:second, where all fields are numeric, and the day is the day number of the year, January 1 being 1, and December 31 being either 365 or 366. Cute little shorthand, we stan a flexible input.
elementnumber (numeric, parse)
This attribute contains the element set number of the data set. In theory, this gets incremented every time a data set is issued. "In theory" doing a lot of work in that sentence ๐ญ.
ephemeristype (numeric, parse)
This attribute records a field in the data set which is supposed to specify which model to use with this data. In practice, it seems always to be zero. Every time. Zero. Iconic in its commitment to nothing.
epoch (numeric, parse)
This attribute contains the epoch of the orbital elements โ that is, the 'as-of' date and time โ as a Perl date. Setting this attribute also modifies the epoch_dynamical and ds50 attributes.
epoch_dynamical (numeric, readonly, parse)
This attribute contains the dynamical time corresponding to the "epoch". Setting the "epoch" also modifies this attribute.
file (numeric)
This attribute contains the file number of the TLE data. It is typically present only if the TLE object was parsed from a Space Track JSON file; otherwise it is undefined.
firstderivative (numeric, parse)
This attribute contains the first time derivative of the mean motion, in radians per minute squared.
geometric (boolean, static)
Tells the pass() method whether to calculate rise and set relative to the geometric horizon (if true) or the horizon attribute (if false).
The default is 0 (i.e. false).
gravconst_r (numeric, static)
Tells the sgp4r() method which set of gravitational constants to use. Legal values are:
72โ Use WGS-72 values;721โ Use old WGS-72 values;84โ Use WGS-84 values.
The 'old WGS-72 values' appear from the code comments to be those embedded in the original SGP4 model given in "Space Track Report Number 3".
Note well that "Revisiting Spacetrack Report #3" says "We use WGS-72 as the default value." It does not state whether it means the values specified by72or the values specified by721, but the former gives results closer to the test results included with the code. Ambiguous queen.
Comparing the positions computed by this code to the positions given in the published test results, the following maximum deviations are found, depending on the gravconst_r value used:
72โ4mm (oid23333, X at epoch)721โ57cm (OID28350, X at1320minutes from epoch)84โ3.22km (OID23333, X at epoch)
The default is 72, to agree with "Revisiting Spacetrack Report #3".
id (numeric, parse)
This attribute contains the NORAD SATCAT catalog ID.
illum (string, static)
This attribute specifies the source of illumination for the body, for the purpose of detecting things like Iridium flares โจ. This is distinguished from the parent class' 'sun' attribute, which is used to determine night or day.
You may specify the class name 'Astro::Coord::ECI' or the name of any subclass (though in practice only 'Astro::Coord::ECI::Sun' or 'Astro::Coord::ECI::Moon' will do anything useful), or an alias() thereof, or you may specify an object of the appropriate class. When you access this attribute, you get an object. ๐ซถ
In addition to the full class names, 'sun' and 'moon' are set up as aliases for Astro::Coord::ECI::Sun and Astro::Coord::ECI::Moon respectively. Other aliases can be set up using the alias() mechanism. The value 'sun' (or something equivalent) is probably the only useful value, but I know people have looked into Iridium 'Moon flares', so I exposed the attribute. ๐ฐ๏ธโจ
The default is 'sun'.
๐ธ interval (numeric, static)
If it's positive, this attribute says the pass() method should return positions at this interval (in seconds) all across the sky ๐ซ. The associated event code on those will be PASS_EVENT_NONE. If it's zero or negative, pass() will only hand you times when some event of interest actually goes down.
The default is 0.
๐ธ inclination (numeric, parse)
This one's holding the orbital inclination in radians. ๐
๐ธ international (string, parse)
Your international launch designator lives here, bestie, and it's got three parts fr:
- a two-digit number (leading zero if needed) giving the last two digits of the launch year (in the range 1957-2056) ๐๏ธ
- a three-digit number (leading zeros if needed) giving the order of the launch within the year ๐ข
- one to three letters designating the "part" of the launch โ payload(s) get the first letters, and spent boosters, debris, etc. get the rest ๐
๐ธ intrinsic_magnitude (numeric or undef)
If it's defined, this is the typical magnitude of the body at half phase and range 1000 kilometers, when it's lit up by the Sun โ๏ธ. Ngl I am not sure how standard this definition really is. It's the definition Ted Molczan used, but Mike McCants' Quicksat data uses maximum magnitude full phase instead. ๐คทโโ๏ธ
๐ธ lazy_pass_position (boolean, static)
This attribute tells the pass() method that the "{azimuth}", "{elevation}", and "{range}" keys in the pass event hashes don't actually need to be generated. ๐ฆฅ
It was intended for when you want event positions in coordinate systems other than โ or in addition to โ azimuth, elevation, and range. In that case it may be faster for you to set this attribute, then compute the event positions after pass() has generated the events. Heads up though: if you do this, you will have to call universal() on the event's "{body}", passing it the event's "{time}", before retrieving the coordinates you want. ๐ซถ
The default is 0 (i.e. false).
๐ธ meananomaly (numeric, parse)
This attribute contains the mean orbital anomaly at the epoch, in radians. In slightly less technical terms ๐ , this is the angular distance a body in a circular orbit of the same period (that's what the 'mean' means) would be from perigee at the epoch, measured in the plane of the orbit. ๐ง
๐ธ meanmotion (numeric, parse)
Holds the mean motion of the body, in radians per minute. โฑ๏ธ
๐ธ model (string, static)
This attribute contains the name of the model to be run (i.e. the name of the method to be called) when the time_set() method is called โ or a false value if no model is to be run. Legal model names are: model, model4, model4r, model8, null, sgp, sgp4, sgp4r, sgp8, sdp4, and sdp8. ๐
The default is 'model'. Setting the value on the class changes the default.
๐ธ model_error (number)
The sgp4r() model sets this to the number of the error encountered, with 0 representing success โ
. See the documentation to that model for the values set. All other models simply set this to undef. It is not a read-only attribute, so the interested user can clear the value if desired.
The default is undef.
๐ธ name (string, parse (three-line sets only))
This attribute contains the common name of the body. ๐ท๏ธ
๐ธ object_type
This attribute contains the object type of the TLE data. It's typically present only if the TLE object was parsed from a Space Track JSON file; otherwise it is undefined. However, if it is defined it will be returned by the body_type() method. โจ
When setting this, possible values are those returned by body_type() โ either the dualvar constants themselves, or the numeric or case-insensitive strings corresponding to them. Whatever you set, what gets stored and returned will be one of the "BODY_TYPE_*" constants. Any unrecognized value will be stored as "BODY_TYPE_UNKNOWN", with a warning. โ ๏ธ
๐ธ ordinal (numeric)
This attribute contains the ordinal number of the TLE data. It's typically present only if the TLE object was parsed from a Space Track JSON file; otherwise it is undefined.
๐ธ originator (string)
This attribute contains the name of the originator of the TLE data. It's typically present only if the TLE object was parsed from a Space Track JSON file; otherwise it is undefined. ๐งพ
๐ธ pass_variant (bits)
This attribute tweaks the pass output as specified by its value, which should be the bitwise 'or' (i.e. "|") of these values ๐:
"PASS_VARIANT_VISIBLE_EVENTS"โ says that events which are not visible (that is, which take place either during daylight or with the body in shadow) are not reported. Illumination changes, however, are always reported. Has no effect unless the"visible"attribute is true. ๐๐"PASS_VARIANT_FAKE_MAX"โ says that if"PASS_VARIANT_VISIBLE_EVENTS"filters out the max, a new max event, at the same time as either the first or last reported event, will be inserted. No effect unless"PASS_VARIANT_VISIBLE_EVENTS"is specified, and the"visible"attribute is true."PASS_VARIANT_START_END"โ says that the first and last events of the pass are to be identified as"PASS_EVENT_START"and"PASS_EVENT_END"respectively. If the"visible"attribute is true and"PASS_VARIANT_VISIBLE_EVENTS"is in effect,"PASS_EVENT_START"will replace either"PASS_EVENT_RISE"or"PASS_EVENT_LIT", and"PASS_EVENT_END"will replace either"PASS_EVENT_SET","PASS_EVENT_SHADOWED", or"PASS_EVENT_DAY". Otherwise, they replace"PASS_EVENT_RISE"and"PASS_EVENT_SET"respectively. ๐ฌ"PASS_VARIANT_NO_ILLUMINATION"โ says that no illumination calculations are to be made at all. That means no"PASS_EVENT_LIT","PASS_EVENT_SHADOWED", or"PASS_EVENT_DAY"events are generated, and the"illumination"key on other events will not be present. I find that setting this (with"visible => 0") saves about 20% in wall clock time versus not setting it. Your mileage may, of course, vary. โก Has no effect unless the"visible"attribute is false."PASS_VARIANT_TRUNCATE"โ says that any pass in progress at the beginning or end of the calculation interval is to be truncated to the interval. If the calculation interval starts with the body already above the horizon, the initial event of that pass will be"PASS_EVENT_START"rather than"PASS_EVENT_RISE". Similarly, if the calculation interval ends with the body still above the horizon, the final event of that pass will be"PASS_EVENT_END". With this variant in effect, 'passes' will be computed for synchronous satellites. ๐ฐ๏ธ This variant is to be considered experimental. ๐"PASS_VARIANT_BRIGHTEST"โ says that the moment the satellite is brightest be computed as part of the pass statistics. The computation is to the nearest second, and is not done if"PASS_VARIANT_NO_ILLUMINATION"is set, the satellite has no intrinsic magnitude set, or the satellite is not illuminated during the pass. ๐"PASS_VARIANT_NONE"โ says that no pass variant processing take place. ๐ซ
The above constants are not exported by default, but are exported by the ":constants" tag.
The default is "PASS_VARIANT_NONE".
๐ธ rcs (string, parse)
This attribute represents the radar cross-section of the body, in square meters. ๐ก
๐ธ reblessable (boolean)
This attribute says whether the rebless() method is allowed to rebless this object. If it's false, the object will not be reblessed when its id changes. ๐ช
Note that if this attribute is false, setting it true will cause the object to be reblessed.
The default is true (i.e. 1).
๐ธ revolutionsatepoch (numeric, parse)
This attribute contains number of revolutions the body has made since launch, at the epoch. ๐
๐ธ secondderivative (numeric, parse)
This attribute contains the second time derivative of the mean motion, in radians per minute cubed. ๐งฎ
๐ธ pass_threshold (numeric or undef)
If it's defined, this attribute defines the elevation in radians that the satellite must reach above the horizon for its passes to be reported. If the "visible" attribute is true, the satellite must be visible above this elevation. ๐
If undefined, any pass above the horizon will be reported (i.e. you get the same behavior as before this attribute was introduced in version 0.046).
Heads up, there's a slight change in the behavior of this attribute from version 0.046. In that version, it did not matter whether the satellite was visible, even if the "visible" attribute was true.
You might use this attribute if you want to use a nominal horizon of .35 radians (20 degrees), but are only interested in passes that reach an elevation of .70 radians (40 degrees). ๐
The default is "undef".
๐ธ tle (string, readonly, parse)
This attribute contains the input data used by the parse() method to generate this object. If the object was not created by the parse() method, a (hopefully) equivalent TLE will be constructed and returned if enough attributes have been set โ otherwise an exception will be raised. ๐ญ
๐ธ visible (boolean, static)
This attribute tells the pass() method whether to report only passes which are illuminated (if true) or all passes (if false). ๐ก
The default is 1 (i.e. true).
๐ ACKNOWLEDGMENTS ๐
okay so the author literally wants to shout out these people and honestly? deserved. here's the whole squad:
- Dominik Brodowski (
<https://www.brodo.de/>) โ his SGP C-lib (over at<https://www.brodo.de/space/sgp/>) was the reference implementation our author could just run and also take apart to get his own code working. Dominik built his stuff on Dr. Kelso's Pascal implementation, so it's like a whole lineage of slay. ๐ - Felix R. Hoots and Ronald L. Roehric โ authors of "SPACETRACK REPORT NO. 3 - Models for Propagation of NORAD Element Sets," which is literally the basis for the
Astro::Coord::ECI::TLEmodule. iconic source material fr fr ๐ - David A. Vallado, Paul Crawford, Richard Hujsak, and T. S. Kelso โ the authors of "Revisiting Spacetrack Report #3", which they presented at the 2006 AIAA/AAS Astrodynamics Specialist Conference. no cap, legends.
- Dr. T. S. Kelso โ made those two key reports available at
<http://celestrak.org/NORAD/documentation/spacetrk.pdf>and<http://celestrak.org/publications/AIAA/2006-6753/>respectively. also his Two-Line Element Set Format FAQ (<http://celestrak.org/columns/v04n03/>) was extremely helpful, plus his discussion of the coordinate system used (<http://celestrak.org/columns/v02n01/>) and (indirectly) his Pascal implementation of these models. king behavior honestly ๐ซถ - The TLE data used in testing the
"sgp4r"model comes from "Revisiting Spacetrack Report #3" (made available at the CelesTrak web site as cited above), and it's used with the kind permission of Dr. Kelso. ๐
๐ SEE ALSO ๐
ngl, the author is aware of no other modules that perform calculations with NORAD orbital element sets. like, none. zero. ๐
There is the Astro::Coords package by Tim Jenness, which does calculations using orbital elements โ but the NORAD elements are tweaked for use by the models implemented in this package, so it's not a like-for-like swap, iykyk.
๐ SUPPORT ๐
Support is by the author. so if something's broken, bestie, 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 just send electronic mail to the author. pick your fighter โจ
๐ AUTHOR ๐
Thomas R. Wyant, III (wyant at cpan dot org)
๐ธ COPYRIGHT AND LICENSE ๐ธ
Copyright (C) 2005-2025 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. so like, use it, love it, but don't come for the author if it acts up ๐
and that's the whole page, bestie!! you made it to the end ๐ this was Astro:...I::TLE(3pm) from the perl v5.42.2 docs, dated 2026-02-15, written by the User Contributed Perl Documentation crew โ go forth and propagate some orbits ๐
๐๐ฆ
๐ฆ where this page comes from
- alpine 3.24: perl-astro-satpass-doc 0.134-r1 ยท GPL-1.0-or-later OR Artistic-1.0-Perl
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms