| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | =head1 NAME | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | Astro::Coord::ECI::TLE - Compute satellite locations using NORAD orbit propagation models | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | The following is a semi-brief script to calculate International Space | 
| 8 |  |  |  |  |  |  | Station visibility. You will need to substitute your own location where | 
| 9 |  |  |  |  |  |  | indicated. | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | use Astro::SpaceTrack; | 
| 12 |  |  |  |  |  |  | use Astro::Coord::ECI; | 
| 13 |  |  |  |  |  |  | use Astro::Coord::ECI::TLE; | 
| 14 |  |  |  |  |  |  | use Astro::Coord::ECI::TLE::Set; | 
| 15 |  |  |  |  |  |  | use Astro::Coord::ECI::Utils qw{deg2rad rad2deg}; | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | # 1600 Pennsylvania Avenue, Washington DC, USA | 
| 18 |  |  |  |  |  |  | my $your_north_latitude_in_degrees = 38.898748; | 
| 19 |  |  |  |  |  |  | my $your_east_longitude_in_degrees = -77.037684; | 
| 20 |  |  |  |  |  |  | my $your_height_above_sea_level_in_meters = 16.68; | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | # Create object representing the observers' location. | 
| 23 |  |  |  |  |  |  | # Note that the input to geodetic() is latitude north | 
| 24 |  |  |  |  |  |  | # and longitude west, in RADIANS, and height above sea | 
| 25 |  |  |  |  |  |  | # level in KILOMETERS. | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | my $loc = Astro::Coord::ECI->geodetic ( | 
| 28 |  |  |  |  |  |  | deg2rad ($your_north_latitude_in_degrees), | 
| 29 |  |  |  |  |  |  | deg2rad ($your_east_longitude_in_degrees), | 
| 30 |  |  |  |  |  |  | $your_height_above_sea_level_in_meters/1000); | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | # Get the 'stations' catalog from Celestrak. This includes | 
| 33 |  |  |  |  |  |  | # all space stations and related bodies. | 
| 34 |  |  |  |  |  |  | # The data are all direct-fetched, so no password is | 
| 35 |  |  |  |  |  |  | # needed. | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | my $st = Astro::SpaceTrack->new( direct => 1 ); | 
| 38 |  |  |  |  |  |  | my $data = $st->celestrak( 'stations' ); | 
| 39 |  |  |  |  |  |  | $data->is_success or die $data->status_line; | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | # Parse the fetched data, yielding TLE objects. Aggregate | 
| 42 |  |  |  |  |  |  | # them into Set objects where this is warranted. We grep | 
| 43 |  |  |  |  |  |  | # the data because the Celestrak catalog we fetched | 
| 44 |  |  |  |  |  |  | # contains other stuff than the International Space | 
| 45 |  |  |  |  |  |  | # Station. | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | my @sats = grep { '25544' eq $_->get( 'id' ) } | 
| 48 |  |  |  |  |  |  | Astro::Coord::ECI::TLE::Set->aggregate( | 
| 49 |  |  |  |  |  |  | Astro::Coord::ECI::TLE->parse( $data->content() ) ); | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | # We want passes for the next 7 days. | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | my $start = time (); | 
| 54 |  |  |  |  |  |  | my $finish = $start + 7 * 86400; | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | # Loop through our objects and predict passes. The | 
| 57 |  |  |  |  |  |  | # validate() step is usually not needed for data from | 
| 58 |  |  |  |  |  |  | # Space Track, but NASA's predicted elements for Space | 
| 59 |  |  |  |  |  |  | # Shuttle flights can be funky. | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | my @passes; | 
| 62 |  |  |  |  |  |  | foreach my $tle (@sats) { | 
| 63 |  |  |  |  |  |  | $tle->validate($start, $finish) or next; | 
| 64 |  |  |  |  |  |  | push @passes, $tle->pass($loc, $start, $finish); | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  | print < | 
| 67 |  |  |  |  |  |  | Date/Time          Satellite        Elevation  Azimuth Event | 
| 68 |  |  |  |  |  |  | eod | 
| 69 |  |  |  |  |  |  | foreach my $pass (sort {$a->{time} <=> $b->{time}} @passes) { | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | #  The returned angles are in radians, so we need to | 
| 72 |  |  |  |  |  |  | #  convert back to degrees. | 
| 73 |  |  |  |  |  |  | # | 
| 74 |  |  |  |  |  |  | #  Note that unless Scalar::Util::dualvar works, the event output | 
| 75 |  |  |  |  |  |  | #  will be integers. | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | print "\n"; | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | foreach my $event (@{$pass->{events}}) { | 
| 80 |  |  |  |  |  |  | printf "%s %-15s %9.1f %9.1f %-5s\n", | 
| 81 |  |  |  |  |  |  | scalar localtime $event->{time}, | 
| 82 |  |  |  |  |  |  | $event->{body}->get ('name'), | 
| 83 |  |  |  |  |  |  | rad2deg ($event->{elevation}), | 
| 84 |  |  |  |  |  |  | rad2deg ($event->{azimuth}), | 
| 85 |  |  |  |  |  |  | $event->{event}; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | =head1 NOTICE | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | Users of JSON functionality (if any!) should be aware of a potential | 
| 92 |  |  |  |  |  |  | problem in the way L encodes numbers. The problem | 
| 93 |  |  |  |  |  |  | basically is that the locale leaks into the encoded JSON, and if the | 
| 94 |  |  |  |  |  |  | locale uses commas for decimal points the encoded JSON can not be | 
| 95 |  |  |  |  |  |  | decoded. As I understand the discussion on the associated Perl ticket | 
| 96 |  |  |  |  |  |  | the problem has always been there, but changes introduced in Perl 5.19.8 | 
| 97 |  |  |  |  |  |  | made it more likely to manifest. | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | Unfortunately the nature of the JSON interface is such that I have no | 
| 100 |  |  |  |  |  |  | control over the issue, since the workaround needs to be applied at the | 
| 101 |  |  |  |  |  |  | point the JSON C method is called. See test F | 
| 102 |  |  |  |  |  |  | for the workaround that allows tests to pass in the affected locales. | 
| 103 |  |  |  |  |  |  | The relevant L ticket is | 
| 104 |  |  |  |  |  |  | L. The relevant Perl | 
| 105 |  |  |  |  |  |  | ticket is L. | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | The C attribute has undergone a slight change in | 
| 108 |  |  |  |  |  |  | functionality from version 0.046, in which it was introduced. In the new | 
| 109 |  |  |  |  |  |  | functionality, if the C attribute is true, the satellite must | 
| 110 |  |  |  |  |  |  | actually be visible above the threshold to be reported. This is actually | 
| 111 |  |  |  |  |  |  | how the attribute would have worked when introduced if I had thought it | 
| 112 |  |  |  |  |  |  | through clearly. | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | Use of the C JSON attribute to represent the common name of the | 
| 115 |  |  |  |  |  |  | satellite is deprecated in favor of the C attribute, since | 
| 116 |  |  |  |  |  |  | the latter is what Space Track uses in their TLE data. Beginning with | 
| 117 |  |  |  |  |  |  | 0.053_01, JSON output of TLEs will use the new name. | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | Beginning with release 0.056_01, loading JSON TLE data which specifies | 
| 120 |  |  |  |  |  |  | C produces a warning the first time it happens. As of version | 
| 121 |  |  |  |  |  |  | 0.061 there is a warning every time it happens. As of version 0.066 | 
| 122 |  |  |  |  |  |  | loading JSON TLE data which specifies C is a fatal error. Six | 
| 123 |  |  |  |  |  |  | months after this, all code referring to C will be removed, | 
| 124 |  |  |  |  |  |  | meaning that the key will be silently ignored. | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | This module implements the orbital propagation models described in | 
| 129 |  |  |  |  |  |  | "SPACETRACK REPORT NO. 3, Models for Propagation of NORAD Element Sets" | 
| 130 |  |  |  |  |  |  | and "Revisiting Spacetrack Report #3." See the | 
| 131 |  |  |  |  |  |  | L section for details on these | 
| 132 |  |  |  |  |  |  | reports. | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | In other words, this module turns the two- or three-line element sets | 
| 135 |  |  |  |  |  |  | available from such places as L or | 
| 136 |  |  |  |  |  |  | L into predictions of where the relevant orbiting | 
| 137 |  |  |  |  |  |  | bodies will be. Additionally, the pass() method implements an actual | 
| 138 |  |  |  |  |  |  | visibility prediction system. | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | The models implemented are: | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | SGP - fairly simple, only useful for near-earth bodies; | 
| 143 |  |  |  |  |  |  | SGP4 - more complex, only useful for near-earth bodies; | 
| 144 |  |  |  |  |  |  | SDP4 - corresponds to SGP4, but for deep-space bodies; | 
| 145 |  |  |  |  |  |  | SGP8 - more complex still, only for near-earth bodies; | 
| 146 |  |  |  |  |  |  | SDP8 - corresponds to SGP8, but for deep-space bodies; | 
| 147 |  |  |  |  |  |  | SGP4R - updates and combines SGP4 and SDP4. | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | All the above models compute ECI coordinates in kilometers, and | 
| 150 |  |  |  |  |  |  | velocities along the same axes in kilometers per second. | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | There are also some meta-models, with the smarts to run either a | 
| 153 |  |  |  |  |  |  | near-earth model or the corresponding deep-space model depending on the | 
| 154 |  |  |  |  |  |  | body the object represents: | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | model - uses the preferred model (sgp4r); | 
| 157 |  |  |  |  |  |  | model4 - runs sgp4 or sdp4; | 
| 158 |  |  |  |  |  |  | model4r - runs sgp4r; | 
| 159 |  |  |  |  |  |  | model8 - runs sgp8 or sdp8. | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | In addition, I have on at least one occasion wanted to turn off the | 
| 162 |  |  |  |  |  |  | automatic calculation of position when the time was set. That is | 
| 163 |  |  |  |  |  |  | accomplished with this model: | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | null - does nothing. | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | The models do not return the coordinates directly, they simply set the | 
| 168 |  |  |  |  |  |  | coordinates represented by the object (by virtue of being a subclass of | 
| 169 |  |  |  |  |  |  | L) and return the object itself. | 
| 170 |  |  |  |  |  |  | You can then call the appropriate inherited method to get the | 
| 171 |  |  |  |  |  |  | coordinates of the body in whatever coordinate system is convenient. For | 
| 172 |  |  |  |  |  |  | example, to find the latitude, longitude, and altitude of a body at a | 
| 173 |  |  |  |  |  |  | given time, you do | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | my ($lat, $long, $alt) = $body->model ($time)->geodetic; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | Or, assuming the C attribute is set the way you want | 
| 178 |  |  |  |  |  |  | it, by | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | my ($lat, $long, $alt) = $body->geodetic ($time); | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | It is also possible to run the desired model (as specified by the | 
| 183 |  |  |  |  |  |  | C attribute) simply by setting the time represented | 
| 184 |  |  |  |  |  |  | by the object. | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | As of release 0.016, the recommended model to use is SGP4R, which was | 
| 187 |  |  |  |  |  |  | added in that release. The SGP4R model, described in "Revisiting | 
| 188 |  |  |  |  |  |  | Spacetrack Report #3" | 
| 189 |  |  |  |  |  |  | (L), combines SGP4 | 
| 190 |  |  |  |  |  |  | and SDP4, and updates them. For the details of the changes, see the | 
| 191 |  |  |  |  |  |  | report. | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | Prior to release 0.016, the recommended model to use was either SGP4 or | 
| 194 |  |  |  |  |  |  | SDP4, depending on whether the orbital elements are for a near-earth or | 
| 195 |  |  |  |  |  |  | deep-space body. For the purpose of these models, any body with a period | 
| 196 |  |  |  |  |  |  | of at least 225 minutes is considered to be a deep-space body. | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | The NORAD report claims accuracy of 5 or 6 places a day after the epoch | 
| 199 |  |  |  |  |  |  | of an element set for the original FORTRAN IV, which used (mostly) 8 | 
| 200 |  |  |  |  |  |  | place single-precision calculations. Perl typically uses many more | 
| 201 |  |  |  |  |  |  | places, but it does not follow that the models are correspondingly more | 
| 202 |  |  |  |  |  |  | accurate when implemented in Perl. My understanding is that in general | 
| 203 |  |  |  |  |  |  | (i.e. disregarding the characteristics of a particular implementation of | 
| 204 |  |  |  |  |  |  | the models involved) the total error of the predictions (including error | 
| 205 |  |  |  |  |  |  | in measuring the position of the satellite) runs from a few hundred | 
| 206 |  |  |  |  |  |  | meters to as much as a kilometer. | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | I have no information on the accuracy claims of SGP4R. | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | This module is a computer-assisted translation of the FORTRAN reference | 
| 211 |  |  |  |  |  |  | implementations in "SPACETRACK REPORT NO. 3" and "Revisiting Spacetrack | 
| 212 |  |  |  |  |  |  | Report #3." That means, basically, that I ran the FORTRAN through a Perl | 
| 213 |  |  |  |  |  |  | script that handled the translation of the assignment statements into | 
| 214 |  |  |  |  |  |  | Perl, and then fixed up the logic by hand. Dominik Borkowski's SGP C-lib | 
| 215 |  |  |  |  |  |  | was used as a reference implementation for testing purposes, because I | 
| 216 |  |  |  |  |  |  | didn't have a Pascal compiler, and I have yet to get any model but SGP | 
| 217 |  |  |  |  |  |  | to run correctly under g77. | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | =head2 Methods | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | The following methods should be considered public: | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | =over 4 | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | =cut | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | package Astro::Coord::ECI::TLE; | 
| 228 |  |  |  |  |  |  |  | 
| 229 | 16 |  |  | 16 |  | 154448 | use strict; | 
|  | 16 |  |  |  |  | 87 |  | 
|  | 16 |  |  |  |  | 452 |  | 
| 230 | 16 |  |  | 16 |  | 80 | use warnings; | 
|  | 16 |  |  |  |  | 30 |  | 
|  | 16 |  |  |  |  | 713 |  | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | our $VERSION = '0.129'; | 
| 233 |  |  |  |  |  |  |  | 
| 234 | 16 |  |  | 16 |  | 104 | use base qw{ Astro::Coord::ECI Exporter }; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 11073 |  | 
| 235 |  |  |  |  |  |  |  | 
| 236 | 16 |  |  |  |  | 4465 | use Astro::Coord::ECI::Utils qw{ :params :ref :greg_time deg2rad distsq | 
| 237 |  |  |  |  |  |  | dynamical_delta embodies find_first_true fold_case | 
| 238 |  |  |  |  |  |  | __format_epoch_time_usec | 
| 239 |  |  |  |  |  |  | format_space_track_json_time load_module looks_like_number max min | 
| 240 |  |  |  |  |  |  | mod2pi PI PIOVER2 rad2deg SECSPERDAY TWOPI thetag __default_station | 
| 241 |  |  |  |  |  |  | @CARP_NOT | 
| 242 | 16 |  |  | 16 |  | 119 | }; | 
|  | 16 |  |  |  |  | 34 |  | 
| 243 |  |  |  |  |  |  |  | 
| 244 | 16 |  |  | 16 |  | 118 | use Carp qw{carp croak confess}; | 
|  | 16 |  |  |  |  | 30 |  | 
|  | 16 |  |  |  |  | 1329 |  | 
| 245 | 16 |  |  | 16 |  | 9218 | use Data::Dumper; | 
|  | 16 |  |  |  |  | 94085 |  | 
|  | 16 |  |  |  |  | 1122 |  | 
| 246 | 16 |  |  | 16 |  | 7694 | use IO::File; | 
|  | 16 |  |  |  |  | 134941 |  | 
|  | 16 |  |  |  |  | 2078 |  | 
| 247 | 16 |  |  | 16 |  | 127 | use POSIX qw{ ceil floor fmod modf strftime }; | 
|  | 16 |  |  |  |  | 38 |  | 
|  | 16 |  |  |  |  | 127 |  | 
| 248 | 16 |  |  | 16 |  | 1578 | use Scalar::Util (); | 
|  | 16 |  |  |  |  | 37 |  | 
|  | 16 |  |  |  |  | 1266 |  | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | BEGIN { | 
| 251 | 16 |  |  | 16 |  | 73 | local $@; | 
| 252 | 16 |  |  |  |  | 86 | eval {require Scalar::Util; Scalar::Util->import ('dualvar'); 1} | 
|  | 16 |  |  |  |  | 440 |  | 
|  | 16 |  |  |  |  | 2367 |  | 
| 253 | 16 | 50 |  |  |  | 38 | or *dualvar = sub {$_[0]}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 254 |  |  |  |  |  |  | } | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | {	# Local symbol block. | 
| 257 |  |  |  |  |  |  | my @const = qw{ | 
| 258 |  |  |  |  |  |  | PASS_EVENT_NONE | 
| 259 |  |  |  |  |  |  | PASS_EVENT_SHADOWED | 
| 260 |  |  |  |  |  |  | PASS_EVENT_LIT | 
| 261 |  |  |  |  |  |  | PASS_EVENT_DAY | 
| 262 |  |  |  |  |  |  | PASS_EVENT_RISE | 
| 263 |  |  |  |  |  |  | PASS_EVENT_MAX | 
| 264 |  |  |  |  |  |  | PASS_EVENT_SET | 
| 265 |  |  |  |  |  |  | PASS_EVENT_APPULSE | 
| 266 |  |  |  |  |  |  | PASS_EVENT_START | 
| 267 |  |  |  |  |  |  | PASS_EVENT_END | 
| 268 |  |  |  |  |  |  | PASS_EVENT_BRIGHTEST | 
| 269 |  |  |  |  |  |  | PASS_VARIANT_VISIBLE_EVENTS | 
| 270 |  |  |  |  |  |  | PASS_VARIANT_FAKE_MAX | 
| 271 |  |  |  |  |  |  | PASS_VARIANT_NO_ILLUMINATION | 
| 272 |  |  |  |  |  |  | PASS_VARIANT_START_END | 
| 273 |  |  |  |  |  |  | PASS_VARIANT_BRIGHTEST | 
| 274 |  |  |  |  |  |  | PASS_VARIANT_TRUNCATE | 
| 275 |  |  |  |  |  |  | PASS_VARIANT_NONE | 
| 276 |  |  |  |  |  |  | BODY_TYPE_UNKNOWN | 
| 277 |  |  |  |  |  |  | BODY_TYPE_DEBRIS | 
| 278 |  |  |  |  |  |  | BODY_TYPE_ROCKET_BODY | 
| 279 |  |  |  |  |  |  | BODY_TYPE_PAYLOAD | 
| 280 |  |  |  |  |  |  | }; | 
| 281 |  |  |  |  |  |  | our @EXPORT_OK = @const; | 
| 282 |  |  |  |  |  |  | our %EXPORT_TAGS = ( | 
| 283 |  |  |  |  |  |  | all => \@EXPORT_OK, | 
| 284 |  |  |  |  |  |  | constants => \@const | 
| 285 |  |  |  |  |  |  | ); | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  |  | 
| 288 | 16 |  |  | 16 |  | 125 | use constant RE_ALL_DIGITS	=> qr{ \A [0-9]+ \z }smx; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 1410 |  | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | # The following constants are from section 12 (Users Guide, Constants, | 
| 291 |  |  |  |  |  |  | # and Symbols) of SpaceTrack Report No. 3, Models for Propagation of | 
| 292 |  |  |  |  |  |  | # NORAD Element Sets by Felix R. Hoots and Ronald L. Roehrich, December | 
| 293 |  |  |  |  |  |  | # 1980, compiled by T. S. Kelso 31 December 1988. The FORTRAN variables | 
| 294 |  |  |  |  |  |  | # in the original are defined without the "SGP_" prefix. Were there | 
| 295 |  |  |  |  |  |  | # are duplicates (with one commented out), the commented-out version is | 
| 296 |  |  |  |  |  |  | # the one in the NORAD report, and the replacement has greater | 
| 297 |  |  |  |  |  |  | # precision. If there are two commented out, the second was a greater | 
| 298 |  |  |  |  |  |  | # precision constant, and the third is (ultimately) calculated based | 
| 299 |  |  |  |  |  |  | # on pi = atan2 (0, -1). | 
| 300 |  |  |  |  |  |  |  | 
| 301 | 16 |  |  | 16 |  | 104 | use constant SGP_CK2 => 5.413080E-4; | 
|  | 16 |  |  |  |  | 53 |  | 
|  | 16 |  |  |  |  | 933 |  | 
| 302 | 16 |  |  | 16 |  | 105 | use constant SGP_CK4 => .62098875E-6; | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 926 |  | 
| 303 | 16 |  |  | 16 |  | 97 | use constant SGP_E6A => 1.0E-6; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 900 |  | 
| 304 | 16 |  |  | 16 |  | 97 | use constant SGP_QOMS2T => 1.88027916E-9; | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 889 |  | 
| 305 | 16 |  |  | 16 |  | 96 | use constant SGP_S => 1.01222928; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 997 |  | 
| 306 |  |  |  |  |  |  | ## use constant SGP_TOTHRD => .66666667; | 
| 307 | 16 |  |  | 16 |  | 117 | use constant SGP_TOTHRD => 2 / 3; | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 855 |  | 
| 308 | 16 |  |  | 16 |  | 105 | use constant SGP_XJ3 => -.253881E-5; | 
|  | 16 |  |  |  |  | 34 |  | 
|  | 16 |  |  |  |  | 874 |  | 
| 309 | 16 |  |  | 16 |  | 103 | use constant SGP_XKE => .743669161E-1; | 
|  | 16 |  |  |  |  | 34 |  | 
|  | 16 |  |  |  |  | 863 |  | 
| 310 | 16 |  |  | 16 |  | 96 | use constant SGP_XKMPER => 6378.135;	# Earth radius, KM. | 
|  | 16 |  |  |  |  | 31 |  | 
|  | 16 |  |  |  |  | 780 |  | 
| 311 | 16 |  |  | 16 |  | 97 | use constant SGP_XMNPDA => 1440.0;	# Time units per day. | 
|  | 16 |  |  |  |  | 29 |  | 
|  | 16 |  |  |  |  | 878 |  | 
| 312 | 16 |  |  | 16 |  | 105 | use constant SGP_XSCPMN => 60;		# Seconds per time unit. | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 872 |  | 
| 313 | 16 |  |  | 16 |  | 97 | use constant SGP_AE => 1.0;		# Distance units / earth radii. | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 854 |  | 
| 314 |  |  |  |  |  |  | ## use constant SGP_DE2RA => .174532925E-1;	# radians/degree. | 
| 315 |  |  |  |  |  |  | ## use constant SGP_DE2RA => 0.0174532925199433;	# radians/degree. | 
| 316 | 16 |  |  | 16 |  | 98 | use constant SGP_DE2RA => PI / 180;		# radians/degree. | 
|  | 16 |  |  |  |  | 35 |  | 
|  | 16 |  |  |  |  | 875 |  | 
| 317 |  |  |  |  |  |  | ## use constant SGP_PI => 3.14159265;	# Pi. | 
| 318 |  |  |  |  |  |  | ## use constant SGP_PI => 3.14159265358979;	# Pi. | 
| 319 | 16 |  |  | 16 |  | 98 | use constant SGP_PI => PI;			# Pi. | 
|  | 16 |  |  |  |  | 60 |  | 
|  | 16 |  |  |  |  | 788 |  | 
| 320 |  |  |  |  |  |  | ## use constant SGP_PIO2 => 1.57079633;	# Pi/2. | 
| 321 |  |  |  |  |  |  | ## use constant SGP_PIO2 => 1.5707963267949;	# Pi/2. | 
| 322 | 16 |  |  | 16 |  | 98 | use constant SGP_PIO2 => PIOVER2;		# Pi/2. | 
|  | 16 |  |  |  |  | 37 |  | 
|  | 16 |  |  |  |  | 837 |  | 
| 323 |  |  |  |  |  |  | ## use constant SGP_TWOPI => 6.2831853;	# 2 * Pi. | 
| 324 |  |  |  |  |  |  | ## use constant SGP_TWOPI => 6.28318530717959;	# 2 * Pi. | 
| 325 | 16 |  |  | 16 |  | 97 | use constant SGP_TWOPI => TWOPI;		# 2 * Pi. | 
|  | 16 |  |  |  |  | 31 |  | 
|  | 16 |  |  |  |  | 919 |  | 
| 326 |  |  |  |  |  |  | ## use constant SGP_X3PIO2 => 4.71238898;	# 3 * Pi / 2. | 
| 327 |  |  |  |  |  |  | ## use constant SGP_X3PIO2 => 4.71238898038469;	# 3 * Pi / 2. | 
| 328 | 16 |  |  | 16 |  | 105 | use constant SGP_X3PIO2 => 3 * PIOVER2; | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 758 |  | 
| 329 |  |  |  |  |  |  |  | 
| 330 | 16 |  |  | 16 |  | 87 | use constant SGP_RHO => .15696615; | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 14019 |  | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | # FORTRAN variable glossary, read from same source, and stated in | 
| 333 |  |  |  |  |  |  | # terms of the output produced by the parse method. | 
| 334 |  |  |  |  |  |  | # | 
| 335 |  |  |  |  |  |  | # EPOCH => epoch | 
| 336 |  |  |  |  |  |  | # XNDT20 => firstderivative | 
| 337 |  |  |  |  |  |  | # XNDD60 => secondderivative | 
| 338 |  |  |  |  |  |  | # BSTAR => bstardrag | 
| 339 |  |  |  |  |  |  | # XINCL => inclination | 
| 340 |  |  |  |  |  |  | # XNODE0 => ascendingnode | 
| 341 |  |  |  |  |  |  | # E0 => eccentricity | 
| 342 |  |  |  |  |  |  | # OMEGA0 => argumentofperigee | 
| 343 |  |  |  |  |  |  | # XM0 => meananomaly | 
| 344 |  |  |  |  |  |  | # XNO => meanmotion | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | #	List all the legitimate attributes for the purposes of the | 
| 347 |  |  |  |  |  |  | #	get and set methods. Possible values of the hash are: | 
| 348 |  |  |  |  |  |  | #	    undef => read-only attribute | 
| 349 |  |  |  |  |  |  | #	    0 => no model re-initializing necessary | 
| 350 |  |  |  |  |  |  | #	    1 => at least one model needs re-initializing | 
| 351 |  |  |  |  |  |  | #	    code reference - the reference is called with the | 
| 352 |  |  |  |  |  |  | #		object unmodified, with the arguments | 
| 353 |  |  |  |  |  |  | #		being the object, the name of the attribute, | 
| 354 |  |  |  |  |  |  | #		and the new value of the attribute. The code | 
| 355 |  |  |  |  |  |  | #		must make the needed changes to the attribute, and | 
| 356 |  |  |  |  |  |  | #		return 0 or 1, interpreted as above. | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | my %attrib = ( | 
| 359 |  |  |  |  |  |  | backdate => 0, | 
| 360 |  |  |  |  |  |  | effective => sub { | 
| 361 |  |  |  |  |  |  | my ($self, $name, $value) = @_; | 
| 362 |  |  |  |  |  |  | if ( defined $value && ! looks_like_number( $value ) ) { | 
| 363 |  |  |  |  |  |  | if ( $value =~ m{ \A ([0-9]+) / ([0-9]+) / ([0-9]+) : ([0-9]+) : | 
| 364 |  |  |  |  |  |  | ([0-9]+ (?: [.] [0-9]* )? ) \z }smx ) { | 
| 365 |  |  |  |  |  |  | $value = greg_time_gm( 0, 0, 0, 1, 0, | 
| 366 |  |  |  |  |  |  | __tle_year_to_Gregorian_year( $1 + 0 ) ) + ( | 
| 367 |  |  |  |  |  |  | (($2 - 1) * 24 + $3) * 60 + $4) * 60 + $5; | 
| 368 |  |  |  |  |  |  | } else { | 
| 369 |  |  |  |  |  |  | carp "Invalid effective date '$value'"; | 
| 370 |  |  |  |  |  |  | $value = undef; | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  | $self->{$name} = $value; | 
| 374 |  |  |  |  |  |  | return 0; | 
| 375 |  |  |  |  |  |  | }, | 
| 376 |  |  |  |  |  |  | classification => 0, | 
| 377 |  |  |  |  |  |  | international => \&_set_intldes, | 
| 378 |  |  |  |  |  |  | epoch => sub { | 
| 379 |  |  |  |  |  |  | $_[0]{$_[1]} = $_[2]; | 
| 380 |  |  |  |  |  |  | $_[0]{ds50} = $_[0]->ds50 (); | 
| 381 |  |  |  |  |  |  | $_[0]{epoch_dynamical} = $_[2] + dynamical_delta ($_[2]); | 
| 382 |  |  |  |  |  |  | return 1; | 
| 383 |  |  |  |  |  |  | }, | 
| 384 |  |  |  |  |  |  | firstderivative => 1, | 
| 385 |  |  |  |  |  |  | gravconst_r => sub { | 
| 386 |  |  |  |  |  |  | ($_[2] == 72 || $_[2] == 721 || $_[2] == 84) | 
| 387 |  |  |  |  |  |  | or croak "Error - Illegal gravconst_r; must be 72, 721, or 84"; | 
| 388 |  |  |  |  |  |  | $_[0]{$_[1]} = $_[2]; | 
| 389 |  |  |  |  |  |  | return 1;		# sgp4r needs reinit if this changes. | 
| 390 |  |  |  |  |  |  | }, | 
| 391 |  |  |  |  |  |  | secondderivative => 1, | 
| 392 |  |  |  |  |  |  | bstardrag => 1, | 
| 393 |  |  |  |  |  |  | ephemeristype => 0, | 
| 394 |  |  |  |  |  |  | elementnumber => 0, | 
| 395 |  |  |  |  |  |  | inclination => 1, | 
| 396 |  |  |  |  |  |  | model => sub { | 
| 397 |  |  |  |  |  |  | $_[0]->is_valid_model ($_[2]) || croak < | 
| 398 |  |  |  |  |  |  | Error - Illegal model name '$_[2]'. | 
| 399 |  |  |  |  |  |  | eod | 
| 400 |  |  |  |  |  |  | $_[0]{$_[1]} = $_[2]; | 
| 401 |  |  |  |  |  |  | return 0; | 
| 402 |  |  |  |  |  |  | }, | 
| 403 |  |  |  |  |  |  | model_error => 0, | 
| 404 |  |  |  |  |  |  | ascendingnode => 1, | 
| 405 |  |  |  |  |  |  | eccentricity => 1, | 
| 406 |  |  |  |  |  |  | argumentofperigee => 1, | 
| 407 |  |  |  |  |  |  | meananomaly => 1, | 
| 408 |  |  |  |  |  |  | meanmotion => 1, | 
| 409 |  |  |  |  |  |  | revolutionsatepoch => 0, | 
| 410 |  |  |  |  |  |  | debug => 0, | 
| 411 |  |  |  |  |  |  | geometric => 0,	# Use geometric horizon for pass rise/set. | 
| 412 |  |  |  |  |  |  | visible => 0,	# Pass() reports only illuminated passes. | 
| 413 |  |  |  |  |  |  | appulse => 0,	# Maximum appulse to report. | 
| 414 |  |  |  |  |  |  | interval => 0,	# Interval for pass() positions, if positive. | 
| 415 |  |  |  |  |  |  | lazy_pass_position => 0,	# Position optional if true. | 
| 416 |  |  |  |  |  |  | pass_variant => sub { | 
| 417 |  |  |  |  |  |  | my ( $self, $name, $val ) = @_; | 
| 418 |  |  |  |  |  |  | $val =~ RE_ALL_DIGITS | 
| 419 |  |  |  |  |  |  | or croak 'The pass_variant attribute must be an unsigned number'; | 
| 420 |  |  |  |  |  |  | $self->{$name} = $val; | 
| 421 |  |  |  |  |  |  | return 0; | 
| 422 |  |  |  |  |  |  | }, | 
| 423 |  |  |  |  |  |  | ds50 => undef,	# Read-only | 
| 424 |  |  |  |  |  |  | epoch_dynamical => undef,	# Read-only | 
| 425 |  |  |  |  |  |  | rcs => 0,		# Radar cross-section | 
| 426 |  |  |  |  |  |  | tle => undef,	# Read-only | 
| 427 |  |  |  |  |  |  | file	=> \&_set_optional_unsigned_integer_no_reinit, | 
| 428 |  |  |  |  |  |  | illum	=> \&_set_illum, | 
| 429 |  |  |  |  |  |  | launch_year => \&_set_intldes_part, | 
| 430 |  |  |  |  |  |  | launch_num	=> \&_set_intldes_part, | 
| 431 |  |  |  |  |  |  | launch_piece	=> \&_set_intldes_part, | 
| 432 |  |  |  |  |  |  | object_type	=> \&_set_object_type, | 
| 433 |  |  |  |  |  |  | ordinal	=> \&_set_optional_unsigned_integer_no_reinit, | 
| 434 |  |  |  |  |  |  | originator	=> 0, | 
| 435 |  |  |  |  |  |  | pass_threshold => sub { | 
| 436 |  |  |  |  |  |  | my ($self, $name, $value) = @_; | 
| 437 |  |  |  |  |  |  | not defined $value | 
| 438 |  |  |  |  |  |  | or looks_like_number( $value ) | 
| 439 |  |  |  |  |  |  | or carp "Invalid $name '$value'"; | 
| 440 |  |  |  |  |  |  | $self->{$name} = $value; | 
| 441 |  |  |  |  |  |  | return 0; | 
| 442 |  |  |  |  |  |  | }, | 
| 443 |  |  |  |  |  |  | reblessable => sub { | 
| 444 |  |  |  |  |  |  | my $doit = !$_[0]{$_[1]} && $_[2] && $_[0]->get ('id'); | 
| 445 |  |  |  |  |  |  | $_[0]{$_[1]} = $_[2]; | 
| 446 |  |  |  |  |  |  | $doit and $_[0]->rebless (); | 
| 447 |  |  |  |  |  |  | return 0; | 
| 448 |  |  |  |  |  |  | }, | 
| 449 |  |  |  |  |  |  | intrinsic_magnitude	=> \&_set_optional_float_no_reinit, | 
| 450 |  |  |  |  |  |  | ); | 
| 451 |  |  |  |  |  |  | my %static = ( | 
| 452 |  |  |  |  |  |  | appulse => deg2rad (10),	# Report appulses < 10 degrees. | 
| 453 |  |  |  |  |  |  | backdate => 1,	# Use object in pass before its epoch. | 
| 454 |  |  |  |  |  |  | geometric => 0,	# Use geometric horizon for pass rise/set. | 
| 455 |  |  |  |  |  |  | gravconst_r => 72,	# Specify geodetic data set for sgp4r. | 
| 456 |  |  |  |  |  |  | illum => 'sun', | 
| 457 |  |  |  |  |  |  | interval => 0, | 
| 458 |  |  |  |  |  |  | lazy_pass_position => 0, | 
| 459 |  |  |  |  |  |  | model => 'model', | 
| 460 |  |  |  |  |  |  | pass_variant => 0, | 
| 461 |  |  |  |  |  |  | reblessable => 1, | 
| 462 |  |  |  |  |  |  | visible => 1, | 
| 463 |  |  |  |  |  |  | ); | 
| 464 |  |  |  |  |  |  | my %model_attrib = (	# For the benefit of is_model_attribute() | 
| 465 |  |  |  |  |  |  | ds50 => 1,		# Read-only, but it fits the definition. | 
| 466 |  |  |  |  |  |  | epoch => 1,		# Hand-set, since we dont want to call the code. | 
| 467 |  |  |  |  |  |  | epoch_dynamical => 1,	# Read-only, but fits the definition. | 
| 468 |  |  |  |  |  |  | ); | 
| 469 |  |  |  |  |  |  | foreach (keys %attrib) { | 
| 470 |  |  |  |  |  |  | $model_attrib{$_} = 1 if $attrib{$_} && !ref $attrib{$_} | 
| 471 |  |  |  |  |  |  | } | 
| 472 |  |  |  |  |  |  | my %status;	# Subclassing data - initialized at end | 
| 473 |  |  |  |  |  |  | my %magnitude_table;	# Magnitude data - initialized at end | 
| 474 |  |  |  |  |  |  | my $magnitude_adjust = 0;	# Adjustment to magnitude table value | 
| 475 |  |  |  |  |  |  |  | 
| 476 | 16 |  |  | 16 |  | 137 | use constant TLE_INIT => '_init'; | 
|  | 16 |  |  |  |  | 51 |  | 
|  | 16 |  |  |  |  | 6639 |  | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | =item $tle = Astro::Coord::ECI::TLE->new() | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | This method instantiates an object to represent a NORAD two- or | 
| 481 |  |  |  |  |  |  | three-line orbital element set. This is a subclass of | 
| 482 |  |  |  |  |  |  | L. | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | Any arguments get passed to the set() method. | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | It is both anticipated and recommended that you use the parse() | 
| 487 |  |  |  |  |  |  | method instead of this method to create an object, since the models | 
| 488 |  |  |  |  |  |  | currently have no code to guard against incomplete data. | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | =cut | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | sub new { | 
| 493 | 64 |  |  | 64 | 1 | 1619 | my $class = shift; | 
| 494 | 64 |  |  |  |  | 436 | my $self = $class->SUPER::new (%static, @_); | 
| 495 | 64 |  |  |  |  | 212 | return $self; | 
| 496 |  |  |  |  |  |  | } | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | =item $tle->after_reblessing (\%possible_attributes) | 
| 499 |  |  |  |  |  |  |  | 
| 500 |  |  |  |  |  |  | This method supports reblessing into a subclass, with the argument | 
| 501 |  |  |  |  |  |  | representing attributes that the subclass may wish to set.  It is called | 
| 502 |  |  |  |  |  |  | by rebless() and should not be called by the user. | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | At this level it does nothing. | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | =cut | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  | 87 | 1 |  | sub after_reblessing {} | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | =item Astro::Coord::ECI::TLE->alias (name => class ...) | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | This static method adds an alias for a class name, for the benefit of | 
| 513 |  |  |  |  |  |  | users of the status() method and 'illum' attributes, and ultimately of | 
| 514 |  |  |  |  |  |  | the rebless() method. It is intended to be used by subclasses to | 
| 515 |  |  |  |  |  |  | register short names for themselves upon initialization, though of | 
| 516 |  |  |  |  |  |  | course you can call it yourself as well. | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | For example, this class calls | 
| 519 |  |  |  |  |  |  |  | 
| 520 |  |  |  |  |  |  | __PACKAGE__->alias (tle => __PACKAGE__); | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | You can register more than one alias in a single call. Aliases | 
| 523 |  |  |  |  |  |  | can be deleted by assigning them a false value (e.g. '' or undef). | 
| 524 |  |  |  |  |  |  |  | 
| 525 |  |  |  |  |  |  | If called without arguments, it returns the current aliases. | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | You can actually call this as a normal method, but it still behaves | 
| 528 |  |  |  |  |  |  | like a static method. | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  | =cut | 
| 531 |  |  |  |  |  |  |  | 
| 532 |  |  |  |  |  |  | my %type_map = (); | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | sub alias { | 
| 535 | 48 |  |  | 48 | 1 | 164 | my ($self, @args) = @_; | 
| 536 | 48 | 50 |  |  |  | 180 | @args % 2 and croak < | 
| 537 |  |  |  |  |  |  | Error - Must have even number of arguments for alias(). | 
| 538 |  |  |  |  |  |  | eod | 
| 539 | 48 | 0 |  |  |  | 161 | return wantarray ? %type_map : {%type_map} unless @args; | 
|  |  | 50 |  |  |  |  |  | 
| 540 | 48 |  |  |  |  | 136 | while (@args) { | 
| 541 | 48 |  |  |  |  | 100 | my $name = shift @args; | 
| 542 | 48 | 50 |  |  |  | 133 | my $class = shift @args or do { | 
| 543 | 0 |  |  |  |  | 0 | delete $type_map{$name}; | 
| 544 | 0 |  |  |  |  | 0 | next; | 
| 545 |  |  |  |  |  |  | }; | 
| 546 | 48 | 50 |  |  |  | 146 | $class = $type_map{$class} if $type_map{$class}; | 
| 547 | 48 |  |  |  |  | 211 | load_module ($class); | 
| 548 | 48 |  |  |  |  | 216 | $type_map{$name} = $class; | 
| 549 |  |  |  |  |  |  | } | 
| 550 | 48 |  |  |  |  | 114 | return $self; | 
| 551 |  |  |  |  |  |  | } | 
| 552 |  |  |  |  |  |  | __PACKAGE__->alias (tle => __PACKAGE__); | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | =item $kilometers = $tle->apoapsis(); | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | This method returns the apoapsis of the orbit, in kilometers. Since | 
| 557 |  |  |  |  |  |  | Astro::Coord::ECI::TLE objects always represent bodies orbiting the | 
| 558 |  |  |  |  |  |  | Earth, this is more usually called apogee. | 
| 559 |  |  |  |  |  |  |  | 
| 560 |  |  |  |  |  |  | Note that this is the distance from the center of the Earth, not the | 
| 561 |  |  |  |  |  |  | altitude. | 
| 562 |  |  |  |  |  |  |  | 
| 563 |  |  |  |  |  |  | =cut | 
| 564 |  |  |  |  |  |  |  | 
| 565 |  |  |  |  |  |  | sub apoapsis { | 
| 566 | 8 |  |  | 8 | 1 | 41 | my $self = shift; | 
| 567 |  |  |  |  |  |  | return $self->{&TLE_INIT}{TLE_apoapsis} ||= | 
| 568 | 8 |  | 66 |  |  | 65 | (1 + $self->get('eccentricity')) * $self->semimajor(); | 
| 569 |  |  |  |  |  |  | } | 
| 570 |  |  |  |  |  |  |  | 
| 571 |  |  |  |  |  |  | =item $kilometers = $tle->apogee(); | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | This method is simply a synonym for apoapsis(). | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | =cut | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | *apogee = \&apoapsis; | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | #	See Astro::Coord::ECI for docs. | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | sub attribute { | 
| 582 | 0 | 0 |  | 0 | 1 | 0 | return exists $attrib{$_[1]} ? | 
| 583 |  |  |  |  |  |  | __PACKAGE__ : | 
| 584 |  |  |  |  |  |  | $_[0]->SUPER::attribute ($_[1]) | 
| 585 |  |  |  |  |  |  | } | 
| 586 |  |  |  |  |  |  |  | 
| 587 |  |  |  |  |  |  | =item $tle->before_reblessing () | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | This method supports reblessing into a subclass. It is intended to do | 
| 590 |  |  |  |  |  |  | any cleanup the old class needs before reblessing into the new class. It | 
| 591 |  |  |  |  |  |  | is called by rebless(), and should not be called by the user. | 
| 592 |  |  |  |  |  |  |  | 
| 593 |  |  |  |  |  |  | At this level it does nothing. | 
| 594 |  |  |  |  |  |  |  | 
| 595 |  |  |  |  |  |  | =cut | 
| 596 |  |  |  |  |  |  |  | 
| 597 |  |  |  | 87 | 1 |  | sub before_reblessing {} | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | =item $type = $tle->body_type () | 
| 600 |  |  |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | This method returns the type of the body as one of the BODY_TYPE_* | 
| 602 |  |  |  |  |  |  | constants. This is the C<'object_type'> attribute if that is defined. | 
| 603 |  |  |  |  |  |  | Otherwise it is derived from the common name using an algorithm similar | 
| 604 |  |  |  |  |  |  | to the one used by the Space Track web site. This algorithm will not | 
| 605 |  |  |  |  |  |  | work if the common name is not available, or if it does not conform to | 
| 606 |  |  |  |  |  |  | the Space Track naming conventions. Known or suspected differences from | 
| 607 |  |  |  |  |  |  | the algorithm described at the bottom of the Satellite Box Score page | 
| 608 |  |  |  |  |  |  | include: | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | * The C algorithm is not case-sensitive. The | 
| 611 |  |  |  |  |  |  | Space Track algorithm appears to assume all upper-case. | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | * The C algorithm looks for words (that is, | 
| 614 |  |  |  |  |  |  | alphanumeric strings delimited by non-alphanumeric characters), whereas | 
| 615 |  |  |  |  |  |  | the Space Track documentation seems to say it just looks for substrings. | 
| 616 |  |  |  |  |  |  | However, implementing the documented algorithm literally results in OID | 
| 617 |  |  |  |  |  |  | 20479 'DEBUT (ORIZURU)' being classified as debris, whereas Space Track | 
| 618 |  |  |  |  |  |  | returns it in response to a query for name 'deb' that excludes debris. | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  | The possible returns are: | 
| 621 |  |  |  |  |  |  |  | 
| 622 |  |  |  |  |  |  | C<< BODY_TYPE_UNKNOWN => dualvar( 0, 'unknown' ) >> if the value of the | 
| 623 |  |  |  |  |  |  | C attribute is C, or if it is empty or contains only | 
| 624 |  |  |  |  |  |  | white space. | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | C<< BODY_TYPE_DEBRIS => dualvar( 1, 'debris' ) >> if the value of the | 
| 627 |  |  |  |  |  |  | C attribute contains one of the words 'deb', 'debris', 'coolant', | 
| 628 |  |  |  |  |  |  | 'shroud', or 'westford needles', all checks being case-insensitive. | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | C<< BODY_TYPE_ROCKET_BODY => dualvar( 2, 'rocket body' ) >> if the body | 
| 631 |  |  |  |  |  |  | is not debris, but the value of the C attribute contains one of | 
| 632 |  |  |  |  |  |  | the strings 'r/b', 'akm' (for 'apogee kick motor') or 'pkm' (for | 
| 633 |  |  |  |  |  |  | 'perigee kick motor') all checks being case-insensitive. | 
| 634 |  |  |  |  |  |  |  | 
| 635 |  |  |  |  |  |  | C<< BODY_TYPE_PAYLOAD => dualvar( 3, 'payload' ) >> if the body is not | 
| 636 |  |  |  |  |  |  | unknown, debris, or a rocket body. | 
| 637 |  |  |  |  |  |  |  | 
| 638 |  |  |  |  |  |  | The above constants are not exported by default, but they are exportable | 
| 639 |  |  |  |  |  |  | either by name or using the C<:constants> tag. | 
| 640 |  |  |  |  |  |  |  | 
| 641 |  |  |  |  |  |  | If L does not export C, the | 
| 642 |  |  |  |  |  |  | constants are defined to be numeric. The cautious programmer will | 
| 643 |  |  |  |  |  |  | therefore test them using numeric tests. | 
| 644 |  |  |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | =cut | 
| 646 |  |  |  |  |  |  |  | 
| 647 | 16 |  |  | 16 |  | 127 | use constant BODY_TYPE_UNKNOWN => dualvar( 0, 'unknown' ); | 
|  | 16 |  |  |  |  | 72 |  | 
|  | 16 |  |  |  |  | 1112 |  | 
| 648 | 16 |  |  | 16 |  | 108 | use constant BODY_TYPE_DEBRIS => dualvar( 1, 'debris' ); | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 1067 |  | 
| 649 | 16 |  |  | 16 |  | 102 | use constant BODY_TYPE_ROCKET_BODY => dualvar( 2, 'rocket body' ); | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 1026 |  | 
| 650 | 16 |  |  | 16 |  | 114 | use constant BODY_TYPE_PAYLOAD => dualvar( 3, 'payload' ); | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 35695 |  | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | sub body_type { | 
| 653 | 12 |  |  | 12 | 1 | 1532 | my ( $self ) = @_; | 
| 654 | 12 |  |  |  |  | 19 | my $type; | 
| 655 | 12 | 50 |  |  |  | 25 | $type = $self->get( 'object_type' ) | 
| 656 |  |  |  |  |  |  | and return $type; | 
| 657 | 12 | 100 |  |  |  | 27 | defined( my $name = $self->get( 'name' ) ) | 
| 658 |  |  |  |  |  |  | or return BODY_TYPE_UNKNOWN; | 
| 659 | 11 | 50 |  |  |  | 55 | $name =~ m/ \A \s* \z /smx | 
| 660 |  |  |  |  |  |  | and return BODY_TYPE_UNKNOWN; | 
| 661 | 11 | 100 | 100 |  |  | 126 | ( $name =~ m/ \b deb \b /smxi | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 662 |  |  |  |  |  |  | || $name =~ m/ \b debris \b /smxi | 
| 663 |  |  |  |  |  |  | || $name =~ m/ \b coolant \b /smxi | 
| 664 |  |  |  |  |  |  | || $name =~ m/ \b shroud \b /smxi | 
| 665 |  |  |  |  |  |  | || $name =~ m/ \b westford \s+ needles \b /smxi ) | 
| 666 |  |  |  |  |  |  | and return BODY_TYPE_DEBRIS; | 
| 667 | 5 | 100 | 100 |  |  | 37 | ( $name =~ m{ \b r/b \b }smxi | 
| 668 |  |  |  |  |  |  | || $name =~ m/ \b [ap] km \b /smxi ) | 
| 669 |  |  |  |  |  |  | and return BODY_TYPE_ROCKET_BODY; | 
| 670 | 2 |  |  |  |  | 12 | return BODY_TYPE_PAYLOAD; | 
| 671 |  |  |  |  |  |  | } | 
| 672 |  |  |  |  |  |  |  | 
| 673 |  |  |  |  |  |  | =item $tle->can_flare () | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | This method returns true if the object is capable of generating flares | 
| 676 |  |  |  |  |  |  | (i.e. predictable bright flashes) and false otherwise. At this level | 
| 677 |  |  |  |  |  |  | of the inheritance hierarchy, it always returns false, but subclasses | 
| 678 |  |  |  |  |  |  | may return true. | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | =cut | 
| 681 |  |  |  |  |  |  |  | 
| 682 | 0 |  |  | 0 | 1 | 0 | sub can_flare {return 0} | 
| 683 |  |  |  |  |  |  |  | 
| 684 |  |  |  |  |  |  | =item $elevation = $tle->correct_for_refraction( $elevation ) | 
| 685 |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  | This override of the superclass' method simply returns the elevation | 
| 687 |  |  |  |  |  |  | passed to it. Atmospheric refraction at orbital altitudes is going to be | 
| 688 |  |  |  |  |  |  | negligible except B close to the horizon, and I have no | 
| 689 |  |  |  |  |  |  | algorithm for that. | 
| 690 |  |  |  |  |  |  |  | 
| 691 |  |  |  |  |  |  | If I B come up with something to handle refraction close to the | 
| 692 |  |  |  |  |  |  | horizon, though, it will appear here. One would expect the refraction | 
| 693 |  |  |  |  |  |  | right at the limb to be twice that calculated by Thorfinn's algorithm | 
| 694 |  |  |  |  |  |  | (used in the superclass) because the light travels to the Earth's | 
| 695 |  |  |  |  |  |  | surface and back out again. | 
| 696 |  |  |  |  |  |  |  | 
| 697 |  |  |  |  |  |  | See the L C and | 
| 698 |  |  |  |  |  |  | C documentation for whether this class' | 
| 699 |  |  |  |  |  |  | C method is actually called by those methods. | 
| 700 |  |  |  |  |  |  |  | 
| 701 |  |  |  |  |  |  | =cut | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | sub correct_for_refraction { | 
| 704 | 917 |  |  | 917 | 1 | 1879 | my ( undef, $elevation ) = @_;	# Invocant unused | 
| 705 | 917 |  |  |  |  | 1798 | return $elevation; | 
| 706 |  |  |  |  |  |  | } | 
| 707 |  |  |  |  |  |  |  | 
| 708 |  |  |  |  |  |  | =item $value = $tle->ds50($time) | 
| 709 |  |  |  |  |  |  |  | 
| 710 |  |  |  |  |  |  | This method converts the time to days since 1950 Jan 0, 0 h GMT. | 
| 711 |  |  |  |  |  |  | The time defaults to the epoch of the data set. This method does not | 
| 712 |  |  |  |  |  |  | affect the $tle object - it is exposed for convenience and for testing | 
| 713 |  |  |  |  |  |  | purposes. | 
| 714 |  |  |  |  |  |  |  | 
| 715 |  |  |  |  |  |  | It can also be called as a "static" method, i.e. as | 
| 716 |  |  |  |  |  |  | Astro::Coord::ECI::TLE->ds50 ($time), but in this case the time may not | 
| 717 |  |  |  |  |  |  | be defaulted, and no attempt has been made to make this a pretty error. | 
| 718 |  |  |  |  |  |  |  | 
| 719 |  |  |  |  |  |  | =cut | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  | {	# Begin local symbol block | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | #	Because different Perl implementations may have different | 
| 724 |  |  |  |  |  |  | #	epochs, we assume that 2000 Jan 1 0h UT is representable, and | 
| 725 |  |  |  |  |  |  | #	pre-calculate that time in terms of seconds since the epoch. | 
| 726 |  |  |  |  |  |  | #	Then, when the method is called, we convert the argument to | 
| 727 |  |  |  |  |  |  | #	days since Y2K, and then add the magic number needed to get | 
| 728 |  |  |  |  |  |  | #	us to days since 1950 Jan 0 0h UT. | 
| 729 |  |  |  |  |  |  |  | 
| 730 |  |  |  |  |  |  | my $y2k = greg_time_gm( 0, 0, 0, 1, 0, 2000 );	# Calc. time of 2000 Jan 1 0h UT | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | sub ds50 { | 
| 733 | 59 |  |  | 59 | 1 | 215 | my ($self, $epoch) = @_; | 
| 734 | 59 | 50 |  |  |  | 194 | defined $epoch or $epoch = $self->{epoch}; | 
| 735 | 59 |  |  |  |  | 159 | my $rslt = ($epoch - $y2k) / SECSPERDAY + 18263; | 
| 736 | 59 | 50 | 33 |  |  | 297 | (ref $self && $self->{debug}) and print < | 
| 737 |  |  |  |  |  |  | Debug ds50 ($epoch) = $rslt | 
| 738 |  |  |  |  |  |  | eod | 
| 739 | 59 |  |  |  |  | 140 | return $rslt; | 
| 740 |  |  |  |  |  |  | } | 
| 741 |  |  |  |  |  |  | }	# End local symbol block | 
| 742 |  |  |  |  |  |  |  | 
| 743 |  |  |  |  |  |  | =item $value = $tle->get('attribute') | 
| 744 |  |  |  |  |  |  |  | 
| 745 |  |  |  |  |  |  | This method retrieves the value of the given attribute. See the | 
| 746 |  |  |  |  |  |  | L section for a description of the attributes. | 
| 747 |  |  |  |  |  |  |  | 
| 748 |  |  |  |  |  |  | =cut | 
| 749 |  |  |  |  |  |  |  | 
| 750 |  |  |  |  |  |  | { | 
| 751 |  |  |  |  |  |  | my %accessor = ( | 
| 752 |  |  |  |  |  |  | tle => sub {$_[0]{$_[1]} ||= $_[0]->_make_tle()}, | 
| 753 |  |  |  |  |  |  | ); | 
| 754 |  |  |  |  |  |  | sub get { | 
| 755 | 45601 |  |  | 45601 | 1 | 1183304 | my $self = shift; | 
| 756 | 45601 |  |  |  |  | 66821 | my $name = shift; | 
| 757 | 45601 | 50 |  |  |  | 88640 | if (ref $self) { | 
| 758 | 45601 | 100 |  |  |  | 154640 | exists $attrib{$name} or return $self->SUPER::get ($name); | 
| 759 |  |  |  |  |  |  | return $accessor{$name} ? | 
| 760 |  |  |  |  |  |  | $accessor{$name}->($self, $name) : | 
| 761 | 4697 | 100 |  |  |  | 16910 | $self->{$name}; | 
| 762 |  |  |  |  |  |  | } else { | 
| 763 | 0 | 0 |  |  |  | 0 | exists $static{$name} or | 
| 764 |  |  |  |  |  |  | return $self->SUPER::get ($name); | 
| 765 | 0 |  |  |  |  | 0 | return $static{$name}; | 
| 766 |  |  |  |  |  |  | } | 
| 767 |  |  |  |  |  |  | } | 
| 768 |  |  |  |  |  |  | } | 
| 769 |  |  |  |  |  |  |  | 
| 770 |  |  |  |  |  |  | =item $illuminated = $tle->illuminated(); | 
| 771 |  |  |  |  |  |  |  | 
| 772 |  |  |  |  |  |  | This method returns a true value if the body is illuminated, and a false | 
| 773 |  |  |  |  |  |  | value if it is not. | 
| 774 |  |  |  |  |  |  |  | 
| 775 |  |  |  |  |  |  | =cut | 
| 776 |  |  |  |  |  |  |  | 
| 777 |  |  |  |  |  |  | sub illuminated { | 
| 778 | 502 |  |  | 502 | 1 | 981 | my ( $self, $time ) = @_; | 
| 779 | 502 |  |  |  |  | 1523 | return $self->__sun_elev_from_sat( $time ) >= 0; | 
| 780 |  |  |  |  |  |  | } | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | =item @events = $tle->intrinsic_events( $start, $end ); | 
| 783 |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  | This method returns any events that are intrinsic to the C<$tle> object. | 
| 785 |  |  |  |  |  |  | If optional argument C<$start> is defined, only events occurring at or | 
| 786 |  |  |  |  |  |  | after that Perl time are returned. Similarly, if optional argument | 
| 787 |  |  |  |  |  |  | C<$end> is defined, only events occurring before that Perl time are | 
| 788 |  |  |  |  |  |  | returned. | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | The return is an array of array references. Each array reference | 
| 791 |  |  |  |  |  |  | specifies the Perl time of the event and a text description of the | 
| 792 |  |  |  |  |  |  | event. | 
| 793 |  |  |  |  |  |  |  | 
| 794 |  |  |  |  |  |  | At this level of the object hierarchy nothing is returned. Subclasses | 
| 795 |  |  |  |  |  |  | may override this to add C events. The overrides should return | 
| 796 |  |  |  |  |  |  | anything returned by C in addition to | 
| 797 |  |  |  |  |  |  | anything they return themselves. | 
| 798 |  |  |  |  |  |  |  | 
| 799 |  |  |  |  |  |  | The order of the returned events is undefined. | 
| 800 |  |  |  |  |  |  |  | 
| 801 |  |  |  |  |  |  | =cut | 
| 802 |  |  |  |  |  |  |  | 
| 803 |  |  |  |  |  |  | sub intrinsic_events { | 
| 804 | 47 |  |  | 47 | 1 | 138 | return; | 
| 805 |  |  |  |  |  |  | } | 
| 806 |  |  |  |  |  |  |  | 
| 807 |  |  |  |  |  |  | =item $deep = $tle->is_deep(); | 
| 808 |  |  |  |  |  |  |  | 
| 809 |  |  |  |  |  |  | This method returns true if the object is in deep space - meaning that | 
| 810 |  |  |  |  |  |  | its period is at least 225 minutes (= 13500 seconds). | 
| 811 |  |  |  |  |  |  |  | 
| 812 |  |  |  |  |  |  | =cut | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | sub is_deep { | 
| 815 |  |  |  |  |  |  | return $_[0]->{&TLE_INIT}{TLE_isdeep} | 
| 816 | 10 | 100 |  | 10 | 1 | 69 | if exists $_[0]->{&TLE_INIT}{TLE_isdeep}; | 
| 817 | 4 |  |  |  |  | 14 | return ($_[0]->{&TLE_INIT}{TLE_isdeep} = $_[0]->period () >= 13500); | 
| 818 |  |  |  |  |  |  | } | 
| 819 |  |  |  |  |  |  |  | 
| 820 |  |  |  |  |  |  | =item $boolean = $tle->is_model_attribute ($name); | 
| 821 |  |  |  |  |  |  |  | 
| 822 |  |  |  |  |  |  | This method returns true if the named attribute is an attribute of | 
| 823 |  |  |  |  |  |  | the model - i.e. it came from the TLE data and actually affects the | 
| 824 |  |  |  |  |  |  | model computations. It is really for the benefit of | 
| 825 |  |  |  |  |  |  | Astro::Coord::ECI::TLE::Set, so that class can determine how its | 
| 826 |  |  |  |  |  |  | set() method should handle the attribute. | 
| 827 |  |  |  |  |  |  |  | 
| 828 |  |  |  |  |  |  | =cut | 
| 829 |  |  |  |  |  |  |  | 
| 830 | 1 |  |  | 1 | 1 | 6 | sub is_model_attribute { return $model_attrib{$_[1]} } | 
| 831 |  |  |  |  |  |  |  | 
| 832 |  |  |  |  |  |  | =item $boolean = $tle->is_valid_model ($model_name); | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  | This method returns true if the given name is the name of an orbital | 
| 835 |  |  |  |  |  |  | model, and false otherwise. | 
| 836 |  |  |  |  |  |  |  | 
| 837 |  |  |  |  |  |  | Actually, in the spirit of UNIVERSAL::can, it returns a reference to | 
| 838 |  |  |  |  |  |  | the code if the model exists, and undef otherwise. | 
| 839 |  |  |  |  |  |  |  | 
| 840 |  |  |  |  |  |  | This is really for the benefit of Astro::Coord::ECI::TLE::Set, so it | 
| 841 |  |  |  |  |  |  | knows it needs to select the correct member object before running the | 
| 842 |  |  |  |  |  |  | model. | 
| 843 |  |  |  |  |  |  |  | 
| 844 |  |  |  |  |  |  | This method can be called as a static method, or even as a subroutine. | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  | =cut | 
| 847 |  |  |  |  |  |  |  | 
| 848 |  |  |  |  |  |  | {	# Begin local symbol block | 
| 849 |  |  |  |  |  |  |  | 
| 850 |  |  |  |  |  |  | my %valid = map {$_ => __PACKAGE__->can ($_)} | 
| 851 |  |  |  |  |  |  | qw{model model4 model4r model8 null sdp4 sdp8 sgp sgp4 sgp4r sgp8}; | 
| 852 |  |  |  |  |  |  |  | 
| 853 |  |  |  |  |  |  | #>>>	NOTE WELL | 
| 854 |  |  |  |  |  |  | #>>>	If a model is added, the period method must change | 
| 855 |  |  |  |  |  |  | #>>>	as well, to calculate using the new model. I really | 
| 856 |  |  |  |  |  |  | #>>>	ought to do all this with code attributes. | 
| 857 |  |  |  |  |  |  |  | 
| 858 |  |  |  |  |  |  | sub is_valid_model { | 
| 859 | 128 |  |  | 128 | 1 | 349 | return $valid{$_[1]} | 
| 860 |  |  |  |  |  |  | } | 
| 861 |  |  |  |  |  |  |  | 
| 862 |  |  |  |  |  |  | }	# End local symbol block | 
| 863 |  |  |  |  |  |  |  | 
| 864 |  |  |  |  |  |  | =item $mag = $tle->magnitude( $station ); | 
| 865 |  |  |  |  |  |  |  | 
| 866 |  |  |  |  |  |  | This method returns the magnitude of the body as seen from the given | 
| 867 |  |  |  |  |  |  | station. If no C<$station> is specified, the object's C<'station'> | 
| 868 |  |  |  |  |  |  | attribute is used. If that is not set, and exception is thrown. | 
| 869 |  |  |  |  |  |  |  | 
| 870 |  |  |  |  |  |  | This is calculated from the C<'intrinsic_magnitude'> attribute, the | 
| 871 |  |  |  |  |  |  | distance from the station to the satellite, and the fraction of the | 
| 872 |  |  |  |  |  |  | satellite illuminated. The formula is from Mike McCants. | 
| 873 |  |  |  |  |  |  |  | 
| 874 |  |  |  |  |  |  | We return C if the C<'intrinsic_magnitude'> or C<'illum'> | 
| 875 |  |  |  |  |  |  | attributes are C, or if the illuminating body is below the | 
| 876 |  |  |  |  |  |  | horizon as seen from the satellite. | 
| 877 |  |  |  |  |  |  |  | 
| 878 |  |  |  |  |  |  | After this method returns the time set in the station attribute should | 
| 879 |  |  |  |  |  |  | be considered undefined. In fact, it will be set to the same time as the | 
| 880 |  |  |  |  |  |  | invocant if a defined magnitude was returned. But if C was | 
| 881 |  |  |  |  |  |  | returned, the station's time may not have been changed. | 
| 882 |  |  |  |  |  |  |  | 
| 883 |  |  |  |  |  |  | Some very desultory investigation of International Space Station | 
| 884 |  |  |  |  |  |  | magnitude predictions suggests that this method produces magnitude | 
| 885 |  |  |  |  |  |  | estimates about half a magnitude less bright than Heavens Above. | 
| 886 |  |  |  |  |  |  |  | 
| 887 |  |  |  |  |  |  | =cut | 
| 888 |  |  |  |  |  |  |  | 
| 889 |  |  |  |  |  |  | sub magnitude { | 
| 890 | 1 |  |  | 1 | 1 | 6 | my ( $self, $sta ) = __default_station( @_ ); | 
| 891 |  |  |  |  |  |  |  | 
| 892 |  |  |  |  |  |  | # If we have no standard magnitude, just return undef. | 
| 893 | 1 | 50 |  |  |  | 4 | defined( my $std_mag = $self->get( 'intrinsic_magnitude' ) ) | 
| 894 |  |  |  |  |  |  | or return undef;	## no critic (ProhibitExplicitReturnUndef) | 
| 895 |  |  |  |  |  |  |  | 
| 896 |  |  |  |  |  |  | # If we have no illuminating body for some reason, we also have to | 
| 897 |  |  |  |  |  |  | # just return undef. | 
| 898 | 1 | 50 |  |  |  | 4 | my $illum = $self->get( 'illum' ) | 
| 899 |  |  |  |  |  |  | or return undef;	## no critic (ProhibitExplicitReturnUndef) | 
| 900 |  |  |  |  |  |  |  | 
| 901 |  |  |  |  |  |  | # Pick up the time. | 
| 902 | 1 |  |  |  |  | 4 | my $time = $self->universal(); | 
| 903 |  |  |  |  |  |  |  | 
| 904 |  |  |  |  |  |  | # If the illuminating body is below the horizon, we return undef. | 
| 905 | 1 | 50 |  |  |  | 5 | $self->illuminated() | 
| 906 |  |  |  |  |  |  | or return undef;	## no critic (ProhibitExplicitReturnUndef) | 
| 907 |  |  |  |  |  |  |  | 
| 908 |  |  |  |  |  |  | # Compute the range amd the elevation. | 
| 909 | 1 |  |  |  |  | 6 | my ( undef, $elev, $range ) = $sta->universal( $time )->azel( $self ); | 
| 910 |  |  |  |  |  |  |  | 
| 911 |  |  |  |  |  |  | # If the satellite is below the horizon, just return undef | 
| 912 | 1 | 50 |  |  |  | 6 | $elev < 0 | 
| 913 |  |  |  |  |  |  | and return undef;	## no critic (ProhibitExplicitReturnUndef) | 
| 914 |  |  |  |  |  |  |  | 
| 915 |  |  |  |  |  |  | # Adjust the magnitude if the illuminating body is not the Sun. | 
| 916 | 1 | 50 |  |  |  | 6 | my $mag_adj = $illum->isa( 'Astro::Coord::ECI::Sun' ) ? 0 : | 
| 917 |  |  |  |  |  |  | $illum->magnitude() - Astro::Coord::ECI::Sun->MEAN_MAGNITUDE(); | 
| 918 |  |  |  |  |  |  |  | 
| 919 |  |  |  |  |  |  | # Compute the fraction of the satellite illuminated. | 
| 920 | 1 |  |  |  |  | 11 | my $frac_illum = ( 1 + cos( $self->angle( $illum, $sta ) ) ) / 2; | 
| 921 |  |  |  |  |  |  |  | 
| 922 |  |  |  |  |  |  | # Finally we get to McCants' algorithm | 
| 923 | 1 |  |  |  |  | 8 | return $std_mag + $mag_adj - 15.75 + | 
| 924 |  |  |  |  |  |  | 2.5 * log( $range ** 2 / $frac_illum ) / log( 10 ); | 
| 925 |  |  |  |  |  |  |  | 
| 926 |  |  |  |  |  |  | } | 
| 927 |  |  |  |  |  |  |  | 
| 928 |  |  |  |  |  |  | =item Astro::Coord::ECI::TLE->magnitude_table( command => arguments ...) | 
| 929 |  |  |  |  |  |  |  | 
| 930 |  |  |  |  |  |  | This method maintains the internal magnitude table, which is used by the | 
| 931 |  |  |  |  |  |  | parse() method to fill in magnitudes, since they are not normally | 
| 932 |  |  |  |  |  |  | available from the usual sources.  The first argument determines what is | 
| 933 |  |  |  |  |  |  | done to the status table; subsequent arguments depend on the first | 
| 934 |  |  |  |  |  |  | argument. Valid commands and arguments are: | 
| 935 |  |  |  |  |  |  |  | 
| 936 |  |  |  |  |  |  | C $id, $mag )> adds a magnitude entry to the | 
| 937 |  |  |  |  |  |  | table, replacing the existing entry for the given OID if any. | 
| 938 |  |  |  |  |  |  |  | 
| 939 |  |  |  |  |  |  | C $adjustment )> maintains a magnitude | 
| 940 |  |  |  |  |  |  | adjustment to be added to the value in the magnitude table before | 
| 941 |  |  |  |  |  |  | setting the C of an object. If the argument is | 
| 942 |  |  |  |  |  |  | C the current adjustment is returned; otherwise the argument | 
| 943 |  |  |  |  |  |  | becomes the new adjustment. Actual magnitude table entries are not | 
| 944 |  |  |  |  |  |  | modified by this operation; the adjustment is done in the C | 
| 945 |  |  |  |  |  |  | method. | 
| 946 |  |  |  |  |  |  |  | 
| 947 |  |  |  |  |  |  | C clears the magnitude table. | 
| 948 |  |  |  |  |  |  |  | 
| 949 |  |  |  |  |  |  | C $id )> removes the given OID from the table | 
| 950 |  |  |  |  |  |  | if it is there. | 
| 951 |  |  |  |  |  |  |  | 
| 952 |  |  |  |  |  |  | C \%mag ) replaces the magnitude table | 
| 953 |  |  |  |  |  |  | with the contents of the given hash. The keys will be normalized to 5 | 
| 954 |  |  |  |  |  |  | digits. | 
| 955 |  |  |  |  |  |  |  | 
| 956 |  |  |  |  |  |  | C $file_name, $mag_offset )> replaces the | 
| 957 |  |  |  |  |  |  | magnitude table with the contents of the named Molczan-format file. The | 
| 958 |  |  |  |  |  |  | C<$file_name> argument can also be a scalar reference with the scalar | 
| 959 |  |  |  |  |  |  | containing the data, or an open handle. The C<$mag_offset> is an | 
| 960 |  |  |  |  |  |  | adjustment to be added to the magnitudes read from the file, and | 
| 961 |  |  |  |  |  |  | defaults to 0. | 
| 962 |  |  |  |  |  |  |  | 
| 963 |  |  |  |  |  |  | C $file_name, $mag_offset )> replaces the | 
| 964 |  |  |  |  |  |  | magnitude table with the contents of the named Quicksat-format file. The | 
| 965 |  |  |  |  |  |  | C<$file_name> argument can also be a scalar reference with the scalar | 
| 966 |  |  |  |  |  |  | containing the data, or an open handle. The C<$mag_offset> is an | 
| 967 |  |  |  |  |  |  | adjustment to be added to the magnitudes read from the file, and | 
| 968 |  |  |  |  |  |  | defaults to 0. In addition to this value, C<0.7> is added to the | 
| 969 |  |  |  |  |  |  | magnitude before storage to adjust the data from full-phase to | 
| 970 |  |  |  |  |  |  | half-phase. | 
| 971 |  |  |  |  |  |  |  | 
| 972 |  |  |  |  |  |  | C ... )> returns an array which is a slice of | 
| 973 |  |  |  |  |  |  | the magnitude table, which is stored as a hash. In other words, it | 
| 974 |  |  |  |  |  |  | returns OID/magnitude pairs in no particular order. If any further | 
| 975 |  |  |  |  |  |  | arguments are passed, they are the OIDs to return. Otherwise all are | 
| 976 |  |  |  |  |  |  | returned. | 
| 977 |  |  |  |  |  |  |  | 
| 978 |  |  |  |  |  |  | Examples of Molczan-format data are contained in F and | 
| 979 |  |  |  |  |  |  | F available on Mike McCants' web site; these can be fetched | 
| 980 |  |  |  |  |  |  | using the L C method. An | 
| 981 |  |  |  |  |  |  | example of Quicksat-format data is contained in F. See Mike | 
| 982 |  |  |  |  |  |  | McCants' web site, L for an | 
| 983 |  |  |  |  |  |  | explanation of the differences. | 
| 984 |  |  |  |  |  |  |  | 
| 985 |  |  |  |  |  |  | Note that if you have one of the reported pure Perl versions of | 
| 986 |  |  |  |  |  |  | L, you can not pass open handles to | 
| 987 |  |  |  |  |  |  | functionality that would otherwise accept them. | 
| 988 |  |  |  |  |  |  |  | 
| 989 |  |  |  |  |  |  | =cut | 
| 990 |  |  |  |  |  |  |  | 
| 991 |  |  |  |  |  |  | { | 
| 992 |  |  |  |  |  |  | my $openhandle = Scalar::Util->can( 'openhandle' ) || sub { return }; | 
| 993 |  |  |  |  |  |  |  | 
| 994 |  |  |  |  |  |  | my $parse_file = sub { | 
| 995 |  |  |  |  |  |  | my ( $file_name, $mag_offset, $parse_info ) = @_; | 
| 996 |  |  |  |  |  |  | defined $mag_offset | 
| 997 |  |  |  |  |  |  | or $mag_offset = 0; | 
| 998 |  |  |  |  |  |  | $mag_offset += $parse_info->{mag_offset}; | 
| 999 |  |  |  |  |  |  | my %mag; | 
| 1000 |  |  |  |  |  |  | my $fh; | 
| 1001 |  |  |  |  |  |  | if ( $openhandle->( $file_name ) ) { | 
| 1002 |  |  |  |  |  |  | $fh = $file_name; | 
| 1003 |  |  |  |  |  |  | } else { | 
| 1004 |  |  |  |  |  |  | open $fh, '<', $file_name	## no critic (RequireBriefOpen) | 
| 1005 |  |  |  |  |  |  | or croak "Failed to open $file_name: $!"; | 
| 1006 |  |  |  |  |  |  | } | 
| 1007 |  |  |  |  |  |  | local $_ = undef;	# while (<>) ... does not localize $_. | 
| 1008 |  |  |  |  |  |  | while ( <$fh> ) { | 
| 1009 |  |  |  |  |  |  | chomp; | 
| 1010 |  |  |  |  |  |  | m/ \A \s* (?: \# | \z ) /smx | 
| 1011 |  |  |  |  |  |  | and next;	# Extension to syntax. | 
| 1012 |  |  |  |  |  |  | $parse_info->{pad} > length | 
| 1013 |  |  |  |  |  |  | and $_ = sprintf '%-*s', $parse_info->{pad}, $_; | 
| 1014 |  |  |  |  |  |  | # Perl 5.8 and below require an explicit buffer to unpack. | 
| 1015 |  |  |  |  |  |  | my ( $id, $mag ) = unpack $parse_info->{template}, $_; | 
| 1016 |  |  |  |  |  |  | $mag =~ s/ \s+ //smxg; | 
| 1017 |  |  |  |  |  |  | looks_like_number( $mag ) | 
| 1018 |  |  |  |  |  |  | or next; | 
| 1019 |  |  |  |  |  |  | $mag{ _normalize_oid( $id ) } = $mag + $parse_info->{mag_offset}; | 
| 1020 |  |  |  |  |  |  | } | 
| 1021 |  |  |  |  |  |  | close $fh; | 
| 1022 |  |  |  |  |  |  | %magnitude_table = %mag; | 
| 1023 |  |  |  |  |  |  | }; | 
| 1024 |  |  |  |  |  |  |  | 
| 1025 |  |  |  |  |  |  | my %cmd_def = ( | 
| 1026 |  |  |  |  |  |  | add	=> sub { | 
| 1027 |  |  |  |  |  |  | my ( $id, $mag ) = @_; | 
| 1028 |  |  |  |  |  |  | defined $id | 
| 1029 |  |  |  |  |  |  | and $id =~ m/ \A [0-9]+ \z /smx | 
| 1030 |  |  |  |  |  |  | and defined $mag | 
| 1031 |  |  |  |  |  |  | and looks_like_number( $mag ) | 
| 1032 |  |  |  |  |  |  | or croak 'magnitude_table add needs an OID and a magnitude'; | 
| 1033 |  |  |  |  |  |  | $magnitude_table{ _normalize_oid( $id ) } = $mag; | 
| 1034 |  |  |  |  |  |  | return; | 
| 1035 |  |  |  |  |  |  | }, | 
| 1036 |  |  |  |  |  |  | adjust	=> sub { | 
| 1037 |  |  |  |  |  |  | my ( $adj ) = @_; | 
| 1038 |  |  |  |  |  |  | if ( defined $adj ) { | 
| 1039 |  |  |  |  |  |  | looks_like_number( $adj ) | 
| 1040 |  |  |  |  |  |  | or croak 'magnitude_table adjust needs a floating point number'; | 
| 1041 |  |  |  |  |  |  | $magnitude_adjust = $adj; | 
| 1042 |  |  |  |  |  |  | return; | 
| 1043 |  |  |  |  |  |  | } else { | 
| 1044 |  |  |  |  |  |  | return $magnitude_adjust; | 
| 1045 |  |  |  |  |  |  | } | 
| 1046 |  |  |  |  |  |  | }, | 
| 1047 |  |  |  |  |  |  | clear	=> sub { | 
| 1048 |  |  |  |  |  |  | %magnitude_table = (); | 
| 1049 |  |  |  |  |  |  | return; | 
| 1050 |  |  |  |  |  |  | }, | 
| 1051 |  |  |  |  |  |  | dump	=> sub { | 
| 1052 |  |  |  |  |  |  | local $Data::Dumper::Terse = 1; | 
| 1053 |  |  |  |  |  |  | local $Data::Dumper::Sortkeys = 1; | 
| 1054 |  |  |  |  |  |  | print Dumper( \%magnitude_table ); | 
| 1055 |  |  |  |  |  |  | return; | 
| 1056 |  |  |  |  |  |  | }, | 
| 1057 |  |  |  |  |  |  | drop	=> sub { | 
| 1058 |  |  |  |  |  |  | my ( $id ) = @_; | 
| 1059 |  |  |  |  |  |  | defined $id | 
| 1060 |  |  |  |  |  |  | and $id =~ m/ \A [0-9]+ \z /smx | 
| 1061 |  |  |  |  |  |  | or croak 'magnitude_table drop needs an OID'; | 
| 1062 |  |  |  |  |  |  | delete $magnitude_table{ _normalize_oid( $id ) }; | 
| 1063 |  |  |  |  |  |  | return; | 
| 1064 |  |  |  |  |  |  | }, | 
| 1065 |  |  |  |  |  |  | magnitude	=> sub { | 
| 1066 |  |  |  |  |  |  | my ( $tbl ) = @_; | 
| 1067 |  |  |  |  |  |  | HASH_REF eq ref $tbl | 
| 1068 |  |  |  |  |  |  | or croak 'magnitude_table magnitude needs a hash ref'; | 
| 1069 |  |  |  |  |  |  | my %mag; | 
| 1070 |  |  |  |  |  |  | foreach my $key ( keys %{ $tbl } ) { | 
| 1071 |  |  |  |  |  |  | my $val = $tbl->{$key}; | 
| 1072 |  |  |  |  |  |  | $key =~ m/ \A [0-9]+ \z /smx | 
| 1073 |  |  |  |  |  |  | or croak "OID '$key' must be numeric"; | 
| 1074 |  |  |  |  |  |  | looks_like_number( $val ) | 
| 1075 |  |  |  |  |  |  | or croak "Magnitude '$val' must be numeric"; | 
| 1076 |  |  |  |  |  |  | $mag{ _normalize_oid( $key ) } = $val; | 
| 1077 |  |  |  |  |  |  | } | 
| 1078 |  |  |  |  |  |  | %magnitude_table = %mag; | 
| 1079 |  |  |  |  |  |  | return; | 
| 1080 |  |  |  |  |  |  | }, | 
| 1081 |  |  |  |  |  |  | molczan	=> sub { | 
| 1082 |  |  |  |  |  |  | my ( $file_name, $mag_factor ) = @_; | 
| 1083 |  |  |  |  |  |  | $parse_file->( $file_name, $mag_factor, { | 
| 1084 |  |  |  |  |  |  | mag_offset	=> 0, | 
| 1085 |  |  |  |  |  |  | pad		=> 49, | 
| 1086 |  |  |  |  |  |  | template	=> 'a5x32a5', | 
| 1087 |  |  |  |  |  |  | } ); | 
| 1088 |  |  |  |  |  |  | return; | 
| 1089 |  |  |  |  |  |  | }, | 
| 1090 |  |  |  |  |  |  | quicksat	=> sub { | 
| 1091 |  |  |  |  |  |  | my ( $file_name, $mag_factor ) = @_; | 
| 1092 |  |  |  |  |  |  | $parse_file->( $file_name, $mag_factor, { | 
| 1093 |  |  |  |  |  |  | mag_offset	=> 0.7, | 
| 1094 |  |  |  |  |  |  | pad		=> 56, | 
| 1095 |  |  |  |  |  |  | template	=> 'a5x28a5', | 
| 1096 |  |  |  |  |  |  | } ); | 
| 1097 |  |  |  |  |  |  | return; | 
| 1098 |  |  |  |  |  |  | }, | 
| 1099 |  |  |  |  |  |  | show	=> sub { | 
| 1100 |  |  |  |  |  |  | my ( @arg ) = @_; | 
| 1101 |  |  |  |  |  |  | @arg | 
| 1102 |  |  |  |  |  |  | or return %magnitude_table; | 
| 1103 |  |  |  |  |  |  | return ( | 
| 1104 |  |  |  |  |  |  | map { $_ => $magnitude_table{$_} } | 
| 1105 |  |  |  |  |  |  | grep { defined $magnitude_table{$_} } | 
| 1106 |  |  |  |  |  |  | map { _normalize_oid( $_ ) } @arg | 
| 1107 |  |  |  |  |  |  | ); | 
| 1108 |  |  |  |  |  |  | }, | 
| 1109 |  |  |  |  |  |  | ); | 
| 1110 |  |  |  |  |  |  |  | 
| 1111 |  |  |  |  |  |  | sub magnitude_table { | 
| 1112 | 29 |  |  | 29 | 1 | 17911 | my ( undef, $cmd, @arg ) = @_;	# Invocant not used | 
| 1113 | 29 | 50 |  |  |  | 100 | my $code = $cmd_def{$cmd} | 
| 1114 |  |  |  |  |  |  | or croak "'$cmd' is not a valid magnitude_table subcommand"; | 
| 1115 | 29 |  |  |  |  | 75 | return $code->( @arg ); | 
| 1116 |  |  |  |  |  |  | } | 
| 1117 |  |  |  |  |  |  | } | 
| 1118 |  |  |  |  |  |  |  | 
| 1119 |  |  |  |  |  |  | =item $time = $tle->max_effective_date(...); | 
| 1120 |  |  |  |  |  |  |  | 
| 1121 |  |  |  |  |  |  | This method returns the maximum date among its arguments and the | 
| 1122 |  |  |  |  |  |  | effective date of the $tle object as set in the C attribute, | 
| 1123 |  |  |  |  |  |  | if that is defined. If no effective date is set but the C | 
| 1124 |  |  |  |  |  |  | attribute is false, the C of the object is used as the effective | 
| 1125 |  |  |  |  |  |  | date. If there are no arguments and no effective date, C is | 
| 1126 |  |  |  |  |  |  | returned. | 
| 1127 |  |  |  |  |  |  |  | 
| 1128 |  |  |  |  |  |  | =cut | 
| 1129 |  |  |  |  |  |  |  | 
| 1130 |  |  |  |  |  |  | sub max_effective_date { | 
| 1131 | 26 |  |  | 26 | 1 | 72 | my ($self, @args) = @_; | 
| 1132 | 26 | 100 |  |  |  | 71 | if (my $effective = $self->get('effective')) { | 
|  |  | 100 |  |  |  |  |  | 
| 1133 | 5 |  |  |  |  | 11 | push @args, $effective; | 
| 1134 |  |  |  |  |  |  | } elsif (!$self->get('backdate')) { | 
| 1135 | 3 |  |  |  |  | 8 | push @args, $self->get('epoch'); | 
| 1136 |  |  |  |  |  |  | } | 
| 1137 | 26 |  |  |  |  | 76 | return max( grep {defined $_} @args ); | 
|  | 31 |  |  |  |  | 170 |  | 
| 1138 |  |  |  |  |  |  | } | 
| 1139 |  |  |  |  |  |  |  | 
| 1140 |  |  |  |  |  |  | =item $tle = $tle->members(); | 
| 1141 |  |  |  |  |  |  |  | 
| 1142 |  |  |  |  |  |  | This method simply returns the object it is called on. It exists for | 
| 1143 |  |  |  |  |  |  | convenience in getting back validated objects when iterating over a | 
| 1144 |  |  |  |  |  |  | mixture of L and | 
| 1145 |  |  |  |  |  |  | L objects. | 
| 1146 |  |  |  |  |  |  |  | 
| 1147 |  |  |  |  |  |  | =cut | 
| 1148 |  |  |  |  |  |  |  | 
| 1149 |  |  |  |  |  |  | sub members { | 
| 1150 | 0 |  |  | 0 | 1 | 0 | return shift; | 
| 1151 |  |  |  |  |  |  | } | 
| 1152 |  |  |  |  |  |  |  | 
| 1153 |  |  |  |  |  |  | =item $tle = $tle->model($time) | 
| 1154 |  |  |  |  |  |  |  | 
| 1155 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 1156 |  |  |  |  |  |  | object at the given time, using the preferred model. As of | 
| 1157 |  |  |  |  |  |  | Astro::Coord::ECI::TLE 0.010_10 this is sgp4r; previously it was sgp4 or | 
| 1158 |  |  |  |  |  |  | sdp4, whichever was appropriate. | 
| 1159 |  |  |  |  |  |  |  | 
| 1160 |  |  |  |  |  |  | The intent is that this method will use whatever model is currently | 
| 1161 |  |  |  |  |  |  | preferred. If the preferred model changes, this method will use the | 
| 1162 |  |  |  |  |  |  | new preferred model as soon as I: | 
| 1163 |  |  |  |  |  |  |  | 
| 1164 |  |  |  |  |  |  | - Find out about the change; | 
| 1165 |  |  |  |  |  |  | - Can get the specifications for the new model; | 
| 1166 |  |  |  |  |  |  | - Can find the time to code up the new model. | 
| 1167 |  |  |  |  |  |  |  | 
| 1168 |  |  |  |  |  |  | You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () | 
| 1169 |  |  |  |  |  |  | or equatorial ()) to retrieve the position you just calculated. | 
| 1170 |  |  |  |  |  |  |  | 
| 1171 |  |  |  |  |  |  | =cut | 
| 1172 |  |  |  |  |  |  |  | 
| 1173 |  |  |  |  |  |  | BEGIN { | 
| 1174 | 16 |  |  | 16 |  | 1474 | *model = \&sgp4r; | 
| 1175 |  |  |  |  |  |  | } | 
| 1176 |  |  |  |  |  |  |  | 
| 1177 |  |  |  |  |  |  | =item $tle = $tle->model4 ($time) | 
| 1178 |  |  |  |  |  |  |  | 
| 1179 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 1180 |  |  |  |  |  |  | object at the given time, using either the SGP4 or SDP4 model, | 
| 1181 |  |  |  |  |  |  | whichever is appropriate. | 
| 1182 |  |  |  |  |  |  |  | 
| 1183 |  |  |  |  |  |  | You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () | 
| 1184 |  |  |  |  |  |  | or equatorial ()) to retrieve the position you just calculated. | 
| 1185 |  |  |  |  |  |  |  | 
| 1186 |  |  |  |  |  |  | =cut | 
| 1187 |  |  |  |  |  |  |  | 
| 1188 |  |  |  |  |  |  | sub model4 { | 
| 1189 | 0 | 0 |  | 0 | 1 | 0 | return $_[0]->is_deep ? $_[0]->sdp4 ($_[1]) : $_[0]->sgp4 ($_[1]); | 
| 1190 |  |  |  |  |  |  | } | 
| 1191 |  |  |  |  |  |  |  | 
| 1192 |  |  |  |  |  |  | =item $tle = $tle->model4r ($time) | 
| 1193 |  |  |  |  |  |  |  | 
| 1194 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 1195 |  |  |  |  |  |  | object at the given time, using the "Revisiting Spacetrack Report #3" | 
| 1196 |  |  |  |  |  |  | model (sgp4r). It is really just a synonym for sgp4r, which covers both | 
| 1197 |  |  |  |  |  |  | near-earth and deep space bodies, but is provided for consistency's | 
| 1198 |  |  |  |  |  |  | sake. If some other model becomes preferred, this method will still call | 
| 1199 |  |  |  |  |  |  | sgp4r. | 
| 1200 |  |  |  |  |  |  |  | 
| 1201 |  |  |  |  |  |  | You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () | 
| 1202 |  |  |  |  |  |  | or equatorial ()) to retrieve the position you just calculated. | 
| 1203 |  |  |  |  |  |  |  | 
| 1204 |  |  |  |  |  |  | =cut | 
| 1205 |  |  |  |  |  |  |  | 
| 1206 |  |  |  |  |  |  | BEGIN { | 
| 1207 | 16 |  |  | 16 |  | 20558 | *model4r = \&sgp4r; | 
| 1208 |  |  |  |  |  |  | } | 
| 1209 |  |  |  |  |  |  |  | 
| 1210 |  |  |  |  |  |  | =item $tle = $tle->model8 ($time) | 
| 1211 |  |  |  |  |  |  |  | 
| 1212 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 1213 |  |  |  |  |  |  | object at the given time, using either the SGP8 or SDP8 model, | 
| 1214 |  |  |  |  |  |  | whichever is appropriate. | 
| 1215 |  |  |  |  |  |  |  | 
| 1216 |  |  |  |  |  |  | You need to call one of the Astro::Coord::ECI methods (e.g. geodetic () | 
| 1217 |  |  |  |  |  |  | or equatorial ()) to retrieve the position you just calculated. | 
| 1218 |  |  |  |  |  |  |  | 
| 1219 |  |  |  |  |  |  | =cut | 
| 1220 |  |  |  |  |  |  |  | 
| 1221 |  |  |  |  |  |  | sub model8 { | 
| 1222 | 0 | 0 |  | 0 | 1 | 0 | return $_[0]->is_deep ? $_[0]->sdp8 ($_[1]) : $_[0]->sgp8 ($_[1]); | 
| 1223 |  |  |  |  |  |  | } | 
| 1224 |  |  |  |  |  |  |  | 
| 1225 |  |  |  |  |  |  | =item $tle = $tle->null ($time) | 
| 1226 |  |  |  |  |  |  |  | 
| 1227 |  |  |  |  |  |  | This method does nothing. It is a valid orbital model, though. If you | 
| 1228 |  |  |  |  |  |  | call $tle->set (model => 'null'), no position calculation is done as a | 
| 1229 |  |  |  |  |  |  | side effect of calling $tle->universal ($time). | 
| 1230 |  |  |  |  |  |  |  | 
| 1231 |  |  |  |  |  |  | =cut | 
| 1232 |  |  |  |  |  |  |  | 
| 1233 | 6 |  |  | 6 | 1 | 12 | sub null { return $_[0] } | 
| 1234 |  |  |  |  |  |  |  | 
| 1235 |  |  |  |  |  |  | =item @elements = Astro::Coord::ECI::TLE->parse( @data ); | 
| 1236 |  |  |  |  |  |  |  | 
| 1237 |  |  |  |  |  |  | This method parses NORAD two- or three-line element sets, JSON element | 
| 1238 |  |  |  |  |  |  | sets, or a mixture, returning a list of Astro::Coord::ECI::TLE objects. | 
| 1239 |  |  |  |  |  |  | The L section identifies those attributes which will be | 
| 1240 |  |  |  |  |  |  | filled in by this method. | 
| 1241 |  |  |  |  |  |  |  | 
| 1242 |  |  |  |  |  |  | TLE input will be split into individual lines, and all blank lines and | 
| 1243 |  |  |  |  |  |  | lines beginning with '#' will be eliminated. The remaining lines are | 
| 1244 |  |  |  |  |  |  | assumed to represent two- or three-line element sets, in so-called | 
| 1245 |  |  |  |  |  |  | external format. Internal format (denoted by a 'G' in column 79 of line | 
| 1246 |  |  |  |  |  |  | 1 of the set, not counting the common name if any) is not supported, | 
| 1247 |  |  |  |  |  |  | and the presence of such data will result in an exception being thrown. | 
| 1248 |  |  |  |  |  |  |  | 
| 1249 |  |  |  |  |  |  | Input beginning with C<[{> (with optional spaces) is presumed to be | 
| 1250 |  |  |  |  |  |  | NORAD JSON element sets and parsed accordingly. | 
| 1251 |  |  |  |  |  |  |  | 
| 1252 |  |  |  |  |  |  | Optionally, the first argument (after the invocant) can be a reference | 
| 1253 |  |  |  |  |  |  | to a hash of default attribute values. These are preferred over the | 
| 1254 |  |  |  |  |  |  | static values, but attributes provided by the TLE or JSON input override | 
| 1255 |  |  |  |  |  |  | both. | 
| 1256 |  |  |  |  |  |  |  | 
| 1257 |  |  |  |  |  |  | =cut | 
| 1258 |  |  |  |  |  |  |  | 
| 1259 |  |  |  |  |  |  | sub parse { | 
| 1260 | 15 |  |  | 15 | 1 | 6695 | my ($self, @args) = @_; | 
| 1261 | 15 |  |  |  |  | 38 | my @rslt; | 
| 1262 | 15 | 100 |  |  |  | 66 | my $attrs = HASH_REF eq ref $args[0] ? shift @args : {}; | 
| 1263 |  |  |  |  |  |  |  | 
| 1264 | 15 |  |  |  |  | 33 | my @data; | 
| 1265 | 15 |  |  |  |  | 41 | foreach my $datum (@args) { | 
| 1266 | 15 | 50 |  |  |  | 51 | ref $datum and croak < | 
| 1267 |  |  |  |  |  |  | Error - Arguments to parse() must be scalar. | 
| 1268 |  |  |  |  |  |  | eod | 
| 1269 | 15 | 50 |  |  |  | 62 | if ( $datum =~ m/ \A \s* \[? \s* \{ /smx ) { | 
| 1270 | 0 |  |  |  |  | 0 | push @rslt, $self->_parse_json( $attrs, $datum ); | 
| 1271 |  |  |  |  |  |  | } else { | 
| 1272 | 15 |  |  |  |  | 161 | foreach my $line (split qr{\n}, $datum) { | 
| 1273 | 96 |  |  |  |  | 325 | $line =~ s/ \s+ \z //smx; | 
| 1274 | 96 | 50 |  |  |  | 206 | $line =~ m/ \A \s* [#] /smx and next; | 
| 1275 | 96 | 50 |  |  |  | 275 | $line and push @data, $line; | 
| 1276 |  |  |  |  |  |  | } | 
| 1277 |  |  |  |  |  |  | } | 
| 1278 |  |  |  |  |  |  | } | 
| 1279 |  |  |  |  |  |  |  | 
| 1280 | 15 |  |  |  |  | 84 | while (@data) { | 
| 1281 | 44 |  |  |  |  | 200 | my %ele = ( %static, %{ $attrs } ); | 
|  | 44 |  |  |  |  | 242 |  | 
| 1282 | 44 |  |  |  |  | 103 | my $name; | 
| 1283 | 44 |  |  |  |  | 81 | my $line = shift @data; | 
| 1284 | 44 |  |  |  |  | 215 | $line =~ s/\s+$//; | 
| 1285 | 44 |  |  |  |  | 110 | my $tle = "$line\n"; | 
| 1286 | 44 | 100 | 100 |  |  | 299 | $line =~ m{ \A 1 (\s* [0-9]+) }smx and length $1 == 6 or do { | 
| 1287 | 8 |  |  |  |  | 23 | ( $name = $line ) =~ s/ \A 0 \s+ //smx;	# SpaceTrack 3le | 
| 1288 | 8 |  |  |  |  | 17 | $line = shift @data; | 
| 1289 | 8 |  |  |  |  | 28 | $tle .= "$line\n"; | 
| 1290 |  |  |  |  |  |  | }; | 
| 1291 | 44 | 50 | 33 |  |  | 156 | if (length ($line) > 79 && substr ($line, 79, 1) eq 'G') { | 
| 1292 | 0 |  |  |  |  | 0 | croak "G (internal) format data not supported"; | 
| 1293 |  |  |  |  |  |  | } else { | 
| 1294 | 44 | 50 | 33 |  |  | 281 | ($line =~ m/^1(\s*[0-9]+)/ && length ($1) == 6) | 
| 1295 |  |  |  |  |  |  | or croak "Invalid line 1 '$line'"; | 
| 1296 | 44 | 50 |  |  |  | 243 | length ($line) < 80 and $line .= ' ' x (80 - length ($line)); | 
| 1297 |  |  |  |  |  |  |  | 
| 1298 | 44 |  |  |  |  | 430 | @ele{qw{id classification international epoch firstderivative | 
| 1299 |  |  |  |  |  |  | secondderivative bstardrag ephemeristype elementnumber}} = | 
| 1300 |  |  |  |  |  |  | unpack 'x2A5A1x1A8x1A14x1A10x1A8x1A8x1A1x1A4', $line; | 
| 1301 | 44 |  |  |  |  | 180 | $ele{elementnumber} =~ s/ \A \s+ //smx; | 
| 1302 |  |  |  |  |  |  |  | 
| 1303 | 44 |  |  |  |  | 96 | $line = shift @data; | 
| 1304 | 44 |  |  |  |  | 123 | $tle .= "$line\n"; | 
| 1305 | 44 | 50 | 33 |  |  | 245 | ($line =~ m/^2(\s*[0-9]+)/ && length ($1) == 6) | 
| 1306 |  |  |  |  |  |  | or croak "Invalid line 2 '$line'"; | 
| 1307 | 44 | 100 |  |  |  | 150 | length ($line) < 80 and $line .= ' ' x (80 - length ($line)); | 
| 1308 | 44 |  |  |  |  | 298 | @ele{qw{id_2 inclination ascendingnode eccentricity | 
| 1309 |  |  |  |  |  |  | argumentofperigee meananomaly meanmotion | 
| 1310 |  |  |  |  |  |  | revolutionsatepoch}} = | 
| 1311 |  |  |  |  |  |  | unpack 'x2A5x1A8x1A8x1A7x1A8x1A8x1A11A5', $line; | 
| 1312 |  |  |  |  |  |  |  | 
| 1313 | 44 |  |  |  |  | 122 | foreach my $key ( qw{ id epoch firstderivative | 
| 1314 |  |  |  |  |  |  | secondderivative bstardrag ephemeristype elementnumber | 
| 1315 |  |  |  |  |  |  | id_2 inclination ascendingnode eccentricity | 
| 1316 |  |  |  |  |  |  | argumentofperigee meananomaly meanmotion } | 
| 1317 |  |  |  |  |  |  | ) { | 
| 1318 | 616 |  |  |  |  | 1429 | $ele{$key} =~ s/ \s /0/smxg; | 
| 1319 |  |  |  |  |  |  | } | 
| 1320 |  |  |  |  |  |  |  | 
| 1321 |  |  |  |  |  |  | $ele{id} == $ele{id_2} or | 
| 1322 | 44 | 50 |  |  |  | 165 | croak "Invalid data. Line 1 was for id $ele{id} but ", | 
| 1323 |  |  |  |  |  |  | "line 2 was for $ele{id_2}"; | 
| 1324 | 44 |  |  |  |  | 95 | delete $ele{id_2}; | 
| 1325 |  |  |  |  |  |  | } | 
| 1326 | 44 |  |  |  |  | 83 | foreach (qw{eccentricity}) { | 
| 1327 | 44 |  |  |  |  | 189 | $ele{$_} = "0.$ele{$_}" + 0; | 
| 1328 |  |  |  |  |  |  | } | 
| 1329 | 44 |  |  |  |  | 88 | foreach (qw{secondderivative bstardrag}) { | 
| 1330 | 88 |  |  |  |  | 554 | $ele{$_} =~ s/(.)(.{5})(..)/$1.$2e$3/; | 
| 1331 | 88 |  |  |  |  | 301 | $ele{$_} += 0; | 
| 1332 |  |  |  |  |  |  | } | 
| 1333 | 44 |  |  |  |  | 88 | foreach (qw{epoch}) { | 
| 1334 | 44 |  |  |  |  | 208 | my ($yr, $day) = $ele{$_} =~ m/(..)(.*)/; | 
| 1335 | 44 |  |  |  |  | 205 | $yr = __tle_year_to_Gregorian_year( $yr ); | 
| 1336 | 44 |  |  |  |  | 179 | $ele{$_} = greg_time_gm( 0, 0, 0, 1, 0, $yr ) + | 
| 1337 |  |  |  |  |  |  | ( $day - 1 ) * SECSPERDAY; | 
| 1338 |  |  |  |  |  |  | } | 
| 1339 |  |  |  |  |  |  |  | 
| 1340 |  |  |  |  |  |  | #	From here is conversion to the units expected by the | 
| 1341 |  |  |  |  |  |  | #	models. | 
| 1342 |  |  |  |  |  |  |  | 
| 1343 | 44 |  |  |  |  | 1615 | foreach (qw{ascendingnode argumentofperigee meananomaly | 
| 1344 |  |  |  |  |  |  | inclination}) { | 
| 1345 | 176 |  |  |  |  | 378 | $ele{$_} *= SGP_DE2RA; | 
| 1346 |  |  |  |  |  |  | } | 
| 1347 | 44 |  |  |  |  | 78 | my $temp = SGP_TWOPI; | 
| 1348 | 44 |  |  |  |  | 79 | foreach (qw{meanmotion firstderivative secondderivative}) { | 
| 1349 | 132 |  |  |  |  | 194 | $temp /= SGP_XMNPDA; | 
| 1350 | 132 |  |  |  |  | 262 | $ele{$_} *= $temp; | 
| 1351 |  |  |  |  |  |  | } | 
| 1352 |  |  |  |  |  |  |  | 
| 1353 | 44 |  |  |  |  | 293 | my $body = __PACKAGE__->new (%ele);	# Note that setting the | 
| 1354 |  |  |  |  |  |  | # ID does the reblessing. | 
| 1355 | 44 |  |  |  |  | 178 | $body->__parse_name( $name ); | 
| 1356 | 44 |  |  |  |  | 97 | $body->{tle} = $tle; | 
| 1357 | 44 |  |  |  |  | 638 | push @rslt, $body; | 
| 1358 |  |  |  |  |  |  | } | 
| 1359 |  |  |  |  |  |  |  | 
| 1360 | 15 | 50 |  |  |  | 76 | if ( keys %magnitude_table ) { | 
| 1361 | 15 |  |  |  |  | 42 | foreach my $tle ( @rslt ) { | 
| 1362 | 44 | 50 |  |  |  | 97 | defined( my $oid = $tle->get( 'id' ) ) | 
| 1363 |  |  |  |  |  |  | or next; | 
| 1364 | 44 | 50 |  |  |  | 96 | defined $tle->get( 'intrinsic_magnitude' ) | 
| 1365 |  |  |  |  |  |  | and next; | 
| 1366 | 44 | 100 |  |  |  | 105 | defined( my $std_mag = $magnitude_table{ _normalize_oid( $oid ) } ) | 
| 1367 |  |  |  |  |  |  | or next; | 
| 1368 | 2 |  |  |  |  | 7 | $tle->set( intrinsic_magnitude => $std_mag + | 
| 1369 |  |  |  |  |  |  | $magnitude_adjust ); | 
| 1370 |  |  |  |  |  |  | } | 
| 1371 |  |  |  |  |  |  | } | 
| 1372 | 15 |  |  |  |  | 129 | return @rslt; | 
| 1373 |  |  |  |  |  |  | } | 
| 1374 |  |  |  |  |  |  |  | 
| 1375 |  |  |  |  |  |  | sub __parse_name { | 
| 1376 | 44 |  |  | 44 |  | 100 | my ( $self, $name ) = @_; | 
| 1377 | 44 | 100 |  |  |  | 115 | defined $name | 
| 1378 |  |  |  |  |  |  | or return; | 
| 1379 | 8 |  |  |  |  | 42 | $name =~ s{ \s* -- ( effective | rcs ) \s+ ( \S+ ) }{ | 
| 1380 | 4 |  |  |  |  | 14 | $self->set( $1 => $2 ); | 
| 1381 | 4 |  |  |  |  | 15 | '' | 
| 1382 |  |  |  |  |  |  | }smxge; | 
| 1383 | 8 | 50 |  |  |  | 34 | $name ne '' | 
| 1384 |  |  |  |  |  |  | and $self->set( name => $name ); | 
| 1385 | 8 |  |  |  |  | 16 | return; | 
| 1386 |  |  |  |  |  |  | } | 
| 1387 |  |  |  |  |  |  |  | 
| 1388 |  |  |  |  |  |  | # Parse information for the above from | 
| 1389 |  |  |  |  |  |  | # CelesTrak "FAQs: Two-Line Element Set Format", by Dr. T. S. Kelso, | 
| 1390 |  |  |  |  |  |  | # http://celestrak.org/columns/v04n03/ | 
| 1391 |  |  |  |  |  |  | # Per this, all data are for the NORAD SGP4/SDP4 model, except for the | 
| 1392 |  |  |  |  |  |  | # first and second time derivative, which are for the simpler SGP model. | 
| 1393 |  |  |  |  |  |  | # The actual documentation of the algorithms, along with a reference | 
| 1394 |  |  |  |  |  |  | # implementation in FORTRAN, is available at | 
| 1395 |  |  |  |  |  |  | # http://celestrak.org/NORAD/documentation/spacetrk.pdf | 
| 1396 |  |  |  |  |  |  |  | 
| 1397 |  |  |  |  |  |  | =item @passes = $tle->pass ($station, $start, $end, \@sky) | 
| 1398 |  |  |  |  |  |  |  | 
| 1399 |  |  |  |  |  |  | This method returns passes of the body over the given station between | 
| 1400 |  |  |  |  |  |  | the given start end end times. The \@sky argument is background bodies | 
| 1401 |  |  |  |  |  |  | to compute appulses with (see note 3). | 
| 1402 |  |  |  |  |  |  |  | 
| 1403 |  |  |  |  |  |  | A pass is detected by this method when the body sets. Unless | 
| 1404 |  |  |  |  |  |  | C (see below) is in effect, this means that | 
| 1405 |  |  |  |  |  |  | passes are not usefully detected for geosynchronous or | 
| 1406 |  |  |  |  |  |  | near-geosynchronous bodies, and that passes where the body sets after | 
| 1407 |  |  |  |  |  |  | the C<$end> time will not be detected. | 
| 1408 |  |  |  |  |  |  |  | 
| 1409 |  |  |  |  |  |  | All arguments are optional, the defaults being | 
| 1410 |  |  |  |  |  |  |  | 
| 1411 |  |  |  |  |  |  | $station = the 'station' attribute of the invocant | 
| 1412 |  |  |  |  |  |  | $start = time() | 
| 1413 |  |  |  |  |  |  | $end = $start + 7 days | 
| 1414 |  |  |  |  |  |  | \@sky = [] | 
| 1415 |  |  |  |  |  |  |  | 
| 1416 |  |  |  |  |  |  | The return is a list of passes, which may be empty. Each pass is | 
| 1417 |  |  |  |  |  |  | represented by an anonymous hash containing the following keys: | 
| 1418 |  |  |  |  |  |  |  | 
| 1419 |  |  |  |  |  |  | {body} => Reference to body making pass; | 
| 1420 |  |  |  |  |  |  | {time} => Time of pass (culmination); | 
| 1421 |  |  |  |  |  |  | {events} => [the individual events of the pass]. | 
| 1422 |  |  |  |  |  |  |  | 
| 1423 |  |  |  |  |  |  | The individual events are also anonymous hashes, with each hash | 
| 1424 |  |  |  |  |  |  | containing the following keys: | 
| 1425 |  |  |  |  |  |  |  | 
| 1426 |  |  |  |  |  |  | {azimuth} => Azimuth of event in radians (see note 1); | 
| 1427 |  |  |  |  |  |  | {body} => Reference to body making pass (see note 2); | 
| 1428 |  |  |  |  |  |  | {appulse} => {  # This is present only for PASS_EVENT_APPULSE; | 
| 1429 |  |  |  |  |  |  | {angle} => minimum separation in radians; | 
| 1430 |  |  |  |  |  |  | {body} => other body involved in appulse; | 
| 1431 |  |  |  |  |  |  | } | 
| 1432 |  |  |  |  |  |  | {elevation} => Elevation of event in radians (see note 1); | 
| 1433 |  |  |  |  |  |  | {event} => Event code (PASS_EVENT_xxxx); | 
| 1434 |  |  |  |  |  |  | {illumination} => Illumination at time of event (PASS_EVENT_xxxx); | 
| 1435 |  |  |  |  |  |  | {range} => Distance to event in kilometers (see note 1); | 
| 1436 |  |  |  |  |  |  | {station} => Reference to observing station (see note 2); | 
| 1437 |  |  |  |  |  |  | {time} => Time of event; | 
| 1438 |  |  |  |  |  |  |  | 
| 1439 |  |  |  |  |  |  | The events are coded by the following manifest constants: | 
| 1440 |  |  |  |  |  |  |  | 
| 1441 |  |  |  |  |  |  | PASS_EVENT_NONE => dualvar (0, ''); | 
| 1442 |  |  |  |  |  |  | PASS_EVENT_SHADOWED => dualvar (1, 'shdw'); | 
| 1443 |  |  |  |  |  |  | PASS_EVENT_LIT => dualvar (2, 'lit'); | 
| 1444 |  |  |  |  |  |  | PASS_EVENT_DAY => dualvar (3, 'day'); | 
| 1445 |  |  |  |  |  |  | PASS_EVENT_RISE => dualvar (4, 'rise'); | 
| 1446 |  |  |  |  |  |  | PASS_EVENT_MAX => dualvar (5, 'max'); | 
| 1447 |  |  |  |  |  |  | PASS_EVENT_SET => dualvar (6, 'set'); | 
| 1448 |  |  |  |  |  |  | PASS_EVENT_APPULSE => dualvar (7, 'apls'); | 
| 1449 |  |  |  |  |  |  | PASS_EVENT_START => dualvar( 11, 'start' ); | 
| 1450 |  |  |  |  |  |  | PASS_EVENT_END => dualvar( 12, 'end' ); | 
| 1451 |  |  |  |  |  |  | PASS_EVENT_BRIGHTEST => dualvar( 13, 'brgt' ); | 
| 1452 |  |  |  |  |  |  |  | 
| 1453 |  |  |  |  |  |  | The C and C events are not normally | 
| 1454 |  |  |  |  |  |  | generated. You can get them in lieu of whatever events start and end the | 
| 1455 |  |  |  |  |  |  | pass by setting C in the C | 
| 1456 |  |  |  |  |  |  | attribute. Unless you are filtering out non-visible events, though, they | 
| 1457 |  |  |  |  |  |  | are just the rise and set events under different names. | 
| 1458 |  |  |  |  |  |  |  | 
| 1459 |  |  |  |  |  |  | The dualvar function comes from Scalar::Util, and generates values | 
| 1460 |  |  |  |  |  |  | which are numeric in numeric context and strings in string context. If | 
| 1461 |  |  |  |  |  |  | Scalar::Util cannot be loaded the numeric values are returned. | 
| 1462 |  |  |  |  |  |  |  | 
| 1463 |  |  |  |  |  |  | These manifest constants can be imported using the individual names, or | 
| 1464 |  |  |  |  |  |  | the tags ':constants' or ':all'. They can also be accessed as methods | 
| 1465 |  |  |  |  |  |  | using (e.g.) $tle->PASS_EVENT_LIT, or as static methods using (e.g.) | 
| 1466 |  |  |  |  |  |  | Astro::Coord::ECI::TLE->PASS_EVENT_LIT. | 
| 1467 |  |  |  |  |  |  |  | 
| 1468 |  |  |  |  |  |  | Illumination is represented by one of PASS_EVENT_SHADOWED, | 
| 1469 |  |  |  |  |  |  | PASS_EVENT_LIT, or PASS_EVENT_DAY. The first two are calculated based on | 
| 1470 |  |  |  |  |  |  | whether the illuminating body (i.e. the body specified by the 'illum' | 
| 1471 |  |  |  |  |  |  | attribute) is above the horizon; the third is based on whether the Sun | 
| 1472 |  |  |  |  |  |  | is higher than specified by the 'twilight' attribute, and trumps the | 
| 1473 |  |  |  |  |  |  | other two (i.e. if it's day it doesn't matter whether the satellite is | 
| 1474 |  |  |  |  |  |  | illuminated). | 
| 1475 |  |  |  |  |  |  |  | 
| 1476 |  |  |  |  |  |  | Time resolution of the events is typically to the nearest second, except | 
| 1477 |  |  |  |  |  |  | for appulses, which need to be calculated more closely to detect | 
| 1478 |  |  |  |  |  |  | transits. The time reported for the event is the time B the event | 
| 1479 |  |  |  |  |  |  | occurred. For example, the time reported for rise is the earliest time | 
| 1480 |  |  |  |  |  |  | the body is found above the horizon, and the time reported for set is | 
| 1481 |  |  |  |  |  |  | the earliest time the body is found below the horizon. | 
| 1482 |  |  |  |  |  |  |  | 
| 1483 |  |  |  |  |  |  | The operation of this method is affected by the following attributes, | 
| 1484 |  |  |  |  |  |  | in addition to its arguments and the orbital elements associated with | 
| 1485 |  |  |  |  |  |  | the object: | 
| 1486 |  |  |  |  |  |  |  | 
| 1487 |  |  |  |  |  |  | * appulse	# Maximum appulse to report | 
| 1488 |  |  |  |  |  |  | * edge_of_earths_shadow	# Used in the calculation of | 
| 1489 |  |  |  |  |  |  | # whether the satellite is illuminated or in | 
| 1490 |  |  |  |  |  |  | # shadow. | 
| 1491 |  |  |  |  |  |  | * geometric	# Use geometric horizon for pass rise/set | 
| 1492 |  |  |  |  |  |  | * horizon	# Effective horizon | 
| 1493 |  |  |  |  |  |  | * interval	# Interval for pass() positions, if positive | 
| 1494 |  |  |  |  |  |  | * lazy_pass_position # {azimuth}, {elevation} and {range} | 
| 1495 |  |  |  |  |  |  | # are optional if true (see note 1). | 
| 1496 |  |  |  |  |  |  | * pass_threshold # Minimum elevation satellite must reach | 
| 1497 |  |  |  |  |  |  | # for the pass to be reportable. If visible | 
| 1498 |  |  |  |  |  |  | # is true, it must be visible above this | 
| 1499 |  |  |  |  |  |  | # elevation | 
| 1500 |  |  |  |  |  |  | * pass_variant # Tweak what pass() returns; currently no | 
| 1501 |  |  |  |  |  |  | # effect unless 'visible' is true. | 
| 1502 |  |  |  |  |  |  | * illum	# Source of illumination. | 
| 1503 |  |  |  |  |  |  | * twilight	# Distance of illuminator below horizon | 
| 1504 |  |  |  |  |  |  | * visible	# Pass() reports only illuminated passes | 
| 1505 |  |  |  |  |  |  |  | 
| 1506 |  |  |  |  |  |  | Note 1: | 
| 1507 |  |  |  |  |  |  |  | 
| 1508 |  |  |  |  |  |  | If the C attribute is true, the {azimuth}, | 
| 1509 |  |  |  |  |  |  | {elevation}, and {range} keys may not be present. This attribute gives | 
| 1510 |  |  |  |  |  |  | the event-calculating algorithm permission to omit these if the time of | 
| 1511 |  |  |  |  |  |  | the event can be determined without computing the position of the body. | 
| 1512 |  |  |  |  |  |  | Currently this happens only for events generated in response to setting | 
| 1513 |  |  |  |  |  |  | the C attribute, but the user should not make this assumption | 
| 1514 |  |  |  |  |  |  | in his or her own code. | 
| 1515 |  |  |  |  |  |  |  | 
| 1516 |  |  |  |  |  |  | Typically you will only want to set this true if, after calling the | 
| 1517 |  |  |  |  |  |  | C method, you are not interested in the azimuth, elevation and | 
| 1518 |  |  |  |  |  |  | range, but compute the event positions in some coordinates other than | 
| 1519 |  |  |  |  |  |  | azimuth, elevation, and range. | 
| 1520 |  |  |  |  |  |  |  | 
| 1521 |  |  |  |  |  |  | Note 2: | 
| 1522 |  |  |  |  |  |  |  | 
| 1523 |  |  |  |  |  |  | The time set in the various {body} and {station} objects is B | 
| 1524 |  |  |  |  |  |  | guaranteed to be anything in particular. Specifically, it is almost | 
| 1525 |  |  |  |  |  |  | certainly not the time of the event. If you make use of the {body} | 
| 1526 |  |  |  |  |  |  | object you will probably need to set its time to the time of the event | 
| 1527 |  |  |  |  |  |  | before you do so. | 
| 1528 |  |  |  |  |  |  |  | 
| 1529 |  |  |  |  |  |  | Note 3: | 
| 1530 |  |  |  |  |  |  |  | 
| 1531 |  |  |  |  |  |  | The algorithm for computing appulses has been modified slightly in | 
| 1532 |  |  |  |  |  |  | version 0.056_04. This modification only applies to elements | 
| 1533 |  |  |  |  |  |  | of the optional C<\@sky> array that represent artificial satellites. | 
| 1534 |  |  |  |  |  |  |  | 
| 1535 |  |  |  |  |  |  | The problem I'm trying to address is that two satellites in very similar | 
| 1536 |  |  |  |  |  |  | orbits can appear to converge again after their appulse, due to their | 
| 1537 |  |  |  |  |  |  | increasing distance from the observer. If this happens early enough in | 
| 1538 |  |  |  |  |  |  | the pass it can fool the binary search algorithm that determines the | 
| 1539 |  |  |  |  |  |  | appulse time. | 
| 1540 |  |  |  |  |  |  |  | 
| 1541 |  |  |  |  |  |  | The revision is to first step across the pass, finding the closest | 
| 1542 |  |  |  |  |  |  | approach of the two bodies. A binary search is then done on a small | 
| 1543 |  |  |  |  |  |  | interval around the closest approach. | 
| 1544 |  |  |  |  |  |  |  | 
| 1545 |  |  |  |  |  |  | =cut | 
| 1546 |  |  |  |  |  |  |  | 
| 1547 | 16 |  |  | 16 |  | 140 | use constant PASS_EVENT_NONE => dualvar (0, '');	# Guaranteed false. | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 1245 |  | 
| 1548 | 16 |  |  | 16 |  | 115 | use constant PASS_EVENT_SHADOWED => dualvar (1, 'shdw'); | 
|  | 16 |  |  |  |  | 50 |  | 
|  | 16 |  |  |  |  | 1075 |  | 
| 1549 | 16 |  |  | 16 |  | 109 | use constant PASS_EVENT_LIT => dualvar (2, 'lit'); | 
|  | 16 |  |  |  |  | 37 |  | 
|  | 16 |  |  |  |  | 1087 |  | 
| 1550 | 16 |  |  | 16 |  | 145 | use constant PASS_EVENT_DAY => dualvar (3, 'day'); | 
|  | 16 |  |  |  |  | 34 |  | 
|  | 16 |  |  |  |  | 1090 |  | 
| 1551 | 16 |  |  | 16 |  | 126 | use constant PASS_EVENT_RISE => dualvar (4, 'rise'); | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 1029 |  | 
| 1552 | 16 |  |  | 16 |  | 105 | use constant PASS_EVENT_MAX => dualvar (5, 'max'); | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 935 |  | 
| 1553 | 16 |  |  | 16 |  | 113 | use constant PASS_EVENT_SET => dualvar (6, 'set'); | 
|  | 16 |  |  |  |  | 49 |  | 
|  | 16 |  |  |  |  | 1017 |  | 
| 1554 | 16 |  |  | 16 |  | 101 | use constant PASS_EVENT_APPULSE => dualvar (7, 'apls'); | 
|  | 16 |  |  |  |  | 54 |  | 
|  | 16 |  |  |  |  | 1169 |  | 
| 1555 | 16 |  |  | 16 |  | 107 | use constant PASS_EVENT_START => dualvar( 11, 'start' ); | 
|  | 16 |  |  |  |  | 37 |  | 
|  | 16 |  |  |  |  | 953 |  | 
| 1556 | 16 |  |  | 16 |  | 110 | use constant PASS_EVENT_END => dualvar( 12, 'end' ); | 
|  | 16 |  |  |  |  | 29 |  | 
|  | 16 |  |  |  |  | 950 |  | 
| 1557 | 16 |  |  | 16 |  | 107 | use constant PASS_EVENT_BRIGHTEST => dualvar( 13, 'brgt' ); | 
|  | 16 |  |  |  |  | 87 |  | 
|  | 16 |  |  |  |  | 911 |  | 
| 1558 |  |  |  |  |  |  |  | 
| 1559 | 16 |  |  | 16 |  | 97 | use constant PASS_VARIANT_VISIBLE_EVENTS => 0x01; | 
|  | 16 |  |  |  |  | 68 |  | 
|  | 16 |  |  |  |  | 860 |  | 
| 1560 | 16 |  |  | 16 |  | 106 | use constant PASS_VARIANT_FAKE_MAX	=> 0x02; | 
|  | 16 |  |  |  |  | 35 |  | 
|  | 16 |  |  |  |  | 743 |  | 
| 1561 | 16 |  |  | 16 |  | 95 | use constant PASS_VARIANT_START_END	=> 0x04; | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 805 |  | 
| 1562 | 16 |  |  | 16 |  | 111 | use constant PASS_VARIANT_NO_ILLUMINATION => 0x08; | 
|  | 16 |  |  |  |  | 34 |  | 
|  | 16 |  |  |  |  | 802 |  | 
| 1563 | 16 |  |  | 16 |  | 96 | use constant PASS_VARIANT_BRIGHTEST	=> 0x10; | 
|  | 16 |  |  |  |  | 43 |  | 
|  | 16 |  |  |  |  | 802 |  | 
| 1564 | 16 |  |  | 16 |  | 95 | use constant PASS_VARIANT_TRUNCATE	=> 0x20; | 
|  | 16 |  |  |  |  | 30 |  | 
|  | 16 |  |  |  |  | 861 |  | 
| 1565 | 16 |  |  | 16 |  | 108 | use constant PASS_VARIANT_NONE => 0x00;		# Must be 0. | 
|  | 16 |  |  |  |  | 43 |  | 
|  | 16 |  |  |  |  | 1514 |  | 
| 1566 |  |  |  |  |  |  |  | 
| 1567 |  |  |  |  |  |  | my @pass_variant_mask = ( | 
| 1568 |  |  |  |  |  |  | PASS_VARIANT_NO_ILLUMINATION | PASS_VARIANT_START_END | | 
| 1569 |  |  |  |  |  |  | PASS_VARIANT_BRIGHTEST | PASS_VARIANT_TRUNCATE, | 
| 1570 |  |  |  |  |  |  | PASS_VARIANT_VISIBLE_EVENTS | PASS_VARIANT_FAKE_MAX | | 
| 1571 |  |  |  |  |  |  | PASS_VARIANT_START_END | PASS_VARIANT_BRIGHTEST | | 
| 1572 |  |  |  |  |  |  | PASS_VARIANT_TRUNCATE, | 
| 1573 |  |  |  |  |  |  | ); | 
| 1574 |  |  |  |  |  |  |  | 
| 1575 | 16 |  |  | 16 |  | 129 | use constant SCREENING_HORIZON_OFFSET => deg2rad( -3 ); | 
|  | 16 |  |  |  |  | 31 |  | 
|  | 16 |  |  |  |  | 86 |  | 
| 1576 |  |  |  |  |  |  |  | 
| 1577 |  |  |  |  |  |  | # *****	Promise Astro::Coord::ECI::TLE::Set that pass() only uses the | 
| 1578 |  |  |  |  |  |  | # *****	public interface. That way pass() will get the Set object, | 
| 1579 |  |  |  |  |  |  | # *****	and will work if we have more than one set of elements for the | 
| 1580 |  |  |  |  |  |  | # *****	body, even if we switch element sets in the middle of a pass. | 
| 1581 |  |  |  |  |  |  |  | 
| 1582 |  |  |  |  |  |  | *_nodelegate_pass = \&pass; | 
| 1583 |  |  |  |  |  |  |  | 
| 1584 |  |  |  |  |  |  | # The following method is not supported, and may be changed or retracted | 
| 1585 |  |  |  |  |  |  | # at any time without notice. Its purpose in life is to provide a handle | 
| 1586 |  |  |  |  |  |  | # by which the experimental and unreleased Astro::Coord::ECI::Points | 
| 1587 |  |  |  |  |  |  | # objects can manipulate the the start and end times of the pass | 
| 1588 |  |  |  |  |  |  | # calculation. | 
| 1589 |  |  |  |  |  |  | sub __default_pass_times { | 
| 1590 | 14 |  |  | 14 |  | 38 | my ( undef, $start, $end ) = @_;	# Invocant unused | 
| 1591 | 14 | 50 |  |  |  | 40 | defined $start | 
| 1592 |  |  |  |  |  |  | or $start = time; | 
| 1593 | 14 | 50 |  |  |  | 36 | defined $end | 
| 1594 |  |  |  |  |  |  | or $end = $start + 7 * SECSPERDAY; | 
| 1595 | 14 |  |  |  |  | 34 | return ( $start, $end ); | 
| 1596 |  |  |  |  |  |  | } | 
| 1597 |  |  |  |  |  |  |  | 
| 1598 |  |  |  |  |  |  | sub pass { | 
| 1599 | 14 |  |  | 14 | 1 | 1000 | my @args = __default_station( @_ ); | 
| 1600 | 14 |  |  |  |  | 38 | my @sky; | 
| 1601 |  |  |  |  |  |  | ARRAY_REF eq ref $args[-1] | 
| 1602 | 14 | 100 |  |  |  | 55 | and @sky = @{pop @args}; | 
|  | 12 |  |  |  |  | 33 |  | 
| 1603 | 14 |  |  |  |  | 33 | my $tle = shift @args; | 
| 1604 | 14 |  |  |  |  | 27 | my $sta = shift @args; | 
| 1605 |  |  |  |  |  |  |  | 
| 1606 |  |  |  |  |  |  | # We give subclasses a way of specifying their own default times. If | 
| 1607 |  |  |  |  |  |  | # an undefined end time is returned, the subclass is stating that | 
| 1608 |  |  |  |  |  |  | # there are no passes in the given range, and we simply return. | 
| 1609 | 14 |  |  |  |  | 69 | my ( $pass_start, $pass_end ) = $tle->__default_pass_times( | 
| 1610 |  |  |  |  |  |  | splice @args, 0, 2 ); | 
| 1611 | 14 | 50 |  |  |  | 47 | defined $pass_start | 
| 1612 |  |  |  |  |  |  | or return; | 
| 1613 |  |  |  |  |  |  |  | 
| 1614 | 14 | 50 |  |  |  | 38 | $pass_end >= $pass_start or croak < | 
| 1615 |  |  |  |  |  |  | Error - End time must be after start time. | 
| 1616 |  |  |  |  |  |  | eod | 
| 1617 |  |  |  |  |  |  |  | 
| 1618 | 14 |  |  |  |  | 62 | $pass_start = $tle->max_effective_date($pass_start); | 
| 1619 | 14 | 50 |  |  |  | 52 | $pass_start <= $pass_end or return; | 
| 1620 |  |  |  |  |  |  |  | 
| 1621 | 14 |  |  |  |  | 56 | my @lighting = ( | 
| 1622 |  |  |  |  |  |  | PASS_EVENT_SHADOWED, | 
| 1623 |  |  |  |  |  |  | PASS_EVENT_LIT, | 
| 1624 |  |  |  |  |  |  | PASS_EVENT_DAY, | 
| 1625 |  |  |  |  |  |  | ); | 
| 1626 | 14 |  |  |  |  | 43 | my $verbose = $tle->get ('interval'); | 
| 1627 | 14 |  |  |  |  | 38 | my $pass_step = 60; | 
| 1628 | 14 |  |  |  |  | 36 | my $horizon = $tle->get ('horizon'); | 
| 1629 | 14 | 50 |  |  |  | 37 | my $effective_horizon = $tle->get ('geometric') ? 0 : $horizon; | 
| 1630 | 14 |  |  |  |  | 45 | my $pass_threshold = $tle->get( 'pass_threshold' ); | 
| 1631 | 14 |  |  |  |  | 33 | my $twilight = $tle->get ('twilight'); | 
| 1632 | 14 |  |  |  |  | 36 | my $want_visible = $tle->get ('visible'); | 
| 1633 | 14 |  |  |  |  | 34 | my $appulse_dist = $tle->get ('appulse'); | 
| 1634 | 14 |  |  |  |  | 35 | my $debug = $tle->get ('debug'); | 
| 1635 | 14 | 100 |  |  |  | 47 | my $pass_variant = $tle->get( 'pass_variant' ) & | 
| 1636 |  |  |  |  |  |  | $pass_variant_mask[ $want_visible ? 1 : 0 ]; | 
| 1637 | 14 | 50 |  |  |  | 42 | defined $tle->get( 'intrinsic_magnitude' ) | 
| 1638 |  |  |  |  |  |  | or $pass_variant &= ~ PASS_VARIANT_BRIGHTEST; | 
| 1639 | 14 |  |  |  |  | 44 | my $truncate = $pass_variant & PASS_VARIANT_TRUNCATE; | 
| 1640 | 14 | 100 | 66 |  |  | 57 | defined $pass_threshold | 
| 1641 |  |  |  |  |  |  | and $pass_threshold > $horizon | 
| 1642 |  |  |  |  |  |  | or $pass_threshold = $horizon; | 
| 1643 |  |  |  |  |  |  |  | 
| 1644 |  |  |  |  |  |  | # We need the number of radians the satellite travels in a minute so | 
| 1645 |  |  |  |  |  |  | # we can be slightly conservative determining whether the satellite | 
| 1646 |  |  |  |  |  |  | # might be lit while screening for a pass. | 
| 1647 |  |  |  |  |  |  | # TODO For something not in orbit the period should be undefined. | 
| 1648 |  |  |  |  |  |  | # But we might call pass() on it anyway because something like a | 
| 1649 |  |  |  |  |  |  | # sounding rocket would still rise and set. What we have at the | 
| 1650 |  |  |  |  |  |  | # moment is a total crock, but until I can figure out something | 
| 1651 |  |  |  |  |  |  | # better ... | 
| 1652 | 14 |  |  |  |  | 65 | my $period = $tle->period(); | 
| 1653 |  |  |  |  |  |  | # TODO the next statement is the crock referred to just above | 
| 1654 | 14 | 50 |  |  |  | 54 | defined $period | 
| 1655 |  |  |  |  |  |  | or $period = 90 * 60;	# Pretend we're in a 90 min orbit | 
| 1656 | 14 |  |  |  |  | 39 | my $min_sun_elev_from_sat = - TWOPI / $period * 60; | 
| 1657 |  |  |  |  |  |  |  | 
| 1658 |  |  |  |  |  |  | # We also want to be slightly conservative when deciding whether the | 
| 1659 |  |  |  |  |  |  | # satellite passes above the horizon. Since the above is clearly too | 
| 1660 |  |  |  |  |  |  | # much (since at its maximum elevation the apparent path of the | 
| 1661 |  |  |  |  |  |  | # satellite is horizontal) we reduce it using a piece of pure | 
| 1662 |  |  |  |  |  |  | # ad-hocery. | 
| 1663 | 14 |  |  |  |  | 33 | my $screening_horizon = $horizon + SCREENING_HORIZON_OFFSET; | 
| 1664 | 14 | 50 |  |  |  | 76 | $effective_horizon < $screening_horizon | 
| 1665 |  |  |  |  |  |  | and $screening_horizon = $effective_horizon; | 
| 1666 |  |  |  |  |  |  |  | 
| 1667 |  |  |  |  |  |  | #	We need the sun at some point, maybe | 
| 1668 |  |  |  |  |  |  |  | 
| 1669 | 14 |  |  |  |  | 30 | my ( $sun, $suntim, $dawn, $sun_screen, $sun_limit ); | 
| 1670 | 14 | 100 |  |  |  | 34 | if ( $pass_variant & PASS_VARIANT_NO_ILLUMINATION ) { | 
| 1671 | 1 |  |  |  |  | 2 | $suntim = $sun_screen = $sun_limit = $pass_end + SECSPERDAY; | 
| 1672 | 1 |  |  |  |  | 3 | $dawn = 1; | 
| 1673 |  |  |  |  |  |  | } else { | 
| 1674 | 13 |  |  |  |  | 27 | $sun = $tle->get( 'sun' ); | 
| 1675 | 13 |  |  |  |  | 54 | ( $suntim, $dawn, $sun_screen, $sun_limit ) = | 
| 1676 |  |  |  |  |  |  | _next_elevation_screen( $sta->universal( $pass_start ), | 
| 1677 |  |  |  |  |  |  | $pass_step, $sun, $twilight ); | 
| 1678 |  |  |  |  |  |  | } | 
| 1679 |  |  |  |  |  |  |  | 
| 1680 |  |  |  |  |  |  | #	For each time to be covered | 
| 1681 |  |  |  |  |  |  |  | 
| 1682 | 14 |  |  |  |  | 33 | my $step = $pass_step; | 
| 1683 | 14 |  |  |  |  | 33 | my $bigstep = 5 * $step; | 
| 1684 | 14 |  |  |  |  | 24 | my $littlestep = $step; | 
| 1685 | 14 |  |  |  |  | 27 | my $end = $pass_end; | 
| 1686 | 14 | 100 |  |  |  | 41 | $truncate | 
| 1687 |  |  |  |  |  |  | and $end += $littlestep; | 
| 1688 | 14 |  |  |  |  | 41 | my @info;	# Information on an individual pass. | 
| 1689 |  |  |  |  |  |  | my @passes;	# Accumulated informtion on all passes. | 
| 1690 | 14 |  |  |  |  | 0 | my $visible; | 
| 1691 | 14 |  |  |  |  | 58 | for (my $time = $pass_start; $time <= $end; $time += $step) { | 
| 1692 |  |  |  |  |  |  |  | 
| 1693 |  |  |  |  |  |  | #	If the current sun event has occurred, handle it and calculate | 
| 1694 |  |  |  |  |  |  | #	the next one. | 
| 1695 |  |  |  |  |  |  |  | 
| 1696 | 41453 | 100 |  |  |  | 69304 | if ( $time >= $sun_limit ) { | 
| 1697 | 82 |  |  |  |  | 392 | ( $suntim, $dawn, $sun_screen, $sun_limit ) = | 
| 1698 |  |  |  |  |  |  | _next_elevation_screen( $sta->universal( $suntim ), | 
| 1699 |  |  |  |  |  |  | $pass_step, $sun, $twilight ); | 
| 1700 |  |  |  |  |  |  | } | 
| 1701 |  |  |  |  |  |  |  | 
| 1702 |  |  |  |  |  |  | #	Skip if the sun is up. We set the step size small, because we | 
| 1703 |  |  |  |  |  |  | #	are not actually tracking the satellite so we do not know what | 
| 1704 |  |  |  |  |  |  | #	the appropriate size is. | 
| 1705 |  |  |  |  |  |  |  | 
| 1706 |  |  |  |  |  |  | $want_visible | 
| 1707 |  |  |  |  |  |  | and	not @info | 
| 1708 |  |  |  |  |  |  | and not $dawn | 
| 1709 |  |  |  |  |  |  | and $time < $sun_screen | 
| 1710 | 41453 | 100 | 100 |  |  | 174643 | and do { | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 1711 | 28770 |  |  |  |  | 35574 | $step = $littlestep; | 
| 1712 | 28770 |  |  |  |  | 50136 | next; | 
| 1713 |  |  |  |  |  |  | }; | 
| 1714 |  |  |  |  |  |  |  | 
| 1715 |  |  |  |  |  |  | #	Calculate azimuth and elevation. | 
| 1716 |  |  |  |  |  |  |  | 
| 1717 | 12683 |  |  |  |  | 33034 | my ($azm, $elev, $rng) = $sta->azel ($tle->universal ($time)); | 
| 1718 |  |  |  |  |  |  |  | 
| 1719 |  |  |  |  |  |  | #	Adjust the step size based on how far the body is below the | 
| 1720 |  |  |  |  |  |  | #	horizon. | 
| 1721 |  |  |  |  |  |  |  | 
| 1722 | 12683 | 100 |  |  |  | 32404 | $step = $elev < -.4 ? $bigstep : $littlestep; | 
| 1723 |  |  |  |  |  |  |  | 
| 1724 |  |  |  |  |  |  | #	If the body is below the horizon, we check for accumulated data, | 
| 1725 |  |  |  |  |  |  | #	handle it if any, clear it, and on to the next iteration. We | 
| 1726 |  |  |  |  |  |  | #	have to make the check on effective horizon as well as screening | 
| 1727 |  |  |  |  |  |  | #	horizon, because maybe we are at the very end of the prediction | 
| 1728 |  |  |  |  |  |  | #	period and the satellite makes it below the effective horizon | 
| 1729 |  |  |  |  |  |  | #	but not the screening horizon before the end of the prediction | 
| 1730 |  |  |  |  |  |  | #	period. Sigh. | 
| 1731 |  |  |  |  |  |  |  | 
| 1732 | 12683 | 100 | 66 |  |  | 32337 | if ( $elev < $screening_horizon | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 1733 |  |  |  |  |  |  | || @info && $elev < $effective_horizon && | 
| 1734 |  |  |  |  |  |  | $info[-1]{elevation} >= $effective_horizon | 
| 1735 |  |  |  |  |  |  | || $truncate && $time >= $pass_end | 
| 1736 |  |  |  |  |  |  | ) { | 
| 1737 | 12022 | 100 |  |  |  | 22754 | @info = () unless $visible; | 
| 1738 | 12022 | 100 |  |  |  | 38589 | next unless @info; | 
| 1739 |  |  |  |  |  |  |  | 
| 1740 |  |  |  |  |  |  | #	    We may have skipped part of the pass because it began in | 
| 1741 |  |  |  |  |  |  | #	    daylight or before the official beginning of the prediction | 
| 1742 |  |  |  |  |  |  | #	    period. Pick up that part now. | 
| 1743 |  |  |  |  |  |  |  | 
| 1744 |  |  |  |  |  |  | {	# Single-iteration loop. | 
| 1745 | 113 |  |  |  |  | 209 | my $time = $info[0]{time} - $step; | 
|  | 113 |  |  |  |  | 298 |  | 
| 1746 | 113 | 100 | 100 |  |  | 411 | $truncate | 
| 1747 |  |  |  |  |  |  | and $time < $pass_start | 
| 1748 |  |  |  |  |  |  | and last; | 
| 1749 | 112 |  |  |  |  | 393 | my ( $try_azm, $try_elev, $try_rng ) = $sta->azel ( | 
| 1750 |  |  |  |  |  |  | $tle->universal( $time ) ); | 
| 1751 | 112 | 50 |  |  |  | 506 | last if $try_elev < $effective_horizon; | 
| 1752 | 0 | 0 |  |  |  | 0 | my $litup = $time < $suntim ? 2 - $dawn : 1 + $dawn; | 
| 1753 | 0 | 0 | 0 |  |  | 0 | 1 == $litup | 
| 1754 |  |  |  |  |  |  | and not $tle->illuminated( $time ) | 
| 1755 |  |  |  |  |  |  | and $litup = 0; | 
| 1756 | 0 |  |  |  |  | 0 | unshift @info, { | 
| 1757 |  |  |  |  |  |  | azimuth => $try_azm, | 
| 1758 |  |  |  |  |  |  | elevation => $try_elev, | 
| 1759 |  |  |  |  |  |  | event => PASS_EVENT_NONE, | 
| 1760 |  |  |  |  |  |  | illumination => $lighting[$litup], | 
| 1761 |  |  |  |  |  |  | range => $try_rng, | 
| 1762 |  |  |  |  |  |  | time => $time, | 
| 1763 |  |  |  |  |  |  | }; | 
| 1764 | 0 |  |  |  |  | 0 | redo; | 
| 1765 |  |  |  |  |  |  | } | 
| 1766 |  |  |  |  |  |  |  | 
| 1767 |  |  |  |  |  |  | # Compute the exact events. | 
| 1768 |  |  |  |  |  |  |  | 
| 1769 | 113 |  |  |  |  | 211 | my @time; | 
| 1770 |  |  |  |  |  |  |  | 
| 1771 |  |  |  |  |  |  | # Compute exact max | 
| 1772 |  |  |  |  |  |  |  | 
| 1773 |  |  |  |  |  |  | =begin comment | 
| 1774 |  |  |  |  |  |  |  | 
| 1775 |  |  |  |  |  |  | { | 
| 1776 |  |  |  |  |  |  | my @try; | 
| 1777 |  |  |  |  |  |  | if ( @info > 1 ) { | 
| 1778 |  |  |  |  |  |  | @try = ( | 
| 1779 |  |  |  |  |  |  | [ $info[0]{time}, $sta->azel( $tle->universal( | 
| 1780 |  |  |  |  |  |  | $info[0]{time} ) ) ], | 
| 1781 |  |  |  |  |  |  | [ $info[-1]{time}, $sta->azel( $tle->universal( | 
| 1782 |  |  |  |  |  |  | $info[-1]{time} ) ) ], | 
| 1783 |  |  |  |  |  |  | ); | 
| 1784 |  |  |  |  |  |  | } else { | 
| 1785 |  |  |  |  |  |  | my $trial_time = $info[0]{time} - 30; | 
| 1786 |  |  |  |  |  |  | push @try, [ $trial_time, $sta->azel( | 
| 1787 |  |  |  |  |  |  | $tle->universal( $trial_time ) ) ]; | 
| 1788 |  |  |  |  |  |  | $trial_time += 60; | 
| 1789 |  |  |  |  |  |  | push @try, [ $trial_time, $sta->azel( | 
| 1790 |  |  |  |  |  |  | $tle->universal( $trial_time ) ) ]; | 
| 1791 |  |  |  |  |  |  | } | 
| 1792 |  |  |  |  |  |  |  | 
| 1793 |  |  |  |  |  |  | while ( $try[1][0] - $try[0][0] > 0.01 ) { | 
| 1794 |  |  |  |  |  |  | my $middle = ( $try[0][0] + $try[1][0] ) / 2; | 
| 1795 |  |  |  |  |  |  | my $inx = $try[0][2] > $try[1][2] ? 1 : 0; | 
| 1796 |  |  |  |  |  |  | splice @try, $inx, 1, [ $middle, $sta->azel( | 
| 1797 |  |  |  |  |  |  | $tle->universal( $middle ) ) ]; | 
| 1798 |  |  |  |  |  |  | } | 
| 1799 |  |  |  |  |  |  |  | 
| 1800 |  |  |  |  |  |  | push @time, [ floor( $try[1][0] + .5 ), PASS_EVENT_MAX ]; | 
| 1801 |  |  |  |  |  |  |  | 
| 1802 |  |  |  |  |  |  | } | 
| 1803 |  |  |  |  |  |  |  | 
| 1804 |  |  |  |  |  |  | =end comment | 
| 1805 |  |  |  |  |  |  |  | 
| 1806 |  |  |  |  |  |  | =cut | 
| 1807 |  |  |  |  |  |  |  | 
| 1808 |  |  |  |  |  |  | my ( $trial_start, $trial_finish ) = | 
| 1809 |  |  |  |  |  |  | ( $info[0]{time} - $pass_step, | 
| 1810 | 113 |  |  |  |  | 466 | $info[-1]{time} + $pass_step | 
| 1811 |  |  |  |  |  |  | ); | 
| 1812 | 113 | 100 |  |  |  | 327 | $truncate | 
| 1813 |  |  |  |  |  |  | and ( $trial_start, $trial_finish ) = ( | 
| 1814 |  |  |  |  |  |  | max( $trial_start, $pass_start ), | 
| 1815 |  |  |  |  |  |  | min( $trial_finish, $pass_end ) | 
| 1816 |  |  |  |  |  |  | ); | 
| 1817 |  |  |  |  |  |  | my $culmination = find_first_true( $trial_start, | 
| 1818 |  |  |  |  |  |  | $trial_finish, | 
| 1819 | 983 |  |  | 983 |  | 2885 | sub { ( $sta->azel( $tle->universal( $_[0] ) ) )[1] > | 
| 1820 |  |  |  |  |  |  | ( $sta->azel( $tle->universal( $_[0] + 1 ) ) )[1] | 
| 1821 | 113 |  |  |  |  | 1205 | }); | 
| 1822 | 113 |  |  |  |  | 792 | push @time, [ $culmination, PASS_EVENT_MAX ]; | 
| 1823 |  |  |  |  |  |  |  | 
| 1824 |  |  |  |  |  |  | # Compute exact rise and set. | 
| 1825 |  |  |  |  |  |  |  | 
| 1826 |  |  |  |  |  |  | $truncate | 
| 1827 |  |  |  |  |  |  | or ( $trial_start, $trial_finish ) = ( | 
| 1828 | 113 | 100 |  |  |  | 715 | $info[0]{time} - $step, $info[-1]{time} + $step ); | 
| 1829 |  |  |  |  |  |  | my $sat_rise = find_first_true( $trial_start, | 
| 1830 |  |  |  |  |  |  | $culmination, | 
| 1831 | 844 |  |  | 844 |  | 2502 | sub { ( $sta->azel( $tle->universal( $_[0] ) ) )[1] >= | 
| 1832 |  |  |  |  |  |  | $effective_horizon | 
| 1833 |  |  |  |  |  |  | }, | 
| 1834 | 113 |  |  |  |  | 869 | ); | 
| 1835 |  |  |  |  |  |  | my $sat_set = find_first_true ( $culmination, | 
| 1836 |  |  |  |  |  |  | $trial_finish, | 
| 1837 | 878 |  |  | 878 |  | 2556 | sub { ( $sta->azel( $tle->universal( $_[0] ) ) )[1] < | 
| 1838 |  |  |  |  |  |  | $effective_horizon | 
| 1839 |  |  |  |  |  |  | }, | 
| 1840 | 113 |  |  |  |  | 1029 | ); | 
| 1841 | 113 |  |  |  |  | 731 | push @time, | 
| 1842 |  |  |  |  |  |  | [ $sat_rise, PASS_EVENT_RISE ], | 
| 1843 |  |  |  |  |  |  | [ $sat_set, PASS_EVENT_SET ], | 
| 1844 |  |  |  |  |  |  | ; | 
| 1845 |  |  |  |  |  |  |  | 
| 1846 | 113 | 50 |  |  |  | 436 | warn < | 
| 1847 |  |  |  |  |  |  |  | 
| 1848 | 0 |  |  |  |  | 0 | Debug - Computed @{[strftime '%d-%b-%Y %H:%M:%S', localtime $time[0][0] | 
| 1849 |  |  |  |  |  |  | ]} $time[0][1] | 
| 1850 | 0 |  |  |  |  | 0 | @{[strftime '%d-%b-%Y %H:%M:%S', localtime $time[1][0] | 
| 1851 |  |  |  |  |  |  | ]} $time[1][1] | 
| 1852 | 0 |  |  |  |  | 0 | @{[strftime '%d-%b-%Y %H:%M:%S', localtime $time[2][0] | 
| 1853 |  |  |  |  |  |  | ]} $time[2][1] | 
| 1854 |  |  |  |  |  |  | eod | 
| 1855 |  |  |  |  |  |  |  | 
| 1856 |  |  |  |  |  |  | # Because we relaxed the detection criteria to be sure we | 
| 1857 |  |  |  |  |  |  | # caught all passes, we may have a pass that ended before | 
| 1858 |  |  |  |  |  |  | # the prediction interval started. Reject that here. | 
| 1859 |  |  |  |  |  |  |  | 
| 1860 |  |  |  |  |  |  | $sat_set < $pass_start | 
| 1861 | 113 | 50 |  |  |  | 467 | and do { | 
| 1862 | 0 |  |  |  |  | 0 | @info = (); | 
| 1863 | 0 |  |  |  |  | 0 | next; | 
| 1864 |  |  |  |  |  |  | }; | 
| 1865 |  |  |  |  |  |  |  | 
| 1866 |  |  |  |  |  |  | # Clear the original data. | 
| 1867 |  |  |  |  |  |  |  | 
| 1868 | 113 |  |  |  |  | 1450 | @info = (); | 
| 1869 |  |  |  |  |  |  |  | 
| 1870 |  |  |  |  |  |  | # Generate the full data for the exact events. | 
| 1871 |  |  |  |  |  |  |  | 
| 1872 | 113 |  |  |  |  | 319 | my ($suntim, $dawn); | 
| 1873 | 113 | 50 |  |  |  | 391 | warn "Contents of \@time: ", Dumper (\@time)	## no critic (RequireCarping) | 
| 1874 |  |  |  |  |  |  | if $debug; | 
| 1875 | 113 |  |  |  |  | 812 | foreach (sort {$a->[0] <=> $b->[0]} @time) { | 
|  | 339 |  |  |  |  | 1050 |  | 
| 1876 | 339 |  |  |  |  | 1093 | my ( $time, $evnt_name, @extra ) = @$_; | 
| 1877 | 339 |  |  |  |  | 1123 | my ($azm, $elev, $rng) = $sta->azel ( | 
| 1878 |  |  |  |  |  |  | $tle->universal ($time)); | 
| 1879 | 339 |  |  |  |  | 749 | my @illumination; | 
| 1880 | 339 | 100 |  |  |  | 1077 | if ( $sun ) { | 
| 1881 | 219 | 100 | 66 |  |  | 1077 | ($suntim, $dawn) = | 
| 1882 |  |  |  |  |  |  | $sta->universal ($time)->next_elevation ($sun, | 
| 1883 |  |  |  |  |  |  | $twilight) | 
| 1884 |  |  |  |  |  |  | if !$suntim || $time >= $suntim; | 
| 1885 | 219 | 50 |  |  |  | 664 | my $litup = $time < $suntim ? 2 - $dawn : 1 + $dawn; | 
| 1886 | 219 | 100 | 66 |  |  | 932 | 1 == $litup | 
| 1887 |  |  |  |  |  |  | and not $tle->illuminated( $time ) | 
| 1888 |  |  |  |  |  |  | and $litup = 0; | 
| 1889 | 219 |  |  |  |  | 859 | push @illumination, illumination => $lighting[$litup]; | 
| 1890 |  |  |  |  |  |  | } | 
| 1891 | 339 |  |  |  |  | 3223 | push @info, { | 
| 1892 |  |  |  |  |  |  | azimuth => $azm, | 
| 1893 |  |  |  |  |  |  | body => $tle, | 
| 1894 |  |  |  |  |  |  | elevation => $elev, | 
| 1895 |  |  |  |  |  |  | event => $evnt_name, | 
| 1896 |  |  |  |  |  |  | range => $rng, | 
| 1897 |  |  |  |  |  |  | station => $sta, | 
| 1898 |  |  |  |  |  |  | time => $time, | 
| 1899 |  |  |  |  |  |  | @illumination, | 
| 1900 |  |  |  |  |  |  | @extra, | 
| 1901 |  |  |  |  |  |  | }; | 
| 1902 |  |  |  |  |  |  | } | 
| 1903 |  |  |  |  |  |  |  | 
| 1904 |  |  |  |  |  |  | # Compute illumination changes | 
| 1905 |  |  |  |  |  |  |  | 
| 1906 | 113 | 100 |  |  |  | 452 | if ( $sun ) { | 
| 1907 | 73 |  |  |  |  | 187 | my @illum; | 
| 1908 |  |  |  |  |  |  | my $prior; | 
| 1909 | 73 |  |  |  |  | 193 | foreach my $evt ( @info ) { | 
| 1910 | 219 | 100 |  |  |  | 570 | $prior or next; | 
| 1911 |  |  |  |  |  |  | $prior->{illumination} == $evt->{illumination} | 
| 1912 | 146 | 100 |  |  |  | 438 | and next; | 
| 1913 |  |  |  |  |  |  | my ($suntim, $dawn) = | 
| 1914 | 36 |  |  |  |  | 143 | $sta->universal ($prior->{time})-> | 
| 1915 |  |  |  |  |  |  | next_elevation ($sun, $twilight); | 
| 1916 |  |  |  |  |  |  | my $time = | 
| 1917 |  |  |  |  |  |  | find_first_true ($prior->{time}, $evt->{time}, | 
| 1918 |  |  |  |  |  |  | sub { | 
| 1919 | 282 | 50 |  | 282 |  | 639 | my $litup = $_[0] < $suntim ? | 
| 1920 |  |  |  |  |  |  | 2 - $dawn : 1 + $dawn; | 
| 1921 | 282 | 100 | 66 |  |  | 1001 | 1 == $litup | 
| 1922 |  |  |  |  |  |  | and not $tle->illuminated( $_[0] ) | 
| 1923 |  |  |  |  |  |  | and $litup = 0; | 
| 1924 |  |  |  |  |  |  | $lighting[$litup] == $evt->{illumination} | 
| 1925 | 36 |  |  |  |  | 474 | }); | 
|  | 282 |  |  |  |  | 1615 |  | 
| 1926 | 36 |  |  |  |  | 241 | my ($azm, $elev, $rng) = $sta->azel ( | 
| 1927 |  |  |  |  |  |  | $tle->universal ($time)); | 
| 1928 |  |  |  |  |  |  | push @illum, { | 
| 1929 |  |  |  |  |  |  | azimuth => $azm, | 
| 1930 |  |  |  |  |  |  | body => $tle, | 
| 1931 |  |  |  |  |  |  | elevation => $elev, | 
| 1932 |  |  |  |  |  |  | event => $evt->{illumination}, | 
| 1933 |  |  |  |  |  |  | illumination => $evt->{illumination}, | 
| 1934 | 36 |  |  |  |  | 506 | range => $rng, | 
| 1935 |  |  |  |  |  |  | station => $sta, | 
| 1936 |  |  |  |  |  |  | time => $time, | 
| 1937 |  |  |  |  |  |  | }; | 
| 1938 |  |  |  |  |  |  | } continue { | 
| 1939 | 219 |  |  |  |  | 519 | $prior = $evt; | 
| 1940 |  |  |  |  |  |  | } | 
| 1941 | 73 |  |  |  |  | 191 | push @info, @illum; | 
| 1942 |  |  |  |  |  |  | } | 
| 1943 |  |  |  |  |  |  |  | 
| 1944 |  |  |  |  |  |  | # Do not record this pass if it turns out not to contain | 
| 1945 |  |  |  |  |  |  | # any points that meet the recording criteria. | 
| 1946 |  |  |  |  |  |  |  | 
| 1947 |  |  |  |  |  |  | eval {	# So I can return(). | 
| 1948 | 113 |  |  |  |  | 261 | foreach my $event ( @info ) { | 
| 1949 | 319 | 100 |  |  |  | 831 | $event->{elevation} < $pass_threshold | 
| 1950 |  |  |  |  |  |  | and next; | 
| 1951 |  |  |  |  |  |  | not $want_visible | 
| 1952 | 50 | 100 | 100 |  |  | 281 | or $event->{illumination} == PASS_EVENT_LIT | 
| 1953 |  |  |  |  |  |  | or next; | 
| 1954 | 47 |  |  |  |  | 180 | return 1; | 
| 1955 |  |  |  |  |  |  | } | 
| 1956 | 66 |  |  |  |  | 244 | return 0; | 
| 1957 | 113 | 100 |  |  |  | 252 | } or do { | 
| 1958 | 66 |  |  |  |  | 430 | @info = (); | 
| 1959 | 66 |  |  |  |  | 517 | next; | 
| 1960 |  |  |  |  |  |  | }; | 
| 1961 |  |  |  |  |  |  |  | 
| 1962 |  |  |  |  |  |  | # Put the events created thus far into order. | 
| 1963 |  |  |  |  |  |  |  | 
| 1964 | 47 |  |  |  |  | 263 | @info = sort { $a->{time} <=> $b->{time} } @info; | 
|  | 168 |  |  |  |  | 427 |  | 
| 1965 |  |  |  |  |  |  |  | 
| 1966 |  |  |  |  |  |  | # Compute the brightest moment if desired. | 
| 1967 |  |  |  |  |  |  |  | 
| 1968 | 47 | 50 |  |  |  | 170 | if ( $pass_variant & PASS_VARIANT_BRIGHTEST ) { | 
| 1969 |  |  |  |  |  |  |  | 
| 1970 | 0 |  |  |  |  | 0 | @info = sort { $a->{time} <=> $b->{time} } @info, | 
|  | 0 |  |  |  |  | 0 |  | 
| 1971 |  |  |  |  |  |  | _pass_compute_brightest( $tle, $sta, $sun, \@info ); | 
| 1972 |  |  |  |  |  |  | } | 
| 1973 |  |  |  |  |  |  |  | 
| 1974 |  |  |  |  |  |  | # If we want visible events only | 
| 1975 |  |  |  |  |  |  |  | 
| 1976 | 47 | 100 |  |  |  | 156 | if ( $pass_variant & PASS_VARIANT_VISIBLE_EVENTS ) { | 
| 1977 |  |  |  |  |  |  |  | 
| 1978 |  |  |  |  |  |  | # Filter out anything that does not pass muster | 
| 1979 |  |  |  |  |  |  |  | 
| 1980 | 20 |  |  |  |  | 60 | @info = grep { $_->{illumination} == PASS_EVENT_LIT || | 
| 1981 |  |  |  |  |  |  | $_->{event} == PASS_EVENT_SHADOWED || | 
| 1982 | 70 | 100 | 66 |  |  | 364 | $_->{event} == PASS_EVENT_DAY | 
| 1983 |  |  |  |  |  |  | } @info; | 
| 1984 |  |  |  |  |  |  |  | 
| 1985 |  |  |  |  |  |  | # If we want to fake a max event if that took place in | 
| 1986 |  |  |  |  |  |  | # darkness | 
| 1987 |  |  |  |  |  |  |  | 
| 1988 | 20 | 100 | 100 |  |  | 105 | if ( $pass_variant & PASS_VARIANT_FAKE_MAX && | 
| 1989 | 41 |  |  |  |  | 127 | ! grep { $_->{event} == PASS_EVENT_MAX } @info ) { | 
| 1990 |  |  |  |  |  |  |  | 
| 1991 |  |  |  |  |  |  | # Given that the max got dropped, the fake max is | 
| 1992 |  |  |  |  |  |  | # either the first or the last point. | 
| 1993 |  |  |  |  |  |  |  | 
| 1994 |  |  |  |  |  |  | my ( $dup_inx, $splice_inx ) = | 
| 1995 |  |  |  |  |  |  | $info[0]{elevation} > $info[-1]{elevation} ? | 
| 1996 | 1 | 50 |  |  |  | 9 | ( 0, 1 ) : ( -1, -1 ); | 
| 1997 |  |  |  |  |  |  |  | 
| 1998 |  |  |  |  |  |  | # Shallow clone, and change the event code to max. | 
| 1999 |  |  |  |  |  |  |  | 
| 2000 | 1 |  |  |  |  | 3 | my $max = { %{ $info[$dup_inx] } }; | 
|  | 1 |  |  |  |  | 12 |  | 
| 2001 | 1 |  |  |  |  | 4 | $max->{event} = PASS_EVENT_MAX; | 
| 2002 |  |  |  |  |  |  |  | 
| 2003 |  |  |  |  |  |  | # Insert the max either just after the first, or | 
| 2004 |  |  |  |  |  |  | # just before the last event, as the case may be. | 
| 2005 |  |  |  |  |  |  |  | 
| 2006 | 1 |  |  |  |  | 4 | splice @info, $splice_inx, 0, $max; | 
| 2007 |  |  |  |  |  |  |  | 
| 2008 |  |  |  |  |  |  | } | 
| 2009 |  |  |  |  |  |  | } | 
| 2010 |  |  |  |  |  |  |  | 
| 2011 |  |  |  |  |  |  | # If we want the first and last events to be 'start' and | 
| 2012 |  |  |  |  |  |  | # 'end', willy-nilly, hammer these codes into them. | 
| 2013 |  |  |  |  |  |  |  | 
| 2014 | 47 | 100 |  |  |  | 190 | if ( $pass_variant & PASS_VARIANT_START_END ) { | 
| 2015 | 8 |  |  |  |  | 24 | $info[0]{event} = PASS_EVENT_START; | 
| 2016 | 8 |  |  |  |  | 23 | $info[-1]{event} = PASS_EVENT_END; | 
| 2017 |  |  |  |  |  |  | } | 
| 2018 |  |  |  |  |  |  |  | 
| 2019 |  |  |  |  |  |  | # If PASS_VARIANT_TRUNCATE is in effect, the first and last | 
| 2020 |  |  |  |  |  |  | # events should be 'start' and 'end' IF AND ONLY IF the | 
| 2021 |  |  |  |  |  |  | # satellite is above the horizon at that point AND the time | 
| 2022 |  |  |  |  |  |  | # is at the start or end of the interval. Because the first | 
| 2023 |  |  |  |  |  |  | # event is AFTER its exact time, we need to back up a bit | 
| 2024 |  |  |  |  |  |  | # and recalculate. | 
| 2025 |  |  |  |  |  |  |  | 
| 2026 | 47 | 100 |  |  |  | 146 | if ( $truncate ) { | 
| 2027 | 2 |  |  |  |  | 6 | my $prior = $info[0]{time} - 1; | 
| 2028 | 2 | 100 |  |  |  | 9 | if ( $prior <= $pass_start ) { | 
| 2029 | 1 |  |  |  |  | 5 | my $elevation = ( $sta->azel( | 
| 2030 |  |  |  |  |  |  | $tle->universal( $prior ) ) )[1]; | 
| 2031 |  |  |  |  |  |  | $elevation > $effective_horizon | 
| 2032 | 1 | 50 |  |  |  | 7 | and $info[0]{event} = PASS_EVENT_START; | 
| 2033 |  |  |  |  |  |  | } | 
| 2034 |  |  |  |  |  |  | $info[-1]{elevation} > $effective_horizon | 
| 2035 |  |  |  |  |  |  | and $info[-1]{time} >= $pass_end | 
| 2036 | 2 | 100 | 66 |  |  | 17 | and $info[-1]{event} = PASS_EVENT_END; | 
| 2037 |  |  |  |  |  |  | } | 
| 2038 |  |  |  |  |  |  |  | 
| 2039 |  |  |  |  |  |  | # Pick up the first and last event times, to use to bracket | 
| 2040 |  |  |  |  |  |  | # future calculations. | 
| 2041 |  |  |  |  |  |  |  | 
| 2042 | 47 |  |  |  |  | 110 | my $first_time = $info[0]{time}; | 
| 2043 | 47 |  |  |  |  | 109 | my $last_time = $info[-1]{time}; | 
| 2044 | 47 |  |  |  |  | 112 | my $number_of_events = @info; | 
| 2045 |  |  |  |  |  |  |  | 
| 2046 |  |  |  |  |  |  | # Compute nearest approach to background bodies | 
| 2047 |  |  |  |  |  |  |  | 
| 2048 |  |  |  |  |  |  | # Note (fortuitous discovery) the ISS travels 1.175 | 
| 2049 |  |  |  |  |  |  | # degrees per second at the zenith, so I need better | 
| 2050 |  |  |  |  |  |  | # than 1 second resolution to detect a transit. | 
| 2051 |  |  |  |  |  |  |  | 
| 2052 | 47 |  |  |  |  | 165 | foreach my $body (@sky) { | 
| 2053 |  |  |  |  |  |  | my $when = find_first_true( | 
| 2054 |  |  |  |  |  |  | _pass_bracket_appulse( $sta, $tle, $body, | 
| 2055 |  |  |  |  |  |  | $first_time, $last_time ), | 
| 2056 | 571 |  |  | 571 |  | 1726 | sub {$sta->angle ($body->universal ($_[0]), | 
| 2057 |  |  |  |  |  |  | $tle->universal ($_[0])) < | 
| 2058 |  |  |  |  |  |  | $sta->angle ($body->universal ($_[0] + .1), | 
| 2059 |  |  |  |  |  |  | $tle->universal ($_[0] + .1))}, | 
| 2060 | 45 |  |  |  |  | 236 | .1); | 
| 2061 | 45 |  |  |  |  | 361 | my $angle = | 
| 2062 |  |  |  |  |  |  | $sta->angle ($body->universal ($when), | 
| 2063 |  |  |  |  |  |  | $tle->universal ($when)); | 
| 2064 | 45 | 100 |  |  |  | 254 | next if $angle > $appulse_dist; | 
| 2065 | 12 |  |  |  |  | 49 | my ( $azimuth, $elevation, $range ) = $sta->azel( $tle ); | 
| 2066 | 12 |  |  |  |  | 156 | push @info, { | 
| 2067 |  |  |  |  |  |  | body	=> $tle, | 
| 2068 |  |  |  |  |  |  | event	=> PASS_EVENT_APPULSE, | 
| 2069 |  |  |  |  |  |  | station	=> $sta, | 
| 2070 |  |  |  |  |  |  | time	=> $when, | 
| 2071 |  |  |  |  |  |  | azimuth	=> $azimuth, | 
| 2072 |  |  |  |  |  |  | elevation	=> $elevation, | 
| 2073 |  |  |  |  |  |  | range	=> $range, | 
| 2074 |  |  |  |  |  |  | appulse	=> { | 
| 2075 |  |  |  |  |  |  | angle	=> $angle, | 
| 2076 |  |  |  |  |  |  | body	=> $body, | 
| 2077 |  |  |  |  |  |  | }, | 
| 2078 |  |  |  |  |  |  | _find_illumination( $sun, $when, \@info ), | 
| 2079 |  |  |  |  |  |  | }; | 
| 2080 |  |  |  |  |  |  |  | 
| 2081 | 12 | 50 |  |  |  | 53 | warn <<"EOD" if $debug;	## no critic (RequireCarping) | 
| 2082 | 0 |  |  |  |  | 0 | $time[$#time][1] @{[strftime '%d-%b-%Y %H:%M:%S', | 
| 2083 |  |  |  |  |  |  | localtime $time[$#time][0]]} | 
| 2084 |  |  |  |  |  |  | EOD | 
| 2085 |  |  |  |  |  |  | } | 
| 2086 |  |  |  |  |  |  |  | 
| 2087 |  |  |  |  |  |  | # Add in the intrinsic events if there are any. | 
| 2088 | 47 |  |  |  |  | 216 | foreach my $evt ( | 
| 2089 |  |  |  |  |  |  | $tle->intrinsic_events( $first_time, $last_time ) | 
| 2090 |  |  |  |  |  |  | ) { | 
| 2091 | 0 |  |  |  |  | 0 | my ( $when, $event ) = @{ $evt }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 2092 | 0 |  |  |  |  | 0 | push @info, { | 
| 2093 |  |  |  |  |  |  | body	=> $tle, | 
| 2094 |  |  |  |  |  |  | event	=> $event, | 
| 2095 |  |  |  |  |  |  | station	=> $sta, | 
| 2096 |  |  |  |  |  |  | time	=> $when, | 
| 2097 |  |  |  |  |  |  | _find_illumination( $sun, $when, \@info ), | 
| 2098 |  |  |  |  |  |  | $tle->_find_position( $sta, $when ), | 
| 2099 |  |  |  |  |  |  | }; | 
| 2100 |  |  |  |  |  |  | } | 
| 2101 |  |  |  |  |  |  |  | 
| 2102 |  |  |  |  |  |  | # If we're verbose, calculate the points. | 
| 2103 |  |  |  |  |  |  |  | 
| 2104 | 47 | 100 |  |  |  | 159 | if ( $verbose ) { | 
| 2105 |  |  |  |  |  |  |  | 
| 2106 | 2 |  |  |  |  | 7 | my %events = map { $_->{time} => 1 } @info; | 
|  | 6 |  |  |  |  | 29 |  | 
| 2107 | 2 |  |  |  |  | 17 | for ( my $it = ceil( $first_time ); $it < $last_time; | 
| 2108 |  |  |  |  |  |  | $it += $verbose ) { | 
| 2109 |  |  |  |  |  |  |  | 
| 2110 |  |  |  |  |  |  | # If we already have an event for this time, skip. | 
| 2111 |  |  |  |  |  |  |  | 
| 2112 | 32 | 100 |  |  |  | 80 | $events{$it} and next; | 
| 2113 |  |  |  |  |  |  |  | 
| 2114 |  |  |  |  |  |  | # The next line of code relies on the fact that the | 
| 2115 |  |  |  |  |  |  | # events from rise through max and set are already | 
| 2116 |  |  |  |  |  |  | # in chronological order. Yes, in theory we step off | 
| 2117 |  |  |  |  |  |  | # the end of that part of @info, but in practice we | 
| 2118 |  |  |  |  |  |  | # exit the for loop before we get to that point. | 
| 2119 |  |  |  |  |  |  |  | 
| 2120 | 30 |  |  |  |  | 77 | push @info, { | 
| 2121 |  |  |  |  |  |  | body => $tle, | 
| 2122 |  |  |  |  |  |  | event => PASS_EVENT_NONE, | 
| 2123 |  |  |  |  |  |  | station => $sta, | 
| 2124 |  |  |  |  |  |  | time => $it, | 
| 2125 |  |  |  |  |  |  | _find_illumination( $sun, $it, \@info ), | 
| 2126 |  |  |  |  |  |  | $tle->_find_position( $sta, $it ), | 
| 2127 |  |  |  |  |  |  | }; | 
| 2128 |  |  |  |  |  |  | } | 
| 2129 |  |  |  |  |  |  | } | 
| 2130 |  |  |  |  |  |  |  | 
| 2131 |  |  |  |  |  |  | # Sort the data again if we have added events. | 
| 2132 |  |  |  |  |  |  |  | 
| 2133 |  |  |  |  |  |  | @info > $number_of_events | 
| 2134 | 47 | 100 |  |  |  | 277 | and @info = sort { $a->{time} <=> $b->{time} } @info; | 
|  | 158 |  |  |  |  | 297 |  | 
| 2135 |  |  |  |  |  |  |  | 
| 2136 |  |  |  |  |  |  | #	    Record the data for the pass. | 
| 2137 |  |  |  |  |  |  |  | 
| 2138 | 47 | 50 |  |  |  | 136 | confess < | 
| 2139 |  |  |  |  |  |  | Programming error - \$culmination undefined at end of pass calculation. | 
| 2140 |  |  |  |  |  |  | eod | 
| 2141 | 47 |  |  |  |  | 326 | push @passes, { | 
| 2142 |  |  |  |  |  |  | body => $tle, | 
| 2143 |  |  |  |  |  |  | events => [@info], | 
| 2144 |  |  |  |  |  |  | time => $culmination, | 
| 2145 |  |  |  |  |  |  | }; | 
| 2146 |  |  |  |  |  |  |  | 
| 2147 |  |  |  |  |  |  | #	    Clear out the data. | 
| 2148 |  |  |  |  |  |  |  | 
| 2149 | 47 |  |  |  |  | 143 | @info = (); | 
| 2150 | 47 |  |  |  |  | 106 | $visible = 0; | 
| 2151 | 47 |  |  |  |  | 120 | $culmination = undef; | 
| 2152 | 47 |  |  |  |  | 422 | next; | 
| 2153 |  |  |  |  |  |  | } | 
| 2154 |  |  |  |  |  |  |  | 
| 2155 |  |  |  |  |  |  | {	# Localize | 
| 2156 |  |  |  |  |  |  |  | 
| 2157 |  |  |  |  |  |  | # Calculate whether the body is visible. | 
| 2158 |  |  |  |  |  |  |  | 
| 2159 | 661 |  |  |  |  | 1023 | my @illumination; | 
|  | 661 |  |  |  |  | 991 |  | 
| 2160 | 661 | 100 |  |  |  | 1302 | if ( $sun ) { | 
| 2161 | 415 | 50 |  |  |  | 946 | my $litup = $time < $sun_screen ? 2 - $dawn : 1 + $dawn; | 
| 2162 | 415 |  |  |  |  | 1069 | my $sun_elev_from_sat = $tle->__sun_elev_from_sat( $time ); | 
| 2163 | 415 |  | 66 |  |  | 1442 | $visible ||= $elev > $screening_horizon && ( | 
|  |  |  | 100 |  |  |  |  | 
| 2164 |  |  |  |  |  |  | ! $want_visible || | 
| 2165 |  |  |  |  |  |  | $litup == 1 && $sun_elev_from_sat >= $min_sun_elev_from_sat | 
| 2166 |  |  |  |  |  |  | ); | 
| 2167 | 415 | 50 |  |  |  | 897 | $litup = $time < $suntim ? 2 - $dawn : 1 + $dawn; | 
| 2168 | 415 | 100 | 66 |  |  | 1674 | $litup == 1 | 
| 2169 |  |  |  |  |  |  | and $sun_elev_from_sat < 0 | 
| 2170 |  |  |  |  |  |  | and $litup = 0; | 
| 2171 | 415 |  |  |  |  | 1292 | push @illumination, illumination => $lighting[$litup]; | 
| 2172 |  |  |  |  |  |  | } else { | 
| 2173 | 246 |  |  |  |  | 475 | $visible = $elev > $screening_horizon; | 
| 2174 |  |  |  |  |  |  | } | 
| 2175 |  |  |  |  |  |  |  | 
| 2176 |  |  |  |  |  |  | # Accumulate results. | 
| 2177 |  |  |  |  |  |  |  | 
| 2178 | 661 |  |  |  |  | 5066 | push @info, { | 
| 2179 |  |  |  |  |  |  | azimuth => $azm, | 
| 2180 |  |  |  |  |  |  | elevation => $elev, | 
| 2181 |  |  |  |  |  |  | event => PASS_EVENT_NONE, | 
| 2182 |  |  |  |  |  |  | range => $rng, | 
| 2183 |  |  |  |  |  |  | time => $time, | 
| 2184 |  |  |  |  |  |  | @illumination, | 
| 2185 |  |  |  |  |  |  | }; | 
| 2186 |  |  |  |  |  |  |  | 
| 2187 |  |  |  |  |  |  | } | 
| 2188 |  |  |  |  |  |  |  | 
| 2189 |  |  |  |  |  |  | } | 
| 2190 | 14 |  |  |  |  | 232 | return @passes; | 
| 2191 |  |  |  |  |  |  |  | 
| 2192 |  |  |  |  |  |  | } | 
| 2193 |  |  |  |  |  |  |  | 
| 2194 |  |  |  |  |  |  | # The problem the following attempts to deal with is that if two | 
| 2195 |  |  |  |  |  |  | # satellites with similar orbits rise about the same time, they may | 
| 2196 |  |  |  |  |  |  | # appear to approach, diverge, and approach again. The last apparent | 
| 2197 |  |  |  |  |  |  | # approach is because they are receding from the observer faster than | 
| 2198 |  |  |  |  |  |  | # from each other. | 
| 2199 |  |  |  |  |  |  | # | 
| 2200 |  |  |  |  |  |  | # What the following code attempts to do is to provide reasonable | 
| 2201 |  |  |  |  |  |  | # brackets around the time of closest approach. If the body is a TLE | 
| 2202 |  |  |  |  |  |  | # object, we step across the pass in 30-second intervals, and return the | 
| 2203 |  |  |  |  |  |  | # interval 30 seconds before and after the closest position found. | 
| 2204 |  |  |  |  |  |  | # Otherwise we just return the beginning and end of the pass. | 
| 2205 |  |  |  |  |  |  | # | 
| 2206 |  |  |  |  |  |  | # Originally there was an attempt to determine if the orbits were | 
| 2207 |  |  |  |  |  |  | # "sufficiently close", and only step across if that was the case. But | 
| 2208 |  |  |  |  |  |  | # it proved impracticable to define "sufficiently close", and it was | 
| 2209 |  |  |  |  |  |  | # determined by benchmarking that the preliminary stepping had only a | 
| 2210 |  |  |  |  |  |  | # minimal effect on the algorithm's execution time. So we step any time | 
| 2211 |  |  |  |  |  |  | # we are computing an appulse of an artificial satellite to another | 
| 2212 |  |  |  |  |  |  | # artificial satellite. | 
| 2213 |  |  |  |  |  |  |  | 
| 2214 |  |  |  |  |  |  | { | 
| 2215 |  |  |  |  |  |  |  | 
| 2216 |  |  |  |  |  |  | # The following manifest constant is to be used only here. Pretend | 
| 2217 |  |  |  |  |  |  | # it is localized. | 
| 2218 |  |  |  |  |  |  |  | 
| 2219 | 16 |  |  | 16 |  | 147 | use constant APPULSE_CHECK_STEP	=> 30;	# seconds | 
|  | 16 |  |  |  |  | 38 |  | 
|  | 16 |  |  |  |  | 214097 |  | 
| 2220 |  |  |  |  |  |  |  | 
| 2221 |  |  |  |  |  |  | sub _pass_bracket_appulse { | 
| 2222 | 45 |  |  | 45 |  | 156 | my ( $sta, $tle, $body, $first_time, $last_time ) = @_; | 
| 2223 |  |  |  |  |  |  |  | 
| 2224 |  |  |  |  |  |  | # The problem we're trying to avoid does not occur unless the | 
| 2225 |  |  |  |  |  |  | # body is a TLE. | 
| 2226 | 45 | 100 |  |  |  | 171 | embodies( $body, 'Astro::Coord::ECI::TLE' ) | 
| 2227 |  |  |  |  |  |  | or return ( $first_time, $last_time ); | 
| 2228 |  |  |  |  |  |  |  | 
| 2229 |  |  |  |  |  |  | # OK, we think we have a problem. Step across the entire pass in | 
| 2230 |  |  |  |  |  |  | # 30-second intervals and find the one where the two bodies | 
| 2231 |  |  |  |  |  |  | # approach most closely. | 
| 2232 | 1 |  |  |  |  | 4 | my ( $smallest, $mark ); | 
| 2233 | 1 |  |  |  |  | 6 | for ( my $time = $first_time; $time <= $last_time; | 
| 2234 |  |  |  |  |  |  | $time += APPULSE_CHECK_STEP | 
| 2235 |  |  |  |  |  |  | ) { | 
| 2236 | 16 |  |  |  |  | 44 | my $angle = $sta->angle( | 
| 2237 |  |  |  |  |  |  | $body->universal( $time ), | 
| 2238 |  |  |  |  |  |  | $tle->universal( $time ), | 
| 2239 |  |  |  |  |  |  | ); | 
| 2240 | 16 | 100 | 66 |  |  | 83 | defined $smallest | 
| 2241 |  |  |  |  |  |  | and $angle > $smallest | 
| 2242 |  |  |  |  |  |  | or ( $smallest, $mark ) = ( $angle, $time ); | 
| 2243 |  |  |  |  |  |  | } | 
| 2244 |  |  |  |  |  |  |  | 
| 2245 |  |  |  |  |  |  | # We return an interval around this closest point as the | 
| 2246 |  |  |  |  |  |  | # interval in which to apply the binary search algorithm. | 
| 2247 |  |  |  |  |  |  | return ( | 
| 2248 | 1 |  |  |  |  | 14 | max( $mark - APPULSE_CHECK_STEP, $first_time ), | 
| 2249 |  |  |  |  |  |  | min( $mark + APPULSE_CHECK_STEP, $last_time ), | 
| 2250 |  |  |  |  |  |  | ); | 
| 2251 |  |  |  |  |  |  | } | 
| 2252 |  |  |  |  |  |  | } | 
| 2253 |  |  |  |  |  |  |  | 
| 2254 |  |  |  |  |  |  | # Compute the position of the satellite at its brightest. We expect to | 
| 2255 |  |  |  |  |  |  | # be called only if the computation makes sense -- that is, if the | 
| 2256 |  |  |  |  |  |  | # intrinsic_magnitude attribute is set and we are calculating | 
| 2257 |  |  |  |  |  |  | # visibility. We will return an event hash, or nothing if there are no | 
| 2258 |  |  |  |  |  |  | # illuminated points. We will return nothing with a warning if there is | 
| 2259 |  |  |  |  |  |  | # exactly one illuminated point, since we can't conveniently make the | 
| 2260 |  |  |  |  |  |  | # calculation from this and it should not happen anyway. | 
| 2261 |  |  |  |  |  |  | # | 
| 2262 |  |  |  |  |  |  | # The arguments are: | 
| 2263 |  |  |  |  |  |  | # $tle - The orbiting body | 
| 2264 |  |  |  |  |  |  | # $sta - The observing body | 
| 2265 |  |  |  |  |  |  | # $sun - The illuminating body (assumed defined) | 
| 2266 |  |  |  |  |  |  | # $info - A reference to the array of events computed thus far, in order | 
| 2267 |  |  |  |  |  |  | #         by time. | 
| 2268 |  |  |  |  |  |  | # | 
| 2269 |  |  |  |  |  |  | # The $info array is assumed to already have visibility and visibility | 
| 2270 |  |  |  |  |  |  | # events calculated. | 
| 2271 |  |  |  |  |  |  | sub _pass_compute_brightest { | 
| 2272 | 0 |  |  | 0 |  | 0 | my ( $tle, $sta, $sun, $info ) = @_; | 
| 2273 | 0 |  |  |  |  | 0 | my @wrk = @{ $info }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 2274 |  |  |  |  |  |  |  | 
| 2275 |  |  |  |  |  |  | # We skip over all the un-illuminated events at the start. | 
| 2276 | 0 |  |  |  |  | 0 | while ( $wrk[0]{illumination} == PASS_EVENT_SHADOWED ) { | 
| 2277 | 0 |  |  |  |  | 0 | shift @wrk; | 
| 2278 |  |  |  |  |  |  | @wrk | 
| 2279 | 0 | 0 |  |  |  | 0 | or return; | 
| 2280 |  |  |  |  |  |  | } | 
| 2281 | 0 |  |  |  |  | 0 | my $earliest = $wrk[0]{time}; | 
| 2282 |  |  |  |  |  |  |  | 
| 2283 |  |  |  |  |  |  | # We want the time of the first shadowed event, since we're | 
| 2284 |  |  |  |  |  |  | # illuminated up to that point. | 
| 2285 | 0 |  |  |  |  | 0 | my $latest = $wrk[-1]{time}; | 
| 2286 | 0 |  |  |  |  | 0 | while ( $wrk[-1]{illumination} == PASS_EVENT_SHADOWED ) { | 
| 2287 | 0 |  |  |  |  | 0 | $latest = $wrk[-1]{time}; | 
| 2288 | 0 |  |  |  |  | 0 | pop @wrk; | 
| 2289 |  |  |  |  |  |  | @wrk | 
| 2290 | 0 | 0 |  |  |  | 0 | or return; | 
| 2291 |  |  |  |  |  |  | } | 
| 2292 |  |  |  |  |  |  |  | 
| 2293 |  |  |  |  |  |  | # We back off a second from the time of the shadow (or set) event, | 
| 2294 |  |  |  |  |  |  | # to get a time when we are illuminated and above the horizon. | 
| 2295 | 0 |  |  |  |  | 0 | $latest -= 1; | 
| 2296 |  |  |  |  |  |  | @wrk > 1 | 
| 2297 | 0 | 0 |  |  |  | 0 | or do { | 
| 2298 |  |  |  |  |  |  | # carp 'No magnitude calculation done: only one illuminated position'; | 
| 2299 | 0 |  |  |  |  | 0 | return; | 
| 2300 |  |  |  |  |  |  | }; | 
| 2301 |  |  |  |  |  |  |  | 
| 2302 |  |  |  |  |  |  | # Because the behavior is non-linear, we step through the time at | 
| 2303 |  |  |  |  |  |  | # 30-second intervals, then at 1-second intervals to find the | 
| 2304 |  |  |  |  |  |  | # brightest. | 
| 2305 | 0 |  |  |  |  | 0 | my $twilight = $tle->get( 'twilight' ); | 
| 2306 | 0 |  |  |  |  | 0 | foreach my $delta ( 30, 1 ) { | 
| 2307 | 0 |  |  |  |  | 0 | @wrk = (); | 
| 2308 | 0 |  |  |  |  | 0 | for ( my $time = $earliest; $time <= $latest; $time += $delta ) { | 
| 2309 | 0 |  |  |  |  | 0 | push @wrk, [ | 
| 2310 |  |  |  |  |  |  | $time, | 
| 2311 |  |  |  |  |  |  | $tle->universal( $time )->magnitude( $sta ), | 
| 2312 |  |  |  |  |  |  | ]; | 
| 2313 |  |  |  |  |  |  | } | 
| 2314 |  |  |  |  |  |  | # Because our time span is probably not a multiple of our step | 
| 2315 |  |  |  |  |  |  | # size, we slap the last time onto the end. | 
| 2316 | 0 | 0 |  |  |  | 0 | $wrk[-1][0] < $latest | 
| 2317 |  |  |  |  |  |  | and push @wrk, [ | 
| 2318 |  |  |  |  |  |  | $latest, | 
| 2319 |  |  |  |  |  |  | $tle->universal( $latest )->magnitude( $sta ), | 
| 2320 |  |  |  |  |  |  | ]; | 
| 2321 |  |  |  |  |  |  |  | 
| 2322 |  |  |  |  |  |  | # The next interval becomes the brightest and second-brightest | 
| 2323 |  |  |  |  |  |  | # time found. | 
| 2324 | 0 |  |  |  |  | 0 | @wrk = sort { $a->[1] <=> $b->[1] } grep { defined $_->[1] } @wrk; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 2325 | 0 |  |  |  |  | 0 | ( $earliest, $latest ) = sort { $a <=> $b } | 
| 2326 | 0 |  |  |  |  | 0 | map { $wrk[$_][0] } 0, 1; | 
|  | 0 |  |  |  |  | 0 |  | 
| 2327 |  |  |  |  |  |  | } | 
| 2328 |  |  |  |  |  |  |  | 
| 2329 |  |  |  |  |  |  | # Make up and return the event. | 
| 2330 | 0 |  |  |  |  | 0 | my $time = $wrk[0][0]; | 
| 2331 | 0 |  |  |  |  | 0 | my ( $azm, $elev, $rng ) = | 
| 2332 |  |  |  |  |  |  | $sta->azel( $tle->universal( $time ) ); | 
| 2333 | 0 |  |  |  |  | 0 | my ( undef, $sun_elev ) = $sta->azel( $sun->universal( | 
| 2334 |  |  |  |  |  |  | $time ) ); | 
| 2335 | 0 | 0 |  |  |  | 0 | my $illum = $sun_elev < $twilight ? | 
| 2336 |  |  |  |  |  |  | PASS_EVENT_LIT : | 
| 2337 |  |  |  |  |  |  | PASS_EVENT_DAY; | 
| 2338 |  |  |  |  |  |  | return { | 
| 2339 | 0 |  |  |  |  | 0 | azimuth		=> $azm, | 
| 2340 |  |  |  |  |  |  | body		=> $tle, | 
| 2341 |  |  |  |  |  |  | elevation	=> $elev, | 
| 2342 |  |  |  |  |  |  | event		=> PASS_EVENT_BRIGHTEST, | 
| 2343 |  |  |  |  |  |  | illumination	=> $illum, | 
| 2344 |  |  |  |  |  |  | magnitude	=> $wrk[0][1], | 
| 2345 |  |  |  |  |  |  | range		=> $rng, | 
| 2346 |  |  |  |  |  |  | station		=> $sta, | 
| 2347 |  |  |  |  |  |  | time		=> $time, | 
| 2348 |  |  |  |  |  |  | }; | 
| 2349 |  |  |  |  |  |  | } | 
| 2350 |  |  |  |  |  |  |  | 
| 2351 |  |  |  |  |  |  | =item $kilometers = $tle->periapsis(); | 
| 2352 |  |  |  |  |  |  |  | 
| 2353 |  |  |  |  |  |  | This method returns the periapsis of the orbit, in kilometers. Since | 
| 2354 |  |  |  |  |  |  | Astro::Coord::ECI::TLE objects always represent bodies orbiting the | 
| 2355 |  |  |  |  |  |  | Earth, this is more usually called perigee. | 
| 2356 |  |  |  |  |  |  |  | 
| 2357 |  |  |  |  |  |  | Note that this is the distance from the center of the Earth, not the | 
| 2358 |  |  |  |  |  |  | altitude. | 
| 2359 |  |  |  |  |  |  |  | 
| 2360 |  |  |  |  |  |  | =cut | 
| 2361 |  |  |  |  |  |  |  | 
| 2362 |  |  |  |  |  |  | sub periapsis { | 
| 2363 | 8 |  |  | 8 | 1 | 46 | my $self = shift; | 
| 2364 |  |  |  |  |  |  | return $self->{&TLE_INIT}{TLE_periapsis} ||= | 
| 2365 | 8 |  | 66 |  |  | 38 | (1 - $self->get('eccentricity')) * $self->semimajor(); | 
| 2366 |  |  |  |  |  |  | } | 
| 2367 |  |  |  |  |  |  |  | 
| 2368 |  |  |  |  |  |  | =item $kilometers = $tle->perigee(); | 
| 2369 |  |  |  |  |  |  |  | 
| 2370 |  |  |  |  |  |  | This method is simply a synonym for periapsis(). | 
| 2371 |  |  |  |  |  |  |  | 
| 2372 |  |  |  |  |  |  | =cut | 
| 2373 |  |  |  |  |  |  |  | 
| 2374 |  |  |  |  |  |  | *perigee = \&periapsis; | 
| 2375 |  |  |  |  |  |  |  | 
| 2376 |  |  |  |  |  |  | =item $seconds = $tle->period ($model); | 
| 2377 |  |  |  |  |  |  |  | 
| 2378 |  |  |  |  |  |  | This method returns the orbital period of the object in seconds using | 
| 2379 |  |  |  |  |  |  | the given model. If the model is unspecified (or specified as a false | 
| 2380 |  |  |  |  |  |  | value), the current setting of the 'model' attribute is used. | 
| 2381 |  |  |  |  |  |  |  | 
| 2382 |  |  |  |  |  |  | There are actually only two period calculations available. If the model | 
| 2383 |  |  |  |  |  |  | is 'sgp4r' (or its equivalents 'model' and 'model4r'), the sgp4r | 
| 2384 |  |  |  |  |  |  | calculation will be used. Otherwise the calculation from the original | 
| 2385 |  |  |  |  |  |  | Space Track Report Number 3 will be used. 'Otherwise' includes the case | 
| 2386 |  |  |  |  |  |  | where the model is 'null'. | 
| 2387 |  |  |  |  |  |  |  | 
| 2388 |  |  |  |  |  |  | The difference between using the original and the revised algorithm is | 
| 2389 |  |  |  |  |  |  | minimal. For the objects in the sgp4-ver.tle file provided with the | 
| 2390 |  |  |  |  |  |  | 'Revisiting Spacetrack Report #3' code, the largest is about 50 | 
| 2391 |  |  |  |  |  |  | nanoseconds for OID 23333, which is in a highly eccentric orbit. | 
| 2392 |  |  |  |  |  |  |  | 
| 2393 |  |  |  |  |  |  | The difference between using the various values of gravconst_r with | 
| 2394 |  |  |  |  |  |  | sgp4r is somewhat more pronounced. Among the objects in sgp4-ver.tle the | 
| 2395 |  |  |  |  |  |  | largest difference was about a millisecond, again for OID 23333. | 
| 2396 |  |  |  |  |  |  |  | 
| 2397 |  |  |  |  |  |  | Neither of these differences seems to me significant, but I thought it | 
| 2398 |  |  |  |  |  |  | would be easier to take the model into account than to explain why I did | 
| 2399 |  |  |  |  |  |  | not. | 
| 2400 |  |  |  |  |  |  |  | 
| 2401 |  |  |  |  |  |  | A note on subclassing: A body that is not in orbit should return a | 
| 2402 |  |  |  |  |  |  | period of C. | 
| 2403 |  |  |  |  |  |  |  | 
| 2404 |  |  |  |  |  |  | =cut | 
| 2405 |  |  |  |  |  |  |  | 
| 2406 |  |  |  |  |  |  | { | 
| 2407 |  |  |  |  |  |  | my %model_map = ( | 
| 2408 |  |  |  |  |  |  | model => \&_period_r, | 
| 2409 |  |  |  |  |  |  | model4r => \&_period_r, | 
| 2410 |  |  |  |  |  |  | sgp4r => \&_period_r, | 
| 2411 |  |  |  |  |  |  | ); | 
| 2412 |  |  |  |  |  |  | sub period { | 
| 2413 | 52 |  |  | 52 | 1 | 13849 | my $self = shift; | 
| 2414 | 52 |  | 100 |  |  | 425 | my $code = $model_map{shift || $self->{model}} || \&_period; | 
| 2415 | 52 |  |  |  |  | 218 | return $code->($self); | 
| 2416 |  |  |  |  |  |  | } | 
| 2417 |  |  |  |  |  |  | } | 
| 2418 |  |  |  |  |  |  |  | 
| 2419 |  |  |  |  |  |  | #	Original period calculation, recast to remove an equivocation on | 
| 2420 |  |  |  |  |  |  | #	where the period was cached, which caused the cache to be | 
| 2421 |  |  |  |  |  |  | #	ineffective. | 
| 2422 |  |  |  |  |  |  |  | 
| 2423 |  |  |  |  |  |  | sub _period { | 
| 2424 | 2 |  |  | 2 |  | 4 | my $self = shift; | 
| 2425 | 2 |  | 33 |  |  | 8 | return $self->{&TLE_INIT}{TLE_period} ||= do { | 
| 2426 | 2 |  |  |  |  | 9 | my $a1 = (SGP_XKE / $self->{meanmotion}) ** SGP_TOTHRD; | 
| 2427 |  |  |  |  |  |  | my $temp = 1.5 * SGP_CK2 * (3 * cos ($self->{inclination}) ** 2 - 1) / | 
| 2428 | 2 |  |  |  |  | 32 | (1 - $self->{eccentricity} * $self->{eccentricity}) ** 1.5; | 
| 2429 | 2 |  |  |  |  | 6 | my $del1 = $temp / ($a1 * $a1); | 
| 2430 | 2 |  |  |  |  | 6 | my $a0 = $a1 * (1 - $del1 * (.5 * SGP_TOTHRD + | 
| 2431 |  |  |  |  |  |  | $del1 * (1 + 134/81 * $del1))); | 
| 2432 | 2 |  |  |  |  | 3 | my $del0 = $temp / ($a0 * $a0); | 
| 2433 | 2 |  |  |  |  | 5 | my $xnodp = $self->{meanmotion} / (1 + $del0); | 
| 2434 | 2 |  |  |  |  | 24 | SGP_TWOPI / $xnodp * SGP_XSCPMN; | 
| 2435 |  |  |  |  |  |  | }; | 
| 2436 |  |  |  |  |  |  | } | 
| 2437 |  |  |  |  |  |  |  | 
| 2438 |  |  |  |  |  |  | #	Compute period using sgp4r's adjusted mean motion. Yes, I took | 
| 2439 |  |  |  |  |  |  | #	the coward's way out and initialized the model, but we use this | 
| 2440 |  |  |  |  |  |  | #	only if the model is sgp4r (implying that it will be initialized | 
| 2441 |  |  |  |  |  |  | #	anyway) or if the user explicitly asked for it. | 
| 2442 |  |  |  |  |  |  |  | 
| 2443 |  |  |  |  |  |  | sub _period_r { | 
| 2444 | 50 |  |  | 50 |  | 120 | my ($self) = @_; | 
| 2445 | 50 |  | 66 |  |  | 370 | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} ||= $self->_r_sgp4init (); | 
| 2446 | 50 |  |  |  |  | 640 | return &SGP_TWOPI/$parm->{meanmotion} * 60; | 
| 2447 |  |  |  |  |  |  | } | 
| 2448 |  |  |  |  |  |  |  | 
| 2449 |  |  |  |  |  |  | =item $tle = $tle->rebless ($class, \%possible_attributes) | 
| 2450 |  |  |  |  |  |  |  | 
| 2451 |  |  |  |  |  |  | This method reblesses a TLE object. The class must be either | 
| 2452 |  |  |  |  |  |  | L or a subclass thereof, as must | 
| 2453 |  |  |  |  |  |  | the object passed in to be reblessed. If the $tle object has its | 
| 2454 |  |  |  |  |  |  | C attribute false, it will not be reblessed, | 
| 2455 |  |  |  |  |  |  | but will be returned unmodified. Before reblessing, the | 
| 2456 |  |  |  |  |  |  | before_reblessing() method is called.  After reblessing, the | 
| 2457 |  |  |  |  |  |  | after_reblessing() method is called with the \%possible_attributes hash | 
| 2458 |  |  |  |  |  |  | reference as argument. | 
| 2459 |  |  |  |  |  |  |  | 
| 2460 |  |  |  |  |  |  | It is possible to omit the $class argument if the \%possible_attributes | 
| 2461 |  |  |  |  |  |  | argument contains the keys {class} or {type}, taken in that order. If | 
| 2462 |  |  |  |  |  |  | the $class argument is omitted and the \%possible_attributes hash does | 
| 2463 |  |  |  |  |  |  | B have the requisite keys, the $tle object is unmodified. | 
| 2464 |  |  |  |  |  |  |  | 
| 2465 |  |  |  |  |  |  | It is also possible to omit both arguments, in which case the object | 
| 2466 |  |  |  |  |  |  | will be reblessed according to the content of the internal status | 
| 2467 |  |  |  |  |  |  | table. | 
| 2468 |  |  |  |  |  |  |  | 
| 2469 |  |  |  |  |  |  | For convenience, you can pass an alias instead of the full class name. The | 
| 2470 |  |  |  |  |  |  | following aliases are recognized: | 
| 2471 |  |  |  |  |  |  |  | 
| 2472 |  |  |  |  |  |  | tle => 'Astro::Coord::ECI::TLE' | 
| 2473 |  |  |  |  |  |  |  | 
| 2474 |  |  |  |  |  |  | If you install | 
| 2475 |  |  |  |  |  |  | L it | 
| 2476 |  |  |  |  |  |  | will define alias | 
| 2477 |  |  |  |  |  |  |  | 
| 2478 |  |  |  |  |  |  | iridium => 'Astro::Coord::ECI::TLE::Iridium' | 
| 2479 |  |  |  |  |  |  |  | 
| 2480 |  |  |  |  |  |  | Other aliases may be defined with the alias() static method. | 
| 2481 |  |  |  |  |  |  |  | 
| 2482 |  |  |  |  |  |  | Note that this method returns the original object (possibly reblessed). | 
| 2483 |  |  |  |  |  |  | It does not under any circumstances manufacture another object. | 
| 2484 |  |  |  |  |  |  |  | 
| 2485 |  |  |  |  |  |  | =cut | 
| 2486 |  |  |  |  |  |  |  | 
| 2487 |  |  |  |  |  |  | sub rebless { | 
| 2488 | 87 |  |  | 87 | 1 | 175 | my ($tle, @args) = @_; | 
| 2489 | 87 | 50 |  |  |  | 280 | __instance( $tle, __PACKAGE__ ) or croak < | 
| 2490 | 0 |  |  |  |  | 0 | Error - You can only rebless an object of class @{[__PACKAGE__]} | 
| 2491 |  |  |  |  |  |  | or a subclass thereof. The object you are trying to rebless | 
| 2492 | 0 |  |  |  |  | 0 | is of class @{[ref $tle]}. | 
| 2493 |  |  |  |  |  |  | eod | 
| 2494 | 87 | 50 |  |  |  | 225 | $tle->get ('reblessable') or return $tle; | 
| 2495 | 87 | 50 |  |  |  | 209 | @args or do { | 
| 2496 | 87 | 50 |  |  |  | 170 | my $id = $tle->get ('id') or return $tle; | 
| 2497 | 87 | 50 |  |  |  | 550 | $id =~ m/ [^0-9] /smx | 
| 2498 |  |  |  |  |  |  | or $id = sprintf '%05d', $id; | 
| 2499 | 87 |  | 50 |  |  | 375 | @args = $status{$id} || 'tle'; | 
| 2500 |  |  |  |  |  |  | }; | 
| 2501 |  |  |  |  |  |  | my $class = HASH_REF eq ref $args[0] ? | 
| 2502 | 87 | 50 | 0 |  |  | 296 | ($args[0]->{class} || $args[0]->{type}) : shift @args | 
|  |  | 50 |  |  |  |  |  | 
| 2503 |  |  |  |  |  |  | or return $tle; | 
| 2504 | 87 | 50 |  |  |  | 330 | $class = $type_map{$class} if $type_map{$class}; | 
| 2505 | 87 |  |  |  |  | 269 | load_module ($class); | 
| 2506 | 87 | 50 |  |  |  | 194 | __classisa( $class, __PACKAGE__ ) or croak < | 
| 2507 | 0 |  |  |  |  | 0 | Error - You can only rebless an object into @{[__PACKAGE__]} or | 
| 2508 |  |  |  |  |  |  | a subclass thereof. You are trying to rebless the object | 
| 2509 |  |  |  |  |  |  | into $class. | 
| 2510 |  |  |  |  |  |  | eod | 
| 2511 | 87 |  |  |  |  | 259 | $tle->before_reblessing (); | 
| 2512 | 87 |  |  |  |  | 148 | bless $tle, $class; | 
| 2513 | 87 |  |  |  |  | 222 | $tle->after_reblessing (@args); | 
| 2514 | 87 |  |  |  |  | 178 | return $tle; | 
| 2515 |  |  |  |  |  |  | } | 
| 2516 |  |  |  |  |  |  |  | 
| 2517 |  |  |  |  |  |  | =item $kilometers = $tle->semimajor(); | 
| 2518 |  |  |  |  |  |  |  | 
| 2519 |  |  |  |  |  |  | This method calculates the semimajor axis of the orbit, using Kepler's | 
| 2520 |  |  |  |  |  |  | Third Law (Isaac Newton's version) in the form | 
| 2521 |  |  |  |  |  |  |  | 
| 2522 |  |  |  |  |  |  | T ** 2 / a ** 3 = 4 * pi ** 2 / mu | 
| 2523 |  |  |  |  |  |  |  | 
| 2524 |  |  |  |  |  |  | where | 
| 2525 |  |  |  |  |  |  |  | 
| 2526 |  |  |  |  |  |  | T is the orbital period, | 
| 2527 |  |  |  |  |  |  | a is the semimajor axis of the orbit, | 
| 2528 |  |  |  |  |  |  | pi is the circle ratio (3.14159 ...), and | 
| 2529 |  |  |  |  |  |  | mu is the Earth's gravitational constant, | 
| 2530 |  |  |  |  |  |  | 3.986005e5 km ** 3 / sec ** 2 | 
| 2531 |  |  |  |  |  |  |  | 
| 2532 |  |  |  |  |  |  | The calculation is carried out using the period implied by the current | 
| 2533 |  |  |  |  |  |  | model. | 
| 2534 |  |  |  |  |  |  |  | 
| 2535 |  |  |  |  |  |  | =cut | 
| 2536 |  |  |  |  |  |  |  | 
| 2537 |  |  |  |  |  |  | { | 
| 2538 |  |  |  |  |  |  | my $mu = 3.986005e5;	# km ** 3 / sec ** 2 -- for Earth. | 
| 2539 |  |  |  |  |  |  | sub semimajor { | 
| 2540 | 12 |  |  | 12 | 1 | 36 | my $self = shift; | 
| 2541 | 12 |  | 66 |  |  | 58 | return $self->{&TLE_INIT}{TLE_semimajor} ||= do { | 
| 2542 | 4 |  |  |  |  | 13 | my $to2pi = $self->period / SGP_TWOPI; | 
| 2543 | 4 |  |  |  |  | 28 | exp (log ($to2pi * $to2pi * $mu) / 3); | 
| 2544 |  |  |  |  |  |  | }; | 
| 2545 |  |  |  |  |  |  | } | 
| 2546 |  |  |  |  |  |  | } | 
| 2547 |  |  |  |  |  |  |  | 
| 2548 |  |  |  |  |  |  | =item $kilometers = $tle->semiminor(); | 
| 2549 |  |  |  |  |  |  |  | 
| 2550 |  |  |  |  |  |  | This method calculates the semiminor axis of the orbit, using the | 
| 2551 |  |  |  |  |  |  | semimajor axis and the eccentricity, by the equation | 
| 2552 |  |  |  |  |  |  |  | 
| 2553 |  |  |  |  |  |  | b = a * sqrt(1 - e) | 
| 2554 |  |  |  |  |  |  |  | 
| 2555 |  |  |  |  |  |  | where a is the semimajor axis and e is the eccentricity. | 
| 2556 |  |  |  |  |  |  |  | 
| 2557 |  |  |  |  |  |  | =cut | 
| 2558 |  |  |  |  |  |  |  | 
| 2559 |  |  |  |  |  |  | sub semiminor { | 
| 2560 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 2561 | 0 |  | 0 |  |  | 0 | return $self->{&TLE_INIT}{TLE_semiminor} ||= do { | 
| 2562 | 0 |  |  |  |  | 0 | my $e = $self->get('eccentricity'); | 
| 2563 | 0 |  |  |  |  | 0 | $self->semimajor() * sqrt(1 - $e * $e); | 
| 2564 |  |  |  |  |  |  | }; | 
| 2565 |  |  |  |  |  |  | } | 
| 2566 |  |  |  |  |  |  |  | 
| 2567 |  |  |  |  |  |  | =item $tle->set (attribute => value ...) | 
| 2568 |  |  |  |  |  |  |  | 
| 2569 |  |  |  |  |  |  | This method sets the values of the various attributes. The changing of | 
| 2570 |  |  |  |  |  |  | attributes actually used by the orbital models will cause the models to | 
| 2571 |  |  |  |  |  |  | be reinitialized. This happens transparently, and is no big deal. For | 
| 2572 |  |  |  |  |  |  | a description of the attributes, see L. | 
| 2573 |  |  |  |  |  |  |  | 
| 2574 |  |  |  |  |  |  | Because this is a subclass of L, | 
| 2575 |  |  |  |  |  |  | any attributes of that class can also be set. | 
| 2576 |  |  |  |  |  |  |  | 
| 2577 |  |  |  |  |  |  | =cut | 
| 2578 |  |  |  |  |  |  |  | 
| 2579 |  |  |  |  |  |  | sub set { | 
| 2580 | 216 |  |  | 216 | 1 | 5834 | my ($self, @args) = @_; | 
| 2581 | 216 | 50 |  |  |  | 569 | @args % 2 and croak "The set method takes an even number of arguments."; | 
| 2582 | 216 |  |  |  |  | 374 | my ($clear, $extant); | 
| 2583 | 216 | 50 |  |  |  | 487 | if (ref $self) { | 
| 2584 | 216 |  |  |  |  | 365 | $extant = \%attrib; | 
| 2585 |  |  |  |  |  |  | } else { | 
| 2586 | 0 |  |  |  |  | 0 | $self = $extant = \%static; | 
| 2587 |  |  |  |  |  |  | } | 
| 2588 | 216 |  |  |  |  | 475 | while (@args) { | 
| 2589 | 2112 |  |  |  |  | 3114 | my $name = shift @args; | 
| 2590 | 2112 |  |  |  |  | 2978 | my $val = shift @args; | 
| 2591 | 2112 | 100 |  |  |  | 3873 | exists $extant->{$name} or do { | 
| 2592 | 194 |  |  |  |  | 641 | $self->SUPER::set ($name, $val); | 
| 2593 | 194 |  |  |  |  | 462 | next; | 
| 2594 |  |  |  |  |  |  | }; | 
| 2595 | 1918 | 50 |  |  |  | 3421 | defined $attrib{$name} or croak "Attribute $name is read-only."; | 
| 2596 | 1918 | 100 |  |  |  | 3299 | if ( CODE_REF eq ref $attrib{$name} ) { | 
| 2597 | 684 | 100 |  |  |  | 1387 | $attrib{$name}->($self, $name, $val) and $clear = 1; | 
| 2598 |  |  |  |  |  |  | } else { | 
| 2599 | 1234 |  |  |  |  | 2047 | $self->{$name} = $val; | 
| 2600 | 1234 |  | 100 |  |  | 3207 | $clear ||= $attrib{$name}; | 
| 2601 |  |  |  |  |  |  | } | 
| 2602 |  |  |  |  |  |  | } | 
| 2603 | 216 | 100 |  |  |  | 601 | $clear and delete $self->{&TLE_INIT}; | 
| 2604 | 216 |  |  |  |  | 448 | return $self; | 
| 2605 |  |  |  |  |  |  | } | 
| 2606 |  |  |  |  |  |  |  | 
| 2607 |  |  |  |  |  |  | =item Astro::Coord::ECI::TLE->status (command => arguments ...) | 
| 2608 |  |  |  |  |  |  |  | 
| 2609 |  |  |  |  |  |  | This method maintains the internal status table, which is used by the | 
| 2610 |  |  |  |  |  |  | parse() method to determine which subclass (if any) to bless the | 
| 2611 |  |  |  |  |  |  | created object into. The first argument determines what is done to the | 
| 2612 |  |  |  |  |  |  | status table; subsequent arguments depend on the first argument. Valid | 
| 2613 |  |  |  |  |  |  | commands and arguments are: | 
| 2614 |  |  |  |  |  |  |  | 
| 2615 |  |  |  |  |  |  | status (add => $id, $type => $status, $name, $comment) adds an item to | 
| 2616 |  |  |  |  |  |  | the status table or modifies an existing item. The $id is the NORAD ID | 
| 2617 |  |  |  |  |  |  | of the body. | 
| 2618 |  |  |  |  |  |  |  | 
| 2619 |  |  |  |  |  |  | No types are supported out of the box, but if you have installed | 
| 2620 |  |  |  |  |  |  | L that | 
| 2621 |  |  |  |  |  |  | or C<'iridium'> will work. | 
| 2622 |  |  |  |  |  |  |  | 
| 2623 |  |  |  |  |  |  | The $status is 0, 1, 2, or 3 representing in-service, spare, failed, or | 
| 2624 |  |  |  |  |  |  | decayed respectively.  The strings '+' or '' will be interpreted as 0, | 
| 2625 |  |  |  |  |  |  | 'S', 's', or '?' as 1, 'D' as 3, and any other non-numeric string as 2. | 
| 2626 |  |  |  |  |  |  | The  $name and $comment arguments default to empty. | 
| 2627 |  |  |  |  |  |  |  | 
| 2628 |  |  |  |  |  |  | status ('clear') clears the status table. | 
| 2629 |  |  |  |  |  |  |  | 
| 2630 |  |  |  |  |  |  | status (clear => 'type') clears all entries of the given type in the | 
| 2631 |  |  |  |  |  |  | status table. For supported types, see the discussion of 'add', | 
| 2632 |  |  |  |  |  |  | above. | 
| 2633 |  |  |  |  |  |  |  | 
| 2634 |  |  |  |  |  |  | status (drop => $id) removes the given NORAD ID from the status table. | 
| 2635 |  |  |  |  |  |  |  | 
| 2636 |  |  |  |  |  |  | status ('show') returns a list of list references, representing the | 
| 2637 |  |  |  |  |  |  | 'add' commands which would be used to regenerate the status table. | 
| 2638 |  |  |  |  |  |  |  | 
| 2639 |  |  |  |  |  |  | Initially, the status table is populated with the status as of December | 
| 2640 |  |  |  |  |  |  | 3, 2010. | 
| 2641 |  |  |  |  |  |  |  | 
| 2642 |  |  |  |  |  |  | =cut | 
| 2643 |  |  |  |  |  |  |  | 
| 2644 |  |  |  |  |  |  | sub status { | 
| 2645 | 0 |  |  | 0 | 1 | 0 | my ( undef, $cmd, @arg ) = @_;	# Invocant unused | 
| 2646 | 0 | 0 |  |  |  | 0 | if ($cmd eq 'add') { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 2647 | 0 |  |  |  |  | 0 | my ( $id, $type, $status, $name, $comment ) = @arg; | 
| 2648 | 0 | 0 |  |  |  | 0 | $id or croak < | 
| 2649 |  |  |  |  |  |  | Error - The status ('add') call requires a NORAD ID. | 
| 2650 |  |  |  |  |  |  | eod | 
| 2651 | 0 | 0 |  |  |  | 0 | $id =~ m/ [^0-9] /smx | 
| 2652 |  |  |  |  |  |  | or $id = sprintf '%05d', $id; | 
| 2653 | 0 | 0 |  |  |  | 0 | $type or croak < | 
| 2654 |  |  |  |  |  |  | Error - The status (add => $id) call requires a type. | 
| 2655 |  |  |  |  |  |  | eod | 
| 2656 | 0 |  | 0 |  |  | 0 | my $class = $type_map{$type} || $type; | 
| 2657 | 0 | 0 |  |  |  | 0 | __classisa( $class, __PACKAGE__ ) or croak < | 
| 2658 | 0 |  |  |  |  | 0 | Error - $type must specify a subclass of @{[__PACKAGE__]}. | 
| 2659 |  |  |  |  |  |  | eod | 
| 2660 | 0 |  | 0 |  |  | 0 | $status ||= 0; | 
| 2661 | 0 | 0 |  |  |  | 0 | if ( my $code = $class->can( '__decode_operational_status' ) ) { | 
| 2662 | 0 |  |  |  |  | 0 | $status = $code->( $status ); | 
| 2663 |  |  |  |  |  |  | } | 
| 2664 | 0 |  | 0 |  |  | 0 | $name ||= ''; | 
| 2665 | 0 |  | 0 |  |  | 0 | $comment ||=''; | 
| 2666 | 0 |  |  |  |  | 0 | $status{$id} = { | 
| 2667 |  |  |  |  |  |  | comment => $comment, | 
| 2668 |  |  |  |  |  |  | status => $status, | 
| 2669 |  |  |  |  |  |  | name => $name, | 
| 2670 |  |  |  |  |  |  | id => $id, | 
| 2671 |  |  |  |  |  |  | type => $type, | 
| 2672 |  |  |  |  |  |  | class => $class, | 
| 2673 |  |  |  |  |  |  | }; | 
| 2674 |  |  |  |  |  |  | } elsif ($cmd eq 'clear') { | 
| 2675 | 0 |  |  |  |  | 0 | my ( $type ) = @arg; | 
| 2676 | 0 | 0 |  |  |  | 0 | if (!defined $type) { | 
| 2677 | 0 |  |  |  |  | 0 | %status = (); | 
| 2678 |  |  |  |  |  |  | } else { | 
| 2679 | 0 |  | 0 |  |  | 0 | my $class = $type_map{$type} || $type; | 
| 2680 | 0 | 0 |  |  |  | 0 | __classisa( $class, __PACKAGE__ ) or croak < | 
| 2681 | 0 |  |  |  |  | 0 | Error - $type must specify a subclass of @{[__PACKAGE__]}. | 
| 2682 |  |  |  |  |  |  | eod | 
| 2683 | 0 |  |  |  |  | 0 | foreach my $key (keys %status) { | 
| 2684 | 0 | 0 |  |  |  | 0 | $status{$key}{class} eq $class and delete $status{$key}; | 
| 2685 |  |  |  |  |  |  | } | 
| 2686 |  |  |  |  |  |  | } | 
| 2687 |  |  |  |  |  |  | } elsif ($cmd eq 'drop') { | 
| 2688 | 0 | 0 |  |  |  | 0 | my $id = $arg[0] or croak < | 
| 2689 |  |  |  |  |  |  | Error - The status ('drop') call requires a NORAD ID. | 
| 2690 |  |  |  |  |  |  | eod | 
| 2691 | 0 |  |  |  |  | 0 | delete $status{$id}; | 
| 2692 |  |  |  |  |  |  | } elsif ($cmd eq 'dump') {	# <<<< Undocumented!!! | 
| 2693 |  |  |  |  |  |  | # This functionality is UNDOCUMENTED and UNSUPPORTED. It exists | 
| 2694 |  |  |  |  |  |  | # for the convenience of the author, who reserves the right to | 
| 2695 |  |  |  |  |  |  | # change or revoke it without notice. | 
| 2696 |  |  |  |  |  |  | # If called in void context, prints a Data::Dumper dump of the | 
| 2697 |  |  |  |  |  |  | # status information; otherwise returns the dump. | 
| 2698 | 0 |  |  |  |  | 0 | local $Data::Dumper::Terse = 1; | 
| 2699 | 0 |  |  |  |  | 0 | local $Data::Dumper::Sortkeys = 1; | 
| 2700 |  |  |  |  |  |  | my $data = @arg ? | 
| 2701 | 0 | 0 |  |  |  | 0 | +{ map { $_ => $status{$_} } grep { $status{$_} } @arg } : | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 2702 |  |  |  |  |  |  | \%status; | 
| 2703 |  |  |  |  |  |  | defined wantarray | 
| 2704 | 0 | 0 |  |  |  | 0 | and return __PACKAGE__ . ' status = ', Dumper( $data ); | 
| 2705 | 0 |  |  |  |  | 0 | print __PACKAGE__, " status = ", Dumper ( $data ); | 
| 2706 |  |  |  |  |  |  | } elsif ($cmd eq 'show') { | 
| 2707 |  |  |  |  |  |  | return ( | 
| 2708 | 0 |  |  |  |  | 0 | sort { $a->[0] <=> $b->[0] } | 
| 2709 |  |  |  |  |  |  | map { [ $_->{id}, $_->{type}, $_->{status}, $_->{name}, | 
| 2710 | 0 |  |  |  |  | 0 | $_->{comment} ] } | 
| 2711 | 0 | 0 |  |  |  | 0 | map { defined $status{$_} ? $status{$_} : () } | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 2712 |  |  |  |  |  |  | @arg ? @arg : keys %status | 
| 2713 |  |  |  |  |  |  | ); | 
| 2714 |  |  |  |  |  |  | } elsif ($cmd eq 'yaml') {	# <<<< Undocumented!!! | 
| 2715 |  |  |  |  |  |  | # This functionality is UNDOCUMENTED and UNSUPPORTED. It exists | 
| 2716 |  |  |  |  |  |  | # for the convenience of the author, who reserves the right to | 
| 2717 |  |  |  |  |  |  | # change or revoke it without notice. | 
| 2718 |  |  |  |  |  |  | # If called in void context, prints a YAML dump of the status | 
| 2719 |  |  |  |  |  |  | # information; otherwise returns the YAML dump. | 
| 2720 | 0 | 0 |  |  |  | 0 | load_module( 'YAML' ) | 
| 2721 |  |  |  |  |  |  | or croak 'YAML not available'; | 
| 2722 |  |  |  |  |  |  | my $data = @arg ? | 
| 2723 | 0 | 0 |  |  |  | 0 | +{ map { $_ => $status{$_} } grep { $status{$_} } @arg } : | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 2724 |  |  |  |  |  |  | \%status; | 
| 2725 |  |  |  |  |  |  | defined wantarray | 
| 2726 | 0 | 0 |  |  |  | 0 | and return YAML::Dump( $data ); | 
| 2727 | 0 |  |  |  |  | 0 | print YAML::Dump( $data ); | 
| 2728 |  |  |  |  |  |  | } else { | 
| 2729 | 0 |  |  |  |  | 0 | croak < | 
| 2730 |  |  |  |  |  |  | Error - '$cmd' is not a legal status() command. | 
| 2731 |  |  |  |  |  |  | eod | 
| 2732 |  |  |  |  |  |  | } | 
| 2733 | 0 |  |  |  |  | 0 | return; | 
| 2734 |  |  |  |  |  |  | } | 
| 2735 |  |  |  |  |  |  |  | 
| 2736 |  |  |  |  |  |  | =item $tle = $tle->sgp($time) | 
| 2737 |  |  |  |  |  |  |  | 
| 2738 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 2739 |  |  |  |  |  |  | object at the given time, using the SGP model. The universal time of the | 
| 2740 |  |  |  |  |  |  | object is set to $time, and the 'equinox_dynamical' attribute is set to | 
| 2741 |  |  |  |  |  |  | to the current value of the 'epoch_dynamical' attribute. | 
| 2742 |  |  |  |  |  |  |  | 
| 2743 |  |  |  |  |  |  | The result is the original object reference. You need to call one of | 
| 2744 |  |  |  |  |  |  | the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to | 
| 2745 |  |  |  |  |  |  | retrieve the position you just calculated. | 
| 2746 |  |  |  |  |  |  |  | 
| 2747 |  |  |  |  |  |  | "Spacetrack Report Number 3" (see "Acknowledgments") says that this | 
| 2748 |  |  |  |  |  |  | model can be used for either near-earth or deep-space orbits, but the | 
| 2749 |  |  |  |  |  |  | reference implementation they provide dies on an attempt to use this | 
| 2750 |  |  |  |  |  |  | model for a deep-space object, and I have followed the reference | 
| 2751 |  |  |  |  |  |  | implementation. | 
| 2752 |  |  |  |  |  |  |  | 
| 2753 |  |  |  |  |  |  | =cut | 
| 2754 |  |  |  |  |  |  |  | 
| 2755 |  |  |  |  |  |  | sub sgp { | 
| 2756 | 7 |  |  | 7 | 1 | 17 | my ($self, $time) = @_; | 
| 2757 | 7 |  |  |  |  | 17 | my $oid = $self->get('id'); | 
| 2758 | 7 |  |  |  |  | 16 | $self->{model_error} = undef; | 
| 2759 | 7 |  |  |  |  | 20 | my $tsince = ($time - $self->{epoch}) / 60;	# Calc. is in minutes. | 
| 2760 |  |  |  |  |  |  |  | 
| 2761 |  |  |  |  |  |  | #*	Initialization. | 
| 2762 |  |  |  |  |  |  |  | 
| 2763 |  |  |  |  |  |  | #>>>	Rather than use a separate indicator argument to trigger | 
| 2764 |  |  |  |  |  |  | #>>>	initialization of the model, we use the Orcish maneuver to | 
| 2765 |  |  |  |  |  |  | #>>>	retrieve the results of initialization, performing the | 
| 2766 |  |  |  |  |  |  | #>>>	calculations if needed. -- TRW | 
| 2767 |  |  |  |  |  |  |  | 
| 2768 | 7 |  | 66 |  |  | 42 | my $parm = $self->{&TLE_INIT}{TLE_sgp} ||= do { | 
| 2769 | 2 | 50 |  |  |  | 10 | $self->is_deep and croak < | 
| 2770 |  |  |  |  |  |  | Error - The SGP model is not valid for deep space objects. | 
| 2771 |  |  |  |  |  |  | Use the SDP4, SDP4R, or SDP8 models instead. | 
| 2772 |  |  |  |  |  |  | EOD | 
| 2773 | 2 |  |  |  |  | 6 | my $c1 = SGP_CK2 * 1.5; | 
| 2774 | 2 |  |  |  |  | 5 | my $c2 = SGP_CK2 / 4; | 
| 2775 | 2 |  |  |  |  | 3 | my $c3 = SGP_CK2 / 2; | 
| 2776 | 2 |  |  |  |  | 4 | my $c4 = SGP_XJ3 * SGP_AE ** 3 / (4 * SGP_CK2); | 
| 2777 | 2 |  |  |  |  | 12 | my $cosi0 = cos ($self->{inclination}); | 
| 2778 | 2 |  |  |  |  | 9 | my $sini0 = sin ($self->{inclination}); | 
| 2779 | 2 |  |  |  |  | 14 | my $a1 = (SGP_XKE / $self->{meanmotion}) ** SGP_TOTHRD; | 
| 2780 |  |  |  |  |  |  | my $d1 = $c1 / $a1 / $a1 * (3 * $cosi0 * $cosi0 - 1) / | 
| 2781 | 2 |  |  |  |  | 14 | (1 - $self->{eccentricity} * $self->{eccentricity}) ** 1.5; | 
| 2782 | 2 |  |  |  |  | 9 | my $a0 = $a1 * | 
| 2783 |  |  |  |  |  |  | (1 - 1/3 * $d1 - $d1 * $d1 - 134/81 * $d1 * $d1 * $d1); | 
| 2784 | 2 |  |  |  |  | 7 | my $p0 = $a0 * (1 - $self->{eccentricity} * $self->{eccentricity}); | 
| 2785 | 2 |  |  |  |  | 6 | my $q0 = $a0 * (1 - $self->{eccentricity}); | 
| 2786 |  |  |  |  |  |  | my $xlo = $self->{meananomaly} + $self->{argumentofperigee} + | 
| 2787 | 2 |  |  |  |  | 6 | $self->{ascendingnode}; | 
| 2788 | 2 |  |  |  |  | 14 | my $d10 = $c3 * $sini0 * $sini0; | 
| 2789 | 2 |  |  |  |  | 8 | my $d20 = $c2 * (7 * $cosi0 * $cosi0 - 1); | 
| 2790 | 2 |  |  |  |  | 6 | my $d30 = $c1 * $cosi0; | 
| 2791 | 2 |  |  |  |  | 5 | my $d40 = $d30 * $sini0; | 
| 2792 | 2 |  |  |  |  | 7 | my $po2no = $self->{meanmotion} / ($p0 * $p0); | 
| 2793 | 2 |  |  |  |  | 6 | my $omgdt = $c1 * $po2no * (5 * $cosi0 * $cosi0 - 1); | 
| 2794 | 2 |  |  |  |  | 6 | my $xnodot = -2 * $d30 * $po2no; | 
| 2795 | 2 |  |  |  |  | 7 | my $c5 = .5 * $c4 * $sini0 * (3 + 5 * $cosi0) / (1 + $cosi0); | 
| 2796 | 2 |  |  |  |  | 3 | my $c6 = $c4 * $sini0; | 
| 2797 | 2 | 50 |  |  |  | 7 | $self->{debug} and warn < | 
| 2798 |  |  |  |  |  |  | Debug sgp initialization - | 
| 2799 |  |  |  |  |  |  | A0 = $a0 | 
| 2800 |  |  |  |  |  |  | C5 = $c5 | 
| 2801 |  |  |  |  |  |  | C6 = $c6 | 
| 2802 |  |  |  |  |  |  | D10 = $d10 | 
| 2803 |  |  |  |  |  |  | D20 = $d20 | 
| 2804 |  |  |  |  |  |  | D30 = $d30 | 
| 2805 |  |  |  |  |  |  | D40 = $d40 | 
| 2806 |  |  |  |  |  |  | OMGDT = $omgdt | 
| 2807 |  |  |  |  |  |  | Q0 = $q0 | 
| 2808 |  |  |  |  |  |  | XLO = $xlo | 
| 2809 |  |  |  |  |  |  | XNODOT = $xnodot | 
| 2810 |  |  |  |  |  |  | eod | 
| 2811 |  |  |  |  |  |  | { | 
| 2812 | 2 |  |  |  |  | 24 | a0 => $a0, | 
| 2813 |  |  |  |  |  |  | c5 => $c5, | 
| 2814 |  |  |  |  |  |  | c6 => $c6, | 
| 2815 |  |  |  |  |  |  | d10 => $d10, | 
| 2816 |  |  |  |  |  |  | d20 => $d20, | 
| 2817 |  |  |  |  |  |  | d30 => $d30, | 
| 2818 |  |  |  |  |  |  | d40 => $d40, | 
| 2819 |  |  |  |  |  |  | omgdt => $omgdt, | 
| 2820 |  |  |  |  |  |  | q0 => $q0, | 
| 2821 |  |  |  |  |  |  | xlo => $xlo, | 
| 2822 |  |  |  |  |  |  | xnodot => $xnodot, | 
| 2823 |  |  |  |  |  |  | }; | 
| 2824 |  |  |  |  |  |  | }; | 
| 2825 |  |  |  |  |  |  |  | 
| 2826 |  |  |  |  |  |  | #*	Update for secular gravity and atmospheric drag. | 
| 2827 |  |  |  |  |  |  |  | 
| 2828 |  |  |  |  |  |  | my $a = $self->{meanmotion} + | 
| 2829 |  |  |  |  |  |  | (2 * $self->{firstderivative} + | 
| 2830 | 7 |  |  |  |  | 25 | 3 * $self->{secondderivative} * $tsince) * $tsince; | 
| 2831 |  |  |  |  |  |  | # $a is only magic inside certain constructions, but Perl::Critic | 
| 2832 |  |  |  |  |  |  | # either does not know this, or does not realize that it is a | 
| 2833 |  |  |  |  |  |  | # lexical variable here. | 
| 2834 |  |  |  |  |  |  | $a =	## no critic (RequireLocalizedPunctuationVars) | 
| 2835 | 7 |  |  |  |  | 22 | $parm->{a0} * ($self->{meanmotion} / $a) ** SGP_TOTHRD; | 
| 2836 | 7 | 100 |  |  |  | 38 | my $e = $a > $parm->{q0} ? 1 - $parm->{q0} / $a : SGP_E6A; | 
| 2837 | 7 |  |  |  |  | 16 | my $p = $a * (1 - $e * $e); | 
| 2838 | 7 |  |  |  |  | 12 | my $xnodes = $self->{ascendingnode} + $parm->{xnodot} * $tsince; | 
| 2839 | 7 |  |  |  |  | 15 | my $omgas = $self->{argumentofperigee} + $parm->{omgdt} * $tsince; | 
| 2840 |  |  |  |  |  |  | my $xls = mod2pi ($parm->{xlo} + ($self->{meanmotion} + $parm->{omgdt} + | 
| 2841 |  |  |  |  |  |  | $parm->{xnodot} + ($self->{firstderivative} + | 
| 2842 | 7 |  |  |  |  | 35 | $self->{secondderivative} * $tsince) * $tsince) * $tsince); | 
| 2843 | 7 | 50 |  |  |  | 18 | $self->{debug} and warn < | 
| 2844 |  |  |  |  |  |  | Debug sgp - atmospheric drag and gravity | 
| 2845 |  |  |  |  |  |  | TSINCE = $tsince | 
| 2846 |  |  |  |  |  |  | A = $a | 
| 2847 |  |  |  |  |  |  | E = $e | 
| 2848 |  |  |  |  |  |  | P = $p | 
| 2849 |  |  |  |  |  |  | XNODES = $xnodes | 
| 2850 |  |  |  |  |  |  | OMGAS = $omgas | 
| 2851 |  |  |  |  |  |  | XLS = $xls | 
| 2852 |  |  |  |  |  |  | eod | 
| 2853 |  |  |  |  |  |  |  | 
| 2854 |  |  |  |  |  |  | #*	Long period periodics. | 
| 2855 |  |  |  |  |  |  |  | 
| 2856 | 7 |  |  |  |  | 19 | my $axnsl = $e * cos ($omgas); | 
| 2857 | 7 |  |  |  |  | 17 | my $aynsl = $e * sin ($omgas) - $parm->{c6} / $p; | 
| 2858 | 7 |  |  |  |  | 25 | my $xl = mod2pi ($xls - $parm->{c5} / $p * $axnsl); | 
| 2859 | 7 | 50 |  |  |  | 24 | $self->{debug} and warn < | 
| 2860 |  |  |  |  |  |  | Debug sgp - long period periodics | 
| 2861 |  |  |  |  |  |  | AXNSL = $axnsl | 
| 2862 |  |  |  |  |  |  | AYNSL = $aynsl | 
| 2863 |  |  |  |  |  |  | XL = $xl | 
| 2864 |  |  |  |  |  |  | eod | 
| 2865 |  |  |  |  |  |  |  | 
| 2866 |  |  |  |  |  |  | #*	Solve Kepler's equation. | 
| 2867 |  |  |  |  |  |  |  | 
| 2868 | 7 |  |  |  |  | 50 | my $u = mod2pi ($xl - $xnodes); | 
| 2869 | 7 |  |  |  |  | 16 | my ($item3, $eo1, $tem5) = (0, $u, 1); | 
| 2870 | 7 |  |  |  |  | 17 | my ($sineo1, $coseo1); | 
| 2871 | 7 |  |  |  |  | 19 | while (1) { | 
| 2872 | 27 |  |  |  |  | 52 | $sineo1 = sin ($eo1); | 
| 2873 | 27 |  |  |  |  | 40 | $coseo1 = cos ($eo1); | 
| 2874 | 27 | 100 | 66 |  |  | 119 | last if abs ($tem5) < SGP_E6A || $item3++ >= 10; | 
| 2875 | 20 |  |  |  |  | 33 | $tem5 = 1 - $coseo1 * $axnsl - $sineo1 * $aynsl; | 
| 2876 | 20 |  |  |  |  | 39 | $tem5 = ($u - $aynsl * $coseo1 + $axnsl * $sineo1 - $eo1) / $tem5; | 
| 2877 | 20 |  |  |  |  | 27 | my $tem2 = abs ($tem5); | 
| 2878 | 20 | 100 |  |  |  | 40 | $tem2 > 1 and $tem5 = $tem2 / $tem5; | 
| 2879 | 20 |  |  |  |  | 30 | $eo1 += $tem5; | 
| 2880 |  |  |  |  |  |  | } | 
| 2881 | 7 | 50 |  |  |  | 17 | $self->{debug} and warn < | 
| 2882 |  |  |  |  |  |  | Debug sgp - solve equation of Kepler | 
| 2883 |  |  |  |  |  |  | U = $u | 
| 2884 |  |  |  |  |  |  | EO1 = $eo1 | 
| 2885 |  |  |  |  |  |  | SINEO1 = $sineo1 | 
| 2886 |  |  |  |  |  |  | COSEO1 = $coseo1 | 
| 2887 |  |  |  |  |  |  | eod | 
| 2888 |  |  |  |  |  |  |  | 
| 2889 |  |  |  |  |  |  | #*	Short period preliminary quantities. | 
| 2890 |  |  |  |  |  |  |  | 
| 2891 | 7 |  |  |  |  | 16 | my $ecose = $axnsl * $coseo1 + $aynsl * $sineo1; | 
| 2892 | 7 |  |  |  |  | 13 | my $esine = $axnsl * $sineo1 - $aynsl * $coseo1; | 
| 2893 | 7 |  |  |  |  | 14 | my $el2 = $axnsl * $axnsl + $aynsl * $aynsl; | 
| 2894 |  |  |  |  |  |  | $self->{debug} | 
| 2895 | 7 | 50 |  |  |  | 15 | and warn "Debug - OID $oid sgp effective eccentricity $el2\n"; | 
| 2896 | 7 | 100 |  |  |  | 540 | $el2 > 1 and croak "Error - OID $oid Sgp effective eccentricity > 1"; | 
| 2897 | 5 |  |  |  |  | 9 | my $pl = $a * (1 - $el2); | 
| 2898 | 5 |  |  |  |  | 6 | my $pl2 = $pl * $pl; | 
| 2899 | 5 |  |  |  |  | 11 | my $r = $a * (1 - $ecose); | 
| 2900 | 5 |  |  |  |  | 8 | my $rdot = SGP_XKE * sqrt ($a) / $r * $esine; | 
| 2901 | 5 |  |  |  |  | 8 | my $rvdot = SGP_XKE * sqrt ($pl) / $r; | 
| 2902 | 5 |  |  |  |  | 11 | my $temp = $esine / (1 + sqrt (1 - $el2)); | 
| 2903 | 5 |  |  |  |  | 8 | my $sinu = $a / $r * ($sineo1 - $aynsl - $axnsl * $temp); | 
| 2904 | 5 |  |  |  |  | 8 | my $cosu = $a / $r * ($coseo1 - $axnsl + $aynsl * $temp); | 
| 2905 | 5 |  |  |  |  | 12 | my $su = _actan ($sinu, $cosu); | 
| 2906 | 5 | 50 |  |  |  | 14 | $self->{debug} and warn < | 
| 2907 |  |  |  |  |  |  | Debug sgp - short period preliminary quantities | 
| 2908 |  |  |  |  |  |  | PL2 = $pl2 | 
| 2909 |  |  |  |  |  |  | R = $r | 
| 2910 |  |  |  |  |  |  | RDOT = $rdot | 
| 2911 |  |  |  |  |  |  | RVDOT = $rvdot | 
| 2912 |  |  |  |  |  |  | SINU = $sinu | 
| 2913 |  |  |  |  |  |  | COSU = $cosu | 
| 2914 |  |  |  |  |  |  | SU = $su | 
| 2915 |  |  |  |  |  |  | eod | 
| 2916 |  |  |  |  |  |  |  | 
| 2917 |  |  |  |  |  |  | #*	Update for short periodics. | 
| 2918 |  |  |  |  |  |  |  | 
| 2919 | 5 |  |  |  |  | 9 | my $sin2u = ($cosu + $cosu) * $sinu; | 
| 2920 | 5 |  |  |  |  | 9 | my $cos2u = 1 - 2 * $sinu * $sinu; | 
| 2921 | 5 |  |  |  |  | 11 | my $rk = $r + $parm->{d10} / $pl * $cos2u; | 
| 2922 | 5 |  |  |  |  | 11 | my $uk = $su - $parm->{d20} / $pl2 * $sin2u; | 
| 2923 | 5 |  |  |  |  | 8 | my $xnodek = $xnodes + $parm->{d30} * $sin2u / $pl2; | 
| 2924 | 5 |  |  |  |  | 11 | my $xinck = $self->{inclination} + $parm->{d40} / $pl2 * $cos2u; | 
| 2925 |  |  |  |  |  |  |  | 
| 2926 |  |  |  |  |  |  | #* 	Orientation vectors. | 
| 2927 |  |  |  |  |  |  |  | 
| 2928 | 5 |  |  |  |  | 9 | my $sinuk = sin ($uk); | 
| 2929 | 5 |  |  |  |  | 8 | my $cosuk = cos ($uk); | 
| 2930 | 5 |  |  |  |  | 7 | my $sinnok = sin ($xnodek); | 
| 2931 | 5 |  |  |  |  | 6 | my $cosnok = cos ($xnodek); | 
| 2932 | 5 |  |  |  |  | 9 | my $sinik = sin ($xinck); | 
| 2933 | 5 |  |  |  |  | 7 | my $cosik = cos ($xinck); | 
| 2934 | 5 |  |  |  |  | 9 | my $xmx = - $sinnok * $cosik; | 
| 2935 | 5 |  |  |  |  | 8 | my $xmy = $cosnok * $cosik; | 
| 2936 | 5 |  |  |  |  | 8 | my $ux = $xmx * $sinuk + $cosnok * $cosuk; | 
| 2937 | 5 |  |  |  |  | 8 | my $uy = $xmy * $sinuk + $sinnok * $cosuk; | 
| 2938 | 5 |  |  |  |  | 8 | my $uz = $sinik * $sinuk; | 
| 2939 | 5 |  |  |  |  | 7 | my $vx = $xmx * $cosuk - $cosnok * $sinuk; | 
| 2940 | 5 |  |  |  |  | 7 | my $vy = $xmy * $cosuk - $sinnok * $sinuk; | 
| 2941 | 5 |  |  |  |  | 9 | my $vz = $sinik * $cosuk; | 
| 2942 |  |  |  |  |  |  |  | 
| 2943 |  |  |  |  |  |  | #*	Position and velocity. | 
| 2944 |  |  |  |  |  |  |  | 
| 2945 | 5 |  |  |  |  | 6 | my $x = $rk * $ux; | 
| 2946 | 5 |  |  |  |  | 8 | my $y = $rk * $uy; | 
| 2947 | 5 |  |  |  |  | 7 | my $z = $rk * $uz; | 
| 2948 | 5 |  |  |  |  | 7 | my $xdot = $rdot * $ux; | 
| 2949 | 5 |  |  |  |  | 7 | my $ydot = $rdot * $uy; | 
| 2950 | 5 |  |  |  |  | 6 | my $zdot = $rdot * $uz; | 
| 2951 | 5 |  |  |  |  | 8 | $xdot = $rvdot * $vx + $xdot; | 
| 2952 | 5 |  |  |  |  | 15 | $ydot = $rvdot * $vy + $ydot; | 
| 2953 | 5 |  |  |  |  | 6 | $zdot = $rvdot * $vz + $zdot; | 
| 2954 |  |  |  |  |  |  |  | 
| 2955 | 5 |  |  |  |  | 19 | return _convert_out($self, $x, $y, $z, $xdot, $ydot, $zdot, $time); | 
| 2956 |  |  |  |  |  |  | } | 
| 2957 |  |  |  |  |  |  |  | 
| 2958 |  |  |  |  |  |  | =item $tle = $tle->sgp4($time) | 
| 2959 |  |  |  |  |  |  |  | 
| 2960 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 2961 |  |  |  |  |  |  | object at the given time, using the SGP4 model. The universal time of | 
| 2962 |  |  |  |  |  |  | the object is set to $time, and the 'equinox_dynamical' attribute is set | 
| 2963 |  |  |  |  |  |  | to the current value of the 'epoch_dynamical' attribute. | 
| 2964 |  |  |  |  |  |  |  | 
| 2965 |  |  |  |  |  |  | The result is the original object reference. See the L | 
| 2966 |  |  |  |  |  |  | heading above for how to retrieve the coordinates you just calculated. | 
| 2967 |  |  |  |  |  |  |  | 
| 2968 |  |  |  |  |  |  | "Spacetrack Report Number 3" (see "Acknowledgments") says that this | 
| 2969 |  |  |  |  |  |  | model can be used only for near-earth orbits. | 
| 2970 |  |  |  |  |  |  |  | 
| 2971 |  |  |  |  |  |  | =cut | 
| 2972 |  |  |  |  |  |  |  | 
| 2973 |  |  |  |  |  |  | sub sgp4 { | 
| 2974 | 7 |  |  | 7 | 1 | 18 | my ($self, $time) = @_; | 
| 2975 | 7 |  |  |  |  | 15 | my $oid = $self->get('id'); | 
| 2976 | 7 |  |  |  |  | 15 | $self->{model_error} = undef; | 
| 2977 | 7 |  |  |  |  | 21 | my $tsince = ($time - $self->{epoch}) / 60;	# Calc. is in minutes. | 
| 2978 |  |  |  |  |  |  |  | 
| 2979 |  |  |  |  |  |  | #>>>	Rather than use a separate indicator argument to trigger | 
| 2980 |  |  |  |  |  |  | #>>>	initialization of the model, we use the Orcish maneuver to | 
| 2981 |  |  |  |  |  |  | #>>>	retrieve the results of initialization, performing the | 
| 2982 |  |  |  |  |  |  | #>>>	calculations if needed. -- TRW | 
| 2983 |  |  |  |  |  |  |  | 
| 2984 | 7 |  | 66 |  |  | 39 | my $parm = $self->{&TLE_INIT}{TLE_sgp4} ||= do { | 
| 2985 | 2 | 50 |  |  |  | 8 | $self->is_deep and croak < | 
| 2986 |  |  |  |  |  |  | Error - The SGP4 model is not valid for deep space objects. | 
| 2987 |  |  |  |  |  |  | Use the SDP4, SDP4R or SDP8 models instead. | 
| 2988 |  |  |  |  |  |  | EOD | 
| 2989 |  |  |  |  |  |  |  | 
| 2990 |  |  |  |  |  |  | #*	Recover original mean motion (XNODP) and semimajor axis (AODP) | 
| 2991 |  |  |  |  |  |  | #*	from input elements. | 
| 2992 |  |  |  |  |  |  |  | 
| 2993 | 2 |  |  |  |  | 12 | my $a1 = (SGP_XKE / $self->{meanmotion}) ** SGP_TOTHRD; | 
| 2994 | 2 |  |  |  |  | 7 | my $cosi0 = cos ($self->{inclination}); | 
| 2995 | 2 |  |  |  |  | 5 | my $theta2 = $cosi0 * $cosi0; | 
| 2996 | 2 |  |  |  |  | 6 | my $x3thm1 = 3 * $theta2 - 1; | 
| 2997 | 2 |  |  |  |  | 6 | my $eosq = $self->{eccentricity} * $self->{eccentricity}; | 
| 2998 | 2 |  |  |  |  | 5 | my $beta02 = 1 - $eosq; | 
| 2999 | 2 |  |  |  |  | 4 | my $beta0 = sqrt ($beta02); | 
| 3000 | 2 |  |  |  |  | 6 | my $del1 = 1.5 * SGP_CK2 * $x3thm1 / ($a1 * $a1 * $beta0 * $beta02); | 
| 3001 | 2 |  |  |  |  | 7 | my $a0 = $a1 * (1 - $del1 * (.5 * SGP_TOTHRD + $del1 * (1 + 134 | 
| 3002 |  |  |  |  |  |  | / 81 * $del1))); | 
| 3003 | 2 |  |  |  |  | 5 | my $del0 = 1.5 * SGP_CK2 * $x3thm1 / ($a0 * $a0 * $beta0 * $beta02); | 
| 3004 | 2 |  |  |  |  | 5 | my $xnodp = $self->{meanmotion} / (1 + $del0); | 
| 3005 | 2 |  |  |  |  | 6 | my $aodp = $a0 / (1 - $del0); | 
| 3006 |  |  |  |  |  |  |  | 
| 3007 |  |  |  |  |  |  | #*	Initialization | 
| 3008 |  |  |  |  |  |  |  | 
| 3009 |  |  |  |  |  |  | #*	For perigee less than 220 kilometers, the ISIMP flag is set and | 
| 3010 |  |  |  |  |  |  | #*	the equations are truncated to linear variation in sqrt(A) and | 
| 3011 |  |  |  |  |  |  | #*	quadratic variation in mean anomaly. Also, the C3 term, the | 
| 3012 |  |  |  |  |  |  | #*	delta omega term, and the delta M term are dropped. | 
| 3013 |  |  |  |  |  |  |  | 
| 3014 |  |  |  |  |  |  | #>>>	Note that the original code sets ISIMP to 1 or 0, but we just | 
| 3015 |  |  |  |  |  |  | #>>>	set $isimp to true or false. - TRW | 
| 3016 |  |  |  |  |  |  |  | 
| 3017 | 2 |  |  |  |  | 5 | my $isimp = ($aodp * (1 - $self->{eccentricity}) / SGP_AE) < | 
| 3018 |  |  |  |  |  |  | (220 / SGP_XKMPER + SGP_AE); | 
| 3019 |  |  |  |  |  |  |  | 
| 3020 |  |  |  |  |  |  | #*	For perigee below 156 KM, the values of | 
| 3021 |  |  |  |  |  |  | #*	S and QOMS2T are altered. | 
| 3022 |  |  |  |  |  |  |  | 
| 3023 | 2 |  |  |  |  | 5 | my $s4 = SGP_S; | 
| 3024 | 2 |  |  |  |  | 5 | my $qoms24 = SGP_QOMS2T; | 
| 3025 | 2 |  |  |  |  | 5 | my $perige = ($aodp * (1 - $self->{eccentricity}) - SGP_AE) * | 
| 3026 |  |  |  |  |  |  | SGP_XKMPER; | 
| 3027 | 2 | 50 |  |  |  | 9 | unless ($perige >= 156) { | 
| 3028 | 0 | 0 |  |  |  | 0 | $s4 = $perige > 98 ? $perige - 78 : 20; | 
| 3029 | 0 |  |  |  |  | 0 | $qoms24 = ((120 - $s4) * SGP_AE / SGP_XKMPER) ** 4; | 
| 3030 | 0 |  |  |  |  | 0 | $s4 = $s4 / SGP_XKMPER + SGP_AE; | 
| 3031 |  |  |  |  |  |  | } | 
| 3032 | 2 |  |  |  |  | 6 | my $pinvsq = 1 / ($aodp * $aodp * $beta02 * $beta02); | 
| 3033 | 2 |  |  |  |  | 16 | my $tsi = 1 / ($aodp - $s4); | 
| 3034 | 2 |  |  |  |  | 8 | my $eta = $aodp * $self->{eccentricity} * $tsi; | 
| 3035 | 2 |  |  |  |  | 4 | my $etasq = $eta * $eta; | 
| 3036 | 2 |  |  |  |  | 5 | my $eeta = $self->{eccentricity} * $eta; | 
| 3037 | 2 |  |  |  |  | 6 | my $psisq = abs (1 - $etasq); | 
| 3038 | 2 |  |  |  |  | 6 | my $coef = $qoms24 * $tsi ** 4; | 
| 3039 | 2 |  |  |  |  | 6 | my $coef1 = $coef / $psisq ** 3.5; | 
| 3040 | 2 |  |  |  |  | 12 | my $c2 = $coef1 * $xnodp * ($aodp * (1 + 1.5 * $etasq + $eeta * | 
| 3041 |  |  |  |  |  |  | (4 + $etasq)) + .75 * SGP_CK2 * $tsi / $psisq * $x3thm1 | 
| 3042 |  |  |  |  |  |  | * (8 + 3 * $etasq * (8 + $etasq))); | 
| 3043 | 2 |  |  |  |  | 5 | my $c1 = $self->{bstardrag} * $c2; | 
| 3044 | 2 |  |  |  |  | 6 | my $sini0 = sin ($self->{inclination}); | 
| 3045 | 2 |  |  |  |  | 3 | my $a3ovk2 = - SGP_XJ3 / SGP_CK2 * SGP_AE ** 3; | 
| 3046 |  |  |  |  |  |  | my $c3 = $coef * $tsi * $a3ovk2 * $xnodp * SGP_AE * $sini0 / | 
| 3047 | 2 |  |  |  |  | 7 | $self->{eccentricity}; | 
| 3048 | 2 |  |  |  |  | 7 | my $x1mth2 = 1 - $theta2; | 
| 3049 |  |  |  |  |  |  | my $c4 = 2 * $xnodp * $coef1 * $aodp * $beta02 * ($eta * (2 + .5 | 
| 3050 |  |  |  |  |  |  | * $etasq) + $self->{eccentricity} * (.5 + 2 * $etasq) - | 
| 3051 |  |  |  |  |  |  | 2 * SGP_CK2 * $tsi / ($aodp * $psisq) * (-3 * $x3thm1 * (1 - | 
| 3052 |  |  |  |  |  |  | 2 * $eeta + $etasq * (1.5 - .5 * $eeta)) + .75 * | 
| 3053 |  |  |  |  |  |  | $x1mth2 * (2 * $etasq - $eeta * (1 + $etasq)) * cos (2 * | 
| 3054 | 2 |  |  |  |  | 22 | $self->{argumentofperigee}))); | 
| 3055 | 2 |  |  |  |  | 7 | my $c5 = 2 * $coef1 * $aodp * $beta02 * (1 + 2.75 * ($etasq + | 
| 3056 |  |  |  |  |  |  | $eeta) + $eeta * $etasq); | 
| 3057 | 2 |  |  |  |  | 4 | my $theta4 = $theta2 * $theta2; | 
| 3058 | 2 |  |  |  |  | 4 | my $temp1 = 3 * SGP_CK2 * $pinvsq * $xnodp; | 
| 3059 | 2 |  |  |  |  | 5 | my $temp2 = $temp1 * SGP_CK2 * $pinvsq; | 
| 3060 | 2 |  |  |  |  | 4 | my $temp3 = 1.25 * SGP_CK4 * $pinvsq * $pinvsq * $xnodp; | 
| 3061 | 2 |  |  |  |  | 7 | my $xmdot = $xnodp + .5 * $temp1 * $beta0 * $x3thm1 + .0625 * | 
| 3062 |  |  |  |  |  |  | $temp2 * $beta0 * (13 - 78 * $theta2 + 137 * $theta4); | 
| 3063 | 2 |  |  |  |  | 5 | my $x1m5th = 1 - 5 * $theta2; | 
| 3064 | 2 |  |  |  |  | 9 | my $omgdot = -.5 * $temp1 * $x1m5th + .0625 * $temp2 * (7 - 114 | 
| 3065 |  |  |  |  |  |  | * $theta2 + 395 * $theta4) + $temp3 * (3 - 36 * $theta2 + 49 | 
| 3066 |  |  |  |  |  |  | * $theta4); | 
| 3067 | 2 |  |  |  |  | 12 | my $xhdot1 = - $temp1 * $cosi0; | 
| 3068 | 2 |  |  |  |  | 11 | my $xnodot = $xhdot1 + (.5 * $temp2 * (4 - 19 * $theta2) + 2 * | 
| 3069 |  |  |  |  |  |  | $temp3 * (3 - 7 * $theta2)) * $cosi0; | 
| 3070 |  |  |  |  |  |  | my $omgcof = $self->{bstardrag} * $c3 * cos | 
| 3071 | 2 |  |  |  |  | 8 | ($self->{argumentofperigee}); | 
| 3072 | 2 |  |  |  |  | 7 | my $xmcof = - SGP_TOTHRD * $coef * $self->{bstardrag} * SGP_AE / $eeta; | 
| 3073 | 2 |  |  |  |  | 5 | my $xnodcf = 3.5 * $beta02 * $xhdot1 * $c1; | 
| 3074 | 2 |  |  |  |  | 4 | my $t2cof = 1.5 * $c1; | 
| 3075 | 2 |  |  |  |  | 10 | my $xlcof = .125 * $a3ovk2 * $sini0 * (3 + 5 * $cosi0) / (1 + $cosi0); | 
| 3076 | 2 |  |  |  |  | 4 | my $aycof = .25 * $a3ovk2 * $sini0; | 
| 3077 | 2 |  |  |  |  | 8 | my $delmo = (1 + $eta * cos ($self->{meananomaly})) ** 3; | 
| 3078 | 2 |  |  |  |  | 5 | my $sinmo = sin ($self->{meananomaly}); | 
| 3079 | 2 |  |  |  |  | 4 | my $x7thm1 = 7 * $theta2 - 1; | 
| 3080 | 2 |  |  |  |  | 6 | my ($d2, $d3, $d4, $t3cof, $t4cof, $t5cof); | 
| 3081 | 2 | 50 |  |  |  | 7 | $isimp or do { | 
| 3082 | 0 |  |  |  |  | 0 | my $c1sq = $c1 * $c1; | 
| 3083 | 0 |  |  |  |  | 0 | $d2 = 4 * $aodp * $tsi * $c1sq; | 
| 3084 | 0 |  |  |  |  | 0 | my $temp = $d2 * $tsi * $c1 / 3; | 
| 3085 | 0 |  |  |  |  | 0 | $d3 = (17 * $aodp + $s4) * $temp; | 
| 3086 | 0 |  |  |  |  | 0 | $d4 = .5 * $temp * $aodp * $tsi * (221 * $aodp + 31 * $s4) * $c1; | 
| 3087 | 0 |  |  |  |  | 0 | $t3cof = $d2 + 2 * $c1sq; | 
| 3088 | 0 |  |  |  |  | 0 | $t4cof = .25 * (3 * $d3 * $c1 * (12 * $d2 + 10 * $c1sq)); | 
| 3089 | 0 |  |  |  |  | 0 | $t5cof = .2 * (3 * $d4 + 12 * $c1 * $d3 + 6 * $d2 * $d2 + 15 | 
| 3090 |  |  |  |  |  |  | * $c1sq * ( 2 * $d2 + $c1sq)); | 
| 3091 |  |  |  |  |  |  | }; | 
| 3092 | 2 | 50 |  |  |  | 7 | $self->{debug} and print < | 
| 3093 |  |  |  |  |  |  | Debug SGP4 - Initialize | 
| 3094 |  |  |  |  |  |  | AODP = $aodp | 
| 3095 |  |  |  |  |  |  | AYCOF = $aycof | 
| 3096 |  |  |  |  |  |  | C1 = $c1 | 
| 3097 |  |  |  |  |  |  | C4 = $c4 | 
| 3098 |  |  |  |  |  |  | C5 = $c5 | 
| 3099 |  |  |  |  |  |  | COSIO = $cosi0 | 
| 3100 | 0 | 0 |  |  |  | 0 | D2 = @{[defined $d2 ? $d2 : 'undef']} | 
| 3101 | 0 | 0 |  |  |  | 0 | D3 = @{[defined $d3 ? $d3 : 'undef']} | 
| 3102 | 0 | 0 |  |  |  | 0 | D4 = @{[defined $d4 ? $d4 : 'undef']} | 
| 3103 |  |  |  |  |  |  | DELMO = $delmo | 
| 3104 |  |  |  |  |  |  | ETA = $eta | 
| 3105 |  |  |  |  |  |  | ISIMP = $isimp | 
| 3106 |  |  |  |  |  |  | OMGCOF = $omgcof | 
| 3107 |  |  |  |  |  |  | OMGDOT = $omgdot | 
| 3108 |  |  |  |  |  |  | SINIO = $sini0 | 
| 3109 |  |  |  |  |  |  | SINMO = $sinmo | 
| 3110 | 0 | 0 |  |  |  | 0 | T2COF = @{[defined $t2cof ? $t2cof : 'undef']} | 
| 3111 | 0 | 0 |  |  |  | 0 | T3COF = @{[defined $t3cof ? $t3cof : 'undef']} | 
| 3112 | 0 | 0 |  |  |  | 0 | T4COF = @{[defined $t4cof ? $t4cof : 'undef']} | 
| 3113 | 0 | 0 |  |  |  | 0 | T5COF = @{[defined $t5cof ? $t5cof : 'undef']} | 
| 3114 |  |  |  |  |  |  | X1MTH2 = $x1mth2 | 
| 3115 |  |  |  |  |  |  | X3THM1 = $x3thm1 | 
| 3116 |  |  |  |  |  |  | X7THM1 = $x7thm1 | 
| 3117 |  |  |  |  |  |  | XLCOF = $xlcof | 
| 3118 |  |  |  |  |  |  | XMCOF = $xmcof | 
| 3119 |  |  |  |  |  |  | XMDOT = $xmdot | 
| 3120 |  |  |  |  |  |  | XNODCF = $xnodcf | 
| 3121 |  |  |  |  |  |  | XNODOT = $xnodot | 
| 3122 |  |  |  |  |  |  | XNODP = $xnodp | 
| 3123 |  |  |  |  |  |  | eod | 
| 3124 |  |  |  |  |  |  | { | 
| 3125 | 2 |  |  |  |  | 52 | aodp => $aodp, | 
| 3126 |  |  |  |  |  |  | aycof => $aycof, | 
| 3127 |  |  |  |  |  |  | c1 => $c1, | 
| 3128 |  |  |  |  |  |  | c4 => $c4, | 
| 3129 |  |  |  |  |  |  | c5 => $c5, | 
| 3130 |  |  |  |  |  |  | cosi0 => $cosi0, | 
| 3131 |  |  |  |  |  |  | d2 => $d2, | 
| 3132 |  |  |  |  |  |  | d3 => $d3, | 
| 3133 |  |  |  |  |  |  | d4 => $d4, | 
| 3134 |  |  |  |  |  |  | delmo => $delmo, | 
| 3135 |  |  |  |  |  |  | eta => $eta, | 
| 3136 |  |  |  |  |  |  | isimp => $isimp, | 
| 3137 |  |  |  |  |  |  | omgcof => $omgcof, | 
| 3138 |  |  |  |  |  |  | omgdot => $omgdot, | 
| 3139 |  |  |  |  |  |  | sini0 => $sini0, | 
| 3140 |  |  |  |  |  |  | sinmo => $sinmo, | 
| 3141 |  |  |  |  |  |  | t2cof => $t2cof, | 
| 3142 |  |  |  |  |  |  | t3cof => $t3cof, | 
| 3143 |  |  |  |  |  |  | t4cof => $t4cof, | 
| 3144 |  |  |  |  |  |  | t5cof => $t5cof, | 
| 3145 |  |  |  |  |  |  | x1mth2 => $x1mth2, | 
| 3146 |  |  |  |  |  |  | x3thm1 => $x3thm1, | 
| 3147 |  |  |  |  |  |  | x7thm1 => $x7thm1, | 
| 3148 |  |  |  |  |  |  | xlcof => $xlcof, | 
| 3149 |  |  |  |  |  |  | xmcof => $xmcof, | 
| 3150 |  |  |  |  |  |  | xmdot => $xmdot, | 
| 3151 |  |  |  |  |  |  | xnodcf => $xnodcf, | 
| 3152 |  |  |  |  |  |  | xnodot => $xnodot, | 
| 3153 |  |  |  |  |  |  | xnodp => $xnodp, | 
| 3154 |  |  |  |  |  |  | }; | 
| 3155 |  |  |  |  |  |  | }; | 
| 3156 |  |  |  |  |  |  |  | 
| 3157 |  |  |  |  |  |  | #*	Update for secular gravity and atmospheric drag. | 
| 3158 |  |  |  |  |  |  |  | 
| 3159 | 7 |  |  |  |  | 22 | my $xmdf = $self->{meananomaly} + $parm->{xmdot} * $tsince; | 
| 3160 | 7 |  |  |  |  | 15 | my $omgadf = $self->{argumentofperigee} + $parm->{omgdot} * $tsince; | 
| 3161 | 7 |  |  |  |  | 25 | my $xnoddf = $self->{ascendingnode} + $parm->{xnodot} * $tsince; | 
| 3162 | 7 |  |  |  |  | 13 | my $omega = $omgadf; | 
| 3163 | 7 |  |  |  |  | 11 | my $xmp = $xmdf; | 
| 3164 | 7 |  |  |  |  | 10 | my $tsq = $tsince * $tsince; | 
| 3165 | 7 |  |  |  |  | 14 | my $xnode = $xnoddf + $parm->{xnodcf} * $tsq; | 
| 3166 | 7 |  |  |  |  | 16 | my $tempa = 1 - $parm->{c1} * $tsince; | 
| 3167 | 7 |  |  |  |  | 15 | my $tempe = $self->{bstardrag} * $parm->{c4} * $tsince; | 
| 3168 | 7 |  |  |  |  | 13 | my $templ = $parm->{t2cof} * $tsq; | 
| 3169 | 7 | 50 |  |  |  | 23 | $parm->{isimp} or do { | 
| 3170 | 0 |  |  |  |  | 0 | my $delomg = $parm->{omgcof} * $tsince; | 
| 3171 |  |  |  |  |  |  | my $delm = $parm->{xmcof} * ((1 + $parm->{eta} * cos($xmdf)) ** | 
| 3172 | 0 |  |  |  |  | 0 | 3 - $parm->{delmo}); | 
| 3173 | 0 |  |  |  |  | 0 | my $temp = $delomg + $delm; | 
| 3174 | 0 |  |  |  |  | 0 | $xmp = $xmdf + $temp; | 
| 3175 | 0 |  |  |  |  | 0 | $omega = $omgadf - $temp; | 
| 3176 | 0 |  |  |  |  | 0 | my $tcube = $tsq * $tsince; | 
| 3177 | 0 |  |  |  |  | 0 | my $tfour = $tsince * $tcube; | 
| 3178 |  |  |  |  |  |  | $tempa = $tempa - $parm->{d2} * $tsq - $parm->{d3} * $tcube - | 
| 3179 | 0 |  |  |  |  | 0 | $parm->{d4} * $tfour; | 
| 3180 |  |  |  |  |  |  | $tempe = $tempe + $self->{bstardrag} * $parm->{c5} * (sin($xmp) | 
| 3181 | 0 |  |  |  |  | 0 | - $parm->{sinmo}); | 
| 3182 |  |  |  |  |  |  | $templ = $templ + $parm->{t3cof} * $tcube + $tfour * | 
| 3183 | 0 |  |  |  |  | 0 | ($parm->{t4cof} + $tsince * $parm->{t5cof}); | 
| 3184 |  |  |  |  |  |  | }; | 
| 3185 | 7 |  |  |  |  | 32 | my $a = $parm->{aodp} * $tempa ** 2; | 
| 3186 | 7 |  |  |  |  | 18 | my $e = $self->{eccentricity} - $tempe; | 
| 3187 | 7 |  |  |  |  | 17 | my $xl = $xmp + $omega + $xnode + $parm->{xnodp} * $templ; | 
| 3188 |  |  |  |  |  |  | $self->{debug} | 
| 3189 | 7 | 50 |  |  |  | 19 | and warn "Debug - OID $oid sgp4 effective eccentricity $e\n"; | 
| 3190 | 7 | 100 | 66 |  |  | 42 | croak < 1 || $e < -1; | 
| 3191 |  |  |  |  |  |  | Error - OID $oid Sgp4 effective eccentricity > 1 | 
| 3192 | 2 |  |  |  |  | 6 | Epoch = @{[scalar gmtime $self->get ('epoch')]} GMT | 
| 3193 |  |  |  |  |  |  | \$self->{bstardrag} = $self->{bstardrag} | 
| 3194 |  |  |  |  |  |  | \$parm->{c4} = $parm->{c4} | 
| 3195 |  |  |  |  |  |  | \$tsince = $tsince | 
| 3196 |  |  |  |  |  |  | \$tempe = \$self->{bstardrag} * \$parm->{c4} * \$tsince | 
| 3197 |  |  |  |  |  |  | \$tempe = $tempe | 
| 3198 |  |  |  |  |  |  | \$self->{eccentricity} = $self->{eccentricity} | 
| 3199 |  |  |  |  |  |  | \$e = \$self->{eccentricity} - \$tempe | 
| 3200 |  |  |  |  |  |  | \$e = $e | 
| 3201 |  |  |  |  |  |  | Either this object represents a bad set of elements, or you are | 
| 3202 |  |  |  |  |  |  | using it beyond its "best by" date ("expiry date" in some dialects | 
| 3203 |  |  |  |  |  |  | of English). | 
| 3204 |  |  |  |  |  |  | eod | 
| 3205 | 5 |  |  |  |  | 12 | my $beta = sqrt(1 - $e * $e); | 
| 3206 | 5 | 50 |  |  |  | 12 | $self->{debug} and print < | 
| 3207 |  |  |  |  |  |  | Debug SGP4 - Before xn, | 
| 3208 | 0 |  |  |  |  | 0 | XKE = @{[SGP_XKE]} | 
| 3209 |  |  |  |  |  |  | A = $a | 
| 3210 |  |  |  |  |  |  | TEMPA = $tempa | 
| 3211 |  |  |  |  |  |  | AODP = $parm->{aodp} | 
| 3212 |  |  |  |  |  |  | eod | 
| 3213 | 5 |  |  |  |  | 14 | my $xn = SGP_XKE / $a ** 1.5; | 
| 3214 |  |  |  |  |  |  |  | 
| 3215 |  |  |  |  |  |  | #*	Long period periodics | 
| 3216 |  |  |  |  |  |  |  | 
| 3217 | 5 |  |  |  |  | 11 | my $axn = $e * cos($omega); | 
| 3218 | 5 |  |  |  |  | 10 | my $temp = 1 / ($a * $beta * $beta); | 
| 3219 | 5 |  |  |  |  | 9 | my $xll = $temp * $parm->{xlcof} * $axn; | 
| 3220 | 5 |  |  |  |  | 8 | my $aynl = $temp * $parm->{aycof}; | 
| 3221 | 5 |  |  |  |  | 7 | my $xlt = $xl + $xll; | 
| 3222 | 5 |  |  |  |  | 11 | my $ayn = $e * sin($omega) + $aynl; | 
| 3223 |  |  |  |  |  |  |  | 
| 3224 |  |  |  |  |  |  | #*	Solve Kepler's equation. | 
| 3225 |  |  |  |  |  |  |  | 
| 3226 | 5 |  |  |  |  | 17 | my $capu = mod2pi($xlt - $xnode); | 
| 3227 | 5 |  |  |  |  | 9 | my $temp2 = $capu; | 
| 3228 | 5 |  |  |  |  | 10 | my ($temp3, $temp4, $temp5, $temp6, $sinepw, $cosepw); | 
| 3229 | 5 |  |  |  |  | 14 | for (my $i = 0; $i < 10; $i++) { | 
| 3230 | 10 |  |  |  |  | 35 | $sinepw = sin($temp2); | 
| 3231 | 10 |  |  |  |  | 20 | $cosepw = cos($temp2); | 
| 3232 | 10 |  |  |  |  | 13 | $temp3 = $axn * $sinepw; | 
| 3233 | 10 |  |  |  |  | 12 | $temp4 = $ayn * $cosepw; | 
| 3234 | 10 |  |  |  |  | 15 | $temp5 = $axn * $cosepw; | 
| 3235 | 10 |  |  |  |  | 14 | $temp6 = $ayn * $sinepw; | 
| 3236 | 10 |  |  |  |  | 21 | my $epw = ($capu - $temp4 + $temp3 - $temp2) / (1 - $temp5 - | 
| 3237 |  |  |  |  |  |  | $temp6) + $temp2; | 
| 3238 | 10 | 100 |  |  |  | 25 | abs ($epw - $temp2) <= SGP_E6A and last; | 
| 3239 | 5 |  |  |  |  | 11 | $temp2 = $epw; | 
| 3240 |  |  |  |  |  |  | } | 
| 3241 |  |  |  |  |  |  |  | 
| 3242 |  |  |  |  |  |  | #*	Short period preliminary quantities. | 
| 3243 |  |  |  |  |  |  |  | 
| 3244 | 5 |  |  |  |  | 9 | my $ecose = $temp5 + $temp6; | 
| 3245 | 5 |  |  |  |  | 10 | my $esine = $temp3 - $temp4; | 
| 3246 | 5 |  |  |  |  | 14 | my $elsq = $axn * $axn + $ayn * $ayn; | 
| 3247 | 5 |  |  |  |  | 9 | $temp = 1 - $elsq; | 
| 3248 | 5 |  |  |  |  | 7 | my $pl = $a * $temp; | 
| 3249 | 5 |  |  |  |  | 9 | my $r = $a * (1 - $ecose); | 
| 3250 | 5 |  |  |  |  | 7 | my $temp1 = 1 / $r; | 
| 3251 | 5 |  |  |  |  | 10 | my $rdot = SGP_XKE * sqrt($a) * $esine * $temp1; | 
| 3252 | 5 |  |  |  |  | 8 | my $rfdot = SGP_XKE * sqrt($pl) * $temp1; | 
| 3253 | 5 |  |  |  |  | 8 | $temp2 = $a * $temp1; | 
| 3254 | 5 |  |  |  |  | 9 | my $betal = sqrt($temp); | 
| 3255 | 5 |  |  |  |  | 8 | $temp3 = 1 / (1 + $betal); | 
| 3256 | 5 |  |  |  |  | 9 | my $cosu = $temp2 * ($cosepw - $axn + $ayn * $esine * $temp3); | 
| 3257 | 5 |  |  |  |  | 8 | my $sinu = $temp2 * ($sinepw - $ayn - $axn * $esine * $temp3); | 
| 3258 | 5 |  |  |  |  | 14 | my $u = _actan($sinu,$cosu); | 
| 3259 | 5 |  |  |  |  | 10 | my $sin2u = 2 * $sinu * $cosu; | 
| 3260 | 5 |  |  |  |  | 10 | my $cos2u = 2 * $cosu * $cosu - 1; | 
| 3261 | 5 |  |  |  |  | 7 | $temp = 1 / $pl; | 
| 3262 | 5 |  |  |  |  | 7 | $temp1 = SGP_CK2 * $temp; | 
| 3263 | 5 |  |  |  |  | 9 | $temp2 = $temp1 * $temp; | 
| 3264 |  |  |  |  |  |  |  | 
| 3265 |  |  |  |  |  |  | #*	Update for short periodics | 
| 3266 |  |  |  |  |  |  |  | 
| 3267 |  |  |  |  |  |  | my $rk = $r * (1 - 1.5 * $temp2 * $betal * $parm->{x3thm1}) + .5 * | 
| 3268 | 5 |  |  |  |  | 12 | $temp1 * $parm->{x1mth2} * $cos2u; | 
| 3269 | 5 |  |  |  |  | 9 | my $uk = $u - .25 * $temp2 * $parm->{x7thm1} * $sin2u; | 
| 3270 | 5 |  |  |  |  | 10 | my $xnodek = $xnode + 1.5 * $temp2 * $parm->{cosi0} * $sin2u; | 
| 3271 |  |  |  |  |  |  | my $xinck = $self->{inclination} + 1.5 * $temp2 * $parm->{cosi0} * | 
| 3272 | 5 |  |  |  |  | 10 | $parm->{sini0} * $cos2u; | 
| 3273 | 5 |  |  |  |  | 8 | my $rdotk = $rdot - $xn * $temp1 * $parm->{x1mth2} * $sin2u; | 
| 3274 |  |  |  |  |  |  | my $rfdotk = $rfdot + $xn * $temp1 * ($parm->{x1mth2} * $cos2u + 1.5 | 
| 3275 | 5 |  |  |  |  | 10 | * $parm->{x3thm1}); | 
| 3276 |  |  |  |  |  |  |  | 
| 3277 |  |  |  |  |  |  | #*	Orientation vectors | 
| 3278 |  |  |  |  |  |  |  | 
| 3279 | 5 |  |  |  |  | 10 | my $sinuk = sin ($uk); | 
| 3280 | 5 |  |  |  |  | 9 | my $cosuk = cos ($uk); | 
| 3281 | 5 |  |  |  |  | 8 | my $sinik = sin ($xinck); | 
| 3282 | 5 |  |  |  |  | 6 | my $cosik = cos ($xinck); | 
| 3283 | 5 |  |  |  |  | 8 | my $sinnok = sin ($xnodek); | 
| 3284 | 5 |  |  |  |  | 9 | my $cosnok = cos ($xnodek); | 
| 3285 | 5 |  |  |  |  | 10 | my $xmx = - $sinnok * $cosik; | 
| 3286 | 5 |  |  |  |  | 7 | my $xmy = $cosnok * $cosik; | 
| 3287 | 5 |  |  |  |  | 10 | my $ux = $xmx * $sinuk + $cosnok * $cosuk; | 
| 3288 | 5 |  |  |  |  | 7 | my $uy = $xmy * $sinuk + $sinnok * $cosuk; | 
| 3289 | 5 |  |  |  |  | 7 | my $uz = $sinik * $sinuk; | 
| 3290 | 5 |  |  |  |  | 15 | my $vx = $xmx * $cosuk - $cosnok * $sinuk; | 
| 3291 | 5 |  |  |  |  | 8 | my $vy = $xmy * $cosuk - $sinnok * $sinuk; | 
| 3292 | 5 |  |  |  |  | 8 | my $vz = $sinik * $cosuk; | 
| 3293 |  |  |  |  |  |  |  | 
| 3294 |  |  |  |  |  |  | #*	Position and velocity | 
| 3295 |  |  |  |  |  |  |  | 
| 3296 | 5 |  |  |  |  | 7 | my $x = $rk * $ux; | 
| 3297 | 5 |  |  |  |  | 7 | my $y = $rk * $uy; | 
| 3298 | 5 |  |  |  |  | 9 | my $z = $rk * $uz; | 
| 3299 | 5 |  |  |  |  | 8 | my $xdot = $rdotk * $ux + $rfdotk * $vx; | 
| 3300 | 5 |  |  |  |  | 9 | my $ydot = $rdotk * $uy + $rfdotk * $vy; | 
| 3301 | 5 |  |  |  |  | 9 | my $zdot = $rdotk * $uz + $rfdotk * $vz; | 
| 3302 |  |  |  |  |  |  |  | 
| 3303 | 5 |  |  |  |  | 12 | return _convert_out($self, $x, $y, $z, $xdot, $ydot, $zdot, $time); | 
| 3304 |  |  |  |  |  |  | } | 
| 3305 |  |  |  |  |  |  |  | 
| 3306 |  |  |  |  |  |  | =item $tle = $tle->sdp4($time) | 
| 3307 |  |  |  |  |  |  |  | 
| 3308 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 3309 |  |  |  |  |  |  | object at the given time, using the SDP4 model. The universal time of | 
| 3310 |  |  |  |  |  |  | the object is set to $time, and the 'equinox_dynamical' attribute is set | 
| 3311 |  |  |  |  |  |  | to the current value of the 'epoch_dynamical' attribute. | 
| 3312 |  |  |  |  |  |  |  | 
| 3313 |  |  |  |  |  |  | The result is the original object reference. You need to call one of | 
| 3314 |  |  |  |  |  |  | the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to | 
| 3315 |  |  |  |  |  |  | retrieve the position you just calculated. | 
| 3316 |  |  |  |  |  |  |  | 
| 3317 |  |  |  |  |  |  | "Spacetrack Report Number 3" (see "Acknowledgments") says that this | 
| 3318 |  |  |  |  |  |  | model can be used only for deep-space orbits. | 
| 3319 |  |  |  |  |  |  |  | 
| 3320 |  |  |  |  |  |  | =cut | 
| 3321 |  |  |  |  |  |  |  | 
| 3322 |  |  |  |  |  |  | sub sdp4 { | 
| 3323 | 7 |  |  | 7 | 1 | 19 | my ($self, $time) = @_; | 
| 3324 | 7 |  |  |  |  | 15 | my $oid = $self->get('id'); | 
| 3325 | 7 |  |  |  |  | 18 | $self->{model_error} = undef; | 
| 3326 | 7 |  |  |  |  | 18 | my $tsince = ($time - $self->{epoch}) / 60;	# Calc. is in minutes. | 
| 3327 |  |  |  |  |  |  |  | 
| 3328 |  |  |  |  |  |  | #>>>	Rather than use a separate indicator argument to trigger | 
| 3329 |  |  |  |  |  |  | #>>>	initialization of the model, we use the Orcish maneuver to | 
| 3330 |  |  |  |  |  |  | #>>>	retrieve the results of initialization, performing the | 
| 3331 |  |  |  |  |  |  | #>>>	calculations if needed. -- TRW | 
| 3332 |  |  |  |  |  |  |  | 
| 3333 | 7 |  | 66 |  |  | 38 | my $parm = $self->{&TLE_INIT}{TLE_sdp4} ||= do { | 
| 3334 | 2 | 50 |  |  |  | 8 | $self->is_deep or croak < | 
| 3335 |  |  |  |  |  |  | Error - The SDP4 model is not valid for near-earth objects. | 
| 3336 |  |  |  |  |  |  | Use the SGP, SGP4, SGP4R, or SGP8 models instead. | 
| 3337 |  |  |  |  |  |  | EOD | 
| 3338 |  |  |  |  |  |  |  | 
| 3339 |  |  |  |  |  |  | #*      Recover original mean motion (XNODP) and semimajor axis (AODP) | 
| 3340 |  |  |  |  |  |  | #*      from input elements. | 
| 3341 |  |  |  |  |  |  |  | 
| 3342 | 2 |  |  |  |  | 12 | my $a1 = (SGP_XKE / $self->{meanmotion}) ** SGP_TOTHRD; | 
| 3343 | 2 |  |  |  |  | 5 | my $cosi0 = cos ($self->{inclination}); | 
| 3344 | 2 |  |  |  |  | 5 | my $theta2 = $cosi0 * $cosi0; | 
| 3345 | 2 |  |  |  |  | 6 | my $x3thm1 = 3 * $theta2 - 1; | 
| 3346 | 2 |  |  |  |  | 6 | my $eosq = $self->{eccentricity} * $self->{eccentricity}; | 
| 3347 | 2 |  |  |  |  | 5 | my $beta02 = 1 - $eosq; | 
| 3348 | 2 |  |  |  |  | 5 | my $beta0 = sqrt ($beta02); | 
| 3349 | 2 |  |  |  |  | 6 | my $del1 = 1.5 * SGP_CK2 * $x3thm1 / ($a1 * $a1 * $beta0 * $beta02); | 
| 3350 | 2 |  |  |  |  | 8 | my $a0 = $a1 * (1 - $del1 * (.5 * SGP_TOTHRD + $del1 * (1 + 134 | 
| 3351 |  |  |  |  |  |  | / 81 * $del1))); | 
| 3352 | 2 |  |  |  |  | 6 | my $del0 = 1.5 * SGP_CK2 * $x3thm1 / ($a0 * $a0 * $beta0 * $beta02); | 
| 3353 | 2 |  |  |  |  | 6 | my $xnodp = $self->{meanmotion} / (1 + $del0); | 
| 3354 |  |  |  |  |  |  | # no problem here - we know this because AODP is returned. | 
| 3355 | 2 |  |  |  |  | 6 | my $aodp = $a0 / (1 - $del0); | 
| 3356 |  |  |  |  |  |  |  | 
| 3357 |  |  |  |  |  |  | #*	Initialization | 
| 3358 |  |  |  |  |  |  |  | 
| 3359 |  |  |  |  |  |  | #*	For perigee below 156 KM, the values of | 
| 3360 |  |  |  |  |  |  | #*	S and QOMS2T are altered | 
| 3361 |  |  |  |  |  |  |  | 
| 3362 | 2 |  |  |  |  | 4 | my $s4 = SGP_S; | 
| 3363 | 2 |  |  |  |  | 4 | my $qoms24 = SGP_QOMS2T; | 
| 3364 | 2 |  |  |  |  | 6 | my $perige = ($aodp * (1 - $self->{eccentricity}) - SGP_AE) * | 
| 3365 |  |  |  |  |  |  | SGP_XKMPER; | 
| 3366 | 2 | 50 |  |  |  | 10 | unless ($perige >= 156) { | 
| 3367 | 2 | 50 |  |  |  | 9 | $s4 = $perige > 98 ? $perige - 78 : 20; | 
| 3368 | 2 |  |  |  |  | 7 | $qoms24 = ((120 - $s4) * SGP_AE / SGP_XKMPER) ** 4; | 
| 3369 | 2 |  |  |  |  | 5 | $s4 = $s4 / SGP_XKMPER + SGP_AE; | 
| 3370 |  |  |  |  |  |  | } | 
| 3371 | 2 |  |  |  |  | 8 | my $pinvsq = 1 / ($aodp * $aodp * $beta02 * $beta02); | 
| 3372 | 2 |  |  |  |  | 6 | my $sing = sin ($self->{argumentofperigee}); | 
| 3373 | 2 |  |  |  |  | 4 | my $cosg = cos ($self->{argumentofperigee}); | 
| 3374 | 2 |  |  |  |  | 6 | my $tsi = 1 / ($aodp - $s4); | 
| 3375 | 2 |  |  |  |  | 6 | my $eta = $aodp * $self->{eccentricity} * $tsi; | 
| 3376 | 2 |  |  |  |  | 4 | my $etasq = $eta * $eta; | 
| 3377 | 2 |  |  |  |  | 4 | my $eeta = $self->{eccentricity} * $eta; | 
| 3378 | 2 |  |  |  |  | 6 | my $psisq = abs (1 - $etasq); | 
| 3379 | 2 |  |  |  |  | 6 | my $coef = $qoms24 * $tsi ** 4; | 
| 3380 | 2 |  |  |  |  | 6 | my $coef1 = $coef / $psisq ** 3.5; | 
| 3381 | 2 |  |  |  |  | 10 | my $c2 = $coef1 * $xnodp * ($aodp * (1 + 1.5 * $etasq + $eeta * | 
| 3382 |  |  |  |  |  |  | (4 + $etasq)) + .75 * SGP_CK2 * $tsi / $psisq * $x3thm1 * | 
| 3383 |  |  |  |  |  |  | (8 + 3 * $etasq * (8 + $etasq))); | 
| 3384 |  |  |  |  |  |  | # minor problem here | 
| 3385 | 2 |  |  |  |  | 5 | my $c1 = $self->{bstardrag} * $c2; | 
| 3386 | 2 |  |  |  |  | 5 | my $sini0 = sin ($self->{inclination}); | 
| 3387 | 2 |  |  |  |  | 4 | my $a3ovk2 = - SGP_XJ3 / SGP_CK2 * SGP_AE ** 3; | 
| 3388 | 2 |  |  |  |  | 4 | my $x1mth2 = 1 - $theta2; | 
| 3389 |  |  |  |  |  |  | my $c4 = 2 * $xnodp * $coef1 * $aodp * $beta02 * ($eta * (2 + .5 * | 
| 3390 |  |  |  |  |  |  | $etasq) + $self->{eccentricity} * (.5 + 2 * $etasq) - | 
| 3391 |  |  |  |  |  |  | 2 * SGP_CK2 * $tsi / ($aodp * $psisq) * ( - 3 * $x3thm1 * | 
| 3392 |  |  |  |  |  |  | (1 - 2 * $eeta + $etasq * (1.5 - .5 * $eeta)) + .75 * $x1mth2 * | 
| 3393 |  |  |  |  |  |  | (2 * $etasq - $eeta * (1 + $etasq)) * | 
| 3394 | 2 |  |  |  |  | 16 | cos (2 * $self->{argumentofperigee}))); | 
| 3395 | 2 |  |  |  |  | 4 | my $theta4 = $theta2 * $theta2; | 
| 3396 | 2 |  |  |  |  | 5 | my $temp1 = 3 * SGP_CK2 * $pinvsq * $xnodp; | 
| 3397 | 2 |  |  |  |  | 4 | my $temp2 = $temp1 * SGP_CK2 * $pinvsq; | 
| 3398 | 2 |  |  |  |  | 5 | my $temp3 = 1.25 * SGP_CK4 * $pinvsq * $pinvsq * $xnodp; | 
| 3399 | 2 |  |  |  |  | 7 | my $xmdot = $xnodp + .5 * $temp1 * $beta0 * $x3thm1 + | 
| 3400 |  |  |  |  |  |  | .0625 * $temp2 * $beta0 * (13 - 78 * $theta2 + 137 * $theta4); | 
| 3401 | 2 |  |  |  |  | 5 | my $x1m5th = 1 - 5 * $theta2; | 
| 3402 | 2 |  |  |  |  | 9 | my $omgdot = - .5 * $temp1 * $x1m5th + | 
| 3403 |  |  |  |  |  |  | .0625 * $temp2 * (7 - 114 * $theta2 + 395 * $theta4) + | 
| 3404 |  |  |  |  |  |  | $temp3 * (3 - 36 * $theta2 + 49 * $theta4); | 
| 3405 | 2 |  |  |  |  | 6 | my $xhdot1 = - $temp1 * $cosi0; | 
| 3406 | 2 |  |  |  |  | 8 | my $xnodot = $xhdot1 + (.5 * $temp2 * (4 - 19 * $theta2) + | 
| 3407 |  |  |  |  |  |  | 2 * $temp3 * (3 - 7 * $theta2)) * $cosi0; | 
| 3408 |  |  |  |  |  |  | # problem here (inherited from C1 problem?) | 
| 3409 | 2 |  |  |  |  | 4 | my $xnodcf = 3.5 * $beta02 * $xhdot1 * $c1; | 
| 3410 |  |  |  |  |  |  | # problem here (inherited from C1 problem?) | 
| 3411 | 2 |  |  |  |  | 5 | my $t2cof = 1.5 * $c1; | 
| 3412 | 2 |  |  |  |  | 17 | my $xlcof = .125 * $a3ovk2 * $sini0 * (3 + 5 * $cosi0) / (1 + $cosi0); | 
| 3413 | 2 |  |  |  |  | 12 | my $aycof = .25 * $a3ovk2 * $sini0; | 
| 3414 | 2 |  |  |  |  | 38 | my $x7thm1 = 7 * $theta2 - 1; | 
| 3415 | 2 |  |  |  |  | 12 | $self->{&TLE_INIT}{TLE_deep} = {$self->_dpinit ($eosq, $sini0, $cosi0, $beta0, | 
| 3416 |  |  |  |  |  |  | $aodp, $theta2, $sing, $cosg, $beta02, $xmdot, $omgdot, | 
| 3417 |  |  |  |  |  |  | $xnodot, $xnodp)}; | 
| 3418 |  |  |  |  |  |  |  | 
| 3419 | 2 | 50 |  |  |  | 15 | $self->{debug} and print < | 
| 3420 |  |  |  |  |  |  | Debug SDP4 - Initialize | 
| 3421 |  |  |  |  |  |  | AODP = $aodp | 
| 3422 |  |  |  |  |  |  | AYCOF = $aycof | 
| 3423 |  |  |  |  |  |  | C1 = $c1  << 2.45532e-06 in test_sgp-c-lib | 
| 3424 |  |  |  |  |  |  | c2 = $c2  << 0.000171569 in test_sgp-c-lib | 
| 3425 |  |  |  |  |  |  | C4 = $c4 | 
| 3426 |  |  |  |  |  |  | COSIO = $cosi0 | 
| 3427 |  |  |  |  |  |  | ETA = $eta | 
| 3428 |  |  |  |  |  |  | OMGDOT = $omgdot | 
| 3429 |  |  |  |  |  |  | s4 = $s4 | 
| 3430 |  |  |  |  |  |  | SINIO = $sini0 | 
| 3431 | 0 | 0 |  |  |  | 0 | T2COF = @{[defined $t2cof ? $t2cof : 'undef']}  << 3.68298e-06 in test_sgp-c-lib | 
| 3432 |  |  |  |  |  |  | X1MTH2 = $x1mth2 | 
| 3433 |  |  |  |  |  |  | X3THM1 = $x3thm1 | 
| 3434 |  |  |  |  |  |  | X7THM1 = $x7thm1 | 
| 3435 |  |  |  |  |  |  | XLCOF = $xlcof | 
| 3436 |  |  |  |  |  |  | XMDOT = $xmdot | 
| 3437 |  |  |  |  |  |  | XNODCF = $xnodcf  << -1.40764e-11 in test_sgp-c-lib | 
| 3438 |  |  |  |  |  |  | XNODOT = $xnodot | 
| 3439 |  |  |  |  |  |  | XNODP = $xnodp | 
| 3440 |  |  |  |  |  |  | eod | 
| 3441 |  |  |  |  |  |  | { | 
| 3442 | 2 |  |  |  |  | 36 | aodp => $aodp, | 
| 3443 |  |  |  |  |  |  | aycof => $aycof, | 
| 3444 |  |  |  |  |  |  | c1 => $c1, | 
| 3445 |  |  |  |  |  |  | c4 => $c4, | 
| 3446 |  |  |  |  |  |  | ###	    c5 => $c5, | 
| 3447 |  |  |  |  |  |  | cosi0 => $cosi0, | 
| 3448 |  |  |  |  |  |  | ###	    d2 => $d2, | 
| 3449 |  |  |  |  |  |  | ###	    d3 => $d3, | 
| 3450 |  |  |  |  |  |  | ###	    d4 => $d4, | 
| 3451 |  |  |  |  |  |  | ###	    delmo => $delmo, | 
| 3452 |  |  |  |  |  |  | eta => $eta, | 
| 3453 |  |  |  |  |  |  | ###	    isimp => $isimp, | 
| 3454 |  |  |  |  |  |  | ###	    omgcof => $omgcof, | 
| 3455 |  |  |  |  |  |  | omgdot => $omgdot, | 
| 3456 |  |  |  |  |  |  | sini0 => $sini0, | 
| 3457 |  |  |  |  |  |  | ###	    sinmo => $sinmo, | 
| 3458 |  |  |  |  |  |  | t2cof => $t2cof, | 
| 3459 |  |  |  |  |  |  | ###	    t3cof => $t3cof, | 
| 3460 |  |  |  |  |  |  | ###	    t4cof => $t4cof, | 
| 3461 |  |  |  |  |  |  | ###	    t5cof => $t5cof, | 
| 3462 |  |  |  |  |  |  | x1mth2 => $x1mth2, | 
| 3463 |  |  |  |  |  |  | x3thm1 => $x3thm1, | 
| 3464 |  |  |  |  |  |  | x7thm1 => $x7thm1, | 
| 3465 |  |  |  |  |  |  | xlcof => $xlcof, | 
| 3466 |  |  |  |  |  |  | ###	    xmcof => $xmcof, | 
| 3467 |  |  |  |  |  |  | xmdot => $xmdot, | 
| 3468 |  |  |  |  |  |  | xnodcf => $xnodcf, | 
| 3469 |  |  |  |  |  |  | xnodot => $xnodot, | 
| 3470 |  |  |  |  |  |  | xnodp => $xnodp, | 
| 3471 |  |  |  |  |  |  | }; | 
| 3472 |  |  |  |  |  |  | }; | 
| 3473 |  |  |  |  |  |  | #>>>trw    my $dpsp = $self->{&TLE_INIT}{TLE_deep}; | 
| 3474 |  |  |  |  |  |  |  | 
| 3475 |  |  |  |  |  |  | #* UPDATE FOR SECULAR GRAVITY AND ATMOSPHERIC DRAG | 
| 3476 |  |  |  |  |  |  |  | 
| 3477 | 7 |  |  |  |  | 20 | my $xmdf = $self->{meananomaly} + $parm->{xmdot} * $tsince; | 
| 3478 | 7 |  |  |  |  | 14 | my $omgadf = $self->{argumentofperigee} + $parm->{omgdot} * $tsince; | 
| 3479 | 7 |  |  |  |  | 13 | my $xnoddf = $self->{ascendingnode} + $parm->{xnodot} * $tsince; | 
| 3480 | 7 |  |  |  |  | 11 | my $tsq = $tsince * $tsince; | 
| 3481 | 7 |  |  |  |  | 15 | my $xnode = $xnoddf + $parm->{xnodcf} * $tsq; | 
| 3482 | 7 |  |  |  |  | 15 | my $tempa = 1 - $parm->{c1} * $tsince; | 
| 3483 | 7 |  |  |  |  | 15 | my $tempe = $self->{bstardrag} * $parm->{c4} * $tsince; | 
| 3484 | 7 |  |  |  |  | 13 | my $templ = $parm->{t2cof} * $tsq; | 
| 3485 | 7 |  |  |  |  | 11 | my $xn = $parm->{xnodp}; | 
| 3486 | 7 |  |  |  |  | 10 | my ($em, $xinc);	# Hope this is right. | 
| 3487 | 7 |  |  |  |  | 28 | $self->_dpsec (\$xmdf, \$omgadf, \$xnode, \$em, \$xinc, \$xn, $tsince); | 
| 3488 | 7 |  |  |  |  | 26 | my $a = (SGP_XKE / $xn) ** SGP_TOTHRD * $tempa ** 2; | 
| 3489 | 7 |  |  |  |  | 14 | my $e = $em - $tempe; | 
| 3490 | 7 |  |  |  |  | 11 | my $xmam = $xmdf + $parm->{xnodp} * $templ; | 
| 3491 | 7 |  |  |  |  | 26 | $self->_dpper (\$e, \$xinc, \$omgadf, \$xnode, \$xmam, $tsince); | 
| 3492 | 7 |  |  |  |  | 13 | my $xl = $xmam + $omgadf + $xnode; | 
| 3493 |  |  |  |  |  |  | $self->{debug} | 
| 3494 | 7 | 50 |  |  |  | 16 | and warn "Debug - OID $oid sdp4 effective eccentricity $e\n"; | 
| 3495 | 7 | 100 | 66 |  |  | 464 | ($e > 1 || $e < -1) | 
| 3496 |  |  |  |  |  |  | and croak "Error - OID $oid Sdp4 effective eccentricity > 1"; | 
| 3497 | 5 |  |  |  |  | 11 | my $beta = sqrt (1 - $e * $e); | 
| 3498 | 5 |  |  |  |  | 14 | $xn = SGP_XKE / $a ** 1.5; | 
| 3499 |  |  |  |  |  |  |  | 
| 3500 |  |  |  |  |  |  | #* LONG PERIOD PERIODICS | 
| 3501 |  |  |  |  |  |  |  | 
| 3502 | 5 |  |  |  |  | 10 | my $axn = $e * cos ($omgadf); | 
| 3503 | 5 |  |  |  |  | 7 | my $temp = 1 / ($a * $beta * $beta); | 
| 3504 | 5 |  |  |  |  | 11 | my $xll = $temp * $parm->{xlcof} * $axn; | 
| 3505 | 5 |  |  |  |  | 9 | my $aynl = $temp * $parm->{aycof}; | 
| 3506 | 5 |  |  |  |  | 8 | my $xlt = $xl + $xll; | 
| 3507 | 5 |  |  |  |  | 10 | my $ayn = $e * sin ($omgadf) + $aynl; | 
| 3508 |  |  |  |  |  |  |  | 
| 3509 |  |  |  |  |  |  | #* SOLVE KEPLERS EQUATION | 
| 3510 |  |  |  |  |  |  |  | 
| 3511 | 5 |  |  |  |  | 17 | my $capu = mod2pi ($xlt - $xnode); | 
| 3512 | 5 |  |  |  |  | 11 | my $temp2 = $capu; | 
| 3513 | 5 |  |  |  |  | 9 | my ($epw, $sinepw, $cosepw, $temp3, $temp4, $temp5, $temp6); | 
| 3514 | 5 |  |  |  |  | 14 | for (my $i = 0; $i < 10; $i++) { | 
| 3515 | 23 |  |  |  |  | 36 | $sinepw = sin ($temp2); | 
| 3516 | 23 |  |  |  |  | 30 | $cosepw = cos ($temp2); | 
| 3517 | 23 |  |  |  |  | 31 | $temp3 = $axn * $sinepw; | 
| 3518 | 23 |  |  |  |  | 25 | $temp4 = $ayn * $cosepw; | 
| 3519 | 23 |  |  |  |  | 29 | $temp5 = $axn * $cosepw; | 
| 3520 | 23 |  |  |  |  | 33 | $temp6 = $ayn * $sinepw; | 
| 3521 | 23 |  |  |  |  | 37 | $epw = ($capu - $temp4 + $temp3 - $temp2) / (1 - $temp5 - | 
| 3522 |  |  |  |  |  |  | $temp6) + $temp2; | 
| 3523 | 23 | 100 |  |  |  | 44 | last if (abs ($epw - $temp2) <= SGP_E6A); | 
| 3524 | 18 |  |  |  |  | 32 | $temp2 = $epw; | 
| 3525 |  |  |  |  |  |  | } | 
| 3526 |  |  |  |  |  |  |  | 
| 3527 |  |  |  |  |  |  | #* SHORT PERIOD PRELIMINARY QUANTITIES | 
| 3528 |  |  |  |  |  |  |  | 
| 3529 | 5 |  |  |  |  | 9 | my $ecose = $temp5 + $temp6; | 
| 3530 | 5 |  |  |  |  | 8 | my $esine = $temp3 - $temp4; | 
| 3531 | 5 |  |  |  |  | 9 | my $elsq = $axn * $axn + $ayn * $ayn; | 
| 3532 | 5 |  |  |  |  | 7 | $temp = 1 - $elsq; | 
| 3533 | 5 |  |  |  |  | 8 | my $pl = $a * $temp; | 
| 3534 | 5 |  |  |  |  | 8 | my $r = $a * (1 - $ecose); | 
| 3535 | 5 |  |  |  |  | 8 | my $temp1 = 1 / $r; | 
| 3536 | 5 |  |  |  |  | 7 | my $rdot = SGP_XKE * sqrt ($a) * $esine * $temp1; | 
| 3537 | 5 |  |  |  |  | 9 | my $rfdot = SGP_XKE * sqrt ($pl) * $temp1; | 
| 3538 | 5 |  |  |  |  | 8 | $temp2 = $a * $temp1; | 
| 3539 | 5 |  |  |  |  | 5 | my $betal = sqrt ($temp); | 
| 3540 | 5 |  |  |  |  | 16 | $temp3 = 1 / (1 + $betal); | 
| 3541 | 5 |  |  |  |  | 10 | my $cosu = $temp2 * ($cosepw - $axn + $ayn * $esine * $temp3); | 
| 3542 | 5 |  |  |  |  | 8 | my $sinu = $temp2 * ($sinepw - $ayn - $axn * $esine * $temp3); | 
| 3543 | 5 |  |  |  |  | 13 | my $u = _actan ($sinu,$cosu); | 
| 3544 | 5 |  |  |  |  | 10 | my $sin2u = 2 * $sinu * $cosu; | 
| 3545 | 5 |  |  |  |  | 9 | my $cos2u = 2 * $cosu * $cosu - 1; | 
| 3546 | 5 |  |  |  |  | 8 | $temp = 1 / $pl; | 
| 3547 | 5 |  |  |  |  | 6 | $temp1 = SGP_CK2 * $temp; | 
| 3548 | 5 |  |  |  |  | 6 | $temp2 = $temp1 * $temp; | 
| 3549 |  |  |  |  |  |  |  | 
| 3550 |  |  |  |  |  |  | #* UPDATE FOR SHORT PERIODICS | 
| 3551 |  |  |  |  |  |  |  | 
| 3552 |  |  |  |  |  |  | my $rk = $r * (1 - 1.5 * $temp2 * $betal * $parm->{x3thm1}) + .5 * | 
| 3553 | 5 |  |  |  |  | 14 | $temp1 * $parm->{x1mth2} * $cos2u; | 
| 3554 | 5 |  |  |  |  | 11 | my $uk = $u - .25 * $temp2 * $parm->{x7thm1} * $sin2u; | 
| 3555 | 5 |  |  |  |  | 7 | my $xnodek = $xnode + 1.5 * $temp2 * $parm->{cosi0} * $sin2u; | 
| 3556 |  |  |  |  |  |  | my $xinck = $xinc + 1.5 * $temp2 * $parm->{cosi0} * $parm->{sini0} * | 
| 3557 | 5 |  |  |  |  | 11 | $cos2u; | 
| 3558 | 5 |  |  |  |  | 9 | my $rdotk = $rdot - $xn * $temp1 * $parm->{x1mth2} * $sin2u; | 
| 3559 |  |  |  |  |  |  | my $rfdotk = $rfdot + $xn * $temp1 * ($parm->{x1mth2} * $cos2u + 1.5 | 
| 3560 | 5 |  |  |  |  | 9 | * $parm->{x3thm1}); | 
| 3561 |  |  |  |  |  |  |  | 
| 3562 |  |  |  |  |  |  | #* ORIENTATION VECTORS | 
| 3563 |  |  |  |  |  |  |  | 
| 3564 | 5 |  |  |  |  | 9 | my $sinuk = sin ($uk); | 
| 3565 | 5 |  |  |  |  | 10 | my $cosuk = cos ($uk); | 
| 3566 | 5 |  |  |  |  | 6 | my $sinik = sin ($xinck); | 
| 3567 | 5 |  |  |  |  | 12 | my $cosik = cos ($xinck); | 
| 3568 | 5 |  |  |  |  | 9 | my $sinnok = sin ($xnodek); | 
| 3569 | 5 |  |  |  |  | 7 | my $cosnok = cos ($xnodek); | 
| 3570 | 5 |  |  |  |  | 9 | my $xmx = - $sinnok * $cosik; | 
| 3571 | 5 |  |  |  |  | 8 | my $xmy = $cosnok * $cosik; | 
| 3572 | 5 |  |  |  |  | 8 | my $ux = $xmx * $sinuk + $cosnok * $cosuk; | 
| 3573 | 5 |  |  |  |  | 8 | my $uy = $xmy * $sinuk + $sinnok * $cosuk; | 
| 3574 | 5 |  |  |  |  | 5 | my $uz = $sinik * $sinuk; | 
| 3575 | 5 |  |  |  |  | 8 | my $vx = $xmx * $cosuk - $cosnok * $sinuk; | 
| 3576 | 5 |  |  |  |  | 8 | my $vy = $xmy * $cosuk - $sinnok * $sinuk; | 
| 3577 | 5 |  |  |  |  | 9 | my $vz = $sinik * $cosuk; | 
| 3578 |  |  |  |  |  |  |  | 
| 3579 |  |  |  |  |  |  | #* POSITION AND VELOCITY | 
| 3580 |  |  |  |  |  |  |  | 
| 3581 | 5 |  |  |  |  | 8 | my $x = $rk * $ux; | 
| 3582 | 5 |  |  |  |  | 6 | my $y = $rk * $uy; | 
| 3583 | 5 |  |  |  |  | 8 | my $z = $rk * $uz; | 
| 3584 | 5 |  |  |  |  | 8 | my $xdot = $rdotk * $ux + $rfdotk * $vx; | 
| 3585 | 5 |  |  |  |  | 7 | my $ydot = $rdotk * $uy + $rfdotk * $vy; | 
| 3586 | 5 |  |  |  |  | 10 | my $zdot = $rdotk * $uz + $rfdotk * $vz; | 
| 3587 |  |  |  |  |  |  |  | 
| 3588 | 5 |  |  |  |  | 22 | return _convert_out($self, $x, $y, $z, $xdot, $ydot, $zdot, $time); | 
| 3589 |  |  |  |  |  |  | } | 
| 3590 |  |  |  |  |  |  |  | 
| 3591 |  |  |  |  |  |  | =item $tle = $tle->sgp8($time) | 
| 3592 |  |  |  |  |  |  |  | 
| 3593 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 3594 |  |  |  |  |  |  | object at the given time, using the SGP8 model. The universal time of | 
| 3595 |  |  |  |  |  |  | the object is set to $time, and the 'equinox_dynamical' attribute is set | 
| 3596 |  |  |  |  |  |  | to the current value of the 'epoch_dynamical' attribute. | 
| 3597 |  |  |  |  |  |  |  | 
| 3598 |  |  |  |  |  |  | The result is the original object reference. You need to call one of | 
| 3599 |  |  |  |  |  |  | the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to | 
| 3600 |  |  |  |  |  |  | retrieve the position you just calculated. | 
| 3601 |  |  |  |  |  |  |  | 
| 3602 |  |  |  |  |  |  | "Spacetrack Report Number 3" (see "Acknowledgments") says that this | 
| 3603 |  |  |  |  |  |  | model can be used only for near-earth orbits. | 
| 3604 |  |  |  |  |  |  |  | 
| 3605 |  |  |  |  |  |  | =cut | 
| 3606 |  |  |  |  |  |  |  | 
| 3607 |  |  |  |  |  |  | sub sgp8 { | 
| 3608 | 7 |  |  | 7 | 1 | 17 | my ($self, $time) = @_; | 
| 3609 | 7 |  |  |  |  | 21 | my $oid = $self->get('id'); | 
| 3610 | 7 |  |  |  |  | 18 | $self->{model_error} = undef; | 
| 3611 | 7 |  |  |  |  | 23 | my $tsince = ($time - $self->{epoch}) / 60;	# Calc. is in minutes. | 
| 3612 |  |  |  |  |  |  |  | 
| 3613 |  |  |  |  |  |  | #>>>	Rather than use a separate indicator argument to trigger | 
| 3614 |  |  |  |  |  |  | #>>>	initialization of the model, we use the Orcish maneuver to | 
| 3615 |  |  |  |  |  |  | #>>>	retrieve the results of initialization, performing the | 
| 3616 |  |  |  |  |  |  | #>>>	calculations if needed. -- TRW | 
| 3617 |  |  |  |  |  |  |  | 
| 3618 | 7 |  | 66 |  |  | 38 | my $parm = $self->{&TLE_INIT}{TLE_sgp8} ||= do { | 
| 3619 | 2 | 50 |  |  |  | 11 | $self->is_deep and croak < | 
| 3620 |  |  |  |  |  |  | Error - The SGP8 model is not valid for deep space objects. | 
| 3621 |  |  |  |  |  |  | Use the SDP4, SGP4R, or SDP8 models instead. | 
| 3622 |  |  |  |  |  |  | EOD | 
| 3623 |  |  |  |  |  |  |  | 
| 3624 |  |  |  |  |  |  | #*	RECOVER ORIGINAL MEAN MOTION (XNODP) AND SEMIMAJOR AXIS (AODP) | 
| 3625 |  |  |  |  |  |  | #*	FROM INPUT ELEMENTS --------- CALCULATE BALLISTIC COEFFICIENT | 
| 3626 |  |  |  |  |  |  | #*	(B TERM) FROM INPUT B* DRAG TERM | 
| 3627 |  |  |  |  |  |  |  | 
| 3628 | 2 |  |  |  |  | 13 | my $a1 = (SGP_XKE / $self->{meanmotion}) ** SGP_TOTHRD; | 
| 3629 | 2 |  |  |  |  | 6 | my $cosi = cos ($self->{inclination}); | 
| 3630 | 2 |  |  |  |  | 5 | my $theta2 = $cosi * $cosi; | 
| 3631 | 2 |  |  |  |  | 8 | my $tthmun = 3 * $theta2 - 1; | 
| 3632 | 2 |  |  |  |  | 7 | my $eosq = $self->{eccentricity} * $self->{eccentricity}; | 
| 3633 | 2 |  |  |  |  | 6 | my $beta02 = 1 - $eosq; | 
| 3634 | 2 |  |  |  |  | 4 | my $beta0 = sqrt ($beta02); | 
| 3635 | 2 |  |  |  |  | 7 | my $del1 = 1.5 * SGP_CK2 * $tthmun / ($a1 * $a1 * $beta0 * $beta02); | 
| 3636 | 2 |  |  |  |  | 8 | my $a0 = $a1 * (1 - $del1 * (.5 * SGP_TOTHRD + | 
| 3637 |  |  |  |  |  |  | $del1 * (1 + 134 / 81 * $del1))); | 
| 3638 | 2 |  |  |  |  | 6 | my $del0 = 1.5 * SGP_CK2 * $tthmun / ($a0 * $a0 * $beta0 * $beta02); | 
| 3639 | 2 |  |  |  |  | 6 | my $aodp = $a0 / (1 - $del0); | 
| 3640 | 2 |  |  |  |  | 6 | my $xnodp = $self->{meanmotion} / (1 + $del0); | 
| 3641 | 2 |  |  |  |  | 6 | my $b = 2 * $self->{bstardrag} / SGP_RHO; | 
| 3642 |  |  |  |  |  |  |  | 
| 3643 |  |  |  |  |  |  | #*	INITIALIZATION | 
| 3644 |  |  |  |  |  |  |  | 
| 3645 | 2 |  |  |  |  | 4 | my $isimp = 0; | 
| 3646 | 2 |  |  |  |  | 4 | my $po = $aodp * $beta02; | 
| 3647 | 2 |  |  |  |  | 5 | my $pom2 = 1 / ($po * $po); | 
| 3648 | 2 |  |  |  |  | 5 | my $sini = sin ($self->{inclination}); | 
| 3649 | 2 |  |  |  |  | 6 | my $sing = sin ($self->{argumentofperigee}); | 
| 3650 | 2 |  |  |  |  | 5 | my $cosg = cos ($self->{argumentofperigee}); | 
| 3651 | 2 |  |  |  |  | 6 | my $temp = .5 * $self->{inclination}; | 
| 3652 | 2 |  |  |  |  | 4 | my $sinio2 = sin ($temp); | 
| 3653 | 2 |  |  |  |  | 6 | my $cosio2 = cos ($temp); | 
| 3654 | 2 |  |  |  |  | 4 | my $theta4 = $theta2 ** 2; | 
| 3655 | 2 |  |  |  |  | 5 | my $unm5th = 1 - 5 * $theta2; | 
| 3656 | 2 |  |  |  |  | 4 | my $unmth2 = 1 - $theta2; | 
| 3657 | 2 |  |  |  |  | 14 | my $a3cof = - SGP_XJ3 / SGP_CK2 * SGP_AE ** 3; | 
| 3658 | 2 |  |  |  |  | 6 | my $pardt1 = 3 * SGP_CK2 * $pom2 * $xnodp; | 
| 3659 | 2 |  |  |  |  | 6 | my $pardt2 = $pardt1 * SGP_CK2 * $pom2; | 
| 3660 | 2 |  |  |  |  | 6 | my $pardt4 = 1.25 * SGP_CK4 * $pom2 * $pom2 * $xnodp; | 
| 3661 | 2 |  |  |  |  | 5 | my $xmdt1 = .5 * $pardt1 * $beta0 * $tthmun; | 
| 3662 | 2 |  |  |  |  | 4 | my $xgdt1 = - .5 * $pardt1 * $unm5th; | 
| 3663 | 2 |  |  |  |  | 5 | my $xhdt1 = - $pardt1 * $cosi; | 
| 3664 | 2 |  |  |  |  | 6 | my $xlldot = $xnodp + $xmdt1 + .0625 * $pardt2 * $beta0 * | 
| 3665 |  |  |  |  |  |  | (13 - 78 * $theta2 + 137 * $theta4); | 
| 3666 | 2 |  |  |  |  | 9 | my $omgdt = $xgdt1 + .0625 * $pardt2 * (7 - 114 * $theta2 + | 
| 3667 |  |  |  |  |  |  | 395 * $theta4) + $pardt4 * (3 - 36 * $theta2 + 49 * $theta4); | 
| 3668 | 2 |  |  |  |  | 8 | my $xnodot = $xhdt1 + (.5 * $pardt2 * (4 - 19 * $theta2) + | 
| 3669 |  |  |  |  |  |  | 2 * $pardt4 * (3 - 7 * $theta2)) * $cosi; | 
| 3670 | 2 |  |  |  |  | 5 | my $tsi = 1 / ($po - SGP_S); | 
| 3671 | 2 |  |  |  |  | 7 | my $eta = $self->{eccentricity} * SGP_S * $tsi; | 
| 3672 | 2 |  |  |  |  | 4 | my $eta2 = $eta ** 2; | 
| 3673 | 2 |  |  |  |  | 6 | my $psim2 = abs (1 / (1 - $eta2)); | 
| 3674 | 2 |  |  |  |  | 4 | my $alpha2 = 1 + $eosq; | 
| 3675 | 2 |  |  |  |  | 4 | my $eeta = $self->{eccentricity} * $eta; | 
| 3676 | 2 |  |  |  |  | 7 | my $cos2g = 2 * $cosg ** 2 - 1; | 
| 3677 | 2 |  |  |  |  | 4 | my $d5 = $tsi * $psim2; | 
| 3678 | 2 |  |  |  |  | 6 | my $d1 = $d5 / $po; | 
| 3679 | 2 |  |  |  |  | 14 | my $d2 = 12 + $eta2 * (36 + 4.5 * $eta2); | 
| 3680 | 2 |  |  |  |  | 7 | my $d3 = $eta2 * (15 + 2.5 * $eta2); | 
| 3681 | 2 |  |  |  |  | 4 | my $d4 = $eta * (5 + 3.75 * $eta2); | 
| 3682 | 2 |  |  |  |  | 11 | my $b1 = SGP_CK2 * $tthmun; | 
| 3683 | 2 |  |  |  |  | 5 | my $b2 = - SGP_CK2 * $unmth2; | 
| 3684 | 2 |  |  |  |  | 4 | my $b3 = $a3cof * $sini; | 
| 3685 | 2 |  |  |  |  | 8 | my $c0 = .5 * $b * SGP_RHO * SGP_QOMS2T * $xnodp * $aodp * | 
| 3686 |  |  |  |  |  |  | $tsi ** 4 * $psim2 ** 3.5 / sqrt ($alpha2); | 
| 3687 | 2 |  |  |  |  | 6 | my $c1 = 1.5 * $xnodp * $alpha2 ** 2 * $c0; | 
| 3688 | 2 |  |  |  |  | 4 | my $c4 = $d1 * $d3 * $b2; | 
| 3689 | 2 |  |  |  |  | 5 | my $c5 = $d5 * $d4 * $b3; | 
| 3690 | 2 |  |  |  |  | 13 | my $xndt = $c1 * ( (2 + $eta2 * (3 + 34 * $eosq) + | 
| 3691 |  |  |  |  |  |  | 5 * $eeta * (4 + $eta2) + 8.5 * $eosq) + $d1 * $d2 * $b1 + | 
| 3692 |  |  |  |  |  |  | $c4 * $cos2g + $c5 * $sing); | 
| 3693 | 2 |  |  |  |  | 5 | my $xndtn = $xndt / $xnodp; | 
| 3694 |  |  |  |  |  |  |  | 
| 3695 |  |  |  |  |  |  | #*	IF DRAG IS VERY SMALL, THE ISIMP FLAG IS SET AND THE | 
| 3696 |  |  |  |  |  |  | #*	EQUATIONS ARE TRUNCATED TO LINEAR VARIATION IN MEAN | 
| 3697 |  |  |  |  |  |  | #*	MOTION AND QUADRATIC VARIATION IN MEAN ANOMALY | 
| 3698 |  |  |  |  |  |  |  | 
| 3699 |  |  |  |  |  |  | #>>>	Note that the simplified version of the code has been swapped | 
| 3700 |  |  |  |  |  |  | #>>>	above the full version to preserve the sense of the comment. | 
| 3701 |  |  |  |  |  |  |  | 
| 3702 | 2 |  |  |  |  | 4 | my ($ed, $edot, $gamma, $pp, $ovgpp, $qq, $xnd); | 
| 3703 | 2 | 50 |  |  |  | 11 | if (abs ($xndtn * SGP_XMNPDA) < 2.16e-3) { | 
| 3704 | 2 |  |  |  |  | 13 | $isimp = 1; | 
| 3705 | 2 |  |  |  |  | 10 | $edot = - SGP_TOTHRD * $xndtn * (1 - $self->{eccentricity}); | 
| 3706 |  |  |  |  |  |  | } else { | 
| 3707 | 0 |  |  |  |  | 0 | my $d6 = $eta * (30 + 22.5 * $eta2); | 
| 3708 | 0 |  |  |  |  | 0 | my $d7 = $eta * (5 + 12.5 * $eta2); | 
| 3709 | 0 |  |  |  |  | 0 | my $d8 = 1 + $eta2 * (6.75 + $eta2); | 
| 3710 | 0 |  |  |  |  | 0 | my $c8 = $d1 * $d7 * $b2; | 
| 3711 | 0 |  |  |  |  | 0 | my $c9 = $d5 * $d8 * $b3; | 
| 3712 |  |  |  |  |  |  | $edot = - $c0 * ($eta * (4 + $eta2 + | 
| 3713 |  |  |  |  |  |  | $eosq * (15.5 + 7 * $eta2)) + | 
| 3714 | 0 |  |  |  |  | 0 | $self->{eccentricity} * (5 + 15 * $eta2) + | 
| 3715 |  |  |  |  |  |  | $d1 * $d6 * $b1 + $c8 * $cos2g + $c9 * $sing); | 
| 3716 | 0 |  |  |  |  | 0 | my $d20 = .5 * SGP_TOTHRD * $xndtn; | 
| 3717 | 0 |  |  |  |  | 0 | my $aldtal = $self->{eccentricity} * $edot / $alpha2; | 
| 3718 |  |  |  |  |  |  | my $tsdtts = 2 * $aodp * $tsi * ($d20 * $beta02 + | 
| 3719 | 0 |  |  |  |  | 0 | $self->{eccentricity} * $edot); | 
| 3720 | 0 |  |  |  |  | 0 | my $etdt = ($edot + $self->{eccentricity} * $tsdtts) | 
| 3721 |  |  |  |  |  |  | * $tsi * SGP_S; | 
| 3722 | 0 |  |  |  |  | 0 | my $psdtps = - $eta * $etdt * $psim2; | 
| 3723 | 0 |  |  |  |  | 0 | my $sin2g = 2 * $sing * $cosg; | 
| 3724 | 0 |  |  |  |  | 0 | my $c0dtc0 = $d20 + 4 * $tsdtts - $aldtal - 7 * $psdtps; | 
| 3725 | 0 |  |  |  |  | 0 | my $c1dtc1 = $xndtn + 4 * $aldtal + $c0dtc0; | 
| 3726 |  |  |  |  |  |  | my $d9 = $eta * (6 + 68 * $eosq) + | 
| 3727 | 0 |  |  |  |  | 0 | $self->{eccentricity} * (20 + 15 * $eta2); | 
| 3728 |  |  |  |  |  |  | my $d10 = 5 * $eta * (4 + $eta2) + | 
| 3729 | 0 |  |  |  |  | 0 | $self->{eccentricity} * (17 + 68 * $eta2); | 
| 3730 | 0 |  |  |  |  | 0 | my $d11 = $eta * (72 + 18 * $eta2); | 
| 3731 | 0 |  |  |  |  | 0 | my $d12 = $eta * (30 + 10 * $eta2); | 
| 3732 | 0 |  |  |  |  | 0 | my $d13 = 5 + 11.25 * $eta2; | 
| 3733 | 0 |  |  |  |  | 0 | my $d14 = $tsdtts - 2 * $psdtps; | 
| 3734 | 0 |  |  |  |  | 0 | my $d15 = 2 * ($d20 + $self->{eccentricity} * $edot / $beta02); | 
| 3735 | 0 |  |  |  |  | 0 | my $d1dt = $d1 * ($d14 + $d15); | 
| 3736 | 0 |  |  |  |  | 0 | my $d2dt = $etdt * $d11; | 
| 3737 | 0 |  |  |  |  | 0 | my $d3dt = $etdt * $d12; | 
| 3738 | 0 |  |  |  |  | 0 | my $d4dt = $etdt * $d13; | 
| 3739 | 0 |  |  |  |  | 0 | my $d5dt = $d5 * $d14; | 
| 3740 | 0 |  |  |  |  | 0 | my $c4dt = $b2 * ($d1dt * $d3 + $d1 * $d3dt); | 
| 3741 | 0 |  |  |  |  | 0 | my $c5dt = $b3 * ($d5dt * $d4 + $d5 * $d4dt); | 
| 3742 | 0 |  |  |  |  | 0 | my $d16 = $d9 * $etdt + $d10 * $edot + | 
| 3743 |  |  |  |  |  |  | $b1 * ($d1dt * $d2 + $d1 * $d2dt) + $c4dt * $cos2g + | 
| 3744 |  |  |  |  |  |  | $c5dt * $sing + | 
| 3745 |  |  |  |  |  |  | $xgdt1 * ($c5 * $cosg - 2 * $c4 * $sin2g); | 
| 3746 | 0 |  |  |  |  | 0 | my $xnddt = $c1dtc1 * $xndt + $c1 * $d16; | 
| 3747 | 0 |  |  |  |  | 0 | my $eddot = $c0dtc0 * $edot - | 
| 3748 |  |  |  |  |  |  | $c0 * ((4 + 3 * $eta2 + 30 * $eeta + | 
| 3749 |  |  |  |  |  |  | $eosq * (15.5 + 21 * $eta2)) * $etdt + | 
| 3750 |  |  |  |  |  |  | (5 + 15 * $eta2 + $eeta * (31 + 14 * $eta2)) * $edot + | 
| 3751 |  |  |  |  |  |  | $b1 * ($d1dt * $d6 + $d1 * $etdt * (30 + 67.5 * | 
| 3752 |  |  |  |  |  |  | $eta2)) + $b2 * ($d1dt * $d7 + | 
| 3753 |  |  |  |  |  |  | $d1 * $etdt * (5 + 37.5 * $eta2)) * $cos2g + | 
| 3754 |  |  |  |  |  |  | $b3 * ($d5dt * $d8 + $d5 * $etdt * $eta * (13.5 + | 
| 3755 |  |  |  |  |  |  | 4 * $eta2)) * $sing + | 
| 3756 |  |  |  |  |  |  | $xgdt1 * ($c9 * $cosg - 2 * $c8 * $sin2g)); | 
| 3757 | 0 |  |  |  |  | 0 | my $d25 = $edot ** 2; | 
| 3758 | 0 |  |  |  |  | 0 | my $d17 = $xnddt / $xnodp - $xndtn ** 2; | 
| 3759 |  |  |  |  |  |  | my $tsddts = 2 * $tsdtts * ($tsdtts - $d20) + $aodp * $tsi * | 
| 3760 |  |  |  |  |  |  | (SGP_TOTHRD * $beta02 * $d17 - 4 * $d20 * | 
| 3761 |  |  |  |  |  |  | $self->{eccentricity} * $edot + 2 * | 
| 3762 | 0 |  |  |  |  | 0 | ($d25 + $self->{eccentricity} * $eddot)); | 
| 3763 | 0 |  |  |  |  | 0 | my $etddt = ($eddot + 2 * $edot * $tsdtts) * $tsi * SGP_S + | 
| 3764 |  |  |  |  |  |  | $tsddts * $eta; | 
| 3765 | 0 |  |  |  |  | 0 | my $d18 = $tsddts - $tsdtts ** 2; | 
| 3766 | 0 |  |  |  |  | 0 | my $d19 = - $psdtps ** 2 / $eta2 - $eta * $etddt * $psim2 - | 
| 3767 |  |  |  |  |  |  | $psdtps ** 2; | 
| 3768 | 0 |  |  |  |  | 0 | my $d23 = $etdt * $etdt; | 
| 3769 |  |  |  |  |  |  | my $d1ddt = $d1dt * ($d14 + $d15) + $d1 * ($d18 - 2 * $d19 + | 
| 3770 |  |  |  |  |  |  | SGP_TOTHRD * $d17 + 2 * ($alpha2 * $d25 / $beta02 + | 
| 3771 | 0 |  |  |  |  | 0 | $self->{eccentricity} * $eddot) / $beta02); | 
| 3772 |  |  |  |  |  |  | my $xntrdt = $xndt * (2 * SGP_TOTHRD * $d17 + 3 * ($d25 + | 
| 3773 |  |  |  |  |  |  | $self->{eccentricity} * $eddot) / $alpha2 - | 
| 3774 |  |  |  |  |  |  | 6 * $aldtal ** 2 + 4 * $d18 - 7 * $d19 ) + | 
| 3775 |  |  |  |  |  |  | $c1dtc1 * $xnddt + $c1 * ($c1dtc1 * $d16 + $d9 * $etddt + | 
| 3776 |  |  |  |  |  |  | $d10 * $eddot + $d23 * (6 + 30 * $eeta + 68 * $eosq) + | 
| 3777 |  |  |  |  |  |  | $etdt * $edot * (40 + 30 * $eta2 + 272 * $eeta) + | 
| 3778 |  |  |  |  |  |  | $d25 * (17 + 68 * $eta2) + $b1 * ($d1ddt * $d2 + | 
| 3779 |  |  |  |  |  |  | 2 * $d1dt * $d2dt + $d1 * ($etddt * $d11 + | 
| 3780 |  |  |  |  |  |  | $d23 * (72 + 54 * $eta2))) + $b2 * ($d1ddt * $d3 + | 
| 3781 |  |  |  |  |  |  | 2 * $d1dt * $d3dt + $d1 * ($etddt * $d12 + | 
| 3782 |  |  |  |  |  |  | $d23 * (30 + 30 * $eta2))) * $cos2g + | 
| 3783 |  |  |  |  |  |  | $b3 * (($d5dt * $d14 + $d5 * ($d18 - 2 * $d19)) * $d4 + | 
| 3784 |  |  |  |  |  |  | 2 * $d4dt * $d5dt + $d5 * ($etddt * $d13 + | 
| 3785 |  |  |  |  |  |  | 22.5 * $eta * $d23)) * $sing + $xgdt1 * ((7 * $d20 + | 
| 3786 | 0 |  |  |  |  | 0 | 4 * $self->{eccentricity} * $edot / $beta02) * | 
| 3787 |  |  |  |  |  |  | ($c5 * $cosg - 2 * $c4 * $sin2g) + ( (2 * $c5dt * $cosg - | 
| 3788 |  |  |  |  |  |  | 4 * $c4dt * $sin2g) - $xgdt1 * ($c5 * $sing + | 
| 3789 |  |  |  |  |  |  | 4 * $c4 * $cos2g)))); | 
| 3790 | 0 |  |  |  |  | 0 | my $tmnddt = $xnddt * 1.e9; | 
| 3791 | 0 |  |  |  |  | 0 | my $temp = $tmnddt ** 2 - $xndt * 1.e18 * $xntrdt; | 
| 3792 | 0 |  |  |  |  | 0 | $pp = ($temp + $tmnddt ** 2) / $temp; | 
| 3793 | 0 |  |  |  |  | 0 | $gamma = - $xntrdt / ($xnddt * ($pp - 2.)); | 
| 3794 | 0 |  |  |  |  | 0 | $xnd = $xndt / ($pp * $gamma); | 
| 3795 | 0 |  |  |  |  | 0 | $qq = 1 - $eddot / ($edot * $gamma); | 
| 3796 | 0 |  |  |  |  | 0 | $ed = $edot / ($qq * $gamma); | 
| 3797 | 0 |  |  |  |  | 0 | $ovgpp = 1 / ($gamma * ($pp + 1.)); | 
| 3798 |  |  |  |  |  |  | } | 
| 3799 | 2 | 50 |  |  |  | 8 | $self->{debug} and print < | 
| 3800 |  |  |  |  |  |  | Debug SGP8 - Initialize | 
| 3801 | 0 | 0 |  |  |  | 0 | A3COF = @{[defined $a3cof ? $a3cof : 'undef']} | 
| 3802 | 0 | 0 |  |  |  | 0 | COSI = @{[defined $cosi ? $cosi : 'undef']} | 
| 3803 | 0 | 0 |  |  |  | 0 | COSIO2 = @{[defined $cosio2 ? $cosio2 : 'undef']} | 
| 3804 | 0 | 0 |  |  |  | 0 | ED = @{[defined $ed ? $ed : 'undef']} | 
| 3805 | 0 | 0 |  |  |  | 0 | EDOT = @{[defined $edot ? $edot : 'undef']} | 
| 3806 | 0 | 0 |  |  |  | 0 | GAMMA = @{[defined $gamma ? $gamma : 'undef']} | 
| 3807 | 0 | 0 |  |  |  | 0 | ISIMP = @{[defined $isimp ? $isimp : 'undef']} | 
| 3808 | 0 | 0 |  |  |  | 0 | OMGDT = @{[defined $omgdt ? $omgdt : 'undef']} | 
| 3809 | 0 | 0 |  |  |  | 0 | OVGPP = @{[defined $ovgpp ? $ovgpp : 'undef']} | 
| 3810 | 0 | 0 |  |  |  | 0 | PP = @{[defined $pp ? $pp : 'undef']} | 
| 3811 | 0 | 0 |  |  |  | 0 | QQ = @{[defined $qq ? $qq : 'undef']} | 
| 3812 | 0 | 0 |  |  |  | 0 | SINI = @{[defined $sini ? $sini : 'undef']} | 
| 3813 | 0 | 0 |  |  |  | 0 | SINIO2 = @{[defined $sinio2 ? $sinio2 : 'undef']} | 
| 3814 | 0 | 0 |  |  |  | 0 | THETA2 = @{[defined $theta2 ? $theta2 : 'undef']} | 
| 3815 | 0 | 0 |  |  |  | 0 | TTHMUN = @{[defined $tthmun ? $tthmun : 'undef']} | 
| 3816 | 0 | 0 |  |  |  | 0 | UNM5TH = @{[defined $unm5th ? $unm5th : 'undef']} | 
| 3817 | 0 | 0 |  |  |  | 0 | UNMTH2 = @{[defined $unmth2 ? $unmth2 : 'undef']} | 
| 3818 | 0 | 0 |  |  |  | 0 | XGDT1 = @{[defined $xgdt1 ? $xgdt1 : 'undef']} | 
| 3819 | 0 | 0 |  |  |  | 0 | XHDT1 = @{[defined $xhdt1 ? $xhdt1 : 'undef']} | 
| 3820 | 0 | 0 |  |  |  | 0 | XLLDOT = @{[defined $xlldot ? $xlldot : 'undef']} | 
| 3821 | 0 | 0 |  |  |  | 0 | XMDT1 = @{[defined $xmdt1 ? $xmdt1 : 'undef']} | 
| 3822 | 0 | 0 |  |  |  | 0 | XND = @{[defined $xnd ? $xnd : 'undef']} | 
| 3823 | 0 | 0 |  |  |  | 0 | XNDT = @{[defined $xndt ? $xndt : 'undef']} | 
| 3824 | 0 | 0 |  |  |  | 0 | XNODOT = @{[defined $xnodot ? $xnodot : 'undef']} | 
| 3825 | 0 | 0 |  |  |  | 0 | XNODP = @{[defined $xnodp ? $xnodp : 'undef']} | 
| 3826 |  |  |  |  |  |  | eod | 
| 3827 |  |  |  |  |  |  | { | 
| 3828 | 2 |  |  |  |  | 49 | a3cof => $a3cof, | 
| 3829 |  |  |  |  |  |  | cosi => $cosi, | 
| 3830 |  |  |  |  |  |  | cosio2 => $cosio2, | 
| 3831 |  |  |  |  |  |  | ed => $ed, | 
| 3832 |  |  |  |  |  |  | edot => $edot, | 
| 3833 |  |  |  |  |  |  | gamma => $gamma, | 
| 3834 |  |  |  |  |  |  | isimp => $isimp, | 
| 3835 |  |  |  |  |  |  | omgdt => $omgdt, | 
| 3836 |  |  |  |  |  |  | ovgpp => $ovgpp, | 
| 3837 |  |  |  |  |  |  | pp => $pp, | 
| 3838 |  |  |  |  |  |  | qq => $qq, | 
| 3839 |  |  |  |  |  |  | sini => $sini, | 
| 3840 |  |  |  |  |  |  | sinio2 => $sinio2, | 
| 3841 |  |  |  |  |  |  | theta2 => $theta2, | 
| 3842 |  |  |  |  |  |  | tthmun => $tthmun, | 
| 3843 |  |  |  |  |  |  | unm5th => $unm5th, | 
| 3844 |  |  |  |  |  |  | unmth2 => $unmth2, | 
| 3845 |  |  |  |  |  |  | xgdt1 => $xgdt1, | 
| 3846 |  |  |  |  |  |  | xhdt1 => $xhdt1, | 
| 3847 |  |  |  |  |  |  | xlldot => $xlldot, | 
| 3848 |  |  |  |  |  |  | xmdt1 => $xmdt1, | 
| 3849 |  |  |  |  |  |  | xnd => $xnd, | 
| 3850 |  |  |  |  |  |  | xndt => $xndt, | 
| 3851 |  |  |  |  |  |  | xnodot => $xnodot, | 
| 3852 |  |  |  |  |  |  | xnodp => $xnodp, | 
| 3853 |  |  |  |  |  |  | }; | 
| 3854 |  |  |  |  |  |  | }; | 
| 3855 |  |  |  |  |  |  |  | 
| 3856 |  |  |  |  |  |  | #*	UPDATE FOR SECULAR GRAVITY AND ATMOSPHERIC DRAG | 
| 3857 |  |  |  |  |  |  |  | 
| 3858 | 7 |  |  |  |  | 38 | my $xmam = mod2pi ($self->{meananomaly} + $parm->{xlldot} * $tsince); | 
| 3859 | 7 |  |  |  |  | 21 | my $omgasm = $self->{argumentofperigee} + $parm->{omgdt} * $tsince; | 
| 3860 | 7 |  |  |  |  | 14 | my $xnodes = $self->{ascendingnode} + $parm->{xnodot} * $tsince; | 
| 3861 |  |  |  |  |  |  |  | 
| 3862 |  |  |  |  |  |  | #>>>	The simplified and full logic have been swapped for clarity. | 
| 3863 |  |  |  |  |  |  |  | 
| 3864 | 7 |  |  |  |  | 14 | my ($xn, $em, $z1); | 
| 3865 | 7 | 50 |  |  |  | 30 | if ($parm->{isimp}) { | 
| 3866 | 7 |  |  |  |  | 18 | $xn = $parm->{xnodp} + $parm->{xndt} * $tsince; | 
| 3867 | 7 |  |  |  |  | 14 | $em = $self->{eccentricity} + $parm->{edot} * $tsince; | 
| 3868 | 7 |  |  |  |  | 14 | $z1 = .5 * $parm->{xndt} * $tsince * $tsince; | 
| 3869 |  |  |  |  |  |  | } else { | 
| 3870 | 0 |  |  |  |  | 0 | my $temp = 1 - $parm->{gamma} * $tsince; | 
| 3871 | 0 |  |  |  |  | 0 | my $temp1 = $temp ** $parm->{pp}; | 
| 3872 | 0 |  |  |  |  | 0 | $xn = $parm->{xnodp} + $parm->{xnd} * (1 - $temp1); | 
| 3873 | 0 |  |  |  |  | 0 | $em = $self->{eccentricity} + $parm->{ed} * (1 - $temp ** $parm->{qq}); | 
| 3874 | 0 |  |  |  |  | 0 | $z1 = $parm->{xnd} * ($tsince + $parm->{ovgpp} * ($temp * $temp1 - 1.)); | 
| 3875 |  |  |  |  |  |  | } | 
| 3876 | 7 |  |  |  |  | 54 | my $z7 = 3.5 * SGP_TOTHRD * $z1 / $parm->{xnodp}; | 
| 3877 | 7 |  |  |  |  | 25 | $xmam = mod2pi ($xmam + $z1 + $z7 * $parm->{xmdt1}); | 
| 3878 | 7 |  |  |  |  | 15 | $omgasm = $omgasm + $z7 * $parm->{xgdt1}; | 
| 3879 | 7 |  |  |  |  | 13 | $xnodes = $xnodes + $z7 * $parm->{xhdt1}; | 
| 3880 |  |  |  |  |  |  |  | 
| 3881 |  |  |  |  |  |  | #*      SOLVE KEPLERS EQUATION | 
| 3882 |  |  |  |  |  |  |  | 
| 3883 | 7 |  |  |  |  | 28 | my $zc2 = $xmam + $em * sin ($xmam) * (1 + $em * cos ($xmam)); | 
| 3884 | 7 |  |  |  |  | 14 | my ($cose, $sine, $zc5); | 
| 3885 | 7 |  |  |  |  | 25 | for (my $i = 0; $i < 10; $i++) { | 
| 3886 | 25 |  |  |  |  | 39 | $sine = sin ($zc2); | 
| 3887 | 25 |  |  |  |  | 34 | $cose = cos ($zc2); | 
| 3888 | 25 |  |  |  |  | 43 | $zc5 = 1 / (1 - $em * $cose); | 
| 3889 | 25 |  |  |  |  | 41 | my $cape = ($xmam + $em * $sine - $zc2) * $zc5 + $zc2; | 
| 3890 | 25 | 100 |  |  |  | 50 | last if (abs ($cape - $zc2) <= SGP_E6A); | 
| 3891 | 20 |  |  |  |  | 36 | $zc2 = $cape; | 
| 3892 |  |  |  |  |  |  | } | 
| 3893 |  |  |  |  |  |  |  | 
| 3894 |  |  |  |  |  |  | #*      SHORT PERIOD PRELIMINARY QUANTITIES | 
| 3895 |  |  |  |  |  |  |  | 
| 3896 | 7 |  |  |  |  | 23 | my $am = (SGP_XKE / $xn) ** SGP_TOTHRD; | 
| 3897 | 7 |  |  |  |  | 16 | my $beta2m = 1 - $em * $em; | 
| 3898 |  |  |  |  |  |  | $self->{debug} | 
| 3899 | 7 | 50 |  |  |  | 19 | and warn "Debug - OID $oid sgp8 effective eccentricity $em\n"; | 
| 3900 | 7 | 100 |  |  |  | 446 | $beta2m < 0 | 
| 3901 |  |  |  |  |  |  | and croak "Error - OID $oid Sgp8 effective eccentricity > 1"; | 
| 3902 | 5 |  |  |  |  | 9 | my $sinos = sin ($omgasm); | 
| 3903 | 5 |  |  |  |  | 17 | my $cosos = cos ($omgasm); | 
| 3904 | 5 |  |  |  |  | 11 | my $axnm = $em * $cosos; | 
| 3905 | 5 |  |  |  |  | 8 | my $aynm = $em * $sinos; | 
| 3906 | 5 |  |  |  |  | 8 | my $pm = $am * $beta2m; | 
| 3907 | 5 |  |  |  |  | 11 | my $g1 = 1 / $pm; | 
| 3908 | 5 |  |  |  |  | 8 | my $g2 = .5 * SGP_CK2 * $g1; | 
| 3909 | 5 |  |  |  |  | 16 | my $g3 = $g2 * $g1; | 
| 3910 | 5 |  |  |  |  | 11 | my $beta = sqrt ($beta2m); | 
| 3911 | 5 |  |  |  |  | 13 | my $g4 = .25 * $parm->{a3cof} * $parm->{sini}; | 
| 3912 | 5 |  |  |  |  | 8 | my $g5 = .25 * $parm->{a3cof} * $g1; | 
| 3913 | 5 |  |  |  |  | 7 | my $snf = $beta * $sine * $zc5; | 
| 3914 | 5 |  |  |  |  | 13 | my $csf = ($cose - $em) * $zc5; | 
| 3915 | 5 |  |  |  |  | 21 | my $fm = _actan ($snf,$csf); | 
| 3916 | 5 |  |  |  |  | 10 | my $snfg = $snf * $cosos + $csf * $sinos; | 
| 3917 | 5 |  |  |  |  | 8 | my $csfg = $csf * $cosos - $snf * $sinos; | 
| 3918 | 5 |  |  |  |  | 11 | my $sn2f2g = 2 * $snfg * $csfg; | 
| 3919 | 5 |  |  |  |  | 12 | my $cs2f2g = 2 * $csfg ** 2 - 1; | 
| 3920 | 5 |  |  |  |  | 6 | my $ecosf = $em * $csf; | 
| 3921 | 5 |  |  |  |  | 11 | my $g10 = $fm - $xmam + $em * $snf; | 
| 3922 | 5 |  |  |  |  | 10 | my $rm = $pm / (1 + $ecosf); | 
| 3923 | 5 |  |  |  |  | 9 | my $aovr = $am / $rm; | 
| 3924 | 5 |  |  |  |  | 7 | my $g13 = $xn * $aovr; | 
| 3925 | 5 |  |  |  |  | 8 | my $g14 = - $g13 * $aovr; | 
| 3926 | 5 |  |  |  |  | 13 | my $dr = $g2 * ($parm->{unmth2} * $cs2f2g - 3 * $parm->{tthmun}) - | 
| 3927 |  |  |  |  |  |  | $g4 * $snfg; | 
| 3928 | 5 |  |  |  |  | 11 | my $diwc = 3 * $g3 * $parm->{sini} * $cs2f2g - $g5 * $aynm; | 
| 3929 | 5 |  |  |  |  | 8 | my $di = $diwc * $parm->{cosi}; | 
| 3930 |  |  |  |  |  |  |  | 
| 3931 |  |  |  |  |  |  | #*      UPDATE FOR SHORT PERIOD PERIODICS | 
| 3932 |  |  |  |  |  |  |  | 
| 3933 |  |  |  |  |  |  | my $sni2du = $parm->{sinio2} * ($g3 * (.5 * (1 - 7 * $parm->{theta2}) * | 
| 3934 |  |  |  |  |  |  | $sn2f2g - 3 * $parm->{unm5th} * $g10) - $g5 * $parm->{sini} * | 
| 3935 |  |  |  |  |  |  | $csfg * (2 + $ecosf)) - .5 * $g5 * $parm->{theta2} * $axnm / | 
| 3936 | 5 |  |  |  |  | 19 | $parm->{cosio2}; | 
| 3937 |  |  |  |  |  |  | my $xlamb = $fm + $omgasm + $xnodes + $g3 * (.5 * (1 + 6 * | 
| 3938 |  |  |  |  |  |  | $parm->{cosi} - 7 * $parm->{theta2}) * $sn2f2g - 3 * | 
| 3939 |  |  |  |  |  |  | ($parm->{unm5th} + 2 * $parm->{cosi}) * $g10) + | 
| 3940 |  |  |  |  |  |  | $g5 * $parm->{sini} * ($parm->{cosi} * $axnm / | 
| 3941 | 5 |  |  |  |  | 26 | (1 + $parm->{cosi}) - (2 + $ecosf) * $csfg); | 
| 3942 |  |  |  |  |  |  | my $y4 = $parm->{sinio2} * $snfg + $csfg * $sni2du + | 
| 3943 | 5 |  |  |  |  | 12 | .5 * $snfg * $parm->{cosio2} * $di; | 
| 3944 |  |  |  |  |  |  | my $y5 = $parm->{sinio2} * $csfg - $snfg * $sni2du + | 
| 3945 | 5 |  |  |  |  | 12 | .5 * $csfg * $parm->{cosio2} * $di; | 
| 3946 | 5 |  |  |  |  | 10 | my $r = $rm + $dr; | 
| 3947 |  |  |  |  |  |  | my $rdot = $xn * $am * $em * $snf / $beta + $g14 * | 
| 3948 | 5 |  |  |  |  | 13 | (2 * $g2 * $parm->{unmth2} * $sn2f2g + $g4 * $csfg); | 
| 3949 |  |  |  |  |  |  | my $rvdot = $xn * $am ** 2 * $beta / $rm + $g14 * $dr + | 
| 3950 | 5 |  |  |  |  | 12 | $am * $g13 * $parm->{sini} * $diwc; | 
| 3951 |  |  |  |  |  |  |  | 
| 3952 |  |  |  |  |  |  | #*      ORIENTATION VECTORS | 
| 3953 |  |  |  |  |  |  |  | 
| 3954 | 5 |  |  |  |  | 9 | my $snlamb = sin ($xlamb); | 
| 3955 | 5 |  |  |  |  | 9 | my $cslamb = cos ($xlamb); | 
| 3956 | 5 |  |  |  |  | 8 | my $temp = 2 * ($y5 * $snlamb - $y4 * $cslamb); | 
| 3957 | 5 |  |  |  |  | 16 | my $ux = $y4 * $temp + $cslamb; | 
| 3958 | 5 |  |  |  |  | 7 | my $vx = $y5 * $temp - $snlamb; | 
| 3959 | 5 |  |  |  |  | 11 | $temp = 2 * ($y5 * $cslamb + $y4 * $snlamb); | 
| 3960 | 5 |  |  |  |  | 10 | my $uy = - $y4 * $temp + $snlamb; | 
| 3961 | 5 |  |  |  |  | 8 | my $vy = - $y5 * $temp + $cslamb; | 
| 3962 | 5 |  |  |  |  | 10 | $temp = 2 * sqrt (1 - $y4 * $y4 - $y5 * $y5); | 
| 3963 | 5 |  |  |  |  | 8 | my $uz = $y4 * $temp; | 
| 3964 | 5 |  |  |  |  | 8 | my $vz = $y5 * $temp; | 
| 3965 |  |  |  |  |  |  |  | 
| 3966 |  |  |  |  |  |  | #*      POSITION AND VELOCITY | 
| 3967 |  |  |  |  |  |  |  | 
| 3968 | 5 |  |  |  |  | 6 | my $x = $r * $ux; | 
| 3969 | 5 |  |  |  |  | 9 | my $y = $r * $uy; | 
| 3970 | 5 |  |  |  |  | 8 | my $z = $r * $uz; | 
| 3971 | 5 |  |  |  |  | 9 | my $xdot = $rdot * $ux + $rvdot * $vx; | 
| 3972 | 5 |  |  |  |  | 8 | my $ydot = $rdot * $uy + $rvdot * $vy; | 
| 3973 | 5 |  |  |  |  | 8 | my $zdot = $rdot * $uz + $rvdot * $vz; | 
| 3974 |  |  |  |  |  |  |  | 
| 3975 | 5 |  |  |  |  | 13 | return _convert_out ($self, $x, $y, $z, $xdot, $ydot, $zdot, $time); | 
| 3976 |  |  |  |  |  |  | } | 
| 3977 |  |  |  |  |  |  |  | 
| 3978 |  |  |  |  |  |  | =item $tle = $tle->sdp8($time) | 
| 3979 |  |  |  |  |  |  |  | 
| 3980 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 3981 |  |  |  |  |  |  | object at the given time, using the SDP8 model. The universal time of | 
| 3982 |  |  |  |  |  |  | the object is set to $time, and the 'equinox_dynamical' attribute is set | 
| 3983 |  |  |  |  |  |  | to the current value of the 'epoch_dynamical' attribute. | 
| 3984 |  |  |  |  |  |  |  | 
| 3985 |  |  |  |  |  |  | The result is the original object reference. You need to call one of | 
| 3986 |  |  |  |  |  |  | the Astro::Coord::ECI methods (e.g. geodetic () or equatorial ()) to | 
| 3987 |  |  |  |  |  |  | retrieve the position you just calculated. | 
| 3988 |  |  |  |  |  |  |  | 
| 3989 |  |  |  |  |  |  | "Spacetrack Report Number 3" (see "Acknowledgments") says that this | 
| 3990 |  |  |  |  |  |  | model can be used only for near-earth orbits. | 
| 3991 |  |  |  |  |  |  |  | 
| 3992 |  |  |  |  |  |  | =cut | 
| 3993 |  |  |  |  |  |  |  | 
| 3994 |  |  |  |  |  |  | sub sdp8 { | 
| 3995 | 7 |  |  | 7 | 1 | 18 | my ($self, $time) = @_; | 
| 3996 | 7 |  |  |  |  | 16 | my $oid = $self->get('id'); | 
| 3997 | 7 |  |  |  |  | 16 | $self->{model_error} = undef; | 
| 3998 | 7 |  |  |  |  | 23 | my $tsince = ($time - $self->{epoch}) / 60;	# Calc. is in minutes. | 
| 3999 |  |  |  |  |  |  |  | 
| 4000 |  |  |  |  |  |  | #>>>	Rather than use a separate indicator argument to trigger | 
| 4001 |  |  |  |  |  |  | #>>>	initialization of the model, we use the Orcish maneuver to | 
| 4002 |  |  |  |  |  |  | #>>>	retrieve the results of initialization, performing the | 
| 4003 |  |  |  |  |  |  | #>>>	calculations if needed. -- TRW | 
| 4004 |  |  |  |  |  |  |  | 
| 4005 | 7 |  | 66 |  |  | 35 | my $parm = $self->{&TLE_INIT}{TLE_sdp8} ||= do { | 
| 4006 | 2 | 50 |  |  |  | 7 | $self->is_deep or croak < | 
| 4007 |  |  |  |  |  |  | Error - The SDP8 model is not valid for near-earth objects. | 
| 4008 |  |  |  |  |  |  | Use the SGP, SGP4, SGP4R, or SGP8 models instead. | 
| 4009 |  |  |  |  |  |  | EOD | 
| 4010 |  |  |  |  |  |  |  | 
| 4011 |  |  |  |  |  |  | #*      RECOVER ORIGINAL MEAN MOTION (XNODP) AND SEMIMAJOR AXIS (AODP) | 
| 4012 |  |  |  |  |  |  | #*      FROM INPUT ELEMENTS --------- CALCULATE BALLISTIC COEFFICIENT | 
| 4013 |  |  |  |  |  |  | #* (B TERM) FROM INPUT B* DRAG TERM | 
| 4014 |  |  |  |  |  |  |  | 
| 4015 | 2 |  |  |  |  | 12 | my $a1 = (SGP_XKE / $self->{meanmotion}) ** SGP_TOTHRD; | 
| 4016 | 2 |  |  |  |  | 8 | my $cosi = cos ($self->{inclination}); | 
| 4017 | 2 |  |  |  |  | 5 | my $theta2 = $cosi * $cosi; | 
| 4018 | 2 |  |  |  |  | 6 | my $tthmun = 3 * $theta2 - 1; | 
| 4019 | 2 |  |  |  |  | 8 | my $eosq = $self->{eccentricity} * $self->{eccentricity}; | 
| 4020 | 2 |  |  |  |  | 6 | my $beta02 = 1 - $eosq; | 
| 4021 | 2 |  |  |  |  | 4 | my $beta0 = sqrt ($beta02); | 
| 4022 | 2 |  |  |  |  | 7 | my $del1 = 1.5 * SGP_CK2 * $tthmun / ($a1 * $a1 * $beta0 * $beta02); | 
| 4023 | 2 |  |  |  |  | 8 | my $a0 = $a1 * (1 - $del1 * (.5 * SGP_TOTHRD + $del1 * (1 + 134 | 
| 4024 |  |  |  |  |  |  | / 81 * $del1))); | 
| 4025 | 2 |  |  |  |  | 6 | my $del0 = 1.5 * SGP_CK2 * $tthmun / ($a0 * $a0 * $beta0 * $beta02); | 
| 4026 | 2 |  |  |  |  | 5 | my $aodp = $a0 / (1 - $del0); | 
| 4027 | 2 |  |  |  |  | 5 | my $xnodp = $self->{meanmotion} / (1 + $del0); | 
| 4028 | 2 |  |  |  |  | 5 | my $b = 2 * $self->{bstardrag} / SGP_RHO; | 
| 4029 |  |  |  |  |  |  |  | 
| 4030 |  |  |  |  |  |  | #*      INITIALIZATION | 
| 4031 |  |  |  |  |  |  |  | 
| 4032 | 2 |  |  |  |  | 4 | my $po = $aodp * $beta02; | 
| 4033 | 2 |  |  |  |  | 5 | my $pom2 = 1 / ($po * $po); | 
| 4034 | 2 |  |  |  |  | 5 | my $sini = sin ($self->{inclination}); | 
| 4035 | 2 |  |  |  |  | 5 | my $sing = sin ($self->{argumentofperigee}); | 
| 4036 | 2 |  |  |  |  | 6 | my $cosg = cos ($self->{argumentofperigee}); | 
| 4037 | 2 |  |  |  |  | 4 | my $temp = .5 * $self->{inclination}; | 
| 4038 | 2 |  |  |  |  | 4 | my $sinio2 = sin ($temp); | 
| 4039 | 2 |  |  |  |  | 5 | my $cosio2 = cos ($temp); | 
| 4040 | 2 |  |  |  |  | 4 | my $theta4 = $theta2 ** 2; | 
| 4041 | 2 |  |  |  |  | 6 | my $unm5th = 1 - 5 * $theta2; | 
| 4042 | 2 |  |  |  |  | 4 | my $unmth2 = 1 - $theta2; | 
| 4043 | 2 |  |  |  |  | 3 | my $a3cof = - SGP_XJ3 / SGP_CK2 * SGP_AE ** 3; | 
| 4044 | 2 |  |  |  |  | 7 | my $pardt1 = 3 * SGP_CK2 * $pom2 * $xnodp; | 
| 4045 | 2 |  |  |  |  | 4 | my $pardt2 = $pardt1 * SGP_CK2 * $pom2; | 
| 4046 | 2 |  |  |  |  | 5 | my $pardt4 = 1.25 * SGP_CK4 * $pom2 * $pom2 * $xnodp; | 
| 4047 | 2 |  |  |  |  | 5 | my $xmdt1 = .5 * $pardt1 * $beta0 * $tthmun; | 
| 4048 | 2 |  |  |  |  | 4 | my $xgdt1 = - .5 * $pardt1 * $unm5th; | 
| 4049 | 2 |  |  |  |  | 4 | my $xhdt1 = - $pardt1 * $cosi; | 
| 4050 | 2 |  |  |  |  | 8 | my $xlldot = $xnodp + $xmdt1 + .0625 * $pardt2 * $beta0 * (13 - | 
| 4051 |  |  |  |  |  |  | 78 * $theta2 + 137 * $theta4); | 
| 4052 | 2 |  |  |  |  | 20 | my $omgdt = $xgdt1 + .0625 * $pardt2 * (7 - 114 * $theta2 + 395 | 
| 4053 |  |  |  |  |  |  | * $theta4) + $pardt4 * (3 - 36 * $theta2 + 49 * $theta4); | 
| 4054 | 2 |  |  |  |  | 10 | my $xnodot = $xhdt1 + (.5 * $pardt2 * (4 - 19 * $theta2) + 2 * | 
| 4055 |  |  |  |  |  |  | $pardt4 * (3 - 7 * $theta2)) * $cosi; | 
| 4056 | 2 |  |  |  |  | 15 | my $tsi = 1 / ($po - SGP_S); | 
| 4057 | 2 |  |  |  |  | 8 | my $eta = $self->{eccentricity} * SGP_S * $tsi; | 
| 4058 | 2 |  |  |  |  | 6 | my $eta2 = $eta ** 2; | 
| 4059 | 2 |  |  |  |  | 7 | my $psim2 = abs (1 / (1 - $eta2)); | 
| 4060 | 2 |  |  |  |  | 5 | my $alpha2 = 1 + $eosq; | 
| 4061 | 2 |  |  |  |  | 12 | my $eeta = $self->{eccentricity} * $eta; | 
| 4062 | 2 |  |  |  |  | 7 | my $cos2g = 2 * $cosg ** 2 - 1; | 
| 4063 | 2 |  |  |  |  | 6 | my $d5 = $tsi * $psim2; | 
| 4064 | 2 |  |  |  |  | 4 | my $d1 = $d5 / $po; | 
| 4065 | 2 |  |  |  |  | 6 | my $d2 = 12 + $eta2 * (36 + 4.5 * $eta2); | 
| 4066 | 2 |  |  |  |  | 6 | my $d3 = $eta2 * (15 + 2.5 * $eta2); | 
| 4067 | 2 |  |  |  |  | 4 | my $d4 = $eta * (5 + 3.75 * $eta2); | 
| 4068 | 2 |  |  |  |  | 5 | my $b1 = SGP_CK2 * $tthmun; | 
| 4069 | 2 |  |  |  |  | 4 | my $b2 = - SGP_CK2 * $unmth2; | 
| 4070 | 2 |  |  |  |  | 4 | my $b3 = $a3cof * $sini; | 
| 4071 | 2 |  |  |  |  | 12 | my $c0 = .5 * $b * SGP_RHO * SGP_QOMS2T * $xnodp * $aodp * | 
| 4072 |  |  |  |  |  |  | $tsi ** 4 * $psim2 ** 3.5 / sqrt ($alpha2); | 
| 4073 | 2 |  |  |  |  | 6 | my $c1 = 1.5 * $xnodp * $alpha2 ** 2 * $c0; | 
| 4074 | 2 |  |  |  |  | 4 | my $c4 = $d1 * $d3 * $b2; | 
| 4075 | 2 |  |  |  |  | 6 | my $c5 = $d5 * $d4 * $b3; | 
| 4076 | 2 |  |  |  |  | 9 | my $xndt = $c1 * ( (2 + $eta2 * (3 + 34 * $eosq) + | 
| 4077 |  |  |  |  |  |  | 5 * $eeta * (4 + $eta2) + 8.5 * $eosq) + $d1 * $d2 * $b1 + | 
| 4078 |  |  |  |  |  |  | $c4 * $cos2g + $c5 * $sing); | 
| 4079 | 2 |  |  |  |  | 4 | my $xndtn = $xndt / $xnodp; | 
| 4080 | 2 |  |  |  |  | 7 | my $edot = - SGP_TOTHRD * $xndtn * (1 - $self->{eccentricity}); | 
| 4081 | 2 |  |  |  |  | 10 | $self->{&TLE_INIT}{TLE_deep} = {$self->_dpinit ($eosq, $sini, | 
| 4082 |  |  |  |  |  |  | $cosi, $beta0, $aodp, $theta2, $sing, $cosg, $beta02, | 
| 4083 |  |  |  |  |  |  | $xlldot, $omgdt, $xnodot, $xnodp)}; | 
| 4084 |  |  |  |  |  |  | { | 
| 4085 | 2 |  |  |  |  | 49 | a3cof => $a3cof, | 
| 4086 |  |  |  |  |  |  | cosi => $cosi, | 
| 4087 |  |  |  |  |  |  | cosio2 => $cosio2, | 
| 4088 |  |  |  |  |  |  | ###	    ed => $ed, | 
| 4089 |  |  |  |  |  |  | edot => $edot, | 
| 4090 |  |  |  |  |  |  | ###	    gamma => $gamma, | 
| 4091 |  |  |  |  |  |  | ###	    isimp => $isimp, | 
| 4092 |  |  |  |  |  |  | omgdt => $omgdt, | 
| 4093 |  |  |  |  |  |  | ###	    ovgpp => $ovgpp, | 
| 4094 |  |  |  |  |  |  | ###	    pp => $pp, | 
| 4095 |  |  |  |  |  |  | ###	    qq => $qq, | 
| 4096 |  |  |  |  |  |  | sini => $sini, | 
| 4097 |  |  |  |  |  |  | sinio2 => $sinio2, | 
| 4098 |  |  |  |  |  |  | theta2 => $theta2, | 
| 4099 |  |  |  |  |  |  | tthmun => $tthmun, | 
| 4100 |  |  |  |  |  |  | unm5th => $unm5th, | 
| 4101 |  |  |  |  |  |  | unmth2 => $unmth2, | 
| 4102 |  |  |  |  |  |  | xgdt1 => $xgdt1, | 
| 4103 |  |  |  |  |  |  | xhdt1 => $xhdt1, | 
| 4104 |  |  |  |  |  |  | xlldot => $xlldot, | 
| 4105 |  |  |  |  |  |  | xmdt1 => $xmdt1, | 
| 4106 |  |  |  |  |  |  | ###	    xnd => $xnd, | 
| 4107 |  |  |  |  |  |  | xndt => $xndt, | 
| 4108 |  |  |  |  |  |  | xnodot => $xnodot, | 
| 4109 |  |  |  |  |  |  | xnodp => $xnodp, | 
| 4110 |  |  |  |  |  |  | }; | 
| 4111 |  |  |  |  |  |  | }; | 
| 4112 |  |  |  |  |  |  | #>>>trw    my $dpsp = $self->{&TLE_INIT}{TLE_deep}; | 
| 4113 |  |  |  |  |  |  |  | 
| 4114 |  |  |  |  |  |  | #*	UPDATE FOR SECULAR GRAVITY AND ATMOSPHERIC DRAG | 
| 4115 |  |  |  |  |  |  |  | 
| 4116 | 7 |  |  |  |  | 19 | my $z1 = .5 * $parm->{xndt} * $tsince * $tsince; | 
| 4117 | 7 |  |  |  |  | 17 | my $z7 = 3.5 * SGP_TOTHRD * $z1 / $parm->{xnodp}; | 
| 4118 | 7 |  |  |  |  | 16 | my $xmamdf = $self->{meananomaly} + $parm->{xlldot} * $tsince; | 
| 4119 |  |  |  |  |  |  | my $omgasm = $self->{argumentofperigee} + $parm->{omgdt} * $tsince + | 
| 4120 | 7 |  |  |  |  | 19 | $z7 * $parm->{xgdt1}; | 
| 4121 |  |  |  |  |  |  | my $xnodes = $self->{ascendingnode} + $parm->{xnodot} * $tsince + | 
| 4122 | 7 |  |  |  |  | 18 | $z7 * $parm->{xhdt1}; | 
| 4123 | 7 |  |  |  |  | 11 | my $xn = $parm->{xnodp}; | 
| 4124 | 7 |  |  |  |  | 14 | my ($em, $xinc); | 
| 4125 | 7 |  |  |  |  | 25 | $self->_dpsec (\$xmamdf, \$omgasm, \$xnodes, \$em, \$xinc, \$xn, $tsince); | 
| 4126 | 7 |  |  |  |  | 18 | $xn = $xn + $parm->{xndt} * $tsince; | 
| 4127 | 7 |  |  |  |  | 16 | $em = $em + $parm->{edot} * $tsince; | 
| 4128 | 7 |  |  |  |  | 11 | my $xmam = $xmamdf + $z1 + $z7 * $parm->{xmdt1}; | 
| 4129 | 7 |  |  |  |  | 24 | $self->_dpper (\$em, \$xinc, \$omgasm, \$xnodes, \$xmam, $tsince); | 
| 4130 | 7 |  |  |  |  | 25 | $xmam = mod2pi ($xmam); | 
| 4131 |  |  |  |  |  |  |  | 
| 4132 |  |  |  |  |  |  | #*	SOLVE KEPLERS EQUATION | 
| 4133 |  |  |  |  |  |  |  | 
| 4134 | 7 |  |  |  |  | 21 | my $zc2 = $xmam + $em * sin ($xmam) * (1 + $em * cos ($xmam)); | 
| 4135 | 7 |  |  |  |  | 13 | my ($cose, $sine, $zc5); | 
| 4136 | 7 |  |  |  |  | 24 | for (my $i = 0; $i < 10; $i++) { | 
| 4137 | 38 |  |  |  |  | 50 | $sine = sin ($zc2); | 
| 4138 | 38 |  |  |  |  | 54 | $cose = cos ($zc2); | 
| 4139 | 38 |  |  |  |  | 51 | $zc5 = 1 / (1 - $em * $cose); | 
| 4140 | 38 |  |  |  |  | 59 | my $cape = ($xmam + $em * $sine - $zc2) * $zc5 + $zc2; | 
| 4141 | 38 | 100 |  |  |  | 77 | last if (abs ($cape - $zc2) <= SGP_E6A); | 
| 4142 | 33 |  |  |  |  | 61 | $zc2 = $cape; | 
| 4143 |  |  |  |  |  |  | } | 
| 4144 |  |  |  |  |  |  |  | 
| 4145 |  |  |  |  |  |  | #*	SHORT PERIOD PRELIMINARY QUANTITIES | 
| 4146 |  |  |  |  |  |  |  | 
| 4147 | 7 |  |  |  |  | 20 | my $am = (SGP_XKE / $xn) ** SGP_TOTHRD; | 
| 4148 | 7 |  |  |  |  | 14 | my $beta2m = 1 - $em * $em; | 
| 4149 |  |  |  |  |  |  | $self->{debug} | 
| 4150 | 7 | 50 |  |  |  | 18 | and warn "Debug - OID $oid sdp8 effective eccentricity $em\n"; | 
| 4151 | 7 | 100 |  |  |  | 451 | $beta2m < 0 | 
| 4152 |  |  |  |  |  |  | and croak "Error - OID $oid Sdp8 effective eccentricity > 1"; | 
| 4153 | 5 |  |  |  |  | 7 | my $sinos = sin ($omgasm); | 
| 4154 | 5 |  |  |  |  | 9 | my $cosos = cos ($omgasm); | 
| 4155 | 5 |  |  |  |  | 8 | my $axnm = $em * $cosos; | 
| 4156 | 5 |  |  |  |  | 7 | my $aynm = $em * $sinos; | 
| 4157 | 5 |  |  |  |  | 9 | my $pm = $am * $beta2m; | 
| 4158 | 5 |  |  |  |  | 7 | my $g1 = 1 / $pm; | 
| 4159 | 5 |  |  |  |  | 7 | my $g2 = .5 * SGP_CK2 * $g1; | 
| 4160 | 5 |  |  |  |  | 10 | my $g3 = $g2 * $g1; | 
| 4161 | 5 |  |  |  |  | 7 | my $beta = sqrt ($beta2m); | 
| 4162 | 5 |  |  |  |  | 10 | my $g4 = .25 * $parm->{a3cof} * $parm->{sini}; | 
| 4163 | 5 |  |  |  |  | 11 | my $g5 = .25 * $parm->{a3cof} * $g1; | 
| 4164 | 5 |  |  |  |  | 8 | my $snf = $beta * $sine * $zc5; | 
| 4165 | 5 |  |  |  |  | 10 | my $csf = ($cose - $em) * $zc5; | 
| 4166 | 5 |  |  |  |  | 12 | my $fm = _actan ($snf,$csf); | 
| 4167 | 5 |  |  |  |  | 10 | my $snfg = $snf * $cosos + $csf * $sinos; | 
| 4168 | 5 |  |  |  |  | 8 | my $csfg = $csf * $cosos - $snf * $sinos; | 
| 4169 | 5 |  |  |  |  | 18 | my $sn2f2g = 2 * $snfg * $csfg; | 
| 4170 | 5 |  |  |  |  | 9 | my $cs2f2g = 2 * $csfg ** 2 - 1; | 
| 4171 | 5 |  |  |  |  | 9 | my $ecosf = $em * $csf; | 
| 4172 | 5 |  |  |  |  | 7 | my $g10 = $fm - $xmam + $em * $snf; | 
| 4173 | 5 |  |  |  |  | 11 | my $rm = $pm / (1 + $ecosf); | 
| 4174 | 5 |  |  |  |  | 7 | my $aovr = $am / $rm; | 
| 4175 | 5 |  |  |  |  | 9 | my $g13 = $xn * $aovr; | 
| 4176 | 5 |  |  |  |  | 7 | my $g14 = - $g13 * $aovr; | 
| 4177 | 5 |  |  |  |  | 14 | my $dr = $g2 * ($parm->{unmth2} * $cs2f2g - 3 * $parm->{tthmun}) - | 
| 4178 |  |  |  |  |  |  | $g4 * $snfg; | 
| 4179 | 5 |  |  |  |  | 10 | my $diwc = 3 * $g3 * $parm->{sini} * $cs2f2g - $g5 * $aynm; | 
| 4180 | 5 |  |  |  |  | 8 | my $di = $diwc * $parm->{cosi}; | 
| 4181 | 5 |  |  |  |  | 10 | my $sini2 = sin (.5 * $xinc); | 
| 4182 |  |  |  |  |  |  |  | 
| 4183 |  |  |  |  |  |  | #*	UPDATE FOR SHORT PERIOD PERIODICS | 
| 4184 |  |  |  |  |  |  |  | 
| 4185 |  |  |  |  |  |  | my $sni2du = $parm->{sinio2} * ($g3 * (.5 * (1 - 7 * $parm->{theta2}) * | 
| 4186 |  |  |  |  |  |  | $sn2f2g - 3 * $parm->{unm5th} * $g10) - $g5 * $parm->{sini} * | 
| 4187 |  |  |  |  |  |  | $csfg * (2 + $ecosf)) - .5 * $g5 * $parm->{theta2} * $axnm / | 
| 4188 | 5 |  |  |  |  | 17 | $parm->{cosio2}; | 
| 4189 |  |  |  |  |  |  | my $xlamb = $fm + $omgasm + $xnodes + $g3 * (.5 * (1 + | 
| 4190 |  |  |  |  |  |  | 6 * $parm->{cosi} - 7 * $parm->{theta2}) * $sn2f2g - | 
| 4191 |  |  |  |  |  |  | 3 * ($parm->{unm5th} + 2 * $parm->{cosi}) * $g10) + | 
| 4192 |  |  |  |  |  |  | $g5 * $parm->{sini} * ($parm->{cosi} * $axnm / | 
| 4193 | 5 |  |  |  |  | 18 | (1 + $parm->{cosi}) - (2 + $ecosf) * $csfg); | 
| 4194 |  |  |  |  |  |  | my $y4 = $sini2 * $snfg + $csfg * $sni2du + | 
| 4195 | 5 |  |  |  |  | 11 | .5 * $snfg * $parm->{cosio2} * $di; | 
| 4196 |  |  |  |  |  |  | my $y5 = $sini2 * $csfg - $snfg * $sni2du + | 
| 4197 | 5 |  |  |  |  | 10 | .5 * $csfg * $parm->{cosio2} * $di; | 
| 4198 | 5 |  |  |  |  | 7 | my $r = $rm + $dr; | 
| 4199 |  |  |  |  |  |  | my $rdot = $xn * $am * $em * $snf / $beta + | 
| 4200 | 5 |  |  |  |  | 14 | $g14 * (2 * $g2 * $parm->{unmth2} * $sn2f2g + $g4 * $csfg); | 
| 4201 |  |  |  |  |  |  | my $rvdot = $xn * $am ** 2 * $beta / $rm + $g14 * $dr + | 
| 4202 | 5 |  |  |  |  | 10 | $am * $g13 * $parm->{sini} * $diwc; | 
| 4203 |  |  |  |  |  |  |  | 
| 4204 |  |  |  |  |  |  | #*	ORIENTATION VECTORS | 
| 4205 |  |  |  |  |  |  |  | 
| 4206 | 5 |  |  |  |  | 9 | my $snlamb = sin ($xlamb); | 
| 4207 | 5 |  |  |  |  | 9 | my $cslamb = cos ($xlamb); | 
| 4208 | 5 |  |  |  |  | 7 | my $temp = 2 * ($y5 * $snlamb - $y4 * $cslamb); | 
| 4209 | 5 |  |  |  |  | 9 | my $ux = $y4 * $temp + $cslamb; | 
| 4210 | 5 |  |  |  |  | 7 | my $vx = $y5 * $temp - $snlamb; | 
| 4211 | 5 |  |  |  |  | 7 | $temp = 2 * ($y5 * $cslamb + $y4 * $snlamb); | 
| 4212 | 5 |  |  |  |  | 9 | my $uy = - $y4 * $temp + $snlamb; | 
| 4213 | 5 |  |  |  |  | 6 | my $vy = - $y5 * $temp + $cslamb; | 
| 4214 | 5 |  |  |  |  | 17 | $temp = 2 * sqrt (1 - $y4 * $y4 - $y5 * $y5); | 
| 4215 | 5 |  |  |  |  | 10 | my $uz = $y4 * $temp; | 
| 4216 | 5 |  |  |  |  | 8 | my $vz = $y5 * $temp; | 
| 4217 |  |  |  |  |  |  |  | 
| 4218 |  |  |  |  |  |  | #*	POSITION AND VELOCITY | 
| 4219 |  |  |  |  |  |  |  | 
| 4220 | 5 |  |  |  |  | 7 | my $x = $r * $ux; | 
| 4221 | 5 |  |  |  |  | 7 | my $y = $r * $uy; | 
| 4222 | 5 |  |  |  |  | 9 | my $z = $r * $uz; | 
| 4223 | 5 |  |  |  |  | 6 | my $xdot = $rdot * $ux + $rvdot * $vx; | 
| 4224 | 5 |  |  |  |  | 10 | my $ydot = $rdot * $uy + $rvdot * $vy; | 
| 4225 | 5 |  |  |  |  | 9 | my $zdot = $rdot * $uz + $rvdot * $vz; | 
| 4226 |  |  |  |  |  |  |  | 
| 4227 | 5 |  |  |  |  | 23 | return _convert_out ($self, $x, $y, $z, $xdot, $ydot, $zdot, $time); | 
| 4228 |  |  |  |  |  |  | } | 
| 4229 |  |  |  |  |  |  |  | 
| 4230 |  |  |  |  |  |  | =item $self->time_set(); | 
| 4231 |  |  |  |  |  |  |  | 
| 4232 |  |  |  |  |  |  | This method sets the coordinates of the object to whatever is | 
| 4233 |  |  |  |  |  |  | computed by the model specified by the model attribute. The | 
| 4234 |  |  |  |  |  |  | 'equinox_dynamical' attribute is set to the current value of the | 
| 4235 |  |  |  |  |  |  | 'epoch_dynamical' attribute. | 
| 4236 |  |  |  |  |  |  |  | 
| 4237 |  |  |  |  |  |  | Although there is no reason this method can not be called directly, it | 
| 4238 |  |  |  |  |  |  | exists to take advantage of the hook in the B | 
| 4239 |  |  |  |  |  |  | object, to allow the position of the body to be computed when the | 
| 4240 |  |  |  |  |  |  | time of the object is set. | 
| 4241 |  |  |  |  |  |  |  | 
| 4242 |  |  |  |  |  |  | =cut | 
| 4243 |  |  |  |  |  |  |  | 
| 4244 |  |  |  |  |  |  | sub time_set { | 
| 4245 | 18318 |  |  | 18318 | 1 | 26449 | my $self = shift; | 
| 4246 | 18318 | 50 |  |  |  | 44075 | my $model = $self->{model} or return; | 
| 4247 | 18318 |  |  |  |  | 44247 | $self->$model ($self->universal); | 
| 4248 | 18304 |  |  |  |  | 34183 | return; | 
| 4249 |  |  |  |  |  |  | } | 
| 4250 |  |  |  |  |  |  |  | 
| 4251 |  |  |  |  |  |  | ####################################################################### | 
| 4252 |  |  |  |  |  |  |  | 
| 4253 |  |  |  |  |  |  | #	The deep-space routines | 
| 4254 |  |  |  |  |  |  |  | 
| 4255 | 16 |  |  | 16 |  | 229 | use constant DS_ZNS => 1.19459E-5; | 
|  | 16 |  |  |  |  | 69 |  | 
|  | 16 |  |  |  |  | 1207 |  | 
| 4256 | 16 |  |  | 16 |  | 108 | use constant DS_C1SS => 2.9864797E-6; | 
|  | 16 |  |  |  |  | 55 |  | 
|  | 16 |  |  |  |  | 1155 |  | 
| 4257 | 16 |  |  | 16 |  | 111 | use constant DS_ZES => .01675; | 
|  | 16 |  |  |  |  | 34 |  | 
|  | 16 |  |  |  |  | 853 |  | 
| 4258 | 16 |  |  | 16 |  | 99 | use constant DS_ZNL => 1.5835218E-4; | 
|  | 16 |  |  |  |  | 37 |  | 
|  | 16 |  |  |  |  | 926 |  | 
| 4259 | 16 |  |  | 16 |  | 113 | use constant DS_C1L => 4.7968065E-7; | 
|  | 16 |  |  |  |  | 46 |  | 
|  | 16 |  |  |  |  | 842 |  | 
| 4260 | 16 |  |  | 16 |  | 103 | use constant DS_ZEL => .05490; | 
|  | 16 |  |  |  |  | 39 |  | 
|  | 16 |  |  |  |  | 762 |  | 
| 4261 | 16 |  |  | 16 |  | 95 | use constant DS_ZCOSIS => .91744867; | 
|  | 16 |  |  |  |  | 35 |  | 
|  | 16 |  |  |  |  | 894 |  | 
| 4262 | 16 |  |  | 16 |  | 102 | use constant DS_ZSINIS => .39785416; | 
|  | 16 |  |  |  |  | 31 |  | 
|  | 16 |  |  |  |  | 868 |  | 
| 4263 | 16 |  |  | 16 |  | 101 | use constant DS_ZSINGS => -.98088458; | 
|  | 16 |  |  |  |  | 50 |  | 
|  | 16 |  |  |  |  | 857 |  | 
| 4264 | 16 |  |  | 16 |  | 105 | use constant DS_ZCOSGS => .1945905; | 
|  | 16 |  |  |  |  | 34 |  | 
|  | 16 |  |  |  |  | 815 |  | 
| 4265 | 16 |  |  | 16 |  | 98 | use constant DS_ZCOSHS => 1.0; | 
|  | 16 |  |  |  |  | 46 |  | 
|  | 16 |  |  |  |  | 1000 |  | 
| 4266 | 16 |  |  | 16 |  | 104 | use constant DS_ZSINHS => 0.0; | 
|  | 16 |  |  |  |  | 42 |  | 
|  | 16 |  |  |  |  | 1000 |  | 
| 4267 | 16 |  |  | 16 |  | 108 | use constant DS_Q22 => 1.7891679E-6; | 
|  | 16 |  |  |  |  | 53 |  | 
|  | 16 |  |  |  |  | 816 |  | 
| 4268 | 16 |  |  | 16 |  | 97 | use constant DS_Q31 => 2.1460748E-6; | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 796 |  | 
| 4269 | 16 |  |  | 16 |  | 98 | use constant DS_Q33 => 2.2123015E-7; | 
|  | 16 |  |  |  |  | 37 |  | 
|  | 16 |  |  |  |  | 789 |  | 
| 4270 | 16 |  |  | 16 |  | 568 | use constant DS_G22 => 5.7686396; | 
|  | 16 |  |  |  |  | 51 |  | 
|  | 16 |  |  |  |  | 812 |  | 
| 4271 | 16 |  |  | 16 |  | 432 | use constant DS_G32 => 0.95240898; | 
|  | 16 |  |  |  |  | 62 |  | 
|  | 16 |  |  |  |  | 1187 |  | 
| 4272 | 16 |  |  | 16 |  | 98 | use constant DS_G44 => 1.8014998; | 
|  | 16 |  |  |  |  | 29 |  | 
|  | 16 |  |  |  |  | 789 |  | 
| 4273 | 16 |  |  | 16 |  | 96 | use constant DS_G52 => 1.0508330; | 
|  | 16 |  |  |  |  | 36 |  | 
|  | 16 |  |  |  |  | 737 |  | 
| 4274 | 16 |  |  | 16 |  | 90 | use constant DS_G54 => 4.4108898; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 785 |  | 
| 4275 | 16 |  |  | 16 |  | 98 | use constant DS_ROOT22 => 1.7891679E-6; | 
|  | 16 |  |  |  |  | 49 |  | 
|  | 16 |  |  |  |  | 763 |  | 
| 4276 | 16 |  |  | 16 |  | 89 | use constant DS_ROOT32 => 3.7393792E-7; | 
|  | 16 |  |  |  |  | 35 |  | 
|  | 16 |  |  |  |  | 815 |  | 
| 4277 | 16 |  |  | 16 |  | 96 | use constant DS_ROOT44 => 7.3636953E-9; | 
|  | 16 |  |  |  |  | 29 |  | 
|  | 16 |  |  |  |  | 767 |  | 
| 4278 | 16 |  |  | 16 |  | 88 | use constant DS_ROOT52 => 1.1428639E-7; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 802 |  | 
| 4279 | 16 |  |  | 16 |  | 95 | use constant DS_ROOT54 => 2.1765803E-9; | 
|  | 16 |  |  |  |  | 29 |  | 
|  | 16 |  |  |  |  | 821 |  | 
| 4280 | 16 |  |  | 16 |  | 100 | use constant DS_THDT => 4.3752691E-3; | 
|  | 16 |  |  |  |  | 30 |  | 
|  | 16 |  |  |  |  | 90705 |  | 
| 4281 |  |  |  |  |  |  |  | 
| 4282 |  |  |  |  |  |  | #	_dpinit | 
| 4283 |  |  |  |  |  |  | # | 
| 4284 |  |  |  |  |  |  | #	the corresponding FORTRAN IV simply leaves values in variables | 
| 4285 |  |  |  |  |  |  | #	for the use of the other deep-space routines. For the Perl | 
| 4286 |  |  |  |  |  |  | #	translation, we figure out which ones are actually used, and | 
| 4287 |  |  |  |  |  |  | #	return a list of key/value pairs to be added to the pre- | 
| 4288 |  |  |  |  |  |  | #	computed model parameters. -- TRW | 
| 4289 |  |  |  |  |  |  |  | 
| 4290 |  |  |  |  |  |  | sub _dpinit { | 
| 4291 | 4 |  |  | 4 |  | 20 | my ($self, $eqsq, $siniq, $cosiq, $rteqsq, $a0, $cosq2, $sinomo, | 
| 4292 |  |  |  |  |  |  | $cosomo, $bsq, $xlldot, $omgdt, $xnodot, $xnodp) = @_; | 
| 4293 |  |  |  |  |  |  |  | 
| 4294 | 4 |  |  |  |  | 25 | my $thgr = thetag ($self->{epoch}); | 
| 4295 | 4 |  |  |  |  | 9 | my $eq  =  $self->{eccentricity}; | 
| 4296 | 4 |  |  |  |  | 7 | my $xnq  =  $xnodp; | 
| 4297 | 4 |  |  |  |  | 10 | my $aqnv  =  1 / $a0; | 
| 4298 | 4 |  |  |  |  | 7 | my $xqncl  =  $self->{inclination}; | 
| 4299 | 4 |  |  |  |  | 8 | my $xmao = $self->{meananomaly}; | 
| 4300 | 4 |  |  |  |  | 10 | my $xpidot = $omgdt + $xnodot; | 
| 4301 | 4 |  |  |  |  | 7 | my $sinq  =  sin ($self->{ascendingnode}); | 
| 4302 | 4 |  |  |  |  | 10 | my $cosq  =  cos ($self->{ascendingnode}); | 
| 4303 |  |  |  |  |  |  |  | 
| 4304 |  |  |  |  |  |  | #*	Initialize lunar & solar terms | 
| 4305 |  |  |  |  |  |  |  | 
| 4306 | 4 |  |  |  |  | 8 | my $day = $self->{ds50} + 18261.5; | 
| 4307 |  |  |  |  |  |  |  | 
| 4308 |  |  |  |  |  |  | #>>>	The original code contained here a comparison of DAY to | 
| 4309 |  |  |  |  |  |  | #>>>	uninitialized variable PREEP, and "optimized out" the | 
| 4310 |  |  |  |  |  |  | #>>>	following if they were equal. This works naturally in | 
| 4311 |  |  |  |  |  |  | #>>>	FORTRAN, which has a different concept of variable scoping. | 
| 4312 |  |  |  |  |  |  | #>>>	Rather than make this work in Perl, I have removed the | 
| 4313 |  |  |  |  |  |  | #>>>	test. As I understand the FORTRAN, it's only used if | 
| 4314 |  |  |  |  |  |  | #>>>	consecutive data sets have exactly the same epoch. Given | 
| 4315 |  |  |  |  |  |  | #>>>	that this is initialization code, the optimization is | 
| 4316 |  |  |  |  |  |  | #>>>	(I hope!) not that important, and given the mess that | 
| 4317 |  |  |  |  |  |  | #>>>	follows, its absence will not (I hope!) be noticable. - TRW | 
| 4318 |  |  |  |  |  |  |  | 
| 4319 | 4 |  |  |  |  | 9 | my $xnodce = 4.5236020 - 9.2422029E-4 * $day; | 
| 4320 | 4 |  |  |  |  | 10 | my $stem = sin ($xnodce); | 
| 4321 | 4 |  |  |  |  | 6 | my $ctem = cos ($xnodce); | 
| 4322 | 4 |  |  |  |  | 10 | my $zcosil = .91375164 - .03568096 * $ctem; | 
| 4323 | 4 |  |  |  |  | 7 | my $zsinil = sqrt (1 - $zcosil * $zcosil); | 
| 4324 | 4 |  |  |  |  | 14 | my $zsinhl =  .089683511 * $stem / $zsinil; | 
| 4325 | 4 |  |  |  |  | 8 | my $zcoshl = sqrt (1 - $zsinhl * $zsinhl); | 
| 4326 | 4 |  |  |  |  | 7 | my $c = 4.7199672 + .22997150 * $day; | 
| 4327 | 4 |  |  |  |  | 8 | my $gam = 5.8351514 + .0019443680 * $day; | 
| 4328 | 4 |  |  |  |  | 12 | my $zmol = mod2pi ($c - $gam); | 
| 4329 | 4 |  |  |  |  | 10 | my $zx = .39785416 * $stem / $zsinil; | 
| 4330 | 4 |  |  |  |  | 10 | my $zy = $zcoshl * $ctem + 0.91744867 * $zsinhl * $stem; | 
| 4331 | 4 |  |  |  |  | 11 | $zx = _actan ($zx, $zy); | 
| 4332 | 4 |  |  |  |  | 8 | $zx = $gam + $zx - $xnodce; | 
| 4333 | 4 |  |  |  |  | 9 | my $zcosgl = cos ($zx); | 
| 4334 | 4 |  |  |  |  | 14 | my $zsingl = sin ($zx); | 
| 4335 | 4 |  |  |  |  | 15 | my $zmos = mod2pi (6.2565837 + .017201977 * $day); | 
| 4336 |  |  |  |  |  |  |  | 
| 4337 |  |  |  |  |  |  | #>>>	Here endeth the optimization - only it isn't one any more | 
| 4338 |  |  |  |  |  |  | #>>>	since I removed it. - TRW | 
| 4339 |  |  |  |  |  |  |  | 
| 4340 |  |  |  |  |  |  | #>>>	The following loop replaces some spaghetti involving an | 
| 4341 |  |  |  |  |  |  | #>>>	assigned goto which essentially executes the same big chunk | 
| 4342 |  |  |  |  |  |  | #>>>	of obscure code twice: once for the Sun, and once for the Moon. | 
| 4343 |  |  |  |  |  |  | #>>>	The comments "Do Solar terms" and "Do Lunar terms" in the | 
| 4344 |  |  |  |  |  |  | #>>>	original apply to the first and second iterations of the loop, | 
| 4345 |  |  |  |  |  |  | #>>>	respectively. The "my" variables declared just before the "for" | 
| 4346 |  |  |  |  |  |  | #>>>	are those values computed inside the loop that are used outside | 
| 4347 |  |  |  |  |  |  | #>>>	the loop. Accumulators are set to zero. -- TRW | 
| 4348 |  |  |  |  |  |  |  | 
| 4349 |  |  |  |  |  |  | #>>>trw    my $savtsn = 1.0E20; | 
| 4350 | 4 |  |  |  |  | 10 | my $xnoi = 1 / $xnq; | 
| 4351 | 4 |  |  |  |  | 17 | my ($sse, $ssi, $ssl, $ssh, $ssg) = (0, 0, 0, 0, 0); | 
| 4352 | 4 |  |  |  |  | 12 | my ($se2, $ee2, $si2, $xi2, $sl2, $xl2, $sgh2, $xgh2, $sh2, $xh2, $se3, | 
| 4353 |  |  |  |  |  |  | $e3, $si3, $xi3, $sl3, $xl3, $sgh3, $xgh3, $sh3, $xh3, $sl4, $xl4, | 
| 4354 |  |  |  |  |  |  | $sgh4, $xgh4); | 
| 4355 |  |  |  |  |  |  |  | 
| 4356 | 4 |  |  |  |  | 27 | foreach my $inputs ( | 
| 4357 |  |  |  |  |  |  | [DS_ZCOSGS, DS_ZSINGS, DS_ZCOSIS, DS_ZSINIS, $cosq, $sinq, | 
| 4358 |  |  |  |  |  |  | DS_C1SS, DS_ZNS, DS_ZES, $zmos, 0], | 
| 4359 |  |  |  |  |  |  | [$zcosgl, $zsingl, $zcosil, $zsinil, | 
| 4360 |  |  |  |  |  |  | $zcoshl * $cosq + $zsinhl * $sinq, | 
| 4361 |  |  |  |  |  |  | $sinq * $zcoshl - $cosq * $zsinhl, DS_C1L, DS_ZNL, | 
| 4362 |  |  |  |  |  |  | DS_ZEL, $zmol, 1], | 
| 4363 |  |  |  |  |  |  | ) { | 
| 4364 |  |  |  |  |  |  |  | 
| 4365 |  |  |  |  |  |  | #>>>	Pick off the terms specific to the body being covered by this | 
| 4366 |  |  |  |  |  |  | #>>>	iteration. The $lunar flag was not in the original FORTRAN, but | 
| 4367 |  |  |  |  |  |  | #>>>	was added to help convert the assigned GOTOs and associated | 
| 4368 |  |  |  |  |  |  | #>>>	code into a loop. -- TRW | 
| 4369 |  |  |  |  |  |  |  | 
| 4370 |  |  |  |  |  |  | #>>>trw	my ($zcosg, $zsing, $zcosi, $zsini, $zcosh, $zsinh, $cc, $zn, $ze, | 
| 4371 |  |  |  |  |  |  | #>>>trw	    $zmo, $lunar) = @$inputs; | 
| 4372 | 8 |  |  |  |  | 27 | my ($zcosg, $zsing, $zcosi, $zsini, $zcosh, $zsinh, $cc, $zn, $ze, | 
| 4373 |  |  |  |  |  |  | undef, $lunar) = @$inputs; | 
| 4374 |  |  |  |  |  |  |  | 
| 4375 |  |  |  |  |  |  | #>>>	From here until the next comment of mine is essentialy | 
| 4376 |  |  |  |  |  |  | #>>>	verbatim from the original FORTRAN - or as verbatim as | 
| 4377 |  |  |  |  |  |  | #>>>	is reasonable considering that the following is Perl. -- TRW | 
| 4378 |  |  |  |  |  |  |  | 
| 4379 | 8 |  |  |  |  | 17 | my $a1 = $zcosg * $zcosh + $zsing * $zcosi * $zsinh; | 
| 4380 | 8 |  |  |  |  | 17 | my $a3 = - $zsing * $zcosh + $zcosg * $zcosi * $zsinh; | 
| 4381 | 8 |  |  |  |  | 16 | my $a7 = - $zcosg * $zsinh + $zsing * $zcosi * $zcosh; | 
| 4382 | 8 |  |  |  |  | 13 | my $a8 = $zsing * $zsini; | 
| 4383 | 8 |  |  |  |  | 12 | my $a9 = $zsing * $zsinh + $zcosg * $zcosi * $zcosh; | 
| 4384 | 8 |  |  |  |  | 22 | my $a10 = $zcosg * $zsini; | 
| 4385 | 8 |  |  |  |  | 14 | my $a2 = $cosiq * $a7 + $siniq * $a8; | 
| 4386 | 8 |  |  |  |  | 11 | my $a4 = $cosiq * $a9 + $siniq * $a10; | 
| 4387 | 8 |  |  |  |  | 13 | my $a5 = - $siniq * $a7 + $cosiq * $a8; | 
| 4388 | 8 |  |  |  |  | 17 | my $a6 = - $siniq * $a9 + $cosiq * $a10; | 
| 4389 |  |  |  |  |  |  | #C | 
| 4390 | 8 |  |  |  |  | 12 | my $x1 = $a1 * $cosomo + $a2 * $sinomo; | 
| 4391 | 8 |  |  |  |  | 17 | my $x2 = $a3 * $cosomo + $a4 * $sinomo; | 
| 4392 | 8 |  |  |  |  | 11 | my $x3 = - $a1 * $sinomo + $a2 * $cosomo; | 
| 4393 | 8 |  |  |  |  | 24 | my $x4 = - $a3 * $sinomo + $a4 * $cosomo; | 
| 4394 | 8 |  |  |  |  | 12 | my $x5 = $a5 * $sinomo; | 
| 4395 | 8 |  |  |  |  | 11 | my $x6 = $a6 * $sinomo; | 
| 4396 | 8 |  |  |  |  | 12 | my $x7 = $a5 * $cosomo; | 
| 4397 | 8 |  |  |  |  | 12 | my $x8 = $a6 * $cosomo; | 
| 4398 |  |  |  |  |  |  | #C | 
| 4399 | 8 |  |  |  |  | 16 | my $z31 = 12 * $x1 * $x1 - 3 * $x3 * $x3; | 
| 4400 | 8 |  |  |  |  | 12 | my $z32 = 24 * $x1 * $x2 - 6 * $x3 * $x4; | 
| 4401 | 8 |  |  |  |  | 17 | my $z33 = 12 * $x2 * $x2 - 3 * $x4 * $x4; | 
| 4402 | 8 |  |  |  |  | 15 | my $z1 = 3 * ($a1 * $a1 + $a2 * $a2) + $z31 * $eqsq; | 
| 4403 | 8 |  |  |  |  | 25 | my $z2 = 6 * ($a1 * $a3 + $a2 * $a4) + $z32 * $eqsq; | 
| 4404 | 8 |  |  |  |  | 180 | my $z3 = 3 * ($a3 * $a3 + $a4 * $a4) + $z33 * $eqsq; | 
| 4405 | 8 |  |  |  |  | 22 | my $z11 = - 6 * $a1 * $a5 + $eqsq * ( - 24 * $x1 * $x7 - 6 * $x3 * $x5); | 
| 4406 | 8 |  |  |  |  | 19 | my $z12 = - 6 * ($a1 * $a6 + $a3 * $a5) + $eqsq * | 
| 4407 |  |  |  |  |  |  | ( - 24 * ($x2 * $x7 + $x1 * $x8) - 6 * ($x3 * $x6 + $x4 * $x5)); | 
| 4408 | 8 |  |  |  |  | 17 | my $z13 = - 6 * $a3 * $a6 + $eqsq * ( - 24 * $x2 * $x8 - 6 * $x4 * $x6); | 
| 4409 | 8 |  |  |  |  | 18 | my $z21 = 6 * $a2 * $a5 + $eqsq * (24 * $x1 * $x5 - 6 * $x3 * $x7); | 
| 4410 | 8 |  |  |  |  | 21 | my $z22 = 6 * ($a4 * $a5 + $a2 * $a6) + $eqsq * | 
| 4411 |  |  |  |  |  |  | (24 * ($x2 * $x5 + $x1 * $x6) - 6 * ($x4 * $x7 + $x3 * $x8)); | 
| 4412 | 8 |  |  |  |  | 19 | my $z23 = 6 * $a4 * $a6 + $eqsq * (24 * $x2 * $x6 - 6 * $x4 * $x8); | 
| 4413 | 8 |  |  |  |  | 13 | $z1 = $z1 + $z1 + $bsq * $z31; | 
| 4414 | 8 |  |  |  |  | 11 | $z2 = $z2 + $z2 + $bsq * $z32; | 
| 4415 | 8 |  |  |  |  | 127 | $z3 = $z3 + $z3 + $bsq * $z33; | 
| 4416 | 8 |  |  |  |  | 17 | my $s3 = $cc * $xnoi; | 
| 4417 | 8 |  |  |  |  | 12 | my $s2 = - .5 * $s3 / $rteqsq; | 
| 4418 | 8 |  |  |  |  | 13 | my $s4 = $s3 * $rteqsq; | 
| 4419 | 8 |  |  |  |  | 12 | my $s1 = - 15 * $eq * $s4; | 
| 4420 | 8 |  |  |  |  | 13 | my $s5 = $x1 * $x3 + $x2 * $x4; | 
| 4421 | 8 |  |  |  |  | 14 | my $s6 = $x2 * $x3 + $x1 * $x4; | 
| 4422 | 8 |  |  |  |  | 13 | my $s7 = $x2 * $x4 - $x1 * $x3; | 
| 4423 | 8 |  |  |  |  | 12 | my $se = $s1 * $zn * $s5; | 
| 4424 | 8 |  |  |  |  | 13 | my $si = $s2 * $zn * ($z11 + $z13); | 
| 4425 | 8 |  |  |  |  | 17 | my $sl = - $zn * $s3 * ($z1 + $z3 - 14 - 6 * $eqsq); | 
| 4426 | 8 |  |  |  |  | 13 | my $sgh = $s4 * $zn * ($z31 + $z33 - 6.); | 
| 4427 | 8 | 50 |  |  |  | 20 | my $sh = $xqncl < 5.2359877E-2 ? 0 : - $zn * $s2 * ($z21 + $z23); | 
| 4428 | 8 |  |  |  |  | 15 | $ee2 = 2 * $s1 * $s6; | 
| 4429 | 8 |  |  |  |  | 13 | $e3 = 2 * $s1 * $s7; | 
| 4430 | 8 |  |  |  |  | 17 | $xi2 = 2 * $s2 * $z12; | 
| 4431 | 8 |  |  |  |  | 16 | $xi3 = 2 * $s2 * ($z13 - $z11); | 
| 4432 | 8 |  |  |  |  | 12 | $xl2 = - 2 * $s3 * $z2; | 
| 4433 | 8 |  |  |  |  | 11 | $xl3 = - 2 * $s3 * ($z3 - $z1); | 
| 4434 | 8 |  |  |  |  | 17 | $xl4 = - 2 * $s3 * ( - 21 - 9 * $eqsq) * $ze; | 
| 4435 | 8 |  |  |  |  | 12 | $xgh2 = 2 * $s4 * $z32; | 
| 4436 | 8 |  |  |  |  | 15 | $xgh3 = 2 * $s4 * ($z33 - $z31); | 
| 4437 | 8 |  |  |  |  | 12 | $xgh4 = - 18 * $s4 * $ze; | 
| 4438 | 8 |  |  |  |  | 11 | $xh2 = - 2 * $s2 * $z22; | 
| 4439 | 8 |  |  |  |  | 19 | $xh3 = - 2 * $s2 * ($z23 - $z21); | 
| 4440 |  |  |  |  |  |  |  | 
| 4441 |  |  |  |  |  |  | #>>>	The following intermediate values are used outside the loop. | 
| 4442 |  |  |  |  |  |  | #>>>	We save off the Solar values. The Lunar values remain after | 
| 4443 |  |  |  |  |  |  | #>>>	the second iteration, and are used in situ. -- TRW | 
| 4444 |  |  |  |  |  |  |  | 
| 4445 | 8 | 100 |  |  |  | 17 | unless ($lunar) { | 
| 4446 | 4 |  |  |  |  | 6 | $se2 = $ee2; | 
| 4447 | 4 |  |  |  |  | 7 | $si2 = $xi2; | 
| 4448 | 4 |  |  |  |  | 6 | $sl2 = $xl2; | 
| 4449 | 4 |  |  |  |  | 7 | $sgh2 = $xgh2; | 
| 4450 | 4 |  |  |  |  | 6 | $sh2 = $xh2; | 
| 4451 | 4 |  |  |  |  | 7 | $se3 = $e3; | 
| 4452 | 4 |  |  |  |  | 5 | $si3 = $xi3; | 
| 4453 | 4 |  |  |  |  | 7 | $sl3 = $xl3; | 
| 4454 | 4 |  |  |  |  | 7 | $sgh3 = $xgh3; | 
| 4455 | 4 |  |  |  |  | 6 | $sh3 = $xh3; | 
| 4456 | 4 |  |  |  |  | 5 | $sl4 = $xl4; | 
| 4457 | 4 |  |  |  |  | 8 | $sgh4 = $xgh4; | 
| 4458 |  |  |  |  |  |  | } | 
| 4459 |  |  |  |  |  |  |  | 
| 4460 |  |  |  |  |  |  | #>>>	Okay, now we accumulate everything that needs accumulating. | 
| 4461 |  |  |  |  |  |  | #>>>	The Lunar calculation is slightly different from the solar | 
| 4462 |  |  |  |  |  |  | #>>>	one, a problem we fix up using the introduced $lunar flag. | 
| 4463 |  |  |  |  |  |  | #>>>	-- TRW | 
| 4464 |  |  |  |  |  |  |  | 
| 4465 | 8 |  |  |  |  | 14 | $sse = $sse + $se; | 
| 4466 | 8 |  |  |  |  | 10 | $ssi = $ssi + $si; | 
| 4467 | 8 |  |  |  |  | 12 | $ssl = $ssl + $sl; | 
| 4468 | 8 |  |  |  |  | 14 | $ssh = $ssh + $sh / $siniq; | 
| 4469 | 8 | 100 |  |  |  | 30 | $ssg = $ssg + $sgh - ($lunar ? $cosiq / $siniq * $sh : $cosiq * $ssh); | 
| 4470 |  |  |  |  |  |  |  | 
| 4471 |  |  |  |  |  |  | } | 
| 4472 |  |  |  |  |  |  |  | 
| 4473 |  |  |  |  |  |  | #>>>	The only substantial modification in the following is the | 
| 4474 |  |  |  |  |  |  | #>>>	swapping of 24-hour and 12-hour calculations for clarity. | 
| 4475 |  |  |  |  |  |  | #>>>	-- TRW | 
| 4476 |  |  |  |  |  |  |  | 
| 4477 | 4 |  |  |  |  | 11 | my $iresfl = 0; | 
| 4478 | 4 |  |  |  |  | 6 | my $isynfl = 0; | 
| 4479 | 4 |  |  |  |  | 16 | my ($bfact, $xlamo); | 
| 4480 | 4 |  |  |  |  | 0 | my ($d2201, $d2211, $d3210, $d3222, $d4410, $d4422, | 
| 4481 |  |  |  |  |  |  | $d5220, $d5232, $d5421, $d5433, | 
| 4482 |  |  |  |  |  |  | $del1, $del2, $del3, $fasx2, $fasx4, $fasx6); | 
| 4483 |  |  |  |  |  |  |  | 
| 4484 | 4 | 50 | 33 |  |  | 36 | if ($xnq < .0052359877 && $xnq > .0034906585) { | 
|  |  | 50 | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 4485 |  |  |  |  |  |  |  | 
| 4486 |  |  |  |  |  |  | #*      Synchronous resonance terms initialization. | 
| 4487 |  |  |  |  |  |  |  | 
| 4488 | 0 |  |  |  |  | 0 | $iresfl = 1; | 
| 4489 | 0 |  |  |  |  | 0 | $isynfl = 1; | 
| 4490 | 0 |  |  |  |  | 0 | my $g200 = 1.0 + $eqsq * ( - 2.5 + .8125 * $eqsq); | 
| 4491 | 0 |  |  |  |  | 0 | my $g310 = 1.0 + 2.0 * $eqsq; | 
| 4492 | 0 |  |  |  |  | 0 | my $g300 = 1.0 + $eqsq * ( - 6.0 + 6.60937 * $eqsq); | 
| 4493 | 0 |  |  |  |  | 0 | my $f220 = .75 * (1 + $cosiq) * (1 + $cosiq); | 
| 4494 | 0 |  |  |  |  | 0 | my $f311 = .9375 * $siniq * $siniq * (1 + 3 * $cosiq) - .75 * (1 | 
| 4495 |  |  |  |  |  |  | + $cosiq); | 
| 4496 | 0 |  |  |  |  | 0 | my $f330 = 1 + $cosiq; | 
| 4497 | 0 |  |  |  |  | 0 | $f330 = 1.875 * $f330 * $f330 * $f330; | 
| 4498 | 0 |  |  |  |  | 0 | $del1 = 3 * $xnq * $xnq * $aqnv * $aqnv; | 
| 4499 | 0 |  |  |  |  | 0 | $del2 = 2 * $del1 * $f220 * $g200 * DS_Q22; | 
| 4500 | 0 |  |  |  |  | 0 | $del3 = 3 * $del1 * $f330 * $g300 * DS_Q33 * $aqnv; | 
| 4501 | 0 |  |  |  |  | 0 | $del1 = $del1 * $f311 * $g310 * DS_Q31 * $aqnv; | 
| 4502 | 0 |  |  |  |  | 0 | $fasx2 = .13130908; | 
| 4503 | 0 |  |  |  |  | 0 | $fasx4 = 2.8843198; | 
| 4504 | 0 |  |  |  |  | 0 | $fasx6 = .37448087; | 
| 4505 |  |  |  |  |  |  | $xlamo = $xmao + $self->{ascendingnode} + | 
| 4506 | 0 |  |  |  |  | 0 | $self->{argumentofperigee} - $thgr; | 
| 4507 | 0 |  |  |  |  | 0 | $bfact = $xlldot + $xpidot - DS_THDT; | 
| 4508 | 0 |  |  |  |  | 0 | $bfact = $bfact + $ssl + $ssg + $ssh; | 
| 4509 |  |  |  |  |  |  | } elsif ($xnq < 8.26E-3 || $xnq > 9.24E-3 || $eq < 0.5) { | 
| 4510 |  |  |  |  |  |  |  | 
| 4511 |  |  |  |  |  |  | #>>>	Do nothing. The original code returned from this point, | 
| 4512 |  |  |  |  |  |  | #>>>	leaving atime, step2, stepn, stepp, xfact, xli, and xni | 
| 4513 |  |  |  |  |  |  | #>>>	uninitialized. It's a minor bit of wasted motion to | 
| 4514 |  |  |  |  |  |  | #>>>	compute these when they're not used, but this way the | 
| 4515 |  |  |  |  |  |  | #>>>	method returns from only one point, which makes the | 
| 4516 |  |  |  |  |  |  | #>>>	provision of debug output easier. | 
| 4517 |  |  |  |  |  |  |  | 
| 4518 |  |  |  |  |  |  | } else { | 
| 4519 |  |  |  |  |  |  |  | 
| 4520 |  |  |  |  |  |  | #*      Geopotential resonance initialization for 12 hour orbits | 
| 4521 |  |  |  |  |  |  |  | 
| 4522 | 0 |  |  |  |  | 0 | $iresfl = 1; | 
| 4523 | 0 |  |  |  |  | 0 | my $eoc = $eq * $eqsq; | 
| 4524 | 0 |  |  |  |  | 0 | my $g201 = - .306 - ($eq - .64) * .440; | 
| 4525 | 0 |  |  |  |  | 0 | my ($g211, $g310, $g322, $g410, $g422, $g520); | 
| 4526 | 0 | 0 |  |  |  | 0 | if ($eq <= .65) { | 
| 4527 | 0 |  |  |  |  | 0 | $g211 = 3.616 - 13.247 * $eq + 16.290 * $eqsq; | 
| 4528 | 0 |  |  |  |  | 0 | $g310 = - 19.302 + 117.390 * $eq - 228.419 * $eqsq + 156.591 | 
| 4529 |  |  |  |  |  |  | * $eoc; | 
| 4530 | 0 |  |  |  |  | 0 | $g322 = - 18.9068 + 109.7927 * $eq - 214.6334 * $eqsq + | 
| 4531 |  |  |  |  |  |  | 146.5816 * $eoc; | 
| 4532 | 0 |  |  |  |  | 0 | $g410 = - 41.122 + 242.694 * $eq - 471.094 * $eqsq + 313.953 | 
| 4533 |  |  |  |  |  |  | * $eoc; | 
| 4534 | 0 |  |  |  |  | 0 | $g422 = - 146.407 + 841.880 * $eq - 1629.014 * $eqsq + | 
| 4535 |  |  |  |  |  |  | 1083.435 * $eoc; | 
| 4536 | 0 |  |  |  |  | 0 | $g520 = - 532.114 + 3017.977 * $eq - 5740 * $eqsq + 3708.276 | 
| 4537 |  |  |  |  |  |  | * $eoc; | 
| 4538 |  |  |  |  |  |  | } else { | 
| 4539 | 0 |  |  |  |  | 0 | $g211 = - 72.099 + 331.819 * $eq - 508.738 * $eqsq + | 
| 4540 |  |  |  |  |  |  | 266.724 * $eoc; | 
| 4541 | 0 |  |  |  |  | 0 | $g310 = - 346.844 + 1582.851 * $eq - 2415.925 * $eqsq + | 
| 4542 |  |  |  |  |  |  | 1246.113 * $eoc; | 
| 4543 | 0 |  |  |  |  | 0 | $g322 = - 342.585 + 1554.908 * $eq - 2366.899 * $eqsq + | 
| 4544 |  |  |  |  |  |  | 1215.972 * $eoc; | 
| 4545 | 0 |  |  |  |  | 0 | $g410 = - 1052.797 + 4758.686 * $eq - 7193.992 * $eqsq + | 
| 4546 |  |  |  |  |  |  | 3651.957 * $eoc; | 
| 4547 | 0 |  |  |  |  | 0 | $g422 = - 3581.69 + 16178.11 * $eq - 24462.77 * $eqsq + | 
| 4548 |  |  |  |  |  |  | 12422.52 * $eoc; | 
| 4549 | 0 | 0 |  |  |  | 0 | $g520 = $eq > .715 ? | 
| 4550 |  |  |  |  |  |  | -5149.66 + 29936.92 * $eq - 54087.36 * $eqsq + 31324.56 * $eoc : | 
| 4551 |  |  |  |  |  |  | 1464.74 - 4664.75 * $eq + 3763.64 * $eqsq; | 
| 4552 |  |  |  |  |  |  | } | 
| 4553 | 0 |  |  |  |  | 0 | my ($g533, $g521, $g532); | 
| 4554 | 0 | 0 |  |  |  | 0 | if ($eq < .7) { | 
| 4555 | 0 |  |  |  |  | 0 | $g533 = - 919.2277 + 4988.61 * $eq - 9064.77 * $eqsq + | 
| 4556 |  |  |  |  |  |  | 5542.21 * $eoc; | 
| 4557 | 0 |  |  |  |  | 0 | $g521 = - 822.71072 + 4568.6173 * $eq - 8491.4146 * $eqsq + | 
| 4558 |  |  |  |  |  |  | 5337.524 * $eoc; | 
| 4559 | 0 |  |  |  |  | 0 | $g532 = - 853.666 + 4690.25 * $eq - 8624.77 * $eqsq + | 
| 4560 |  |  |  |  |  |  | 5341.4 * $eoc; | 
| 4561 |  |  |  |  |  |  | } else { | 
| 4562 | 0 |  |  |  |  | 0 | $g533 = - 37995.78 + 161616.52 * $eq - 229838.2 * $eqsq + | 
| 4563 |  |  |  |  |  |  | 109377.94 * $eoc; | 
| 4564 | 0 |  |  |  |  | 0 | $g521 = - 51752.104 + 218913.95 * $eq - 309468.16 * $eqsq + | 
| 4565 |  |  |  |  |  |  | 146349.42 * $eoc; | 
| 4566 | 0 |  |  |  |  | 0 | $g532 = - 40023.88 + 170470.89 * $eq - 242699.48 * $eqsq + | 
| 4567 |  |  |  |  |  |  | 115605.82 * $eoc; | 
| 4568 |  |  |  |  |  |  | } | 
| 4569 |  |  |  |  |  |  |  | 
| 4570 | 0 |  |  |  |  | 0 | my $sini2 = $siniq * $siniq; | 
| 4571 | 0 |  |  |  |  | 0 | my $f220 = .75 * (1 + 2 * $cosiq + $cosq2); | 
| 4572 | 0 |  |  |  |  | 0 | my $f221 = 1.5 * $sini2; | 
| 4573 | 0 |  |  |  |  | 0 | my $f321 = 1.875 * $siniq * (1 - 2 * $cosiq - 3 * $cosq2); | 
| 4574 | 0 |  |  |  |  | 0 | my $f322 = - 1.875 * $siniq * (1 + 2 * $cosiq - 3 * $cosq2); | 
| 4575 | 0 |  |  |  |  | 0 | my $f441 = 35 * $sini2 * $f220; | 
| 4576 | 0 |  |  |  |  | 0 | my $f442 = 39.3750 * $sini2 * $sini2; | 
| 4577 | 0 |  |  |  |  | 0 | my $f522 = 9.84375 * $siniq * ($sini2 * (1 - 2 * $cosiq - 5 * $cosq2) + | 
| 4578 |  |  |  |  |  |  | .33333333 * ( - 2 + 4 * $cosiq + 6 * $cosq2)); | 
| 4579 | 0 |  |  |  |  | 0 | my $f523 = $siniq * (4.92187512 * $sini2 * ( - 2 - 4 * $cosiq + | 
| 4580 |  |  |  |  |  |  | 10 * $cosq2) + 6.56250012 * (1 + 2 * $cosiq - 3 * $cosq2)); | 
| 4581 | 0 |  |  |  |  | 0 | my $f542 = 29.53125 * $siniq * (2 - 8 * $cosiq + $cosq2 * ( - 12 + | 
| 4582 |  |  |  |  |  |  | 8 * $cosiq + 10 * $cosq2)); | 
| 4583 | 0 |  |  |  |  | 0 | my $f543 = 29.53125 * $siniq * ( - 2 - 8 * $cosiq + $cosq2 * (12 + | 
| 4584 |  |  |  |  |  |  | 8 * $cosiq - 10 * $cosq2)); | 
| 4585 | 0 |  |  |  |  | 0 | my $xno2 = $xnq * $xnq; | 
| 4586 | 0 |  |  |  |  | 0 | my $ainv2 = $aqnv * $aqnv; | 
| 4587 | 0 |  |  |  |  | 0 | my $temp1 = 3 * $xno2 * $ainv2; | 
| 4588 | 0 |  |  |  |  | 0 | my $temp = $temp1 * DS_ROOT22; | 
| 4589 | 0 |  |  |  |  | 0 | $d2201 = $temp * $f220 * $g201; | 
| 4590 | 0 |  |  |  |  | 0 | $d2211 = $temp * $f221 * $g211; | 
| 4591 | 0 |  |  |  |  | 0 | $temp1 = $temp1 * $aqnv; | 
| 4592 | 0 |  |  |  |  | 0 | $temp = $temp1 * DS_ROOT32; | 
| 4593 | 0 |  |  |  |  | 0 | $d3210 = $temp * $f321 * $g310; | 
| 4594 | 0 |  |  |  |  | 0 | $d3222 = $temp * $f322 * $g322; | 
| 4595 | 0 |  |  |  |  | 0 | $temp1 = $temp1 * $aqnv; | 
| 4596 | 0 |  |  |  |  | 0 | $temp = 2 * $temp1 * DS_ROOT44; | 
| 4597 | 0 |  |  |  |  | 0 | $d4410 = $temp * $f441 * $g410; | 
| 4598 | 0 |  |  |  |  | 0 | $d4422 = $temp * $f442 * $g422; | 
| 4599 | 0 |  |  |  |  | 0 | $temp1 = $temp1 * $aqnv; | 
| 4600 | 0 |  |  |  |  | 0 | $temp = $temp1 * DS_ROOT52; | 
| 4601 | 0 |  |  |  |  | 0 | $d5220 = $temp * $f522 * $g520; | 
| 4602 | 0 |  |  |  |  | 0 | $d5232 = $temp * $f523 * $g532; | 
| 4603 | 0 |  |  |  |  | 0 | $temp = 2 * $temp1 * DS_ROOT54; | 
| 4604 | 0 |  |  |  |  | 0 | $d5421 = $temp * $f542 * $g521; | 
| 4605 | 0 |  |  |  |  | 0 | $d5433 = $temp * $f543 * $g533; | 
| 4606 |  |  |  |  |  |  | $xlamo = $xmao + $self->{ascendingnode} + $self->{ascendingnode} - | 
| 4607 | 0 |  |  |  |  | 0 | $thgr - $thgr; | 
| 4608 | 0 |  |  |  |  | 0 | $bfact = $xlldot + $xnodot + $xnodot - DS_THDT - DS_THDT; | 
| 4609 | 0 |  |  |  |  | 0 | $bfact = $bfact + $ssl + $ssh + $ssh; | 
| 4610 |  |  |  |  |  |  | } | 
| 4611 |  |  |  |  |  |  |  | 
| 4612 |  |  |  |  |  |  | #	$bfact won't be defined unless we're a 12- or 24-hour orbit. | 
| 4613 | 4 |  |  |  |  | 7 | my $xfact; | 
| 4614 | 4 | 50 |  |  |  | 19 | defined $bfact and $xfact = $bfact - $xnq; | 
| 4615 |  |  |  |  |  |  | #C | 
| 4616 |  |  |  |  |  |  | #C INITIALIZE INTEGRATOR | 
| 4617 |  |  |  |  |  |  | #C | 
| 4618 | 4 |  |  |  |  | 7 | my $xli = $xlamo; | 
| 4619 | 4 |  |  |  |  | 14 | my $xni = $xnq; | 
| 4620 | 4 |  |  |  |  | 8 | my $atime = 0; | 
| 4621 | 4 |  |  |  |  | 7 | my $stepp = 720; | 
| 4622 | 4 |  |  |  |  | 6 | my $stepn = -720; | 
| 4623 | 4 |  |  |  |  | 6 | my $step2 = 259200; | 
| 4624 |  |  |  |  |  |  |  | 
| 4625 | 4 | 50 |  |  |  | 13 | $self->{debug} and do { | 
| 4626 | 0 |  |  |  |  | 0 | local $Data::Dumper::Terse = 1; | 
| 4627 | 0 |  |  |  |  | 0 | print < | 
| 4628 |  |  |  |  |  |  | Debug _dpinit - | 
| 4629 | 0 | 0 |  |  |  | 0 | atime = @{[defined $atime ? $atime : q{undef}]} | 
| 4630 | 0 | 0 |  |  |  | 0 | cosiq = @{[defined $cosiq ? $cosiq : q{undef}]} | 
| 4631 | 0 | 0 |  |  |  | 0 | d2201 = @{[defined $d2201 ? $d2201 : q{undef}]} | 
| 4632 | 0 | 0 |  |  |  | 0 | d2211 = @{[defined $d2211 ? $d2211 : q{undef}]} | 
| 4633 | 0 | 0 |  |  |  | 0 | d3210 = @{[defined $d3210 ? $d3210 : q{undef}]} | 
| 4634 | 0 | 0 |  |  |  | 0 | d3222 = @{[defined $d3222 ? $d3222 : q{undef}]} | 
| 4635 | 0 | 0 |  |  |  | 0 | d4410 = @{[defined $d4410 ? $d4410 : q{undef}]} | 
| 4636 | 0 | 0 |  |  |  | 0 | d4422 = @{[defined $d4422 ? $d4422 : q{undef}]} | 
| 4637 | 0 | 0 |  |  |  | 0 | d5220 = @{[defined $d5220 ? $d5220 : q{undef}]} | 
| 4638 | 0 | 0 |  |  |  | 0 | d5232 = @{[defined $d5232 ? $d5232 : q{undef}]} | 
| 4639 | 0 | 0 |  |  |  | 0 | d5421 = @{[defined $d5421 ? $d5421 : q{undef}]} | 
| 4640 | 0 | 0 |  |  |  | 0 | d5433 = @{[defined $d5433 ? $d5433 : q{undef}]} | 
| 4641 | 0 | 0 |  |  |  | 0 | del1  = @{[defined $del1 ? $del1 : q{undef}]} | 
| 4642 | 0 | 0 |  |  |  | 0 | del2  = @{[defined $del2 ? $del2 : q{undef}]} | 
| 4643 | 0 | 0 |  |  |  | 0 | del3  = @{[defined $del3 ? $del3 : q{undef}]} | 
| 4644 | 0 | 0 |  |  |  | 0 | e3    = @{[defined $e3 ? $e3 : q{undef}]} | 
| 4645 | 0 | 0 |  |  |  | 0 | ee2   = @{[defined $ee2 ? $ee2 : q{undef}]} | 
| 4646 | 0 | 0 |  |  |  | 0 | fasx2 = @{[defined $fasx2 ? $fasx2 : q{undef}]} | 
| 4647 | 0 | 0 |  |  |  | 0 | fasx4 = @{[defined $fasx4 ? $fasx4 : q{undef}]} | 
| 4648 | 0 | 0 |  |  |  | 0 | fasx6 = @{[defined $fasx6 ? $fasx6 : q{undef}]} | 
| 4649 | 0 | 0 |  |  |  | 0 | iresfl = @{[defined $iresfl ? $iresfl : q{undef}]} | 
| 4650 | 0 | 0 |  |  |  | 0 | isynfl = @{[defined $isynfl ? $isynfl : q{undef}]} | 
| 4651 | 0 | 0 |  |  |  | 0 | omgdt = @{[defined $omgdt ? $omgdt : q{undef}]} | 
| 4652 | 0 | 0 |  |  |  | 0 | se2   = @{[defined $se2 ? $se2 : q{undef}]} | 
| 4653 | 0 | 0 |  |  |  | 0 | se3   = @{[defined $se3 ? $se3 : q{undef}]} | 
| 4654 | 0 | 0 |  |  |  | 0 | sgh2  = @{[defined $sgh2 ? $sgh2 : q{undef}]} | 
| 4655 | 0 | 0 |  |  |  | 0 | sgh3  = @{[defined $sgh3 ? $sgh3 : q{undef}]} | 
| 4656 | 0 | 0 |  |  |  | 0 | sgh4  = @{[defined $sgh4 ? $sgh4 : q{undef}]} | 
| 4657 | 0 | 0 |  |  |  | 0 | sh2   = @{[defined $sh2 ? $sh2 : q{undef}]} | 
| 4658 | 0 | 0 |  |  |  | 0 | sh3   = @{[defined $sh3 ? $sh3 : q{undef}]} | 
| 4659 | 0 | 0 |  |  |  | 0 | si2   = @{[defined $si2 ? $si2 : q{undef}]} | 
| 4660 | 0 | 0 |  |  |  | 0 | si3   = @{[defined $si3 ? $si3 : q{undef}]} | 
| 4661 | 0 | 0 |  |  |  | 0 | siniq = @{[defined $siniq ? $siniq : q{undef}]} | 
| 4662 | 0 | 0 |  |  |  | 0 | sl2   = @{[defined $sl2 ? $sl2 : q{undef}]} | 
| 4663 | 0 | 0 |  |  |  | 0 | sl3   = @{[defined $sl3 ? $sl3 : q{undef}]} | 
| 4664 | 0 | 0 |  |  |  | 0 | sl4   = @{[defined $sl4 ? $sl4 : q{undef}]} | 
| 4665 | 0 | 0 |  |  |  | 0 | sse   = @{[defined $sse ? $sse : q{undef}]} | 
| 4666 | 0 | 0 |  |  |  | 0 | ssg   = @{[defined $ssg ? $ssg : q{undef}]}  << 9.4652e-09 in test_sgp-c-lib | 
| 4667 | 0 | 0 |  |  |  | 0 | ssh   = @{[defined $ssh ? $ssh : q{undef}]} | 
| 4668 | 0 | 0 |  |  |  | 0 | ssi   = @{[defined $ssi ? $ssi : q{undef}]} | 
| 4669 | 0 | 0 |  |  |  | 0 | ssl   = @{[defined $ssl ? $ssl : q{undef}]} | 
| 4670 | 0 | 0 |  |  |  | 0 | step2 = @{[defined $step2 ? $step2 : q{undef}]} | 
| 4671 | 0 | 0 |  |  |  | 0 | stepn = @{[defined $stepn ? $stepn : q{undef}]} | 
| 4672 | 0 | 0 |  |  |  | 0 | stepp = @{[defined $stepp ? $stepp : q{undef}]} | 
| 4673 | 0 | 0 |  |  |  | 0 | thgr  = @{[defined $thgr ? $thgr : q{undef}]}  << 1.26513 in test_sgp-c-lib | 
| 4674 | 0 | 0 |  |  |  | 0 | xfact = @{[defined $xfact ? $xfact : q{undef}]} | 
| 4675 | 0 | 0 |  |  |  | 0 | xgh2  = @{[defined $xgh2 ? $xgh2 : q{undef}]} | 
| 4676 | 0 | 0 |  |  |  | 0 | xgh3  = @{[defined $xgh3 ? $xgh3 : q{undef}]} | 
| 4677 | 0 | 0 |  |  |  | 0 | xgh4  = @{[defined $xgh4 ? $xgh4 : q{undef}]} | 
| 4678 | 0 | 0 |  |  |  | 0 | xh2   = @{[defined $xh2 ? $xh2 : q{undef}]} | 
| 4679 | 0 | 0 |  |  |  | 0 | xh3   = @{[defined $xh3 ? $xh3 : q{undef}]} | 
| 4680 | 0 | 0 |  |  |  | 0 | xi2   = @{[defined $xi2 ? $xi2 : q{undef}]} | 
| 4681 | 0 | 0 |  |  |  | 0 | xi3   = @{[defined $xi3 ? $xi3 : q{undef}]} | 
| 4682 | 0 | 0 |  |  |  | 0 | xl2   = @{[defined $xl2 ? $xl2 : q{undef}]} | 
| 4683 | 0 | 0 |  |  |  | 0 | xl3   = @{[defined $xl3 ? $xl3 : q{undef}]} | 
| 4684 | 0 | 0 |  |  |  | 0 | xl4   = @{[defined $xl4 ? $xl4 : q{undef}]} | 
| 4685 | 0 | 0 |  |  |  | 0 | xlamo = @{[defined $xlamo ? $xlamo : q{undef}]} | 
| 4686 | 0 | 0 |  |  |  | 0 | xli   = @{[defined $xli ? $xli : q{undef}]} | 
| 4687 | 0 | 0 |  |  |  | 0 | xni   = @{[defined $xni ? $xni : q{undef}]} | 
| 4688 | 0 | 0 |  |  |  | 0 | xnq   = @{[defined $xnq ? $xnq : q{undef}]} | 
| 4689 | 0 | 0 |  |  |  | 0 | zmol  = @{[defined $zmol ? $zmol : q{undef}]} | 
| 4690 | 0 | 0 |  |  |  | 0 | zmos  = @{[defined $zmos ? $zmos : q{undef}]} | 
| 4691 |  |  |  |  |  |  | eod | 
| 4692 |  |  |  |  |  |  | }; | 
| 4693 |  |  |  |  |  |  |  | 
| 4694 |  |  |  |  |  |  | return ( | 
| 4695 | 4 |  |  |  |  | 217 | atime => $atime, | 
| 4696 |  |  |  |  |  |  | cosiq => $cosiq, | 
| 4697 |  |  |  |  |  |  | d2201 => $d2201, | 
| 4698 |  |  |  |  |  |  | d2211 => $d2211, | 
| 4699 |  |  |  |  |  |  | d3210 => $d3210, | 
| 4700 |  |  |  |  |  |  | d3222 => $d3222, | 
| 4701 |  |  |  |  |  |  | d4410 => $d4410, | 
| 4702 |  |  |  |  |  |  | d4422 => $d4422, | 
| 4703 |  |  |  |  |  |  | d5220 => $d5220, | 
| 4704 |  |  |  |  |  |  | d5232 => $d5232, | 
| 4705 |  |  |  |  |  |  | d5421 => $d5421, | 
| 4706 |  |  |  |  |  |  | d5433 => $d5433, | 
| 4707 |  |  |  |  |  |  | del1  => $del1, | 
| 4708 |  |  |  |  |  |  | del2  => $del2, | 
| 4709 |  |  |  |  |  |  | del3  => $del3, | 
| 4710 |  |  |  |  |  |  | e3    => $e3, | 
| 4711 |  |  |  |  |  |  | ee2   => $ee2, | 
| 4712 |  |  |  |  |  |  | fasx2 => $fasx2, | 
| 4713 |  |  |  |  |  |  | fasx4 => $fasx4, | 
| 4714 |  |  |  |  |  |  | fasx6 => $fasx6, | 
| 4715 |  |  |  |  |  |  | iresfl => $iresfl, | 
| 4716 |  |  |  |  |  |  | isynfl => $isynfl, | 
| 4717 |  |  |  |  |  |  | omgdt => $omgdt, | 
| 4718 |  |  |  |  |  |  | se2   => $se2, | 
| 4719 |  |  |  |  |  |  | se3   => $se3, | 
| 4720 |  |  |  |  |  |  | sgh2  => $sgh2, | 
| 4721 |  |  |  |  |  |  | sgh3  => $sgh3, | 
| 4722 |  |  |  |  |  |  | sgh4  => $sgh4, | 
| 4723 |  |  |  |  |  |  | sh2   => $sh2, | 
| 4724 |  |  |  |  |  |  | sh3   => $sh3, | 
| 4725 |  |  |  |  |  |  | si2   => $si2, | 
| 4726 |  |  |  |  |  |  | si3   => $si3, | 
| 4727 |  |  |  |  |  |  | siniq => $siniq, | 
| 4728 |  |  |  |  |  |  | sl2   => $sl2, | 
| 4729 |  |  |  |  |  |  | sl3   => $sl3, | 
| 4730 |  |  |  |  |  |  | sl4   => $sl4, | 
| 4731 |  |  |  |  |  |  | sse   => $sse, | 
| 4732 |  |  |  |  |  |  | ssg   => $ssg, | 
| 4733 |  |  |  |  |  |  | ssh   => $ssh, | 
| 4734 |  |  |  |  |  |  | ssi   => $ssi, | 
| 4735 |  |  |  |  |  |  | ssl   => $ssl, | 
| 4736 |  |  |  |  |  |  | step2 => $step2, | 
| 4737 |  |  |  |  |  |  | stepn => $stepn, | 
| 4738 |  |  |  |  |  |  | stepp => $stepp, | 
| 4739 |  |  |  |  |  |  | thgr  => $thgr, | 
| 4740 |  |  |  |  |  |  | xfact => $xfact, | 
| 4741 |  |  |  |  |  |  | xgh2  => $xgh2, | 
| 4742 |  |  |  |  |  |  | xgh3  => $xgh3, | 
| 4743 |  |  |  |  |  |  | xgh4  => $xgh4, | 
| 4744 |  |  |  |  |  |  | xh2   => $xh2, | 
| 4745 |  |  |  |  |  |  | xh3   => $xh3, | 
| 4746 |  |  |  |  |  |  | xi2   => $xi2, | 
| 4747 |  |  |  |  |  |  | xi3   => $xi3, | 
| 4748 |  |  |  |  |  |  | xl2   => $xl2, | 
| 4749 |  |  |  |  |  |  | xl3   => $xl3, | 
| 4750 |  |  |  |  |  |  | xl4   => $xl4, | 
| 4751 |  |  |  |  |  |  | xlamo => $xlamo, | 
| 4752 |  |  |  |  |  |  | xli   => $xli, | 
| 4753 |  |  |  |  |  |  | xni   => $xni, | 
| 4754 |  |  |  |  |  |  | xnq   => $xnq, | 
| 4755 |  |  |  |  |  |  | zmol  => $zmol, | 
| 4756 |  |  |  |  |  |  | zmos  => $zmos, | 
| 4757 |  |  |  |  |  |  | ); | 
| 4758 |  |  |  |  |  |  | } | 
| 4759 |  |  |  |  |  |  |  | 
| 4760 |  |  |  |  |  |  | #	_dpsec | 
| 4761 |  |  |  |  |  |  |  | 
| 4762 |  |  |  |  |  |  | #	Compute deep space secular effects. | 
| 4763 |  |  |  |  |  |  |  | 
| 4764 |  |  |  |  |  |  | #	The corresponding FORTRAN was a goodly plate of spaghetti, with | 
| 4765 |  |  |  |  |  |  | #	a couple chunks of code being executed via assigned GOTOs. Not | 
| 4766 |  |  |  |  |  |  | #	only that, but most of the arguments get modified, and | 
| 4767 |  |  |  |  |  |  | #	therefore need to be passed by reference. So the corresponding | 
| 4768 |  |  |  |  |  |  | #	PERL may not end up corresponding very closely. | 
| 4769 |  |  |  |  |  |  |  | 
| 4770 |  |  |  |  |  |  | #	In fact, at this point in the code the only argument that is | 
| 4771 |  |  |  |  |  |  | #	NOT modified is T. | 
| 4772 |  |  |  |  |  |  |  | 
| 4773 |  |  |  |  |  |  | sub _dpsec { | 
| 4774 | 14 |  |  | 14 |  | 36 | my ($self, @args) = @_; | 
| 4775 | 14 |  |  |  |  | 33 | my $dpsp = $self->{&TLE_INIT}{TLE_deep}; | 
| 4776 | 14 |  |  |  |  | 37 | my ($xll, $omgasm, $xnodes, $em, $xinc, $xn, $t) = @args; | 
| 4777 | 14 |  |  |  |  | 21 | my @orig; | 
| 4778 |  |  |  |  |  |  | $self->{debug} | 
| 4779 | 0 | 0 |  |  |  | 0 | and @orig = map {defined $_ ? $_ : 'undef'} | 
| 4780 | 14 | 0 |  |  |  | 33 | map { SCALAR_REF eq ref $_ ? $$_ : $_} @args; | 
|  | 0 | 50 |  |  |  | 0 |  | 
| 4781 |  |  |  |  |  |  |  | 
| 4782 |  |  |  |  |  |  | #* ENTRANCE FOR DEEP SPACE SECULAR EFFECTS | 
| 4783 |  |  |  |  |  |  |  | 
| 4784 | 14 |  |  |  |  | 28 | $$xll = $$xll + $dpsp->{ssl} * $t; | 
| 4785 | 14 |  |  |  |  | 28 | $$omgasm = $$omgasm + $dpsp->{ssg} * $t; | 
| 4786 | 14 |  |  |  |  | 22 | $$xnodes = $$xnodes + $dpsp->{ssh} * $t; | 
| 4787 | 14 |  |  |  |  | 28 | $$em = $self->{eccentricity} + $dpsp->{sse} * $t; | 
| 4788 | 14 | 100 |  |  |  | 36 | ($$xinc = $self->{inclination} + $dpsp->{ssi} * $t) < 0 and do { | 
| 4789 | 4 |  |  |  |  | 8 | $$xinc = - $$xinc; | 
| 4790 | 4 |  |  |  |  | 7 | $$xnodes = $$xnodes + SGP_PI; | 
| 4791 | 4 |  |  |  |  | 8 | $$omgasm = $$omgasm - SGP_PI; | 
| 4792 |  |  |  |  |  |  | }; | 
| 4793 |  |  |  |  |  |  |  | 
| 4794 | 14 | 50 |  |  |  | 69 | $dpsp->{iresfl} and do { | 
| 4795 |  |  |  |  |  |  |  | 
| 4796 | 0 |  |  |  |  | 0 | my ($delt); | 
| 4797 | 0 |  |  |  |  | 0 | while (1) { | 
| 4798 |  |  |  |  |  |  | (!$dpsp->{atime} || $t >= 0 && $dpsp->{atime} < 0 || | 
| 4799 | 0 | 0 | 0 |  |  | 0 | $t < 0 && $dpsp->{atime} >= 0) and do { | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 4800 |  |  |  |  |  |  |  | 
| 4801 |  |  |  |  |  |  | #C | 
| 4802 |  |  |  |  |  |  | #C EPOCH RESTART | 
| 4803 |  |  |  |  |  |  | #C | 
| 4804 |  |  |  |  |  |  |  | 
| 4805 | 0 | 0 |  |  |  | 0 | $delt = $t >= 0 ? $dpsp->{stepp} : $dpsp->{stepn}; | 
| 4806 | 0 |  |  |  |  | 0 | $dpsp->{atime} = 0; | 
| 4807 | 0 |  |  |  |  | 0 | $dpsp->{xni} = $dpsp->{xnq}; | 
| 4808 | 0 |  |  |  |  | 0 | $dpsp->{xli} = $dpsp->{xlamo}; | 
| 4809 | 0 |  |  |  |  | 0 | last; | 
| 4810 |  |  |  |  |  |  | }; | 
| 4811 | 0 | 0 |  |  |  | 0 | abs ($t) >= abs ($dpsp->{atime}) and do { | 
| 4812 | 0 | 0 |  |  |  | 0 | $delt = $t > 0 ? $dpsp->{stepp} : $dpsp->{stepn}; | 
| 4813 | 0 |  |  |  |  | 0 | last; | 
| 4814 |  |  |  |  |  |  | }; | 
| 4815 | 0 | 0 |  |  |  | 0 | $delt = $t > 0 ? $dpsp->{stepn} : $dpsp->{stepp}; | 
| 4816 | 0 |  |  |  |  | 0 | $self->_dps_dot ($delt);	# Calc. dot terms and integrate. | 
| 4817 |  |  |  |  |  |  | } | 
| 4818 |  |  |  |  |  |  |  | 
| 4819 | 0 |  |  |  |  | 0 | while (abs ($t - $dpsp->{atime}) >= $dpsp->{stepp}) { | 
| 4820 | 0 |  |  |  |  | 0 | $self->_dps_dot ($delt);	# Calc. dot terms and integrate. | 
| 4821 |  |  |  |  |  |  | } | 
| 4822 | 0 |  |  |  |  | 0 | my $ft = $t - $dpsp->{atime}; | 
| 4823 | 0 |  |  |  |  | 0 | my ($xldot, $xndot, $xnddt) = $self->_dps_dot ();	# Calc. dot terms. | 
| 4824 | 0 |  |  |  |  | 0 | $$xn = $dpsp->{xni} + $xndot * $ft + $xnddt * $ft * $ft * 0.5; | 
| 4825 | 0 |  |  |  |  | 0 | my $xl = $dpsp->{xli} + $xldot * $ft + $xndot * $ft * $ft * 0.5; | 
| 4826 | 0 |  |  |  |  | 0 | my $temp = - $$xnodes + $dpsp->{thgr} + $t * DS_THDT; | 
| 4827 | 0 | 0 |  |  |  | 0 | $$xll = $dpsp->{isynfl}  ? $xl - $$omgasm + $temp : $xl + $temp + $temp; | 
| 4828 |  |  |  |  |  |  | }; | 
| 4829 |  |  |  |  |  |  |  | 
| 4830 | 14 | 50 |  |  |  | 31 | $self->{debug} and print < | 
| 4831 |  |  |  |  |  |  | Debug _dpsec - | 
| 4832 |  |  |  |  |  |  | xll    : $orig[0] -> $$xll | 
| 4833 |  |  |  |  |  |  | omgasm : $orig[1] -> $$omgasm | 
| 4834 |  |  |  |  |  |  | xnodes : $orig[2] -> $$xnodes | 
| 4835 |  |  |  |  |  |  | em     : $orig[3] -> $$em | 
| 4836 |  |  |  |  |  |  | xinc   : $orig[4] -> $$xinc | 
| 4837 |  |  |  |  |  |  | xn     : $orig[5] -> $$xn | 
| 4838 |  |  |  |  |  |  | t      : $t | 
| 4839 |  |  |  |  |  |  | eod | 
| 4840 | 14 |  |  |  |  | 32 | return; | 
| 4841 |  |  |  |  |  |  | } | 
| 4842 |  |  |  |  |  |  |  | 
| 4843 |  |  |  |  |  |  | #	_dps_dot | 
| 4844 |  |  |  |  |  |  |  | 
| 4845 |  |  |  |  |  |  | #	Calculate the dot terms for the secular effects. | 
| 4846 |  |  |  |  |  |  |  | 
| 4847 |  |  |  |  |  |  | #	In the original FORTRAN, this was a chunk of code followed | 
| 4848 |  |  |  |  |  |  | #	by an assigned GOTO. But here it has transmogrified into a | 
| 4849 |  |  |  |  |  |  | #	method. If an argument is passed, it is taken to be the delta | 
| 4850 |  |  |  |  |  |  | #	for an iteration of the integration step, which is done. It | 
| 4851 |  |  |  |  |  |  | #	returns xldot, xndot, and xnddt | 
| 4852 |  |  |  |  |  |  |  | 
| 4853 |  |  |  |  |  |  | sub _dps_dot { | 
| 4854 | 0 |  |  | 0 |  | 0 | my ($self, $delt) = @_; | 
| 4855 | 0 |  |  |  |  | 0 | my $dpsp = $self->{&TLE_INIT}{TLE_deep}; | 
| 4856 |  |  |  |  |  |  |  | 
| 4857 |  |  |  |  |  |  | #C | 
| 4858 |  |  |  |  |  |  | #C DOT TERMS CALCULATED | 
| 4859 |  |  |  |  |  |  | #C | 
| 4860 |  |  |  |  |  |  |  | 
| 4861 |  |  |  |  |  |  | # We get here from either: | 
| 4862 |  |  |  |  |  |  | #   - an explicit GOTO below line 130; | 
| 4863 |  |  |  |  |  |  | #   - an explicit GOTO below line 160, which is reached from below 110 or 125. | 
| 4864 |  |  |  |  |  |  | # This is the only reference to line 152. | 
| 4865 |  |  |  |  |  |  | # XNDOT, XNDDT, and XLDOT come out of this. | 
| 4866 |  |  |  |  |  |  | #150: | 
| 4867 | 0 |  |  |  |  | 0 | my ($xndot, $xnddt); | 
| 4868 | 0 | 0 |  |  |  | 0 | if ($dpsp->{isynfl}) { | 
| 4869 |  |  |  |  |  |  | $xndot = $dpsp->{del1} * sin ($dpsp->{xli} - $dpsp->{fasx2}) + | 
| 4870 |  |  |  |  |  |  | $dpsp->{del2} * sin (2 * ($dpsp->{xli} - $dpsp->{fasx4})) + | 
| 4871 | 0 |  |  |  |  | 0 | $dpsp->{del3} * sin (3 * ($dpsp->{xli} - $dpsp->{fasx6})); | 
| 4872 |  |  |  |  |  |  | $xnddt = $dpsp->{del1} * cos ($dpsp->{xli} - $dpsp->{fasx2}) + | 
| 4873 |  |  |  |  |  |  | 2 * $dpsp->{del2} * cos (2 * ($dpsp->{xli} - $dpsp->{fasx4})) + | 
| 4874 | 0 |  |  |  |  | 0 | 3 * $dpsp->{del3} * cos (3 * ($dpsp->{xli} - $dpsp->{fasx6})); | 
| 4875 |  |  |  |  |  |  | } else { | 
| 4876 |  |  |  |  |  |  | my $xomi = $self->{argumentofperigee} + | 
| 4877 | 0 |  |  |  |  | 0 | $dpsp->{omgdt} * $dpsp->{atime}; | 
| 4878 | 0 |  |  |  |  | 0 | my $x2omi = $xomi + $xomi; | 
| 4879 | 0 |  |  |  |  | 0 | my $x2li = $dpsp->{xli} + $dpsp->{xli}; | 
| 4880 |  |  |  |  |  |  | $xndot = $dpsp->{d2201} * sin ($x2omi + $dpsp->{xli} - DS_G22) + | 
| 4881 |  |  |  |  |  |  | $dpsp->{d2211} * sin ($dpsp->{xli} - DS_G22) + | 
| 4882 |  |  |  |  |  |  | $dpsp->{d3210} * sin ($xomi + $dpsp->{xli} - DS_G32) + | 
| 4883 |  |  |  |  |  |  | $dpsp->{d3222} * sin ( - $xomi + $dpsp->{xli} - DS_G32) + | 
| 4884 |  |  |  |  |  |  | $dpsp->{d4410} * sin ($x2omi + $x2li - DS_G44) + | 
| 4885 |  |  |  |  |  |  | $dpsp->{d4422} * sin ($x2li - DS_G44) + | 
| 4886 |  |  |  |  |  |  | $dpsp->{d5220} * sin ($xomi + $dpsp->{xli} - DS_G52) + | 
| 4887 |  |  |  |  |  |  | $dpsp->{d5232} * sin ( - $xomi + $dpsp->{xli} - DS_G52) + | 
| 4888 |  |  |  |  |  |  | $dpsp->{d5421} * sin ($xomi + $x2li - DS_G54) + | 
| 4889 | 0 |  |  |  |  | 0 | $dpsp->{d5433} * sin ( - $xomi + $x2li - DS_G54); | 
| 4890 |  |  |  |  |  |  | $xnddt = $dpsp->{d2201} * cos ($x2omi + $dpsp->{xli} - DS_G22) + | 
| 4891 |  |  |  |  |  |  | $dpsp->{d2211} * cos ($dpsp->{xli} - DS_G22) + | 
| 4892 |  |  |  |  |  |  | $dpsp->{d3210} * cos ($xomi + $dpsp->{xli} - DS_G32) + | 
| 4893 |  |  |  |  |  |  | $dpsp->{d3222} * cos ( - $xomi + $dpsp->{xli} - DS_G32) + | 
| 4894 |  |  |  |  |  |  | $dpsp->{d5220} * cos ($xomi + $dpsp->{xli} - DS_G52) + | 
| 4895 |  |  |  |  |  |  | $dpsp->{d5232} * cos ( - $xomi + $dpsp->{xli} - DS_G52) + | 
| 4896 |  |  |  |  |  |  | 2 * ($dpsp->{d4410} * cos ($x2omi + $x2li - DS_G44) + | 
| 4897 |  |  |  |  |  |  | $dpsp->{d4422} * cos ($x2li - DS_G44) + | 
| 4898 |  |  |  |  |  |  | $dpsp->{d5421} * cos ($xomi + $x2li - DS_G54) + | 
| 4899 | 0 |  |  |  |  | 0 | $dpsp->{d5433} * cos ( - $xomi + $x2li - DS_G54)); | 
| 4900 |  |  |  |  |  |  | } | 
| 4901 | 0 |  |  |  |  | 0 | my $xldot = $dpsp->{xni} + $dpsp->{xfact}; | 
| 4902 | 0 |  |  |  |  | 0 | $xnddt = $xnddt * $xldot; | 
| 4903 |  |  |  |  |  |  |  | 
| 4904 |  |  |  |  |  |  | #C | 
| 4905 |  |  |  |  |  |  | #C INTEGRATOR | 
| 4906 |  |  |  |  |  |  | #C | 
| 4907 |  |  |  |  |  |  |  | 
| 4908 | 0 | 0 |  |  |  | 0 | defined $delt and do { | 
| 4909 | 0 |  |  |  |  | 0 | $dpsp->{xli} = $dpsp->{xli} + $xldot * $delt + $xndot * $dpsp->{step2}; | 
| 4910 | 0 |  |  |  |  | 0 | $dpsp->{xni} = $dpsp->{xni} + $xndot * $delt + $xnddt * $dpsp->{step2}; | 
| 4911 | 0 |  |  |  |  | 0 | $dpsp->{atime} = $dpsp->{atime} + $delt; | 
| 4912 |  |  |  |  |  |  | }; | 
| 4913 |  |  |  |  |  |  |  | 
| 4914 | 0 |  |  |  |  | 0 | return ($xldot, $xndot, $xnddt); | 
| 4915 |  |  |  |  |  |  | } | 
| 4916 |  |  |  |  |  |  |  | 
| 4917 |  |  |  |  |  |  | #	_dpper | 
| 4918 |  |  |  |  |  |  |  | 
| 4919 |  |  |  |  |  |  | #	Calculate solar/lunar periodics. | 
| 4920 |  |  |  |  |  |  |  | 
| 4921 |  |  |  |  |  |  | #	Note that T must also be passed. | 
| 4922 |  |  |  |  |  |  |  | 
| 4923 |  |  |  |  |  |  | #	Note also that EM, XINC, OMGASM, XNODES, and XLL must be passed | 
| 4924 |  |  |  |  |  |  | #	by reference, since they get modified. Sigh. | 
| 4925 |  |  |  |  |  |  |  | 
| 4926 |  |  |  |  |  |  | sub _dpper { | 
| 4927 | 14 |  |  | 14 |  | 34 | my ($self, @args) = @_; | 
| 4928 | 14 |  |  |  |  | 34 | my $dpsp = $self->{&TLE_INIT}{TLE_deep}; | 
| 4929 | 14 |  |  |  |  | 30 | my ($em, $xinc, $omgasm, $xnodes, $xll, $t) = @args; | 
| 4930 | 14 |  |  |  |  | 20 | my @orig; | 
| 4931 |  |  |  |  |  |  | $self->{debug} | 
| 4932 | 0 | 0 |  |  |  | 0 | and @orig = map {defined $_ ? $_ : 'undef'} | 
| 4933 | 14 | 0 |  |  |  | 27 | map { SCALAR_REF eq ref $_ ? $$_ : $_} @args; | 
|  | 0 | 50 |  |  |  | 0 |  | 
| 4934 |  |  |  |  |  |  |  | 
| 4935 |  |  |  |  |  |  | #C | 
| 4936 |  |  |  |  |  |  | #C ENTRANCES FOR LUNAR-SOLAR PERIODICS | 
| 4937 |  |  |  |  |  |  | #C | 
| 4938 |  |  |  |  |  |  | #C | 
| 4939 |  |  |  |  |  |  | #ENTRY DPPER(EM,XINC,OMGASM,XNODES,XLL) | 
| 4940 |  |  |  |  |  |  |  | 
| 4941 | 14 |  |  |  |  | 29 | my $sinis = sin ($$xinc); | 
| 4942 | 14 |  |  |  |  | 26 | my $cosis = cos ($$xinc); | 
| 4943 |  |  |  |  |  |  |  | 
| 4944 |  |  |  |  |  |  | # The following is an optimization that | 
| 4945 |  |  |  |  |  |  | # skips a bunch of calculations if the | 
| 4946 |  |  |  |  |  |  | # current time is within 30 (minutes) of | 
| 4947 |  |  |  |  |  |  | # the previous. | 
| 4948 |  |  |  |  |  |  | # This is the only reference to line 210 | 
| 4949 |  |  |  |  |  |  |  | 
| 4950 | 14 | 100 | 100 |  |  | 71 | unless (defined $dpsp->{savtsn} && abs ($dpsp->{savtsn} - $t) < 30) { | 
| 4951 | 12 |  |  |  |  | 23 | $dpsp->{savtsn} = $t; | 
| 4952 | 12 |  |  |  |  | 23 | my $zm = $dpsp->{zmos} + DS_ZNS * $t; | 
| 4953 | 12 |  |  |  |  | 27 | my $zf = $zm + 2 * DS_ZES * sin ($zm); | 
| 4954 | 12 |  |  |  |  | 18 | my $sinzf = sin ($zf); | 
| 4955 | 12 |  |  |  |  | 24 | my $f2 = .5 * $sinzf * $sinzf - .25; | 
| 4956 | 12 |  |  |  |  | 23 | my $f3 = - .5 * $sinzf * cos ($zf); | 
| 4957 | 12 |  |  |  |  | 24 | my $ses = $dpsp->{se2} * $f2 + $dpsp->{se3} * $f3; | 
| 4958 | 12 |  |  |  |  | 19 | my $sis = $dpsp->{si2} * $f2 + $dpsp->{si3} * $f3; | 
| 4959 |  |  |  |  |  |  | my $sls = $dpsp->{sl2} * $f2 + $dpsp->{sl3} * $f3 + | 
| 4960 | 12 |  |  |  |  | 26 | $dpsp->{sl4} * $sinzf; | 
| 4961 |  |  |  |  |  |  | $dpsp->{sghs} = $dpsp->{sgh2} * $f2 + $dpsp->{sgh3} * $f3 + | 
| 4962 | 12 |  |  |  |  | 69 | $dpsp->{sgh4} * $sinzf; | 
| 4963 | 12 |  |  |  |  | 24 | $dpsp->{shs} = $dpsp->{sh2} * $f2 + $dpsp->{sh3} * $f3; | 
| 4964 | 12 |  |  |  |  | 21 | $zm = $dpsp->{zmol} + DS_ZNL * $t; | 
| 4965 | 12 |  |  |  |  | 28 | $zf = $zm + 2 * DS_ZEL * sin ($zm); | 
| 4966 | 12 |  |  |  |  | 13 | $sinzf = sin ($zf); | 
| 4967 | 12 |  |  |  |  | 23 | $f2 = .5 * $sinzf * $sinzf - .25; | 
| 4968 | 12 |  |  |  |  | 21 | $f3 = - .5 * $sinzf * cos ($zf); | 
| 4969 | 12 |  |  |  |  | 22 | my $sel = $dpsp->{ee2} * $f2 + $dpsp->{e3} * $f3; | 
| 4970 | 12 |  |  |  |  | 18 | my $sil = $dpsp->{xi2} * $f2 + $dpsp->{xi3} * $f3; | 
| 4971 | 12 |  |  |  |  | 23 | my $sll = $dpsp->{xl2} * $f2 + $dpsp->{xl3} * $f3 + $dpsp->{xl4} * $sinzf; | 
| 4972 | 12 |  |  |  |  | 26 | $dpsp->{sghl} = $dpsp->{xgh2} * $f2 + $dpsp->{xgh3} * $f3 + $dpsp->{xgh4} * $sinzf; | 
| 4973 | 12 |  |  |  |  | 21 | $dpsp->{shl} = $dpsp->{xh2} * $f2 + $dpsp->{xh3} * $f3; | 
| 4974 | 12 |  |  |  |  | 20 | $dpsp->{pe} = $ses + $sel; | 
| 4975 | 12 |  |  |  |  | 28 | $dpsp->{pinc} = $sis + $sil; | 
| 4976 | 12 |  |  |  |  | 26 | $dpsp->{pl} = $sls + $sll; | 
| 4977 |  |  |  |  |  |  | } | 
| 4978 |  |  |  |  |  |  |  | 
| 4979 | 14 |  |  |  |  | 25 | my $pgh = $dpsp->{sghs} + $dpsp->{sghl}; | 
| 4980 | 14 |  |  |  |  | 21 | my $ph = $dpsp->{shs} + $dpsp->{shl}; | 
| 4981 | 14 |  |  |  |  | 31 | $$xinc = $$xinc + $dpsp->{pinc}; | 
| 4982 | 14 |  |  |  |  | 24 | $$em = $$em + $dpsp->{pe}; | 
| 4983 |  |  |  |  |  |  |  | 
| 4984 | 14 | 50 |  |  |  | 43 | if ($self->{inclination} >= .2) { | 
| 4985 |  |  |  |  |  |  |  | 
| 4986 |  |  |  |  |  |  | #C | 
| 4987 |  |  |  |  |  |  | #C APPLY PERIODICS DIRECTLY | 
| 4988 |  |  |  |  |  |  | #C | 
| 4989 |  |  |  |  |  |  | #218: | 
| 4990 |  |  |  |  |  |  |  | 
| 4991 | 14 |  |  |  |  | 28 | my $ph = $ph / $dpsp->{siniq}; | 
| 4992 | 14 |  |  |  |  | 22 | my $pgh = $pgh - $dpsp->{cosiq} * $ph; | 
| 4993 | 14 |  |  |  |  | 30 | $$omgasm = $$omgasm + $pgh; | 
| 4994 | 14 |  |  |  |  | 22 | $$xnodes = $$xnodes + $ph; | 
| 4995 | 14 |  |  |  |  | 22 | $$xll = $$xll + $dpsp->{pl}; | 
| 4996 |  |  |  |  |  |  | } else { | 
| 4997 |  |  |  |  |  |  |  | 
| 4998 |  |  |  |  |  |  | #C | 
| 4999 |  |  |  |  |  |  | #C APPLY PERIODICS WITH LYDDANE MODIFICATION | 
| 5000 |  |  |  |  |  |  | #C | 
| 5001 |  |  |  |  |  |  | #220: | 
| 5002 | 0 |  |  |  |  | 0 | my $sinok = sin ($$xnodes); | 
| 5003 | 0 |  |  |  |  | 0 | my $cosok = cos ($$xnodes); | 
| 5004 | 0 |  |  |  |  | 0 | my $alfdp = $sinis * $sinok; | 
| 5005 | 0 |  |  |  |  | 0 | my $betdp = $sinis * $cosok; | 
| 5006 | 0 |  |  |  |  | 0 | my $dalf = $ph * $cosok + $dpsp->{pinc} * $cosis * $sinok; | 
| 5007 | 0 |  |  |  |  | 0 | my $dbet = - $ph * $sinok + $dpsp->{pinc} * $cosis * $cosok; | 
| 5008 | 0 |  |  |  |  | 0 | $alfdp = $alfdp + $dalf; | 
| 5009 | 0 |  |  |  |  | 0 | $betdp = $betdp + $dbet; | 
| 5010 | 0 |  |  |  |  | 0 | my $xls = $$xll + $$omgasm + $cosis * $$xnodes; | 
| 5011 | 0 |  |  |  |  | 0 | my $dls = $dpsp->{pl} + $pgh - $dpsp->{pinc} * $$xnodes * $sinis; | 
| 5012 | 0 |  |  |  |  | 0 | $xls = $xls + $dls; | 
| 5013 | 0 |  |  |  |  | 0 | $$xnodes = _actan ($alfdp,$betdp); | 
| 5014 | 0 |  |  |  |  | 0 | $$xll = $$xll + $dpsp->{pl}; | 
| 5015 | 0 |  |  |  |  | 0 | $$omgasm = $xls - $$xll - cos ($$xinc) * $$xnodes; | 
| 5016 |  |  |  |  |  |  | } | 
| 5017 |  |  |  |  |  |  |  | 
| 5018 | 14 | 50 |  |  |  | 34 | $self->{debug} and print < | 
| 5019 |  |  |  |  |  |  | Debug _dpper - | 
| 5020 |  |  |  |  |  |  | em     : $orig[0] -> $$em | 
| 5021 |  |  |  |  |  |  | xinc   : $orig[1] -> $$xinc | 
| 5022 |  |  |  |  |  |  | omgasm : $orig[2] -> $$omgasm | 
| 5023 |  |  |  |  |  |  | xnodes : $orig[3] -> $$xnodes | 
| 5024 |  |  |  |  |  |  | xll    : $orig[4] -> $$xll | 
| 5025 |  |  |  |  |  |  | t      : $t | 
| 5026 |  |  |  |  |  |  | eod | 
| 5027 |  |  |  |  |  |  |  | 
| 5028 | 14 |  |  |  |  | 31 | return; | 
| 5029 |  |  |  |  |  |  | } | 
| 5030 |  |  |  |  |  |  |  | 
| 5031 |  |  |  |  |  |  | ####################################################################### | 
| 5032 |  |  |  |  |  |  |  | 
| 5033 |  |  |  |  |  |  | #	All "Revisiting Spacetrack Report #3" code | 
| 5034 |  |  |  |  |  |  |  | 
| 5035 |  |  |  |  |  |  | =item $tle = $tle->sgp4r($time) | 
| 5036 |  |  |  |  |  |  |  | 
| 5037 |  |  |  |  |  |  | This method calculates the position of the body described by the TLE | 
| 5038 |  |  |  |  |  |  | object at the given time, using the revised SGP4 model. The universal | 
| 5039 |  |  |  |  |  |  | time of the object is set to $time, and the 'equinox_dynamical' | 
| 5040 |  |  |  |  |  |  | attribute is set to the current value of the 'epoch_dynamical' | 
| 5041 |  |  |  |  |  |  | attribute. | 
| 5042 |  |  |  |  |  |  |  | 
| 5043 |  |  |  |  |  |  | The result is the original object reference. See the L | 
| 5044 |  |  |  |  |  |  | heading above for how to retrieve the coordinates you just calculated. | 
| 5045 |  |  |  |  |  |  |  | 
| 5046 |  |  |  |  |  |  | The algorithm for this model comes from "Revisiting Spacetrack Report | 
| 5047 |  |  |  |  |  |  | Number 3" (see L). That report | 
| 5048 |  |  |  |  |  |  | considers the algorithm to be a correction and extension of SGP4 | 
| 5049 |  |  |  |  |  |  | (merging it with SDP4), and simply calls the algorithm SGP4. I have | 
| 5050 |  |  |  |  |  |  | appended the "r" (for 'revised' or 'revisited', take your pick) because | 
| 5051 |  |  |  |  |  |  | I have preserved the original algorithm as well. | 
| 5052 |  |  |  |  |  |  |  | 
| 5053 |  |  |  |  |  |  | B that this algorithm depends on the setting of the | 
| 5054 |  |  |  |  |  |  | 'gravconst_r' attribute. The default setting of that attribute in this | 
| 5055 |  |  |  |  |  |  | module is 84, but the test data that comes with "Revisiting Spacetrack | 
| 5056 |  |  |  |  |  |  | Report #3" uses 72. | 
| 5057 |  |  |  |  |  |  |  | 
| 5058 |  |  |  |  |  |  | This algorithm is also (currently) the only one that returns a useful | 
| 5059 |  |  |  |  |  |  | value in the model_error attribute, as follows: | 
| 5060 |  |  |  |  |  |  |  | 
| 5061 |  |  |  |  |  |  | 0 = success | 
| 5062 |  |  |  |  |  |  | 1 = mean eccentricity < 0 or > 1, or a < .95 | 
| 5063 |  |  |  |  |  |  | 2 = mean motion < 0.0 | 
| 5064 |  |  |  |  |  |  | 3 = instantaneous eccentricity < 0 or > 1 | 
| 5065 |  |  |  |  |  |  | 4 = semi-latus rectum < 0 | 
| 5066 |  |  |  |  |  |  | 5 = epoch elements are sub-orbital | 
| 5067 |  |  |  |  |  |  | 6 = satellite has decayed | 
| 5068 |  |  |  |  |  |  |  | 
| 5069 |  |  |  |  |  |  | These errors are dualvars if your Scalar::Util supports these. That is, | 
| 5070 |  |  |  |  |  |  | they are interpreted as numbers in numeric context and the | 
| 5071 |  |  |  |  |  |  | corresponding string in string context. The string is generally the | 
| 5072 |  |  |  |  |  |  | explanation, except for 0, which is '' in string context. If your | 
| 5073 |  |  |  |  |  |  | Scalar::Util does not support dualvar, the numeric value is returned. | 
| 5074 |  |  |  |  |  |  |  | 
| 5075 |  |  |  |  |  |  | Currently, errors 1 through 4 cause an explicit exception to be thrown | 
| 5076 |  |  |  |  |  |  | after setting the model_error attribute. Exceptions will also be thrown | 
| 5077 |  |  |  |  |  |  | if the TLE eccentricity is negative or greater than one, or the TLE mean | 
| 5078 |  |  |  |  |  |  | motion is negative. | 
| 5079 |  |  |  |  |  |  |  | 
| 5080 |  |  |  |  |  |  | Errors 5 and 6 look more like informational errors to me. Error 5 | 
| 5081 |  |  |  |  |  |  | indicates that the perigee is less than the radius of the earth. This | 
| 5082 |  |  |  |  |  |  | could very well happen if the TLE represents a coasting arc of a | 
| 5083 |  |  |  |  |  |  | spacecraft being launched or preparing for re-entry. Error 6 means the | 
| 5084 |  |  |  |  |  |  | actual computed position was underground. Maybe this should be an | 
| 5085 |  |  |  |  |  |  | exception, though I have never needed this kind of exception previously. | 
| 5086 |  |  |  |  |  |  |  | 
| 5087 |  |  |  |  |  |  | B that this first release of the 'Revisiting Spacetrack Report #3' | 
| 5088 |  |  |  |  |  |  | functionality should be considered alpha code. That is to say, I may | 
| 5089 |  |  |  |  |  |  | need to change the way it behaves, especially in the matter of what is | 
| 5090 |  |  |  |  |  |  | an exception and what is not. | 
| 5091 |  |  |  |  |  |  |  | 
| 5092 |  |  |  |  |  |  | =cut | 
| 5093 |  |  |  |  |  |  |  | 
| 5094 |  |  |  |  |  |  | #	What follows (down to, but not including, the 'end sgp4unit.for' | 
| 5095 |  |  |  |  |  |  | #	comment) is the Fortran code from sgp4unit.for, translated into | 
| 5096 |  |  |  |  |  |  | #	Perl by the custom for2pl script, with conversion specification | 
| 5097 |  |  |  |  |  |  | #	sgp4unit.spec. No hand-edits have been applied. The preferred | 
| 5098 |  |  |  |  |  |  | #	way to modify this code is to enhance for2pl (which is _not_ | 
| 5099 |  |  |  |  |  |  | #	included in the CPAN kit) or to modify sgp4unit.for (ditto), | 
| 5100 |  |  |  |  |  |  | #	since that way further modifications can be easily incorporated | 
| 5101 |  |  |  |  |  |  | #	into this module. | 
| 5102 |  |  |  |  |  |  | # | 
| 5103 |  |  |  |  |  |  | #	Comments in the included file are those from the original | 
| 5104 |  |  |  |  |  |  | #	Fortran unless preceded by '>>>>trw'. The latter are comments | 
| 5105 |  |  |  |  |  |  | #	introduced by the conversion program to remove unwanted Fortran. | 
| 5106 |  |  |  |  |  |  | # | 
| 5107 |  |  |  |  |  |  | #	IMPLEMENTATION NOTES: | 
| 5108 |  |  |  |  |  |  | # | 
| 5109 |  |  |  |  |  |  | #	The original Space Track Report Number 3 code used a custom | 
| 5110 |  |  |  |  |  |  | #	function called FMOD2P to reduce an angle to the range 0 <= | 
| 5111 |  |  |  |  |  |  | #	angle < 2*PI. This is translated to Astro::Coord::ECI::Utils | 
| 5112 |  |  |  |  |  |  | #	function mod2pi. But the Revisiting Spacetrack Report #3 code | 
| 5113 |  |  |  |  |  |  | #	used the Fortran intrinsic function DMOD, which produces | 
| 5114 |  |  |  |  |  |  | #	negative results for a negative divisor. So instead of using | 
| 5115 |  |  |  |  |  |  | #	mod2pi, sgp4r() and related code use the POSIX fmod function, | 
| 5116 |  |  |  |  |  |  | #	which has the same behaviour. | 
| 5117 |  |  |  |  |  |  | # | 
| 5118 |  |  |  |  |  |  | #	Similarly, the original code used a custom function ACTAN to | 
| 5119 |  |  |  |  |  |  | #	produce an arc in the range 0 <= arc < 2*PI from its two | 
| 5120 |  |  |  |  |  |  | #	arguments and the single-argument ATAN intrinsic. The | 
| 5121 |  |  |  |  |  |  | #	translation into Perl ended up with an _actan function at that | 
| 5122 |  |  |  |  |  |  | #	point. But the revised code simply uses atan2. | 
| 5123 |  |  |  |  |  |  | # | 
| 5124 |  |  |  |  |  |  | #	The included file processed from sgp4unit.for begins here. | 
| 5125 |  |  |  |  |  |  |  | 
| 5126 | 16 |  |  | 16 |  | 154 | use constant SGP4R_ERROR_0 => dualvar (0, '');  # guaranteed false | 
|  | 16 |  |  |  |  | 36 |  | 
|  | 16 |  |  |  |  | 1062 |  | 
| 5127 | 16 |  |  |  |  | 1107 | use constant SGP4R_ERROR_MEAN_ECCEN => | 
| 5128 | 16 |  |  | 16 |  | 106 | 'Sgp4r 1: Mean eccentricity < 0 or > 1, or a < .95'; | 
|  | 16 |  |  |  |  | 41 |  | 
| 5129 | 16 |  |  | 16 |  | 121 | use constant SGP4R_ERROR_1 => dualvar (1, SGP4R_ERROR_MEAN_ECCEN); | 
|  | 16 |  |  |  |  | 43 |  | 
|  | 16 |  |  |  |  | 913 |  | 
| 5130 | 16 |  |  |  |  | 1105 | use constant SGP4R_ERROR_MEAN_MOTION => | 
| 5131 | 16 |  |  | 16 |  | 95 | 'Sgp4r 2: Mean motion < 0.0'; | 
|  | 16 |  |  |  |  | 46 |  | 
| 5132 | 16 |  |  | 16 |  | 114 | use constant SGP4R_ERROR_2 => dualvar (2, SGP4R_ERROR_MEAN_MOTION); | 
|  | 16 |  |  |  |  | 35 |  | 
|  | 16 |  |  |  |  | 934 |  | 
| 5133 | 16 |  |  |  |  | 916 | use constant SGP4R_ERROR_INST_ECCEN => | 
| 5134 | 16 |  |  | 16 |  | 101 | 'Sgp4r 3: Instantaneous eccentricity < 0 or > 1'; | 
|  | 16 |  |  |  |  | 31 |  | 
| 5135 | 16 |  |  | 16 |  | 96 | use constant SGP4R_ERROR_3 => dualvar (3, SGP4R_ERROR_INST_ECCEN); | 
|  | 16 |  |  |  |  | 40 |  | 
|  | 16 |  |  |  |  | 913 |  | 
| 5136 | 16 |  |  |  |  | 981 | use constant SGP4R_ERROR_LATUSRECTUM => | 
| 5137 | 16 |  |  | 16 |  | 106 | 'Sgp4r 4: Semi-latus rectum < 0'; | 
|  | 16 |  |  |  |  | 45 |  | 
| 5138 | 16 |  |  | 16 |  | 98 | use constant SGP4R_ERROR_4 => dualvar (4, SGP4R_ERROR_LATUSRECTUM); | 
|  | 16 |  |  |  |  | 43 |  | 
|  | 16 |  |  |  |  | 1013 |  | 
| 5139 | 16 |  |  |  |  | 1043 | use constant SGP4R_ERROR_5 => dualvar (5, | 
| 5140 | 16 |  |  | 16 |  | 108 | 'Sgp4r 5: Epoch elements are sub-orbital'); | 
|  | 16 |  |  |  |  | 59 |  | 
| 5141 | 16 |  |  |  |  | 232402 | use constant SGP4R_ERROR_6 => dualvar (6, | 
| 5142 | 16 |  |  | 16 |  | 115 | 'Sgp4r 6: Satellite has decayed'); | 
|  | 16 |  |  |  |  | 37 |  | 
| 5143 |  |  |  |  |  |  |  | 
| 5144 |  |  |  |  |  |  | #*   ------------------------------------------------------------------- | 
| 5145 |  |  |  |  |  |  | #* | 
| 5146 |  |  |  |  |  |  | #*                               sgp4unit.for | 
| 5147 |  |  |  |  |  |  | #* | 
| 5148 |  |  |  |  |  |  | #*    this file contains the sgp4 procedures for analytical propagation | 
| 5149 |  |  |  |  |  |  | #*    of a satellite. the code was originally released in the 1980 and 1986 | 
| 5150 |  |  |  |  |  |  | #*    spacetrack papers. a detailed discussion of the theory and history | 
| 5151 |  |  |  |  |  |  | #*    may be found in the 2006 aiaa paper by vallado, crawford, hujsak, | 
| 5152 |  |  |  |  |  |  | #*    and kelso. | 
| 5153 |  |  |  |  |  |  | #* | 
| 5154 |  |  |  |  |  |  | #*                            companion code for | 
| 5155 |  |  |  |  |  |  | #*               fundamentals of astrodynamics and applications | 
| 5156 |  |  |  |  |  |  | #*                                    2007 | 
| 5157 |  |  |  |  |  |  | #*                              by david vallado | 
| 5158 |  |  |  |  |  |  | #* | 
| 5159 |  |  |  |  |  |  | #*       (w) 719-573-2600, email dvallado@agi.com | 
| 5160 |  |  |  |  |  |  | #* | 
| 5161 |  |  |  |  |  |  | #*    current : | 
| 5162 |  |  |  |  |  |  | #*               2 apr 07  david vallado | 
| 5163 |  |  |  |  |  |  | #*                           misc fixes for constants | 
| 5164 |  |  |  |  |  |  | #*    changes : | 
| 5165 |  |  |  |  |  |  | #*              14 aug 06  david vallado | 
| 5166 |  |  |  |  |  |  | #*                           chg lyddane choice back to strn3, constants, | 
| 5167 |  |  |  |  |  |  | #*                           separate debug and writes, misc doc | 
| 5168 |  |  |  |  |  |  | #*              26 jul 05  david vallado | 
| 5169 |  |  |  |  |  |  | #*                           fixes for paper | 
| 5170 |  |  |  |  |  |  | #*                           note that each fix is preceded by a | 
| 5171 |  |  |  |  |  |  | #*                           comment with "sgp4fix" and an explanation of | 
| 5172 |  |  |  |  |  |  | #*                           what was changed | 
| 5173 |  |  |  |  |  |  | #*              10 aug 04  david vallado | 
| 5174 |  |  |  |  |  |  | #*                           2nd printing baseline working | 
| 5175 |  |  |  |  |  |  | #*              14 may 01  david vallado | 
| 5176 |  |  |  |  |  |  | #*                           2nd edition baseline | 
| 5177 |  |  |  |  |  |  | #*                     80  norad | 
| 5178 |  |  |  |  |  |  | #*                           original baseline | 
| 5179 |  |  |  |  |  |  | #* | 
| 5180 |  |  |  |  |  |  | #*     ***************************************************************** | 
| 5181 |  |  |  |  |  |  | #*  Files         : | 
| 5182 |  |  |  |  |  |  | #*    Unit 14     - sgp4test.dbg    debug output file | 
| 5183 |  |  |  |  |  |  |  | 
| 5184 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 5185 |  |  |  |  |  |  | #* | 
| 5186 |  |  |  |  |  |  | #*                           SUBROUTINE DPPER | 
| 5187 |  |  |  |  |  |  | #* | 
| 5188 |  |  |  |  |  |  | #*  This Subroutine provides deep space long period periodic contributions | 
| 5189 |  |  |  |  |  |  | #*    to the mean elements.  by design, these periodics are zero at epoch. | 
| 5190 |  |  |  |  |  |  | #*    this used to be dscom which included initialization, but it's really a | 
| 5191 |  |  |  |  |  |  | #*    recurring function. | 
| 5192 |  |  |  |  |  |  | #* | 
| 5193 |  |  |  |  |  |  | #*  author        : david vallado                  719-573-2600   28 jun 2005 | 
| 5194 |  |  |  |  |  |  | #* | 
| 5195 |  |  |  |  |  |  | #*  inputs        : | 
| 5196 |  |  |  |  |  |  | #*    e3          - | 
| 5197 |  |  |  |  |  |  | #*    ee2         - | 
| 5198 |  |  |  |  |  |  | #*    peo         - | 
| 5199 |  |  |  |  |  |  | #*    pgho        - | 
| 5200 |  |  |  |  |  |  | #*    pho         - | 
| 5201 |  |  |  |  |  |  | #*    pinco       - | 
| 5202 |  |  |  |  |  |  | #*    plo         - | 
| 5203 |  |  |  |  |  |  | #*    se2 , se3 , Sgh2, Sgh3, Sgh4, Sh2, Sh3, Si2, Si3, Sl2, Sl3, Sl4 - | 
| 5204 |  |  |  |  |  |  | #*    t           - | 
| 5205 |  |  |  |  |  |  | #*    xh2, xh3, xi2, xi3, xl2, xl3, xl4 - | 
| 5206 |  |  |  |  |  |  | #*    zmol        - | 
| 5207 |  |  |  |  |  |  | #*    zmos        - | 
| 5208 |  |  |  |  |  |  | #*    ep          - eccentricity                           0.0 - 1.0 | 
| 5209 |  |  |  |  |  |  | #*    inclo       - inclination - needed for lyddane modification | 
| 5210 |  |  |  |  |  |  | #*    nodep       - right ascension of ascending node | 
| 5211 |  |  |  |  |  |  | #*    argpp       - argument of perigee | 
| 5212 |  |  |  |  |  |  | #*    mp          - mean anomaly | 
| 5213 |  |  |  |  |  |  | #* | 
| 5214 |  |  |  |  |  |  | #*  outputs       : | 
| 5215 |  |  |  |  |  |  | #*    ep          - eccentricity                           0.0 - 1.0 | 
| 5216 |  |  |  |  |  |  | #*    inclp       - inclination | 
| 5217 |  |  |  |  |  |  | #*    nodep       - right ascension of ascending node | 
| 5218 |  |  |  |  |  |  | #*    argpp       - argument of perigee | 
| 5219 |  |  |  |  |  |  | #*    mp          - mean anomaly | 
| 5220 |  |  |  |  |  |  | #* | 
| 5221 |  |  |  |  |  |  | #*  locals        : | 
| 5222 |  |  |  |  |  |  | #*    alfdp       - | 
| 5223 |  |  |  |  |  |  | #*    betdp       - | 
| 5224 |  |  |  |  |  |  | #*    cosip  , sinip  , cosop  , sinop  , | 
| 5225 |  |  |  |  |  |  | #*    dalf        - | 
| 5226 |  |  |  |  |  |  | #*    dbet        - | 
| 5227 |  |  |  |  |  |  | #*    dls         - | 
| 5228 |  |  |  |  |  |  | #*    f2, f3      - | 
| 5229 |  |  |  |  |  |  | #*    pe          - | 
| 5230 |  |  |  |  |  |  | #*    pgh         - | 
| 5231 |  |  |  |  |  |  | #*    ph          - | 
| 5232 |  |  |  |  |  |  | #*    pinc        - | 
| 5233 |  |  |  |  |  |  | #*    pl          - | 
| 5234 |  |  |  |  |  |  | #*    sel   , ses   , sghl  , sghs  , shl   , shs   , sil   , sinzf , sis   , | 
| 5235 |  |  |  |  |  |  | #*    sll   , sls | 
| 5236 |  |  |  |  |  |  | #*    xls         - | 
| 5237 |  |  |  |  |  |  | #*    xnoh        - | 
| 5238 |  |  |  |  |  |  | #*    zf          - | 
| 5239 |  |  |  |  |  |  | #*    zm          - | 
| 5240 |  |  |  |  |  |  | #* | 
| 5241 |  |  |  |  |  |  | #*  coupling      : | 
| 5242 |  |  |  |  |  |  | #*    none. | 
| 5243 |  |  |  |  |  |  | #* | 
| 5244 |  |  |  |  |  |  | #*  references    : | 
| 5245 |  |  |  |  |  |  | #*    hoots, roehrich, norad spacetrack report #3 1980 | 
| 5246 |  |  |  |  |  |  | #*    hoots, norad spacetrack report #6 1986 | 
| 5247 |  |  |  |  |  |  | #*    hoots, schumacher and glover 2004 | 
| 5248 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 5249 |  |  |  |  |  |  | #*------------------------------------------------------------------------------ | 
| 5250 |  |  |  |  |  |  |  | 
| 5251 |  |  |  |  |  |  | sub _r_dpper { | 
| 5252 | 418 |  |  | 418 |  | 966 | my ($self, $t, $eccp, $inclp, $nodep, $argpp, $mp) = @_; | 
| 5253 |  |  |  |  |  |  | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} | 
| 5254 | 418 | 50 |  |  |  | 1310 | or confess "Programming error - Sgp4r not initialized"; | 
| 5255 |  |  |  |  |  |  |  | 
| 5256 |  |  |  |  |  |  | #* -------------------------- Local Variables -------------------------- | 
| 5257 | 418 |  |  |  |  | 1105 | my ($alfdp, $betdp, $cosip, $cosop, $dalf, $dbet, $dls, $f2, $f3, | 
| 5258 |  |  |  |  |  |  | $pe, $pgh, $ph, $pinc, $pl, $sel, $ses, $sghl, $sghs, $shl, | 
| 5259 |  |  |  |  |  |  | $shs, $sil, $sinip, $sinop, $sinzf, $sis, $sll, $sls, $xls, | 
| 5260 |  |  |  |  |  |  | $xnoh, $zf, $zm); | 
| 5261 | 418 |  |  |  |  | 0 | my ($zel, $zes, $znl, $zns); | 
| 5262 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'ASTMATH.CMN' | 
| 5263 |  |  |  |  |  |  |  | 
| 5264 |  |  |  |  |  |  | #* ----------------------------- Constants ----------------------------- | 
| 5265 | 418 |  |  |  |  | 564 | $zes= 0.01675; | 
| 5266 | 418 |  |  |  |  | 551 | $zel= 0.0549; | 
| 5267 | 418 |  |  |  |  | 535 | $zns= 1.19459e-05; | 
| 5268 |  |  |  |  |  |  |  | 
| 5269 | 418 |  |  |  |  | 637 | $znl= 0.00015835218; | 
| 5270 |  |  |  |  |  |  | #* ------------------- CALCULATE TIME VARYING PERIODICS ---------------- | 
| 5271 |  |  |  |  |  |  |  | 
| 5272 | 418 |  |  |  |  | 663 | $zm= $parm->{zmos}+ $zns*$t; | 
| 5273 | 418 | 100 |  |  |  | 866 | if ($parm->{init}) { | 
| 5274 |  |  |  |  |  |  | $zm= $parm->{zmos} | 
| 5275 | 23 |  |  |  |  | 51 | } | 
| 5276 | 418 |  |  |  |  | 774 | $zf= $zm+ 2*$zes*sin($zm); | 
| 5277 | 418 |  |  |  |  | 681 | $sinzf= sin($zf); | 
| 5278 | 418 |  |  |  |  | 679 | $f2=  0.5*$sinzf*$sinzf- 0.25; | 
| 5279 | 418 |  |  |  |  | 695 | $f3= -0.5*$sinzf*cos($zf); | 
| 5280 | 418 |  |  |  |  | 823 | $ses= $parm->{se2}*$f2+ $parm->{se3}*$f3; | 
| 5281 | 418 |  |  |  |  | 674 | $sis= $parm->{si2}*$f2+ $parm->{si3}*$f3; | 
| 5282 | 418 |  |  |  |  | 743 | $sls= $parm->{sl2}*$f2+ $parm->{sl3}*$f3+ $parm->{sl4}*$sinzf; | 
| 5283 | 418 |  |  |  |  | 706 | $sghs= $parm->{sgh2}*$f2+ $parm->{sgh3}*$f3+ $parm->{sgh4}*$sinzf; | 
| 5284 | 418 |  |  |  |  | 660 | $shs= $parm->{sh2}*$f2+ $parm->{sh3}*$f3; | 
| 5285 |  |  |  |  |  |  |  | 
| 5286 | 418 |  |  |  |  | 594 | $zm= $parm->{zmol}+ $znl*$t; | 
| 5287 | 418 | 100 |  |  |  | 763 | if ($parm->{init}) { | 
| 5288 |  |  |  |  |  |  | $zm= $parm->{zmol} | 
| 5289 | 23 |  |  |  |  | 45 | } | 
| 5290 | 418 |  |  |  |  | 672 | $zf= $zm+ 2*$zel*sin($zm); | 
| 5291 | 418 |  |  |  |  | 682 | $sinzf= sin($zf); | 
| 5292 | 418 |  |  |  |  | 642 | $f2=  0.5*$sinzf*$sinzf- 0.25; | 
| 5293 | 418 |  |  |  |  | 685 | $f3= -0.5*$sinzf*cos($zf); | 
| 5294 | 418 |  |  |  |  | 714 | $sel= $parm->{ee2}*$f2+ $parm->{e3}*$f3; | 
| 5295 | 418 |  |  |  |  | 715 | $sil= $parm->{xi2}*$f2+ $parm->{xi3}*$f3; | 
| 5296 | 418 |  |  |  |  | 758 | $sll= $parm->{xl2}*$f2+ $parm->{xl3}*$f3+ $parm->{xl4}*$sinzf; | 
| 5297 | 418 |  |  |  |  | 741 | $sghl= $parm->{xgh2}*$f2+ $parm->{xgh3}*$f3+ $parm->{xgh4}*$sinzf; | 
| 5298 | 418 |  |  |  |  | 628 | $shl= $parm->{xh2}*$f2+ $parm->{xh3}*$f3; | 
| 5299 | 418 |  |  |  |  | 634 | $pe= $ses+ $sel; | 
| 5300 | 418 |  |  |  |  | 512 | $pinc= $sis+ $sil; | 
| 5301 | 418 |  |  |  |  | 620 | $pl= $sls+ $sll; | 
| 5302 | 418 |  |  |  |  | 784 | $pgh= $sghs+ $sghl; | 
| 5303 |  |  |  |  |  |  |  | 
| 5304 | 418 |  |  |  |  | 540 | $ph= $shs+ $shl; | 
| 5305 | 418 | 100 |  |  |  | 859 | if ( !  $parm->{init}) { | 
| 5306 | 395 |  |  |  |  | 614 | $pe= $pe- $parm->{peo}; | 
| 5307 | 395 |  |  |  |  | 542 | $pinc= $pinc- $parm->{pinco}; | 
| 5308 | 395 |  |  |  |  | 543 | $pl= $pl- $parm->{plo}; | 
| 5309 | 395 |  |  |  |  | 547 | $pgh= $pgh- $parm->{pgho}; | 
| 5310 | 395 |  |  |  |  | 552 | $ph= $ph- $parm->{pho}; | 
| 5311 | 395 |  |  |  |  | 584 | $$inclp= $$inclp+ $pinc; | 
| 5312 | 395 |  |  |  |  | 595 | $$eccp= $$eccp+ $pe; | 
| 5313 | 395 |  |  |  |  | 537 | $sinip= sin($$inclp); | 
| 5314 |  |  |  |  |  |  |  | 
| 5315 | 395 |  |  |  |  | 586 | $cosip= cos($$inclp); | 
| 5316 |  |  |  |  |  |  | #* ------------------------- APPLY PERIODICS DIRECTLY ------------------ | 
| 5317 |  |  |  |  |  |  | #c    sgp4fix for lyddane choice | 
| 5318 |  |  |  |  |  |  | #c    strn3 used original inclination - this is technically feasible | 
| 5319 |  |  |  |  |  |  | #c    gsfc used perturbed inclination - also technically feasible | 
| 5320 |  |  |  |  |  |  | #c    probably best to readjust the 0.2 limit value and limit discontinuity | 
| 5321 |  |  |  |  |  |  | #c    0.2 rad = 11.45916 deg | 
| 5322 |  |  |  |  |  |  | #c    use next line for original strn3 approach and original inclination | 
| 5323 |  |  |  |  |  |  | #c            IF (inclo.ge.0.2D0) THEN | 
| 5324 |  |  |  |  |  |  | #c    use next line for gsfc version and perturbed inclination | 
| 5325 |  |  |  |  |  |  |  | 
| 5326 | 395 | 100 |  |  |  | 764 | if ($$inclp >= 0.2) { | 
| 5327 | 232 |  |  |  |  | 395 | $ph= $ph/$sinip; | 
| 5328 | 232 |  |  |  |  | 354 | $pgh= $pgh- $cosip*$ph; | 
| 5329 | 232 |  |  |  |  | 336 | $$argpp= $$argpp+ $pgh; | 
| 5330 | 232 |  |  |  |  | 385 | $$nodep= $$nodep+ $ph; | 
| 5331 | 232 |  |  |  |  | 365 | $$mp= $$mp+ $pl; | 
| 5332 |  |  |  |  |  |  |  | 
| 5333 |  |  |  |  |  |  | } else { | 
| 5334 |  |  |  |  |  |  | #* ----------------- APPLY PERIODICS WITH LYDDANE MODIFICATION --------- | 
| 5335 | 163 |  |  |  |  | 237 | $sinop= sin($$nodep); | 
| 5336 | 163 |  |  |  |  | 255 | $cosop= cos($$nodep); | 
| 5337 | 163 |  |  |  |  | 222 | $alfdp= $sinip*$sinop; | 
| 5338 | 163 |  |  |  |  | 238 | $betdp= $sinip*$cosop; | 
| 5339 | 163 |  |  |  |  | 254 | $dalf=  $ph*$cosop+ $pinc*$cosip*$sinop; | 
| 5340 | 163 |  |  |  |  | 272 | $dbet= -$ph*$sinop+ $pinc*$cosip*$cosop; | 
| 5341 | 163 |  |  |  |  | 198 | $alfdp= $alfdp+ $dalf; | 
| 5342 | 163 |  |  |  |  | 218 | $betdp= $betdp+ $dbet; | 
| 5343 | 163 |  |  |  |  | 392 | $$nodep= fmod($$nodep, &SGP_TWOPI); | 
| 5344 | 163 |  |  |  |  | 271 | $xls= $$mp+ $$argpp+ $cosip*$$nodep; | 
| 5345 | 163 |  |  |  |  | 267 | $dls= $pl+ $pgh- $pinc*$$nodep*$sinip; | 
| 5346 | 163 |  |  |  |  | 217 | $xls= $xls+ $dls; | 
| 5347 | 163 |  |  |  |  | 268 | $xnoh= $$nodep; | 
| 5348 | 163 |  |  |  |  | 382 | $$nodep= atan2($alfdp, $betdp); | 
| 5349 | 163 | 100 |  |  |  | 474 | if (abs($xnoh-$$nodep)  >  &SGP_PI) { | 
| 5350 | 57 | 50 |  |  |  | 135 | if ($$nodep <  $xnoh) { | 
| 5351 | 57 |  |  |  |  | 128 | $$nodep= $$nodep+&SGP_TWOPI; | 
| 5352 |  |  |  |  |  |  | } else { | 
| 5353 | 0 |  |  |  |  | 0 | $$nodep= $$nodep-&SGP_TWOPI; | 
| 5354 |  |  |  |  |  |  | } | 
| 5355 |  |  |  |  |  |  | } | 
| 5356 | 163 |  |  |  |  | 269 | $$mp= $$mp+ $pl; | 
| 5357 | 163 |  |  |  |  | 283 | $$argpp=  $xls- $$mp- $cosip*$$nodep; | 
| 5358 |  |  |  |  |  |  | } | 
| 5359 |  |  |  |  |  |  |  | 
| 5360 |  |  |  |  |  |  | } | 
| 5361 |  |  |  |  |  |  | #c        INCLUDE 'debug1.for' | 
| 5362 |  |  |  |  |  |  |  | 
| 5363 | 418 |  |  |  |  | 843 | return; | 
| 5364 |  |  |  |  |  |  | } | 
| 5365 |  |  |  |  |  |  |  | 
| 5366 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 5367 |  |  |  |  |  |  | #* | 
| 5368 |  |  |  |  |  |  | #*                           SUBROUTINE DSCOM | 
| 5369 |  |  |  |  |  |  | #* | 
| 5370 |  |  |  |  |  |  | #*  This Subroutine provides deep space common items used by both the secular | 
| 5371 |  |  |  |  |  |  | #*    and periodics subroutines.  input is provided as shown. this routine | 
| 5372 |  |  |  |  |  |  | #*    used to be called dpper, but the functions inside weren't well organized. | 
| 5373 |  |  |  |  |  |  | #* | 
| 5374 |  |  |  |  |  |  | #*  author        : david vallado                  719-573-2600   28 jun 2005 | 
| 5375 |  |  |  |  |  |  | #* | 
| 5376 |  |  |  |  |  |  | #*  inputs        : | 
| 5377 |  |  |  |  |  |  | #*    epoch       - | 
| 5378 |  |  |  |  |  |  | #*    ep          - eccentricity | 
| 5379 |  |  |  |  |  |  | #*    argpp       - argument of perigee | 
| 5380 |  |  |  |  |  |  | #*    tc          - | 
| 5381 |  |  |  |  |  |  | #*    inclp       - inclination | 
| 5382 |  |  |  |  |  |  | #*    nodep      - right ascension of ascending node | 
| 5383 |  |  |  |  |  |  | #*    np          - mean motion | 
| 5384 |  |  |  |  |  |  | #* | 
| 5385 |  |  |  |  |  |  | #*  outputs       : | 
| 5386 |  |  |  |  |  |  | #*    sinim  , cosim  , sinomm , cosomm , snodm  , cnodm | 
| 5387 |  |  |  |  |  |  | #*    day         - | 
| 5388 |  |  |  |  |  |  | #*    e3          - | 
| 5389 |  |  |  |  |  |  | #*    ee2         - | 
| 5390 |  |  |  |  |  |  | #*    em          - eccentricity | 
| 5391 |  |  |  |  |  |  | #*    emsq        - eccentricity squared | 
| 5392 |  |  |  |  |  |  | #*    gam         - | 
| 5393 |  |  |  |  |  |  | #*    peo         - | 
| 5394 |  |  |  |  |  |  | #*    pgho        - | 
| 5395 |  |  |  |  |  |  | #*    pho         - | 
| 5396 |  |  |  |  |  |  | #*    pinco       - | 
| 5397 |  |  |  |  |  |  | #*    plo         - | 
| 5398 |  |  |  |  |  |  | #*    rtemsq      - | 
| 5399 |  |  |  |  |  |  | #*    se2, se3         - | 
| 5400 |  |  |  |  |  |  | #*    sgh2, sgh3, sgh4        - | 
| 5401 |  |  |  |  |  |  | #*    sh2, sh3, si2, si3, sl2, sl3, sl4         - | 
| 5402 |  |  |  |  |  |  | #*    s1, s2, s3, s4, s5, s6, s7          - | 
| 5403 |  |  |  |  |  |  | #*    ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3         - | 
| 5404 |  |  |  |  |  |  | #*    sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33        - | 
| 5405 |  |  |  |  |  |  | #*    xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4         - | 
| 5406 |  |  |  |  |  |  | #*    nm          - mean motion | 
| 5407 |  |  |  |  |  |  | #*    z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33         - | 
| 5408 |  |  |  |  |  |  | #*    zmol        - | 
| 5409 |  |  |  |  |  |  | #*    zmos        - | 
| 5410 |  |  |  |  |  |  | #* | 
| 5411 |  |  |  |  |  |  | #*  locals        : | 
| 5412 |  |  |  |  |  |  | #*    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10         - | 
| 5413 |  |  |  |  |  |  | #*    betasq      - | 
| 5414 |  |  |  |  |  |  | #*    cc          - | 
| 5415 |  |  |  |  |  |  | #*    ctem, stem        - | 
| 5416 |  |  |  |  |  |  | #*    x1, x2, x3, x4, x5, x6, x7, x8          - | 
| 5417 |  |  |  |  |  |  | #*    xnodce      - | 
| 5418 |  |  |  |  |  |  | #*    xnoi        - | 
| 5419 |  |  |  |  |  |  | #*    zcosg  , zsing  , zcosgl , zsingl , zcosh  , zsinh  , zcoshl , zsinhl , | 
| 5420 |  |  |  |  |  |  | #*    zcosi  , zsini  , zcosil , zsinil , | 
| 5421 |  |  |  |  |  |  | #*    zx          - | 
| 5422 |  |  |  |  |  |  | #*    zy          - | 
| 5423 |  |  |  |  |  |  | #* | 
| 5424 |  |  |  |  |  |  | #*  coupling      : | 
| 5425 |  |  |  |  |  |  | #*    none. | 
| 5426 |  |  |  |  |  |  | #* | 
| 5427 |  |  |  |  |  |  | #*  references    : | 
| 5428 |  |  |  |  |  |  | #*    hoots, roehrich, norad spacetrack report #3 1980 | 
| 5429 |  |  |  |  |  |  | #*    hoots, norad spacetrack report #6 1986 | 
| 5430 |  |  |  |  |  |  | #*    hoots, schumacher and glover 2004 | 
| 5431 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 5432 |  |  |  |  |  |  | #*------------------------------------------------------------------------------ | 
| 5433 |  |  |  |  |  |  |  | 
| 5434 |  |  |  |  |  |  | sub _r_dscom { | 
| 5435 | 23 |  |  | 23 |  | 69 | my ($self, $tc) = @_; | 
| 5436 |  |  |  |  |  |  | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} | 
| 5437 | 23 | 50 |  |  |  | 116 | or confess "Programming error - Sgp4r not initialized"; | 
| 5438 |  |  |  |  |  |  | my $init = $parm->{init} | 
| 5439 | 23 | 50 |  |  |  | 69 | or confess "Programming error - Sgp4r initialization not in progress"; | 
| 5440 |  |  |  |  |  |  |  | 
| 5441 |  |  |  |  |  |  | #* -------------------------- Local Variables -------------------------- | 
| 5442 | 23 |  |  |  |  | 163 | my ($c1ss, $c1l, $zcosis, $zsinis, $zsings, $zcosgs, $zes, $zel); | 
| 5443 |  |  |  |  |  |  |  | 
| 5444 | 23 |  |  |  |  | 0 | my ($a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9, $a10, $betasq, $cc, | 
| 5445 |  |  |  |  |  |  | $ctem, $stem, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $xnodce, | 
| 5446 |  |  |  |  |  |  | $xnoi, $zcosg, $zcosgl, $zcosh, $zcoshl, $zcosi, $zcosil, | 
| 5447 |  |  |  |  |  |  | $zsing, $zsingl, $zsinh, $zsinhl, $zsini, $zsinil, $zx, $zy); | 
| 5448 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'ASTMATH.CMN' | 
| 5449 |  |  |  |  |  |  |  | 
| 5450 |  |  |  |  |  |  | #* ------------------------------ Constants ---------------------------- | 
| 5451 | 23 |  |  |  |  | 44 | $zes=  0.01675; | 
| 5452 | 23 |  |  |  |  | 39 | $zel=  0.0549; | 
| 5453 | 23 |  |  |  |  | 40 | $c1ss=  2.9864797e-06; | 
| 5454 | 23 |  |  |  |  | 44 | $c1l=  4.7968065e-07; | 
| 5455 | 23 |  |  |  |  | 38 | $zsinis=  0.39785416; | 
| 5456 | 23 |  |  |  |  | 38 | $zcosis=  0.91744867; | 
| 5457 | 23 |  |  |  |  | 37 | $zcosgs=  0.1945905; | 
| 5458 |  |  |  |  |  |  |  | 
| 5459 | 23 |  |  |  |  | 50 | $zsings= -0.98088458; | 
| 5460 |  |  |  |  |  |  | #* ----------------- DEEP SPACE PERIODICS INITIALIZATION --------------- | 
| 5461 | 23 |  |  |  |  | 77 | $init->{xn}= $parm->{meanmotion}; | 
| 5462 | 23 |  |  |  |  | 71 | $init->{eccm}= $parm->{eccentricity}; | 
| 5463 | 23 |  |  |  |  | 101 | $init->{snodm}= sin($parm->{ascendingnode}); | 
| 5464 | 23 |  |  |  |  | 66 | $init->{cnodm}= cos($parm->{ascendingnode}); | 
| 5465 | 23 |  |  |  |  | 61 | $init->{sinomm}= sin($parm->{argumentofperigee}); | 
| 5466 | 23 |  |  |  |  | 58 | $init->{cosomm}= cos($parm->{argumentofperigee}); | 
| 5467 | 23 |  |  |  |  | 60 | $init->{sinim}= sin($parm->{inclination}); | 
| 5468 | 23 |  |  |  |  | 53 | $init->{cosim}= cos($parm->{inclination}); | 
| 5469 | 23 |  |  |  |  | 60 | $init->{emsq}= $init->{eccm}*$init->{eccm}; | 
| 5470 | 23 |  |  |  |  | 53 | $betasq= 1-$init->{emsq}; | 
| 5471 |  |  |  |  |  |  |  | 
| 5472 | 23 |  |  |  |  | 44 | $init->{rtemsq}= sqrt($betasq); | 
| 5473 |  |  |  |  |  |  | #* --------------------- INITIALIZE LUNAR SOLAR TERMS ------------------ | 
| 5474 | 23 |  |  |  |  | 65 | $parm->{peo}= 0; | 
| 5475 | 23 |  |  |  |  | 42 | $parm->{pinco}= 0; | 
| 5476 | 23 |  |  |  |  | 45 | $parm->{plo}= 0; | 
| 5477 | 23 |  |  |  |  | 59 | $parm->{pgho}= 0; | 
| 5478 | 23 |  |  |  |  | 48 | $parm->{pho}= 0; | 
| 5479 | 23 |  |  |  |  | 80 | $init->{day}= $self->{ds50}+ 18261.5 + $tc/1440; | 
| 5480 | 23 |  |  |  |  | 111 | $xnodce= fmod(4.523602 - 0.00092422029*$init->{day}, &SGP_TWOPI); | 
| 5481 | 23 |  |  |  |  | 57 | $stem= sin($xnodce); | 
| 5482 | 23 |  |  |  |  | 47 | $ctem= cos($xnodce); | 
| 5483 | 23 |  |  |  |  | 47 | $zcosil= 0.91375164 - 0.03568096*$ctem; | 
| 5484 | 23 |  |  |  |  | 47 | $zsinil= sqrt(1 - $zcosil*$zcosil); | 
| 5485 | 23 |  |  |  |  | 61 | $zsinhl= 0.089683511*$stem/ $zsinil; | 
| 5486 | 23 |  |  |  |  | 55 | $zcoshl= sqrt(1 - $zsinhl*$zsinhl); | 
| 5487 | 23 |  |  |  |  | 80 | $init->{gam}= 5.8351514 + 0.001944368*$init->{day}; | 
| 5488 | 23 |  |  |  |  | 77 | $zx= 0.39785416*$stem/$zsinil; | 
| 5489 | 23 |  |  |  |  | 59 | $zy= $zcoshl*$ctem+ 0.91744867*$zsinhl*$stem; | 
| 5490 | 23 |  |  |  |  | 61 | $zx= atan2($zx, $zy); | 
| 5491 | 23 |  |  |  |  | 47 | $zx= $init->{gam}+ $zx- $xnodce; | 
| 5492 | 23 |  |  |  |  | 40 | $zcosgl= cos($zx); | 
| 5493 |  |  |  |  |  |  |  | 
| 5494 | 23 |  |  |  |  | 38 | $zsingl= sin($zx); | 
| 5495 |  |  |  |  |  |  | #* ---------------------------- DO SOLAR TERMS ------------------------- | 
| 5496 | 23 |  |  |  |  | 45 | $zcosg= $zcosgs; | 
| 5497 | 23 |  |  |  |  | 42 | $zsing= $zsings; | 
| 5498 | 23 |  |  |  |  | 41 | $zcosi= $zcosis; | 
| 5499 | 23 |  |  |  |  | 37 | $zsini= $zsinis; | 
| 5500 | 23 |  |  |  |  | 43 | $zcosh= $init->{cnodm}; | 
| 5501 | 23 |  |  |  |  | 43 | $zsinh= $init->{snodm}; | 
| 5502 | 23 |  |  |  |  | 44 | $cc= $c1ss; | 
| 5503 |  |  |  |  |  |  |  | 
| 5504 | 23 |  |  |  |  | 51 | $xnoi= 1 / $init->{xn}; | 
| 5505 | 23 |  |  |  |  | 73 | foreach my $lsflg (1 .. 2) { | 
| 5506 | 46 |  |  |  |  | 99 | $a1=   $zcosg*$zcosh+ $zsing*$zcosi*$zsinh; | 
| 5507 | 46 |  |  |  |  | 106 | $a3=  -$zsing*$zcosh+ $zcosg*$zcosi*$zsinh; | 
| 5508 | 46 |  |  |  |  | 92 | $a7=  -$zcosg*$zsinh+ $zsing*$zcosi*$zcosh; | 
| 5509 | 46 |  |  |  |  | 64 | $a8=   $zsing*$zsini; | 
| 5510 | 46 |  |  |  |  | 74 | $a9=   $zsing*$zsinh+ $zcosg*$zcosi*$zcosh; | 
| 5511 | 46 |  |  |  |  | 73 | $a10=   $zcosg*$zsini; | 
| 5512 | 46 |  |  |  |  | 89 | $a2=   $init->{cosim}*$a7+ $init->{sinim}*$a8; | 
| 5513 | 46 |  |  |  |  | 98 | $a4=   $init->{cosim}*$a9+ $init->{sinim}*$a10; | 
| 5514 | 46 |  |  |  |  | 122 | $a5=  -$init->{sinim}*$a7+ $init->{cosim}*$a8; | 
| 5515 |  |  |  |  |  |  |  | 
| 5516 | 46 |  |  |  |  | 111 | $a6=  -$init->{sinim}*$a9+ $init->{cosim}*$a10; | 
| 5517 | 46 |  |  |  |  | 84 | $x1=  $a1*$init->{cosomm}+ $a2*$init->{sinomm}; | 
| 5518 | 46 |  |  |  |  | 93 | $x2=  $a3*$init->{cosomm}+ $a4*$init->{sinomm}; | 
| 5519 | 46 |  |  |  |  | 97 | $x3= -$a1*$init->{sinomm}+ $a2*$init->{cosomm}; | 
| 5520 | 46 |  |  |  |  | 86 | $x4= -$a3*$init->{sinomm}+ $a4*$init->{cosomm}; | 
| 5521 | 46 |  |  |  |  | 66 | $x5=  $a5*$init->{sinomm}; | 
| 5522 | 46 |  |  |  |  | 68 | $x6=  $a6*$init->{sinomm}; | 
| 5523 | 46 |  |  |  |  | 82 | $x7=  $a5*$init->{cosomm}; | 
| 5524 |  |  |  |  |  |  |  | 
| 5525 | 46 |  |  |  |  | 69 | $x8=  $a6*$init->{cosomm}; | 
| 5526 | 46 |  |  |  |  | 95 | $init->{z31}= 12*$x1*$x1- 3*$x3*$x3; | 
| 5527 | 46 |  |  |  |  | 106 | $init->{z32}= 24*$x1*$x2- 6*$x3*$x4; | 
| 5528 | 46 |  |  |  |  | 99 | $init->{z33}= 12*$x2*$x2- 3*$x4*$x4; | 
| 5529 |  |  |  |  |  |  | $init->{z1}=  3* ($a1*$a1+ $a2*$a2) + | 
| 5530 | 46 |  |  |  |  | 133 | $init->{z31}*$init->{emsq}; | 
| 5531 |  |  |  |  |  |  | $init->{z2}=  6* ($a1*$a3+ $a2*$a4) + | 
| 5532 | 46 |  |  |  |  | 138 | $init->{z32}*$init->{emsq}; | 
| 5533 |  |  |  |  |  |  | $init->{z3}=  3* ($a3*$a3+ $a4*$a4) + | 
| 5534 | 46 |  |  |  |  | 115 | $init->{z33}*$init->{emsq}; | 
| 5535 |  |  |  |  |  |  | $init->{z11}= -6*$a1*$a5+ $init->{emsq}* | 
| 5536 | 46 |  |  |  |  | 196 | (-24*$x1*$x7-6*$x3*$x5); | 
| 5537 |  |  |  |  |  |  | $init->{z12}= -6* ($a1*$a6+ $a3*$a5) + $init->{emsq}* ( | 
| 5538 | 46 |  |  |  |  | 157 | -24*($x2*$x7+$x1*$x8) - 6*($x3*$x6+$x4*$x5) ); | 
| 5539 | 46 |  |  |  |  | 140 | $init->{z13}= -6*$a3*$a6+ $init->{emsq}*(-24*$x2*$x8- | 
| 5540 |  |  |  |  |  |  | 6*$x4*$x6); | 
| 5541 | 46 |  |  |  |  | 121 | $init->{z21}=  6*$a2*$a5+ $init->{emsq}*(24*$x1*$x5-6*$x3*$x7); | 
| 5542 |  |  |  |  |  |  | $init->{z22}=  6* ($a4*$a5+ $a2*$a6) + $init->{emsq}* ( | 
| 5543 | 46 |  |  |  |  | 168 | 24*($x2*$x5+$x1*$x6) - 6*($x4*$x7+$x3*$x8) ); | 
| 5544 | 46 |  |  |  |  | 136 | $init->{z23}=  6*$a4*$a6+ $init->{emsq}*(24*$x2*$x6- 6*$x4*$x8); | 
| 5545 | 46 |  |  |  |  | 93 | $init->{z1}= $init->{z1}+ $init->{z1}+ $betasq*$init->{z31}; | 
| 5546 | 46 |  |  |  |  | 108 | $init->{z2}= $init->{z2}+ $init->{z2}+ $betasq*$init->{z32}; | 
| 5547 | 46 |  |  |  |  | 113 | $init->{z3}= $init->{z3}+ $init->{z3}+ $betasq*$init->{z33}; | 
| 5548 | 46 |  |  |  |  | 100 | $init->{s3}= $cc*$xnoi; | 
| 5549 | 46 |  |  |  |  | 139 | $init->{s2}= -0.5*$init->{s3}/ $init->{rtemsq}; | 
| 5550 | 46 |  |  |  |  | 95 | $init->{s4}= $init->{s3}*$init->{rtemsq}; | 
| 5551 | 46 |  |  |  |  | 100 | $init->{s1}= -15*$init->{eccm}*$init->{s4}; | 
| 5552 | 46 |  |  |  |  | 84 | $init->{s5}= $x1*$x3+ $x2*$x4; | 
| 5553 | 46 |  |  |  |  | 93 | $init->{s6}= $x2*$x3+ $x1*$x4; | 
| 5554 |  |  |  |  |  |  |  | 
| 5555 | 46 |  |  |  |  | 98 | $init->{s7}= $x2*$x4- $x1*$x3; | 
| 5556 |  |  |  |  |  |  | #* ------------------------------ DO LUNAR TERMS ----------------------- | 
| 5557 | 46 | 100 |  |  |  | 140 | if ($lsflg == 1) { | 
| 5558 | 23 |  |  |  |  | 54 | $init->{ss1}= $init->{s1}; | 
| 5559 | 23 |  |  |  |  | 62 | $init->{ss2}= $init->{s2}; | 
| 5560 | 23 |  |  |  |  | 55 | $init->{ss3}= $init->{s3}; | 
| 5561 | 23 |  |  |  |  | 58 | $init->{ss4}= $init->{s4}; | 
| 5562 | 23 |  |  |  |  | 40 | $init->{ss5}= $init->{s5}; | 
| 5563 | 23 |  |  |  |  | 58 | $init->{ss6}= $init->{s6}; | 
| 5564 | 23 |  |  |  |  | 51 | $init->{ss7}= $init->{s7}; | 
| 5565 | 23 |  |  |  |  | 55 | $init->{sz1}= $init->{z1}; | 
| 5566 | 23 |  |  |  |  | 58 | $init->{sz2}= $init->{z2}; | 
| 5567 | 23 |  |  |  |  | 71 | $init->{sz3}= $init->{z3}; | 
| 5568 | 23 |  |  |  |  | 51 | $init->{sz11}= $init->{z11}; | 
| 5569 | 23 |  |  |  |  | 50 | $init->{sz12}= $init->{z12}; | 
| 5570 | 23 |  |  |  |  | 54 | $init->{sz13}= $init->{z13}; | 
| 5571 | 23 |  |  |  |  | 61 | $init->{sz21}= $init->{z21}; | 
| 5572 | 23 |  |  |  |  | 62 | $init->{sz22}= $init->{z22}; | 
| 5573 | 23 |  |  |  |  | 49 | $init->{sz23}= $init->{z23}; | 
| 5574 | 23 |  |  |  |  | 51 | $init->{sz31}= $init->{z31}; | 
| 5575 | 23 |  |  |  |  | 47 | $init->{sz32}= $init->{z32}; | 
| 5576 | 23 |  |  |  |  | 57 | $init->{sz33}= $init->{z33}; | 
| 5577 | 23 |  |  |  |  | 44 | $zcosg= $zcosgl; | 
| 5578 | 23 |  |  |  |  | 43 | $zsing= $zsingl; | 
| 5579 | 23 |  |  |  |  | 45 | $zcosi= $zcosil; | 
| 5580 | 23 |  |  |  |  | 39 | $zsini= $zsinil; | 
| 5581 | 23 |  |  |  |  | 48 | $zcosh= $zcoshl*$init->{cnodm}+$zsinhl*$init->{snodm}; | 
| 5582 | 23 |  |  |  |  | 46 | $zsinh= $init->{snodm}*$zcoshl-$init->{cnodm}*$zsinhl; | 
| 5583 | 23 |  |  |  |  | 46 | $cc= $c1l; | 
| 5584 |  |  |  |  |  |  | } | 
| 5585 |  |  |  |  |  |  |  | 
| 5586 |  |  |  |  |  |  | } | 
| 5587 |  |  |  |  |  |  | $parm->{zmol}= fmod(4.7199672 + 0.2299715*$init->{day}-$init->{gam}, | 
| 5588 | 23 |  |  |  |  | 139 | &SGP_TWOPI); | 
| 5589 |  |  |  |  |  |  |  | 
| 5590 |  |  |  |  |  |  | $parm->{zmos}= fmod(6.2565837 + 0.017201977*$init->{day}, | 
| 5591 | 23 |  |  |  |  | 115 | &SGP_TWOPI); | 
| 5592 |  |  |  |  |  |  | #* ---------------------------- DO SOLAR TERMS ------------------------- | 
| 5593 | 23 |  |  |  |  | 79 | $parm->{se2}=   2*$init->{ss1}*$init->{ss6}; | 
| 5594 | 23 |  |  |  |  | 78 | $parm->{se3}=   2*$init->{ss1}*$init->{ss7}; | 
| 5595 | 23 |  |  |  |  | 64 | $parm->{si2}=   2*$init->{ss2}*$init->{sz12}; | 
| 5596 | 23 |  |  |  |  | 73 | $parm->{si3}=   2*$init->{ss2}*($init->{sz13}-$init->{sz11}); | 
| 5597 | 23 |  |  |  |  | 68 | $parm->{sl2}=  -2*$init->{ss3}*$init->{sz2}; | 
| 5598 | 23 |  |  |  |  | 68 | $parm->{sl3}=  -2*$init->{ss3}*($init->{sz3}-$init->{sz1}); | 
| 5599 | 23 |  |  |  |  | 93 | $parm->{sl4}=  -2*$init->{ss3}*(-21-9*$init->{emsq})*$zes; | 
| 5600 | 23 |  |  |  |  | 55 | $parm->{sgh2}=   2*$init->{ss4}*$init->{sz32}; | 
| 5601 | 23 |  |  |  |  | 83 | $parm->{sgh3}=   2*$init->{ss4}*($init->{sz33}-$init->{sz31}); | 
| 5602 | 23 |  |  |  |  | 57 | $parm->{sgh4}= -18*$init->{ss4}*$zes; | 
| 5603 | 23 |  |  |  |  | 71 | $parm->{sh2}=  -2*$init->{ss2}*$init->{sz22}; | 
| 5604 |  |  |  |  |  |  |  | 
| 5605 | 23 |  |  |  |  | 78 | $parm->{sh3}=  -2*$init->{ss2}*($init->{sz23}-$init->{sz21}); | 
| 5606 |  |  |  |  |  |  | #* ---------------------------- DO LUNAR TERMS ------------------------- | 
| 5607 | 23 |  |  |  |  | 75 | $parm->{ee2}=   2*$init->{s1}*$init->{s6}; | 
| 5608 | 23 |  |  |  |  | 63 | $parm->{e3}=   2*$init->{s1}*$init->{s7}; | 
| 5609 | 23 |  |  |  |  | 71 | $parm->{xi2}=   2*$init->{s2}*$init->{z12}; | 
| 5610 | 23 |  |  |  |  | 75 | $parm->{xi3}=   2*$init->{s2}*($init->{z13}-$init->{z11}); | 
| 5611 | 23 |  |  |  |  | 65 | $parm->{xl2}=  -2*$init->{s3}*$init->{z2}; | 
| 5612 | 23 |  |  |  |  | 95 | $parm->{xl3}=  -2*$init->{s3}*($init->{z3}-$init->{z1}); | 
| 5613 | 23 |  |  |  |  | 66 | $parm->{xl4}=  -2*$init->{s3}*(-21-9*$init->{emsq})*$zel; | 
| 5614 | 23 |  |  |  |  | 57 | $parm->{xgh2}=   2*$init->{s4}*$init->{z32}; | 
| 5615 | 23 |  |  |  |  | 164 | $parm->{xgh3}=   2*$init->{s4}*($init->{z33}-$init->{z31}); | 
| 5616 | 23 |  |  |  |  | 90 | $parm->{xgh4}= -18*$init->{s4}*$zel; | 
| 5617 | 23 |  |  |  |  | 64 | $parm->{xh2}=  -2*$init->{s2}*$init->{z22}; | 
| 5618 |  |  |  |  |  |  |  | 
| 5619 | 23 |  |  |  |  | 68 | $parm->{xh3}=  -2*$init->{s2}*($init->{z23}-$init->{z21}); | 
| 5620 |  |  |  |  |  |  | #c        INCLUDE 'debug2.for' | 
| 5621 |  |  |  |  |  |  |  | 
| 5622 | 23 |  |  |  |  | 56 | return; | 
| 5623 |  |  |  |  |  |  | } | 
| 5624 |  |  |  |  |  |  |  | 
| 5625 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 5626 |  |  |  |  |  |  | #* | 
| 5627 |  |  |  |  |  |  | #*                           SUBROUTINE DSINIT | 
| 5628 |  |  |  |  |  |  | #* | 
| 5629 |  |  |  |  |  |  | #*  This Subroutine provides Deep Space contributions to Mean Motion Dot due | 
| 5630 |  |  |  |  |  |  | #*    to geopotential resonance with half day and one day orbits. | 
| 5631 |  |  |  |  |  |  | #* | 
| 5632 |  |  |  |  |  |  | #*  Inputs        : | 
| 5633 |  |  |  |  |  |  | #*    Cosim, Sinim- | 
| 5634 |  |  |  |  |  |  | #*    Emsq        - Eccentricity squared | 
| 5635 |  |  |  |  |  |  | #*    Argpo       - Argument of Perigee | 
| 5636 |  |  |  |  |  |  | #*    S1, S2, S3, S4, S5      - | 
| 5637 |  |  |  |  |  |  | #*    Ss1, Ss2, Ss3, Ss4, Ss5 - | 
| 5638 |  |  |  |  |  |  | #*    Sz1, Sz3, Sz11, Sz13, Sz21, Sz23, Sz31, Sz33 - | 
| 5639 |  |  |  |  |  |  | #*    T           - Time | 
| 5640 |  |  |  |  |  |  | #*    Tc          - | 
| 5641 |  |  |  |  |  |  | #*    GSTo        - Greenwich sidereal time                   rad | 
| 5642 |  |  |  |  |  |  | #*    Mo          - Mean Anomaly | 
| 5643 |  |  |  |  |  |  | #*    MDot        - Mean Anomaly dot (rate) | 
| 5644 |  |  |  |  |  |  | #*    No          - Mean Motion | 
| 5645 |  |  |  |  |  |  | #*    nodeo       - right ascension of ascending node | 
| 5646 |  |  |  |  |  |  | #*    nodeDot     - right ascension of ascending node dot (rate) | 
| 5647 |  |  |  |  |  |  | #*    XPIDOT      - | 
| 5648 |  |  |  |  |  |  | #*    Z1, Z3, Z11, Z13, Z21, Z23, Z31, Z33 - | 
| 5649 |  |  |  |  |  |  | #*    Eccm        - Eccentricity | 
| 5650 |  |  |  |  |  |  | #*    Argpm       - Argument of perigee | 
| 5651 |  |  |  |  |  |  | #*    Inclm       - Inclination | 
| 5652 |  |  |  |  |  |  | #*    Mm          - Mean Anomaly | 
| 5653 |  |  |  |  |  |  | #*    Xn          - Mean Motion | 
| 5654 |  |  |  |  |  |  | #*    nodem       - right ascension of ascending node | 
| 5655 |  |  |  |  |  |  | #* | 
| 5656 |  |  |  |  |  |  | #*  Outputs       : | 
| 5657 |  |  |  |  |  |  | #*    Eccm        - Eccentricity | 
| 5658 |  |  |  |  |  |  | #*    Argpm       - Argument of perigee | 
| 5659 |  |  |  |  |  |  | #*    Inclm       - Inclination | 
| 5660 |  |  |  |  |  |  | #*    Mm          - Mean Anomaly | 
| 5661 |  |  |  |  |  |  | #*    Xn          - Mean motion | 
| 5662 |  |  |  |  |  |  | #*    nodem       - right ascension of ascending node | 
| 5663 |  |  |  |  |  |  | #*    IRez        - Resonance flags              0-none, 1-One day,  2-Half day | 
| 5664 |  |  |  |  |  |  | #*    Atime       - | 
| 5665 |  |  |  |  |  |  | #*    D2201, D2211, D3210, D3222, D4410, D4422, D5220, D5232, D5421, D5433       - | 
| 5666 |  |  |  |  |  |  | #*    Dedt        - | 
| 5667 |  |  |  |  |  |  | #*    Didt        - | 
| 5668 |  |  |  |  |  |  | #*    DMDT        - | 
| 5669 |  |  |  |  |  |  | #*    DNDT        - | 
| 5670 |  |  |  |  |  |  | #*    DNODT       - | 
| 5671 |  |  |  |  |  |  | #*    DOMDT       - | 
| 5672 |  |  |  |  |  |  | #*    Del1, Del2, Del3 - | 
| 5673 |  |  |  |  |  |  | #*    Ses  , Sghl , Sghs , Sgs  , Shl  , Shs  , Sis  , Sls | 
| 5674 |  |  |  |  |  |  | #*    THETA       - | 
| 5675 |  |  |  |  |  |  | #*    Xfact       - | 
| 5676 |  |  |  |  |  |  | #*    Xlamo       - | 
| 5677 |  |  |  |  |  |  | #*    Xli         - | 
| 5678 |  |  |  |  |  |  | #*    Xni | 
| 5679 |  |  |  |  |  |  | #* | 
| 5680 |  |  |  |  |  |  | #*  Locals        : | 
| 5681 |  |  |  |  |  |  | #*    ainv2       - | 
| 5682 |  |  |  |  |  |  | #*    aonv        - | 
| 5683 |  |  |  |  |  |  | #*    cosisq      - | 
| 5684 |  |  |  |  |  |  | #*    eoc         - | 
| 5685 |  |  |  |  |  |  | #*    f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543        - | 
| 5686 |  |  |  |  |  |  | #*    g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533        - | 
| 5687 |  |  |  |  |  |  | #*    sini2       - | 
| 5688 |  |  |  |  |  |  | #*    temp, temp1 - | 
| 5689 |  |  |  |  |  |  | #*    Theta       - | 
| 5690 |  |  |  |  |  |  | #*    xno2        - | 
| 5691 |  |  |  |  |  |  | #* | 
| 5692 |  |  |  |  |  |  | #*  Coupling      : | 
| 5693 |  |  |  |  |  |  | #*    getgravconst- | 
| 5694 |  |  |  |  |  |  | #* | 
| 5695 |  |  |  |  |  |  | #*  references    : | 
| 5696 |  |  |  |  |  |  | #*    hoots, roehrich, norad spacetrack report #3 1980 | 
| 5697 |  |  |  |  |  |  | #*    hoots, norad spacetrack report #6 1986 | 
| 5698 |  |  |  |  |  |  | #*    hoots, schumacher and glover 2004 | 
| 5699 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 5700 |  |  |  |  |  |  | #*------------------------------------------------------------------------------ | 
| 5701 |  |  |  |  |  |  |  | 
| 5702 |  |  |  |  |  |  | sub _r_dsinit { | 
| 5703 | 23 |  |  | 23 |  | 96 | my ($self, $t, $tc) = @_; | 
| 5704 |  |  |  |  |  |  | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} | 
| 5705 | 23 | 50 |  |  |  | 126 | or confess "Programming error - Sgp4r not initialized"; | 
| 5706 |  |  |  |  |  |  | my $init = $parm->{init} | 
| 5707 | 23 | 50 |  |  |  | 196 | or confess "Programming error - Sgp4r initialization not in progress"; | 
| 5708 |  |  |  |  |  |  |  | 
| 5709 |  |  |  |  |  |  | #* -------------------------- Local Variables -------------------------- | 
| 5710 | 23 |  |  |  |  | 150 | my ($ainv2, $aonv, $cosisq, $eoc, $f220, $f221, $f311, $f321, $f322, | 
| 5711 |  |  |  |  |  |  | $f330, $f441, $f442, $f522, $f523, $f542, $f543, $g200, $g201, | 
| 5712 |  |  |  |  |  |  | $g211, $g300, $g310, $g322, $g410, $g422, $g520, $g521, $g532, | 
| 5713 |  |  |  |  |  |  | $g533, $ses, $sgs, $sghl, $sghs, $shs, $shl, $sis, $sini2, $sls, | 
| 5714 |  |  |  |  |  |  | $temp, $temp1, $theta, $xno2); | 
| 5715 |  |  |  |  |  |  |  | 
| 5716 | 23 |  |  |  |  | 0 | my ($q22, $q31, $q33, $root22, $root44, $root54, $rptim, $root32, | 
| 5717 |  |  |  |  |  |  | $root52, $znl, $zns, $emo, $emsqo); | 
| 5718 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'ASTMATH.CMN' | 
| 5719 |  |  |  |  |  |  |  | 
| 5720 | 23 |  |  |  |  | 46 | $q22= 1.7891679e-06; | 
| 5721 | 23 |  |  |  |  | 40 | $q31= 2.1460748e-06; | 
| 5722 | 23 |  |  |  |  | 48 | $q33= 2.2123015e-07; | 
| 5723 | 23 |  |  |  |  | 52 | $root22= 1.7891679e-06; | 
| 5724 | 23 |  |  |  |  | 40 | $root44= 7.3636953e-09; | 
| 5725 | 23 |  |  |  |  | 37 | $root54= 2.1765803e-09; | 
| 5726 | 23 |  |  |  |  | 41 | $rptim= 0.0043752690880113; | 
| 5727 | 23 |  |  |  |  | 34 | $root32= 3.7393792e-07; | 
| 5728 | 23 |  |  |  |  | 37 | $root52= 1.1428639e-07; | 
| 5729 |  |  |  |  |  |  | #>>>>trw	X2o3   = 2.0D0 / 3.0D0 | 
| 5730 | 23 |  |  |  |  | 42 | $znl= 0.00015835218; | 
| 5731 |  |  |  |  |  |  |  | 
| 5732 | 23 |  |  |  |  | 49 | $zns= 1.19459e-05; | 
| 5733 |  |  |  |  |  |  |  | 
| 5734 |  |  |  |  |  |  | #>>>>trw	CALL getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ) | 
| 5735 |  |  |  |  |  |  | #* ------------------------ DEEP SPACE INITIALIZATION ------------------ | 
| 5736 | 23 |  |  |  |  | 46 | $parm->{irez}= 0; | 
| 5737 | 23 | 100 | 100 |  |  | 109 | if (($init->{xn} < 0.0052359877) && ($init->{xn} > 0.0034906585)) { | 
| 5738 | 6 |  |  |  |  | 15 | $parm->{irez}= 1; | 
| 5739 |  |  |  |  |  |  | } | 
| 5740 | 23 | 100 | 100 |  |  | 170 | if (($init->{xn} >= 0.00826) && ($init->{xn} <= 0.00924) && | 
|  |  |  | 100 |  |  |  |  | 
| 5741 |  |  |  |  |  |  | ($init->{eccm} >= 0.5)) { | 
| 5742 | 5 |  |  |  |  | 12 | $parm->{irez}= 2; | 
| 5743 |  |  |  |  |  |  |  | 
| 5744 |  |  |  |  |  |  | } | 
| 5745 |  |  |  |  |  |  | #* ---------------------------- DO SOLAR TERMS ------------------------- | 
| 5746 | 23 |  |  |  |  | 66 | $ses=  $init->{ss1}*$zns*$init->{ss5}; | 
| 5747 | 23 |  |  |  |  | 70 | $sis=  $init->{ss2}*$zns*($init->{sz11}+ $init->{sz13}); | 
| 5748 |  |  |  |  |  |  | $sls= -$zns*$init->{ss3}*($init->{sz1}+ $init->{sz3}- 14 - | 
| 5749 | 23 |  |  |  |  | 79 | 6*$init->{emsq}); | 
| 5750 | 23 |  |  |  |  | 74 | $sghs=  $init->{ss4}*$zns*($init->{sz31}+ $init->{sz33}- 6); | 
| 5751 | 23 |  |  |  |  | 66 | $shs= -$zns*$init->{ss2}*($init->{sz21}+ $init->{sz23}); | 
| 5752 |  |  |  |  |  |  | #c       sgp4fix for 180 deg incl | 
| 5753 | 23 | 100 | 66 |  |  | 167 | if (($init->{inclm} < 0.052359877) || ($init->{inclm} > | 
| 5754 |  |  |  |  |  |  | &SGP_PI-0.052359877)) { | 
| 5755 | 3 |  |  |  |  | 8 | $shs= 0; | 
| 5756 |  |  |  |  |  |  | } | 
| 5757 | 23 | 50 |  |  |  | 79 | if ($init->{sinim} != 0) { | 
| 5758 | 23 |  |  |  |  | 59 | $shs= $shs/$init->{sinim}; | 
| 5759 |  |  |  |  |  |  | } | 
| 5760 |  |  |  |  |  |  |  | 
| 5761 | 23 |  |  |  |  | 48 | $sgs= $sghs- $init->{cosim}*$shs; | 
| 5762 |  |  |  |  |  |  | #* ----------------------------- DO LUNAR TERMS ------------------------ | 
| 5763 | 23 |  |  |  |  | 88 | $parm->{dedt}= $ses+ $init->{s1}*$znl*$init->{s5}; | 
| 5764 | 23 |  |  |  |  | 124 | $parm->{didt}= $sis+ $init->{s2}*$znl*($init->{z11}+ $init->{z13}); | 
| 5765 |  |  |  |  |  |  | $parm->{dmdt}= $sls- $znl*$init->{s3}*($init->{z1}+ $init->{z3}- 14 | 
| 5766 | 23 |  |  |  |  | 113 | - 6*$init->{emsq}); | 
| 5767 | 23 |  |  |  |  | 68 | $sghl= $init->{s4}*$znl*($init->{z31}+ $init->{z33}- 6); | 
| 5768 | 23 |  |  |  |  | 59 | $shl= -$znl*$init->{s2}*($init->{z21}+ $init->{z23}); | 
| 5769 |  |  |  |  |  |  | #c       sgp4fix for 180 deg incl | 
| 5770 | 23 | 100 | 66 |  |  | 132 | if (($init->{inclm} < 0.052359877) || ($init->{inclm} > | 
| 5771 |  |  |  |  |  |  | &SGP_PI-0.052359877)) { | 
| 5772 | 3 |  |  |  |  | 7 | $shl= 0; | 
| 5773 |  |  |  |  |  |  | } | 
| 5774 | 23 |  |  |  |  | 50 | $parm->{domdt}= $sgs+$sghl; | 
| 5775 | 23 |  |  |  |  | 53 | $parm->{dnodt}= $shs; | 
| 5776 | 23 | 50 |  |  |  | 88 | if ($init->{sinim} !=  0) { | 
| 5777 |  |  |  |  |  |  | $parm->{domdt}= | 
| 5778 | 23 |  |  |  |  | 80 | $parm->{domdt}-$init->{cosim}/$init->{sinim}*$shl; | 
| 5779 | 23 |  |  |  |  | 63 | $parm->{dnodt}= $parm->{dnodt}+$shl/$init->{sinim}; | 
| 5780 |  |  |  |  |  |  |  | 
| 5781 |  |  |  |  |  |  | } | 
| 5782 |  |  |  |  |  |  | #* --------------- CALCULATE DEEP SPACE RESONANCE EFFECTS -------------- | 
| 5783 | 23 |  |  |  |  | 76 | $init->{dndt}= 0; | 
| 5784 | 23 |  |  |  |  | 112 | $theta= fmod($parm->{gsto}+ $tc*$rptim, &SGP_TWOPI); | 
| 5785 | 23 |  |  |  |  | 70 | $init->{eccm}= $init->{eccm}+ $parm->{dedt}*$t; | 
| 5786 | 23 |  |  |  |  | 62 | $init->{emsq}= $init->{eccm}**2; | 
| 5787 | 23 |  |  |  |  | 60 | $init->{inclm}= $init->{inclm}+ $parm->{didt}*$t; | 
| 5788 | 23 |  |  |  |  | 66 | $init->{argpm}= $init->{argpm}+ $parm->{domdt}*$t; | 
| 5789 | 23 |  |  |  |  | 58 | $init->{nodem}= $init->{nodem}+ $parm->{dnodt}*$t; | 
| 5790 | 23 |  |  |  |  | 59 | $init->{mm}= $init->{mm}+ $parm->{dmdt}*$t; | 
| 5791 |  |  |  |  |  |  | #c   sgp4fix for negative inclinations | 
| 5792 |  |  |  |  |  |  | #c   the following if statement should be commented out | 
| 5793 |  |  |  |  |  |  | #c           IF(Inclm .lt. 0.0D0) THEN | 
| 5794 |  |  |  |  |  |  | #c             Inclm  = -Inclm | 
| 5795 |  |  |  |  |  |  | #c             Argpm  = Argpm-PI | 
| 5796 |  |  |  |  |  |  | #c             nodem = nodem+PI | 
| 5797 |  |  |  |  |  |  | #c           ENDIF | 
| 5798 |  |  |  |  |  |  |  | 
| 5799 |  |  |  |  |  |  | #* ------------------ Initialize the resonance terms ------------------- | 
| 5800 | 23 | 100 |  |  |  | 93 | if ($parm->{irez} !=  0) { | 
| 5801 |  |  |  |  |  |  |  | 
| 5802 | 11 |  |  |  |  | 44 | $aonv= ($init->{xn}/$parm->{xke})**&SGP_TOTHRD; | 
| 5803 |  |  |  |  |  |  | #* -------------- GEOPOTENTIAL RESONANCE FOR 12 HOUR ORBITS ------------ | 
| 5804 | 11 | 100 |  |  |  | 39 | if ($parm->{irez} ==  2) { | 
| 5805 | 5 |  |  |  |  | 11 | $cosisq= $init->{cosim}*$init->{cosim}; | 
| 5806 | 5 |  |  |  |  | 11 | $emo= $init->{eccm}; | 
| 5807 | 5 |  |  |  |  | 8 | $emsqo= $init->{emsq}; | 
| 5808 | 5 |  |  |  |  | 12 | $init->{eccm}= $parm->{eccentricity}; | 
| 5809 | 5 |  |  |  |  | 9 | $init->{emsq}= $init->{eccsq}; | 
| 5810 | 5 |  |  |  |  | 10 | $eoc= $init->{eccm}*$init->{emsq}; | 
| 5811 | 5 |  |  |  |  | 13 | $g201= -0.306-($init->{eccm}-0.64)*0.44; | 
| 5812 | 5 | 100 |  |  |  | 17 | if ($init->{eccm} <= 0.65) { | 
| 5813 |  |  |  |  |  |  | $g211=   3.616 -  13.247*$init->{eccm}+ | 
| 5814 | 1 |  |  |  |  | 5 | 16.29*$init->{emsq}; | 
| 5815 |  |  |  |  |  |  | $g310= -19.302 + 117.39*$init->{eccm}- | 
| 5816 | 1 |  |  |  |  | 4 | 228.419*$init->{emsq}+ 156.591*$eoc; | 
| 5817 |  |  |  |  |  |  | $g322= -18.9068+ 109.7927*$init->{eccm}- | 
| 5818 | 1 |  |  |  |  | 4 | 214.6334*$init->{emsq}+ 146.5816*$eoc; | 
| 5819 |  |  |  |  |  |  | $g410= -41.122 + 242.694*$init->{eccm}- | 
| 5820 | 1 |  |  |  |  | 3 | 471.094*$init->{emsq}+ 313.953*$eoc; | 
| 5821 |  |  |  |  |  |  | $g422=-146.407 + 841.88*$init->{eccm}- | 
| 5822 | 1 |  |  |  |  | 3 | 1629.014*$init->{emsq}+ 1083.435*$eoc; | 
| 5823 |  |  |  |  |  |  | $g520=-532.114 + 3017.977*$init->{eccm}- | 
| 5824 | 1 |  |  |  |  | 4 | 5740.032*$init->{emsq}+ 3708.276*$eoc; | 
| 5825 |  |  |  |  |  |  | } else { | 
| 5826 |  |  |  |  |  |  | $g211=  -72.099 +  331.819*$init->{eccm}- | 
| 5827 | 4 |  |  |  |  | 14 | 508.738*$init->{emsq}+ 266.724*$eoc; | 
| 5828 |  |  |  |  |  |  | $g310= -346.844 + 1582.851*$init->{eccm}- | 
| 5829 | 4 |  |  |  |  | 14 | 2415.925*$init->{emsq}+ 1246.113*$eoc; | 
| 5830 |  |  |  |  |  |  | $g322= -342.585 + 1554.908*$init->{eccm}- | 
| 5831 | 4 |  |  |  |  | 11 | 2366.899*$init->{emsq}+ 1215.972*$eoc; | 
| 5832 |  |  |  |  |  |  | $g410=-1052.797 + 4758.686*$init->{eccm}- | 
| 5833 | 4 |  |  |  |  | 13 | 7193.992*$init->{emsq}+ 3651.957*$eoc; | 
| 5834 |  |  |  |  |  |  | $g422=-3581.69 + 16178.11*$init->{eccm}- | 
| 5835 | 4 |  |  |  |  | 12 | 24462.77*$init->{emsq}+ 12422.52*$eoc; | 
| 5836 | 4 | 100 |  |  |  | 12 | if ($init->{eccm} > 0.715) { | 
| 5837 |  |  |  |  |  |  | $g520=-5149.66 + | 
| 5838 |  |  |  |  |  |  | 29936.92*$init->{eccm}-54087.36*$init->{emsq}+ | 
| 5839 | 2 |  |  |  |  | 7 | 31324.56*$eoc; | 
| 5840 |  |  |  |  |  |  | } else { | 
| 5841 |  |  |  |  |  |  | $g520= 1464.74 -  4664.75*$init->{eccm}+ | 
| 5842 | 2 |  |  |  |  | 5 | 3763.64*$init->{emsq}; | 
| 5843 |  |  |  |  |  |  | } | 
| 5844 |  |  |  |  |  |  | } | 
| 5845 | 5 | 100 |  |  |  | 18 | if ($init->{eccm} < 0.7) { | 
| 5846 |  |  |  |  |  |  | $g533= -919.2277 + | 
| 5847 |  |  |  |  |  |  | 4988.61*$init->{eccm}-9064.77*$init->{emsq}+ | 
| 5848 | 2 |  |  |  |  | 8 | 5542.21*$eoc; | 
| 5849 |  |  |  |  |  |  | $g521= -822.71072 + | 
| 5850 |  |  |  |  |  |  | 4568.6173*$init->{eccm}-8491.4146*$init->{emsq}+ | 
| 5851 | 2 |  |  |  |  | 6 | 5337.524*$eoc; | 
| 5852 |  |  |  |  |  |  | $g532= -853.666 + | 
| 5853 |  |  |  |  |  |  | 4690.25*$init->{eccm}-8624.77*$init->{emsq}+ | 
| 5854 | 2 |  |  |  |  | 5 | 5341.4*$eoc; | 
| 5855 |  |  |  |  |  |  | } else { | 
| 5856 |  |  |  |  |  |  | $g533=-37995.78 + | 
| 5857 |  |  |  |  |  |  | 161616.52*$init->{eccm}-229838.2*$init->{emsq}+ | 
| 5858 | 3 |  |  |  |  | 10 | 109377.94*$eoc; | 
| 5859 |  |  |  |  |  |  | $g521=-51752.104 + | 
| 5860 |  |  |  |  |  |  | 218913.95*$init->{eccm}-309468.16*$init->{emsq}+ | 
| 5861 | 3 |  |  |  |  | 12 | 146349.42*$eoc; | 
| 5862 |  |  |  |  |  |  | $g532=-40023.88 + | 
| 5863 |  |  |  |  |  |  | 170470.89*$init->{eccm}-242699.48*$init->{emsq}+ | 
| 5864 | 3 |  |  |  |  | 11 | 115605.82*$eoc; | 
| 5865 |  |  |  |  |  |  | } | 
| 5866 | 5 |  |  |  |  | 11 | $sini2=  $init->{sinim}*$init->{sinim}; | 
| 5867 | 5 |  |  |  |  | 16 | $f220=  0.75* (1+2*$init->{cosim}+$cosisq); | 
| 5868 | 5 |  |  |  |  | 10 | $f221=  1.5*$sini2; | 
| 5869 |  |  |  |  |  |  | $f321=  1.875*$init->{sinim}* | 
| 5870 | 5 |  |  |  |  | 17 | (1-2*$init->{cosim}-3*$cosisq); | 
| 5871 |  |  |  |  |  |  | $f322= -1.875*$init->{sinim}* | 
| 5872 | 5 |  |  |  |  | 18 | (1+2*$init->{cosim}-3*$cosisq); | 
| 5873 | 5 |  |  |  |  | 9 | $f441= 35*$sini2*$f220; | 
| 5874 | 5 |  |  |  |  | 9 | $f442= 39.375*$sini2*$sini2; | 
| 5875 |  |  |  |  |  |  | $f522=  9.84375*$init->{sinim}* ($sini2* | 
| 5876 |  |  |  |  |  |  | (1-2*$init->{cosim}- 5*$cosisq)+0.33333333 * | 
| 5877 | 5 |  |  |  |  | 21 | (-2+4*$init->{cosim}+ 6*$cosisq) ); | 
| 5878 |  |  |  |  |  |  | $f523=  $init->{sinim}* (4.92187512*$sini2* | 
| 5879 |  |  |  |  |  |  | (-2-4*$init->{cosim}+ 10*$cosisq) + 6.56250012* | 
| 5880 | 5 |  |  |  |  | 29 | (1+2*$init->{cosim}-3*$cosisq)); | 
| 5881 |  |  |  |  |  |  | $f542=  29.53125*$init->{sinim}* | 
| 5882 |  |  |  |  |  |  | (2-8*$init->{cosim}+$cosisq* | 
| 5883 | 5 |  |  |  |  | 17 | (-12+8*$init->{cosim}+10*$cosisq) ); | 
| 5884 |  |  |  |  |  |  |  | 
| 5885 |  |  |  |  |  |  | $f543= 29.53125*$init->{sinim}* | 
| 5886 |  |  |  |  |  |  | (-2-8*$init->{cosim}+$cosisq* | 
| 5887 | 5 |  |  |  |  | 18 | (12+8*$init->{cosim}-10*$cosisq) ); | 
| 5888 | 5 |  |  |  |  | 11 | $xno2=  $init->{xn}* $init->{xn}; | 
| 5889 | 5 |  |  |  |  | 9 | $ainv2=  $aonv* $aonv; | 
| 5890 | 5 |  |  |  |  | 11 | $temp1=  3*$xno2*$ainv2; | 
| 5891 | 5 |  |  |  |  | 11 | $temp=  $temp1*$root22; | 
| 5892 | 5 |  |  |  |  | 10 | $parm->{d2201}=  $temp*$f220*$g201; | 
| 5893 | 5 |  |  |  |  | 12 | $parm->{d2211}=  $temp*$f221*$g211; | 
| 5894 | 5 |  |  |  |  | 9 | $temp1=  $temp1*$aonv; | 
| 5895 | 5 |  |  |  |  | 9 | $temp=  $temp1*$root32; | 
| 5896 | 5 |  |  |  |  | 9 | $parm->{d3210}=  $temp*$f321*$g310; | 
| 5897 | 5 |  |  |  |  | 11 | $parm->{d3222}=  $temp*$f322*$g322; | 
| 5898 | 5 |  |  |  |  | 6 | $temp1=  $temp1*$aonv; | 
| 5899 | 5 |  |  |  |  | 9 | $temp=  2*$temp1*$root44; | 
| 5900 | 5 |  |  |  |  | 12 | $parm->{d4410}=  $temp*$f441*$g410; | 
| 5901 | 5 |  |  |  |  | 13 | $parm->{d4422}=  $temp*$f442*$g422; | 
| 5902 | 5 |  |  |  |  | 9 | $temp1=  $temp1*$aonv; | 
| 5903 | 5 |  |  |  |  | 7 | $temp=  $temp1*$root52; | 
| 5904 | 5 |  |  |  |  | 18 | $parm->{d5220}=  $temp*$f522*$g520; | 
| 5905 | 5 |  |  |  |  | 11 | $parm->{d5232}=  $temp*$f523*$g532; | 
| 5906 | 5 |  |  |  |  | 9 | $temp=  2*$temp1*$root54; | 
| 5907 | 5 |  |  |  |  | 12 | $parm->{d5421}=  $temp*$f542*$g521; | 
| 5908 | 5 |  |  |  |  | 25 | $parm->{d5433}=  $temp*$f543*$g533; | 
| 5909 |  |  |  |  |  |  | $parm->{xlamo}= | 
| 5910 | 5 |  |  |  |  | 31 | fmod($parm->{meananomaly}+$parm->{ascendingnode}+$parm->{ascendingnode}-$theta-$theta, | 
| 5911 |  |  |  |  |  |  | &SGP_TWOPI); | 
| 5912 |  |  |  |  |  |  |  | 
| 5913 |  |  |  |  |  |  | $parm->{xfact}= $parm->{mdot}+ $parm->{dmdt}+ 2 * | 
| 5914 |  |  |  |  |  |  | ($parm->{nodedot}+$parm->{dnodt}-$rptim) - | 
| 5915 | 5 |  |  |  |  | 19 | $parm->{meanmotion}; | 
| 5916 | 5 |  |  |  |  | 11 | $init->{eccm}= $emo; | 
| 5917 | 5 |  |  |  |  | 10 | $init->{emsq}= $emsqo; | 
| 5918 |  |  |  |  |  |  |  | 
| 5919 |  |  |  |  |  |  | } | 
| 5920 | 11 | 100 |  |  |  | 46 | if ($parm->{irez} ==  1) { | 
| 5921 |  |  |  |  |  |  | #* -------------------- SYNCHRONOUS RESONANCE TERMS -------------------- | 
| 5922 | 6 |  |  |  |  | 19 | $g200= 1 + $init->{emsq}* (-2.5+0.8125*$init->{emsq}); | 
| 5923 | 6 |  |  |  |  | 18 | $g310= 1 + 2*$init->{emsq}; | 
| 5924 | 6 |  |  |  |  | 19 | $g300= 1 + $init->{emsq}* (-6+6.60937*$init->{emsq}); | 
| 5925 | 6 |  |  |  |  | 17 | $f220= 0.75 * (1+$init->{cosim}) * (1+$init->{cosim}); | 
| 5926 |  |  |  |  |  |  | $f311= 0.9375*$init->{sinim}*$init->{sinim}* | 
| 5927 | 6 |  |  |  |  | 30 | (1+3*$init->{cosim}) - 0.75*(1+$init->{cosim}); | 
| 5928 | 6 |  |  |  |  | 13 | $f330= 1+$init->{cosim}; | 
| 5929 | 6 |  |  |  |  | 12 | $f330= 1.875*$f330*$f330*$f330; | 
| 5930 | 6 |  |  |  |  | 21 | $parm->{del1}= 3*$init->{xn}*$init->{xn}*$aonv*$aonv; | 
| 5931 | 6 |  |  |  |  | 16 | $parm->{del2}= 2*$parm->{del1}*$f220*$g200*$q22; | 
| 5932 | 6 |  |  |  |  | 44 | $parm->{del3}= 3*$parm->{del1}*$f330*$g300*$q33*$aonv; | 
| 5933 | 6 |  |  |  |  | 19 | $parm->{del1}= $parm->{del1}*$f311*$g310*$q31*$aonv; | 
| 5934 |  |  |  |  |  |  | $parm->{xlamo}= | 
| 5935 | 6 |  |  |  |  | 36 | fmod($parm->{meananomaly}+$parm->{ascendingnode}+$parm->{argumentofperigee}-$theta, | 
| 5936 |  |  |  |  |  |  | &SGP_TWOPI); | 
| 5937 |  |  |  |  |  |  | $parm->{xfact}= $parm->{mdot}+ $init->{xpidot}- $rptim+ | 
| 5938 |  |  |  |  |  |  | $parm->{dmdt}+ $parm->{domdt}+ $parm->{dnodt}- | 
| 5939 | 6 |  |  |  |  | 33 | $parm->{meanmotion}; | 
| 5940 |  |  |  |  |  |  |  | 
| 5941 |  |  |  |  |  |  | } | 
| 5942 |  |  |  |  |  |  | #* ---------------- FOR SGP4, INITIALIZE THE INTEGRATOR ---------------- | 
| 5943 | 11 |  |  |  |  | 25 | $parm->{xli}= $parm->{xlamo}; | 
| 5944 | 11 |  |  |  |  | 30 | $parm->{xni}= $parm->{meanmotion}; | 
| 5945 | 11 |  |  |  |  | 24 | $parm->{atime}= 0; | 
| 5946 | 11 |  |  |  |  | 37 | $init->{xn}= $parm->{meanmotion}+ $init->{dndt}; | 
| 5947 |  |  |  |  |  |  |  | 
| 5948 |  |  |  |  |  |  | } | 
| 5949 |  |  |  |  |  |  | #c        INCLUDE 'debug3.for' | 
| 5950 |  |  |  |  |  |  |  | 
| 5951 | 23 |  |  |  |  | 70 | return; | 
| 5952 |  |  |  |  |  |  | } | 
| 5953 |  |  |  |  |  |  |  | 
| 5954 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 5955 |  |  |  |  |  |  | #* | 
| 5956 |  |  |  |  |  |  | #*                           SUBROUTINE DSPACE | 
| 5957 |  |  |  |  |  |  | #* | 
| 5958 |  |  |  |  |  |  | #*  This Subroutine provides deep space contributions to mean elements for | 
| 5959 |  |  |  |  |  |  | #*    perturbing third body.  these effects have been averaged over one | 
| 5960 |  |  |  |  |  |  | #*    revolution of the sun and moon.  for earth resonance effects, the | 
| 5961 |  |  |  |  |  |  | #*    effects have been averaged over no revolutions of the satellite. | 
| 5962 |  |  |  |  |  |  | #*    (mean motion) | 
| 5963 |  |  |  |  |  |  | #* | 
| 5964 |  |  |  |  |  |  | #*  author        : david vallado                  719-573-2600   28 jun 2005 | 
| 5965 |  |  |  |  |  |  | #* | 
| 5966 |  |  |  |  |  |  | #*  inputs        : | 
| 5967 |  |  |  |  |  |  | #*    d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433       - | 
| 5968 |  |  |  |  |  |  | #*    dedt        - | 
| 5969 |  |  |  |  |  |  | #*    del1, del2, del3  - | 
| 5970 |  |  |  |  |  |  | #*    didt        - | 
| 5971 |  |  |  |  |  |  | #*    dmdt        - | 
| 5972 |  |  |  |  |  |  | #*    dnodt       - | 
| 5973 |  |  |  |  |  |  | #*    domdt       - | 
| 5974 |  |  |  |  |  |  | #*    irez        - flag for resonance           0-none, 1-one day, 2-half day | 
| 5975 |  |  |  |  |  |  | #*    argpo       - argument of perigee | 
| 5976 |  |  |  |  |  |  | #*    argpdot     - argument of perigee dot (rate) | 
| 5977 |  |  |  |  |  |  | #*    t           - time | 
| 5978 |  |  |  |  |  |  | #*    tc          - | 
| 5979 |  |  |  |  |  |  | #*    gsto        - gst | 
| 5980 |  |  |  |  |  |  | #*    xfact       - | 
| 5981 |  |  |  |  |  |  | #*    xlamo       - | 
| 5982 |  |  |  |  |  |  | #*    no          - mean motion | 
| 5983 |  |  |  |  |  |  | #*    atime       - | 
| 5984 |  |  |  |  |  |  | #*    em          - eccentricity | 
| 5985 |  |  |  |  |  |  | #*    ft          - | 
| 5986 |  |  |  |  |  |  | #*    argpm       - argument of perigee | 
| 5987 |  |  |  |  |  |  | #*    inclm       - inclination | 
| 5988 |  |  |  |  |  |  | #*    xli         - | 
| 5989 |  |  |  |  |  |  | #*    mm          - mean anomaly | 
| 5990 |  |  |  |  |  |  | #*    xni         - mean motion | 
| 5991 |  |  |  |  |  |  | #*    nodem       - right ascension of ascending node | 
| 5992 |  |  |  |  |  |  | #* | 
| 5993 |  |  |  |  |  |  | #*  outputs       : | 
| 5994 |  |  |  |  |  |  | #*    atime       - | 
| 5995 |  |  |  |  |  |  | #*    em          - eccentricity | 
| 5996 |  |  |  |  |  |  | #*    argpm       - argument of perigee | 
| 5997 |  |  |  |  |  |  | #*    inclm       - inclination | 
| 5998 |  |  |  |  |  |  | #*    xli         - | 
| 5999 |  |  |  |  |  |  | #*    mm          - mean anomaly | 
| 6000 |  |  |  |  |  |  | #*    xni         - | 
| 6001 |  |  |  |  |  |  | #*    nodem       - right ascension of ascending node | 
| 6002 |  |  |  |  |  |  | #*    dndt        - | 
| 6003 |  |  |  |  |  |  | #*    nm          - mean motion | 
| 6004 |  |  |  |  |  |  | #* | 
| 6005 |  |  |  |  |  |  | #*  locals        : | 
| 6006 |  |  |  |  |  |  | #*    delt        - | 
| 6007 |  |  |  |  |  |  | #*    ft          - | 
| 6008 |  |  |  |  |  |  | #*    theta       - | 
| 6009 |  |  |  |  |  |  | #*    x2li        - | 
| 6010 |  |  |  |  |  |  | #*    x2omi       - | 
| 6011 |  |  |  |  |  |  | #*    xl          - | 
| 6012 |  |  |  |  |  |  | #*    xldot       - | 
| 6013 |  |  |  |  |  |  | #*    xnddt       - | 
| 6014 |  |  |  |  |  |  | #*    xndt        - | 
| 6015 |  |  |  |  |  |  | #*    xomi        - | 
| 6016 |  |  |  |  |  |  | #* | 
| 6017 |  |  |  |  |  |  | #*  coupling      : | 
| 6018 |  |  |  |  |  |  | #*    none        - | 
| 6019 |  |  |  |  |  |  | #* | 
| 6020 |  |  |  |  |  |  | #*  references    : | 
| 6021 |  |  |  |  |  |  | #*    hoots, roehrich, norad spacetrack report #3 1980 | 
| 6022 |  |  |  |  |  |  | #*    hoots, norad spacetrack report #6 1986 | 
| 6023 |  |  |  |  |  |  | #*    hoots, schumacher and glover 2004 | 
| 6024 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 6025 |  |  |  |  |  |  | #*------------------------------------------------------------------------------ | 
| 6026 |  |  |  |  |  |  |  | 
| 6027 |  |  |  |  |  |  | sub _r_dspace { | 
| 6028 | 397 |  |  | 397 |  | 1080 | my ($self, $t, $tc, $atime, $eccm, $argpm, $inclm, $xli, $mm, $xni, | 
| 6029 |  |  |  |  |  |  | $nodem, $dndt, $xn) = @_; | 
| 6030 |  |  |  |  |  |  | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} | 
| 6031 | 397 | 50 |  |  |  | 1215 | or confess "Programming error - Sgp4r not initialized"; | 
| 6032 |  |  |  |  |  |  |  | 
| 6033 |  |  |  |  |  |  | #* -------------------------- Local Variables -------------------------- | 
| 6034 | 397 |  |  |  |  | 1310 | my ($iretn, $iret); | 
| 6035 | 397 |  |  |  |  | 0 | my ($delt, $ft, $theta, $x2li, $x2omi, $xl, $xldot, $xnddt, $xndt, | 
| 6036 |  |  |  |  |  |  | $xomi); | 
| 6037 |  |  |  |  |  |  |  | 
| 6038 | 397 |  |  |  |  | 0 | my ($g22, $g32, $g44, $g52, $g54, $fasx2, $fasx4, $fasx6, $rptim, | 
| 6039 |  |  |  |  |  |  | $step2, $stepn, $stepp); | 
| 6040 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'ASTMATH.CMN' | 
| 6041 |  |  |  |  |  |  |  | 
| 6042 |  |  |  |  |  |  | #* ----------------------------- Constants ----------------------------- | 
| 6043 | 397 |  |  |  |  | 526 | $fasx2= 0.13130908; | 
| 6044 | 397 |  |  |  |  | 572 | $fasx4= 2.8843198; | 
| 6045 | 397 |  |  |  |  | 591 | $fasx6= 0.37448087; | 
| 6046 | 397 |  |  |  |  | 504 | $g22= 5.7686396; | 
| 6047 | 397 |  |  |  |  | 511 | $g32= 0.95240898; | 
| 6048 | 397 |  |  |  |  | 512 | $g44= 1.8014998; | 
| 6049 | 397 |  |  |  |  | 547 | $g52= 1.050833; | 
| 6050 | 397 |  |  |  |  | 574 | $g54= 4.4108898; | 
| 6051 | 397 |  |  |  |  | 538 | $rptim= 0.0043752690880113; | 
| 6052 | 397 |  |  |  |  | 522 | $stepp=    720; | 
| 6053 | 397 |  |  |  |  | 500 | $stepn=   -720; | 
| 6054 |  |  |  |  |  |  |  | 
| 6055 | 397 |  |  |  |  | 554 | $step2= 259200; | 
| 6056 |  |  |  |  |  |  | #* --------------- CALCULATE DEEP SPACE RESONANCE EFFECTS -------------- | 
| 6057 | 397 |  |  |  |  | 596 | $$dndt= 0; | 
| 6058 | 397 |  |  |  |  | 1455 | $theta= fmod($parm->{gsto}+ $tc*$rptim, &SGP_TWOPI); | 
| 6059 |  |  |  |  |  |  |  | 
| 6060 | 397 |  |  |  |  | 775 | $$eccm= $$eccm+ $parm->{dedt}*$t; | 
| 6061 | 397 |  |  |  |  | 595 | $$inclm= $$inclm+ $parm->{didt}*$t; | 
| 6062 | 397 |  |  |  |  | 565 | $$argpm= $$argpm+ $parm->{domdt}*$t; | 
| 6063 | 397 |  |  |  |  | 647 | $$nodem= $$nodem+ $parm->{dnodt}*$t; | 
| 6064 |  |  |  |  |  |  |  | 
| 6065 | 397 |  |  |  |  | 597 | $$mm= $$mm+ $parm->{dmdt}*$t; | 
| 6066 |  |  |  |  |  |  | #c   sgp4fix for negative inclinations | 
| 6067 |  |  |  |  |  |  | #c   the following if statement should be commented out | 
| 6068 |  |  |  |  |  |  | #c        IF(Inclm .lt. 0.0D0) THEN | 
| 6069 |  |  |  |  |  |  | #c            Inclm  = -Inclm | 
| 6070 |  |  |  |  |  |  | #c            Argpm  = Argpm-PI | 
| 6071 |  |  |  |  |  |  | #c            nodem = nodem+PI | 
| 6072 |  |  |  |  |  |  | #c          ENDIF | 
| 6073 |  |  |  |  |  |  |  | 
| 6074 |  |  |  |  |  |  | #c   sgp4fix for propagator problems | 
| 6075 |  |  |  |  |  |  | #c   the following integration works for negative time steps and periods | 
| 6076 |  |  |  |  |  |  | #c   the specific changes are unknown because the original code was so convoluted | 
| 6077 | 397 |  |  |  |  | 535 | $ft= 0; | 
| 6078 |  |  |  |  |  |  |  | 
| 6079 | 397 |  |  |  |  | 546 | $$atime= 0; | 
| 6080 | 397 | 100 |  |  |  | 871 | if ($parm->{irez} !=  0) { | 
| 6081 |  |  |  |  |  |  | #* ----- UPDATE RESONANCES : NUMERICAL (EULER-MACLAURIN) INTEGRATION --- | 
| 6082 |  |  |  |  |  |  | #* ---------------------------- EPOCH RESTART -------------------------- | 
| 6083 | 220 | 0 | 0 |  |  | 524 | if ( ($$atime == 0)   ||  (($t >= 0)  &&  ($$atime < 0))  || | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 6084 |  |  |  |  |  |  | (($t < 0)  &&  ($$atime >= 0)) ) { | 
| 6085 | 220 | 100 |  |  |  | 489 | if ($t >= 0) { | 
| 6086 | 195 |  |  |  |  | 284 | $delt= $stepp; | 
| 6087 |  |  |  |  |  |  | } else { | 
| 6088 | 25 |  |  |  |  | 36 | $delt= $stepn; | 
| 6089 |  |  |  |  |  |  | } | 
| 6090 | 220 |  |  |  |  | 374 | $$atime= 0; | 
| 6091 | 220 |  |  |  |  | 342 | $$xni= $parm->{meanmotion}; | 
| 6092 | 220 |  |  |  |  | 350 | $$xli= $parm->{xlamo}; | 
| 6093 |  |  |  |  |  |  | } | 
| 6094 | 220 |  |  |  |  | 278 | $iretn= 381; | 
| 6095 | 220 |  |  |  |  | 284 | $iret=   0; | 
| 6096 | 220 |  |  |  |  | 435 | while ($iretn == 381) { | 
| 6097 | 544 | 50 | 33 |  |  | 1792 | if ( (abs($t) < abs($$atime)) || ($iret == 351) ) { | 
| 6098 | 0 | 0 |  |  |  | 0 | if ($t >= 0) { | 
| 6099 | 0 |  |  |  |  | 0 | $delt= $stepn; | 
| 6100 |  |  |  |  |  |  | } else { | 
| 6101 | 0 |  |  |  |  | 0 | $delt= $stepp; | 
| 6102 |  |  |  |  |  |  | } | 
| 6103 | 0 |  |  |  |  | 0 | $iret= 351; | 
| 6104 | 0 |  |  |  |  | 0 | $iretn= 381; | 
| 6105 |  |  |  |  |  |  | } else { | 
| 6106 | 544 | 100 |  |  |  | 930 | if ($t > 0) { | 
| 6107 | 485 |  |  |  |  | 657 | $delt= $stepp; | 
| 6108 |  |  |  |  |  |  | } else { | 
| 6109 | 59 |  |  |  |  | 88 | $delt= $stepn; | 
| 6110 |  |  |  |  |  |  | } | 
| 6111 | 544 | 100 |  |  |  | 971 | if (abs($t-$$atime) >= $stepp) { | 
| 6112 | 324 |  |  |  |  | 440 | $iret= 0; | 
| 6113 | 324 |  |  |  |  | 765 | $iretn= 381; | 
| 6114 |  |  |  |  |  |  | } else { | 
| 6115 | 220 |  |  |  |  | 310 | $ft= $t-$$atime; | 
| 6116 | 220 |  |  |  |  | 296 | $iretn= 0; | 
| 6117 |  |  |  |  |  |  | } | 
| 6118 |  |  |  |  |  |  |  | 
| 6119 |  |  |  |  |  |  | } | 
| 6120 |  |  |  |  |  |  | #* --------------------------- DOT TERMS CALCULATED -------------------- | 
| 6121 |  |  |  |  |  |  | #* ------------------- NEAR - SYNCHRONOUS RESONANCE TERMS -------------- | 
| 6122 | 544 | 100 |  |  |  | 952 | if ($parm->{irez} !=  2) { | 
| 6123 |  |  |  |  |  |  | $xndt= $parm->{del1}*sin($$xli-$fasx2) + | 
| 6124 |  |  |  |  |  |  | $parm->{del2}*sin(2*($$xli-$fasx4)) + | 
| 6125 | 219 |  |  |  |  | 588 | $parm->{del3}*sin(3*($$xli-$fasx6)); | 
| 6126 | 219 |  |  |  |  | 318 | $xldot= $$xni+ $parm->{xfact}; | 
| 6127 |  |  |  |  |  |  | $xnddt= $parm->{del1}*cos($$xli-$fasx2) + | 
| 6128 |  |  |  |  |  |  | 2*$parm->{del2}*cos(2*($$xli-$fasx4)) + | 
| 6129 | 219 |  |  |  |  | 531 | 3*$parm->{del3}*cos(3*($$xli-$fasx6)); | 
| 6130 | 219 |  |  |  |  | 296 | $xnddt= $xnddt*$xldot; | 
| 6131 |  |  |  |  |  |  |  | 
| 6132 |  |  |  |  |  |  | } else { | 
| 6133 |  |  |  |  |  |  | #* --------------------- NEAR - HALF-DAY RESONANCE TERMS --------------- | 
| 6134 |  |  |  |  |  |  | $xomi= $parm->{argumentofperigee}+ | 
| 6135 | 325 |  |  |  |  | 568 | $parm->{argpdot}*$$atime; | 
| 6136 | 325 |  |  |  |  | 458 | $x2omi= $xomi+ $xomi; | 
| 6137 | 325 |  |  |  |  | 440 | $x2li= $$xli+ $$xli; | 
| 6138 |  |  |  |  |  |  | $xndt= $parm->{d2201}*sin($x2omi+$$xli-$g22) + | 
| 6139 |  |  |  |  |  |  | $parm->{d2211}*sin($$xli-$g22) + | 
| 6140 |  |  |  |  |  |  | $parm->{d3210}*sin($xomi+$$xli-$g32) + | 
| 6141 |  |  |  |  |  |  | $parm->{d3222}*sin(-$xomi+$$xli-$g32) + | 
| 6142 |  |  |  |  |  |  | $parm->{d4410}*sin($x2omi+$x2li-$g44)+ | 
| 6143 |  |  |  |  |  |  | $parm->{d4422}*sin($x2li-$g44)+ | 
| 6144 |  |  |  |  |  |  | $parm->{d5220}*sin($xomi+$$xli-$g52) + | 
| 6145 |  |  |  |  |  |  | $parm->{d5232}*sin(-$xomi+$$xli-$g52) + | 
| 6146 |  |  |  |  |  |  | $parm->{d5421}*sin($xomi+$x2li-$g54)+ | 
| 6147 | 325 |  |  |  |  | 1527 | $parm->{d5433}*sin(-$xomi+$x2li-$g54); | 
| 6148 | 325 |  |  |  |  | 464 | $xldot= $$xni+$parm->{xfact}; | 
| 6149 |  |  |  |  |  |  | $xnddt= $parm->{d2201}*cos($x2omi+$$xli-$g22) + | 
| 6150 |  |  |  |  |  |  | $parm->{d2211}*cos($$xli-$g22)+ | 
| 6151 |  |  |  |  |  |  | $parm->{d3210}*cos($xomi+$$xli-$g32) + | 
| 6152 |  |  |  |  |  |  | $parm->{d3222}*cos(-$xomi+$$xli-$g32) + | 
| 6153 |  |  |  |  |  |  | $parm->{d5220}*cos($xomi+$$xli-$g52) + | 
| 6154 |  |  |  |  |  |  | $parm->{d5232}*cos(-$xomi+$$xli-$g52) + | 
| 6155 |  |  |  |  |  |  | 2*($parm->{d4410}*cos($x2omi+$x2li-$g44) + | 
| 6156 |  |  |  |  |  |  | $parm->{d4422}*cos($x2li-$g44) + | 
| 6157 |  |  |  |  |  |  | $parm->{d5421}*cos($xomi+$x2li-$g54) + | 
| 6158 | 325 |  |  |  |  | 1486 | $parm->{d5433}*cos(-$xomi+$x2li-$g54)); | 
| 6159 | 325 |  |  |  |  | 449 | $xnddt= $xnddt*$xldot; | 
| 6160 |  |  |  |  |  |  |  | 
| 6161 |  |  |  |  |  |  | } | 
| 6162 |  |  |  |  |  |  | #* ------------------------------- INTEGRATOR -------------------------- | 
| 6163 | 544 | 100 |  |  |  | 1169 | if ($iretn == 381) { | 
| 6164 | 324 |  |  |  |  | 613 | $$xli= $$xli+ $xldot*$delt+ $xndt*$step2; | 
| 6165 | 324 |  |  |  |  | 475 | $$xni= $$xni+ $xndt*$delt+ $xnddt*$step2; | 
| 6166 | 324 |  |  |  |  | 614 | $$atime= $$atime+ $delt; | 
| 6167 |  |  |  |  |  |  |  | 
| 6168 |  |  |  |  |  |  | } | 
| 6169 |  |  |  |  |  |  |  | 
| 6170 |  |  |  |  |  |  | } | 
| 6171 | 220 |  |  |  |  | 427 | $$xn= $$xni+ $xndt*$ft+ $xnddt*$ft*$ft*0.5; | 
| 6172 | 220 |  |  |  |  | 358 | $xl= $$xli+ $xldot*$ft+ $xndt*$ft*$ft*0.5; | 
| 6173 | 220 | 100 |  |  |  | 429 | if ($parm->{irez} !=  1) { | 
| 6174 | 125 |  |  |  |  | 223 | $$mm= $xl-2*$$nodem+2*$theta; | 
| 6175 | 125 |  |  |  |  | 203 | $$dndt= $$xn-$parm->{meanmotion}; | 
| 6176 |  |  |  |  |  |  | } else { | 
| 6177 | 95 |  |  |  |  | 1701 | $$mm= $xl-$$nodem-$$argpm+$theta; | 
| 6178 | 95 |  |  |  |  | 160 | $$dndt= $$xn-$parm->{meanmotion}; | 
| 6179 |  |  |  |  |  |  |  | 
| 6180 |  |  |  |  |  |  | } | 
| 6181 | 220 |  |  |  |  | 389 | $$xn= $parm->{meanmotion}+ $$dndt; | 
| 6182 |  |  |  |  |  |  |  | 
| 6183 |  |  |  |  |  |  | } | 
| 6184 |  |  |  |  |  |  | #c        INCLUDE 'debug4.for' | 
| 6185 |  |  |  |  |  |  |  | 
| 6186 | 397 |  |  |  |  | 1200 | return; | 
| 6187 |  |  |  |  |  |  | } | 
| 6188 |  |  |  |  |  |  |  | 
| 6189 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 6190 |  |  |  |  |  |  | #* | 
| 6191 |  |  |  |  |  |  | #*                           SUBROUTINE INITL | 
| 6192 |  |  |  |  |  |  | #* | 
| 6193 |  |  |  |  |  |  | #*  this subroutine initializes the spg4 propagator. all the initialization is | 
| 6194 |  |  |  |  |  |  | #*    consolidated here instead of having multiple loops inside other routines. | 
| 6195 |  |  |  |  |  |  | #* | 
| 6196 |  |  |  |  |  |  | #*  author        : david vallado                  719-573-2600   28 jun 2005 | 
| 6197 |  |  |  |  |  |  | #* | 
| 6198 |  |  |  |  |  |  | #*  inputs        : | 
| 6199 |  |  |  |  |  |  | #*    ecco        - eccentricity                           0.0 - 1.0 | 
| 6200 |  |  |  |  |  |  | #*    epoch       - epoch time in days from jan 0, 1950. 0 hr | 
| 6201 |  |  |  |  |  |  | #*    inclo       - inclination of satellite | 
| 6202 |  |  |  |  |  |  | #*    no          - mean motion of satellite | 
| 6203 |  |  |  |  |  |  | #*    satn        - satellite number | 
| 6204 |  |  |  |  |  |  | #* | 
| 6205 |  |  |  |  |  |  | #*  outputs       : | 
| 6206 |  |  |  |  |  |  | #*    ainv        - 1.0 / a | 
| 6207 |  |  |  |  |  |  | #*    ao          - semi major axis | 
| 6208 |  |  |  |  |  |  | #*    con41       - | 
| 6209 |  |  |  |  |  |  | #*    con42       - 1.0 - 5.0 cos(i) | 
| 6210 |  |  |  |  |  |  | #*    cosio       - cosine of inclination | 
| 6211 |  |  |  |  |  |  | #*    cosio2      - cosio squared | 
| 6212 |  |  |  |  |  |  | #*    eccsq       - eccentricity squared | 
| 6213 |  |  |  |  |  |  | #*    method      - flag for deep space                    'd', 'n' | 
| 6214 |  |  |  |  |  |  | #*    omeosq      - 1.0 - ecco * ecco | 
| 6215 |  |  |  |  |  |  | #*    posq        - semi-parameter squared | 
| 6216 |  |  |  |  |  |  | #*    rp          - radius of perigee | 
| 6217 |  |  |  |  |  |  | #*    rteosq      - square root of (1.0 - ecco*ecco) | 
| 6218 |  |  |  |  |  |  | #*    sinio       - sine of inclination | 
| 6219 |  |  |  |  |  |  | #*    gsto        - gst at time of observation               rad | 
| 6220 |  |  |  |  |  |  | #*    no          - mean motion of satellite | 
| 6221 |  |  |  |  |  |  | #* | 
| 6222 |  |  |  |  |  |  | #*  locals        : | 
| 6223 |  |  |  |  |  |  | #*    ak          - | 
| 6224 |  |  |  |  |  |  | #*    d1          - | 
| 6225 |  |  |  |  |  |  | #*    del         - | 
| 6226 |  |  |  |  |  |  | #*    adel        - | 
| 6227 |  |  |  |  |  |  | #*    po          - | 
| 6228 |  |  |  |  |  |  | #* | 
| 6229 |  |  |  |  |  |  | #*  coupling      : | 
| 6230 |  |  |  |  |  |  | #*    getgravconst- | 
| 6231 |  |  |  |  |  |  | #* | 
| 6232 |  |  |  |  |  |  | #*  references    : | 
| 6233 |  |  |  |  |  |  | #*    hoots, roehrich, norad spacetrack report #3 1980 | 
| 6234 |  |  |  |  |  |  | #*    hoots, norad spacetrack report #6 1986 | 
| 6235 |  |  |  |  |  |  | #*    hoots, schumacher and glover 2004 | 
| 6236 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 6237 |  |  |  |  |  |  | #*------------------------------------------------------------------------------ | 
| 6238 |  |  |  |  |  |  |  | 
| 6239 |  |  |  |  |  |  | sub _r_initl { | 
| 6240 | 35 |  |  | 35 |  | 113 | my ($self) = @_; | 
| 6241 |  |  |  |  |  |  | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} | 
| 6242 | 35 | 50 |  |  |  | 172 | or confess "Programming error - Sgp4r not initialized"; | 
| 6243 |  |  |  |  |  |  | my $init = $parm->{init} | 
| 6244 | 35 | 50 |  |  |  | 106 | or confess "Programming error - Sgp4r initialization not in progress"; | 
| 6245 |  |  |  |  |  |  |  | 
| 6246 |  |  |  |  |  |  | #* -------------------------- Local Variables -------------------------- | 
| 6247 |  |  |  |  |  |  | #cdav old way | 
| 6248 |  |  |  |  |  |  | #c        integer ids70 | 
| 6249 |  |  |  |  |  |  | #c        real*8 ts70, ds70, tfrac, c1, thgr70, fk5r, c1p2p, thgr, thgro, | 
| 6250 |  |  |  |  |  |  | #c     &     twopi | 
| 6251 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'ASTMATH.CMN' | 
| 6252 |  |  |  |  |  |  |  | 
| 6253 |  |  |  |  |  |  | #* ------------------------ WGS-72 EARTH CONSTANTS --------------------- | 
| 6254 |  |  |  |  |  |  |  | 
| 6255 |  |  |  |  |  |  | #>>>>trw	X2o3   = 2.0D0/3.0D0 | 
| 6256 |  |  |  |  |  |  |  | 
| 6257 |  |  |  |  |  |  | #>>>>trw	CALL getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ) | 
| 6258 |  |  |  |  |  |  | #* ----------------- CALCULATE AUXILLARY EPOCH QUANTITIES -------------- | 
| 6259 | 35 |  |  |  |  | 119 | $init->{eccsq}= $parm->{eccentricity}*$parm->{eccentricity}; | 
| 6260 | 35 |  |  |  |  | 111 | $init->{omeosq}= 1 - $init->{eccsq}; | 
| 6261 | 35 |  |  |  |  | 114 | $init->{rteosq}= sqrt($init->{omeosq}); | 
| 6262 | 35 |  |  |  |  | 96 | $init->{cosio}= cos($parm->{inclination}); | 
| 6263 |  |  |  |  |  |  |  | 
| 6264 | 35 |  |  |  |  | 98 | $init->{cosio2}= $init->{cosio}*$init->{cosio}; | 
| 6265 |  |  |  |  |  |  | #* ---------------------- UN-KOZAI THE MEAN MOTION --------------------- | 
| 6266 | 35 |  |  |  |  | 160 | my $ak=  ($parm->{xke}/$parm->{meanmotion})**&SGP_TOTHRD; | 
| 6267 |  |  |  |  |  |  | my $d1=  0.75*$parm->{j2}* (3*$init->{cosio2}-1) / | 
| 6268 | 35 |  |  |  |  | 143 | ($init->{rteosq}*$init->{omeosq}); | 
| 6269 | 35 |  |  |  |  | 79 | my $del=  $d1/($ak*$ak); | 
| 6270 | 35 |  |  |  |  | 145 | my $adel=  $ak* ( 1 - $del*$del- $del* (1/3 + 134*$del*$del/ 81) ); | 
| 6271 | 35 |  |  |  |  | 95 | $del=  $d1/($adel*$adel); | 
| 6272 |  |  |  |  |  |  |  | 
| 6273 | 35 |  |  |  |  | 95 | $parm->{meanmotion}=  $parm->{meanmotion}/(1 + $del); | 
| 6274 | 35 |  |  |  |  | 149 | $init->{ao}=  ($parm->{xke}/$parm->{meanmotion})**&SGP_TOTHRD; | 
| 6275 | 35 |  |  |  |  | 122 | $init->{sinio}=  sin($parm->{inclination}); | 
| 6276 | 35 |  |  |  |  | 102 | my $po=  $init->{ao}*$init->{omeosq}; | 
| 6277 | 35 |  |  |  |  | 114 | $init->{con42}=  1-5*$init->{cosio2}; | 
| 6278 | 35 |  |  |  |  | 108 | $parm->{con41}=  -$init->{con42}-$init->{cosio2}-$init->{cosio2}; | 
| 6279 | 35 |  |  |  |  | 102 | $init->{ainv}=  1/$init->{ao}; | 
| 6280 | 35 |  |  |  |  | 82 | $init->{posq}=  $po*$po; | 
| 6281 | 35 |  |  |  |  | 100 | $init->{rp}=  $init->{ao}*(1-$parm->{eccentricity}); | 
| 6282 |  |  |  |  |  |  |  | 
| 6283 | 35 |  |  |  |  | 69 | $parm->{deep_space}=0; | 
| 6284 |  |  |  |  |  |  | #* ----------------- CALCULATE GREENWICH LOCATION AT EPOCH ------------- | 
| 6285 |  |  |  |  |  |  | #cdav new approach using JD | 
| 6286 | 35 |  |  |  |  | 92 | my $radperday= &SGP_TWOPI* 1.0027379093508; | 
| 6287 |  |  |  |  |  |  |  | 
| 6288 | 35 |  |  |  |  | 82 | my $temp= $self->{ds50}+ 2433281.5; | 
| 6289 | 35 |  |  |  |  | 107 | my $tut1= ( int($temp-0.5) + 0.5 - 2451545 ) / 36525; | 
| 6290 |  |  |  |  |  |  |  | 
| 6291 | 35 |  |  |  |  | 220 | $parm->{gsto}= 1.75336855923327 + 628.331970688841*$tut1+ | 
| 6292 |  |  |  |  |  |  | 6.77071394490334e-06*$tut1*$tut1- | 
| 6293 |  |  |  |  |  |  | 4.50876723431868e-10*$tut1*$tut1*$tut1+ $radperday*( | 
| 6294 |  |  |  |  |  |  | $temp-0.5-int($temp-0.5) ); | 
| 6295 | 35 |  |  |  |  | 160 | $parm->{gsto}= fmod($parm->{gsto}, &SGP_TWOPI); | 
| 6296 | 35 | 100 |  |  |  | 117 | if ( $parm->{gsto} <  0 ) { | 
| 6297 | 9 |  |  |  |  | 26 | $parm->{gsto}= $parm->{gsto}+ &SGP_TWOPI; | 
| 6298 |  |  |  |  |  |  |  | 
| 6299 |  |  |  |  |  |  | } | 
| 6300 |  |  |  |  |  |  | #*     CALCULATE NUMBER OF INTEGER DAYS SINCE 0 JAN 1970. | 
| 6301 |  |  |  |  |  |  | #cdav    old way | 
| 6302 |  |  |  |  |  |  | #c      TS70 =EPOCH-7305.D0 | 
| 6303 |  |  |  |  |  |  | #c      IDS70=TS70 + 1.D-8 | 
| 6304 |  |  |  |  |  |  | #c      DS70 =IDS70 | 
| 6305 |  |  |  |  |  |  | #c      TFRAC=TS70-DS70 | 
| 6306 |  |  |  |  |  |  | #*     CALCULATE GREENWICH LOCATION AT EPOCH | 
| 6307 |  |  |  |  |  |  | #c      C1    = 1.72027916940703639D-2 | 
| 6308 |  |  |  |  |  |  | #c      THGR70= 1.7321343856509374D0 | 
| 6309 |  |  |  |  |  |  | #c      FK5R  = 5.07551419432269442D-15 | 
| 6310 |  |  |  |  |  |  | #c      twopi = 6.283185307179586D0 | 
| 6311 |  |  |  |  |  |  | #c      C1P2P = C1+TWOPI | 
| 6312 |  |  |  |  |  |  | #c      THGR  = DMOD(THGR70+C1*DS70+C1P2P*TFRAC+TS70*TS70*FK5R,twopi) | 
| 6313 |  |  |  |  |  |  | #c      THGRO = DMOD(THGR,twopi) | 
| 6314 |  |  |  |  |  |  | #c      gsto  = thgro | 
| 6315 |  |  |  |  |  |  | #c      write(*,*) Satn,'  gst delta ', gsto-gsto1 | 
| 6316 |  |  |  |  |  |  |  | 
| 6317 |  |  |  |  |  |  | #c        INCLUDE 'debug5.for' | 
| 6318 |  |  |  |  |  |  |  | 
| 6319 | 35 |  |  |  |  | 93 | return; | 
| 6320 |  |  |  |  |  |  | } | 
| 6321 |  |  |  |  |  |  |  | 
| 6322 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 6323 |  |  |  |  |  |  | #* | 
| 6324 |  |  |  |  |  |  | #*                             SUBROUTINE SGP4INIT | 
| 6325 |  |  |  |  |  |  | #* | 
| 6326 |  |  |  |  |  |  | #*  This subroutine initializes variables for SGP4. | 
| 6327 |  |  |  |  |  |  | #* | 
| 6328 |  |  |  |  |  |  | #*  author        : david vallado                  719-573-2600   28 jun 2005 | 
| 6329 |  |  |  |  |  |  | #* | 
| 6330 |  |  |  |  |  |  | #*  inputs        : | 
| 6331 |  |  |  |  |  |  | #*    satn        - satellite number | 
| 6332 |  |  |  |  |  |  | #*    bstar       - sgp4 type drag coefficient              kg/m2er | 
| 6333 |  |  |  |  |  |  | #*    ecco        - eccentricity | 
| 6334 |  |  |  |  |  |  | #*    epoch       - epoch time in days from jan 0, 1950. 0 hr | 
| 6335 |  |  |  |  |  |  | #*    argpo       - argument of perigee (output if ds) | 
| 6336 |  |  |  |  |  |  | #*    inclo       - inclination | 
| 6337 |  |  |  |  |  |  | #*    mo          - mean anomaly (output if ds) | 
| 6338 |  |  |  |  |  |  | #*    no          - mean motion | 
| 6339 |  |  |  |  |  |  | #*    nodeo      - right ascension of ascending node | 
| 6340 |  |  |  |  |  |  | #* | 
| 6341 |  |  |  |  |  |  | #*  outputs       : | 
| 6342 |  |  |  |  |  |  | #*    satrec      - common block values for subsequent calls | 
| 6343 |  |  |  |  |  |  | #*    return code - non-zero on error. | 
| 6344 |  |  |  |  |  |  | #*                   1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er | 
| 6345 |  |  |  |  |  |  | #*                   2 - mean motion less than 0.0 | 
| 6346 |  |  |  |  |  |  | #*                   3 - pert elements, ecc < 0.0  or  ecc > 1.0 | 
| 6347 |  |  |  |  |  |  | #*                   4 - semi-latus rectum < 0.0 | 
| 6348 |  |  |  |  |  |  | #*                   5 - epoch elements are sub-orbital | 
| 6349 |  |  |  |  |  |  | #*                   6 - satellite has decayed | 
| 6350 |  |  |  |  |  |  | #* | 
| 6351 |  |  |  |  |  |  | #*  locals        : | 
| 6352 |  |  |  |  |  |  | #*    CNODM  , SNODM  , COSIM  , SINIM  , COSOMM , SINOMM | 
| 6353 |  |  |  |  |  |  | #*    Cc1sq  , Cc2    , Cc3 | 
| 6354 |  |  |  |  |  |  | #*    Coef   , Coef1 | 
| 6355 |  |  |  |  |  |  | #*    cosio4      - | 
| 6356 |  |  |  |  |  |  | #*    day         - | 
| 6357 |  |  |  |  |  |  | #*    dndt        - | 
| 6358 |  |  |  |  |  |  | #*    em          - eccentricity | 
| 6359 |  |  |  |  |  |  | #*    emsq        - eccentricity squared | 
| 6360 |  |  |  |  |  |  | #*    eeta        - | 
| 6361 |  |  |  |  |  |  | #*    etasq       - | 
| 6362 |  |  |  |  |  |  | #*    gam         - | 
| 6363 |  |  |  |  |  |  | #*    argpm       - argument of perigee | 
| 6364 |  |  |  |  |  |  | #*    ndem        - | 
| 6365 |  |  |  |  |  |  | #*    inclm       - inclination | 
| 6366 |  |  |  |  |  |  | #*    mm          - mean anomaly | 
| 6367 |  |  |  |  |  |  | #*    nm          - mean motion | 
| 6368 |  |  |  |  |  |  | #*    perige      - perigee | 
| 6369 |  |  |  |  |  |  | #*    pinvsq      - | 
| 6370 |  |  |  |  |  |  | #*    psisq       - | 
| 6371 |  |  |  |  |  |  | #*    qzms24      - | 
| 6372 |  |  |  |  |  |  | #*    rtemsq      - | 
| 6373 |  |  |  |  |  |  | #*    s1, s2, s3, s4, s5, s6, s7          - | 
| 6374 |  |  |  |  |  |  | #*    sfour       - | 
| 6375 |  |  |  |  |  |  | #*    ss1, ss2, ss3, ss4, ss5, ss6, ss7         - | 
| 6376 |  |  |  |  |  |  | #*    sz1, sz2, sz3 | 
| 6377 |  |  |  |  |  |  | #*    sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33        - | 
| 6378 |  |  |  |  |  |  | #*    tc          - | 
| 6379 |  |  |  |  |  |  | #*    temp        - | 
| 6380 |  |  |  |  |  |  | #*    temp1, temp2, temp3       - | 
| 6381 |  |  |  |  |  |  | #*    tsi         - | 
| 6382 |  |  |  |  |  |  | #*    xpidot      - | 
| 6383 |  |  |  |  |  |  | #*    xhdot1      - | 
| 6384 |  |  |  |  |  |  | #*    z1, z2, z3          - | 
| 6385 |  |  |  |  |  |  | #*    z11, z12, z13, z21, z22, z23, z31, z32, z33         - | 
| 6386 |  |  |  |  |  |  | #* | 
| 6387 |  |  |  |  |  |  | #*  coupling      : | 
| 6388 |  |  |  |  |  |  | #*    getgravconst- | 
| 6389 |  |  |  |  |  |  | #*    initl       - | 
| 6390 |  |  |  |  |  |  | #*    dscom       - | 
| 6391 |  |  |  |  |  |  | #*    dpper       - | 
| 6392 |  |  |  |  |  |  | #*    dsinit      - | 
| 6393 |  |  |  |  |  |  | #* | 
| 6394 |  |  |  |  |  |  | #*  references    : | 
| 6395 |  |  |  |  |  |  | #*    hoots, roehrich, norad spacetrack report #3 1980 | 
| 6396 |  |  |  |  |  |  | #*    hoots, norad spacetrack report #6 1986 | 
| 6397 |  |  |  |  |  |  | #*    hoots, schumacher and glover 2004 | 
| 6398 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 6399 |  |  |  |  |  |  | #* ---------------------------------------------------------------------------- } | 
| 6400 |  |  |  |  |  |  |  | 
| 6401 |  |  |  |  |  |  | sub _r_sgp4init { | 
| 6402 | 35 |  |  | 35 |  | 88 | my ($self) = @_; | 
| 6403 | 35 |  |  |  |  | 103 | my $oid = $self->get('id'); | 
| 6404 | 35 |  |  |  |  | 168 | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} = {}; | 
| 6405 | 35 |  |  |  |  | 116 | my $init = $parm->{init} = {}; | 
| 6406 |  |  |  |  |  |  | # The following is modified in _r_initl | 
| 6407 | 35 |  |  |  |  | 161 | $parm->{meanmotion} = $self->{meanmotion}; | 
| 6408 |  |  |  |  |  |  | # The following may be modified for deep space | 
| 6409 | 35 |  |  |  |  | 100 | $parm->{eccentricity} = $self->{eccentricity}; | 
| 6410 | 35 |  |  |  |  | 93 | $parm->{inclination} = $self->{inclination}; | 
| 6411 | 35 |  |  |  |  | 93 | $parm->{ascendingnode} = $self->{ascendingnode}; | 
| 6412 | 35 |  |  |  |  | 97 | $parm->{argumentofperigee} = $self->{argumentofperigee}; | 
| 6413 | 35 |  |  |  |  | 88 | $parm->{meananomaly} = $self->{meananomaly}; | 
| 6414 |  |  |  |  |  |  |  | 
| 6415 |  |  |  |  |  |  | #>>>>trw    my ($t, @r, @v); | 
| 6416 | 35 |  |  |  |  | 68 | my ($t); | 
| 6417 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'SGP4.CMN' | 
| 6418 |  |  |  |  |  |  |  | 
| 6419 |  |  |  |  |  |  | #* -------------------------- Local Variables -------------------------- | 
| 6420 |  |  |  |  |  |  |  | 
| 6421 | 35 |  |  |  |  | 149 | my ($cc1sq, $cc2, $cc3, $coef, $coef1, $cosio4, $eeta, $etasq, | 
| 6422 |  |  |  |  |  |  | $perige, $pinvsq, $psisq, $qzms24, $sfour, $tc, $temp, $temp1, | 
| 6423 |  |  |  |  |  |  | $temp2, $temp3, $tsi, $xhdot1); | 
| 6424 | 35 |  |  |  |  | 0 | my ($qzms2t, $ss, $temp4); | 
| 6425 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'ASTMATH.CMN' | 
| 6426 |  |  |  |  |  |  |  | 
| 6427 |  |  |  |  |  |  | #* ---------------------------- INITIALIZATION ------------------------- | 
| 6428 | 35 |  |  |  |  | 135 | $parm->{deep_space}=0; | 
| 6429 |  |  |  |  |  |  | #c       clear sgp4 flag | 
| 6430 |  |  |  |  |  |  |  | 
| 6431 | 35 |  |  |  |  | 138 | $self->{model_error}= &SGP4R_ERROR_0; | 
| 6432 |  |  |  |  |  |  | #c      sgp4fix - note the following variables are also passed directly via sgp4 common. | 
| 6433 |  |  |  |  |  |  | #c      it is possible to streamline the sgp4init call by deleting the "x" | 
| 6434 |  |  |  |  |  |  | #c      variables, but the user would need to set the common values first. we | 
| 6435 |  |  |  |  |  |  | #c      include the additional assignment in case twoline2rv is not used. | 
| 6436 |  |  |  |  |  |  |  | 
| 6437 |  |  |  |  |  |  | #>>>>trw	bstar  = xbstar | 
| 6438 |  |  |  |  |  |  | #>>>>trw	ecco   = xecco | 
| 6439 |  |  |  |  |  |  | #>>>>trw	argpo  = xargpo | 
| 6440 |  |  |  |  |  |  | #>>>>trw	inclo  = xinclo | 
| 6441 |  |  |  |  |  |  | #>>>>trw	mo     = xmo | 
| 6442 |  |  |  |  |  |  | #>>>>trw	no     = xno | 
| 6443 |  |  |  |  |  |  |  | 
| 6444 |  |  |  |  |  |  | #>>>>trw	nodeo  = xnodeo | 
| 6445 |  |  |  |  |  |  |  | 
| 6446 | 35 |  |  |  |  | 153 | $self->_r_getgravconst(); | 
| 6447 | 35 |  |  |  |  | 99 | $ss= 78/$parm->{radiusearthkm}+ 1; | 
| 6448 | 35 |  |  |  |  | 97 | $qzms2t= ((120-78)/$parm->{radiusearthkm}) ** 4; | 
| 6449 |  |  |  |  |  |  | #>>>>trw	X2o3   =  2.0D0 / 3.0D0 | 
| 6450 |  |  |  |  |  |  |  | 
| 6451 | 35 |  |  |  |  | 177 | $temp4=  1 + cos(&SGP_PI-1e-09); | 
| 6452 |  |  |  |  |  |  | #>>>>trw	Init = 'y' | 
| 6453 |  |  |  |  |  |  |  | 
| 6454 | 35 |  |  |  |  | 76 | $t= 0; | 
| 6455 |  |  |  |  |  |  |  | 
| 6456 | 35 | 50 |  |  |  | 126 | $self->{eccentricity} > 1 | 
| 6457 |  |  |  |  |  |  | and croak "Error - OID $oid Sgp4r TLE eccentricity > 1"; | 
| 6458 | 35 | 50 |  |  |  | 130 | $self->{eccentricity} < 0 | 
| 6459 |  |  |  |  |  |  | and croak "Error - OID $oid Sgp4r TLE eccentricity < 0"; | 
| 6460 | 35 | 50 |  |  |  | 100 | $self->{meanmotion} < 0 | 
| 6461 |  |  |  |  |  |  | and croak "Error - OID $oid Sgp4r TLE mean motion < 0"; | 
| 6462 | 35 |  |  |  |  | 151 | $self->_r_initl(); | 
| 6463 | 35 | 100 |  |  |  | 117 | if ($init->{rp} <  1) { | 
| 6464 |  |  |  |  |  |  | #c            Write(*,*) '# *** SATN',Satn,' EPOCH ELTS SUB-ORBITAL *** ' | 
| 6465 | 1 |  |  |  |  | 6 | $self->{model_error}= &SGP4R_ERROR_5; | 
| 6466 |  |  |  |  |  |  |  | 
| 6467 |  |  |  |  |  |  | } | 
| 6468 | 35 | 50 | 33 |  |  | 132 | if ($init->{omeosq} >=  0  ||  $parm->{meanmotion} >=  0) { | 
| 6469 | 35 |  |  |  |  | 92 | $parm->{isimp}= 0; | 
| 6470 | 35 | 100 |  |  |  | 150 | if ($init->{rp} <  (220/$parm->{radiusearthkm}+1)) { | 
| 6471 | 16 |  |  |  |  | 35 | $parm->{isimp}= 1; | 
| 6472 |  |  |  |  |  |  | } | 
| 6473 | 35 |  |  |  |  | 64 | $sfour= $ss; | 
| 6474 | 35 |  |  |  |  | 70 | $qzms24= $qzms2t; | 
| 6475 |  |  |  |  |  |  |  | 
| 6476 | 35 |  |  |  |  | 84 | $perige= ($init->{rp}-1)*$parm->{radiusearthkm}; | 
| 6477 |  |  |  |  |  |  | #* ----------- For perigees below 156 km, S and Qoms2t are altered ----- | 
| 6478 | 35 | 100 |  |  |  | 106 | if ($perige <  156) { | 
| 6479 | 9 |  |  |  |  | 37 | $sfour= $perige-78; | 
| 6480 | 9 | 100 |  |  |  | 43 | if ($perige <=  98) { | 
| 6481 | 3 |  |  |  |  | 8 | $sfour= 20; | 
| 6482 |  |  |  |  |  |  | } | 
| 6483 | 9 |  |  |  |  | 35 | $qzms24= ( (120-$sfour)/$parm->{radiusearthkm})**4; | 
| 6484 | 9 |  |  |  |  | 26 | $sfour= $sfour/$parm->{radiusearthkm}+ 1; | 
| 6485 |  |  |  |  |  |  | } | 
| 6486 |  |  |  |  |  |  |  | 
| 6487 | 35 |  |  |  |  | 81 | $pinvsq= 1/$init->{posq}; | 
| 6488 | 35 |  |  |  |  | 84 | $tsi= 1/($init->{ao}-$sfour); | 
| 6489 | 35 |  |  |  |  | 120 | $parm->{eta}= $init->{ao}*$parm->{eccentricity}*$tsi; | 
| 6490 | 35 |  |  |  |  | 77 | $etasq= $parm->{eta}*$parm->{eta}; | 
| 6491 | 35 |  |  |  |  | 63 | $eeta= $parm->{eccentricity}*$parm->{eta}; | 
| 6492 | 35 |  |  |  |  | 70 | $psisq= abs(1-$etasq); | 
| 6493 | 35 |  |  |  |  | 85 | $coef= $qzms24*$tsi**4; | 
| 6494 | 35 |  |  |  |  | 93 | $coef1= $coef/$psisq**3.5; | 
| 6495 |  |  |  |  |  |  | $cc2= $coef1*$parm->{meanmotion}* ($init->{ao}* | 
| 6496 |  |  |  |  |  |  | (1+1.5*$etasq+$eeta* (4+$etasq) )+0.375* | 
| 6497 | 35 |  |  |  |  | 180 | $parm->{j2}*$tsi/$psisq*$parm->{con41}*(8+3*$etasq*(8+$etasq))); | 
| 6498 | 35 |  |  |  |  | 92 | $parm->{cc1}= $self->{bstardrag}*$cc2; | 
| 6499 | 35 |  |  |  |  | 62 | $cc3= 0; | 
| 6500 | 35 | 100 |  |  |  | 99 | if ($parm->{eccentricity} >  0.0001) { | 
| 6501 |  |  |  |  |  |  | $cc3= | 
| 6502 |  |  |  |  |  |  | -2*$coef*$tsi*$parm->{j3oj2}*$parm->{meanmotion}* | 
| 6503 | 33 |  |  |  |  | 117 | $init->{sinio}/$parm->{eccentricity}; | 
| 6504 |  |  |  |  |  |  | } | 
| 6505 | 35 |  |  |  |  | 108 | $parm->{x1mth2}= 1-$init->{cosio2}; | 
| 6506 |  |  |  |  |  |  | $parm->{cc4}= | 
| 6507 |  |  |  |  |  |  | 2*$parm->{meanmotion}*$coef1*$init->{ao}*$init->{omeosq}* | 
| 6508 |  |  |  |  |  |  | ($parm->{eta}*(2+0.5*$etasq) | 
| 6509 |  |  |  |  |  |  | +$parm->{eccentricity}*(0.5 + 2*$etasq) - $parm->{j2}*$tsi/ | 
| 6510 |  |  |  |  |  |  | ($init->{ao}*$psisq)* (-3*$parm->{con41}*(1-2* | 
| 6511 |  |  |  |  |  |  | $eeta+$etasq*(1.5-0.5*$eeta))+0.75*$parm->{x1mth2}* | 
| 6512 | 35 |  |  |  |  | 277 | (2*$etasq-$eeta*(1+$etasq))*cos(2*$parm->{argumentofperigee}))); | 
| 6513 | 35 |  |  |  |  | 134 | $parm->{cc5}= 2*$coef1*$init->{ao}*$init->{omeosq}* (1 + 2.75* | 
| 6514 |  |  |  |  |  |  | ($etasq+ $eeta) + $eeta*$etasq); | 
| 6515 | 35 |  |  |  |  | 90 | $cosio4= $init->{cosio2}*$init->{cosio2}; | 
| 6516 | 35 |  |  |  |  | 87 | $temp1= 1.5*$parm->{j2}*$pinvsq*$parm->{meanmotion}; | 
| 6517 | 35 |  |  |  |  | 95 | $temp2= 0.5*$temp1*$parm->{j2}*$pinvsq; | 
| 6518 |  |  |  |  |  |  | $temp3= | 
| 6519 | 35 |  |  |  |  | 125 | -0.46875*$parm->{j4}*$pinvsq*$pinvsq*$parm->{meanmotion}; | 
| 6520 |  |  |  |  |  |  | $parm->{mdot}= $parm->{meanmotion}+ | 
| 6521 |  |  |  |  |  |  | 0.5*$temp1*$init->{rteosq}*$parm->{con41}+ 0.0625*$temp2* | 
| 6522 | 35 |  |  |  |  | 178 | $init->{rteosq}*(13 - 78*$init->{cosio2}+ 137*$cosio4); | 
| 6523 |  |  |  |  |  |  | $parm->{argpdot}= -0.5*$temp1*$init->{con42}+ 0.0625*$temp2* (7 | 
| 6524 |  |  |  |  |  |  | - 114*$init->{cosio2}+ | 
| 6525 | 35 |  |  |  |  | 168 | 395*$cosio4)+$temp3*(3-36*$init->{cosio2}+49*$cosio4); | 
| 6526 | 35 |  |  |  |  | 73 | $xhdot1= -$temp1*$init->{cosio}; | 
| 6527 |  |  |  |  |  |  | $parm->{nodedot}= $xhdot1+(0.5*$temp2*(4-19*$init->{cosio2})+ | 
| 6528 | 35 |  |  |  |  | 172 | 2*$temp3*(3 - 7*$init->{cosio2}))*$init->{cosio}; | 
| 6529 | 35 |  |  |  |  | 83 | $init->{xpidot}= $parm->{argpdot}+$parm->{nodedot}; | 
| 6530 |  |  |  |  |  |  | $parm->{omgcof}= | 
| 6531 | 35 |  |  |  |  | 109 | $self->{bstardrag}*$cc3*cos($parm->{argumentofperigee}); | 
| 6532 | 35 |  |  |  |  | 103 | $parm->{xmcof}= 0; | 
| 6533 | 35 | 100 |  |  |  | 122 | if ($parm->{eccentricity} >  0.0001) { | 
| 6534 | 33 |  |  |  |  | 142 | $parm->{xmcof}= -&SGP_TOTHRD*$coef*$self->{bstardrag}/$eeta; | 
| 6535 |  |  |  |  |  |  | } | 
| 6536 | 35 |  |  |  |  | 112 | $parm->{xnodcf}= 3.5*$init->{omeosq}*$xhdot1*$parm->{cc1}; | 
| 6537 | 35 |  |  |  |  | 101 | $parm->{t2cof}= 1.5*$parm->{cc1}; | 
| 6538 |  |  |  |  |  |  | #c           sgp4fix for divide by zero with xinco = 180 deg | 
| 6539 | 35 | 50 |  |  |  | 150 | if (abs($init->{cosio}+1) >  1.5e-12) { | 
| 6540 |  |  |  |  |  |  | $parm->{xlcof}= -0.25*$parm->{j3oj2}*$init->{sinio}* | 
| 6541 | 35 |  |  |  |  | 219 | (3+5*$init->{cosio})/(1+$init->{cosio}); | 
| 6542 |  |  |  |  |  |  | } else { | 
| 6543 |  |  |  |  |  |  | $parm->{xlcof}= -0.25*$parm->{j3oj2}*$init->{sinio}* | 
| 6544 | 0 |  |  |  |  | 0 | (3+5*$init->{cosio})/$temp4; | 
| 6545 |  |  |  |  |  |  | } | 
| 6546 | 35 |  |  |  |  | 126 | $parm->{aycof}= -0.5*$parm->{j3oj2}*$init->{sinio}; | 
| 6547 | 35 |  |  |  |  | 136 | $parm->{delmo}= (1+$parm->{eta}*cos($parm->{meananomaly}))**3; | 
| 6548 | 35 |  |  |  |  | 110 | $parm->{sinmao}= sin($parm->{meananomaly}); | 
| 6549 |  |  |  |  |  |  |  | 
| 6550 | 35 |  |  |  |  | 122 | $parm->{x7thm1}= 7*$init->{cosio2}-1; | 
| 6551 |  |  |  |  |  |  | #* ------------------------ Deep Space Initialization ------------------ | 
| 6552 | 35 | 100 |  |  |  | 135 | if ((&SGP_TWOPI/$parm->{meanmotion})  >=  225) { | 
| 6553 | 23 |  |  |  |  | 64 | $parm->{deep_space}=1; | 
| 6554 | 23 |  |  |  |  | 44 | $parm->{isimp}= 1; | 
| 6555 | 23 |  |  |  |  | 52 | $tc= 0; | 
| 6556 | 23 |  |  |  |  | 60 | $init->{inclm}= $parm->{inclination}; | 
| 6557 | 23 |  |  |  |  | 119 | $self->_r_dscom ($tc); | 
| 6558 |  |  |  |  |  |  |  | 
| 6559 |  |  |  |  |  |  | $self->_r_dpper ($t, \$parm->{eccentricity}, | 
| 6560 |  |  |  |  |  |  | \$parm->{inclination}, \$parm->{ascendingnode}, | 
| 6561 | 23 |  |  |  |  | 144 | \$parm->{argumentofperigee}, \$parm->{meananomaly}); | 
| 6562 | 23 |  |  |  |  | 148 | $init->{argpm}= 0; | 
| 6563 | 23 |  |  |  |  | 65 | $init->{nodem}= 0; | 
| 6564 |  |  |  |  |  |  |  | 
| 6565 | 23 |  |  |  |  | 56 | $init->{mm}= 0; | 
| 6566 | 23 |  |  |  |  | 83 | $self->_r_dsinit ($t, $tc); | 
| 6567 |  |  |  |  |  |  |  | 
| 6568 |  |  |  |  |  |  | } | 
| 6569 |  |  |  |  |  |  | #* ------------ Set variables if not deep space or rp < 220 ------------- | 
| 6570 | 35 | 100 |  |  |  | 138 | if ( !  $parm->{isimp}) { | 
| 6571 | 4 |  |  |  |  | 10 | $cc1sq= $parm->{cc1}*$parm->{cc1}; | 
| 6572 | 4 |  |  |  |  | 12 | $parm->{d2}= 4*$init->{ao}*$tsi*$cc1sq; | 
| 6573 | 4 |  |  |  |  | 11 | $temp= $parm->{d2}*$tsi*$parm->{cc1}/ 3; | 
| 6574 | 4 |  |  |  |  | 13 | $parm->{d3}= (17*$init->{ao}+ $sfour) * $temp; | 
| 6575 |  |  |  |  |  |  | $parm->{d4}= 0.5*$temp*$init->{ao}*$tsi* (221*$init->{ao}+ | 
| 6576 | 4 |  |  |  |  | 16 | 31*$sfour)*$parm->{cc1}; | 
| 6577 | 4 |  |  |  |  | 12 | $parm->{t3cof}= $parm->{d2}+ 2*$cc1sq; | 
| 6578 |  |  |  |  |  |  | $parm->{t4cof}= 0.25* | 
| 6579 | 4 |  |  |  |  | 16 | (3*$parm->{d3}+$parm->{cc1}*(12*$parm->{d2}+10*$cc1sq) | 
| 6580 |  |  |  |  |  |  | ); | 
| 6581 |  |  |  |  |  |  | $parm->{t5cof}= 0.2* (3*$parm->{d4}+ | 
| 6582 |  |  |  |  |  |  | 12*$parm->{cc1}*$parm->{d3}+ 6*$parm->{d2}*$parm->{d2}+ | 
| 6583 | 4 |  |  |  |  | 25 | 15*$cc1sq* (2*$parm->{d2}+ $cc1sq) ); | 
| 6584 |  |  |  |  |  |  |  | 
| 6585 |  |  |  |  |  |  | } | 
| 6586 |  |  |  |  |  |  |  | 
| 6587 |  |  |  |  |  |  | } | 
| 6588 |  |  |  |  |  |  |  | 
| 6589 |  |  |  |  |  |  | #>>>>trw	init = 'n' | 
| 6590 |  |  |  |  |  |  |  | 
| 6591 |  |  |  |  |  |  | #>>>>trw	CALL SGP4(whichconst, 0.0D0, r, v, error) | 
| 6592 |  |  |  |  |  |  | #c        INCLUDE 'debug6.for' | 
| 6593 |  |  |  |  |  |  |  | 
| 6594 |  |  |  |  |  |  | #>>>>trw	RETURN | 
| 6595 |  |  |  |  |  |  |  | 
| 6596 | 35 |  |  |  |  | 82 | delete $parm->{init}; | 
| 6597 | 35 |  |  |  |  | 292 | return $parm; | 
| 6598 |  |  |  |  |  |  | } | 
| 6599 |  |  |  |  |  |  |  | 
| 6600 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 6601 |  |  |  |  |  |  | #* | 
| 6602 |  |  |  |  |  |  | #*                             SUBROUTINE SGP4 | 
| 6603 |  |  |  |  |  |  | #* | 
| 6604 |  |  |  |  |  |  | #*  this procedure is the sgp4 prediction model from space command. this is an | 
| 6605 |  |  |  |  |  |  | #*    updated and combined version of sgp4 and sdp4, which were originally | 
| 6606 |  |  |  |  |  |  | #*    published separately in spacetrack report #3. this version follows the | 
| 6607 |  |  |  |  |  |  | #*    methodology from the aiaa paper (2006) describing the history and | 
| 6608 |  |  |  |  |  |  | #*    development of the code. | 
| 6609 |  |  |  |  |  |  | #* | 
| 6610 |  |  |  |  |  |  | #*  author        : david vallado                  719-573-2600   28 jun 2005 | 
| 6611 |  |  |  |  |  |  | #* | 
| 6612 |  |  |  |  |  |  | #*  inputs        : | 
| 6613 |  |  |  |  |  |  | #*    satrec      - initialised structure from sgp4init() call. | 
| 6614 |  |  |  |  |  |  | #*    tsince      - time eince epoch (minutes) | 
| 6615 |  |  |  |  |  |  | #* | 
| 6616 |  |  |  |  |  |  | #*  outputs       : | 
| 6617 |  |  |  |  |  |  | #*    r           - position vector                     km | 
| 6618 |  |  |  |  |  |  | #*    v           - velocity                            km/sec | 
| 6619 |  |  |  |  |  |  | #*  return code - non-zero on error. | 
| 6620 |  |  |  |  |  |  | #*                   1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er | 
| 6621 |  |  |  |  |  |  | #*                   2 - mean motion less than 0.0 | 
| 6622 |  |  |  |  |  |  | #*                   3 - pert elements, ecc < 0.0  or  ecc > 1.0 | 
| 6623 |  |  |  |  |  |  | #*                   4 - semi-latus rectum < 0.0 | 
| 6624 |  |  |  |  |  |  | #*                   5 - epoch elements are sub-orbital | 
| 6625 |  |  |  |  |  |  | #*                   6 - satellite has decayed | 
| 6626 |  |  |  |  |  |  | #* | 
| 6627 |  |  |  |  |  |  | #*  locals        : | 
| 6628 |  |  |  |  |  |  | #*    am          - | 
| 6629 |  |  |  |  |  |  | #*    axnl, aynl        - | 
| 6630 |  |  |  |  |  |  | #*    betal       - | 
| 6631 |  |  |  |  |  |  | #*    COSIM   , SINIM   , COSOMM  , SINOMM  , Cnod    , Snod    , Cos2u   , | 
| 6632 |  |  |  |  |  |  | #*    Sin2u   , Coseo1  , Sineo1  , Cosi    , Sini    , Cosip   , Sinip   , | 
| 6633 |  |  |  |  |  |  | #*    Cosisq  , Cossu   , Sinsu   , Cosu    , Sinu | 
| 6634 |  |  |  |  |  |  | #*    Delm        - | 
| 6635 |  |  |  |  |  |  | #*    Delomg      - | 
| 6636 |  |  |  |  |  |  | #*    Dndt        - | 
| 6637 |  |  |  |  |  |  | #*    Eccm        - | 
| 6638 |  |  |  |  |  |  | #*    EMSQ        - | 
| 6639 |  |  |  |  |  |  | #*    Ecose       - | 
| 6640 |  |  |  |  |  |  | #*    El2         - | 
| 6641 |  |  |  |  |  |  | #*    Eo1         - | 
| 6642 |  |  |  |  |  |  | #*    Eccp        - | 
| 6643 |  |  |  |  |  |  | #*    Esine       - | 
| 6644 |  |  |  |  |  |  | #*    Argpm       - | 
| 6645 |  |  |  |  |  |  | #*    Argpp       - | 
| 6646 |  |  |  |  |  |  | #*    Omgadf      - | 
| 6647 |  |  |  |  |  |  | #*    Pl          - | 
| 6648 |  |  |  |  |  |  | #*    R           - | 
| 6649 |  |  |  |  |  |  | #*    RTEMSQ      - | 
| 6650 |  |  |  |  |  |  | #*    Rdotl       - | 
| 6651 |  |  |  |  |  |  | #*    Rl          - | 
| 6652 |  |  |  |  |  |  | #*    Rvdot       - | 
| 6653 |  |  |  |  |  |  | #*    Rvdotl      - | 
| 6654 |  |  |  |  |  |  | #*    Su          - | 
| 6655 |  |  |  |  |  |  | #*    T2  , T3   , T4    , Tc | 
| 6656 |  |  |  |  |  |  | #*    Tem5, Temp , Temp1 , Temp2  , Tempa  , Tempe  , Templ | 
| 6657 |  |  |  |  |  |  | #*    U   , Ux   , Uy    , Uz     , Vx     , Vy     , Vz | 
| 6658 |  |  |  |  |  |  | #*    inclm       - inclination | 
| 6659 |  |  |  |  |  |  | #*    mm          - mean anomaly | 
| 6660 |  |  |  |  |  |  | #*    nm          - mean motion | 
| 6661 |  |  |  |  |  |  | #*    nodem       - longi of ascending node | 
| 6662 |  |  |  |  |  |  | #*    xinc        - | 
| 6663 |  |  |  |  |  |  | #*    xincp       - | 
| 6664 |  |  |  |  |  |  | #*    xl          - | 
| 6665 |  |  |  |  |  |  | #*    xlm         - | 
| 6666 |  |  |  |  |  |  | #*    mp          - | 
| 6667 |  |  |  |  |  |  | #*    xmdf        - | 
| 6668 |  |  |  |  |  |  | #*    xmx         - | 
| 6669 |  |  |  |  |  |  | #*    xmy         - | 
| 6670 |  |  |  |  |  |  | #*    nodedf     - | 
| 6671 |  |  |  |  |  |  | #*    xnode       - | 
| 6672 |  |  |  |  |  |  | #*    nodep      - | 
| 6673 |  |  |  |  |  |  | #*    np          - | 
| 6674 |  |  |  |  |  |  | #* | 
| 6675 |  |  |  |  |  |  | #*  coupling      : | 
| 6676 |  |  |  |  |  |  | #*    getgravconst- | 
| 6677 |  |  |  |  |  |  | #*    dpper | 
| 6678 |  |  |  |  |  |  | #*    dpspace | 
| 6679 |  |  |  |  |  |  | #* | 
| 6680 |  |  |  |  |  |  | #*  references    : | 
| 6681 |  |  |  |  |  |  | #*    hoots, roehrich, norad spacetrack report #3 1980 | 
| 6682 |  |  |  |  |  |  | #*    hoots, norad spacetrack report #6 1986 | 
| 6683 |  |  |  |  |  |  | #*    hoots, schumacher and glover 2004 | 
| 6684 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 6685 |  |  |  |  |  |  | #*------------------------------------------------------------------------------ | 
| 6686 |  |  |  |  |  |  |  | 
| 6687 |  |  |  |  |  |  | sub sgp4r { | 
| 6688 | 18820 |  |  | 18820 | 1 | 38489 | my ($self, $t) = @_; | 
| 6689 | 18820 |  |  |  |  | 36192 | my $oid = $self->get('id'); | 
| 6690 | 18820 |  | 66 |  |  | 72314 | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} ||= $self->_r_sgp4init (); | 
| 6691 | 18820 |  |  |  |  | 29260 | my $time = $t; | 
| 6692 | 18820 |  |  |  |  | 37334 | $t = ($t - $self->{epoch}) / 60; | 
| 6693 |  |  |  |  |  |  |  | 
| 6694 | 18820 |  |  |  |  | 83405 | my (@r, @v); | 
| 6695 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'SGP4.CMN' | 
| 6696 |  |  |  |  |  |  |  | 
| 6697 |  |  |  |  |  |  | #* -------------------------- Local Variables -------------------------- | 
| 6698 |  |  |  |  |  |  |  | 
| 6699 | 18820 |  |  |  |  | 0 | my ($am, $axnl, $aynl, $betal, $cosim, $cnod, $cos2u, $coseo1, | 
| 6700 |  |  |  |  |  |  | $cosi, $cosip, $cosisq, $cossu, $cosu, $delm, $delomg, $eccm, | 
| 6701 |  |  |  |  |  |  | $emsq, $ecose, $el2, $eo1, $eccp, $esine, $argpm, $argpp, | 
| 6702 |  |  |  |  |  |  | $omgadf, $pl, $rdotl, $rl, $rvdot, $rvdotl, $sinim, $sin2u, | 
| 6703 |  |  |  |  |  |  | $sineo1, $sini, $sinip, $sinsu, $sinu, $snod, $su, $t2, $t3, | 
| 6704 |  |  |  |  |  |  | $t4, $tem5, $temp, $temp1, $temp2, $tempa, $tempe, $templ, $u, | 
| 6705 |  |  |  |  |  |  | $ux, $uy, $uz, $vx, $vy, $vz, $inclm, $mm, $xn, $nodem, $xinc, | 
| 6706 |  |  |  |  |  |  | $xincp, $xl, $xlm, $mp, $xmdf, $xmx, $xmy, $xnoddf, $xnode, | 
| 6707 |  |  |  |  |  |  | $nodep, $tc, $dndt); | 
| 6708 | 18820 |  |  |  |  | 0 | my ($mr, $mv, $vkmpersec, $temp4); | 
| 6709 |  |  |  |  |  |  |  | 
| 6710 | 18820 |  |  |  |  | 0 | my ($iter); | 
| 6711 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'ASTMATH.CMN' | 
| 6712 |  |  |  |  |  |  |  | 
| 6713 |  |  |  |  |  |  | #* ------------------------ WGS-72 EARTH CONSTANTS --------------------- | 
| 6714 |  |  |  |  |  |  | #* ---------------------- SET MATHEMATICAL CONSTANTS ------------------- | 
| 6715 |  |  |  |  |  |  |  | 
| 6716 |  |  |  |  |  |  | #>>>>trw	X2O3   = 2.0D0/3.0D0 | 
| 6717 |  |  |  |  |  |  | #c     Keep compiler ok for warnings on uninitialized variables | 
| 6718 | 18820 |  |  |  |  | 26759 | $mr= 0; | 
| 6719 | 18820 |  |  |  |  | 25869 | $coseo1= 1; | 
| 6720 |  |  |  |  |  |  |  | 
| 6721 | 18820 |  |  |  |  | 24780 | $sineo1= 0; | 
| 6722 |  |  |  |  |  |  | #>>>>trw	CALL getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ) | 
| 6723 | 18820 |  |  |  |  | 55788 | $temp4=   1 + cos(&SGP_PI-1e-09); | 
| 6724 |  |  |  |  |  |  |  | 
| 6725 | 18820 |  |  |  |  | 38205 | $vkmpersec=  $parm->{radiusearthkm}* $parm->{xke}/60; | 
| 6726 |  |  |  |  |  |  | #* ------------------------- CLEAR SGP4 ERROR FLAG --------------------- | 
| 6727 |  |  |  |  |  |  |  | 
| 6728 | 18820 |  |  |  |  | 40487 | $self->{model_error}= &SGP4R_ERROR_0; | 
| 6729 |  |  |  |  |  |  | #* ----------- UPDATE FOR SECULAR GRAVITY AND ATMOSPHERIC DRAG --------- | 
| 6730 | 18820 |  |  |  |  | 34390 | $xmdf= $parm->{meananomaly}+ $parm->{mdot}*$t; | 
| 6731 | 18820 |  |  |  |  | 35689 | $omgadf= $parm->{argumentofperigee}+ $parm->{argpdot}*$t; | 
| 6732 | 18820 |  |  |  |  | 28857 | $xnoddf= $parm->{ascendingnode}+ $parm->{nodedot}*$t; | 
| 6733 | 18820 |  |  |  |  | 26191 | $argpm= $omgadf; | 
| 6734 | 18820 |  |  |  |  | 25581 | $mm= $xmdf; | 
| 6735 | 18820 |  |  |  |  | 24512 | $t2= $t*$t; | 
| 6736 | 18820 |  |  |  |  | 29875 | $nodem= $xnoddf+ $parm->{xnodcf}*$t2; | 
| 6737 | 18820 |  |  |  |  | 31405 | $tempa= 1 - $parm->{cc1}*$t; | 
| 6738 | 18820 |  |  |  |  | 30825 | $tempe= $self->{bstardrag}*$parm->{cc4}*$t; | 
| 6739 | 18820 |  |  |  |  | 27000 | $templ= $parm->{t2cof}*$t2; | 
| 6740 | 18820 | 100 |  |  |  | 36129 | if ( !  $parm->{isimp}) { | 
| 6741 | 85 |  |  |  |  | 135 | $delomg= $parm->{omgcof}*$t; | 
| 6742 |  |  |  |  |  |  | $delm= $parm->{xmcof}*(( 1+$parm->{eta}*cos($xmdf) | 
| 6743 | 85 |  |  |  |  | 320 | )**3-$parm->{delmo}); | 
| 6744 | 85 |  |  |  |  | 134 | $temp= $delomg+ $delm; | 
| 6745 | 85 |  |  |  |  | 127 | $mm= $xmdf+ $temp; | 
| 6746 | 85 |  |  |  |  | 113 | $argpm= $omgadf- $temp; | 
| 6747 | 85 |  |  |  |  | 129 | $t3= $t2*$t; | 
| 6748 | 85 |  |  |  |  | 132 | $t4= $t3*$t; | 
| 6749 |  |  |  |  |  |  | $tempa= $tempa- $parm->{d2}*$t2- $parm->{d3}*$t3- | 
| 6750 | 85 |  |  |  |  | 189 | $parm->{d4}*$t4; | 
| 6751 |  |  |  |  |  |  | $tempe= $tempe+ $self->{bstardrag}*$parm->{cc5}*(sin($mm) - | 
| 6752 | 85 |  |  |  |  | 210 | $parm->{sinmao}); | 
| 6753 |  |  |  |  |  |  | $templ= $templ+ $parm->{t3cof}*$t3+ $t4*($parm->{t4cof}+ | 
| 6754 | 85 |  |  |  |  | 242 | $t*$parm->{t5cof}); | 
| 6755 |  |  |  |  |  |  | } | 
| 6756 | 18820 |  |  |  |  | 28758 | $xn= $parm->{meanmotion}; | 
| 6757 | 18820 |  |  |  |  | 28001 | $eccm= $parm->{eccentricity}; | 
| 6758 | 18820 |  |  |  |  | 26505 | $inclm= $parm->{inclination}; | 
| 6759 | 18820 | 100 |  |  |  | 36176 | if ($parm->{deep_space}) { | 
| 6760 | 397 |  |  |  |  | 594 | $tc= $t; | 
| 6761 |  |  |  |  |  |  | $self->_r_dspace ($t, $tc, \$parm->{atime}, \$eccm, \$argpm, | 
| 6762 | 397 |  |  |  |  | 2085 | \$inclm, \$parm->{xli}, \$mm, \$parm->{xni}, \$nodem, | 
| 6763 |  |  |  |  |  |  | \$dndt, \$xn); | 
| 6764 |  |  |  |  |  |  |  | 
| 6765 |  |  |  |  |  |  | } | 
| 6766 |  |  |  |  |  |  | #c     mean motion less than 0.0 | 
| 6767 | 18820 | 50 |  |  |  | 36598 | if ($xn <=  0) { | 
| 6768 | 0 |  |  |  |  | 0 | $self->{model_error}= &SGP4R_ERROR_2; | 
| 6769 | 0 |  |  |  |  | 0 | croak "Error - OID $oid ", &SGP4R_ERROR_MEAN_MOTION; | 
| 6770 |  |  |  |  |  |  | } | 
| 6771 | 18820 |  |  |  |  | 58783 | $am= ($parm->{xke}/$xn)**&SGP_TOTHRD*$tempa**2; | 
| 6772 | 18820 |  |  |  |  | 35813 | $xn= $parm->{xke}/$am**1.5; | 
| 6773 | 18820 |  |  |  |  | 26536 | $eccm= $eccm-$tempe; | 
| 6774 |  |  |  |  |  |  | $self->{debug} | 
| 6775 | 18820 | 50 |  |  |  | 37530 | and warn "Debug - OID $oid sgp4r effective eccentricity $eccm\n"; | 
| 6776 |  |  |  |  |  |  | #c   fix tolerance for error recognition | 
| 6777 | 18820 | 100 | 66 |  |  | 88194 | if ($eccm >=  1  ||  $eccm < -0.001  ||  $am <  0.95) { | 
|  |  |  | 66 |  |  |  |  | 
| 6778 |  |  |  |  |  |  | #c         write(6,*) '# Error 1, Eccm = ',  Eccm, ' AM = ', AM | 
| 6779 | 4 |  |  |  |  | 12 | $self->{model_error} = &SGP4R_ERROR_1; | 
| 6780 | 4 |  |  |  |  | 7 | my $tfmt = '%d-%b-%Y %H:%M:%S'; | 
| 6781 | 4 |  |  |  |  | 19 | my @data = "Error - OID $oid " . &SGP4R_ERROR_MEAN_ECCEN; | 
| 6782 | 4 |  |  |  |  | 51 | push @data, "eccentricity = $eccm"; | 
| 6783 | 4 |  |  |  |  | 10 | foreach my $thing (qw{universal epoch effective}) { | 
| 6784 | 12 | 100 |  |  |  | 65 | if (defined ( my $value = $self->can($thing) ? | 
|  |  | 100 |  |  |  |  |  | 
| 6785 |  |  |  |  |  |  | $self->$thing() : | 
| 6786 |  |  |  |  |  |  | $self->get($thing))) { | 
| 6787 | 8 |  |  |  |  | 13 | local $@ = undef; | 
| 6788 | 8 |  |  |  |  | 15 | my $diag = eval { | 
| 6789 | 8 |  |  |  |  | 328 | strftime( "$thing = $tfmt", gmtime $value ) }; | 
| 6790 | 8 | 50 |  |  |  | 26 | defined $diag or $diag = "$thing = $value"; | 
| 6791 | 8 |  |  |  |  | 28 | push @data, $diag; | 
| 6792 |  |  |  |  |  |  | } else { | 
| 6793 | 4 |  |  |  |  | 14 | push @data, "$thing is undefined"; | 
| 6794 |  |  |  |  |  |  | } | 
| 6795 |  |  |  |  |  |  | } | 
| 6796 | 4 |  |  |  |  | 868 | croak join '; ', @data | 
| 6797 |  |  |  |  |  |  | } | 
| 6798 | 18816 | 100 |  |  |  | 35128 | if ($eccm <  0) { | 
| 6799 | 5 |  |  |  |  | 12 | $eccm= 1e-06 | 
| 6800 |  |  |  |  |  |  | } | 
| 6801 | 18816 |  |  |  |  | 30532 | $mm= $mm+$parm->{meanmotion}*$templ; | 
| 6802 | 18816 |  |  |  |  | 26639 | $xlm= $mm+$argpm+$nodem; | 
| 6803 | 18816 |  |  |  |  | 25059 | $emsq= $eccm*$eccm; | 
| 6804 | 18816 |  |  |  |  | 26652 | $temp= 1 - $emsq; | 
| 6805 | 18816 |  |  |  |  | 51954 | $nodem= fmod($nodem, &SGP_TWOPI); | 
| 6806 | 18816 |  |  |  |  | 37467 | $argpm= fmod($argpm, &SGP_TWOPI); | 
| 6807 | 18816 |  |  |  |  | 40043 | $xlm= fmod($xlm, &SGP_TWOPI); | 
| 6808 |  |  |  |  |  |  |  | 
| 6809 | 18816 |  |  |  |  | 43411 | $mm= fmod($xlm- $argpm- $nodem, &SGP_TWOPI); | 
| 6810 |  |  |  |  |  |  | #* --------------------- COMPUTE EXTRA MEAN QUANTITIES ----------------- | 
| 6811 | 18816 |  |  |  |  | 31493 | $sinim= sin($inclm); | 
| 6812 |  |  |  |  |  |  |  | 
| 6813 | 18816 |  |  |  |  | 27113 | $cosim= cos($inclm); | 
| 6814 |  |  |  |  |  |  | #* ------------------------ ADD LUNAR-SOLAR PERIODICS ------------------ | 
| 6815 | 18816 |  |  |  |  | 27145 | $eccp= $eccm; | 
| 6816 | 18816 |  |  |  |  | 26271 | $xincp= $inclm; | 
| 6817 | 18816 |  |  |  |  | 26213 | $argpp= $argpm; | 
| 6818 | 18816 |  |  |  |  | 23957 | $nodep= $nodem; | 
| 6819 | 18816 |  |  |  |  | 23255 | $mp= $mm; | 
| 6820 | 18816 |  |  |  |  | 25507 | $sinip= $sinim; | 
| 6821 | 18816 |  |  |  |  | 26630 | $cosip= $cosim; | 
| 6822 | 18816 | 100 |  |  |  | 40456 | if ($parm->{deep_space}) { | 
| 6823 | 395 |  |  |  |  | 1304 | $self->_r_dpper ($t, \$eccp, \$xincp, \$nodep, \$argpp, \$mp); | 
| 6824 | 395 | 100 |  |  |  | 991 | if ($xincp <  0) { | 
| 6825 | 26 |  |  |  |  | 44 | $xincp= -$xincp; | 
| 6826 | 26 |  |  |  |  | 51 | $nodep= $nodep+ &SGP_PI; | 
| 6827 | 26 |  |  |  |  | 45 | $argpp= $argpp- &SGP_PI; | 
| 6828 |  |  |  |  |  |  | } | 
| 6829 | 395 | 50 | 33 |  |  | 1419 | if ($eccp <  0  ||  $eccp >  1) { | 
| 6830 | 0 |  |  |  |  | 0 | $self->{model_error}= &SGP4R_ERROR_3; | 
| 6831 | 0 |  |  |  |  | 0 | croak "Error - OID $oid ", &SGP4R_ERROR_INST_ECCEN; | 
| 6832 |  |  |  |  |  |  | } | 
| 6833 |  |  |  |  |  |  |  | 
| 6834 |  |  |  |  |  |  | } | 
| 6835 |  |  |  |  |  |  | #* ------------------------ LONG PERIOD PERIODICS ---------------------- | 
| 6836 | 18816 | 100 |  |  |  | 37543 | if ($parm->{deep_space}) { | 
| 6837 | 395 |  |  |  |  | 544 | $sinip=  sin($xincp); | 
| 6838 | 395 |  |  |  |  | 555 | $cosip=  cos($xincp); | 
| 6839 | 395 |  |  |  |  | 717 | $parm->{aycof}= -0.5*$parm->{j3oj2}*$sinip; | 
| 6840 |  |  |  |  |  |  | #c         sgp4fix for divide by zero with xincp = 180 deg | 
| 6841 | 395 | 50 |  |  |  | 823 | if (abs($cosip+1) >  1.5e-12) { | 
| 6842 | 395 |  |  |  |  | 888 | $parm->{xlcof}= -0.25*$parm->{j3oj2}*$sinip* | 
| 6843 |  |  |  |  |  |  | (3+5*$cosip)/(1+$cosip); | 
| 6844 |  |  |  |  |  |  | } else { | 
| 6845 | 0 |  |  |  |  | 0 | $parm->{xlcof}= -0.25*$parm->{j3oj2}*$sinip* | 
| 6846 |  |  |  |  |  |  | (3+5*$cosip)/$temp4; | 
| 6847 |  |  |  |  |  |  | } | 
| 6848 |  |  |  |  |  |  | } | 
| 6849 | 18816 |  |  |  |  | 29291 | $axnl= $eccp*cos($argpp); | 
| 6850 | 18816 |  |  |  |  | 30033 | $temp= 1 / ($am*(1-$eccp*$eccp)); | 
| 6851 | 18816 |  |  |  |  | 35071 | $aynl= $eccp*sin($argpp) + $temp*$parm->{aycof}; | 
| 6852 |  |  |  |  |  |  |  | 
| 6853 | 18816 |  |  |  |  | 34516 | $xl= $mp+ $argpp+ $nodep+ $temp*$parm->{xlcof}*$axnl; | 
| 6854 |  |  |  |  |  |  | #* ------------------------- SOLVE KEPLER'S EQUATION ------------------- | 
| 6855 | 18816 |  |  |  |  | 41671 | $u= fmod($xl-$nodep, &SGP_TWOPI); | 
| 6856 | 18816 |  |  |  |  | 30897 | $eo1= $u; | 
| 6857 | 18816 |  |  |  |  | 24278 | $iter=0; | 
| 6858 |  |  |  |  |  |  | #c   sgp4fix for kepler iteration | 
| 6859 |  |  |  |  |  |  | #c   the following iteration needs better limits on corrections | 
| 6860 | 18816 |  |  |  |  | 24748 | $temp= 9999.9; | 
| 6861 | 18816 |  | 66 |  |  | 58103 | while (($temp >= 1e-12) && ($iter < 10)) { | 
| 6862 | 56901 |  |  |  |  | 73272 | $iter=$iter+1; | 
| 6863 | 56901 |  |  |  |  | 77689 | $sineo1= sin($eo1); | 
| 6864 | 56901 |  |  |  |  | 73836 | $coseo1= cos($eo1); | 
| 6865 | 56901 |  |  |  |  | 80099 | $tem5= 1 - $coseo1*$axnl- $sineo1*$aynl; | 
| 6866 | 56901 |  |  |  |  | 83481 | $tem5= ($u- $aynl*$coseo1+ $axnl*$sineo1- $eo1) / $tem5; | 
| 6867 | 56901 |  |  |  |  | 74882 | $temp= abs($tem5); | 
| 6868 | 56901 | 100 |  |  |  | 95332 | if ($temp > 1) { | 
| 6869 | 27 |  |  |  |  | 57 | $tem5=$tem5/$temp | 
| 6870 |  |  |  |  |  |  | } | 
| 6871 | 56901 |  |  |  |  | 140691 | $eo1= $eo1+$tem5; | 
| 6872 |  |  |  |  |  |  |  | 
| 6873 |  |  |  |  |  |  | } | 
| 6874 |  |  |  |  |  |  | #* ----------------- SHORT PERIOD PRELIMINARY QUANTITIES --------------- | 
| 6875 | 18816 |  |  |  |  | 28409 | $ecose= $axnl*$coseo1+$aynl*$sineo1; | 
| 6876 | 18816 |  |  |  |  | 26027 | $esine= $axnl*$sineo1-$aynl*$coseo1; | 
| 6877 | 18816 |  |  |  |  | 26786 | $el2= $axnl*$axnl+$aynl*$aynl; | 
| 6878 | 18816 |  |  |  |  | 26230 | $pl= $am*(1-$el2); | 
| 6879 |  |  |  |  |  |  | #c     semi-latus rectum < 0.0 | 
| 6880 | 18816 | 50 |  |  |  | 32813 | if ( $pl <  0 ) { | 
| 6881 | 0 |  |  |  |  | 0 | $self->{model_error}= &SGP4R_ERROR_4; | 
| 6882 | 0 |  |  |  |  | 0 | croak "Error - OID $oid ", &SGP4R_ERROR_LATUSRECTUM; | 
| 6883 |  |  |  |  |  |  | } else { | 
| 6884 | 18816 |  |  |  |  | 26051 | $rl= $am*(1-$ecose); | 
| 6885 | 18816 |  |  |  |  | 28914 | $rdotl= sqrt($am)*$esine/$rl; | 
| 6886 | 18816 |  |  |  |  | 26242 | $rvdotl= sqrt($pl)/$rl; | 
| 6887 | 18816 |  |  |  |  | 24789 | $betal= sqrt(1-$el2); | 
| 6888 | 18816 |  |  |  |  | 27245 | $temp= $esine/(1+$betal); | 
| 6889 | 18816 |  |  |  |  | 28424 | $sinu= $am/$rl*($sineo1-$aynl-$axnl*$temp); | 
| 6890 | 18816 |  |  |  |  | 28116 | $cosu= $am/$rl*($coseo1-$axnl+$aynl*$temp); | 
| 6891 | 18816 |  |  |  |  | 37522 | $su= atan2($sinu, $cosu); | 
| 6892 | 18816 |  |  |  |  | 24691 | $sin2u= ($cosu+$cosu)*$sinu; | 
| 6893 | 18816 |  |  |  |  | 26557 | $cos2u= 1-2*$sinu*$sinu; | 
| 6894 | 18816 |  |  |  |  | 28029 | $temp= 1/$pl; | 
| 6895 | 18816 |  |  |  |  | 27651 | $temp1= 0.5*$parm->{j2}*$temp; | 
| 6896 |  |  |  |  |  |  |  | 
| 6897 | 18816 |  |  |  |  | 25838 | $temp2= $temp1*$temp; | 
| 6898 |  |  |  |  |  |  | #* ------------------ UPDATE FOR SHORT PERIOD PERIODICS ---------------- | 
| 6899 | 18816 | 100 |  |  |  | 34594 | if ($parm->{deep_space}) { | 
| 6900 | 395 |  |  |  |  | 553 | $cosisq= $cosip*$cosip; | 
| 6901 | 395 |  |  |  |  | 681 | $parm->{con41}= 3*$cosisq- 1; | 
| 6902 | 395 |  |  |  |  | 596 | $parm->{x1mth2}= 1 - $cosisq; | 
| 6903 | 395 |  |  |  |  | 656 | $parm->{x7thm1}= 7*$cosisq- 1; | 
| 6904 |  |  |  |  |  |  | } | 
| 6905 |  |  |  |  |  |  | $mr= $rl*(1 - 1.5*$temp2*$betal*$parm->{con41}) + | 
| 6906 | 18816 |  |  |  |  | 39097 | 0.5*$temp1*$parm->{x1mth2}*$cos2u; | 
| 6907 | 18816 |  |  |  |  | 31419 | $su= $su- 0.25*$temp2*$parm->{x7thm1}*$sin2u; | 
| 6908 | 18816 |  |  |  |  | 26499 | $xnode= $nodep+ 1.5*$temp2*$cosip*$sin2u; | 
| 6909 | 18816 |  |  |  |  | 28684 | $xinc= $xincp+ 1.5*$temp2*$cosip*$sinip*$cos2u; | 
| 6910 | 18816 |  |  |  |  | 33435 | $mv= $rdotl- $xn*$temp1*$parm->{x1mth2}*$sin2u/ $parm->{xke}; | 
| 6911 |  |  |  |  |  |  |  | 
| 6912 |  |  |  |  |  |  | $rvdot= $rvdotl+ $xn*$temp1* | 
| 6913 | 18816 |  |  |  |  | 34305 | ($parm->{x1mth2}*$cos2u+1.5*$parm->{con41}) / $parm->{xke}; | 
| 6914 |  |  |  |  |  |  | #* ------------------------- ORIENTATION VECTORS ----------------------- | 
| 6915 | 18816 |  |  |  |  | 26141 | $sinsu=  sin($su); | 
| 6916 | 18816 |  |  |  |  | 26034 | $cossu=  cos($su); | 
| 6917 | 18816 |  |  |  |  | 24488 | $snod=  sin($xnode); | 
| 6918 | 18816 |  |  |  |  | 26749 | $cnod=  cos($xnode); | 
| 6919 | 18816 |  |  |  |  | 23110 | $sini=  sin($xinc); | 
| 6920 | 18816 |  |  |  |  | 25129 | $cosi=  cos($xinc); | 
| 6921 | 18816 |  |  |  |  | 26474 | $xmx= -$snod*$cosi; | 
| 6922 | 18816 |  |  |  |  | 24604 | $xmy=  $cnod*$cosi; | 
| 6923 | 18816 |  |  |  |  | 25510 | $ux=  $xmx*$sinsu+ $cnod*$cossu; | 
| 6924 | 18816 |  |  |  |  | 26030 | $uy=  $xmy*$sinsu+ $snod*$cossu; | 
| 6925 | 18816 |  |  |  |  | 24385 | $uz=  $sini*$sinsu; | 
| 6926 | 18816 |  |  |  |  | 28232 | $vx=  $xmx*$cossu- $cnod*$sinsu; | 
| 6927 | 18816 |  |  |  |  | 24944 | $vy=  $xmy*$cossu- $snod*$sinsu; | 
| 6928 |  |  |  |  |  |  |  | 
| 6929 | 18816 |  |  |  |  | 27353 | $vz=  $sini*$cossu; | 
| 6930 |  |  |  |  |  |  | #* ----------------------- POSITION AND VELOCITY ----------------------- | 
| 6931 | 18816 |  |  |  |  | 31981 | $r[1] = $mr*$ux* $parm->{radiusearthkm}; | 
| 6932 | 18816 |  |  |  |  | 29371 | $r[2] = $mr*$uy* $parm->{radiusearthkm}; | 
| 6933 | 18816 |  |  |  |  | 29176 | $r[3] = $mr*$uz* $parm->{radiusearthkm}; | 
| 6934 | 18816 |  |  |  |  | 29973 | $v[1] = ($mv*$ux+ $rvdot*$vx) * $vkmpersec; | 
| 6935 | 18816 |  |  |  |  | 27841 | $v[2] = ($mv*$uy+ $rvdot*$vy) * $vkmpersec; | 
| 6936 | 18816 |  |  |  |  | 30324 | $v[3] = ($mv*$uz+ $rvdot*$vz) * $vkmpersec; | 
| 6937 |  |  |  |  |  |  |  | 
| 6938 |  |  |  |  |  |  | } | 
| 6939 |  |  |  |  |  |  | #* --------------------------- ERROR PROCESSING ------------------------ | 
| 6940 |  |  |  |  |  |  | #c     sgp4fix for decaying satellites | 
| 6941 | 18816 | 50 |  |  |  | 36322 | if ($mr <  1) { | 
| 6942 |  |  |  |  |  |  | #c          write(*,*) '# decay condition ',mr | 
| 6943 | 0 |  |  |  |  | 0 | $self->{model_error}= &SGP4R_ERROR_6; | 
| 6944 |  |  |  |  |  |  |  | 
| 6945 |  |  |  |  |  |  | } | 
| 6946 |  |  |  |  |  |  | #c        INCLUDE 'debug7.for' | 
| 6947 |  |  |  |  |  |  |  | 
| 6948 |  |  |  |  |  |  | #>>>>trw	RETURN | 
| 6949 |  |  |  |  |  |  |  | 
| 6950 | 18816 |  |  |  |  | 66927 | $self->__universal( $time ); | 
| 6951 | 18816 |  |  |  |  | 69870 | $self->eci (@r[1..3], @v[1..3]); | 
| 6952 | 18816 |  |  |  |  | 56703 | $self->equinox_dynamical ($self->{epoch_dynamical}); | 
| 6953 | 18816 |  |  |  |  | 46259 | return $self; | 
| 6954 |  |  |  |  |  |  | } | 
| 6955 |  |  |  |  |  |  |  | 
| 6956 |  |  |  |  |  |  | =begin comment | 
| 6957 |  |  |  |  |  |  |  | 
| 6958 |  |  |  |  |  |  | The following code was converted from the Fortran reference | 
| 6959 |  |  |  |  |  |  | implementation, but is not used by this code. | 
| 6960 |  |  |  |  |  |  |  | 
| 6961 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 6962 |  |  |  |  |  |  | #* | 
| 6963 |  |  |  |  |  |  | #*                           FUNCTION GSTIME | 
| 6964 |  |  |  |  |  |  | #* | 
| 6965 |  |  |  |  |  |  | #*  This function finds the Greenwich SIDEREAL time.  Notice just the INTEGER | 
| 6966 |  |  |  |  |  |  | #*    part of the Julian Date is used for the Julian centuries calculation. | 
| 6967 |  |  |  |  |  |  | #*    We use radper Solar day because we're multiplying by 0-24 solar hours. | 
| 6968 |  |  |  |  |  |  | #* | 
| 6969 |  |  |  |  |  |  | #*  Author        : David Vallado                  719-573-2600    1 Mar 2001 | 
| 6970 |  |  |  |  |  |  | #* | 
| 6971 |  |  |  |  |  |  | #*  Inputs          Description                    Range / Units | 
| 6972 |  |  |  |  |  |  | #*    JD          - Julian Date                    days from 4713 BC | 
| 6973 |  |  |  |  |  |  | #* | 
| 6974 |  |  |  |  |  |  | #*  OutPuts       : | 
| 6975 |  |  |  |  |  |  | #*    GSTIME      - Greenwich SIDEREAL Time        0 to 2Pi rad | 
| 6976 |  |  |  |  |  |  | #* | 
| 6977 |  |  |  |  |  |  | #*  Locals        : | 
| 6978 |  |  |  |  |  |  | #*    Temp        - Temporary variable for reals   rad | 
| 6979 |  |  |  |  |  |  | #*    TUT1        - Julian Centuries from the | 
| 6980 |  |  |  |  |  |  | #*                  Jan 1, 2000 12 h epoch (UT1) | 
| 6981 |  |  |  |  |  |  | #* | 
| 6982 |  |  |  |  |  |  | #*  Coupling      : | 
| 6983 |  |  |  |  |  |  | #* | 
| 6984 |  |  |  |  |  |  | #*  References    : | 
| 6985 |  |  |  |  |  |  | #*    Vallado       2007, 194, Eq 3-45 | 
| 6986 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 6987 |  |  |  |  |  |  |  | 
| 6988 |  |  |  |  |  |  | sub _r_gstime { | 
| 6989 |  |  |  |  |  |  | my ($jd) = @_; | 
| 6990 |  |  |  |  |  |  | my $gstime; | 
| 6991 |  |  |  |  |  |  | #* ----------------------------  Locals  ------------------------------- | 
| 6992 |  |  |  |  |  |  |  | 
| 6993 |  |  |  |  |  |  | my ($temp, $tut1); | 
| 6994 |  |  |  |  |  |  | #>>>>trw	INCLUDE 'astmath.cmn' | 
| 6995 |  |  |  |  |  |  |  | 
| 6996 |  |  |  |  |  |  | $tut1= ( $$jd- 2451545 ) / 36525; | 
| 6997 |  |  |  |  |  |  | $temp= - 6.2e-06*$tut1*$tut1*$tut1+ 0.093104*$tut1*$tut1+ | 
| 6998 |  |  |  |  |  |  | (876600*3600 + 8640184.812866)*$tut1+ 67310.54841; | 
| 6999 |  |  |  |  |  |  |  | 
| 7000 |  |  |  |  |  |  | $temp= fmod($temp*&SGP_DE2RA/240, &SGP_TWOPI); | 
| 7001 |  |  |  |  |  |  | if ( $temp <  0 ) { | 
| 7002 |  |  |  |  |  |  | $temp= $temp+ &SGP_TWOPI; | 
| 7003 |  |  |  |  |  |  |  | 
| 7004 |  |  |  |  |  |  | } | 
| 7005 |  |  |  |  |  |  |  | 
| 7006 |  |  |  |  |  |  | $gstime= $temp; | 
| 7007 |  |  |  |  |  |  | return $gstime; | 
| 7008 |  |  |  |  |  |  | } | 
| 7009 |  |  |  |  |  |  |  | 
| 7010 |  |  |  |  |  |  | =end comment | 
| 7011 |  |  |  |  |  |  |  | 
| 7012 |  |  |  |  |  |  | =cut | 
| 7013 |  |  |  |  |  |  |  | 
| 7014 |  |  |  |  |  |  | #* ----------------------------------------------------------------------------- | 
| 7015 |  |  |  |  |  |  | #* | 
| 7016 |  |  |  |  |  |  | #*                           function getgravconst | 
| 7017 |  |  |  |  |  |  | #* | 
| 7018 |  |  |  |  |  |  | #*  this function gets constants for the propagator. note that mu is identified to | 
| 7019 |  |  |  |  |  |  | #*    facilitiate comparisons with newer models. | 
| 7020 |  |  |  |  |  |  | #* | 
| 7021 |  |  |  |  |  |  | #*  author        : david vallado                  719-573-2600   21 jul 2006 | 
| 7022 |  |  |  |  |  |  | #* | 
| 7023 |  |  |  |  |  |  | #*  inputs        : | 
| 7024 |  |  |  |  |  |  | #*    whichconst  - which set of constants to use  721, 72, 84 | 
| 7025 |  |  |  |  |  |  | #* | 
| 7026 |  |  |  |  |  |  | #*  outputs       : | 
| 7027 |  |  |  |  |  |  | #*    tumin       - minutes in one time unit | 
| 7028 |  |  |  |  |  |  | #*    mu          - earth gravitational parameter | 
| 7029 |  |  |  |  |  |  | #*    radiusearthkm - radius of the earth in km | 
| 7030 |  |  |  |  |  |  | #*    xke         - reciprocal of tumin | 
| 7031 |  |  |  |  |  |  | #*    j2, j3, j4  - un-normalized zonal harmonic values | 
| 7032 |  |  |  |  |  |  | #*    j3oj2       - j3 divided by j2 | 
| 7033 |  |  |  |  |  |  | #* | 
| 7034 |  |  |  |  |  |  | #*  locals        : | 
| 7035 |  |  |  |  |  |  | #* | 
| 7036 |  |  |  |  |  |  | #*  coupling      : | 
| 7037 |  |  |  |  |  |  | #* | 
| 7038 |  |  |  |  |  |  | #*  references    : | 
| 7039 |  |  |  |  |  |  | #*    norad spacetrack report #3 | 
| 7040 |  |  |  |  |  |  | #*    vallado, crawford, hujsak, kelso  2006 | 
| 7041 |  |  |  |  |  |  | #*  ---------------------------------------------------------------------------- | 
| 7042 |  |  |  |  |  |  |  | 
| 7043 |  |  |  |  |  |  | sub _r_getgravconst { | 
| 7044 | 35 |  |  | 35 |  | 86 | my ($self) = @_; | 
| 7045 |  |  |  |  |  |  | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} | 
| 7046 | 35 | 50 |  |  |  | 176 | or confess "Programming error - Sgp4r not initialized"; | 
| 7047 |  |  |  |  |  |  |  | 
| 7048 | 35 | 50 |  |  |  | 120 | if ($self->{gravconst_r} == 721) { | 
| 7049 | 0 |  |  |  |  | 0 | $parm->{radiusearthkm}= 6378.135; | 
| 7050 | 0 |  |  |  |  | 0 | $parm->{xke}= 0.0743669161; | 
| 7051 | 0 |  |  |  |  | 0 | $parm->{mu}= 398600.79964; | 
| 7052 | 0 |  |  |  |  | 0 | $parm->{tumin}= 1 / $parm->{xke}; | 
| 7053 | 0 |  |  |  |  | 0 | $parm->{j2}=   0.001082616; | 
| 7054 | 0 |  |  |  |  | 0 | $parm->{j3}=  -2.53881e-06; | 
| 7055 | 0 |  |  |  |  | 0 | $parm->{j4}=  -1.65597e-06; | 
| 7056 | 0 |  |  |  |  | 0 | $parm->{j3oj2}=  $parm->{j3}/ $parm->{j2}; | 
| 7057 |  |  |  |  |  |  | } | 
| 7058 |  |  |  |  |  |  |  | 
| 7059 | 35 | 50 |  |  |  | 118 | if ($self->{gravconst_r} == 72) { | 
| 7060 | 35 |  |  |  |  | 104 | $parm->{mu}= 398600.8; | 
| 7061 | 35 |  |  |  |  | 76 | $parm->{radiusearthkm}= 6378.135; | 
| 7062 | 35 |  |  |  |  | 193 | $parm->{xke}= 60 / sqrt($parm->{radiusearthkm}**3/$parm->{mu}); | 
| 7063 | 35 |  |  |  |  | 85 | $parm->{tumin}= 1 / $parm->{xke}; | 
| 7064 | 35 |  |  |  |  | 69 | $parm->{j2}=   0.001082616; | 
| 7065 | 35 |  |  |  |  | 90 | $parm->{j3}=  -2.53881e-06; | 
| 7066 | 35 |  |  |  |  | 91 | $parm->{j4}=  -1.65597e-06; | 
| 7067 | 35 |  |  |  |  | 135 | $parm->{j3oj2}=  $parm->{j3}/ $parm->{j2}; | 
| 7068 |  |  |  |  |  |  | } | 
| 7069 |  |  |  |  |  |  |  | 
| 7070 | 35 | 50 |  |  |  | 127 | if ($self->{gravconst_r} == 84) { | 
| 7071 | 0 |  |  |  |  | 0 | $parm->{mu}= 398600.5; | 
| 7072 | 0 |  |  |  |  | 0 | $parm->{radiusearthkm}= 6378.137; | 
| 7073 | 0 |  |  |  |  | 0 | $parm->{xke}= 60 / sqrt($parm->{radiusearthkm}**3/$parm->{mu}); | 
| 7074 | 0 |  |  |  |  | 0 | $parm->{tumin}= 1 / $parm->{xke}; | 
| 7075 | 0 |  |  |  |  | 0 | $parm->{j2}=   0.00108262998905; | 
| 7076 | 0 |  |  |  |  | 0 | $parm->{j3}=  -2.53215306e-06; | 
| 7077 | 0 |  |  |  |  | 0 | $parm->{j4}=  -1.61098761e-06; | 
| 7078 | 0 |  |  |  |  | 0 | $parm->{j3oj2}=  $parm->{j3}/ $parm->{j2}; | 
| 7079 |  |  |  |  |  |  |  | 
| 7080 |  |  |  |  |  |  | } | 
| 7081 | 35 |  |  |  |  | 68 | return; | 
| 7082 |  |  |  |  |  |  | } | 
| 7083 |  |  |  |  |  |  |  | 
| 7084 |  |  |  |  |  |  | ##### end of sgp4unit.for | 
| 7085 |  |  |  |  |  |  |  | 
| 7086 |  |  |  |  |  |  | =begin comment | 
| 7087 |  |  |  |  |  |  |  | 
| 7088 |  |  |  |  |  |  | # Used for debugging | 
| 7089 |  |  |  |  |  |  |  | 
| 7090 |  |  |  |  |  |  | sub _r_dump { | 
| 7091 |  |  |  |  |  |  | my $self = shift; | 
| 7092 |  |  |  |  |  |  | no warnings qw{uninitialized}; | 
| 7093 |  |  |  |  |  |  | my $parm = $self->{&TLE_INIT}{TLE_sgp4r} | 
| 7094 |  |  |  |  |  |  | or confess "Programming error - Sgp4r not initialized"; | 
| 7095 |  |  |  |  |  |  | my $fh = IO::File->new('perldump.out', '>>') | 
| 7096 |  |  |  |  |  |  | or croak "Failed to open perldump.out: $!"; | 
| 7097 |  |  |  |  |  |  | print $fh ' ========== sgp4r initialization', "\n"; | 
| 7098 |  |  |  |  |  |  | print $fh ' SatNum = ', $self->get ('id'), "\n"; | 
| 7099 |  |  |  |  |  |  | print $fh ' ...', "\n"; | 
| 7100 |  |  |  |  |  |  | print $fh ' Bstar = ', $self->{bstardrag}, "\n"; | 
| 7101 |  |  |  |  |  |  | print $fh ' Ecco = ', $parm->{eccentricity}, "\n"; | 
| 7102 |  |  |  |  |  |  | print $fh ' Inclo = ', $parm->{inclination}, "\n"; | 
| 7103 |  |  |  |  |  |  | print $fh ' nodeo = ', $parm->{ascendingnode}, "\n"; | 
| 7104 |  |  |  |  |  |  | print $fh ' Argpo = ', $parm->{argumentofperigee}, "\n"; | 
| 7105 |  |  |  |  |  |  | print $fh ' No = ', $parm->{meanmotion}, "\n"; | 
| 7106 |  |  |  |  |  |  | print $fh ' Mo = ', $parm->{meananomaly}, "\n"; | 
| 7107 |  |  |  |  |  |  | print $fh ' NDot = ', '????', "\n"; | 
| 7108 |  |  |  |  |  |  | print $fh ' NDDot = ', '????', "\n"; | 
| 7109 |  |  |  |  |  |  | print $fh ' alta = ', 'not computed; unused?', "\n"; | 
| 7110 |  |  |  |  |  |  | print $fh ' altp = ', 'not computed; unused?', "\n"; | 
| 7111 |  |  |  |  |  |  | print $fh ' a = ', 'not computed; unused?', "\n"; | 
| 7112 |  |  |  |  |  |  | print $fh ' ...', "\n"; | 
| 7113 |  |  |  |  |  |  | print $fh ' ----', "\n"; | 
| 7114 |  |  |  |  |  |  | print $fh ' Aycof = ', $parm->{aycof}, "\n"; | 
| 7115 |  |  |  |  |  |  | print $fh ' CON41 = ', $parm->{con41}, "\n"; | 
| 7116 |  |  |  |  |  |  | print $fh ' Cc1 = ', $parm->{cc1}, "\n"; | 
| 7117 |  |  |  |  |  |  | print $fh ' Cc4 = ', $parm->{cc4}, "\n"; | 
| 7118 |  |  |  |  |  |  | print $fh ' Cc5 = ', $parm->{cc5}, "\n"; | 
| 7119 |  |  |  |  |  |  | print $fh ' D2 = ', $parm->{d2}, "\n"; | 
| 7120 |  |  |  |  |  |  | print $fh ' D3 = ', $parm->{d3}, "\n"; | 
| 7121 |  |  |  |  |  |  | print $fh ' D4 = ', $parm->{d4}, "\n"; | 
| 7122 |  |  |  |  |  |  | print $fh ' Delmo = ', $parm->{delmo}, "\n"; | 
| 7123 |  |  |  |  |  |  | print $fh ' Eta = ', $parm->{eta}, "\n"; | 
| 7124 |  |  |  |  |  |  | print $fh ' ArgpDot = ', $parm->{argpdot}, "\n"; | 
| 7125 |  |  |  |  |  |  | print $fh ' Omgcof = ', $parm->{omgcof}, "\n"; | 
| 7126 |  |  |  |  |  |  | print $fh ' Sinmao = ', $parm->{sinmao}, "\n"; | 
| 7127 |  |  |  |  |  |  | print $fh ' T2cof = ', $parm->{t2cof}, "\n"; | 
| 7128 |  |  |  |  |  |  | print $fh ' T3cof = ', $parm->{t3cof}, "\n"; | 
| 7129 |  |  |  |  |  |  | print $fh ' T4cof = ', $parm->{t4cof}, "\n"; | 
| 7130 |  |  |  |  |  |  | print $fh ' T5cof = ', $parm->{t5cof}, "\n"; | 
| 7131 |  |  |  |  |  |  | print $fh ' X1mth2 = ', $parm->{x1mth2}, "\n"; | 
| 7132 |  |  |  |  |  |  | print $fh ' MDot = ', $parm->{mdot}, "\n"; | 
| 7133 |  |  |  |  |  |  | print $fh ' nodeDot = ', $parm->{nodedot}, "\n"; | 
| 7134 |  |  |  |  |  |  | print $fh ' Xlcof = ', $parm->{xlcof}, "\n"; | 
| 7135 |  |  |  |  |  |  | print $fh ' Xmcof = ', $parm->{xmcof}, "\n"; | 
| 7136 |  |  |  |  |  |  | print $fh ' Xnodcf = ', $parm->{xnodcf}, "\n"; | 
| 7137 |  |  |  |  |  |  | print $fh ' ----', "\n"; | 
| 7138 |  |  |  |  |  |  | print $fh ' D2201 = ', $parm->{d2201}, "\n"; | 
| 7139 |  |  |  |  |  |  | print $fh ' D2211 = ', $parm->{d2211}, "\n"; | 
| 7140 |  |  |  |  |  |  | print $fh ' D3210 = ', $parm->{d3210}, "\n"; | 
| 7141 |  |  |  |  |  |  | print $fh ' D3222 = ', $parm->{d3222}, "\n"; | 
| 7142 |  |  |  |  |  |  | print $fh ' D4410 = ', $parm->{d4410}, "\n"; | 
| 7143 |  |  |  |  |  |  | print $fh ' D4422 = ', $parm->{d4422}, "\n"; | 
| 7144 |  |  |  |  |  |  | print $fh ' D5220 = ', $parm->{d5220}, "\n"; | 
| 7145 |  |  |  |  |  |  | print $fh ' D5232 = ', $parm->{d5232}, "\n"; | 
| 7146 |  |  |  |  |  |  | print $fh ' D5421 = ', $parm->{d5421}, "\n"; | 
| 7147 |  |  |  |  |  |  | print $fh ' D5433 = ', $parm->{d5433}, "\n"; | 
| 7148 |  |  |  |  |  |  | print $fh ' Dedt = ', $parm->{dedt}, "\n"; | 
| 7149 |  |  |  |  |  |  | print $fh ' Del1 = ', $parm->{del1}, "\n"; | 
| 7150 |  |  |  |  |  |  | print $fh ' Del2 = ', $parm->{del2}, "\n"; | 
| 7151 |  |  |  |  |  |  | print $fh ' Del3 = ', $parm->{del3}, "\n"; | 
| 7152 |  |  |  |  |  |  | print $fh ' Didt = ', $parm->{didt}, "\n"; | 
| 7153 |  |  |  |  |  |  | print $fh ' Dmdt = ', $parm->{dmdt}, "\n"; | 
| 7154 |  |  |  |  |  |  | print $fh ' Dnodt = ', $parm->{dnodt}, "\n"; | 
| 7155 |  |  |  |  |  |  | print $fh ' Domdt = ', $parm->{domdt}, "\n"; | 
| 7156 |  |  |  |  |  |  | print $fh ' E3 = ', $parm->{e3}, "\n"; | 
| 7157 |  |  |  |  |  |  | print $fh ' Ee2 = ', $parm->{ee2}, "\n"; | 
| 7158 |  |  |  |  |  |  | print $fh ' Peo = ', $parm->{peo}, "\n"; | 
| 7159 |  |  |  |  |  |  | print $fh ' Pgho = ', $parm->{pgho}, "\n"; | 
| 7160 |  |  |  |  |  |  | print $fh ' Pho = ', $parm->{pho}, "\n"; | 
| 7161 |  |  |  |  |  |  | print $fh ' Pinco = ', $parm->{pinco}, "\n"; | 
| 7162 |  |  |  |  |  |  | print $fh ' Plo = ', $parm->{plo}, "\n"; | 
| 7163 |  |  |  |  |  |  | print $fh ' Se2 = ', $parm->{se2}, "\n"; | 
| 7164 |  |  |  |  |  |  | print $fh ' Se3 = ', $parm->{se3}, "\n"; | 
| 7165 |  |  |  |  |  |  | print $fh ' Sgh2 = ', $parm->{sgh2}, "\n"; | 
| 7166 |  |  |  |  |  |  | print $fh ' Sgh3 = ', $parm->{sgh3}, "\n"; | 
| 7167 |  |  |  |  |  |  | print $fh ' Sgh4 = ', $parm->{sgh4}, "\n"; | 
| 7168 |  |  |  |  |  |  | print $fh ' Sh2 = ', $parm->{sh2}, "\n"; | 
| 7169 |  |  |  |  |  |  | print $fh ' Sh3 = ', $parm->{sh3}, "\n"; | 
| 7170 |  |  |  |  |  |  | print $fh ' Si2 = ', $parm->{si2}, "\n"; | 
| 7171 |  |  |  |  |  |  | print $fh ' Si3 = ', $parm->{si3}, "\n"; | 
| 7172 |  |  |  |  |  |  | print $fh ' Sl2 = ', $parm->{sl2}, "\n"; | 
| 7173 |  |  |  |  |  |  | print $fh ' Sl3 = ', $parm->{sl3}, "\n"; | 
| 7174 |  |  |  |  |  |  | print $fh ' Sl4 = ', $parm->{sl4}, "\n"; | 
| 7175 |  |  |  |  |  |  | print $fh ' GSTo = ', $parm->{gsto}, "\n"; | 
| 7176 |  |  |  |  |  |  | print $fh ' Xfact = ', $parm->{xfact}, "\n"; | 
| 7177 |  |  |  |  |  |  | print $fh ' Xgh2 = ', $parm->{xgh2}, "\n"; | 
| 7178 |  |  |  |  |  |  | print $fh ' Xgh3 = ', $parm->{xgh3}, "\n"; | 
| 7179 |  |  |  |  |  |  | print $fh ' Xgh4 = ', $parm->{xgh4}, "\n"; | 
| 7180 |  |  |  |  |  |  | print $fh ' Xh2 = ', $parm->{xh2}, "\n"; | 
| 7181 |  |  |  |  |  |  | print $fh ' Xh3 = ', $parm->{xh3}, "\n"; | 
| 7182 |  |  |  |  |  |  | print $fh ' Xi2 = ', $parm->{xi2}, "\n"; | 
| 7183 |  |  |  |  |  |  | print $fh ' Xi3 = ', $parm->{xi3}, "\n"; | 
| 7184 |  |  |  |  |  |  | print $fh ' Xl2 = ', $parm->{xl2}, "\n"; | 
| 7185 |  |  |  |  |  |  | print $fh ' Xl3 = ', $parm->{xl3}, "\n"; | 
| 7186 |  |  |  |  |  |  | print $fh ' Xl4 = ', $parm->{xl4}, "\n"; | 
| 7187 |  |  |  |  |  |  | print $fh ' Xlamo = ', $parm->{xlamo}, "\n"; | 
| 7188 |  |  |  |  |  |  | print $fh ' Zmol = ', $parm->{zmol}, "\n"; | 
| 7189 |  |  |  |  |  |  | print $fh ' Zmos = ', $parm->{zmos}, "\n"; | 
| 7190 |  |  |  |  |  |  | print $fh ' Atime = ', $parm->{atime}, "\n"; | 
| 7191 |  |  |  |  |  |  | print $fh ' Xli = ', $parm->{xli}, "\n"; | 
| 7192 |  |  |  |  |  |  | print $fh ' Xni = ', $parm->{xni}, "\n"; | 
| 7193 |  |  |  |  |  |  | print $fh ' IRez = ', $parm->{irez}, "\n"; | 
| 7194 |  |  |  |  |  |  | print $fh ' Isimp = ', $parm->{isimp}, "\n"; | 
| 7195 |  |  |  |  |  |  | print $fh ' Init = ', $parm->{init}, "\n"; | 
| 7196 |  |  |  |  |  |  | print $fh ' Method = ', ($parm->{deep_space} ? 'd' : 'n'), "\n"; | 
| 7197 |  |  |  |  |  |  | return; | 
| 7198 |  |  |  |  |  |  | } | 
| 7199 |  |  |  |  |  |  |  | 
| 7200 |  |  |  |  |  |  | =end comment | 
| 7201 |  |  |  |  |  |  |  | 
| 7202 |  |  |  |  |  |  | =cut | 
| 7203 |  |  |  |  |  |  |  | 
| 7204 |  |  |  |  |  |  | # Elevation of the illuminating body as seen from the satellite at the | 
| 7205 |  |  |  |  |  |  | # given time. | 
| 7206 |  |  |  |  |  |  | sub __sun_elev_from_sat { | 
| 7207 | 917 |  |  | 917 |  | 1944 | my ( $self, $time ) = @_; | 
| 7208 | 917 | 100 |  |  |  | 1928 | if ( defined $time ) { | 
| 7209 | 916 |  |  |  |  | 2328 | $self->universal( $time ); | 
| 7210 |  |  |  |  |  |  | } else { | 
| 7211 | 1 |  |  |  |  | 3 | $time = $self->universal(); | 
| 7212 |  |  |  |  |  |  | } | 
| 7213 | 917 |  |  |  |  | 2549 | return ( $self->azel_offset( | 
| 7214 |  |  |  |  |  |  | $self->get( 'illum' )->universal( $time ), | 
| 7215 |  |  |  |  |  |  | $self->get( 'edge_of_earths_shadow' ), | 
| 7216 |  |  |  |  |  |  | ) )[1] - $self->dip(); | 
| 7217 |  |  |  |  |  |  | } | 
| 7218 |  |  |  |  |  |  |  | 
| 7219 |  |  |  |  |  |  | =item $text = $tle->tle_verbose(...); | 
| 7220 |  |  |  |  |  |  |  | 
| 7221 |  |  |  |  |  |  | This method returns a verbose version of the TLE data, with one data | 
| 7222 |  |  |  |  |  |  | field per line, labeled. The optional arguments are key-value pairs | 
| 7223 |  |  |  |  |  |  | affecting the formatting of the output. The only key implemented at the | 
| 7224 |  |  |  |  |  |  | moment is | 
| 7225 |  |  |  |  |  |  |  | 
| 7226 |  |  |  |  |  |  | date_format | 
| 7227 |  |  |  |  |  |  | specifies the strftime() format used for dates | 
| 7228 |  |  |  |  |  |  | (default: '%d-%b-%Y %H:%M:%S'). | 
| 7229 |  |  |  |  |  |  |  | 
| 7230 |  |  |  |  |  |  | =cut | 
| 7231 |  |  |  |  |  |  |  | 
| 7232 |  |  |  |  |  |  | sub tle_verbose { | 
| 7233 | 0 |  |  | 0 | 1 | 0 | my ($self, %args) = @_; | 
| 7234 | 0 |  | 0 |  |  | 0 | my $dtfmt = $args{date_format} || '%d-%b-%Y %H:%M:%S'; | 
| 7235 | 0 |  |  |  |  | 0 | my $epoch = __format_epoch_time_usec( $self->get( 'epoch' ), $dtfmt ); | 
| 7236 | 0 |  |  |  |  | 0 | my $semimajor = $self->get('semimajor');	# Of reference ellipsoid. | 
| 7237 |  |  |  |  |  |  |  | 
| 7238 | 0 |  |  |  |  | 0 | my $result = < | 
| 7239 | 0 |  |  |  |  | 0 | NORAD ID: @{[$self->get ('id')]} | 
| 7240 | 0 |  | 0 |  |  | 0 | Name: @{[$self->get ('name') || 'unspecified']} | 
| 7241 | 0 |  |  |  |  | 0 | International launch designator: @{[$self->get ('international')]} | 
| 7242 |  |  |  |  |  |  | Epoch of data: $epoch GMT | 
| 7243 |  |  |  |  |  |  | EOD | 
| 7244 | 0 | 0 |  |  |  | 0 | if (defined (my $effective = $self->get('effective'))) { | 
| 7245 | 0 |  |  |  |  | 0 | $result .= < | 
| 7246 | 0 |  |  |  |  | 0 | Effective date: @{[strftime $dtfmt, gmtime $effective]} GMT | 
| 7247 |  |  |  |  |  |  | EOD | 
| 7248 |  |  |  |  |  |  | } | 
| 7249 | 0 |  |  |  |  | 0 | $result .= < | 
| 7250 | 0 |  |  |  |  | 0 | Classification status: @{[$self->get ('classification')]} | 
| 7251 | 0 |  |  |  |  | 0 | Mean motion: @{[rad2deg ($self->get ('meanmotion'))]} degrees/minute | 
| 7252 | 0 |  |  |  |  | 0 | First derivative of motion: @{[rad2deg ($self->get ('firstderivative'))]} degrees/minute squared | 
| 7253 | 0 |  |  |  |  | 0 | Second derivative of motion: @{[rad2deg ($self->get ('secondderivative'))]} degrees/minute cubed | 
| 7254 | 0 |  |  |  |  | 0 | B Star drag term: @{[$self->get ('bstardrag')]} | 
| 7255 | 0 |  |  |  |  | 0 | Ephemeris type: @{[$self->get ('ephemeristype')]} | 
| 7256 | 0 |  |  |  |  | 0 | Inclination of orbit: @{[rad2deg ($self->get ('inclination'))]} degrees | 
| 7257 | 0 |  |  |  |  | 0 | Right ascension of ascending node: @{[rad2deg ($self->get ('ascendingnode'))]} degrees | 
| 7258 | 0 |  |  |  |  | 0 | Eccentricity: @{[$self->get ('eccentricity')]} | 
| 7259 | 0 |  |  |  |  | 0 | Argument of perigee: @{[rad2deg ($self->get ('argumentofperigee'))]} degrees from ascending node | 
| 7260 | 0 |  |  |  |  | 0 | Mean anomaly: @{[rad2deg ($self->get ('meananomaly'))]} degrees | 
| 7261 | 0 |  |  |  |  | 0 | Element set number: @{[$self->get ('elementnumber')]} | 
| 7262 | 0 |  |  |  |  | 0 | Revolutions at epoch: @{[$self->get ('revolutionsatepoch')]} | 
| 7263 | 0 |  |  |  |  | 0 | Period (derived): @{[$self->period()]} seconds | 
| 7264 | 0 |  |  |  |  | 0 | Semimajor axis (derived): @{[$self->semimajor()]} kilometers | 
| 7265 | 0 |  |  |  |  | 0 | Altitude at perigee (derived): @{[$self->periapsis() - $semimajor]} kilometers | 
| 7266 | 0 |  |  |  |  | 0 | Altitude at apogee (derived): @{[$self->apoapsis() - $semimajor]} kilometers | 
| 7267 |  |  |  |  |  |  | EOD | 
| 7268 | 0 |  |  |  |  | 0 | return $result; | 
| 7269 |  |  |  |  |  |  | } | 
| 7270 |  |  |  |  |  |  |  | 
| 7271 |  |  |  |  |  |  | =item $hash_ref = $tle->TO_JSON(); | 
| 7272 |  |  |  |  |  |  |  | 
| 7273 |  |  |  |  |  |  | Despite its name, this method B convert the object to JSON. | 
| 7274 |  |  |  |  |  |  | What it does instead is to return a reference to a hash that the | 
| 7275 |  |  |  |  |  |  | L class will use to encode the object into JSON. The possible | 
| 7276 |  |  |  |  |  |  | keys are, to the extent possible, those used by the Space Track REST | 
| 7277 |  |  |  |  |  |  | interface. | 
| 7278 |  |  |  |  |  |  |  | 
| 7279 |  |  |  |  |  |  | In order to get L to use this hook you need to instantiate a | 
| 7280 |  |  |  |  |  |  | L object and turn on the conversion of blessed objects, like | 
| 7281 |  |  |  |  |  |  | so: | 
| 7282 |  |  |  |  |  |  |  | 
| 7283 |  |  |  |  |  |  | my $json = JSON->new()->convert_blessed( 1 ); | 
| 7284 |  |  |  |  |  |  | print $json->encode( $tle ); | 
| 7285 |  |  |  |  |  |  |  | 
| 7286 |  |  |  |  |  |  | The returned keys are a mish-mash of the keys returned by the Space | 
| 7287 |  |  |  |  |  |  | Track C and C classes, plus others that are not maintained | 
| 7288 |  |  |  |  |  |  | by Space Track. Since the Space Track keys are all upper case, I have | 
| 7289 |  |  |  |  |  |  | made the non-Space Track keys all lower case. | 
| 7290 |  |  |  |  |  |  |  | 
| 7291 |  |  |  |  |  |  | At this point I am not going to document the keys returned by this | 
| 7292 |  |  |  |  |  |  | method, but they are generally self-explanatory. I find the most cryptic | 
| 7293 |  |  |  |  |  |  | one is C<{INTLDES}>, which is the International Launch Designator, | 
| 7294 |  |  |  |  |  |  | encoded with a four-digit year. | 
| 7295 |  |  |  |  |  |  |  | 
| 7296 |  |  |  |  |  |  | =cut | 
| 7297 |  |  |  |  |  |  |  | 
| 7298 |  |  |  |  |  |  | { | 
| 7299 |  |  |  |  |  |  |  | 
| 7300 |  |  |  |  |  |  | my %json_map = ( | 
| 7301 |  |  |  |  |  |  | ARG_OF_PERICENTER	=> sub { | 
| 7302 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7303 |  |  |  |  |  |  | return rad2deg( $self->get( 'argumentofperigee' ) ); | 
| 7304 |  |  |  |  |  |  | }, | 
| 7305 |  |  |  |  |  |  | BSTAR		=> 'bstardrag', | 
| 7306 |  |  |  |  |  |  | CLASSIFICATION_TYPE	=> 'classification', | 
| 7307 |  |  |  |  |  |  | COMMENT		=> sub { | 
| 7308 |  |  |  |  |  |  | return 'Generated by ' . __PACKAGE__ . ' v' . $VERSION; | 
| 7309 |  |  |  |  |  |  | }, | 
| 7310 |  |  |  |  |  |  | CREATION_DATE	=> sub { | 
| 7311 |  |  |  |  |  |  | return format_space_track_json_time( time ); | 
| 7312 |  |  |  |  |  |  | }, | 
| 7313 |  |  |  |  |  |  | ECCENTRICITY	=> 'eccentricity', | 
| 7314 |  |  |  |  |  |  | ELEMENT_SET_NO	=> 'elementnumber', | 
| 7315 |  |  |  |  |  |  | EPHEMERIS_TYPE	=> 'ephemeristype', | 
| 7316 |  |  |  |  |  |  | EPOCH		=> sub { | 
| 7317 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7318 |  |  |  |  |  |  | return format_space_track_json_time( $self->get( 'epoch' ) ); | 
| 7319 |  |  |  |  |  |  | }, | 
| 7320 |  |  |  |  |  |  | EPOCH_MICROSECONDS	=> sub { | 
| 7321 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7322 |  |  |  |  |  |  | my $epoch = sprintf '%.6f', $self->get( 'epoch' ); | 
| 7323 |  |  |  |  |  |  | $epoch =~ s/ [^.]* [.] //smx; | 
| 7324 |  |  |  |  |  |  | return $epoch; | 
| 7325 |  |  |  |  |  |  | }, | 
| 7326 |  |  |  |  |  |  | FILE		=> 'file', | 
| 7327 |  |  |  |  |  |  | INCLINATION	=> sub { | 
| 7328 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7329 |  |  |  |  |  |  | return rad2deg( $self->get( 'inclination' ) ); | 
| 7330 |  |  |  |  |  |  | }, | 
| 7331 |  |  |  |  |  |  | INTLDES		=> sub { | 
| 7332 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7333 |  |  |  |  |  |  | my $year = $self->get( 'launch_year' ); | 
| 7334 |  |  |  |  |  |  | my $num = $self->get( 'launch_num' ); | 
| 7335 |  |  |  |  |  |  | my $part = $self->get( 'launch_piece' ); | 
| 7336 |  |  |  |  |  |  | # As of August 27 2012, this is no longer yyyy-lllp, it is | 
| 7337 |  |  |  |  |  |  | # yylllp, same as it has always been in the TLE format. | 
| 7338 |  |  |  |  |  |  | $year %= 100; | 
| 7339 |  |  |  |  |  |  | foreach ( $year, $num, $part ) { | 
| 7340 |  |  |  |  |  |  | defined $_ | 
| 7341 |  |  |  |  |  |  | and $_ =~ m/ \S /smx | 
| 7342 |  |  |  |  |  |  | or return; | 
| 7343 |  |  |  |  |  |  | } | 
| 7344 |  |  |  |  |  |  | return sprintf '%02d%03d%s', $year, $num, $part;	# ditto | 
| 7345 |  |  |  |  |  |  | }, | 
| 7346 |  |  |  |  |  |  | LAUNCH_NUM	=> 'launch_num', | 
| 7347 |  |  |  |  |  |  | LAUNCH_PIECE	=> 'launch_piece', | 
| 7348 |  |  |  |  |  |  | LAUNCH_YEAR	=> 'launch_year', | 
| 7349 |  |  |  |  |  |  | MEAN_ANOMALY	=> sub { | 
| 7350 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7351 |  |  |  |  |  |  | return rad2deg( $self->get( 'meananomaly' ) ); | 
| 7352 |  |  |  |  |  |  | }, | 
| 7353 |  |  |  |  |  |  | MEAN_MOTION	=> sub { | 
| 7354 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7355 |  |  |  |  |  |  | return $self->get( 'meanmotion' ) * SGP_XMNPDA / TWOPI; | 
| 7356 |  |  |  |  |  |  | }, | 
| 7357 |  |  |  |  |  |  | MEAN_MOTION_DDOT	=> sub { | 
| 7358 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7359 |  |  |  |  |  |  | return $self->get( | 
| 7360 |  |  |  |  |  |  | 'secondderivative' | 
| 7361 |  |  |  |  |  |  | ) * SGP_XMNPDA * SGP_XMNPDA * SGP_XMNPDA / TWOPI; | 
| 7362 |  |  |  |  |  |  | }, | 
| 7363 |  |  |  |  |  |  | MEAN_MOTION_DOT	=> sub { | 
| 7364 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7365 |  |  |  |  |  |  | return $self->get( | 
| 7366 |  |  |  |  |  |  | 'firstderivative' | 
| 7367 |  |  |  |  |  |  | ) * SGP_XMNPDA * SGP_XMNPDA / TWOPI; | 
| 7368 |  |  |  |  |  |  | }, | 
| 7369 |  |  |  |  |  |  | NORAD_CAT_ID	=> 'id', | 
| 7370 |  |  |  |  |  |  | OBJECT_ID	=> sub { | 
| 7371 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7372 |  |  |  |  |  |  | my $year = $self->get( 'launch_year' ); | 
| 7373 |  |  |  |  |  |  | my $num = $self->get( 'launch_num' ); | 
| 7374 |  |  |  |  |  |  | my $part = $self->get( 'launch_piece' ); | 
| 7375 |  |  |  |  |  |  | foreach ( $year, $num, $part ) { | 
| 7376 |  |  |  |  |  |  | defined $_ | 
| 7377 |  |  |  |  |  |  | and $_ =~ m/ \S /smx | 
| 7378 |  |  |  |  |  |  | or return; | 
| 7379 |  |  |  |  |  |  | } | 
| 7380 |  |  |  |  |  |  | return sprintf '%04d-%03d%s', $year, $num, $part; | 
| 7381 |  |  |  |  |  |  | }, | 
| 7382 |  |  |  |  |  |  | OBJECT_NAME	=> 'name', | 
| 7383 |  |  |  |  |  |  | OBJECT_NUMBER	=> 'id', | 
| 7384 |  |  |  |  |  |  | OBJECT_TYPE	=> sub { | 
| 7385 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7386 |  |  |  |  |  |  | return uc $self->body_type(); | 
| 7387 |  |  |  |  |  |  | }, | 
| 7388 |  |  |  |  |  |  | ORDINAL		=> 'ordinal', | 
| 7389 |  |  |  |  |  |  | ORIGINATOR	=> 'originator', | 
| 7390 |  |  |  |  |  |  | RA_OF_ASC_NODE	=> sub { | 
| 7391 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7392 |  |  |  |  |  |  | return rad2deg( $self->get( 'ascendingnode' ) ); | 
| 7393 |  |  |  |  |  |  | }, | 
| 7394 |  |  |  |  |  |  | RCSVALUE	=> 'rcs', | 
| 7395 |  |  |  |  |  |  | REV_AT_EPOCH	=> 'revolutionsatepoch', | 
| 7396 |  |  |  |  |  |  | #	TLE_LINE0	=> sub { | 
| 7397 |  |  |  |  |  |  | #	    my ( $self ) = @_; | 
| 7398 |  |  |  |  |  |  | #	    my $name = $self->get( 'name' ); | 
| 7399 |  |  |  |  |  |  | #	    defined $name | 
| 7400 |  |  |  |  |  |  | #		and $name = "0 $name"; | 
| 7401 |  |  |  |  |  |  | #	    return $name; | 
| 7402 |  |  |  |  |  |  | #	}, | 
| 7403 |  |  |  |  |  |  | # TLE_LINE0 is handled programmatically | 
| 7404 |  |  |  |  |  |  | # TLE_LINE1 is handled programmatically | 
| 7405 |  |  |  |  |  |  | # TLE_LINE2 is handled programmatically | 
| 7406 |  |  |  |  |  |  | effective_date	=> sub { | 
| 7407 |  |  |  |  |  |  | my ( $self ) = @_; | 
| 7408 |  |  |  |  |  |  | return format_space_track_json_time( $self->get( 'effective' ) ); | 
| 7409 |  |  |  |  |  |  | }, | 
| 7410 |  |  |  |  |  |  | intrinsic_magnitude	=> 'intrinsic_magnitude', | 
| 7411 |  |  |  |  |  |  | ); | 
| 7412 |  |  |  |  |  |  |  | 
| 7413 |  |  |  |  |  |  | # This guy is to be used by subclasses so they don't have to | 
| 7414 |  |  |  |  |  |  | # implement their own converter. The arguments (after the invocant) | 
| 7415 |  |  |  |  |  |  | # are a reference to the mapping hash and an optional reference to | 
| 7416 |  |  |  |  |  |  | # a hash to populate. The return is a hash reference, which will be | 
| 7417 |  |  |  |  |  |  | # the one provided if there _was_ one provided. | 
| 7418 |  |  |  |  |  |  |  | 
| 7419 |  |  |  |  |  |  | # The mapping hash's keys are the keys to be provided in the output. | 
| 7420 |  |  |  |  |  |  | # The values are either the Astro::Coord::ECI::TLE attributes | 
| 7421 |  |  |  |  |  |  | # corresponding to those keys, or a code reference which computes | 
| 7422 |  |  |  |  |  |  | # the value. If a code reference, it is called with the invocant and | 
| 7423 |  |  |  |  |  |  | # the JSON key. No matter where they come from, values which are | 
| 7424 |  |  |  |  |  |  | # undef or '' will not appear in the output hash. | 
| 7425 |  |  |  |  |  |  |  | 
| 7426 |  |  |  |  |  |  | sub __to_json { | 
| 7427 | 0 |  |  | 0 |  | 0 | my ( $self, $mapping, $rslt ) = @_; | 
| 7428 | 0 |  | 0 |  |  | 0 | $rslt ||= {}; | 
| 7429 |  |  |  |  |  |  |  | 
| 7430 | 0 |  |  |  |  | 0 | foreach my $key ( keys %{ $mapping } ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 7431 | 0 |  |  |  |  | 0 | my $map = $mapping->{$key}; | 
| 7432 | 0 | 0 |  |  |  | 0 | my $val = CODE_REF eq ref $map ? | 
| 7433 |  |  |  |  |  |  | $map->( $self, $key ) : | 
| 7434 |  |  |  |  |  |  | $self->get( $map ); | 
| 7435 |  |  |  |  |  |  | defined $val | 
| 7436 |  |  |  |  |  |  | and $val ne '' | 
| 7437 | 0 | 0 | 0 |  |  | 0 | and $rslt->{$key} = $val; | 
| 7438 |  |  |  |  |  |  | } | 
| 7439 |  |  |  |  |  |  |  | 
| 7440 | 0 | 0 |  |  |  | 0 | if ( defined ( my $tle = $self->get( 'tle' ) ) ) { | 
| 7441 | 0 |  |  |  |  | 0 | chomp $tle; | 
| 7442 | 0 |  |  |  |  | 0 | my @lines = split "\n", $tle; | 
| 7443 | 0 |  |  |  |  | 0 | unshift @lines, '' while @lines < 3; | 
| 7444 | 0 |  |  |  |  | 0 | foreach my $line ( 1 .. 2 ) { | 
| 7445 |  |  |  |  |  |  | defined $lines[$line] | 
| 7446 |  |  |  |  |  |  | and $lines[$line] =~ m/ \S /smx | 
| 7447 | 0 | 0 | 0 |  |  | 0 | and $rslt->{"TLE_LINE$line"} = $lines[$line]; | 
| 7448 |  |  |  |  |  |  | } | 
| 7449 | 0 | 0 |  |  |  | 0 | if ( defined( my $name = $self->get( 'name' ) ) ) { | 
| 7450 | 0 |  |  |  |  | 0 | $rslt->{TLE_LINE0} = "0 $name"; | 
| 7451 |  |  |  |  |  |  | } | 
| 7452 |  |  |  |  |  |  | } | 
| 7453 |  |  |  |  |  |  |  | 
| 7454 | 0 |  |  |  |  | 0 | return $rslt; | 
| 7455 |  |  |  |  |  |  | } | 
| 7456 |  |  |  |  |  |  |  | 
| 7457 |  |  |  |  |  |  | sub TO_JSON { | 
| 7458 | 0 |  |  | 0 | 1 | 0 | my ( $self ) = @_; | 
| 7459 | 0 |  |  |  |  | 0 | return $self->__to_json( \%json_map ); | 
| 7460 |  |  |  |  |  |  | } | 
| 7461 |  |  |  |  |  |  |  | 
| 7462 |  |  |  |  |  |  | } | 
| 7463 |  |  |  |  |  |  |  | 
| 7464 |  |  |  |  |  |  | { | 
| 7465 |  |  |  |  |  |  | my $have_json; | 
| 7466 |  |  |  |  |  |  | my @required = qw{ | 
| 7467 |  |  |  |  |  |  | NORAD_CAT_ID | 
| 7468 |  |  |  |  |  |  | EPOCH | 
| 7469 |  |  |  |  |  |  | MEAN_MOTION | 
| 7470 |  |  |  |  |  |  | ECCENTRICITY | 
| 7471 |  |  |  |  |  |  | INCLINATION | 
| 7472 |  |  |  |  |  |  | RA_OF_ASC_NODE | 
| 7473 |  |  |  |  |  |  | ARG_OF_PERICENTER | 
| 7474 |  |  |  |  |  |  | MEAN_ANOMALY | 
| 7475 |  |  |  |  |  |  | EPHEMERIS_TYPE | 
| 7476 |  |  |  |  |  |  | CLASSIFICATION_TYPE | 
| 7477 |  |  |  |  |  |  | ELEMENT_SET_NO | 
| 7478 |  |  |  |  |  |  | REV_AT_EPOCH | 
| 7479 |  |  |  |  |  |  | BSTAR | 
| 7480 |  |  |  |  |  |  | MEAN_MOTION_DOT | 
| 7481 |  |  |  |  |  |  | MEAN_MOTION_DDOT | 
| 7482 |  |  |  |  |  |  | }; | 
| 7483 |  |  |  |  |  |  | my %json_map = ( | 
| 7484 |  |  |  |  |  |  | #	INTLDES		=> 'international', | 
| 7485 |  |  |  |  |  |  | NORAD_CAT_ID	=> 'id', | 
| 7486 |  |  |  |  |  |  | OBJECT_NAME	=> 'name', | 
| 7487 |  |  |  |  |  |  | #	OBJECT_ID	=> 'international', | 
| 7488 |  |  |  |  |  |  | RCSVALUE	=> 'rcs', | 
| 7489 |  |  |  |  |  |  | #	LAUNCH_YEAR	=> 'launch_year', | 
| 7490 |  |  |  |  |  |  | #	LAUNCH_NUM	=> 'launch_num', | 
| 7491 |  |  |  |  |  |  | #	LAUNCH_PIECE	=> 'launch_piece', | 
| 7492 |  |  |  |  |  |  | #	COMMENT		=> sub { | 
| 7493 |  |  |  |  |  |  | #	    return 'Generated by ' . __PACKAGE__ . ' v' . $VERSION; | 
| 7494 |  |  |  |  |  |  | #	}, | 
| 7495 |  |  |  |  |  |  | #	CREATION_DATE	=> sub { | 
| 7496 |  |  |  |  |  |  | #	    return format_space_track_json_time( time ); | 
| 7497 |  |  |  |  |  |  | #	}, | 
| 7498 |  |  |  |  |  |  | EPOCH		=> 'epoch', | 
| 7499 |  |  |  |  |  |  | FILE		=> 'file', | 
| 7500 |  |  |  |  |  |  | MEAN_MOTION	=> 'meanmotion', | 
| 7501 |  |  |  |  |  |  | ECCENTRICITY	=> 'eccentricity', | 
| 7502 |  |  |  |  |  |  | INCLINATION	=> 'inclination', | 
| 7503 |  |  |  |  |  |  | RA_OF_ASC_NODE	=> 'ascendingnode', | 
| 7504 |  |  |  |  |  |  | ARG_OF_PERICENTER	=> 'argumentofperigee', | 
| 7505 |  |  |  |  |  |  | MEAN_ANOMALY	=> 'meananomaly', | 
| 7506 |  |  |  |  |  |  | EPHEMERIS_TYPE	=> 'ephemeristype', | 
| 7507 |  |  |  |  |  |  | CLASSIFICATION_TYPE	=> 'classification', | 
| 7508 |  |  |  |  |  |  | ELEMENT_SET_NO	=> 'elementnumber', | 
| 7509 |  |  |  |  |  |  | REV_AT_EPOCH	=> 'revolutionsatepoch', | 
| 7510 |  |  |  |  |  |  | BSTAR		=> 'bstardrag', | 
| 7511 |  |  |  |  |  |  | MEAN_MOTION_DOT	=> 'firstderivative', | 
| 7512 |  |  |  |  |  |  | MEAN_MOTION_DDOT	=> 'secondderivative', | 
| 7513 |  |  |  |  |  |  | OBJECT_TYPE	=> 'object_type', | 
| 7514 |  |  |  |  |  |  | ORDINAL		=> 'ordinal', | 
| 7515 |  |  |  |  |  |  | ORIGINATOR	=> 'originator', | 
| 7516 |  |  |  |  |  |  | effective_date	=> 'effective', | 
| 7517 |  |  |  |  |  |  | intrinsic_magnitude	=> 'intrinsic_magnitude', | 
| 7518 |  |  |  |  |  |  | ); | 
| 7519 |  |  |  |  |  |  |  | 
| 7520 |  |  |  |  |  |  | sub _decode_json_time { | 
| 7521 | 0 |  |  | 0 |  | 0 | my ( $string ) = @_; | 
| 7522 | 0 | 0 |  |  |  | 0 | $string =~ m{ \A \s* | 
| 7523 |  |  |  |  |  |  | ( [0-9]+ ) [^0-9]+ ( [0-9]+ ) [^0-9]+ ( [0-9]+ ) [^0-9]+ | 
| 7524 |  |  |  |  |  |  | ( [0-9]+ ) [^0-9]+ ( [0-9]+ ) [^0-9]+ ( [0-9]+ ) | 
| 7525 |  |  |  |  |  |  | (?: ( [.] [0-9]* ) )? | 
| 7526 |  |  |  |  |  |  | \s* \z }smx | 
| 7527 |  |  |  |  |  |  | or return; | 
| 7528 | 0 |  |  |  |  | 0 | my @time = ( $1, $2, $3, $4, $5, $6 ); | 
| 7529 | 0 |  |  |  |  | 0 | my $frac = $7; | 
| 7530 | 0 |  |  |  |  | 0 | $time[0] = __tle_year_to_Gregorian_year( $time[0] ); | 
| 7531 | 0 |  |  |  |  | 0 | $time[1] -= 1; | 
| 7532 | 0 |  |  |  |  | 0 | my $rslt = greg_time_gm( reverse @time ); | 
| 7533 | 0 | 0 | 0 |  |  | 0 | defined $frac | 
| 7534 |  |  |  |  |  |  | and $frac ne '.' | 
| 7535 |  |  |  |  |  |  | and $rslt += $frac; | 
| 7536 | 0 |  |  |  |  | 0 | return $rslt; | 
| 7537 |  |  |  |  |  |  | } | 
| 7538 |  |  |  |  |  |  |  | 
| 7539 |  |  |  |  |  |  | sub _parse_json { | 
| 7540 | 0 |  |  | 0 |  | 0 | my ( undef, @args ) = @_;	# Invocant unused | 
| 7541 |  |  |  |  |  |  | defined $have_json | 
| 7542 | 0 | 0 |  |  |  | 0 | or $have_json = eval { | 
|  |  | 0 |  |  |  |  |  | 
| 7543 | 0 |  |  |  |  | 0 | require JSON; | 
| 7544 | 0 |  |  |  |  | 0 | 1; | 
| 7545 |  |  |  |  |  |  | } ? 1 : 0; | 
| 7546 | 0 | 0 |  |  |  | 0 | $have_json | 
| 7547 |  |  |  |  |  |  | or croak 'Can not load JSON'; | 
| 7548 | 0 |  |  |  |  | 0 | my $json = JSON->new()->utf8( 1 ); | 
| 7549 | 0 | 0 |  |  |  | 0 | my $attrs = HASH_REF eq ref $args[0] ? shift @args : {}; | 
| 7550 | 0 |  |  |  |  | 0 | my @rslt; | 
| 7551 |  |  |  |  |  |  |  | 
| 7552 | 0 |  |  |  |  | 0 | foreach my $arg ( @args ) { | 
| 7553 | 0 |  |  |  |  | 0 | my $decode = $json->decode( $arg ); | 
| 7554 |  |  |  |  |  |  |  | 
| 7555 | 0 | 0 |  |  |  | 0 | foreach my $hash ( ARRAY_REF eq ref $decode ? @{ $decode } : | 
|  | 0 |  |  |  |  | 0 |  | 
| 7556 |  |  |  |  |  |  | $decode ) { | 
| 7557 |  |  |  |  |  |  |  | 
| 7558 | 0 |  | 0 |  |  | 0 | my $class = $hash->{astro_coord_eci_class} || __PACKAGE__; | 
| 7559 | 0 |  |  |  |  | 0 | load_module( $class ); | 
| 7560 | 0 |  |  |  |  | 0 | push @rslt, $class->__from_json( $hash, $attrs ); | 
| 7561 |  |  |  |  |  |  |  | 
| 7562 |  |  |  |  |  |  | } | 
| 7563 |  |  |  |  |  |  | } | 
| 7564 |  |  |  |  |  |  |  | 
| 7565 | 0 |  |  |  |  | 0 | return @rslt; | 
| 7566 |  |  |  |  |  |  | } | 
| 7567 |  |  |  |  |  |  |  | 
| 7568 |  |  |  |  |  |  | sub __from_json { | 
| 7569 | 0 |  |  | 0 |  | 0 | my ( $class, $hash, $attrs ) = @_; | 
| 7570 |  |  |  |  |  |  |  | 
| 7571 | 0 |  | 0 |  |  | 0 | $attrs ||= {}; | 
| 7572 |  |  |  |  |  |  |  | 
| 7573 | 0 | 0 |  |  |  | 0 | if ( exists $hash->{SATNAME} ) {	# TODO Deprecated | 
| 7574 | 0 | 0 |  |  |  | 0 | warnings::enabled( 'deprecated' ) | 
| 7575 |  |  |  |  |  |  | and croak 'The SATNAME JSON key is deprecated ', | 
| 7576 |  |  |  |  |  |  | 'in favor of the OBJECT_NAME key'; | 
| 7577 |  |  |  |  |  |  | exists $hash->{OBJECT_NAME} | 
| 7578 | 0 | 0 |  |  |  | 0 | or $hash->{OBJECT_NAME} = $hash->{SATNAME}; | 
| 7579 | 0 |  |  |  |  | 0 | delete $hash->{SATNAME}; | 
| 7580 |  |  |  |  |  |  | } | 
| 7581 |  |  |  |  |  |  |  | 
| 7582 | 0 |  |  |  |  | 0 | foreach my $key ( @required ) { | 
| 7583 | 0 | 0 |  |  |  | 0 | defined $hash->{$key} | 
| 7584 |  |  |  |  |  |  | or return; | 
| 7585 |  |  |  |  |  |  | } | 
| 7586 |  |  |  |  |  |  |  | 
| 7587 |  |  |  |  |  |  | defined $hash->{INTLDES} | 
| 7588 |  |  |  |  |  |  | and $hash->{INTLDES} =~ | 
| 7589 | 0 | 0 |  |  |  | 0 | s/ \A [0-9]{2} ( [0-9]{2} ) - /$1/smx; | 
| 7590 |  |  |  |  |  |  |  | 
| 7591 | 0 |  |  |  |  | 0 | foreach my $key ( qw{ EPOCH effective_date } ) { | 
| 7592 |  |  |  |  |  |  | defined $hash->{$key} | 
| 7593 | 0 | 0 |  |  |  | 0 | and $hash->{$key} = _decode_json_time( $hash->{$key} ); | 
| 7594 |  |  |  |  |  |  | } | 
| 7595 |  |  |  |  |  |  | defined $hash->{EPOCH_MICROSECONDS} | 
| 7596 |  |  |  |  |  |  | and $hash->{EPOCH} += $hash->{EPOCH_MICROSECONDS} / | 
| 7597 | 0 | 0 |  |  |  | 0 | 1_000_000; | 
| 7598 |  |  |  |  |  |  |  | 
| 7599 | 0 |  |  |  |  | 0 | foreach my $key ( qw{ | 
| 7600 |  |  |  |  |  |  | ARG_OF_PERICENTER INCLINATION MEAN_ANOMALY | 
| 7601 |  |  |  |  |  |  | RA_OF_ASC_NODE | 
| 7602 |  |  |  |  |  |  | } ) { | 
| 7603 | 0 |  |  |  |  | 0 | $hash->{$key} *= SGP_DE2RA; | 
| 7604 |  |  |  |  |  |  | } | 
| 7605 |  |  |  |  |  |  |  | 
| 7606 |  |  |  |  |  |  | { | 
| 7607 | 0 |  |  |  |  | 0 | my $temp = SGP_TWOPI; | 
|  | 0 |  |  |  |  | 0 |  | 
| 7608 | 0 |  |  |  |  | 0 | foreach my $key ( qw{ | 
| 7609 |  |  |  |  |  |  | MEAN_MOTION MEAN_MOTION_DOT MEAN_MOTION_DDOT | 
| 7610 |  |  |  |  |  |  | } ) { | 
| 7611 | 0 |  |  |  |  | 0 | $temp /= SGP_XMNPDA; | 
| 7612 | 0 |  |  |  |  | 0 | $hash->{$key} *= $temp; | 
| 7613 |  |  |  |  |  |  | } | 
| 7614 |  |  |  |  |  |  | } | 
| 7615 |  |  |  |  |  |  |  | 
| 7616 | 0 |  |  |  |  | 0 | my %tle = %{ $attrs }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 7617 | 0 |  |  |  |  | 0 | foreach my $key ( keys %{ $hash } ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 7618 | 0 |  |  |  |  | 0 | my $value = $hash->{$key}; | 
| 7619 | 0 | 0 |  |  |  | 0 | my $attr = $json_map{$key} | 
| 7620 |  |  |  |  |  |  | or next; | 
| 7621 | 0 |  |  |  |  | 0 | $tle{$attr} = $value; | 
| 7622 |  |  |  |  |  |  | } | 
| 7623 |  |  |  |  |  |  |  | 
| 7624 | 0 |  |  |  |  | 0 | my $obj = $class->new( %tle ); | 
| 7625 |  |  |  |  |  |  |  | 
| 7626 | 0 |  |  |  |  | 0 | foreach my $key ( qw{ OBJECT_ID INTLDES } ) { | 
| 7627 | 0 | 0 |  |  |  | 0 | defined $hash->{$key} | 
| 7628 |  |  |  |  |  |  | or next; | 
| 7629 | 0 |  |  |  |  | 0 | $obj->_set_intldes( international => $hash->{$key} ); | 
| 7630 | 0 |  |  |  |  | 0 | last; | 
| 7631 |  |  |  |  |  |  | } | 
| 7632 |  |  |  |  |  |  |  | 
| 7633 | 0 |  |  |  |  | 0 | return $obj; | 
| 7634 |  |  |  |  |  |  | } | 
| 7635 |  |  |  |  |  |  | } | 
| 7636 |  |  |  |  |  |  |  | 
| 7637 |  |  |  |  |  |  | =item $valid = $tle->validate($options, $time ...); | 
| 7638 |  |  |  |  |  |  |  | 
| 7639 |  |  |  |  |  |  | This method checks to see if the currently-selected model can be run | 
| 7640 |  |  |  |  |  |  | successfully. If so, it returns 1; if not, it returns 0. | 
| 7641 |  |  |  |  |  |  |  | 
| 7642 |  |  |  |  |  |  | The $options argument is itself optional. If passed, it is a reference | 
| 7643 |  |  |  |  |  |  | to a hash of option names and values. At the moment the only option used | 
| 7644 |  |  |  |  |  |  | is | 
| 7645 |  |  |  |  |  |  |  | 
| 7646 |  |  |  |  |  |  | quiet => 1 to suppress output to STDERR. | 
| 7647 |  |  |  |  |  |  |  | 
| 7648 |  |  |  |  |  |  | If the C option is not specified, or is specified as a false | 
| 7649 |  |  |  |  |  |  | value, validation failures will produce output to STDERR. | 
| 7650 |  |  |  |  |  |  |  | 
| 7651 |  |  |  |  |  |  | Each $time argument is adjusted by passing it through C<< | 
| 7652 |  |  |  |  |  |  | $tle->max_effective_date >>, and the distinct adjusted times are sorted | 
| 7653 |  |  |  |  |  |  | into ascending order. The currently-selected model is run at each of the | 
| 7654 |  |  |  |  |  |  | times thus computed. The return is 0 if any run fails, or 1 if they all | 
| 7655 |  |  |  |  |  |  | succeed. | 
| 7656 |  |  |  |  |  |  |  | 
| 7657 |  |  |  |  |  |  | If there are no $time arguments, the model is run at the effective date | 
| 7658 |  |  |  |  |  |  | if that is specified, or the epoch if the effective date is not | 
| 7659 |  |  |  |  |  |  | specified. | 
| 7660 |  |  |  |  |  |  |  | 
| 7661 |  |  |  |  |  |  | =cut | 
| 7662 |  |  |  |  |  |  |  | 
| 7663 |  |  |  |  |  |  | sub validate { | 
| 7664 | 0 |  |  | 0 | 1 | 0 | my ($self, @args) = @_; | 
| 7665 | 0 | 0 |  |  |  | 0 | my $opt = HASH_REF eq ref $args[0] ? shift @args : {}; | 
| 7666 | 0 |  |  |  |  | 0 | my %args; | 
| 7667 | 0 | 0 |  |  |  | 0 | if (@args) { | 
| 7668 | 0 |  |  |  |  | 0 | %args = map { ( $self->max_effective_date( $_ ) => 1 ) } @args; | 
|  | 0 |  |  |  |  | 0 |  | 
| 7669 |  |  |  |  |  |  | } else { | 
| 7670 | 0 |  | 0 |  |  | 0 | $args{$self->get('effective') || $self->get('epoch')} = 1; | 
| 7671 |  |  |  |  |  |  | } | 
| 7672 | 0 | 0 |  |  |  | 0 | eval { | 
| 7673 | 0 |  |  |  |  | 0 | foreach my $time ( sort { $a <=> $b } keys %args ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 7674 | 0 |  |  |  |  | 0 | $self->universal( $time ); | 
| 7675 |  |  |  |  |  |  | } | 
| 7676 | 0 |  |  |  |  | 0 | 1; | 
| 7677 |  |  |  |  |  |  | } and return 1; | 
| 7678 | 0 | 0 | 0 |  |  | 0 | $opt->{quiet} or $@ and warn $@; | 
| 7679 | 0 |  |  |  |  | 0 | return 0; | 
| 7680 |  |  |  |  |  |  | } | 
| 7681 |  |  |  |  |  |  |  | 
| 7682 |  |  |  |  |  |  | ####################################################################### | 
| 7683 |  |  |  |  |  |  |  | 
| 7684 |  |  |  |  |  |  | #	_actan | 
| 7685 |  |  |  |  |  |  |  | 
| 7686 |  |  |  |  |  |  | #	This function wraps the atan2 function, and normalizes the | 
| 7687 |  |  |  |  |  |  | #	result to the range 0 < result < 2 * pi. | 
| 7688 |  |  |  |  |  |  |  | 
| 7689 |  |  |  |  |  |  | sub _actan { | 
| 7690 | 29 |  |  | 29 |  | 96 | my $rslt = atan2 ($_[0], $_[1]); | 
| 7691 | 29 | 100 |  |  |  | 75 | $rslt < 0 and $rslt += SGP_TWOPI; | 
| 7692 | 29 |  |  |  |  | 55 | return $rslt; | 
| 7693 |  |  |  |  |  |  | } | 
| 7694 |  |  |  |  |  |  |  | 
| 7695 |  |  |  |  |  |  | #	_convert_out | 
| 7696 |  |  |  |  |  |  |  | 
| 7697 |  |  |  |  |  |  | #	Convert model results to kilometers and kilometers per second. | 
| 7698 |  |  |  |  |  |  |  | 
| 7699 |  |  |  |  |  |  | sub _convert_out { | 
| 7700 | 25 |  |  | 25 |  | 66 | my ($self, @args) = @_; | 
| 7701 | 25 |  |  |  |  | 36 | $args[0] *= (SGP_XKMPER / SGP_AE);		# x | 
| 7702 | 25 |  |  |  |  | 36 | $args[1] *= (SGP_XKMPER / SGP_AE);		# y | 
| 7703 | 25 |  |  |  |  | 32 | $args[2] *= (SGP_XKMPER / SGP_AE);		# z | 
| 7704 | 25 |  |  |  |  | 31 | $args[3] *= (SGP_XKMPER / SGP_AE * SGP_XMNPDA / SECSPERDAY);	# dx/dt | 
| 7705 | 25 |  |  |  |  | 40 | $args[4] *= (SGP_XKMPER / SGP_AE * SGP_XMNPDA / SECSPERDAY);	# dy/dt | 
| 7706 | 25 |  |  |  |  | 30 | $args[5] *= (SGP_XKMPER / SGP_AE * SGP_XMNPDA / SECSPERDAY);	# dz/dt | 
| 7707 | 25 |  |  |  |  | 102 | $self->__universal( pop @args ); | 
| 7708 | 25 |  |  |  |  | 92 | $self->eci (@args); | 
| 7709 |  |  |  |  |  |  |  | 
| 7710 | 25 |  |  |  |  | 92 | $self->equinox_dynamical ($self->{epoch_dynamical}); | 
| 7711 |  |  |  |  |  |  |  | 
| 7712 | 25 |  |  |  |  | 103 | return $self; | 
| 7713 |  |  |  |  |  |  | } | 
| 7714 |  |  |  |  |  |  |  | 
| 7715 |  |  |  |  |  |  | # Called by pass() to find the illumination. The arguments are the sun | 
| 7716 |  |  |  |  |  |  | # object (or nothing), the time, and a reference to the pass information | 
| 7717 |  |  |  |  |  |  | # hash. The return is either nothing (if $sun is not defined) or | 
| 7718 |  |  |  |  |  |  | # ( illumination => $illum ). | 
| 7719 |  |  |  |  |  |  | sub _find_illumination { | 
| 7720 | 42 |  |  | 42 |  | 94 | my ( $sun, $when, $info ) = @_; | 
| 7721 | 42 | 100 |  |  |  | 123 | $sun | 
| 7722 |  |  |  |  |  |  | or return; | 
| 7723 | 39 |  |  |  |  | 97 | my $illum = $info->[0]{illumination}; | 
| 7724 | 39 |  |  |  |  | 70 | foreach my $evt ( @{ $info } ) { | 
|  | 39 |  |  |  |  | 85 |  | 
| 7725 | 96 | 100 |  |  |  | 203 | $evt->{time} > $when | 
| 7726 |  |  |  |  |  |  | and last; | 
| 7727 | 58 |  |  |  |  | 101 | $illum = $evt->{illumination}; | 
| 7728 |  |  |  |  |  |  | } | 
| 7729 | 39 |  |  |  |  | 206 | return ( illumination	=> $illum ); | 
| 7730 |  |  |  |  |  |  | } | 
| 7731 |  |  |  |  |  |  |  | 
| 7732 |  |  |  |  |  |  | # Called by pass() to calculate azimuth, elevation, and range. The | 
| 7733 |  |  |  |  |  |  | # arguments are the TLE object, the station object, and the time. If the | 
| 7734 |  |  |  |  |  |  | # TLE's 'lazy_pass_position' attribute is true, nothing is returned. | 
| 7735 |  |  |  |  |  |  | # Otherwise the azimuth, elevation, and range are calculated and | 
| 7736 |  |  |  |  |  |  | # returned as three name/value pairs (i.e. a six-element list). | 
| 7737 |  |  |  |  |  |  | sub _find_position { | 
| 7738 | 30 |  |  | 30 |  | 58 | my ( $tle, $sta, $when ) = @_; | 
| 7739 | 30 | 100 |  |  |  | 62 | $tle->get( 'lazy_pass_position' ) | 
| 7740 |  |  |  |  |  |  | and return; | 
| 7741 | 15 |  |  |  |  | 55 | $tle->universal( $when ); | 
| 7742 | 15 |  |  |  |  | 44 | my ( $azimuth, $elevation, $range ) = $sta->azel( $tle ); | 
| 7743 |  |  |  |  |  |  | return ( | 
| 7744 | 15 |  |  |  |  | 155 | azimuth	=> $azimuth, | 
| 7745 |  |  |  |  |  |  | elevation	=> $elevation, | 
| 7746 |  |  |  |  |  |  | range		=> $range, | 
| 7747 |  |  |  |  |  |  | ); | 
| 7748 |  |  |  |  |  |  | } | 
| 7749 |  |  |  |  |  |  |  | 
| 7750 |  |  |  |  |  |  | # Initial value of the 'inertial' attribute. TLEs are assumed to be | 
| 7751 |  |  |  |  |  |  | # inertial until set otherwise. | 
| 7752 |  |  |  |  |  |  |  | 
| 7753 | 64 |  |  | 64 |  | 228 | sub __initial_inertial{ return 1 }; | 
| 7754 |  |  |  |  |  |  |  | 
| 7755 |  |  |  |  |  |  | # Unsupported, experimental, and subject to change or retraction without | 
| 7756 |  |  |  |  |  |  | # notice. The intent is to provide a way for the Astro::App::Satpass2 | 
| 7757 |  |  |  |  |  |  | # 'list' command to pick an appropriate template to format each line of | 
| 7758 |  |  |  |  |  |  | # the listing based on the object being listed. | 
| 7759 |  |  |  |  |  |  | sub __list_type { | 
| 7760 | 3 |  |  | 3 |  | 9 | my ( $self ) = @_; | 
| 7761 | 3 | 100 |  |  |  | 15 | return $self->{inertial} ? 'inertial' : 'fixed'; | 
| 7762 |  |  |  |  |  |  | } | 
| 7763 |  |  |  |  |  |  |  | 
| 7764 |  |  |  |  |  |  | # _looks_like_real | 
| 7765 |  |  |  |  |  |  | # | 
| 7766 |  |  |  |  |  |  | # This returns a boolean which is true if the input looks like a real | 
| 7767 |  |  |  |  |  |  | # number and is false otherwise. It is based on looks_like_number, but | 
| 7768 |  |  |  |  |  |  | # excludes things like NaN, and Inf. | 
| 7769 |  |  |  |  |  |  | sub _looks_like_real { | 
| 7770 | 3 |  |  | 3 |  | 20 | my ( $number ) = @_; | 
| 7771 | 3 | 50 |  |  |  | 13 | looks_like_number( $number ) | 
| 7772 |  |  |  |  |  |  | or return; | 
| 7773 | 3 | 50 |  |  |  | 29 | $number =~ m/ \A nan \z /smxi | 
| 7774 |  |  |  |  |  |  | and return; | 
| 7775 | 3 | 50 |  |  |  | 17 | $number =~ m/ \A [+-]? inf (?: inity )? \z /smxi | 
| 7776 |  |  |  |  |  |  | and return; | 
| 7777 | 3 |  |  |  |  | 13 | return 1; | 
| 7778 |  |  |  |  |  |  | } | 
| 7779 |  |  |  |  |  |  |  | 
| 7780 |  |  |  |  |  |  | # *equinox_dynamical = \&Astro::Coord::ECI::equinox_dynamical; | 
| 7781 |  |  |  |  |  |  |  | 
| 7782 |  |  |  |  |  |  | #	$text = $self->_make_tle(); | 
| 7783 |  |  |  |  |  |  | # | 
| 7784 |  |  |  |  |  |  | #	This method manufactures a TLE. It's a 'real' TLE if the 'name' | 
| 7785 |  |  |  |  |  |  | #	attribute is not set, and a 'NASA' TLE (i.e. the 'T' stands for | 
| 7786 |  |  |  |  |  |  | #	'three') if the 'name' attribute is set. The output is intended | 
| 7787 |  |  |  |  |  |  | #	to be equivalent to the TLE (if any) that initialized the | 
| 7788 |  |  |  |  |  |  | #	object, not identical to it. This method is used to manufacture | 
| 7789 |  |  |  |  |  |  | #	a TLE in the case where $self->get('tle') was called but the | 
| 7790 |  |  |  |  |  |  | #	object was not initialized by the parse() method. | 
| 7791 |  |  |  |  |  |  |  | 
| 7792 |  |  |  |  |  |  | { | 
| 7793 |  |  |  |  |  |  |  | 
| 7794 |  |  |  |  |  |  | my %hack = ( | 
| 7795 |  |  |  |  |  |  | effective => sub { | 
| 7796 |  |  |  |  |  |  | ##	    my ( $self, $name, $value ) = @_; | 
| 7797 |  |  |  |  |  |  | my ( undef, undef, $value ) = @_;	# Invocant & name unused | 
| 7798 |  |  |  |  |  |  | my $whole = floor($value); | 
| 7799 |  |  |  |  |  |  | my ($sec, $min, $hr, undef, undef, $year, undef, $yday) = | 
| 7800 |  |  |  |  |  |  | gmtime $value; | 
| 7801 |  |  |  |  |  |  | my $effective = | 
| 7802 |  |  |  |  |  |  | sprintf '%04d/%03d/%02d:%02d:%06.3f', | 
| 7803 |  |  |  |  |  |  | $year + 1900, $yday + 1, $hr, $min, | 
| 7804 |  |  |  |  |  |  | $sec + ($value - $whole); | 
| 7805 |  |  |  |  |  |  | $effective =~ s/ [.]? 0+ \z //smx; | 
| 7806 |  |  |  |  |  |  | return ( '--effective', $effective ); | 
| 7807 |  |  |  |  |  |  | }, | 
| 7808 |  |  |  |  |  |  | rcs => sub { | 
| 7809 |  |  |  |  |  |  | ##	    my ( $self, $name, $value ) = @_; | 
| 7810 |  |  |  |  |  |  | my ( undef, undef, $value ) = @_;	# Invocant & name unused | 
| 7811 |  |  |  |  |  |  | return ( '--rcs', $value ); | 
| 7812 |  |  |  |  |  |  | }, | 
| 7813 |  |  |  |  |  |  | ); | 
| 7814 |  |  |  |  |  |  |  | 
| 7815 |  |  |  |  |  |  | my @required_fields = qw{ | 
| 7816 |  |  |  |  |  |  | firstderivative secondderivative bstardrag inclination | 
| 7817 |  |  |  |  |  |  | ascendingnode eccentricity argumentofperigee meananomaly | 
| 7818 |  |  |  |  |  |  | meanmotion revolutionsatepoch | 
| 7819 |  |  |  |  |  |  | }; | 
| 7820 |  |  |  |  |  |  |  | 
| 7821 |  |  |  |  |  |  | sub _make_tle { | 
| 7822 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 7823 | 0 |  |  |  |  | 0 | my $output; | 
| 7824 |  |  |  |  |  |  |  | 
| 7825 | 0 |  |  |  |  | 0 | my $oid = $self->get('id'); | 
| 7826 | 0 |  |  |  |  | 0 | my $name = $self->get( 'name' ); | 
| 7827 | 0 |  |  |  |  | 0 | my @line0; | 
| 7828 |  |  |  |  |  |  |  | 
| 7829 | 0 | 0 |  |  |  | 0 | if ( defined $name ) { | 
| 7830 | 0 |  |  |  |  | 0 | $name =~ s/ \s+ \z //smx; | 
| 7831 | 0 | 0 |  |  |  | 0 | $name ne '' | 
| 7832 |  |  |  |  |  |  | and push @line0, substr $name, 0, 24; | 
| 7833 |  |  |  |  |  |  | } | 
| 7834 |  |  |  |  |  |  |  | 
| 7835 | 0 | 0 |  |  |  | 0 | if ( my $code = $self->can( '__encode_operational_status' ) ) { | 
| 7836 | 0 |  |  |  |  | 0 | push @line0, sprintf '[%s]', $code->( $self, 'status' ); | 
| 7837 |  |  |  |  |  |  | } | 
| 7838 |  |  |  |  |  |  |  | 
| 7839 | 0 |  |  |  |  | 0 | foreach my $name ( sort keys %hack ) { | 
| 7840 | 0 | 0 |  |  |  | 0 | defined( my $value = $self->get( $name ) ) or next; | 
| 7841 | 0 |  |  |  |  | 0 | push @line0, $hack{$name}->( $self, $name, $value ); | 
| 7842 |  |  |  |  |  |  | } | 
| 7843 | 0 | 0 |  |  |  | 0 | @line0 and $output .= join (' ', @line0) . "\n"; | 
| 7844 |  |  |  |  |  |  |  | 
| 7845 | 0 |  |  |  |  | 0 | my %ele; | 
| 7846 |  |  |  |  |  |  | { | 
| 7847 | 0 |  |  |  |  | 0 | my @missing_fields; | 
|  | 0 |  |  |  |  | 0 |  | 
| 7848 | 0 |  |  |  |  | 0 | foreach ( @required_fields ) { | 
| 7849 | 0 | 0 |  |  |  | 0 | defined( $ele{$_} = $self->get( $_ ) ) | 
| 7850 |  |  |  |  |  |  | and next; | 
| 7851 | 0 |  |  |  |  | 0 | push @missing_fields, $_; | 
| 7852 |  |  |  |  |  |  | } | 
| 7853 |  |  |  |  |  |  |  | 
| 7854 | 0 | 0 |  |  |  | 0 | if ( @missing_fields ) { | 
| 7855 |  |  |  |  |  |  | # If all required fields are missing we presume it is | 
| 7856 |  |  |  |  |  |  | # deliberate, and return nothing. | 
| 7857 | 0 | 0 |  |  |  | 0 | @required_fields == @missing_fields | 
| 7858 |  |  |  |  |  |  | and return undef;	## no critic (ProhibitExplicitReturnUndef) | 
| 7859 |  |  |  |  |  |  | # Otherwise we croak with an error | 
| 7860 | 0 | 0 |  |  |  | 0 | croak 'Can not generate TLE for ', | 
| 7861 |  |  |  |  |  |  | defined $oid ? $oid : $name, | 
| 7862 |  |  |  |  |  |  | '; undefined attribute(s) ', | 
| 7863 |  |  |  |  |  |  | join ', ', @missing_fields; | 
| 7864 |  |  |  |  |  |  | } | 
| 7865 | 0 |  |  |  |  | 0 | my $temp = SGP_TWOPI; | 
| 7866 | 0 |  |  |  |  | 0 | foreach (qw{meanmotion firstderivative secondderivative}) { | 
| 7867 | 0 |  |  |  |  | 0 | $temp /= SGP_XMNPDA; | 
| 7868 | 0 |  |  |  |  | 0 | $ele{$_} /= $temp; | 
| 7869 |  |  |  |  |  |  | } | 
| 7870 | 0 |  |  |  |  | 0 | foreach (qw{ascendingnode argumentofperigee meananomaly | 
| 7871 |  |  |  |  |  |  | inclination}) { | 
| 7872 | 0 |  |  |  |  | 0 | $ele{$_} /= SGP_DE2RA; | 
| 7873 |  |  |  |  |  |  | } | 
| 7874 | 0 |  |  |  |  | 0 | foreach my $key (qw{eccentricity}) { | 
| 7875 | 0 |  |  |  |  | 0 | local $_ = sprintf '%.7f', $ele{$key}; | 
| 7876 | 0 |  |  |  |  | 0 | s/.*?\.//; | 
| 7877 | 0 |  |  |  |  | 0 | $ele{$key} = $_; | 
| 7878 |  |  |  |  |  |  | } | 
| 7879 | 0 |  |  |  |  | 0 | $ele{epoch} = $self->__make_tle_epoch(); | 
| 7880 |  |  |  |  |  |  | $ele{firstderivative} = sprintf ( | 
| 7881 | 0 |  |  |  |  | 0 | '%.8f', $ele{firstderivative}); | 
| 7882 | 0 |  |  |  |  | 0 | $ele{firstderivative} =~ s/([-+]?)[\s0]*\./$1./; | 
| 7883 | 0 |  |  |  |  | 0 | foreach my $key (qw{secondderivative bstardrag}) { | 
| 7884 | 0 | 0 |  |  |  | 0 | if ($ele{$key}) { | 
| 7885 | 0 |  |  |  |  | 0 | local $_ = sprintf '%.4e', $ele{$key}; | 
| 7886 | 0 |  |  |  |  | 0 | s/\.//; | 
| 7887 | 0 |  |  |  |  | 0 | my ($mantissa, $exponent) = split 'e', $_; | 
| 7888 | 0 |  |  |  |  | 0 | $exponent++; | 
| 7889 | 0 |  |  |  |  | 0 | $ele{$key} = sprintf '%s%+1d', $mantissa, $exponent; | 
| 7890 |  |  |  |  |  |  | } else { | 
| 7891 | 0 |  |  |  |  | 0 | $ele{$key} = '00000-0'; | 
| 7892 |  |  |  |  |  |  | } | 
| 7893 |  |  |  |  |  |  | } | 
| 7894 |  |  |  |  |  |  | } | 
| 7895 |  |  |  |  |  |  | $output .= _make_tle_checksum ('1%6s%s %-8s %-14s %10s %8s %8s %s %4s', | 
| 7896 |  |  |  |  |  |  | $oid, $self->get('classification'), | 
| 7897 |  |  |  |  |  |  | $self->get('international'), | 
| 7898 | 0 |  |  |  |  | 0 | ( map { $ele{$_} } qw{ epoch firstderivative | 
|  | 0 |  |  |  |  | 0 |  | 
| 7899 |  |  |  |  |  |  | secondderivative bstardrag} ), | 
| 7900 |  |  |  |  |  |  | $self->get('ephemeristype'), $self->get('elementnumber'), | 
| 7901 |  |  |  |  |  |  | ); | 
| 7902 |  |  |  |  |  |  | $output .= _make_tle_checksum ('2%6s%9.4f%9.4f %-7s%9.4f%9.4f%12.8f%5s', | 
| 7903 | 0 |  |  |  |  | 0 | $oid, ( map { $ele{$_} } qw{ inclination ascendingnode | 
|  | 0 |  |  |  |  | 0 |  | 
| 7904 |  |  |  |  |  |  | eccentricity argumentofperigee meananomaly meanmotion | 
| 7905 |  |  |  |  |  |  | revolutionsatepoch } ), | 
| 7906 |  |  |  |  |  |  | ); | 
| 7907 | 0 |  |  |  |  | 0 | return $output; | 
| 7908 |  |  |  |  |  |  | } | 
| 7909 |  |  |  |  |  |  | } | 
| 7910 |  |  |  |  |  |  |  | 
| 7911 |  |  |  |  |  |  | sub __make_tle_epoch { | 
| 7912 | 0 |  |  | 0 |  | 0 | my ( $self ) = @_; | 
| 7913 | 0 |  |  |  |  | 0 | my $epoch = $self->get('epoch'); | 
| 7914 | 0 |  |  |  |  | 0 | my $epoch_dayfrac = sprintf '%.8f', ($epoch / SECSPERDAY); | 
| 7915 | 0 |  |  |  |  | 0 | $epoch_dayfrac =~ s/.*?\././; | 
| 7916 | 0 |  |  |  |  | 0 | my $epoch_daynum = strftime '%y%j', gmtime ($epoch); | 
| 7917 | 0 |  |  |  |  | 0 | return $epoch_daynum . $epoch_dayfrac; | 
| 7918 |  |  |  |  |  |  | } | 
| 7919 |  |  |  |  |  |  |  | 
| 7920 |  |  |  |  |  |  | #	$output = _make_tle_checksum($fmt ...); | 
| 7921 |  |  |  |  |  |  | # | 
| 7922 |  |  |  |  |  |  | #	This subroutine calls sprintf using the first argument as a | 
| 7923 |  |  |  |  |  |  | #	format and the rest as arguments. It then computes the TLE-style | 
| 7924 |  |  |  |  |  |  | #	checksum, appends it to the output, slaps a newline on the end | 
| 7925 |  |  |  |  |  |  | #	of the whole thing, and returns it. | 
| 7926 |  |  |  |  |  |  |  | 
| 7927 |  |  |  |  |  |  | sub _make_tle_checksum { | 
| 7928 | 0 |  |  | 0 |  | 0 | my ($fmt, @args) = @_; | 
| 7929 | 0 |  |  |  |  | 0 | my $buffer = sprintf $fmt, @args; | 
| 7930 | 0 |  |  |  |  | 0 | my $sum = 0; | 
| 7931 | 0 |  |  |  |  | 0 | foreach (split '', $buffer) { | 
| 7932 | 0 | 0 |  |  |  | 0 | if ($_ eq '-') { | 
|  |  | 0 |  |  |  |  |  | 
| 7933 | 0 |  |  |  |  | 0 | $sum++; | 
| 7934 |  |  |  |  |  |  | } elsif ( m/ [0-9] /smx ) { | 
| 7935 | 0 |  |  |  |  | 0 | $sum += $_; | 
| 7936 |  |  |  |  |  |  | } | 
| 7937 |  |  |  |  |  |  | } | 
| 7938 | 0 |  |  |  |  | 0 | $sum = $sum % 10; | 
| 7939 | 0 |  |  |  |  | 0 | return sprintf "%-68s%i\n", substr ($buffer, 0, 68), $sum; | 
| 7940 |  |  |  |  |  |  | } | 
| 7941 |  |  |  |  |  |  |  | 
| 7942 |  |  |  |  |  |  | #	_normalize_oid | 
| 7943 |  |  |  |  |  |  | # | 
| 7944 |  |  |  |  |  |  | #	Normalize an OID by expanding it to five digits. | 
| 7945 |  |  |  |  |  |  |  | 
| 7946 |  |  |  |  |  |  | sub _normalize_oid { | 
| 7947 | 63 |  |  | 63 |  | 147 | my ( $oid ) = @_; | 
| 7948 | 63 | 50 |  |  |  | 186 | $oid =~ m/ [^0-9] /smx | 
| 7949 |  |  |  |  |  |  | and return $oid; | 
| 7950 | 63 |  |  |  |  | 356 | return sprintf '%05d', $oid; | 
| 7951 |  |  |  |  |  |  | } | 
| 7952 |  |  |  |  |  |  |  | 
| 7953 |  |  |  |  |  |  | #	_set_illum | 
| 7954 |  |  |  |  |  |  |  | 
| 7955 |  |  |  |  |  |  | #	Setting the {illum} attribute is complex enough that the code | 
| 7956 |  |  |  |  |  |  | #	got pulled out into its own subroutine. As with all mutators, | 
| 7957 |  |  |  |  |  |  | #	the arguments are the object reference, the attribute name, and | 
| 7958 |  |  |  |  |  |  | #	the new value. | 
| 7959 |  |  |  |  |  |  |  | 
| 7960 |  |  |  |  |  |  | __PACKAGE__->alias (sun => 'Astro::Coord::ECI::Sun'); | 
| 7961 |  |  |  |  |  |  | __PACKAGE__->alias (moon => 'Astro::Coord::ECI::Moon'); | 
| 7962 |  |  |  |  |  |  | sub _set_illum { | 
| 7963 | 108 |  |  | 108 |  | 240 | my ($self, $name, $body) = @_; | 
| 7964 | 108 | 50 |  |  |  | 238 | unless (ref $body) { | 
| 7965 | 108 | 50 |  |  |  | 295 | $type_map{$body} and $body = $type_map{$body}; | 
| 7966 | 108 |  |  |  |  | 323 | load_module ($body); | 
| 7967 |  |  |  |  |  |  | } | 
| 7968 | 108 | 50 |  |  |  | 284 | embodies ($body, 'Astro::Coord::ECI') or croak < | 
| 7969 |  |  |  |  |  |  | Error - The illuminating body must be an Astro::Coord::ECI, or a | 
| 7970 |  |  |  |  |  |  | subclass thereof, or the words 'sun' or 'moon', which are | 
| 7971 |  |  |  |  |  |  | handled as special cases. You tried to use a | 
| 7972 | 0 |  | 0 |  |  | 0 | '@{[ref $body || $body]}'. | 
| 7973 |  |  |  |  |  |  | eod | 
| 7974 | 108 | 50 |  |  |  | 439 | ref $body or $body = $body->new (); | 
| 7975 | 108 |  |  |  |  | 236 | $self->{$name} = $body; | 
| 7976 | 108 |  |  |  |  | 452 | return 0; | 
| 7977 |  |  |  |  |  |  | } | 
| 7978 |  |  |  |  |  |  |  | 
| 7979 |  |  |  |  |  |  | sub _set_intldes { | 
| 7980 | 44 |  |  | 44 |  | 104 | my ( $self, $name, $val ) = @_; | 
| 7981 |  |  |  |  |  |  |  | 
| 7982 | 44 | 100 | 66 |  |  | 225 | if ( defined $val && $val =~ m/ \S /smx ) { | 
| 7983 |  |  |  |  |  |  |  | 
| 7984 | 31 |  |  |  |  | 55 | my $working = $val; | 
| 7985 |  |  |  |  |  |  |  | 
| 7986 | 31 |  |  |  |  | 76 | $working =~ s/ \s+ \z //smx; | 
| 7987 | 31 |  |  |  |  | 52 | $working =~ s/ \s /0/smxg; | 
| 7988 |  |  |  |  |  |  |  | 
| 7989 | 31 |  |  |  |  | 138 | foreach my $re ( | 
| 7990 |  |  |  |  |  |  | qr< ( [0-9]+ ) - ( [0-9]+ ) ( .+ ) >smx, | 
| 7991 |  |  |  |  |  |  | qr< ( [0-9]{2} ) ( [0-9]{3} ) ( .+ ) >smx, | 
| 7992 |  |  |  |  |  |  | ) { | 
| 7993 | 62 | 100 |  |  |  | 1483 | $working =~ m/ \A $re \z /smx | 
| 7994 |  |  |  |  |  |  | or next; | 
| 7995 | 30 |  |  |  |  | 137 | my ( $year, $num, $piece ) = ( $1, $2, $3 ); | 
| 7996 |  |  |  |  |  |  |  | 
| 7997 | 30 | 100 |  |  |  | 117 | $year < 100 | 
|  |  | 50 |  |  |  |  |  | 
| 7998 |  |  |  |  |  |  | and $year += $year < 57 ? 2000 : 1900; | 
| 7999 |  |  |  |  |  |  |  | 
| 8000 | 30 |  |  |  |  | 85 | $self->{launch_year} = $year; | 
| 8001 | 30 |  |  |  |  | 58 | $self->{launch_num} = $num; | 
| 8002 | 30 |  |  |  |  | 63 | $self->{launch_piece} = $piece; | 
| 8003 |  |  |  |  |  |  |  | 
| 8004 | 30 |  |  |  |  | 159 | $self->{$name} = sprintf '%02d%03d%s', $year % 100, $num, $piece; | 
| 8005 |  |  |  |  |  |  |  | 
| 8006 | 30 |  |  |  |  | 177 | return 0; | 
| 8007 |  |  |  |  |  |  | } | 
| 8008 |  |  |  |  |  |  |  | 
| 8009 |  |  |  |  |  |  | } | 
| 8010 |  |  |  |  |  |  |  | 
| 8011 |  |  |  |  |  |  | # We bypass the public interface to avoid thrashing | 
| 8012 |  |  |  |  |  |  |  | 
| 8013 |  |  |  |  |  |  | $self->{launch_year} = | 
| 8014 |  |  |  |  |  |  | $self->{launch_num} = | 
| 8015 | 14 |  |  |  |  | 65 | $self->{launch_piece} = undef; | 
| 8016 |  |  |  |  |  |  |  | 
| 8017 | 14 |  |  |  |  | 49 | $self->{$name} = $val; | 
| 8018 |  |  |  |  |  |  |  | 
| 8019 | 14 |  |  |  |  | 51 | return 0; | 
| 8020 |  |  |  |  |  |  | } | 
| 8021 |  |  |  |  |  |  |  | 
| 8022 |  |  |  |  |  |  | { | 
| 8023 |  |  |  |  |  |  | my %intldes_valid = ( | 
| 8024 |  |  |  |  |  |  | launch_year	=> sub { | 
| 8025 |  |  |  |  |  |  | my ( $val ) = @_; | 
| 8026 |  |  |  |  |  |  | $val =~ RE_ALL_DIGITS | 
| 8027 |  |  |  |  |  |  | and $val <= 9999 | 
| 8028 |  |  |  |  |  |  | or croak 'Invalid launch_year'; | 
| 8029 |  |  |  |  |  |  | $val < 100 | 
| 8030 |  |  |  |  |  |  | and $val += $val < 57 ? 2000 : 1900; | 
| 8031 |  |  |  |  |  |  | return $val + 0; | 
| 8032 |  |  |  |  |  |  | }, | 
| 8033 |  |  |  |  |  |  | launch_num	=> sub { | 
| 8034 |  |  |  |  |  |  | my ( $val ) = @_; | 
| 8035 |  |  |  |  |  |  | $val =~ RE_ALL_DIGITS | 
| 8036 |  |  |  |  |  |  | and $val < 1000 | 
| 8037 |  |  |  |  |  |  | or croak 'Invalid launch_num'; | 
| 8038 |  |  |  |  |  |  | return $val + 0; | 
| 8039 |  |  |  |  |  |  | }, | 
| 8040 |  |  |  |  |  |  | launch_piece	=> sub { | 
| 8041 |  |  |  |  |  |  | my ( $val ) = @_; | 
| 8042 |  |  |  |  |  |  | $val =~ m/ \A [[:alpha:]]+ \z /smx | 
| 8043 |  |  |  |  |  |  | or croak 'Invalid launch_piece'; | 
| 8044 |  |  |  |  |  |  | return uc $val; | 
| 8045 |  |  |  |  |  |  | }, | 
| 8046 |  |  |  |  |  |  | ); | 
| 8047 |  |  |  |  |  |  |  | 
| 8048 |  |  |  |  |  |  | my $value_or_empty = sub { | 
| 8049 |  |  |  |  |  |  | my ( $self, $name ) = @_; | 
| 8050 |  |  |  |  |  |  | return defined $self->{$name} ? $self->{$name} : ''; | 
| 8051 |  |  |  |  |  |  | }; | 
| 8052 |  |  |  |  |  |  |  | 
| 8053 |  |  |  |  |  |  | sub _set_intldes_part { | 
| 8054 | 4 |  |  | 4 |  | 11 | my ( $self, $name, $val ) = @_; | 
| 8055 |  |  |  |  |  |  |  | 
| 8056 |  |  |  |  |  |  | $self->{$name} = defined $val ? | 
| 8057 | 4 | 100 |  |  |  | 16 | $intldes_valid{$name}->( $val ) : | 
| 8058 |  |  |  |  |  |  | $val; | 
| 8059 |  |  |  |  |  |  |  | 
| 8060 | 4 |  |  |  |  | 7 | my %intldes; | 
| 8061 | 4 |  |  |  |  | 10 | foreach my $key ( qw{ launch_year launch_num launch_piece } ) { | 
| 8062 | 12 |  |  |  |  | 20 | $intldes{$key} = $value_or_empty->( $self, $key ); | 
| 8063 |  |  |  |  |  |  | } | 
| 8064 |  |  |  |  |  |  | $intldes{launch_year} eq '' | 
| 8065 | 4 | 100 |  |  |  | 14 | or $intldes{launch_year} %= 100; | 
| 8066 |  |  |  |  |  |  |  | 
| 8067 |  |  |  |  |  |  | my $tplt = join '', | 
| 8068 |  |  |  |  |  |  | ( $intldes{launch_year} eq '' ? '%2s' : '%02d' ), | 
| 8069 | 4 | 100 |  |  |  | 16 | ( $intldes{launch_num} eq '' ? '%3s' : '%03d' ), | 
|  |  | 100 |  |  |  |  |  | 
| 8070 |  |  |  |  |  |  | '%s'; | 
| 8071 | 4 |  |  |  |  | 9 | $self->{international} = sprintf $tplt, map { $intldes{$_} } | 
|  | 12 |  |  |  |  | 36 |  | 
| 8072 |  |  |  |  |  |  | qw{ launch_year launch_num launch_piece }; | 
| 8073 |  |  |  |  |  |  |  | 
| 8074 | 4 |  |  |  |  | 19 | return 0; | 
| 8075 |  |  |  |  |  |  | } | 
| 8076 |  |  |  |  |  |  |  | 
| 8077 |  |  |  |  |  |  | } | 
| 8078 |  |  |  |  |  |  |  | 
| 8079 |  |  |  |  |  |  | # _set_object_type | 
| 8080 |  |  |  |  |  |  | # | 
| 8081 |  |  |  |  |  |  | # This acts as a mutator for the object type. | 
| 8082 |  |  |  |  |  |  | { | 
| 8083 |  |  |  |  |  |  | my %name_to_type; | 
| 8084 |  |  |  |  |  |  | my @number_to_type; | 
| 8085 |  |  |  |  |  |  | foreach my $type ( | 
| 8086 |  |  |  |  |  |  | BODY_TYPE_UNKNOWN, | 
| 8087 |  |  |  |  |  |  | BODY_TYPE_DEBRIS, | 
| 8088 |  |  |  |  |  |  | BODY_TYPE_ROCKET_BODY, | 
| 8089 |  |  |  |  |  |  | BODY_TYPE_PAYLOAD, | 
| 8090 |  |  |  |  |  |  | ) { | 
| 8091 |  |  |  |  |  |  | $number_to_type[$type] = $type; | 
| 8092 |  |  |  |  |  |  | $name_to_type{ fold_case( $type ) } = $type; | 
| 8093 |  |  |  |  |  |  | } | 
| 8094 |  |  |  |  |  |  | sub _set_object_type { | 
| 8095 | 0 |  |  | 0 |  | 0 | my ( $self, $name, $value ) = @_; | 
| 8096 | 0 | 0 |  |  |  | 0 | if ( defined $value ) { | 
| 8097 | 0 | 0 |  |  |  | 0 | if ( $value =~ RE_ALL_DIGITS ) { | 
| 8098 | 0 |  |  |  |  | 0 | $self->{$name} = $number_to_type[$value]; | 
| 8099 |  |  |  |  |  |  | } else { | 
| 8100 | 0 |  |  |  |  | 0 | $self->{$name} = $name_to_type{ fold_case( $value ) }; | 
| 8101 |  |  |  |  |  |  | } | 
| 8102 | 0 | 0 |  |  |  | 0 | unless ( defined $self->{$name} ) { | 
| 8103 | 0 |  |  |  |  | 0 | carp "Invalid $name '$value'; setting to unknown"; | 
| 8104 | 0 |  |  |  |  | 0 | $self->{$name} = BODY_TYPE_UNKNOWN; | 
| 8105 |  |  |  |  |  |  | } | 
| 8106 |  |  |  |  |  |  | } else { | 
| 8107 | 0 |  |  |  |  | 0 | $self->{$name} = undef; | 
| 8108 |  |  |  |  |  |  | } | 
| 8109 | 0 |  |  |  |  | 0 | return 0; | 
| 8110 |  |  |  |  |  |  | } | 
| 8111 |  |  |  |  |  |  | } | 
| 8112 |  |  |  |  |  |  |  | 
| 8113 |  |  |  |  |  |  | # _set_optional_float_no_reinit | 
| 8114 |  |  |  |  |  |  | # | 
| 8115 |  |  |  |  |  |  | # This acts as a mutator for any attribute whose value is either undef | 
| 8116 |  |  |  |  |  |  | # or a floating-point number, and which does not cause the model to be | 
| 8117 |  |  |  |  |  |  | # renitialized when its value changes. We disallow NaN. | 
| 8118 |  |  |  |  |  |  |  | 
| 8119 |  |  |  |  |  |  | sub _set_optional_float_no_reinit { | 
| 8120 | 3 |  |  | 3 |  | 9 | my ( $self, $name, $value ) = @_; | 
| 8121 | 3 | 50 | 33 |  |  | 17 | if ( defined $value && ! _looks_like_real( $value ) ) { | 
| 8122 | 0 |  |  |  |  | 0 | carp "Invalid $name '$value'; must be a float or undef"; | 
| 8123 | 0 |  |  |  |  | 0 | $value = undef; | 
| 8124 |  |  |  |  |  |  | } | 
| 8125 | 3 |  |  |  |  | 9 | $self->{$name} = $value; | 
| 8126 | 3 |  |  |  |  | 13 | return 0; | 
| 8127 |  |  |  |  |  |  | } | 
| 8128 |  |  |  |  |  |  |  | 
| 8129 |  |  |  |  |  |  | # _set_optional_unsigned_integer_no_reinit | 
| 8130 |  |  |  |  |  |  | # | 
| 8131 |  |  |  |  |  |  | # This acts as a mutator for any attribute whose value is either undef | 
| 8132 |  |  |  |  |  |  | # or an unsigned integer, and which does not cause the model to be | 
| 8133 |  |  |  |  |  |  | # reinitialized when its value changes. | 
| 8134 |  |  |  |  |  |  |  | 
| 8135 |  |  |  |  |  |  | sub _set_optional_unsigned_integer_no_reinit { | 
| 8136 | 0 |  |  | 0 |  | 0 | my ( $self, $name, $value ) = @_; | 
| 8137 | 0 | 0 | 0 |  |  | 0 | if ( defined $value && $value =~ m/ [^0-9] /smx ) { | 
| 8138 | 0 |  |  |  |  | 0 | carp "Invalid $name '$value'; must be unsigned integer or undef"; | 
| 8139 | 0 |  |  |  |  | 0 | $value = undef; | 
| 8140 |  |  |  |  |  |  | } | 
| 8141 | 0 |  |  |  |  | 0 | $self->{$name} = $value; | 
| 8142 | 0 |  |  |  |  | 0 | return 0; | 
| 8143 |  |  |  |  |  |  | } | 
| 8144 |  |  |  |  |  |  |  | 
| 8145 |  |  |  |  |  |  | sub _next_elevation_screen { | 
| 8146 | 95 |  |  | 95 |  | 351 | my ( $sta, $pass_step, @args ) = @_; | 
| 8147 | 95 | 50 |  |  |  | 286 | ref $sta | 
| 8148 |  |  |  |  |  |  | or confess 'Programming error - station not a reference'; | 
| 8149 | 95 |  |  |  |  | 410 | my ( $suntim, $dawn ) = $sta->next_elevation( @args ); | 
| 8150 | 95 | 50 |  |  |  | 326 | defined $suntim | 
| 8151 |  |  |  |  |  |  | or confess 'Programming error - time of next elevation undefined'; | 
| 8152 | 95 | 100 |  |  |  | 294 | $dawn or $pass_step = - $pass_step; | 
| 8153 | 95 |  |  |  |  | 294 | my $sun_screen = $suntim + $pass_step / 2; | 
| 8154 | 95 | 100 |  |  |  | 590 | return ( $suntim, $dawn, $sun_screen, | 
| 8155 |  |  |  |  |  |  | $dawn ? $sun_screen : $suntim, | 
| 8156 |  |  |  |  |  |  | ); | 
| 8157 |  |  |  |  |  |  | } | 
| 8158 |  |  |  |  |  |  |  | 
| 8159 |  |  |  |  |  |  | ####################################################################### | 
| 8160 |  |  |  |  |  |  |  | 
| 8161 |  |  |  |  |  |  | #	Initialization of aliases and status | 
| 8162 |  |  |  |  |  |  |  | 
| 8163 |  |  |  |  |  |  | { | 
| 8164 |  |  |  |  |  |  | # The following classes initialize themselves on load. | 
| 8165 |  |  |  |  |  |  | local $@ = undef; | 
| 8166 |  |  |  |  |  |  | eval {	## no critic (RequireCheckingReturnValueOfEval) | 
| 8167 |  |  |  |  |  |  | require Astro::Coord::ECI::TLE::Iridium; | 
| 8168 |  |  |  |  |  |  | }; | 
| 8169 |  |  |  |  |  |  | } | 
| 8170 |  |  |  |  |  |  |  | 
| 8171 |  |  |  |  |  |  | # The following is all the Celestrak visual list that have magnitudes in | 
| 8172 |  |  |  |  |  |  | # Heavens Above.  These data are generated by the following: | 
| 8173 |  |  |  |  |  |  | # | 
| 8174 |  |  |  |  |  |  | #   $ tools/heavens-above-mag --celestrak | 
| 8175 |  |  |  |  |  |  | # | 
| 8176 |  |  |  |  |  |  | # Last-Modified: Mon, 27 Feb 2023 21:40:21 GMT | 
| 8177 |  |  |  |  |  |  |  | 
| 8178 |  |  |  |  |  |  | # The following constants are unsupported, and may be modified or | 
| 8179 |  |  |  |  |  |  | # revoked at any time. They exist to support | 
| 8180 |  |  |  |  |  |  | # xt/author/magnitude_status.t | 
| 8181 | 16 |  |  | 16 |  | 190 | use constant _CELESTRAK_VISUAL => 'Mon, 27 Feb 2023 21:40:21 GMT'; | 
|  | 16 |  |  |  |  | 41 |  | 
|  | 16 |  |  |  |  | 1379 |  | 
| 8182 | 16 |  |  | 16 |  | 123 | use constant _MCCANTS_VSNAMES  => undef; | 
|  | 16 |  |  |  |  | 47 |  | 
|  | 16 |  |  |  |  | 1036 |  | 
| 8183 | 16 |  |  | 16 |  | 107 | use constant _MCCANTS_QUICKSAT => undef; | 
|  | 16 |  |  |  |  | 45 |  | 
|  | 16 |  |  |  |  | 7238 |  | 
| 8184 |  |  |  |  |  |  |  | 
| 8185 |  |  |  |  |  |  | %magnitude_table = ( | 
| 8186 |  |  |  |  |  |  | '00694' =>   2.7, # ATLAS CENTAUR 2 R/B | 
| 8187 |  |  |  |  |  |  | '00733' =>   4.2, # THOR AGENA D R/B | 
| 8188 |  |  |  |  |  |  | '00877' =>   4.2, # SL-3 R/B | 
| 8189 |  |  |  |  |  |  | '02802' =>   4.7, # SL-8 R/B | 
| 8190 |  |  |  |  |  |  | '03230' =>   5.2, # SL-8 R/B | 
| 8191 |  |  |  |  |  |  | '03597' =>   5.7, # OAO 2 | 
| 8192 |  |  |  |  |  |  | '03669' =>   8.2, # ISIS 1 | 
| 8193 |  |  |  |  |  |  | '04327' =>   5.7, # SERT 2 | 
| 8194 |  |  |  |  |  |  | '04814' =>   4.2, # SL-3 R/B | 
| 8195 |  |  |  |  |  |  | '05118' =>   4.2, # SL-3 R/B | 
| 8196 |  |  |  |  |  |  | '05560' =>   4.2, # ASTEX 1 | 
| 8197 |  |  |  |  |  |  | '05730' =>   4.2, # SL-8 R/B | 
| 8198 |  |  |  |  |  |  | '06073' =>   5.7, # COSMOS 482 DESCENT CRAFT | 
| 8199 |  |  |  |  |  |  | '06153' =>   5.2, # OAO 3 (COPERNICUS) | 
| 8200 |  |  |  |  |  |  | '06155' =>   4.2, # ATLAS CENTAUR R/B | 
| 8201 |  |  |  |  |  |  | '08459' =>   5.2, # SL-8 R/B | 
| 8202 |  |  |  |  |  |  | '10114' =>   4.7, # SL-3 R/B | 
| 8203 |  |  |  |  |  |  | '10967' =>   3.2, # SEASAT 1 | 
| 8204 |  |  |  |  |  |  | '11251' =>   4.7, # METEOR 1-29 | 
| 8205 |  |  |  |  |  |  | '11267' =>   4.7, # SL-14 R/B | 
| 8206 |  |  |  |  |  |  | '11574' =>   4.2, # SL-8 R/B | 
| 8207 |  |  |  |  |  |  | '11672' =>   4.2, # SL-14 R/B | 
| 8208 |  |  |  |  |  |  | '12139' =>   4.2, # SL-8 R/B | 
| 8209 |  |  |  |  |  |  | '12465' =>   4.2, # SL-3 R/B | 
| 8210 |  |  |  |  |  |  | '12585' =>   5.2, # METEOR PRIRODA | 
| 8211 |  |  |  |  |  |  | '12904' =>   4.2, # SL-3 R/B | 
| 8212 |  |  |  |  |  |  | '13068' =>   4.2, # SL-3 R/B | 
| 8213 |  |  |  |  |  |  | '13154' =>   4.7, # SL-3 R/B | 
| 8214 |  |  |  |  |  |  | '13403' =>   4.2, # SL-3 R/B | 
| 8215 |  |  |  |  |  |  | '13552' =>   4.2, # COSMOS 1408 | 
| 8216 |  |  |  |  |  |  | '13553' =>   4.7, # SL-14 R/B | 
| 8217 |  |  |  |  |  |  | '13819' =>   4.7, # SL-3 R/B | 
| 8218 |  |  |  |  |  |  | '14032' =>   3.7, # COSMOS 1455 | 
| 8219 |  |  |  |  |  |  | '14208' =>   4.2, # SL-3 R/B | 
| 8220 |  |  |  |  |  |  | '14372' =>   4.7, # COSMOS 1500 | 
| 8221 |  |  |  |  |  |  | '14699' =>   4.2, # COSMOS 1536 | 
| 8222 |  |  |  |  |  |  | '14819' =>   4.7, # COSMOS 1544 | 
| 8223 |  |  |  |  |  |  | '14820' =>   4.7, # SL-14 R/B | 
| 8224 |  |  |  |  |  |  | '15483' =>   4.7, # SL-8 R/B | 
| 8225 |  |  |  |  |  |  | '15494' =>   3.7, # COSMOS 1626 | 
| 8226 |  |  |  |  |  |  | '15772' =>   4.2, # SL-12 R/B(2) | 
| 8227 |  |  |  |  |  |  | '15945' =>   4.7, # SL-14 R/B | 
| 8228 |  |  |  |  |  |  | '16182' =>   3.2, # SL-16 R/B | 
| 8229 |  |  |  |  |  |  | '16496' =>   4.7, # SL-14 R/B | 
| 8230 |  |  |  |  |  |  | '16719' =>   4.2, # COSMOS 1743 | 
| 8231 |  |  |  |  |  |  | '16792' =>   4.7, # SL-14 R/B | 
| 8232 |  |  |  |  |  |  | '16882' =>   4.7, # SL-14 R/B | 
| 8233 |  |  |  |  |  |  | '16908' =>   4.2, # EGS (AJISAI) | 
| 8234 |  |  |  |  |  |  | '17295' =>   4.2, # COSMOS 1812 | 
| 8235 |  |  |  |  |  |  | '17567' =>   4.7, # SL-14 R/B | 
| 8236 |  |  |  |  |  |  | '17589' =>   4.7, # COSMOS 1833 | 
| 8237 |  |  |  |  |  |  | '17590' =>   3.2, # SL-16 R/B | 
| 8238 |  |  |  |  |  |  | '17912' =>   4.7, # SL-14 R/B | 
| 8239 |  |  |  |  |  |  | '17973' =>   4.2, # COSMOS 1844 | 
| 8240 |  |  |  |  |  |  | '18153' =>   4.7, # SL-14 R/B | 
| 8241 |  |  |  |  |  |  | '18187' =>   4.2, # COSMOS 1867 | 
| 8242 |  |  |  |  |  |  | '18421' =>   4.2, # COSMOS 1892 | 
| 8243 |  |  |  |  |  |  | '18749' =>   4.7, # SL-14 R/B | 
| 8244 |  |  |  |  |  |  | '18958' =>   4.7, # COSMOS 1933 | 
| 8245 |  |  |  |  |  |  | '19046' =>   4.2, # SL-3 R/B | 
| 8246 |  |  |  |  |  |  | '19120' =>   2.7, # SL-16 R/B | 
| 8247 |  |  |  |  |  |  | '19210' =>   3.7, # COSMOS 1953 | 
| 8248 |  |  |  |  |  |  | '19257' =>   4.7, # SL-8 R/B | 
| 8249 |  |  |  |  |  |  | '19573' =>   4.2, # COSMOS 1975 | 
| 8250 |  |  |  |  |  |  | '19574' =>   4.2, # SL-14 R/B | 
| 8251 |  |  |  |  |  |  | '19650' =>   2.7, # SL-16 R/B | 
| 8252 |  |  |  |  |  |  | '20261' =>   5.2, # INTERCOSMOS 24 | 
| 8253 |  |  |  |  |  |  | '20262' =>   5.7, # SL-14 R/B | 
| 8254 |  |  |  |  |  |  | '20303' =>   4.2, # DELTA 2 R/B(1) | 
| 8255 |  |  |  |  |  |  | '20323' =>   4.7, # DELTA 1 R/B | 
| 8256 |  |  |  |  |  |  | '20443' =>   4.2, # ARIANE 40 R/B | 
| 8257 |  |  |  |  |  |  | '20453' =>   4.7, # DELTA 2 R/B(1) | 
| 8258 |  |  |  |  |  |  | '20465' =>   4.2, # COSMOS 2058 | 
| 8259 |  |  |  |  |  |  | '20466' =>   4.2, # SL-14 R/B | 
| 8260 |  |  |  |  |  |  | '20511' =>   4.2, # SL-14 R/B | 
| 8261 |  |  |  |  |  |  | '20580' =>   2.2, # HST | 
| 8262 |  |  |  |  |  |  | '20625' =>   2.7, # SL-16 R/B | 
| 8263 |  |  |  |  |  |  | '20663' =>   4.7, # COSMOS 2084 | 
| 8264 |  |  |  |  |  |  | '20666' =>   4.7, # SL-6 R/B(2) | 
| 8265 |  |  |  |  |  |  | '20775' =>   4.2, # SL-8 R/B | 
| 8266 |  |  |  |  |  |  | '21088' =>   4.2, # SL-8 R/B | 
| 8267 |  |  |  |  |  |  | '21397' =>   4.7, # OKEAN 3 | 
| 8268 |  |  |  |  |  |  | '21422' =>   4.2, # COSMOS 2151 | 
| 8269 |  |  |  |  |  |  | '21423' =>   4.7, # SL-14 R/B | 
| 8270 |  |  |  |  |  |  | '21574' =>   5.2, # ERS 1 | 
| 8271 |  |  |  |  |  |  | '21610' =>   3.7, # ARIANE 40 R/B | 
| 8272 |  |  |  |  |  |  | '21819' =>   4.7, # INTERCOSMOS 25 | 
| 8273 |  |  |  |  |  |  | '21876' =>   4.7, # SL-8 R/B | 
| 8274 |  |  |  |  |  |  | '21938' =>   4.2, # SL-8 R/B | 
| 8275 |  |  |  |  |  |  | '21949' =>   4.7, # USA 81 | 
| 8276 |  |  |  |  |  |  | '22219' =>   3.7, # COSMOS 2219 | 
| 8277 |  |  |  |  |  |  | '22220' =>   2.7, # SL-16 R/B | 
| 8278 |  |  |  |  |  |  | '22236' =>   3.7, # COSMOS 2221 | 
| 8279 |  |  |  |  |  |  | '22285' =>   2.7, # SL-16 R/B | 
| 8280 |  |  |  |  |  |  | '22286' =>   4.2, # COSMOS 2228 | 
| 8281 |  |  |  |  |  |  | '22566' =>   2.7, # SL-16 R/B | 
| 8282 |  |  |  |  |  |  | '22626' =>   4.2, # COSMOS 2242 | 
| 8283 |  |  |  |  |  |  | '22803' =>   2.7, # SL-16 R/B | 
| 8284 |  |  |  |  |  |  | '22830' =>   4.2, # ARIANE 40 R/B | 
| 8285 |  |  |  |  |  |  | '23087' =>   4.2, # COSMOS 2278 | 
| 8286 |  |  |  |  |  |  | '23088' =>   2.7, # SL-16 R/B | 
| 8287 |  |  |  |  |  |  | '23343' =>   2.7, # SL-16 R/B | 
| 8288 |  |  |  |  |  |  | '23405' =>   2.7, # SL-16 R/B | 
| 8289 |  |  |  |  |  |  | '23560' =>   3.7, # ERS 2 | 
| 8290 |  |  |  |  |  |  | '23561' =>   3.7, # ARIANE 40+ R/B | 
| 8291 |  |  |  |  |  |  | '23705' =>   2.7, # SL-16 R/B | 
| 8292 |  |  |  |  |  |  | '24298' =>   2.7, # SL-16 R/B | 
| 8293 |  |  |  |  |  |  | '24883' =>   6.8, # ORBVIEW 2 (SEASTAR) | 
| 8294 |  |  |  |  |  |  | '25400' =>   2.7, # SL-16 R/B | 
| 8295 |  |  |  |  |  |  | '25407' =>   2.7, # SL-16 R/B | 
| 8296 |  |  |  |  |  |  | '25544' =>  -1.8, # ISS (ZARYA) | 
| 8297 |  |  |  |  |  |  | '25732' =>   4.2, # CZ-4B R/B | 
| 8298 |  |  |  |  |  |  | '25860' =>   3.7, # OKEAN O | 
| 8299 |  |  |  |  |  |  | '25861' =>   2.7, # SL-16 R/B | 
| 8300 |  |  |  |  |  |  | '25876' =>   4.2, # DELTA 2 R/B | 
| 8301 |  |  |  |  |  |  | '25977' =>   5.7, # HELIOS 1B | 
| 8302 |  |  |  |  |  |  | '25994' =>   2.7, # TERRA | 
| 8303 |  |  |  |  |  |  | '26070' =>   2.7, # SL-16 R/B | 
| 8304 |  |  |  |  |  |  | '26474' =>   2.7, # TITAN 4B R/B | 
| 8305 |  |  |  |  |  |  | '26905' =>   3.7, # USA 160 | 
| 8306 |  |  |  |  |  |  | '26907' =>   3.7, # USA 160 DEB | 
| 8307 |  |  |  |  |  |  | '27386' =>   3.7, # ENVISAT | 
| 8308 |  |  |  |  |  |  | '27422' =>   3.2, # IDEFIX/ARIANE 42P | 
| 8309 |  |  |  |  |  |  | '27424' =>   4.7, # AQUA | 
| 8310 |  |  |  |  |  |  | '27432' =>   3.7, # CZ-4B R/B | 
| 8311 |  |  |  |  |  |  | '27597' =>   2.7, # ADEOS 2 | 
| 8312 |  |  |  |  |  |  | '27601' =>   2.7, # H-2A R/B | 
| 8313 |  |  |  |  |  |  | '28059' =>   4.7, # CZ-4B R/B | 
| 8314 |  |  |  |  |  |  | '28222' =>   4.2, # CZ-2C R/B | 
| 8315 |  |  |  |  |  |  | '28353' =>   2.7, # SL-16 R/B | 
| 8316 |  |  |  |  |  |  | '28415' =>   4.2, # CZ-4B R/B | 
| 8317 |  |  |  |  |  |  | '28480' =>   3.7, # CZ-2C R/B | 
| 8318 |  |  |  |  |  |  | # '28499' => undef, # ARIANE 5 R/B has no recorded magnitude | 
| 8319 |  |  |  |  |  |  | '28738' =>   4.7, # CZ-2D R/B | 
| 8320 |  |  |  |  |  |  | '28773' =>   4.2, # ASTRO E2 | 
| 8321 |  |  |  |  |  |  | '28931' =>   3.2, # ALOS | 
| 8322 |  |  |  |  |  |  | '28932' =>   3.7, # H-2A R/B | 
| 8323 |  |  |  |  |  |  | '28939' =>   6.2, # ASTRO F (AKARI) | 
| 8324 |  |  |  |  |  |  | '29093' =>   3.2, # CZ-4B R/B | 
| 8325 |  |  |  |  |  |  | '29228' =>   3.7, # RESURS DK-1 | 
| 8326 |  |  |  |  |  |  | '29252' =>   4.7, # GENESIS 1 | 
| 8327 |  |  |  |  |  |  | '29507' =>   2.7, # CZ-4B R/B | 
| 8328 |  |  |  |  |  |  | '31114' =>   3.2, # CZ-2C R/B | 
| 8329 |  |  |  |  |  |  | '31598' =>   3.7, # SKYMED 1 | 
| 8330 |  |  |  |  |  |  | '31789' =>   5.7, # GENESIS 2 | 
| 8331 |  |  |  |  |  |  | '31792' =>   3.2, # COSMOS 2428 | 
| 8332 |  |  |  |  |  |  | '31793' =>   2.7, # SL-16 R/B | 
| 8333 |  |  |  |  |  |  | '33504' =>   5.3, # KORONAS-FOTON | 
| 8334 |  |  |  |  |  |  | # '37731' => undef, # CZ-2C R/B has no recorded magnitude | 
| 8335 |  |  |  |  |  |  | '38341' =>   3.2, # H-2A R/B | 
| 8336 |  |  |  |  |  |  | # '39271' => undef, # CUSAT 2/FALCON 9 has no recorded magnitude | 
| 8337 |  |  |  |  |  |  | # '39358' => undef, # SJ-16 has no recorded magnitude | 
| 8338 |  |  |  |  |  |  | # '39364' => undef, # CZ-2C R/B has no recorded magnitude | 
| 8339 |  |  |  |  |  |  | '39679' =>   3.4, # SL-4 R/B | 
| 8340 |  |  |  |  |  |  | '39766' =>   3.7, # ALOS 2 | 
| 8341 |  |  |  |  |  |  | '40354' =>   4.2, # SL-27 R/B | 
| 8342 |  |  |  |  |  |  | # '41038' => undef, # YAOGAN 29 has no recorded magnitude | 
| 8343 |  |  |  |  |  |  | # '41337' => undef, # ASTRO H has no recorded magnitude | 
| 8344 |  |  |  |  |  |  | # '42758' => undef, # HXMT has no recorded magnitude | 
| 8345 |  |  |  |  |  |  | # '43521' => undef, # CZ-2C R/B has no recorded magnitude | 
| 8346 |  |  |  |  |  |  | # '43600' => undef, # AEOLUS has no recorded magnitude | 
| 8347 |  |  |  |  |  |  | # '43641' => undef, # SAOCOM 1-A has no recorded magnitude | 
| 8348 |  |  |  |  |  |  | # '43682' => undef, # H-2A R/B has no recorded magnitude | 
| 8349 |  |  |  |  |  |  | # '46265' => undef, # SAOCOM 1-B has no recorded magnitude | 
| 8350 |  |  |  |  |  |  | '48274' =>   0.0, # CSS (TIANHE-1) | 
| 8351 |  |  |  |  |  |  | # '51842' => undef, # OBJECT U has no recorded magnitude | 
| 8352 |  |  |  |  |  |  | # '52260' => undef, # SZ-13 MODULE has no recorded magnitude | 
| 8353 |  |  |  |  |  |  | # '52794' => undef, # CZ-2C R/B has no recorded magnitude | 
| 8354 |  |  |  |  |  |  | # '53131' => undef, # CZ-2C R/B has no recorded magnitude | 
| 8355 |  |  |  |  |  |  | '53807' =>   3.5, # BLUEWALKER 3 | 
| 8356 |  |  |  |  |  |  | # '54047' => undef, # DRAGON FREEDOM DEB has no recorded magnitude | 
| 8357 |  |  |  |  |  |  | ); | 
| 8358 |  |  |  |  |  |  |  | 
| 8359 |  |  |  |  |  |  | 1; | 
| 8360 |  |  |  |  |  |  |  | 
| 8361 |  |  |  |  |  |  | __END__ |