././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1682599655.3394356 sgp4-2.22/0000755000175100001730000000000014422467347011732 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/LICENSE0000644000175100001730000000207614422467341012736 0ustar00runnerdockerThe MIT License (MIT) Copyright © 2012–2016 Brandon Rhodes Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/MANIFEST.in0000644000175100001730000000016114422467341013460 0ustar00runnerdockerinclude LICENSE include extension/SGP4.h include sgp4/SGP4-VER.TLE include sgp4/sample* include sgp4/tcppver.out ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1682599655.3394356 sgp4-2.22/PKG-INFO0000644000175100001730000007437314422467347013045 0ustar00runnerdockerMetadata-Version: 2.1 Name: sgp4 Version: 2.22 Summary: Track Earth satellites given TLE data, using up-to-date 2020 SGP4 routines. Home-page: https://github.com/brandon-rhodes/python-sgp4 Author: Brandon Rhodes Author-email: brandon@rhodesmill.org License: MIT Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Scientific/Engineering :: Astronomy License-File: LICENSE This package compiles the official C++ code from `Revisiting Spacetrack Report #3 `_ (AIAA 2006-6753) and uses it to compute the positions of satellites in Earth orbit. Orbital elements can be read from either a legacy TLE file or from a modern OMM element set, both of which you can fetch from a site like `CelesTrak `_. If your machine can’t install or compile the C++ code, then this package falls back to using a slower pure-Python implementation of SGP4. Tests make sure that its positions **agree to within 0.1 mm** with the standard version of the algorithm — an error far less than the 1–3 km/day by which satellites themselves deviate from the ideal orbits described in TLE files. An accelerated routine is available that, given a series of times and of satellites, computes a whole array of output positions using a fast C++ loop. See the “Array Acceleration” section below. Note that the SGP4 propagator returns raw *x,y,z* Cartesian coordinates in a “True Equator Mean Equinox” (TEME) reference frame that’s centered on the Earth but does not rotate with it — an “Earth centered inertial” (ECI) reference frame. The SGP4 propagator itself does not implement the math to convert these positions into more official ECI frames like J2000 or the ICRS, nor into any Earth-centered Earth-fixed (ECEF) frames like the ITRS, nor into latitudes and longitudes through an Earth ellipsoid like WGS84. For conversions into these other coordinate frames, look for a comprehensive astronomy library, like the `Skyfield `_ library that is built atop this one (see the `section on Earth satellites `_ in its documentation). Usage ----- You will probably first want to to check whether your machine has successfully installed the fast SGP4 C++ code, or is using the slow Python version (in which case this value will be false): >>> from sgp4.api import accelerated >>> print(accelerated) True This library uses the same function names as the official C++ code, to help users who are already familiar with SGP4 in other languages. Here is how to compute the x,y,z position and velocity for the International Space Station at 12:50:19 on 29 June 2000: >>> from sgp4.api import Satrec >>> >>> s = '1 25544U 98067A 19343.69339541 .00001764 00000-0 38792-4 0 9991' >>> t = '2 25544 51.6439 211.2001 0007417 17.6667 85.6398 15.50103472202482' >>> satellite = Satrec.twoline2rv(s, t) >>> >>> jd, fr = 2458827, 0.362605 >>> e, r, v = satellite.sgp4(jd, fr) >>> e 0 >>> print(r) # True Equator Mean Equinox position (km) (-6102.44..., -986.33..., -2820.31...) >>> print(v) # True Equator Mean Equinox velocity (km/s) (-1.45..., -5.52..., 5.10...) As input, you can provide either: * A simple floating-point Julian Date for ``jd`` and the value 0.0 for ``fr``, if you are happy with the precision of a 64-bit floating point number. Note that modern Julian Dates are greater than 2,450,000 which means that nearly half of the precision of a 64-bit float will be consumed by the whole part that specifies the day. The remaining digits will provide a precision for the fraction of around 20.1 µs. This should be no problem for the accuracy of your result — satellite positions usually off by a few kilometers anyway, far less than a satellite moves in 20.1 µs — but if you run a solver that dives down into the microseconds while searching for a rising or setting time, the solver might be bothered by the 20.1 µs plateau between each jump in the satellite’s position. * Or, you can provide a coarse date ``jd`` plus a very precise fraction ``fr`` that supplies the rest of the value. The Julian Date for which the satellite position is computed is the sum of the two values. One common practice is to provide the whole number as ``jd`` and the fraction as ``fr``; another is to have ``jd`` carry the fraction 0.5 since UTC midnight occurs halfway through each Julian Date. Either way, splitting the value allows a solver to run all the way down into the nanoseconds and still see SGP4 respond smoothly to tiny date adjustments with tiny changes in the resulting satellite position. Here is how to intrepret the results: * ``e`` will be a non-zero error code if the satellite position could not be computed for the given date. You can ``from sgp4.api import SGP4_ERRORS`` to access a dictionary mapping error codes to error messages explaining what each code means. * ``r`` measures the satellite position in **kilometers** from the center of the earth in the idiosyncratic True Equator Mean Equinox coordinate frame used by SGP4. * ``v`` velocity is the rate at which the position is changing, expressed in **kilometers per second**. If your application does not natively handle Julian dates, you can compute ``jd`` and ``fr`` from calendar dates using ``jday()``. >>> from sgp4.api import jday >>> jd, fr = jday(2019, 12, 9, 12, 0, 0) >>> jd 2458826.5 >>> fr 0.5 Double-checking your TLE lines ------------------------------ Because TLE is an old punch-card fixed-width format, it’s very sensitive to whether exactly the right number of spaces are positioned in exactly the right columns. If you suspect that your satellite elements aren’t getting loaded correctly, try calling the slow pure-Python version of ``twoline2rv()``, which performs extra checks that the fast C++ doesn’t: >>> from sgp4.earth_gravity import wgs72 >>> from sgp4.io import twoline2rv >>> assert twoline2rv(s, t, wgs72) Any TLE formatting errors will be raised as a ``ValueError``. Using OMM elements instead of TLE --------------------------------- The industry is migrating away from the original TLE format, because it will soon run out of satellite numbers. * Some TLE files now use a new “Alpha-5” convention that expands the range of satellite numbers by using an initial letter; for example, “E8493” means satellite 148493. This library supports the Alpha-5 convention and should return the correct integer in Python. * Some authorities are now distributing satellite elements in an “OMM” Orbit Mean Elements Message format that replaces the TLE format. You can learn about OMM in Dr. T.S. Kelso’s `“A New Way to Obtain GP Data” `_ at the CelesTrak site. You can already try out experimental support for OMM: >>> from sgp4 import omm Reading OMM data takes two steps, because OMM supports several different text formats. First, parse the input text to recover the field names and values that it stores; second, build a Python satellite object from those field values. For example, to load OMM from XML: >>> with open('sample_omm.xml') as f: ... fields = next(omm.parse_xml(f)) >>> sat = Satrec() >>> omm.initialize(sat, fields) Or, to load OMM from CSV: >>> with open('sample_omm.csv') as f: ... fields = next(omm.parse_csv(f)) >>> sat = Satrec() >>> omm.initialize(sat, fields) Either way, the satellite object should wind up properly initialized and ready to start producing positions. If you are interested in saving satellite parameters using the new OMM format, then read the section on “Export” below. Epoch ----- Over a given satellite’s lifetime, dozens or hundreds of different TLE records will be produced as its orbit evolves. Each TLE record specifies the “epoch date” for which it is most accurate. Typically a TLE is only useful for a couple of weeks to either side of its epoch date, beyond which its predictions become unreliable. Satellite objects natively provide their epoch as a two-digit year and then a fractional number of days into the year: >>> satellite.epochyr 19 >>> satellite.epochdays 343.69339541 Because Sputnik was launched in 1957, satellite element sets will never refer to an earlier year, so years 57 through 99 mean 1957–1999 while 0 through 56 mean 2000–2056. The TLE format will presumably be obsolete in 2057 and have to be upgraded to 4-digit years. To turn the number of days and its fraction into a calendar date and time, use the ``days2mdhms()`` function. >>> from sgp4.api import days2mdhms >>> month, day, hour, minute, second = days2mdhms(19, 343.69339541) >>> month 12 >>> day 9 >>> hour 16 >>> minute 38 >>> second 29.363424 The SGP4 library also translates those two numbers into a Julian date and fractional Julian date, since Julian dates are more commonly used in astronomy. >>> satellite.jdsatepoch 2458826.5 >>> satellite.jdsatepochF 0.69339541 Finally, a convenience function is available in the library if you need the epoch date and time as Python ``datetime``. >>> from sgp4.conveniences import sat_epoch_datetime >>> sat_epoch_datetime(satellite) datetime.datetime(2019, 12, 9, 16, 38, 29, 363423, tzinfo=UTC) Array Acceleration ------------------ To avoid the expense of running a Python loop when you have many dates and times for which you want a position, you can pass your Julian dates as arrays. The array routine is only faster if your machine has successfully installed or compiled the SGP4 C++ code, so you might want to check first: >>> from sgp4.api import accelerated >>> print(accelerated) True To call the array routine, make NumPy arrays for ``jd`` and ``fr`` that are the same length: >>> import numpy as np >>> np.set_printoptions(precision=2) >>> jd = np.array((2458826, 2458826, 2458826, 2458826)) >>> fr = np.array((0.0001, 0.0002, 0.0003, 0.0004)) >>> e, r, v = satellite.sgp4_array(jd, fr) >>> print(e) [0 0 0 0] >>> print(r) [[-3431.31 2620.15 -5252.97] [-3478.86 2575.14 -5243.87] [-3526.09 2529.89 -5234.28] [-3572.98 2484.41 -5224.19]] >>> print(v) [[-5.52 -5.19 1.02] [-5.49 -5.22 1.08] [-5.45 -5.25 1.14] [-5.41 -5.28 1.2 ]] To avoid the expense of Python loops when you have many satellites and dates, build a ``SatrecArray`` from several individual satellites. Its ``sgp4()`` method will expect both ``jd`` and ``fr`` to be NumPy arrays, so if you only have one date, be sure to provide NumPy arrays of length one. Here is a sample computation for 2 satellites and 4 dates: >>> u = '1 20580U 90037B 19342.88042116 .00000361 00000-0 11007-4 0 9996' >>> w = '2 20580 28.4682 146.6676 0002639 185.9222 322.7238 15.09309432427086' >>> satellite2 = Satrec.twoline2rv(u, w) >>> from sgp4.api import SatrecArray >>> a = SatrecArray([satellite, satellite2]) >>> e, r, v = a.sgp4(jd, fr) >>> np.set_printoptions(precision=2) >>> print(e) [[0 0 0 0] [0 0 0 0]] >>> print(r) [[[-3431.31 2620.15 -5252.97] [-3478.86 2575.14 -5243.87] [-3526.09 2529.89 -5234.28] [-3572.98 2484.41 -5224.19]] [[ 5781.85 2564. -2798.22] [ 5749.36 2618.59 -2814.63] [ 5716.35 2672.94 -2830.78] [ 5682.83 2727.05 -2846.68]]] >>> print(v) [[[-5.52 -5.19 1.02] [-5.49 -5.22 1.08] [-5.45 -5.25 1.14] [-5.41 -5.28 1.2 ]] [[-3.73 6.33 -1.91] [-3.79 6.3 -1.88] [-3.85 6.28 -1.85] [-3.91 6.25 -1.83]]] Export ------ If you have a ``Satrec`` you want to share with friends or persist to a file, there’s an export routine that will turn it back into a TLE: >>> from sgp4 import exporter >>> line1, line2 = exporter.export_tle(satellite) >>> line1 '1 25544U 98067A 19343.69339541 .00001764 00000-0 38792-4 0 9991' >>> line2 '2 25544 51.6439 211.2001 0007417 17.6667 85.6398 15.50103472202482' Happily, these are exactly the two TLE lines that we used to create this satellite object: >>> (s == line1) and (t == line2) True Another export routine is available that produces the fields defined by the new OMM format (see the “OMM” section above): >>> from pprint import pprint >>> fields = exporter.export_omm(satellite, 'ISS (ZARYA)') >>> pprint(fields) {'ARG_OF_PERICENTER': 17.6667, 'BSTAR': 3.8792e-05, 'CENTER_NAME': 'EARTH', 'CLASSIFICATION_TYPE': 'U', 'ECCENTRICITY': 0.0007417, 'ELEMENT_SET_NO': 999, 'EPHEMERIS_TYPE': 0, 'EPOCH': '2019-12-09T16:38:29.363423', 'INCLINATION': 51.6439, 'MEAN_ANOMALY': 85.6398, 'MEAN_ELEMENT_THEORY': 'SGP4', 'MEAN_MOTION': 15.501034720000002, 'MEAN_MOTION_DDOT': 0.0, 'MEAN_MOTION_DOT': 1.764e-05, 'NORAD_CAT_ID': 25544, 'OBJECT_ID': '1998-067A', 'OBJECT_NAME': 'ISS (ZARYA)', 'RA_OF_ASC_NODE': 211.2001, 'REF_FRAME': 'TEME', 'REV_AT_EPOCH': 20248, 'TIME_SYSTEM': 'UTC'} Gravity ------- The SGP4 algorithm operates atop a set of constants specifying how strong the Earth’s gravity is. The most recent official paper on SGP4 (see below) specifies that “We use WGS-72 as the default value”, so this Python module uses the same default. But in case you want to use either the old legacy version of the WGS-72 constants, or else the non-standard but more modern WGS-84 constants, the ``twoline2rv()`` constructor takes an optional argument: >>> from sgp4.api import WGS72OLD, WGS72, WGS84 >>> satellite3 = Satrec.twoline2rv(s, t, WGS84) You will in general get less accurate results if you choose WGS-84. Even though it reflects more recent and accurate measures of the Earth, satellite TLEs across the industry are most likely generated with WGS-72 as their basis. The positions you generate will better agree with the real positions of each satellite if you use the same underlying gravity constants as were used to generate the TLE. Providing your own elements --------------------------- If instead of parsing a TLE you want to specify orbital elements directly, you can pass them as floating point numbers to a satellite object’s ``sgp4init()`` method. For example, here’s how to build the same International Space Station orbit that we loaded from a TLE in the first code example above: >>> satellite2 = Satrec() >>> satellite2.sgp4init( ... WGS72, # gravity model ... 'i', # 'a' = old AFSPC mode, 'i' = improved mode ... 25544, # satnum: Satellite number ... 25545.69339541, # epoch: days since 1949 December 31 00:00 UT ... 3.8792e-05, # bstar: drag coefficient (1/earth radii) ... 0.0, # ndot: ballistic coefficient (radians/minute^2) ... 0.0, # nddot: mean motion 2nd derivative (radians/minute^3) ... 0.0007417, # ecco: eccentricity ... 0.3083420829620822, # argpo: argument of perigee (radians) ... 0.9013560935706996, # inclo: inclination (radians) ... 1.4946964807494398, # mo: mean anomaly (radians) ... 0.06763602333248933, # no_kozai: mean motion (radians/minute) ... 3.686137125541276, # nodeo: R.A. of ascending node (radians) ... ) These numbers don’t look the same as the numbers in the TLE, because the underlying ``sgp4init()`` routine uses different units: radians rather than degrees. But this is the same orbit and will produce the same positions. Note that ``ndot`` and ``nddot`` are ignored by the SGP4 propagator, so you can leave them ``0.0`` without any effect on the resulting satellite positions. But they do at least get saved to the satellite object, and written out if you write the parameters to a TLE or OMM file (see the “Export” section, above). To compute the “epoch” argument, take the epoch’s Julian date and subtract 2433281.5 days. While the underlying ``sgp4init()`` routine leaves the attributes ``epochyr``, ``epochdays``, ``jdsatepoch``, and ``jdsatepochF`` unset, this library goes ahead and sets them anyway for you, using the epoch you provided. See the next section for the complete list of attributes that are available from the satellite record once it has been initialized. Attributes ---------- There are several dozen ``Satrec`` attributes that expose data from the underlying C++ SGP4 record. They fall into the following categories. *Identification* These are copied directly from the TLE record but aren’t used by the propagation math. | ``satnum_str`` — Satellite number, as a 5-character string. | ``satnum`` — Satellite number, converted to an integer. | ``classification`` — ``'U'``, ``'C'``, or ``'S'`` indicating the element set is Unclassified, Classified, or Secret. | ``ephtype`` — Integer “ephemeris type”, used internally by space agencies to mark element sets that are not ready for publication; this field should always be ``0`` in published TLEs. | ``elnum`` — Element set number. | ``revnum`` — Satellite’s revolution number at the moment of the epoch, presumably counting from 1 following launch. *Orbital Elements* These are the orbital parameters, copied verbatim from the text of the TLE record. They describe the orbit at the moment of the TLE’s epoch and so remain constant even as the satellite record is used over and over again to propagate positions for different times. | ``epochyr`` — Epoch date: the last two digits of the year. | ``epochdays`` — Epoch date: the number of days into the year, including a decimal fraction for the UTC time of day. | ``ndot`` — First time derivative of the mean motion (loaded from the TLE, but otherwise ignored). | ``nddot`` — Second time derivative of the mean motion (loaded from the TLE, but otherwise ignored). | ``bstar`` — Ballistic drag coefficient B* (1/earth radii). | ``inclo`` — Inclination (radians). | ``nodeo`` — Right ascension of ascending node (radians). | ``ecco`` — Eccentricity. | ``argpo`` — Argument of perigee (radians). | ``mo`` — Mean anomaly (radians). | ``no_kozai`` — Mean motion (radians/minute). | ``no`` — Alias for ``no_kozai``, for compatibility with old code. You can also access the epoch as a Julian date: | ``jdsatepoch`` — Whole part of the epoch’s Julian date. | ``jdsatepochF`` — Fractional part of the epoch’s Julian date. *Computed Orbit Properties* These are computed when the satellite is first loaded, as a convenience for callers who might be interested in them. They aren’t used by the SGP4 propagator itself. | ``a`` — Semi-major axis (earth radii). | ``altp`` — Altitude of the satellite at perigee (earth radii, assuming a spherical Earth). | ``alta`` — Altitude of the satellite at apogee (earth radii, assuming a spherical Earth). | ``argpdot`` — Rate at which the argument of perigee is changing (radians/minute). | ``gsto`` — Greenwich Sidereal Time at the satellite’s epoch (radians). | ``mdot`` — Rate at which the mean anomaly is changing (radians/minute) | ``nodedot`` — Rate at which the right ascension of the ascending node is changing (radians/minute). *Propagator Mode* | ``operationmode`` — A single character that directs SGP4 to either operate in its modern ``'i'`` improved mode or in its legacy ``'a'`` AFSPC mode. | ``method`` — A single character, chosen automatically when the orbital elements were loaded, that indicates whether SGP4 has chosen to use its built-in ``'n'`` Near Earth or ``'d'`` Deep Space mode for this satellite. *Result of Most Recent Propagation* | ``t`` — The time you gave when you most recently asked SGP4 to compute this satellite’s position, measured in minutes before (negative) or after (positive) the satellite’s epoch. | ``error`` — Error code produced by the most recent SGP4 propagation you performed with this element set. The possible ``error`` codes are: 0. No error. 1. Mean eccentricity is outside the range 0 ≤ e < 1. 2. Mean motion has fallen below zero. 3. Perturbed eccentricity is outside the range 0 ≤ e ≤ 1. 4. Length of the orbit’s semi-latus rectum has fallen below zero. 5. (No longer used.) 6. Orbit has decayed: the computed position is underground. (The position is still returned, in case the vector is helpful to software that might be searching for the moment of re-entry.) *Mean Elements From Most Recent Propagation* Partway through each propagation, the SGP4 routine saves a set of “singly averaged mean elements” that describe the orbit’s shape at the moment for which a position is being computed. They are averaged with respect to the mean anomaly and include the effects of secular gravity, atmospheric drag, and — in Deep Space mode — of those pertubations from the Sun and Moon that SGP4 averages over an entire revolution of each of those bodies. They omit both the shorter-term and longer-term periodic pertubations from the Sun and Moon that SGP4 applies right before computing each position. | ``am`` — Average semi-major axis (earth radii). | ``em`` — Average eccentricity. | ``im`` — Average inclination (radians). | ``Om`` — Average right ascension of ascending node (radians). | ``om`` — Average argument of perigee (radians). | ``mm`` — Average mean anomaly (radians). | ``nm`` — Average mean motion (radians/minute). *Gravity Model Parameters* When the satellite record is initialized, your choice of gravity model results in a slate of eight constants being copied in: | ``tumin`` — Minutes in one “time unit”. | ``xke`` — The reciprocal of ``tumin``. | ``mu`` — Earth’s gravitational parameter (km³/s²). | ``radiusearthkm`` — Radius of the earth (km). | ``j2``, ``j3``, ``j4`` — Un-normalized zonal harmonic values J₂, J₃, and J₄. | ``j3oj2`` — The ratio J₃/J₂. Printing satellite attributes ----------------------------- If you want to print out a satellite, this library provides a convenient “attribute dump” routine that takes a satellite and generates lines that list its attributes:: from sys import stdout from sgp4.conveniences import dump_satrec stdout.writelines(dump_satrec(satellite)) If you want to compare two satellites, then simply pass a second argument; the second satellite’s attributes will be printed in a second column next to those of the first. :: stdout.writelines(dump_satrec(satellite, satellite2)) Validation against the official algorithm ----------------------------------------- This implementation passes all of the automated tests in the August 2010 release of the reference implementation of SGP4 by Vallado et al., who originally published their revision of SGP4 in 2006: Vallado, David A., Paul Crawford, Richard Hujsak, and T.S. Kelso, “Revisiting Spacetrack Report #3,” presented at the AIAA/AAS Astrodynamics Specialist Conference, Keystone, CO, 2006 August 21–24. If you would like to review the paper, it is `available online `_. You can always download the latest version of their code for comparison against this Python module (or other implementations) at `AIAA-2006-6753.zip `_. For developers -------------- Developers can check out this full project from GitHub: https://github.com/brandon-rhodes/python-sgp4 To run its unit tests, install Python 2, Python 3, and the ``tox`` testing tool. The tests runing in Python 2 will exercise the fallback pure-Python version of the routines, while Python 3 exercises the fast new C++ accelerated code:: cd python-sgp4 tox Legacy API ---------- Before this library pivoted to wrapping Vallado's official C++ code and was operating in pure Python only, it had a slightly quirkier API, which is still supported for compatibility with older clients. You can learn about it by reading the documentation from version 1.4 or earlier: https://pypi.org/project/sgp4/1.4/ Changelog --------- 2023-04-27 — 2.22 * Added a ``satnum_str`` attribute, exposing the fact that the C++ now stores the satellite number as a string; and check that ``satnum`` is never greater than 339999. * Fixed the units of the ``nddot`` attribute when the value is loaded from an OMM record. (Since the TLE computation itself ignores this attribute, this did not affect any satellite positions.) * Enhanced the fallback Python version of ``twoline2rv()`` to verify that TLE lines are ASCII, and added documentation using it to double-check TLEs that might suffer from non-ASCII characters. * If the user doesn’t set a satellite’s ``classification``, it now defaults to ``'U'`` for ‘unclassified’. 2022-04-06 — 2.21 * Added ``dump_satrec()`` to the ``sgp4.conveniences`` module. * Fixed the ``Satrec`` attribute ``.error``, which was previously building a nonsense integer from the wrong data in memory. * Removed ``.whichconst`` from Python ``Satrec``, to help users avoid writing code that will break when the C++ extension is available. 2021-07-01 — 2.20 * Taught ``sgp4init()`` to round both ``epochdays`` and ``jdsatepochF`` to the same 8 decimal places used for the date fraction in a TLE, if the user-supplied ``epoch`` itself has 8 or fewer digits behind the decimal point. This should make it easier to build satellites that round-trip to TLE format with perfect accuracy. * Fixed how ``export_tle()`` formats the BSTAR field when its value, if written in scientific notation, has a positive exponent. * Fixed the ``epochyr`` assigned by ``sgp4init()`` so years before 2000 have two digits instead of three (for example, so that 1980 produces an ``epochyr`` of 80 instead of 980). 2021-04-22 — 2.19 * Extended the documentation on the Python Package Index and in the module docstring so it lists every ``Satrec`` attribute that this library exposes; even the more obscure ones might be useful to folks working to analyze satellite orbits. 2021-03-08 — 2.18 * If a TLE satellite number lacks the required 5 digits, ``twoline2rv()`` now gives the underlying C++ library a little help so it can still parse the classification and international designator correctly. * The ``Satrec`` attributes ``jdsatepoch``, ``jdsatepochF``, ``epochyr``, and ``epochdays`` are now writeable, so users can adjust their values manually — which should make up for the fact that the ``sgp4init()`` method can’t set them with full floating point precision. | 2021-02-17 — 2.17 — Fixed where in the output array the ``sgp4_array()`` method writes NaN values when an SGP4 propagation fails. | 2021-02-12 — 2.16 — Fixed ``days2mdhms()`` rounding to always match TLE epoch. | 2021-01-08 — 2.15 — Fixed parsing of the ``satnum`` TLE field in the Python fallback code, when the field has a leading space; added OMM export routine. | 2020-12-16 — 2.14 — New data formats: added OMM message support for both XML and CSV, and added support for the new Alpha-5 extension to TLE files. | 2020-10-14 — 2.13 — Enhanced ``sgp4init()`` with custom code that also sets the ``epochdays`` and ``epochyr`` satellite attributes. | 2020-05-28 — 2.12 — Moved the decision of whether to set the locale during ``twoline2rv()`` from import time to runtime, for users who change locales after their application is up and running. | 2020-05-24 — 2.11 — Fixed a regression in how dates are split into hours, minutes, and seconds that would sometimes produce a time whose second=60, crashing the pure-Python version of the library. | 2020-05-22 — 2.10 — Switch the locale temporarily to ``C`` during the C++ accelerated ``twoline2rv()``, since it does not protect its ``sscanf()`` calls from locales that, like German, expect comma decimal points instead of the period decimal points always used in a TLE. | 2020-05-21 — 2.9 — Added ``sat_epoch_datetime()``, expanded documentation around converting a satellite epoch to a date and time, and started rounding the epoch to exactly the digits provided in the TLE; and removed the ``Satrec.epoch`` attribute from Python fallback code to better match the C++ version. | 2020-05-07 — 2.8 — New function ``jday_datetime()`` is now available in the ``sgp4.conveniences`` module, thanks to Egemen Imre. | 2020-04-24 — 2.7 — New method ``sgp4init()`` (thank you, Chris Lewicki!) is available. | 2020-04-20 — 2.6 — New routine ``export_tle()`` (thank you, Egemen Imre!) is available. Improved how the accelerated C++ backend parses the ``intldesg`` string and the ``revnum`` integer. | 2020-03-22 — 2.5 — Gave the new accelerated ``twoline2rv()`` an optional argument that lets the user choose a non-standard set of gravity constants. | 2020-02-25 — 2.4 — Improved the ``jday()`` docstring; made the old legacy Python resilient if the day of the month is out-of-range (past the end of the month) in a TLE; and Mark Rutten fixed the C++ so it compiles on Windows! | 2020-02-04 — 2.3 — Removed experimental code that caused performance problems for users with Numba installed. | 2020-02-02 — 2.2 — A second release on Palindrome Day: fix the Satrec ``.epochyr`` attribute so it behaves the same way in Python as it does in the official C library, where it is only the last 2 digits of the year; and make ``.no`` available in the Python fallback case as well. | 2020-02-02 — 2.1 — Add vectorized array method to Satrec object; add ``.no`` attribute to new Satrec object to support old code that has not migrated to the new name ``.no_kozai``; gave Python wrapper classes ``__slots__`` to avoid the expense of a per-object attribute dictionary. | 2020-01-30 — 2.0 — Rewrite API to use genuine Vallado C++ code on those systems where it can be compiled; add accelerated vectorized array interface; make ``gstime()`` a public function; clarify format error message. | 2015-01-15 — 1.4 — Display detailed help when TLE input does not match format. | 2014-06-26 — 1.3 — Return ``(NaN,NaN,NaN)`` vectors on error and set ``.error_message`` | 2013-11-29 — 1.2 — Made ``epochyr`` 4 digits; add ``datetime`` for ``.epoch`` | 2012-11-22 — 1.1 — Python 3 compatibility; more documentation | 2012-08-27 — 1.0 — Initial release ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/README.md0000644000175100001730000000041414422467341013202 0ustar00runnerdockerpython-sgp4 =========== Python implementation of most recent version of the SGP4 satellite tracking algorithm. * Documentation: https://pypi.python.org/pypi/sgp4/ * Download: https://pypi.org/project/sgp4/#files * Changelog: https://pypi.org/project/sgp4/#changelog ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1682599655.3354356 sgp4-2.22/extension/0000755000175100001730000000000014422467347013746 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/extension/SGP4.cpp0000644000175100001730000033007014422467341015164 0ustar00runnerdocker/* ---------------------------------------------------------------- * * sgp4unit.cpp * * this file contains the sgp4 procedures for analytical propagation * of a satellite. the code was originally released in the 1980 and 1986 * spacetrack papers. a detailed discussion of the theory and history * may be found in the 2006 aiaa paper by vallado, crawford, hujsak, * and kelso. * * companion code for * fundamentals of astrodynamics and applications * 2013 * by david vallado * * (w) 719-573-2600, email dvallado@agi.com, davallado@gmail.com * * current : * 12 mar 20 david vallado * chg satnum to string for alpha 5 or 9-digit * changes : * 7 dec 15 david vallado * fix jd, jdfrac * 3 nov 14 david vallado * update to msvs2013 c++ * 30 aug 10 david vallado * delete unused variables in initl * replace pow integer 2, 3 with multiplies for speed * 3 nov 08 david vallado * put returns in for error codes * 29 sep 08 david vallado * fix atime for faster operation in dspace * add operationmode for afspc (a) or improved (i) * performance mode * 16 jun 08 david vallado * update small eccentricity check * 16 nov 07 david vallado * misc fixes for better compliance * 20 apr 07 david vallado * misc fixes for constants * 11 aug 06 david vallado * chg lyddane choice back to strn3, constants, misc doc * 15 dec 05 david vallado * misc fixes * 26 jul 05 david vallado * fixes for paper * note that each fix is preceded by a * comment with "sgp4fix" and an explanation of * what was changed * 10 aug 04 david vallado * 2nd printing baseline working * 14 may 01 david vallado * 2nd edition baseline * 80 norad * original baseline * ---------------------------------------------------------------- */ #include "SGP4.h" #define pi 3.14159265358979323846 // define global variables here, not in .h // use extern in main char help = 'n'; FILE *dbgfile; /* ----------- local functions - only ever used internally by sgp4 ---------- */ static void dpper ( double e3, double ee2, double peo, double pgho, double pho, double pinco, double plo, double se2, double se3, double sgh2, double sgh3, double sgh4, double sh2, double sh3, double si2, double si3, double sl2, double sl3, double sl4, double t, double xgh2, double xgh3, double xgh4, double xh2, double xh3, double xi2, double xi3, double xl2, double xl3, double xl4, double zmol, double zmos, double inclo, char init, double& ep, double& inclp, double& nodep, double& argpp, double& mp, char opsmode ); static void dscom ( double epoch, double ep, double argpp, double tc, double inclp, double nodep, double np, double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, double& cosomm, double& day, double& e3, double& ee2, double& em, double& emsq, double& gam, double& peo, double& pgho, double& pho, double& pinco, double& plo, double& rtemsq, double& se2, double& se3, double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, double& si2, double& si3, double& sl2, double& sl3, double& sl4, double& s1, double& s2, double& s3, double& s4, double& s5, double& s6, double& s7, double& ss1, double& ss2, double& ss3, double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, double& xl4, double& nm, double& z1, double& z2, double& z3, double& z11, double& z12, double& z13, double& z21, double& z22, double& z23, double& z31, double& z32, double& z33, double& zmol, double& zmos ); static void dsinit ( //sgp4fix no longer needed pass in xke //gravconsttype whichconst, double xke, double cosim, double emsq, double argpo, double s1, double s2, double s3, double s4, double s5, double sinim, double ss1, double ss2, double ss3, double ss4, double ss5, double sz1, double sz3, double sz11, double sz13, double sz21, double sz23, double sz31, double sz33, double t, double tc, double gsto, double mo, double mdot, double no, double nodeo, double nodedot, double xpidot, double z1, double z3, double z11, double z13, double z21, double z23, double z31, double z33, double ecco, double eccsq, double& em, double& argpm, double& inclm, double& mm, double& nm, double& nodem, int& irez, double& atime, double& d2201, double& d2211, double& d3210, double& d3222, double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, double& dnodt, double& domdt, double& del1, double& del2, double& del3, double& xfact, double& xlamo, double& xli, double& xni ); static void dspace ( int irez, double d2201, double d2211, double d3210, double d3222, double d4410, double d4422, double d5220, double d5232, double d5421, double d5433, double dedt, double del1, double del2, double del3, double didt, double dmdt, double dnodt, double domdt, double argpo, double argpdot, double t, double tc, double gsto, double xfact, double xlamo, double no, double& atime, double& em, double& argpm, double& inclm, double& xli, double& mm, double& xni, double& nodem, double& dndt, double& nm ); static void initl ( // not needeed. included in satrec if needed later // int satn, // sgp4fix assin xke and j2 // gravconsttype whichconst, double xke, double j2, double ecco, double epoch, double inclo, double& no, char& method, double& ainv, double& ao, double& con41, double& con42, double& cosio, double& cosio2, double& eccsq, double& omeosq, double& posq, double& rp, double& rteosq, double& sinio, double& gsto, char opsmode ); namespace SGP4Funcs { /* ----------------------------------------------------------------------------- * * procedure dpper * * this procedure provides deep space long period periodic contributions * to the mean elements. by design, these periodics are zero at epoch. * this used to be dscom which included initialization, but it's really a * recurring function. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * e3 - * ee2 - * peo - * pgho - * pho - * pinco - * plo - * se2 , se3 , sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4 - * t - * xh2, xh3, xi2, xi3, xl2, xl3, xl4 - * zmol - * zmos - * ep - eccentricity 0.0 - 1.0 * inclo - inclination - needed for lyddane modification * nodep - right ascension of ascending node * argpp - argument of perigee * mp - mean anomaly * * outputs : * ep - eccentricity 0.0 - 1.0 * inclp - inclination * nodep - right ascension of ascending node * argpp - argument of perigee * mp - mean anomaly * * locals : * alfdp - * betdp - * cosip , sinip , cosop , sinop , * dalf - * dbet - * dls - * f2, f3 - * pe - * pgh - * ph - * pinc - * pl - * sel , ses , sghl , sghs , shl , shs , sil , sinzf , sis , * sll , sls * xls - * xnoh - * zf - * zm - * * coupling : * none. * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ static void dpper ( double e3, double ee2, double peo, double pgho, double pho, double pinco, double plo, double se2, double se3, double sgh2, double sgh3, double sgh4, double sh2, double sh3, double si2, double si3, double sl2, double sl3, double sl4, double t, double xgh2, double xgh3, double xgh4, double xh2, double xh3, double xi2, double xi3, double xl2, double xl3, double xl4, double zmol, double zmos, double inclo, char init, double& ep, double& inclp, double& nodep, double& argpp, double& mp, char opsmode ) { /* --------------------- local variables ------------------------ */ const double twopi = 2.0 * pi; double alfdp, betdp, cosip, cosop, dalf, dbet, dls, f2, f3, pe, pgh, ph, pinc, pl, sel, ses, sghl, sghs, shll, shs, sil, sinip, sinop, sinzf, sis, sll, sls, xls, xnoh, zf, zm, zel, zes, znl, zns; /* ---------------------- constants ----------------------------- */ zns = 1.19459e-5; zes = 0.01675; znl = 1.5835218e-4; zel = 0.05490; /* --------------- calculate time varying periodics ----------- */ zm = zmos + zns * t; // be sure that the initial call has time set to zero if (init == 'y') zm = zmos; zf = zm + 2.0 * zes * sin(zm); sinzf = sin(zf); f2 = 0.5 * sinzf * sinzf - 0.25; f3 = -0.5 * sinzf * cos(zf); ses = se2* f2 + se3 * f3; sis = si2 * f2 + si3 * f3; sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf; sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf; shs = sh2 * f2 + sh3 * f3; zm = zmol + znl * t; if (init == 'y') zm = zmol; zf = zm + 2.0 * zel * sin(zm); sinzf = sin(zf); f2 = 0.5 * sinzf * sinzf - 0.25; f3 = -0.5 * sinzf * cos(zf); sel = ee2 * f2 + e3 * f3; sil = xi2 * f2 + xi3 * f3; sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf; sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf; shll = xh2 * f2 + xh3 * f3; pe = ses + sel; pinc = sis + sil; pl = sls + sll; pgh = sghs + sghl; ph = shs + shll; if (init == 'n') { pe = pe - peo; pinc = pinc - pinco; pl = pl - plo; pgh = pgh - pgho; ph = ph - pho; inclp = inclp + pinc; ep = ep + pe; sinip = sin(inclp); cosip = cos(inclp); /* ----------------- apply periodics directly ------------ */ // sgp4fix for lyddane choice // strn3 used original inclination - this is technically feasible // gsfc used perturbed inclination - also technically feasible // probably best to readjust the 0.2 limit value and limit discontinuity // 0.2 rad = 11.45916 deg // use next line for original strn3 approach and original inclination // if (inclo >= 0.2) // use next line for gsfc version and perturbed inclination if (inclp >= 0.2) { ph = ph / sinip; pgh = pgh - cosip * ph; argpp = argpp + pgh; nodep = nodep + ph; mp = mp + pl; } else { /* ---- apply periodics with lyddane modification ---- */ sinop = sin(nodep); cosop = cos(nodep); alfdp = sinip * sinop; betdp = sinip * cosop; dalf = ph * cosop + pinc * cosip * sinop; dbet = -ph * sinop + pinc * cosip * cosop; alfdp = alfdp + dalf; betdp = betdp + dbet; nodep = fmod(nodep, twopi); // sgp4fix for afspc written intrinsic functions // nodep used without a trigonometric function ahead if ((nodep < 0.0) && (opsmode == 'a')) nodep = nodep + twopi; xls = mp + argpp + cosip * nodep; dls = pl + pgh - pinc * nodep * sinip; xls = xls + dls; xnoh = nodep; nodep = atan2(alfdp, betdp); // sgp4fix for afspc written intrinsic functions // nodep used without a trigonometric function ahead if ((nodep < 0.0) && (opsmode == 'a')) nodep = nodep + twopi; if (fabs(xnoh - nodep) > pi) if (nodep < xnoh) nodep = nodep + twopi; else nodep = nodep - twopi; mp = mp + pl; argpp = xls - mp - cosip * nodep; } } // if init == 'n' //#include "debug1.cpp" } // dpper /*----------------------------------------------------------------------------- * * procedure dscom * * this procedure provides deep space common items used by both the secular * and periodics subroutines. input is provided as shown. this routine * used to be called dpper, but the functions inside weren't well organized. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * epoch - * ep - eccentricity * argpp - argument of perigee * tc - * inclp - inclination * nodep - right ascension of ascending node * np - mean motion * * outputs : * sinim , cosim , sinomm , cosomm , snodm , cnodm * day - * e3 - * ee2 - * em - eccentricity * emsq - eccentricity squared * gam - * peo - * pgho - * pho - * pinco - * plo - * rtemsq - * se2, se3 - * sgh2, sgh3, sgh4 - * sh2, sh3, si2, si3, sl2, sl3, sl4 - * s1, s2, s3, s4, s5, s6, s7 - * ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3 - * sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - * xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4 - * nm - mean motion * z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33 - * zmol - * zmos - * * locals : * a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 - * betasq - * cc - * ctem, stem - * x1, x2, x3, x4, x5, x6, x7, x8 - * xnodce - * xnoi - * zcosg , zsing , zcosgl , zsingl , zcosh , zsinh , zcoshl , zsinhl , * zcosi , zsini , zcosil , zsinil , * zx - * zy - * * coupling : * none. * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ static void dscom ( double epoch, double ep, double argpp, double tc, double inclp, double nodep, double np, double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, double& cosomm, double& day, double& e3, double& ee2, double& em, double& emsq, double& gam, double& peo, double& pgho, double& pho, double& pinco, double& plo, double& rtemsq, double& se2, double& se3, double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, double& si2, double& si3, double& sl2, double& sl3, double& sl4, double& s1, double& s2, double& s3, double& s4, double& s5, double& s6, double& s7, double& ss1, double& ss2, double& ss3, double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, double& xl4, double& nm, double& z1, double& z2, double& z3, double& z11, double& z12, double& z13, double& z21, double& z22, double& z23, double& z31, double& z32, double& z33, double& zmol, double& zmos ) { /* -------------------------- constants ------------------------- */ const double zes = 0.01675; const double zel = 0.05490; const double c1ss = 2.9864797e-6; const double c1l = 4.7968065e-7; const double zsinis = 0.39785416; const double zcosis = 0.91744867; const double zcosgs = 0.1945905; const double zsings = -0.98088458; const double twopi = 2.0 * pi; /* --------------------- local variables ------------------------ */ int lsflg; double a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, betasq, cc, ctem, stem, x1, x2, x3, x4, x5, x6, x7, x8, xnodce, xnoi, zcosg, zcosgl, zcosh, zcoshl, zcosi, zcosil, zsing, zsingl, zsinh, zsinhl, zsini, zsinil, zx, zy; nm = np; em = ep; snodm = sin(nodep); cnodm = cos(nodep); sinomm = sin(argpp); cosomm = cos(argpp); sinim = sin(inclp); cosim = cos(inclp); emsq = em * em; betasq = 1.0 - emsq; rtemsq = sqrt(betasq); /* ----------------- initialize lunar solar terms --------------- */ peo = 0.0; pinco = 0.0; plo = 0.0; pgho = 0.0; pho = 0.0; day = epoch + 18261.5 + tc / 1440.0; xnodce = fmod(4.5236020 - 9.2422029e-4 * day, twopi); stem = sin(xnodce); ctem = cos(xnodce); zcosil = 0.91375164 - 0.03568096 * ctem; zsinil = sqrt(1.0 - zcosil * zcosil); zsinhl = 0.089683511 * stem / zsinil; zcoshl = sqrt(1.0 - zsinhl * zsinhl); gam = 5.8351514 + 0.0019443680 * day; zx = 0.39785416 * stem / zsinil; zy = zcoshl * ctem + 0.91744867 * zsinhl * stem; zx = atan2(zx, zy); zx = gam + zx - xnodce; zcosgl = cos(zx); zsingl = sin(zx); /* ------------------------- do solar terms --------------------- */ zcosg = zcosgs; zsing = zsings; zcosi = zcosis; zsini = zsinis; zcosh = cnodm; zsinh = snodm; cc = c1ss; xnoi = 1.0 / nm; for (lsflg = 1; lsflg <= 2; lsflg++) { a1 = zcosg * zcosh + zsing * zcosi * zsinh; a3 = -zsing * zcosh + zcosg * zcosi * zsinh; a7 = -zcosg * zsinh + zsing * zcosi * zcosh; a8 = zsing * zsini; a9 = zsing * zsinh + zcosg * zcosi * zcosh; a10 = zcosg * zsini; a2 = cosim * a7 + sinim * a8; a4 = cosim * a9 + sinim * a10; a5 = -sinim * a7 + cosim * a8; a6 = -sinim * a9 + cosim * a10; x1 = a1 * cosomm + a2 * sinomm; x2 = a3 * cosomm + a4 * sinomm; x3 = -a1 * sinomm + a2 * cosomm; x4 = -a3 * sinomm + a4 * cosomm; x5 = a5 * sinomm; x6 = a6 * sinomm; x7 = a5 * cosomm; x8 = a6 * cosomm; z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3; z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4; z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4; z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq; z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq; z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq; z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7 - 6.0 * x3 * x5); z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5)); z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6); z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7); z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8)); z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8); z1 = z1 + z1 + betasq * z31; z2 = z2 + z2 + betasq * z32; z3 = z3 + z3 + betasq * z33; s3 = cc * xnoi; s2 = -0.5 * s3 / rtemsq; s4 = s3 * rtemsq; s1 = -15.0 * em * s4; s5 = x1 * x3 + x2 * x4; s6 = x2 * x3 + x1 * x4; s7 = x2 * x4 - x1 * x3; /* ----------------------- do lunar terms ------------------- */ if (lsflg == 1) { ss1 = s1; ss2 = s2; ss3 = s3; ss4 = s4; ss5 = s5; ss6 = s6; ss7 = s7; sz1 = z1; sz2 = z2; sz3 = z3; sz11 = z11; sz12 = z12; sz13 = z13; sz21 = z21; sz22 = z22; sz23 = z23; sz31 = z31; sz32 = z32; sz33 = z33; zcosg = zcosgl; zsing = zsingl; zcosi = zcosil; zsini = zsinil; zcosh = zcoshl * cnodm + zsinhl * snodm; zsinh = snodm * zcoshl - cnodm * zsinhl; cc = c1l; } } zmol = fmod(4.7199672 + 0.22997150 * day - gam, twopi); zmos = fmod(6.2565837 + 0.017201977 * day, twopi); /* ------------------------ do solar terms ---------------------- */ se2 = 2.0 * ss1 * ss6; se3 = 2.0 * ss1 * ss7; si2 = 2.0 * ss2 * sz12; si3 = 2.0 * ss2 * (sz13 - sz11); sl2 = -2.0 * ss3 * sz2; sl3 = -2.0 * ss3 * (sz3 - sz1); sl4 = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes; sgh2 = 2.0 * ss4 * sz32; sgh3 = 2.0 * ss4 * (sz33 - sz31); sgh4 = -18.0 * ss4 * zes; sh2 = -2.0 * ss2 * sz22; sh3 = -2.0 * ss2 * (sz23 - sz21); /* ------------------------ do lunar terms ---------------------- */ ee2 = 2.0 * s1 * s6; e3 = 2.0 * s1 * s7; xi2 = 2.0 * s2 * z12; xi3 = 2.0 * s2 * (z13 - z11); xl2 = -2.0 * s3 * z2; xl3 = -2.0 * s3 * (z3 - z1); xl4 = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel; xgh2 = 2.0 * s4 * z32; xgh3 = 2.0 * s4 * (z33 - z31); xgh4 = -18.0 * s4 * zel; xh2 = -2.0 * s2 * z22; xh3 = -2.0 * s2 * (z23 - z21); //#include "debug2.cpp" } // dscom /*----------------------------------------------------------------------------- * * procedure dsinit * * this procedure provides deep space contributions to mean motion dot due * to geopotential resonance with half day and one day orbits. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * xke - reciprocal of tumin * cosim, sinim- * emsq - eccentricity squared * argpo - argument of perigee * s1, s2, s3, s4, s5 - * ss1, ss2, ss3, ss4, ss5 - * sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33 - * t - time * tc - * gsto - greenwich sidereal time rad * mo - mean anomaly * mdot - mean anomaly dot (rate) * no - mean motion * nodeo - right ascension of ascending node * nodedot - right ascension of ascending node dot (rate) * xpidot - * z1, z3, z11, z13, z21, z23, z31, z33 - * eccm - eccentricity * argpm - argument of perigee * inclm - inclination * mm - mean anomaly * xn - mean motion * nodem - right ascension of ascending node * * outputs : * em - eccentricity * argpm - argument of perigee * inclm - inclination * mm - mean anomaly * nm - mean motion * nodem - right ascension of ascending node * irez - flag for resonance 0-none, 1-one day, 2-half day * atime - * d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - * dedt - * didt - * dmdt - * dndt - * dnodt - * domdt - * del1, del2, del3 - * ses , sghl , sghs , sgs , shl , shs , sis , sls * theta - * xfact - * xlamo - * xli - * xni * * locals : * ainv2 - * aonv - * cosisq - * eoc - * f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543 - * g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533 - * sini2 - * temp - * temp1 - * theta - * xno2 - * * coupling : * getgravconst- no longer used * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ static void dsinit ( // sgp4fix just send in xke as a constant and eliminate getgravconst call // gravconsttype whichconst, double xke, double cosim, double emsq, double argpo, double s1, double s2, double s3, double s4, double s5, double sinim, double ss1, double ss2, double ss3, double ss4, double ss5, double sz1, double sz3, double sz11, double sz13, double sz21, double sz23, double sz31, double sz33, double t, double tc, double gsto, double mo, double mdot, double no, double nodeo, double nodedot, double xpidot, double z1, double z3, double z11, double z13, double z21, double z23, double z31, double z33, double ecco, double eccsq, double& em, double& argpm, double& inclm, double& mm, double& nm, double& nodem, int& irez, double& atime, double& d2201, double& d2211, double& d3210, double& d3222, double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, double& dnodt, double& domdt, double& del1, double& del2, double& del3, double& xfact, double& xlamo, double& xli, double& xni ) { /* --------------------- local variables ------------------------ */ const double twopi = 2.0 * pi; double ainv2, aonv = 0.0, cosisq, eoc, f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543, g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533, ses, sgs, sghl, sghs, shs, shll, sis, sini2, sls, temp, temp1, theta, xno2, q22, q31, q33, root22, root44, root54, rptim, root32, root52, x2o3, znl, emo, zns, emsqo; q22 = 1.7891679e-6; q31 = 2.1460748e-6; q33 = 2.2123015e-7; root22 = 1.7891679e-6; root44 = 7.3636953e-9; root54 = 2.1765803e-9; rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec root32 = 3.7393792e-7; root52 = 1.1428639e-7; x2o3 = 2.0 / 3.0; znl = 1.5835218e-4; zns = 1.19459e-5; // sgp4fix identify constants and allow alternate values // just xke is used here so pass it in rather than have multiple calls // getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); /* -------------------- deep space initialization ------------ */ irez = 0; if ((nm < 0.0052359877) && (nm > 0.0034906585)) irez = 1; if ((nm >= 8.26e-3) && (nm <= 9.24e-3) && (em >= 0.5)) irez = 2; /* ------------------------ do solar terms ------------------- */ ses = ss1 * zns * ss5; sis = ss2 * zns * (sz11 + sz13); sls = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq); sghs = ss4 * zns * (sz31 + sz33 - 6.0); shs = -zns * ss2 * (sz21 + sz23); // sgp4fix for 180 deg incl if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) shs = 0.0; if (sinim != 0.0) shs = shs / sinim; sgs = sghs - cosim * shs; /* ------------------------- do lunar terms ------------------ */ dedt = ses + s1 * znl * s5; didt = sis + s2 * znl * (z11 + z13); dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq); sghl = s4 * znl * (z31 + z33 - 6.0); shll = -znl * s2 * (z21 + z23); // sgp4fix for 180 deg incl if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) shll = 0.0; domdt = sgs + sghl; dnodt = shs; if (sinim != 0.0) { domdt = domdt - cosim / sinim * shll; dnodt = dnodt + shll / sinim; } /* ----------- calculate deep space resonance effects -------- */ dndt = 0.0; theta = fmod(gsto + tc * rptim, twopi); em = em + dedt * t; inclm = inclm + didt * t; argpm = argpm + domdt * t; nodem = nodem + dnodt * t; mm = mm + dmdt * t; // sgp4fix for negative inclinations // the following if statement should be commented out //if (inclm < 0.0) // { // inclm = -inclm; // argpm = argpm - pi; // nodem = nodem + pi; // } /* -------------- initialize the resonance terms ------------- */ if (irez != 0) { aonv = pow(nm / xke, x2o3); /* ---------- geopotential resonance for 12 hour orbits ------ */ if (irez == 2) { cosisq = cosim * cosim; emo = em; em = ecco; emsqo = emsq; emsq = eccsq; eoc = em * emsq; g201 = -0.306 - (em - 0.64) * 0.440; if (em <= 0.65) { g211 = 3.616 - 13.2470 * em + 16.2900 * emsq; g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc; g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc; g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc; g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc; g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc; } else { g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc; g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc; g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc; g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc; g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc; if (em > 0.715) g520 = -5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc; else g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq; } if (em < 0.7) { g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc; g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc; g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc; } else { g533 = -37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc; g521 = -51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc; g532 = -40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc; } sini2 = sinim * sinim; f220 = 0.75 * (1.0 + 2.0 * cosim + cosisq); f221 = 1.5 * sini2; f321 = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq); f322 = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq); f441 = 35.0 * sini2 * f220; f442 = 39.3750 * sini2 * sini2; f522 = 9.84375 * sinim * (sini2 * (1.0 - 2.0 * cosim - 5.0 * cosisq) + 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq)); f523 = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + 10.0 * cosisq) + 6.56250012 * (1.0 + 2.0 * cosim - 3.0 * cosisq)); f542 = 29.53125 * sinim * (2.0 - 8.0 * cosim + cosisq * (-12.0 + 8.0 * cosim + 10.0 * cosisq)); f543 = 29.53125 * sinim * (-2.0 - 8.0 * cosim + cosisq * (12.0 + 8.0 * cosim - 10.0 * cosisq)); xno2 = nm * nm; ainv2 = aonv * aonv; temp1 = 3.0 * xno2 * ainv2; temp = temp1 * root22; d2201 = temp * f220 * g201; d2211 = temp * f221 * g211; temp1 = temp1 * aonv; temp = temp1 * root32; d3210 = temp * f321 * g310; d3222 = temp * f322 * g322; temp1 = temp1 * aonv; temp = 2.0 * temp1 * root44; d4410 = temp * f441 * g410; d4422 = temp * f442 * g422; temp1 = temp1 * aonv; temp = temp1 * root52; d5220 = temp * f522 * g520; d5232 = temp * f523 * g532; temp = 2.0 * temp1 * root54; d5421 = temp * f542 * g521; d5433 = temp * f543 * g533; xlamo = fmod(mo + nodeo + nodeo - theta - theta, twopi); xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - no; em = emo; emsq = emsqo; } /* ---------------- synchronous resonance terms -------------- */ if (irez == 1) { g200 = 1.0 + emsq * (-2.5 + 0.8125 * emsq); g310 = 1.0 + 2.0 * emsq; g300 = 1.0 + emsq * (-6.0 + 6.60937 * emsq); f220 = 0.75 * (1.0 + cosim) * (1.0 + cosim); f311 = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim); f330 = 1.0 + cosim; f330 = 1.875 * f330 * f330 * f330; del1 = 3.0 * nm * nm * aonv * aonv; del2 = 2.0 * del1 * f220 * g200 * q22; del3 = 3.0 * del1 * f330 * g300 * q33 * aonv; del1 = del1 * f311 * g310 * q31 * aonv; xlamo = fmod(mo + nodeo + argpo - theta, twopi); xfact = mdot + xpidot - rptim + dmdt + domdt + dnodt - no; } /* ------------ for sgp4, initialize the integrator ---------- */ xli = xlamo; xni = no; atime = 0.0; nm = no + dndt; } //#include "debug3.cpp" } // dsinit /*----------------------------------------------------------------------------- * * procedure dspace * * this procedure provides deep space contributions to mean elements for * perturbing third body. these effects have been averaged over one * revolution of the sun and moon. for earth resonance effects, the * effects have been averaged over no revolutions of the satellite. * (mean motion) * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - * dedt - * del1, del2, del3 - * didt - * dmdt - * dnodt - * domdt - * irez - flag for resonance 0-none, 1-one day, 2-half day * argpo - argument of perigee * argpdot - argument of perigee dot (rate) * t - time * tc - * gsto - gst * xfact - * xlamo - * no - mean motion * atime - * em - eccentricity * ft - * argpm - argument of perigee * inclm - inclination * xli - * mm - mean anomaly * xni - mean motion * nodem - right ascension of ascending node * * outputs : * atime - * em - eccentricity * argpm - argument of perigee * inclm - inclination * xli - * mm - mean anomaly * xni - * nodem - right ascension of ascending node * dndt - * nm - mean motion * * locals : * delt - * ft - * theta - * x2li - * x2omi - * xl - * xldot - * xnddt - * xndt - * xomi - * * coupling : * none - * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ static void dspace ( int irez, double d2201, double d2211, double d3210, double d3222, double d4410, double d4422, double d5220, double d5232, double d5421, double d5433, double dedt, double del1, double del2, double del3, double didt, double dmdt, double dnodt, double domdt, double argpo, double argpdot, double t, double tc, double gsto, double xfact, double xlamo, double no, double& atime, double& em, double& argpm, double& inclm, double& xli, double& mm, double& xni, double& nodem, double& dndt, double& nm ) { const double twopi = 2.0 * pi; int iretn, iret; double delt, ft, theta, x2li, x2omi, xl, xldot, xnddt, xndt, xomi, g22, g32, g44, g52, g54, fasx2, fasx4, fasx6, rptim, step2, stepn, stepp; fasx2 = 0.13130908; fasx4 = 2.8843198; fasx6 = 0.37448087; g22 = 5.7686396; g32 = 0.95240898; g44 = 1.8014998; g52 = 1.0508330; g54 = 4.4108898; rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec stepp = 720.0; stepn = -720.0; step2 = 259200.0; /* ----------- calculate deep space resonance effects ----------- */ dndt = 0.0; theta = fmod(gsto + tc * rptim, twopi); em = em + dedt * t; inclm = inclm + didt * t; argpm = argpm + domdt * t; nodem = nodem + dnodt * t; mm = mm + dmdt * t; // sgp4fix for negative inclinations // the following if statement should be commented out // if (inclm < 0.0) // { // inclm = -inclm; // argpm = argpm - pi; // nodem = nodem + pi; // } /* - update resonances : numerical (euler-maclaurin) integration - */ /* ------------------------- epoch restart ---------------------- */ // sgp4fix for propagator problems // the following integration works for negative time steps and periods // the specific changes are unknown because the original code was so convoluted // sgp4fix take out atime = 0.0 and fix for faster operation ft = 0.0; if (irez != 0) { // sgp4fix streamline check if ((atime == 0.0) || (t * atime <= 0.0) || (fabs(t) < fabs(atime))) { atime = 0.0; xni = no; xli = xlamo; } // sgp4fix move check outside loop if (t > 0.0) delt = stepp; else delt = stepn; iretn = 381; // added for do loop iret = 0; // added for loop while (iretn == 381) { /* ------------------- dot terms calculated ------------- */ /* ----------- near - synchronous resonance terms ------- */ if (irez != 2) { xndt = del1 * sin(xli - fasx2) + del2 * sin(2.0 * (xli - fasx4)) + del3 * sin(3.0 * (xli - fasx6)); xldot = xni + xfact; xnddt = del1 * cos(xli - fasx2) + 2.0 * del2 * cos(2.0 * (xli - fasx4)) + 3.0 * del3 * cos(3.0 * (xli - fasx6)); xnddt = xnddt * xldot; } else { /* --------- near - half-day resonance terms -------- */ xomi = argpo + argpdot * atime; x2omi = xomi + xomi; x2li = xli + xli; xndt = d2201 * sin(x2omi + xli - g22) + d2211 * sin(xli - g22) + d3210 * sin(xomi + xli - g32) + d3222 * sin(-xomi + xli - g32) + d4410 * sin(x2omi + x2li - g44) + d4422 * sin(x2li - g44) + d5220 * sin(xomi + xli - g52) + d5232 * sin(-xomi + xli - g52) + d5421 * sin(xomi + x2li - g54) + d5433 * sin(-xomi + x2li - g54); xldot = xni + xfact; xnddt = d2201 * cos(x2omi + xli - g22) + d2211 * cos(xli - g22) + d3210 * cos(xomi + xli - g32) + d3222 * cos(-xomi + xli - g32) + d5220 * cos(xomi + xli - g52) + d5232 * cos(-xomi + xli - g52) + 2.0 * (d4410 * cos(x2omi + x2li - g44) + d4422 * cos(x2li - g44) + d5421 * cos(xomi + x2li - g54) + d5433 * cos(-xomi + x2li - g54)); xnddt = xnddt * xldot; } /* ----------------------- integrator ------------------- */ // sgp4fix move end checks to end of routine if (fabs(t - atime) >= stepp) { iret = 0; iretn = 381; } else // exit here { ft = t - atime; iretn = 0; } if (iretn == 381) { xli = xli + xldot * delt + xndt * step2; xni = xni + xndt * delt + xnddt * step2; atime = atime + delt; } } // while iretn = 381 nm = xni + xndt * ft + xnddt * ft * ft * 0.5; xl = xli + xldot * ft + xndt * ft * ft * 0.5; if (irez != 1) { mm = xl - 2.0 * nodem + 2.0 * theta; dndt = nm - no; } else { mm = xl - nodem - argpm + theta; dndt = nm - no; } nm = no + dndt; } //#include "debug4.cpp" } // dsspace /*----------------------------------------------------------------------------- * * procedure initl * * this procedure initializes the spg4 propagator. all the initialization is * consolidated here instead of having multiple loops inside other routines. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * satn - satellite number - not needed, placed in satrec * xke - reciprocal of tumin * j2 - j2 zonal harmonic * ecco - eccentricity 0.0 - 1.0 * epoch - epoch time in days from jan 0, 1950. 0 hr * inclo - inclination of satellite * no - mean motion of satellite * * outputs : * ainv - 1.0 / a * ao - semi major axis * con41 - * con42 - 1.0 - 5.0 cos(i) * cosio - cosine of inclination * cosio2 - cosio squared * eccsq - eccentricity squared * method - flag for deep space 'd', 'n' * omeosq - 1.0 - ecco * ecco * posq - semi-parameter squared * rp - radius of perigee * rteosq - square root of (1.0 - ecco*ecco) * sinio - sine of inclination * gsto - gst at time of observation rad * no - mean motion of satellite * * locals : * ak - * d1 - * del - * adel - * po - * * coupling : * getgravconst- no longer used * gstime - find greenwich sidereal time from the julian date * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ static void initl ( // sgp4fix satn not needed. include in satrec in case needed later // int satn, // sgp4fix just pass in xke and j2 // gravconsttype whichconst, double xke, double j2, double ecco, double epoch, double inclo, double no_kozai, char opsmode, char& method, double& ainv, double& ao, double& con41, double& con42, double& cosio, double& cosio2, double& eccsq, double& omeosq, double& posq, double& rp, double& rteosq, double& sinio, double& gsto, double& no_unkozai ) { /* --------------------- local variables ------------------------ */ double ak, d1, del, adel, po, x2o3; // sgp4fix use old way of finding gst double ds70; double ts70, tfrac, c1, thgr70, fk5r, c1p2p; const double twopi = 2.0 * pi; /* ----------------------- earth constants ---------------------- */ // sgp4fix identify constants and allow alternate values // only xke and j2 are used here so pass them in directly // getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); x2o3 = 2.0 / 3.0; /* ------------- calculate auxillary epoch quantities ---------- */ eccsq = ecco * ecco; omeosq = 1.0 - eccsq; rteosq = sqrt(omeosq); cosio = cos(inclo); cosio2 = cosio * cosio; /* ------------------ un-kozai the mean motion ----------------- */ ak = pow(xke / no_kozai, x2o3); d1 = 0.75 * j2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq); del = d1 / (ak * ak); adel = ak * (1.0 - del * del - del * (1.0 / 3.0 + 134.0 * del * del / 81.0)); del = d1 / (adel * adel); no_unkozai = no_kozai / (1.0 + del); ao = pow(xke / (no_unkozai), x2o3); sinio = sin(inclo); po = ao * omeosq; con42 = 1.0 - 5.0 * cosio2; con41 = -con42 - cosio2 - cosio2; ainv = 1.0 / ao; posq = po * po; rp = ao * (1.0 - ecco); method = 'n'; // sgp4fix modern approach to finding sidereal time // if (opsmode == 'a') // { // sgp4fix use old way of finding gst // count integer number of days from 0 jan 1970 ts70 = epoch - 7305.0; ds70 = floor(ts70 + 1.0e-8); tfrac = ts70 - ds70; // find greenwich location at epoch c1 = 1.72027916940703639e-2; thgr70 = 1.7321343856509374; fk5r = 5.07551419432269442e-15; c1p2p = c1 + twopi; double gsto1 = fmod(thgr70 + c1*ds70 + c1p2p*tfrac + ts70*ts70*fk5r, twopi); if (gsto1 < 0.0) gsto1 = gsto1 + twopi; // } // else gsto = gstime_SGP4(epoch + 2433281.5); //#include "debug5.cpp" } // initl /*----------------------------------------------------------------------------- * * procedure sgp4init * * this procedure initializes variables for sgp4. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * opsmode - mode of operation afspc or improved 'a', 'i' * whichconst - which set of constants to use 72, 84 * satn - satellite number * bstar - sgp4 type drag coefficient kg/m2er * ecco - eccentricity * epoch - epoch time in days from jan 0, 1950. 0 hr * argpo - argument of perigee (output if ds) * inclo - inclination * mo - mean anomaly (output if ds) * no - mean motion * nodeo - right ascension of ascending node * * outputs : * satrec - common values for subsequent calls * return code - non-zero on error. * 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er * 2 - mean motion less than 0.0 * 3 - pert elements, ecc < 0.0 or ecc > 1.0 * 4 - semi-latus rectum < 0.0 * 5 - epoch elements are sub-orbital * 6 - satellite has decayed * * locals : * cnodm , snodm , cosim , sinim , cosomm , sinomm * cc1sq , cc2 , cc3 * coef , coef1 * cosio4 - * day - * dndt - * em - eccentricity * emsq - eccentricity squared * eeta - * etasq - * gam - * argpm - argument of perigee * nodem - * inclm - inclination * mm - mean anomaly * nm - mean motion * perige - perigee * pinvsq - * psisq - * qzms24 - * rtemsq - * s1, s2, s3, s4, s5, s6, s7 - * sfour - * ss1, ss2, ss3, ss4, ss5, ss6, ss7 - * sz1, sz2, sz3 * sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - * tc - * temp - * temp1, temp2, temp3 - * tsi - * xpidot - * xhdot1 - * z1, z2, z3 - * z11, z12, z13, z21, z22, z23, z31, z32, z33 - * * coupling : * getgravconst- * initl - * dscom - * dpper - * dsinit - * sgp4 - * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ bool sgp4init ( gravconsttype whichconst, char opsmode, const char satn[5], const double epoch, const double xbstar, const double xndot, const double xnddot, const double xecco, const double xargpo, const double xinclo, const double xmo, const double xno_kozai, const double xnodeo, elsetrec& satrec ) { /* --------------------- local variables ------------------------ */ double ao, ainv, con42, cosio, sinio, cosio2, eccsq, omeosq, posq, rp, rteosq, cnodm, snodm, cosim, sinim, cosomm, sinomm, cc1sq, cc2, cc3, coef, coef1, cosio4, day, dndt, em, emsq, eeta, etasq, gam, argpm, nodem, inclm, mm, nm, perige, pinvsq, psisq, qzms24, rtemsq, s1, s2, s3, s4, s5, s6, s7, sfour, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, tc, temp, temp1, temp2, temp3, tsi, xpidot, xhdot1, z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33, qzms2t, ss, x2o3, r[3], v[3], delmotemp, qzms2ttemp, qzms24temp; /* ------------------------ initialization --------------------- */ // sgp4fix divisor for divide by zero check on inclination // the old check used 1.0 + cos(pi-1.0e-9), but then compared it to // 1.5 e-12, so the threshold was changed to 1.5e-12 for consistency const double temp4 = 1.5e-12; /* ----------- set all near earth variables to zero ------------ */ satrec.isimp = 0; satrec.method = 'n'; satrec.aycof = 0.0; satrec.con41 = 0.0; satrec.cc1 = 0.0; satrec.cc4 = 0.0; satrec.cc5 = 0.0; satrec.d2 = 0.0; satrec.d3 = 0.0; satrec.d4 = 0.0; satrec.delmo = 0.0; satrec.eta = 0.0; satrec.argpdot = 0.0; satrec.omgcof = 0.0; satrec.sinmao = 0.0; satrec.t = 0.0; satrec.t2cof = 0.0; satrec.t3cof = 0.0; satrec.t4cof = 0.0; satrec.t5cof = 0.0; satrec.x1mth2 = 0.0; satrec.x7thm1 = 0.0; satrec.mdot = 0.0; satrec.nodedot = 0.0; satrec.xlcof = 0.0; satrec.xmcof = 0.0; satrec.nodecf = 0.0; /* ----------- set all deep space variables to zero ------------ */ satrec.irez = 0; satrec.d2201 = 0.0; satrec.d2211 = 0.0; satrec.d3210 = 0.0; satrec.d3222 = 0.0; satrec.d4410 = 0.0; satrec.d4422 = 0.0; satrec.d5220 = 0.0; satrec.d5232 = 0.0; satrec.d5421 = 0.0; satrec.d5433 = 0.0; satrec.dedt = 0.0; satrec.del1 = 0.0; satrec.del2 = 0.0; satrec.del3 = 0.0; satrec.didt = 0.0; satrec.dmdt = 0.0; satrec.dnodt = 0.0; satrec.domdt = 0.0; satrec.e3 = 0.0; satrec.ee2 = 0.0; satrec.peo = 0.0; satrec.pgho = 0.0; satrec.pho = 0.0; satrec.pinco = 0.0; satrec.plo = 0.0; satrec.se2 = 0.0; satrec.se3 = 0.0; satrec.sgh2 = 0.0; satrec.sgh3 = 0.0; satrec.sgh4 = 0.0; satrec.sh2 = 0.0; satrec.sh3 = 0.0; satrec.si2 = 0.0; satrec.si3 = 0.0; satrec.sl2 = 0.0; satrec.sl3 = 0.0; satrec.sl4 = 0.0; satrec.gsto = 0.0; satrec.xfact = 0.0; satrec.xgh2 = 0.0; satrec.xgh3 = 0.0; satrec.xgh4 = 0.0; satrec.xh2 = 0.0; satrec.xh3 = 0.0; satrec.xi2 = 0.0; satrec.xi3 = 0.0; satrec.xl2 = 0.0; satrec.xl3 = 0.0; satrec.xl4 = 0.0; satrec.xlamo = 0.0; satrec.zmol = 0.0; satrec.zmos = 0.0; satrec.atime = 0.0; satrec.xli = 0.0; satrec.xni = 0.0; /* ------------------------ earth constants ----------------------- */ // sgp4fix identify constants and allow alternate values // this is now the only call for the constants getgravconst(whichconst, satrec.tumin, satrec.mus, satrec.radiusearthkm, satrec.xke, satrec.j2, satrec.j3, satrec.j4, satrec.j3oj2); //------------------------------------------------------------------------- satrec.error = 0; satrec.operationmode = opsmode; // new alpha5 or 9-digit number #ifdef _MSC_VER strcpy_s(satrec.satnum, 6 * sizeof(char), satn); #else strcpy(satrec.satnum, satn); #endif // sgp4fix - note the following variables are also passed directly via satrec. // it is possible to streamline the sgp4init call by deleting the "x" // variables, but the user would need to set the satrec.* values first. we // include the additional assignments in case twoline2rv is not used. satrec.bstar = xbstar; // sgp4fix allow additional parameters in the struct satrec.ndot = xndot; satrec.nddot = xnddot; satrec.ecco = xecco; satrec.argpo = xargpo; satrec.inclo = xinclo; satrec.mo = xmo; // sgp4fix rename variables to clarify which mean motion is intended satrec.no_kozai = xno_kozai; satrec.nodeo = xnodeo; // single averaged mean elements satrec.am = satrec.em = satrec.im = satrec.Om = satrec.mm = satrec.nm = 0.0; /* ------------------------ earth constants ----------------------- */ // sgp4fix identify constants and allow alternate values no longer needed // getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); ss = 78.0 / satrec.radiusearthkm + 1.0; // sgp4fix use multiply for speed instead of pow qzms2ttemp = (120.0 - 78.0) / satrec.radiusearthkm; qzms2t = qzms2ttemp * qzms2ttemp * qzms2ttemp * qzms2ttemp; x2o3 = 2.0 / 3.0; satrec.init = 'y'; satrec.t = 0.0; // sgp4fix remove satn as it is not needed in initl initl (satrec.xke, satrec.j2, satrec.ecco, epoch, satrec.inclo, satrec.no_kozai, satrec.operationmode, satrec.method, ainv, ao, satrec.con41, con42, cosio, cosio2, eccsq, omeosq, posq, rp, rteosq, sinio, satrec.gsto, satrec.no_unkozai); satrec.a = pow(satrec.no_unkozai * satrec.tumin, (-2.0 / 3.0)); satrec.alta = satrec.a * (1.0 + satrec.ecco) - 1.0; satrec.altp = satrec.a * (1.0 - satrec.ecco) - 1.0; satrec.error = 0; // sgp4fix remove this check as it is unnecessary // the mrt check in sgp4 handles decaying satellite cases even if the starting // condition is below the surface of te earth // if (rp < 1.0) // { // printf("# *** satn%d epoch elts sub-orbital ***\n", satn); // satrec.error = 5; // } if ((omeosq >= 0.0) || (satrec.no_unkozai >= 0.0)) { satrec.isimp = 0; if (rp < (220.0 / satrec.radiusearthkm + 1.0)) satrec.isimp = 1; sfour = ss; qzms24 = qzms2t; perige = (rp - 1.0) * satrec.radiusearthkm; /* - for perigees below 156 km, s and qoms2t are altered - */ if (perige < 156.0) { sfour = perige - 78.0; if (perige < 98.0) sfour = 20.0; // sgp4fix use multiply for speed instead of pow qzms24temp = (120.0 - sfour) / satrec.radiusearthkm; qzms24 = qzms24temp * qzms24temp * qzms24temp * qzms24temp; sfour = sfour / satrec.radiusearthkm + 1.0; } pinvsq = 1.0 / posq; tsi = 1.0 / (ao - sfour); satrec.eta = ao * satrec.ecco * tsi; etasq = satrec.eta * satrec.eta; eeta = satrec.ecco * satrec.eta; psisq = fabs(1.0 - etasq); coef = qzms24 * pow(tsi, 4.0); coef1 = coef / pow(psisq, 3.5); cc2 = coef1 * satrec.no_unkozai * (ao * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) + 0.375 * satrec.j2 * tsi / psisq * satrec.con41 * (8.0 + 3.0 * etasq * (8.0 + etasq))); satrec.cc1 = satrec.bstar * cc2; cc3 = 0.0; if (satrec.ecco > 1.0e-4) cc3 = -2.0 * coef * tsi * satrec.j3oj2 * satrec.no_unkozai * sinio / satrec.ecco; satrec.x1mth2 = 1.0 - cosio2; satrec.cc4 = 2.0* satrec.no_unkozai * coef1 * ao * omeosq * (satrec.eta * (2.0 + 0.5 * etasq) + satrec.ecco * (0.5 + 2.0 * etasq) - satrec.j2 * tsi / (ao * psisq) * (-3.0 * satrec.con41 * (1.0 - 2.0 * eeta + etasq * (1.5 - 0.5 * eeta)) + 0.75 * satrec.x1mth2 * (2.0 * etasq - eeta * (1.0 + etasq)) * cos(2.0 * satrec.argpo))); satrec.cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * (etasq + eeta) + eeta * etasq); cosio4 = cosio2 * cosio2; temp1 = 1.5 * satrec.j2 * pinvsq * satrec.no_unkozai; temp2 = 0.5 * temp1 * satrec.j2 * pinvsq; temp3 = -0.46875 * satrec.j4 * pinvsq * pinvsq * satrec.no_unkozai; satrec.mdot = satrec.no_unkozai + 0.5 * temp1 * rteosq * satrec.con41 + 0.0625 * temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4); satrec.argpdot = -0.5 * temp1 * con42 + 0.0625 * temp2 * (7.0 - 114.0 * cosio2 + 395.0 * cosio4) + temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4); xhdot1 = -temp1 * cosio; satrec.nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio; xpidot = satrec.argpdot + satrec.nodedot; satrec.omgcof = satrec.bstar * cc3 * cos(satrec.argpo); satrec.xmcof = 0.0; if (satrec.ecco > 1.0e-4) satrec.xmcof = -x2o3 * coef * satrec.bstar / eeta; satrec.nodecf = 3.5 * omeosq * xhdot1 * satrec.cc1; satrec.t2cof = 1.5 * satrec.cc1; // sgp4fix for divide by zero with xinco = 180 deg if (fabs(cosio + 1.0) > 1.5e-12) satrec.xlcof = -0.25 * satrec.j3oj2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio); else satrec.xlcof = -0.25 * satrec.j3oj2 * sinio * (3.0 + 5.0 * cosio) / temp4; satrec.aycof = -0.5 * satrec.j3oj2 * sinio; // sgp4fix use multiply for speed instead of pow delmotemp = 1.0 + satrec.eta * cos(satrec.mo); satrec.delmo = delmotemp * delmotemp * delmotemp; satrec.sinmao = sin(satrec.mo); satrec.x7thm1 = 7.0 * cosio2 - 1.0; /* --------------- deep space initialization ------------- */ if ((2 * pi / satrec.no_unkozai) >= 225.0) { satrec.method = 'd'; satrec.isimp = 1; tc = 0.0; inclm = satrec.inclo; dscom ( epoch, satrec.ecco, satrec.argpo, tc, satrec.inclo, satrec.nodeo, satrec.no_unkozai, snodm, cnodm, sinim, cosim, sinomm, cosomm, day, satrec.e3, satrec.ee2, em, emsq, gam, satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, satrec.plo, rtemsq, satrec.se2, satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, satrec.sl2, satrec.sl3, satrec.sl4, s1, s2, s3, s4, s5, s6, s7, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, satrec.xl3, satrec.xl4, nm, z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33, satrec.zmol, satrec.zmos ); dpper ( satrec.e3, satrec.ee2, satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, satrec.plo, satrec.se2, satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, satrec.sl2, satrec.sl3, satrec.sl4, satrec.t, satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, satrec.xl3, satrec.xl4, satrec.zmol, satrec.zmos, inclm, satrec.init, satrec.ecco, satrec.inclo, satrec.nodeo, satrec.argpo, satrec.mo, satrec.operationmode ); argpm = 0.0; nodem = 0.0; mm = 0.0; dsinit ( satrec.xke, cosim, emsq, satrec.argpo, s1, s2, s3, s4, s5, sinim, ss1, ss2, ss3, ss4, ss5, sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33, satrec.t, tc, satrec.gsto, satrec.mo, satrec.mdot, satrec.no_unkozai, satrec.nodeo, satrec.nodedot, xpidot, z1, z3, z11, z13, z21, z23, z31, z33, satrec.ecco, eccsq, em, argpm, inclm, mm, nm, nodem, satrec.irez, satrec.atime, satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222, satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, satrec.d5421, satrec.d5433, satrec.dedt, satrec.didt, satrec.dmdt, dndt, satrec.dnodt, satrec.domdt, satrec.del1, satrec.del2, satrec.del3, satrec.xfact, satrec.xlamo, satrec.xli, satrec.xni ); } /* ----------- set variables if not deep space ----------- */ if (satrec.isimp != 1) { cc1sq = satrec.cc1 * satrec.cc1; satrec.d2 = 4.0 * ao * tsi * cc1sq; temp = satrec.d2 * tsi * satrec.cc1 / 3.0; satrec.d3 = (17.0 * ao + sfour) * temp; satrec.d4 = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * satrec.cc1; satrec.t3cof = satrec.d2 + 2.0 * cc1sq; satrec.t4cof = 0.25 * (3.0 * satrec.d3 + satrec.cc1 * (12.0 * satrec.d2 + 10.0 * cc1sq)); satrec.t5cof = 0.2 * (3.0 * satrec.d4 + 12.0 * satrec.cc1 * satrec.d3 + 6.0 * satrec.d2 * satrec.d2 + 15.0 * cc1sq * (2.0 * satrec.d2 + cc1sq)); } } // if omeosq = 0 ... /* finally propogate to zero epoch to initialize all others. */ // sgp4fix take out check to let satellites process until they are actually below earth surface // if(satrec.error == 0) sgp4(satrec, 0.0, r, v); satrec.init = 'n'; //#include "debug6.cpp" //sgp4fix return boolean. satrec.error contains any error codes return true; } // sgp4init /*----------------------------------------------------------------------------- * * procedure sgp4 * * this procedure is the sgp4 prediction model from space command. this is an * updated and combined version of sgp4 and sdp4, which were originally * published separately in spacetrack report #3. this version follows the * methodology from the aiaa paper (2006) describing the history and * development of the code. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * satrec - initialised structure from sgp4init() call. * tsince - time since epoch (minutes) * * outputs : * r - position vector km * v - velocity km/sec * return code - non-zero on error. * 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er * 2 - mean motion less than 0.0 * 3 - pert elements, ecc < 0.0 or ecc > 1.0 * 4 - semi-latus rectum < 0.0 * 5 - epoch elements are sub-orbital * 6 - satellite has decayed * * locals : * am - * axnl, aynl - * betal - * cosim , sinim , cosomm , sinomm , cnod , snod , cos2u , * sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip , * cosisq , cossu , sinsu , cosu , sinu * delm - * delomg - * dndt - * eccm - * emsq - * ecose - * el2 - * eo1 - * eccp - * esine - * argpm - * argpp - * omgadf -c * pl - * r - * rtemsq - * rdotl - * rl - * rvdot - * rvdotl - * su - * t2 , t3 , t4 , tc * tem5, temp , temp1 , temp2 , tempa , tempe , templ * u , ux , uy , uz , vx , vy , vz * inclm - inclination * mm - mean anomaly * nm - mean motion * nodem - right asc of ascending node * xinc - * xincp - * xl - * xlm - * mp - * xmdf - * xmx - * xmy - * nodedf - * xnode - * nodep - * np - * * coupling : * getgravconst- no longer used. Variables are conatined within satrec * dpper * dpspace * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ bool sgp4 ( elsetrec& satrec, double tsince, double r[3], double v[3] ) { double am, axnl, aynl, betal, cosim, cnod, cos2u, coseo1, cosi, cosip, cosisq, cossu, cosu, delm, delomg, em, emsq, ecose, el2, eo1, ep, esine, argpm, argpp, argpdf, pl, mrt = 0.0, mvt, rdotl, rl, rvdot, rvdotl, sinim, sin2u, sineo1, sini, sinip, sinsu, sinu, snod, su, t2, t3, t4, tem5, temp, temp1, temp2, tempa, tempe, templ, u, ux, uy, uz, vx, vy, vz, inclm, mm, nm, nodem, xinc, xincp, xl, xlm, mp, xmdf, xmx, xmy, nodedf, xnode, nodep, tc, dndt, twopi, x2o3, vkmpersec, delmtemp; int ktr; /* ------------------ set mathematical constants --------------- */ // sgp4fix divisor for divide by zero check on inclination // the old check used 1.0 + cos(pi-1.0e-9), but then compared it to // 1.5 e-12, so the threshold was changed to 1.5e-12 for consistency const double temp4 = 1.5e-12; twopi = 2.0 * pi; x2o3 = 2.0 / 3.0; // sgp4fix identify constants and allow alternate values // getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); vkmpersec = satrec.radiusearthkm * satrec.xke / 60.0; /* --------------------- clear sgp4 error flag ----------------- */ satrec.t = tsince; satrec.error = 0; /* ------- update for secular gravity and atmospheric drag ----- */ xmdf = satrec.mo + satrec.mdot * satrec.t; argpdf = satrec.argpo + satrec.argpdot * satrec.t; nodedf = satrec.nodeo + satrec.nodedot * satrec.t; argpm = argpdf; mm = xmdf; t2 = satrec.t * satrec.t; nodem = nodedf + satrec.nodecf * t2; tempa = 1.0 - satrec.cc1 * satrec.t; tempe = satrec.bstar * satrec.cc4 * satrec.t; templ = satrec.t2cof * t2; if (satrec.isimp != 1) { delomg = satrec.omgcof * satrec.t; // sgp4fix use mutliply for speed instead of pow delmtemp = 1.0 + satrec.eta * cos(xmdf); delm = satrec.xmcof * (delmtemp * delmtemp * delmtemp - satrec.delmo); temp = delomg + delm; mm = xmdf + temp; argpm = argpdf - temp; t3 = t2 * satrec.t; t4 = t3 * satrec.t; tempa = tempa - satrec.d2 * t2 - satrec.d3 * t3 - satrec.d4 * t4; tempe = tempe + satrec.bstar * satrec.cc5 * (sin(mm) - satrec.sinmao); templ = templ + satrec.t3cof * t3 + t4 * (satrec.t4cof + satrec.t * satrec.t5cof); } nm = satrec.no_unkozai; em = satrec.ecco; inclm = satrec.inclo; if (satrec.method == 'd') { tc = satrec.t; dspace ( satrec.irez, satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222, satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, satrec.d5421, satrec.d5433, satrec.dedt, satrec.del1, satrec.del2, satrec.del3, satrec.didt, satrec.dmdt, satrec.dnodt, satrec.domdt, satrec.argpo, satrec.argpdot, satrec.t, tc, satrec.gsto, satrec.xfact, satrec.xlamo, satrec.no_unkozai, satrec.atime, em, argpm, inclm, satrec.xli, mm, satrec.xni, nodem, dndt, nm ); } // if method = d if (nm <= 0.0) { // printf("# error nm %f\n", nm); satrec.error = 2; // sgp4fix add return return false; } am = pow((satrec.xke / nm), x2o3) * tempa * tempa; nm = satrec.xke / pow(am, 1.5); em = em - tempe; // fix tolerance for error recognition // sgp4fix am is fixed from the previous nm check if ((em >= 1.0) || (em < -0.001)/* || (am < 0.95)*/) { // printf("# error em %f\n", em); satrec.error = 1; // sgp4fix to return if there is an error in eccentricity return false; } // sgp4fix fix tolerance to avoid a divide by zero if (em < 1.0e-6) em = 1.0e-6; mm = mm + satrec.no_unkozai * templ; xlm = mm + argpm + nodem; emsq = em * em; temp = 1.0 - emsq; nodem = fmod(nodem, twopi); argpm = fmod(argpm, twopi); xlm = fmod(xlm, twopi); mm = fmod(xlm - argpm - nodem, twopi); // sgp4fix recover singly averaged mean elements satrec.am = am; satrec.em = em; satrec.im = inclm; satrec.Om = nodem; satrec.om = argpm; satrec.mm = mm; satrec.nm = nm; /* ----------------- compute extra mean quantities ------------- */ sinim = sin(inclm); cosim = cos(inclm); /* -------------------- add lunar-solar periodics -------------- */ ep = em; xincp = inclm; argpp = argpm; nodep = nodem; mp = mm; sinip = sinim; cosip = cosim; if (satrec.method == 'd') { dpper ( satrec.e3, satrec.ee2, satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, satrec.plo, satrec.se2, satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, satrec.sl2, satrec.sl3, satrec.sl4, satrec.t, satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, satrec.xl3, satrec.xl4, satrec.zmol, satrec.zmos, satrec.inclo, 'n', ep, xincp, nodep, argpp, mp, satrec.operationmode ); if (xincp < 0.0) { xincp = -xincp; nodep = nodep + pi; argpp = argpp - pi; } if ((ep < 0.0) || (ep > 1.0)) { // printf("# error ep %f\n", ep); satrec.error = 3; // sgp4fix add return return false; } } // if method = d /* -------------------- long period periodics ------------------ */ if (satrec.method == 'd') { sinip = sin(xincp); cosip = cos(xincp); satrec.aycof = -0.5*satrec.j3oj2*sinip; // sgp4fix for divide by zero for xincp = 180 deg if (fabs(cosip + 1.0) > 1.5e-12) satrec.xlcof = -0.25 * satrec.j3oj2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip); else satrec.xlcof = -0.25 * satrec.j3oj2 * sinip * (3.0 + 5.0 * cosip) / temp4; } axnl = ep * cos(argpp); temp = 1.0 / (am * (1.0 - ep * ep)); aynl = ep* sin(argpp) + temp * satrec.aycof; xl = mp + argpp + nodep + temp * satrec.xlcof * axnl; /* --------------------- solve kepler's equation --------------- */ u = fmod(xl - nodep, twopi); eo1 = u; tem5 = 9999.9; ktr = 1; // sgp4fix for kepler iteration // the following iteration needs better limits on corrections while ((fabs(tem5) >= 1.0e-12) && (ktr <= 10)) { sineo1 = sin(eo1); coseo1 = cos(eo1); tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl; tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5; if (fabs(tem5) >= 0.95) tem5 = tem5 > 0.0 ? 0.95 : -0.95; eo1 = eo1 + tem5; ktr = ktr + 1; } /* ------------- short period preliminary quantities ----------- */ ecose = axnl*coseo1 + aynl*sineo1; esine = axnl*sineo1 - aynl*coseo1; el2 = axnl*axnl + aynl*aynl; pl = am*(1.0 - el2); if (pl < 0.0) { // printf("# error pl %f\n", pl); satrec.error = 4; // sgp4fix add return return false; } else { rl = am * (1.0 - ecose); rdotl = sqrt(am) * esine / rl; rvdotl = sqrt(pl) / rl; betal = sqrt(1.0 - el2); temp = esine / (1.0 + betal); sinu = am / rl * (sineo1 - aynl - axnl * temp); cosu = am / rl * (coseo1 - axnl + aynl * temp); su = atan2(sinu, cosu); sin2u = (cosu + cosu) * sinu; cos2u = 1.0 - 2.0 * sinu * sinu; temp = 1.0 / pl; temp1 = 0.5 * satrec.j2 * temp; temp2 = temp1 * temp; /* -------------- update for short period periodics ------------ */ if (satrec.method == 'd') { cosisq = cosip * cosip; satrec.con41 = 3.0*cosisq - 1.0; satrec.x1mth2 = 1.0 - cosisq; satrec.x7thm1 = 7.0*cosisq - 1.0; } mrt = rl * (1.0 - 1.5 * temp2 * betal * satrec.con41) + 0.5 * temp1 * satrec.x1mth2 * cos2u; su = su - 0.25 * temp2 * satrec.x7thm1 * sin2u; xnode = nodep + 1.5 * temp2 * cosip * sin2u; xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u; mvt = rdotl - nm * temp1 * satrec.x1mth2 * sin2u / satrec.xke; rvdot = rvdotl + nm * temp1 * (satrec.x1mth2 * cos2u + 1.5 * satrec.con41) / satrec.xke; /* --------------------- orientation vectors ------------------- */ sinsu = sin(su); cossu = cos(su); snod = sin(xnode); cnod = cos(xnode); sini = sin(xinc); cosi = cos(xinc); xmx = -snod * cosi; xmy = cnod * cosi; ux = xmx * sinsu + cnod * cossu; uy = xmy * sinsu + snod * cossu; uz = sini * sinsu; vx = xmx * cossu - cnod * sinsu; vy = xmy * cossu - snod * sinsu; vz = sini * cossu; /* --------- position and velocity (in km and km/sec) ---------- */ r[0] = (mrt * ux)* satrec.radiusearthkm; r[1] = (mrt * uy)* satrec.radiusearthkm; r[2] = (mrt * uz)* satrec.radiusearthkm; v[0] = (mvt * ux + rvdot * vx) * vkmpersec; v[1] = (mvt * uy + rvdot * vy) * vkmpersec; v[2] = (mvt * uz + rvdot * vz) * vkmpersec; } // if pl > 0 // sgp4fix for decaying satellites if (mrt < 1.0) { // printf("# decay condition %11.6f \n",mrt); satrec.error = 6; return false; } //#include "debug7.cpp" return true; } // sgp4 /* ----------------------------------------------------------------------------- * * function getgravconst * * this function gets constants for the propagator. note that mu is identified to * facilitiate comparisons with newer models. the common useage is wgs72. * * author : david vallado 719-573-2600 21 jul 2006 * * inputs : * whichconst - which set of constants to use wgs72old, wgs72, wgs84 * * outputs : * tumin - minutes in one time unit * mu - earth gravitational parameter * radiusearthkm - radius of the earth in km * xke - reciprocal of tumin * j2, j3, j4 - un-normalized zonal harmonic values * j3oj2 - j3 divided by j2 * * locals : * * coupling : * none * * references : * norad spacetrack report #3 * vallado, crawford, hujsak, kelso 2006 --------------------------------------------------------------------------- */ void getgravconst ( gravconsttype whichconst, double& tumin, double& mus, double& radiusearthkm, double& xke, double& j2, double& j3, double& j4, double& j3oj2 ) { switch (whichconst) { // -- wgs-72 low precision str#3 constants -- case wgs72old: mus = 398600.79964; // in km3 / s2 radiusearthkm = 6378.135; // km xke = 0.0743669161; // reciprocal of tumin tumin = 1.0 / xke; j2 = 0.001082616; j3 = -0.00000253881; j4 = -0.00000165597; j3oj2 = j3 / j2; break; // ------------ wgs-72 constants ------------ case wgs72: mus = 398600.8; // in km3 / s2 radiusearthkm = 6378.135; // km xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm / mus); tumin = 1.0 / xke; j2 = 0.001082616; j3 = -0.00000253881; j4 = -0.00000165597; j3oj2 = j3 / j2; break; case wgs84: // ------------ wgs-84 constants ------------ mus = 398600.5; // in km3 / s2 radiusearthkm = 6378.137; // km xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm / mus); tumin = 1.0 / xke; j2 = 0.00108262998905; j3 = -0.00000253215306; j4 = -0.00000161098761; j3oj2 = j3 / j2; break; default: fprintf(stderr, "unknown gravity option (%d)\n", whichconst); break; } } // getgravconst // older sgp4io methods /* ----------------------------------------------------------------------------- * * function twoline2rv * * this function converts the two line element set character string data to * variables and initializes the sgp4 variables. several intermediate varaibles * and quantities are determined. note that the result is a structure so multiple * satellites can be processed simaltaneously without having to reinitialize. the * verification mode is an important option that permits quick checks of any * changes to the underlying technical theory. this option works using a * modified tle file in which the start, stop, and delta time values are * included at the end of the second line of data. this only works with the * verification mode. the catalog mode simply propagates from -1440 to 1440 min * from epoch and is useful when performing entire catalog runs. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs : * longstr1 - first line of the tle * longstr2 - second line of the tle * typerun - type of run verification 'v', catalog 'c', * manual 'm' * typeinput - type of manual input mfe 'm', epoch 'e', dayofyr 'd' * opsmode - mode of operation afspc or improved 'a', 'i' * whichconst - which set of constants to use 72, 84 * * outputs : * satrec - structure containing all the sgp4 satellite information * * coupling : * getgravconst- * days2mdhms - conversion of days to month, day, hour, minute, second * jday - convert day month year hour minute second into julian date * sgp4init - initialize the sgp4 variables * * references : * norad spacetrack report #3 * vallado, crawford, hujsak, kelso 2006 --------------------------------------------------------------------------- */ void twoline2rv ( char longstr1[130], char longstr2[130], char typerun, char typeinput, char opsmode, gravconsttype whichconst, double& startmfe, double& stopmfe, double& deltamin, elsetrec& satrec ) { const double deg2rad = pi / 180.0; // 0.0174532925199433 const double xpdotp = 1440.0 / (2.0 *pi); // 229.1831180523293 double sec; double startsec, stopsec, startdayofyr, stopdayofyr, jdstart, jdstop, jdstartF, jdstopF; int startyear, stopyear, startmon, stopmon, startday, stopday, starthr, stophr, startmin, stopmin; int cardnumb, j; // sgp4fix include in satrec // long revnum = 0, elnum = 0; // char classification, intldesg[11]; int year = 0; int mon, day, hr, minute, nexp, ibexp; // sgp4fix no longer needed // getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); satrec.error = 0; // set the implied decimal points since doing a formated read // fixes for bad input data values (missing, ...) for (j = 10; j <= 15; j++) if (longstr1[j] == ' ') longstr1[j] = '_'; if (longstr1[44] != ' ') longstr1[43] = longstr1[44]; longstr1[44] = '.'; if (longstr1[7] == ' ') longstr1[7] = 'U'; if (longstr1[9] == ' ') longstr1[9] = '.'; for (j = 45; j <= 49; j++) if (longstr1[j] == ' ') longstr1[j] = '0'; if (longstr1[51] == ' ') longstr1[51] = '0'; if (longstr1[53] != ' ') longstr1[52] = longstr1[53]; longstr1[53] = '.'; longstr2[25] = '.'; for (j = 26; j <= 32; j++) if (longstr2[j] == ' ') longstr2[j] = '0'; if (longstr1[62] == ' ') longstr1[62] = '0'; if (longstr1[68] == ' ') longstr1[68] = '0'; #ifdef _MSC_VER // chk if compiling in MSVS c++ sscanf_s(longstr1, "%2d %5s %1c %10s %2d %12lf %11lf %7lf %2d %7lf %2d %2d %6ld ", &cardnumb, &satrec.satnum, 6 * sizeof(char), &satrec.classification, sizeof(char), &satrec.intldesg, 11 * sizeof(char), &satrec.epochyr, &satrec.epochdays, &satrec.ndot, &satrec.nddot, &nexp, &satrec.bstar, &ibexp, &satrec.ephtype, &satrec.elnum); #else sscanf(longstr1, "%2d %5s %1c %10s %2d %12lf %11lf %7lf %2d %7lf %2d %2d %6ld ", &cardnumb, &satrec.satnum, &satrec.classification, &satrec.intldesg, &satrec.epochyr, &satrec.epochdays, &satrec.ndot, &satrec.nddot, &nexp, &satrec.bstar, &ibexp, &satrec.ephtype, &satrec.elnum); #endif if (typerun == 'v') // run for specified times from the file { if (longstr2[52] == ' ') { #ifdef _MSC_VER sscanf_s(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %10lf %6ld %lf %lf %lf \n", &cardnumb, &satrec.satnum, 6 * sizeof(char), &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum, &startmfe, &stopmfe, &deltamin); #else sscanf(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %10lf %6ld %lf %lf %lf \n", &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum, &startmfe, &stopmfe, &deltamin); #endif } else { #ifdef _MSC_VER sscanf_s(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %11lf %6ld %lf %lf %lf \n", &cardnumb, &satrec.satnum, 6 * sizeof(char), &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum, &startmfe, &stopmfe, &deltamin); #else sscanf(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %11lf %6ld %lf %lf %lf \n", &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum, &startmfe, &stopmfe, &deltamin); #endif } } else // simply run -1 day to +1 day or user input times { if (longstr2[52] == ' ') { #ifdef _MSC_VER sscanf_s(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %10lf %6ld \n", &cardnumb, &satrec.satnum, 6 * sizeof(char), &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum); #else sscanf(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %10lf %6ld \n", &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum); #endif } else { #ifdef _MSC_VER sscanf_s(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %11lf %6ld \n", &cardnumb, &satrec.satnum, 6 * sizeof(char), &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum); #else sscanf(longstr2, "%2d %5s %9lf %9lf %8lf %9lf %9lf %11lf %6ld \n", &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no_kozai, &satrec.revnum); #endif } } // ---- find no, ndot, nddot ---- satrec.no_kozai = satrec.no_kozai / xpdotp; //* rad/min satrec.nddot = satrec.nddot * pow(10.0, nexp); satrec.bstar = satrec.bstar * pow(10.0, ibexp); // ---- convert to sgp4 units ---- // satrec.a = pow( satrec.no_kozai*tumin , (-2.0/3.0) ); satrec.ndot = satrec.ndot / (xpdotp*1440.0); //* ? * minperday satrec.nddot = satrec.nddot / (xpdotp*1440.0 * 1440); // ---- find standard orbital elements ---- satrec.inclo = satrec.inclo * deg2rad; satrec.nodeo = satrec.nodeo * deg2rad; satrec.argpo = satrec.argpo * deg2rad; satrec.mo = satrec.mo * deg2rad; // sgp4fix not needed here // satrec.alta = satrec.a*(1.0 + satrec.ecco) - 1.0; // satrec.altp = satrec.a*(1.0 - satrec.ecco) - 1.0; // ---------------------------------------------------------------- // find sgp4epoch time of element set // remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch) // and minutes from the epoch (time) // ---------------------------------------------------------------- // ---------------- temp fix for years from 1957-2056 ------------------- // --------- correct fix will occur when year is 4-digit in tle --------- if (satrec.epochyr < 57) year = satrec.epochyr + 2000; else year = satrec.epochyr + 1900; days2mdhms_SGP4(year, satrec.epochdays, mon, day, hr, minute, sec); jday_SGP4(year, mon, day, hr, minute, sec, satrec.jdsatepoch, satrec.jdsatepochF); // ---- input start stop times manually if ((typerun != 'v') && (typerun != 'c')) { // ------------- enter start/stop ymd hms values -------------------- if (typeinput == 'e') { printf("input start prop year mon day hr min sec \n"); // make sure there is no space at the end of the format specifiers in scanf! #ifdef _MSC_VER scanf_s("%i %i %i %i %i %lf", &startyear, &startmon, &startday, &starthr, &startmin, &startsec); #else scanf("%i %i %i %i %i %lf", &startyear, &startmon, &startday, &starthr, &startmin, &startsec); #endif fflush(stdin); jday_SGP4(startyear, startmon, startday, starthr, startmin, startsec, jdstart, jdstartF); printf("input stop prop year mon day hr min sec \n"); #ifdef _MSC_VER scanf_s("%i %i %i %i %i %lf", &stopyear, &stopmon, &stopday, &stophr, &stopmin, &stopsec); #else scanf("%i %i %i %i %i %lf", &stopyear, &stopmon, &stopday, &stophr, &stopmin, &stopsec); #endif fflush(stdin); jday_SGP4(stopyear, stopmon, stopday, stophr, stopmin, stopsec, jdstop, jdstopF); startmfe = (jdstart - satrec.jdsatepoch) * 1440.0 + (jdstartF - satrec.jdsatepochF) * 1440.0; stopmfe = (jdstop - satrec.jdsatepoch) * 1440.0 + (jdstopF - satrec.jdsatepochF) * 1440.0; printf("input time step in minutes \n"); #ifdef _MSC_VER scanf_s("%lf", &deltamin); #else scanf("%lf", &deltamin); #endif } // -------- enter start/stop year and days of year values ----------- if (typeinput == 'd') { printf("input start year dayofyr \n"); #ifdef _MSC_VER scanf_s("%i %lf", &startyear, &startdayofyr); #else scanf("%i %lf", &startyear, &startdayofyr); #endif printf("input stop year dayofyr \n"); #ifdef _MSC_VER scanf_s("%i %lf", &stopyear, &stopdayofyr); #else scanf("%i %lf", &stopyear, &stopdayofyr); #endif days2mdhms_SGP4(startyear, startdayofyr, mon, day, hr, minute, sec); jday_SGP4(startyear, mon, day, hr, minute, sec, jdstart, jdstartF); days2mdhms_SGP4(stopyear, stopdayofyr, mon, day, hr, minute, sec); jday_SGP4(stopyear, mon, day, hr, minute, sec, jdstop, jdstopF); startmfe = (jdstart - satrec.jdsatepoch) * 1440.0 + (jdstartF - satrec.jdsatepochF) * 1440.0; stopmfe = (jdstop - satrec.jdsatepoch) * 1440.0 + (jdstopF - satrec.jdsatepochF) * 1440.0; printf("input time step in minutes \n"); #ifdef _MSC_VER scanf_s("%lf", &deltamin); #else scanf("%lf", &deltamin); #endif } // ------------------ enter start/stop mfe values ------------------- if (typeinput == 'm') { #ifdef _MSC_VER printf("input start min from epoch \n"); scanf_s("%lf", &startmfe); printf("input stop min from epoch \n"); scanf_s("%lf", &stopmfe); printf("input time step in minutes \n"); scanf_s("%lf", &deltamin); #else printf("input start min from epoch \n"); scanf("%lf", &startmfe); printf("input stop min from epoch \n"); scanf("%lf", &stopmfe); printf("input time step in minutes \n"); scanf("%lf", &deltamin); #endif } } // ------------ perform complete catalog evaluation, -+ 1 day ----------- if (typerun == 'c') { startmfe = -1440.0; stopmfe = 1440.0; deltamin = 10.0; } // ---------------- initialize the orbit at sgp4epoch ------------------- sgp4init(whichconst, opsmode, satrec.satnum, (satrec.jdsatepoch + satrec.jdsatepochF) - 2433281.5, satrec.bstar, satrec.ndot, satrec.nddot, satrec.ecco, satrec.argpo, satrec.inclo, satrec.mo, satrec.no_kozai, satrec.nodeo, satrec); } // twoline2rv // older sgp4ext methods /* ----------------------------------------------------------------------------- * * function gstime_SGP4 * * this function finds the greenwich sidereal time. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * jdut1 - julian date in ut1 days from 4713 bc * * outputs : * gstime - greenwich sidereal time 0 to 2pi rad * * locals : * temp - temporary variable for doubles rad * tut1 - julian centuries from the * jan 1, 2000 12 h epoch (ut1) * * coupling : * none * * references : * vallado 2013, 187, eq 3-45 * --------------------------------------------------------------------------- */ double gstime_SGP4 ( double jdut1 ) { const double twopi = 2.0 * pi; const double deg2rad = pi / 180.0; double temp, tut1; tut1 = (jdut1 - 2451545.0) / 36525.0; temp = -6.2e-6* tut1 * tut1 * tut1 + 0.093104 * tut1 * tut1 + (876600.0 * 3600 + 8640184.812866) * tut1 + 67310.54841; // sec temp = fmod(temp * deg2rad / 240.0, twopi); //360/86400 = 1/240, to deg, to rad // ------------------------ check quadrants --------------------- if (temp < 0.0) temp += twopi; return temp; } // gstime double sgn_SGP4 ( double x ) { if (x < 0.0) { return -1.0; } else { return 1.0; } } // sgn /* ----------------------------------------------------------------------------- * * function mag_SGP4 * * this procedure finds the magnitude of a vector. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec - vector * * outputs : * mag - answer * * locals : * none. * * coupling : * none. * --------------------------------------------------------------------------- */ double mag_SGP4 ( double x[3] ) { return sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); } // mag /* ----------------------------------------------------------------------------- * * procedure cross_SGP4 * * this procedure crosses two vectors. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec1 - vector number 1 * vec2 - vector number 2 * * outputs : * outvec - vector result of a x b * * locals : * none. * * coupling : * mag magnitude of a vector ---------------------------------------------------------------------------- */ void cross_SGP4 ( double vec1[3], double vec2[3], double outvec[3] ) { outvec[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1]; outvec[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2]; outvec[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0]; } // end cross /* ----------------------------------------------------------------------------- * * function dot_SGP4 * * this function finds the dot product of two vectors. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec1 - vector number 1 * vec2 - vector number 2 * * outputs : * dot - result * * locals : * none. * * coupling : * none. * --------------------------------------------------------------------------- */ double dot_SGP4 ( double x[3], double y[3] ) { return (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]); } // dot /* ----------------------------------------------------------------------------- * * procedure angle_SGP4 * * this procedure calculates the angle between two vectors. the output is * set to 999999.1 to indicate an undefined value. be sure to check for * this at the output phase. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec1 - vector number 1 * vec2 - vector number 2 * * outputs : * theta - angle between the two vectors -pi to pi * * locals : * temp - temporary real variable * * coupling : * dot dot product of two vectors * --------------------------------------------------------------------------- */ double angle_SGP4 ( double vec1[3], double vec2[3] ) { double small, undefined, magv1, magv2, temp; small = 0.00000001; undefined = 999999.1; magv1 = mag_SGP4(vec1); magv2 = mag_SGP4(vec2); if (magv1*magv2 > small*small) { temp = dot_SGP4(vec1, vec2) / (magv1*magv2); if (fabs(temp) > 1.0) temp = sgn_SGP4(temp) * 1.0; return acos(temp); } else return undefined; } // angle /* ----------------------------------------------------------------------------- * * function asinh_SGP4 * * this function evaluates the inverse hyperbolic sine function. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * xval - angle value any real * * outputs : * arcsinh - result any real * * locals : * none. * * coupling : * none. * --------------------------------------------------------------------------- */ double asinh_SGP4 ( double xval ) { return log(xval + sqrt(xval*xval + 1.0)); } // asinh /* ----------------------------------------------------------------------------- * * function newtonnu_SGP4 * * this function solves keplers equation when the true anomaly is known. * the mean and eccentric, parabolic, or hyperbolic anomaly is also found. * the parabolic limit at 168 is arbitrary. the hyperbolic anomaly is also * limited. the hyperbolic sine is used because it's not double valued. * * author : david vallado 719-573-2600 27 may 2002 * * revisions * vallado - fix small 24 sep 2002 * * inputs description range / units * ecc - eccentricity 0.0 to * nu - true anomaly -2pi to 2pi rad * * outputs : * e0 - eccentric anomaly 0.0 to 2pi rad 153.02 * m - mean anomaly 0.0 to 2pi rad 151.7425 * * locals : * e1 - eccentric anomaly, next value rad * sine - sine of e * cose - cosine of e * ktr - index * * coupling : * asinh - arc hyperbolic sine * * references : * vallado 2013, 77, alg 5 * --------------------------------------------------------------------------- */ void newtonnu_SGP4 ( double ecc, double nu, double& e0, double& m ) { double small, sine, cose; // --------------------- implementation --------------------- e0 = 999999.9; m = 999999.9; small = 0.00000001; // --------------------------- circular ------------------------ if (fabs(ecc) < small) { m = nu; e0 = nu; } else // ---------------------- elliptical ----------------------- if (ecc < 1.0 - small) { sine = (sqrt(1.0 - ecc*ecc) * sin(nu)) / (1.0 + ecc*cos(nu)); cose = (ecc + cos(nu)) / (1.0 + ecc*cos(nu)); e0 = atan2(sine, cose); m = e0 - ecc*sin(e0); } else // -------------------- hyperbolic -------------------- if (ecc > 1.0 + small) { if ((ecc > 1.0) && (fabs(nu) + 0.00001 < pi - acos(1.0 / ecc))) { sine = (sqrt(ecc*ecc - 1.0) * sin(nu)) / (1.0 + ecc*cos(nu)); e0 = asinh_SGP4(sine); m = ecc*sinh(e0) - e0; } } else // ----------------- parabolic --------------------- if (fabs(nu) < 168.0*pi / 180.0) { e0 = tan(nu*0.5); m = e0 + (e0*e0*e0) / 3.0; } if (ecc < 1.0) { m = fmod(m, 2.0 *pi); if (m < 0.0) m = m + 2.0 *pi; e0 = fmod(e0, 2.0 *pi); } } // newtonnu /* ----------------------------------------------------------------------------- * * function rv2coe_SGP4 * * this function finds the classical orbital elements given the geocentric * equatorial position and velocity vectors. * * author : david vallado 719-573-2600 21 jun 2002 * * revisions * vallado - fix special cases 5 sep 2002 * vallado - delete extra check in inclination code 16 oct 2002 * vallado - add constant file use 29 jun 2003 * vallado - add mu 2 apr 2007 * * inputs description range / units * r - ijk position vector km * v - ijk velocity vector km / s * mu - gravitational parameter km3 / s2 * * outputs : * p - semilatus rectum km * a - semimajor axis km * ecc - eccentricity * incl - inclination 0.0 to pi rad * omega - right ascension of ascending node 0.0 to 2pi rad * argp - argument of perigee 0.0 to 2pi rad * nu - true anomaly 0.0 to 2pi rad * m - mean anomaly 0.0 to 2pi rad * arglat - argument of latitude (ci) 0.0 to 2pi rad * truelon - true longitude (ce) 0.0 to 2pi rad * lonper - longitude of periapsis (ee) 0.0 to 2pi rad * * locals : * hbar - angular momentum h vector km2 / s * ebar - eccentricity e vector * nbar - line of nodes n vector * c1 - v**2 - u/r * rdotv - r dot v * hk - hk unit vector * sme - specfic mechanical energy km2 / s2 * i - index * e - eccentric, parabolic, * hyperbolic anomaly rad * temp - temporary variable * typeorbit - type of orbit ee, ei, ce, ci * * coupling : * mag - magnitude of a vector * cross - cross product of two vectors * angle - find the angle between two vectors * newtonnu - find the mean anomaly * * references : * vallado 2013, 113, alg 9, ex 2-5 * --------------------------------------------------------------------------- */ void rv2coe_SGP4 ( double r[3], double v[3], double mus, double& p, double& a, double& ecc, double& incl, double& omega, double& argp, double& nu, double& m, double& arglat, double& truelon, double& lonper ) { double undefined, small, hbar[3], nbar[3], magr, magv, magn, ebar[3], sme, rdotv, infinite, temp, c1, hk, twopi, magh, halfpi, e; int i; // switch this to an integer msvs seems to have probelms with this and strncpy_s //char typeorbit[2]; int typeorbit; // here // typeorbit = 1 = 'ei' // typeorbit = 2 = 'ce' // typeorbit = 3 = 'ci' // typeorbit = 4 = 'ee' twopi = 2.0 * pi; halfpi = 0.5 * pi; small = 0.00000001; undefined = 999999.1; infinite = 999999.9; // ------------------------- implementation ----------------- magr = mag_SGP4(r); magv = mag_SGP4(v); // ------------------ find h n and e vectors ---------------- cross_SGP4(r, v, hbar); magh = mag_SGP4(hbar); if (magh > small) { nbar[0] = -hbar[1]; nbar[1] = hbar[0]; nbar[2] = 0.0; magn = mag_SGP4(nbar); c1 = magv*magv - mus / magr; rdotv = dot_SGP4(r, v); for (i = 0; i <= 2; i++) ebar[i] = (c1*r[i] - rdotv*v[i]) / mus; ecc = mag_SGP4(ebar); // ------------ find a e and semi-latus rectum ---------- sme = (magv*magv*0.5) - (mus / magr); if (fabs(sme) > small) a = -mus / (2.0 *sme); else a = infinite; p = magh*magh / mus; // ----------------- find inclination ------------------- hk = hbar[2] / magh; incl = acos(hk); // -------- determine type of orbit for later use -------- // ------ elliptical, parabolic, hyperbolic inclined ------- //#ifdef _MSC_VER // chk if compiling under MSVS // strcpy_s(typeorbit, 2 * sizeof(char), "ei"); //#else // strcpy(typeorbit, "ei"); //#endif typeorbit = 1; if (ecc < small) { // ---------------- circular equatorial --------------- if ((incl < small) | (fabs(incl - pi) < small)) { //#ifdef _MSC_VER // strcpy_s(typeorbit, sizeof(typeorbit), "ce"); //#else // strcpy(typeorbit, "ce"); //#endif typeorbit = 2; } else { // -------------- circular inclined --------------- //#ifdef _MSC_VER // strcpy_s(typeorbit, sizeof(typeorbit), "ci"); //#else // strcpy(typeorbit, "ci"); //#endif typeorbit = 3; } } else { // - elliptical, parabolic, hyperbolic equatorial -- if ((incl < small) | (fabs(incl - pi) < small)){ //#ifdef _MSC_VER // strcpy_s(typeorbit, sizeof(typeorbit), "ee"); //#else // strcpy(typeorbit, "ee"); //#endif typeorbit = 4; } } // ---------- find right ascension of the ascending node ------------ if (magn > small) { temp = nbar[0] / magn; if (fabs(temp) > 1.0) temp = sgn_SGP4(temp); omega = acos(temp); if (nbar[1] < 0.0) omega = twopi - omega; } else omega = undefined; // ---------------- find argument of perigee --------------- //if (strcmp(typeorbit, "ei") == 0) if (typeorbit == 1) { argp = angle_SGP4(nbar, ebar); if (ebar[2] < 0.0) argp = twopi - argp; } else argp = undefined; // ------------ find true anomaly at epoch ------------- //if (typeorbit[0] == 'e') if ((typeorbit == 1) || (typeorbit == 4)) { nu = angle_SGP4(ebar, r); if (rdotv < 0.0) nu = twopi - nu; } else nu = undefined; // ---- find argument of latitude - circular inclined ----- //if (strcmp(typeorbit, "ci") == 0) if (typeorbit == 3) { arglat = angle_SGP4(nbar, r); if (r[2] < 0.0) arglat = twopi - arglat; m = arglat; } else arglat = undefined; // -- find longitude of perigee - elliptical equatorial ---- //if ((ecc>small) && (strcmp(typeorbit, "ee") == 0)) if ((ecc>small) && (typeorbit == 4)) { temp = ebar[0] / ecc; if (fabs(temp) > 1.0) temp = sgn_SGP4(temp); lonper = acos(temp); if (ebar[1] < 0.0) lonper = twopi - lonper; if (incl > halfpi) lonper = twopi - lonper; } else lonper = undefined; // -------- find true longitude - circular equatorial ------ //if ((magr>small) && (strcmp(typeorbit, "ce") == 0)) if ((magr > small) && (typeorbit == 2)) { temp = r[0] / magr; if (fabs(temp) > 1.0) temp = sgn_SGP4(temp); truelon = acos(temp); if (r[1] < 0.0) truelon = twopi - truelon; if (incl > halfpi) truelon = twopi - truelon; m = truelon; } else truelon = undefined; // ------------ find mean anomaly for all orbits ----------- //if (typeorbit[0] == 'e') if ((typeorbit == 1) || (typeorbit == 4)) newtonnu_SGP4(ecc, nu, e, m); } else { p = undefined; a = undefined; ecc = undefined; incl = undefined; omega = undefined; argp = undefined; nu = undefined; m = undefined; arglat = undefined; truelon = undefined; lonper = undefined; } } // rv2coe /* ----------------------------------------------------------------------------- * * procedure jday_SGP4 * * this procedure finds the julian date given the year, month, day, and time. * the julian date is defined by each elapsed day since noon, jan 1, 4713 bc. * * algorithm : calculate the answer in one step for efficiency * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * year - year 1900 .. 2100 * mon - month 1 .. 12 * day - day 1 .. 28,29,30,31 * hr - universal time hour 0 .. 23 * min - universal time min 0 .. 59 * sec - universal time sec 0.0 .. 59.999 * * outputs : * jd - julian date days from 4713 bc * jdfrac - julian date fraction into day days from 4713 bc * * locals : * none. * * coupling : * none. * * references : * vallado 2013, 183, alg 14, ex 3-4 * --------------------------------------------------------------------------- */ void jday_SGP4 ( int year, int mon, int day, int hr, int minute, double sec, double& jd, double& jdFrac ) { jd = 367.0 * year - floor((7 * (year + floor((mon + 9) / 12.0))) * 0.25) + floor(275 * mon / 9.0) + day + 1721013.5; // use - 678987.0 to go to mjd directly jdFrac = (sec + minute * 60.0 + hr * 3600.0) / 86400.0; // check that the day and fractional day are correct if (fabs(jdFrac) > 1.0) { double dtt = floor(jdFrac); jd = jd + dtt; jdFrac = jdFrac - dtt; } // - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5; } // jday /* ----------------------------------------------------------------------------- * * procedure days2mdhms_SGP4 * * this procedure converts the day of the year, days, to the equivalent month * day, hour, minute and second. * * algorithm : set up array for the number of days per month * find leap year - use 1900 because 2000 is a leap year * loop through a temp value while the value is < the days * perform int conversions to the correct day and month * convert remainder into h m s using type conversions * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * year - year 1900 .. 2100 * days - julian day of the year 1.0 .. 366.0 * * outputs : * mon - month 1 .. 12 * day - day 1 .. 28,29,30,31 * hr - hour 0 .. 23 * min - minute 0 .. 59 * sec - second 0.0 .. 59.999 * * locals : * dayofyr - day of year * temp - temporary extended values * inttemp - temporary int value * i - index * lmonth[13] - int array containing the number of days per month * * coupling : * none. * --------------------------------------------------------------------------- */ void days2mdhms_SGP4 ( int year, double days, int& mon, int& day, int& hr, int& minute, double& sec ) { int i, inttemp, dayofyr; double temp; int lmonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; dayofyr = (int)floor(days); /* ----------------- find month and day of month ---------------- */ if ((year % 4) == 0) lmonth[2] = 29; i = 1; inttemp = 0; while ((dayofyr > inttemp + lmonth[i]) && (i < 12)) { inttemp = inttemp + lmonth[i]; i++; } mon = i; day = dayofyr - inttemp; /* ----------------- find hours minutes and seconds ------------- */ temp = (days - dayofyr) * 24.0; hr = (int)floor(temp); temp = (temp - hr) * 60.0; minute = (int)floor(temp); sec = (temp - minute) * 60.0; } // days2mdhms /* ----------------------------------------------------------------------------- * * procedure invjday_SGP4 * * this procedure finds the year, month, day, hour, minute and second * given the julian date. tu can be ut1, tdt, tdb, etc. * * algorithm : set up starting values * find leap year - use 1900 because 2000 is a leap year * find the elapsed days through the year in a loop * call routine to find each individual value * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * jd - julian date days from 4713 bc * jdfrac - julian date fraction into day days from 4713 bc * * outputs : * year - year 1900 .. 2100 * mon - month 1 .. 12 * day - day 1 .. 28,29,30,31 * hr - hour 0 .. 23 * min - minute 0 .. 59 * sec - second 0.0 .. 59.999 * * locals : * days - day of year plus fractional * portion of a day days * tu - julian centuries from 0 h * jan 0, 1900 * temp - temporary double values * leapyrs - number of leap years from 1900 * * coupling : * days2mdhms - finds month, day, hour, minute and second given days and year * * references : * vallado 2013, 203, alg 22, ex 3-13 * --------------------------------------------------------------------------- */ void invjday_SGP4 ( double jd, double jdfrac, int& year, int& mon, int& day, int& hr, int& minute, double& sec ) { int leapyrs; double dt, days, tu, temp; // check jdfrac for multiple days if (fabs(jdfrac) >= 1.0) { jd = jd + floor(jdfrac); jdfrac = jdfrac - floor(jdfrac); } // check for fraction of a day included in the jd dt = jd - floor(jd) - 0.5; if (fabs(dt) > 0.00000001) { jd = jd - dt; jdfrac = jdfrac + dt; } /* --------------- find year and days of the year --------------- */ temp = jd - 2415019.5; tu = temp / 365.25; year = 1900 + (int)floor(tu); leapyrs = (int)floor((year - 1901) * 0.25); days = floor(temp - ((year - 1900) * 365.0 + leapyrs)); /* ------------ check for case of beginning of a year ----------- */ if (days + jdfrac < 1.0) { year = year - 1; leapyrs = (int)floor((year - 1901) * 0.25); days = floor(temp - ((year - 1900) * 365.0 + leapyrs)); } /* ----------------- find remaining data ------------------------- */ days2mdhms_SGP4(year, days + jdfrac, mon, day, hr, minute, sec); } // invjday } // namespace SGP4Funcs ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/extension/SGP4.h0000644000175100001730000001525614422467341014637 0ustar00runnerdocker#ifndef _SGP4h_ #define _SGP4h_ /* ---------------------------------------------------------------- * * SGP4.h * * this file contains the sgp4 procedures for analytical propagation * of a satellite. the code was originally released in the 1980 and 1986 * spacetrack papers. a detailed discussion of the theory and history * may be found in the 2006 aiaa paper by vallado, crawford, hujsak, * and kelso. * * current : * 12 mar 20 david vallado * chg satnum to string for alpha 5 or 9-digit * changes : * 7 dec 15 david vallado * fix jd, jdfrac * 3 nov 14 david vallado * update to msvs2013 c++ * 30 Dec 11 david vallado * consolidate updated code version * 30 Aug 10 david vallado * delete unused variables in initl * replace pow inetger 2, 3 with multiplies for speed * 3 Nov 08 david vallado * put returns in for error codes * 29 sep 08 david vallado * fix atime for faster operation in dspace * add operationmode for afspc (a) or improved (i) * performance mode * 20 apr 07 david vallado * misc fixes for constants * 11 aug 06 david vallado * chg lyddane choice back to strn3, constants, misc doc * 15 dec 05 david vallado * misc fixes * 26 jul 05 david vallado * fixes for paper * note that each fix is preceded by a * comment with "sgp4fix" and an explanation of * what was changed * 10 aug 04 david vallado * 2nd printing baseline working * 14 may 01 david vallado * 2nd edition baseline * 80 norad * original baseline * ---------------------------------------------------------------- */ #pragma once #include #include #include #include #define SGP4Version "SGP4 Version 2020-07-13" // -------------------------- structure declarations ---------------------------- typedef enum { wgs72old, wgs72, wgs84 } gravconsttype; typedef struct elsetrec { char satnum[6]; int epochyr, epochtynumrev; int error; char operationmode; char init, method; /* Near Earth */ int isimp; double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 , delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof , t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof , nodecf; /* Deep Space */ int irez; double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 , d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt , dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco , plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 , si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 , xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 , xl4 , xlamo , zmol , zmos , atime , xli , xni; double a, altp, alta, epochdays, jdsatepoch, jdsatepochF, nddot, ndot, bstar, rcse, inclo, nodeo, ecco, argpo, mo, no_kozai; // sgp4fix add new variables from tle char classification, intldesg[11]; int ephtype; long elnum , revnum; // sgp4fix add unkozai'd variable double no_unkozai; // sgp4fix add singly averaged variables double am , em , im , Om , om , mm , nm; // sgp4fix add constant parameters to eliminate mutliple calls during execution double tumin, mus, radiusearthkm, xke, j2, j3, j4, j3oj2; // Additional elements to capture relevant TLE and object information: long dia_mm; // RSO dia in mm double period_sec; // Period in seconds unsigned char active; // "Active S/C" flag (0=n, 1=y) unsigned char not_orbital; // "Orbiting S/C" flag (0=n, 1=y) double rcs_m2; // "RCS (m^2)" storage } elsetrec; namespace SGP4Funcs { // public class SGP4Class // { bool sgp4init ( gravconsttype whichconst, char opsmode, const char satn[9], const double epoch, const double xbstar, const double xndot, const double xnddot, const double xecco, const double xargpo, const double xinclo, const double xmo, const double xno, const double xnodeo, elsetrec& satrec ); bool sgp4 ( // no longer need gravconsttype whichconst, all data contained in satrec elsetrec& satrec, double tsince, double r[3], double v[3] ); void getgravconst ( gravconsttype whichconst, double& tumin, double& mus, double& radiusearthkm, double& xke, double& j2, double& j3, double& j4, double& j3oj2 ); // older sgp4io methods void twoline2rv ( char longstr1[130], char longstr2[130], char typerun, char typeinput, char opsmode, gravconsttype whichconst, double& startmfe, double& stopmfe, double& deltamin, elsetrec& satrec ); // older sgp4ext methods double gstime_SGP4 ( double jdut1 ); double sgn_SGP4 ( double x ); double mag_SGP4 ( double x[3] ); void cross_SGP4 ( double vec1[3], double vec2[3], double outvec[3] ); double dot_SGP4 ( double x[3], double y[3] ); double angle_SGP4 ( double vec1[3], double vec2[3] ); void newtonnu_SGP4 ( double ecc, double nu, double& e0, double& m ); double asinh_SGP4 ( double xval ); void rv2coe_SGP4 ( double r[3], double v[3], double mus, double& p, double& a, double& ecc, double& incl, double& omega, double& argp, double& nu, double& m, double& arglat, double& truelon, double& lonper ); void jday_SGP4 ( int year, int mon, int day, int hr, int minute, double sec, double& jd, double& jdFrac ); void days2mdhms_SGP4 ( int year, double days, int& mon, int& day, int& hr, int& minute, double& sec ); void invjday_SGP4 ( double jd, double jdFrac, int& year, int& mon, int& day, int& hr, int& minute, double& sec ); } // namespace #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/extension/wrapper.cpp0000644000175100001730000005332514422467341016134 0ustar00runnerdocker#define PY_SSIZE_T_CLEAN #include #include "SGP4.h" #include "structmember.h" /* Whether scanf() prefers commas as the decimal point: true means that we cannot count on the current locale to interpret numbers correctly when the Vallado C++ code calls `sscanf()`. */ static bool switch_locale; /* Satrec object that wraps a single raw SGP4 struct, and a Satrec array that can broadcast into NumPy arrays. */ typedef struct { PyObject_HEAD elsetrec satrec; } SatrecObject; typedef struct { PyObject_VAR_HEAD elsetrec satrec[0]; } SatrecArrayObject; /* Support routine that is used to support NumPy array broadcasting for both individual satellite objects and also arrays. */ static PyObject * _vectorized_sgp4(PyObject *args, elsetrec *raw_satrec_array, int imax) { PyObject *jd_arg, *fr_arg, *e_arg, *r_arg, *v_arg; Py_buffer jd_buf, fr_buf, e_buf, r_buf, v_buf; PyObject *rv = NULL; // To prepare for "cleanup:" below. jd_buf.buf = fr_buf.buf = e_buf.buf = r_buf.buf = v_buf.buf = NULL; if (!PyArg_ParseTuple(args, "OOOOO:sgp4", &jd_arg, &fr_arg, &e_arg, &r_arg, &v_arg)) return NULL; if (PyObject_GetBuffer(jd_arg, &jd_buf, PyBUF_SIMPLE)) goto cleanup; if (PyObject_GetBuffer(fr_arg, &fr_buf, PyBUF_SIMPLE)) goto cleanup; if (PyObject_GetBuffer(e_arg, &e_buf, PyBUF_WRITABLE)) goto cleanup; if (PyObject_GetBuffer(r_arg, &r_buf, PyBUF_WRITABLE)) goto cleanup; if (PyObject_GetBuffer(v_arg, &v_buf, PyBUF_WRITABLE)) goto cleanup; if (jd_buf.len != fr_buf.len) { PyErr_SetString(PyExc_ValueError, "jd and fr must have the same shape"); goto cleanup; } // This extra block allows the "goto" statements above to jump // across these further variable declarations. { Py_ssize_t jmax = jd_buf.len / sizeof(double); if ((r_buf.len != (Py_ssize_t) sizeof(double) * imax * jmax * 3) || (v_buf.len != (Py_ssize_t) sizeof(double) * imax * jmax * 3) || (e_buf.len != (Py_ssize_t) sizeof(uint8_t) * imax * jmax)) { PyErr_SetString(PyExc_ValueError, "bad output array dimension"); goto cleanup; } double *jd = (double*) jd_buf.buf; double *fr = (double*) fr_buf.buf; double *r = (double*) r_buf.buf; double *v = (double*) v_buf.buf; uint8_t *e = (uint8_t*) e_buf.buf; #pragma omp parallel for for (Py_ssize_t i=0; i < imax; i++) { elsetrec &satrec = raw_satrec_array[i]; for (Py_ssize_t j=0; j < jmax; j++) { double t = (jd[j] - satrec.jdsatepoch) * 1440.0 + (fr[j] - satrec.jdsatepochF) * 1440.0; Py_ssize_t k1 = i * jmax + j; Py_ssize_t k3 = 3 * k1; SGP4Funcs::sgp4(satrec, t, r + k3, v + k3); e[k1] = (uint8_t) satrec.error; if (satrec.error && satrec.error < 6) { r[k3] = r[k3+1] = r[k3+2] = v[k3] = v[k3+1] = v[k3+2] = NAN; } } } } Py_INCREF(Py_None); rv = Py_None; cleanup: if (jd_buf.buf) PyBuffer_Release(&jd_buf); if (fr_buf.buf) PyBuffer_Release(&fr_buf); if (r_buf.buf) PyBuffer_Release(&r_buf); if (v_buf.buf) PyBuffer_Release(&v_buf); if (e_buf.buf) PyBuffer_Release(&e_buf); return rv; } /* Details of the "Satrec" satellite object. */ static PyObject * Satrec_twoline2rv(PyTypeObject *cls, PyObject *args) { char *string1, *string2, line1[130], line2[130]; gravconsttype whichconst = wgs72; double dummy; if (!PyArg_ParseTuple(args, "ss|i:twoline2rv", &string1, &string2, &whichconst)) return NULL; // Copy both lines, since twoline2rv() might write to both buffers. strncpy(line1, string1, 130); strncpy(line2, string2, 130); // Truncate the line before any checksum characters, if present; // otherwise the C++ scanf() interprets each checksum character as // part of the preceding value. line1[68] = '\0'; line2[68] = '\0'; /* Allocate the new object. */ SatrecObject *self = (SatrecObject*) cls->tp_alloc(cls, 0); if (!self) return NULL; /* Correct for locales that use a comma as the decimal point, since users report that the scanf() function on macOS is sensitive to locale when parsing floats. This operation is not thread-safe, but we have not released the GIL. */ float f; sscanf("1,5", "%f", &f); switch_locale = (f == 1.5); char *old_locale = NULL; if (switch_locale) old_locale = setlocale(LC_NUMERIC, "C"); /* Leading spaces in a catalog number make scanf() in the official code consume the Classification letter as part of the catalog number. (The first character of the International Designator then gets consumed as the Classification instead.) But no parsing error is reported, which is bad for users, so let's avoid the situation by adding leading zeros ourselves. */ for (int i=2; i<7; i++) { if (line1[i] == ' ') line1[i] = '0'; if (line2[i] == ' ') line2[i] = '0'; } /* Call the official routine. */ SGP4Funcs::twoline2rv(line1, line2, ' ', ' ', 'i', whichconst, dummy, dummy, dummy, self->satrec); /* Usability bonus: round the fractional day to exactly the eight digits specified in the TLE. */ self->satrec.jdsatepochF = round(self->satrec.jdsatepochF * 1e8) / 1e8; /* To avoid having scanf() interpret the "intldesg" as zero or as several fields, the C++ library changes spaces to periods and underscores. Let's convert them back to avoid surprising users and to match our Python implementation. */ if (self->satrec.intldesg[0] == '.') self->satrec.intldesg[0] = ' '; for (int i=1; i<11; i++) if (self->satrec.intldesg[i] == '_') self->satrec.intldesg[i] = ' '; /* Restore previous locale. */ if (switch_locale) setlocale(LC_NUMERIC, old_locale); return (PyObject*) self; } static PyObject * Satrec_sgp4init(PyObject *self, PyObject *args) { char satnum_str[6]; int whichconst; /* "int" rather than "gravconsttype" so we know size */ int opsmode; /* "int" rather than "char" because "C" needs an int */ long int satnum; double epoch, bstar, ndot, nddot; double ecco, argpo, inclo, mo, no_kozai, nodeo; if (!PyArg_ParseTuple(args, "iCldddddddddd:sgp4init", &whichconst, &opsmode, &satnum, &epoch, &bstar, &ndot, &nddot, &ecco, &argpo, &inclo, &mo, &no_kozai, &nodeo)) return NULL; // See https://www.space-track.org/documentation#tle-alpha5 if (satnum < 100000) { snprintf(satnum_str, 6, "%05ld", satnum); } else if (satnum > 339999) { PyErr_SetString(PyExc_ValueError, "satellite number cannot exceed " "339999, whose Alpha 5 encoding is 'Z9999'"); return 0; } else { char c = 'A' + satnum / 10000 - 10; if (c > 'I') c++; if (c > 'O') c++; satnum_str[0] = c; snprintf(satnum_str + 1, 5, "%04ld", satnum % 10000); } elsetrec &satrec = ((SatrecObject*) self)->satrec; SGP4Funcs::sgp4init((gravconsttype) whichconst, opsmode, satnum_str, epoch, bstar, ndot, nddot, ecco, argpo, inclo, mo, no_kozai, nodeo, satrec); /* Populate date fields that SGP4Funcs::twoline2rv would set. */ double whole; double fraction = modf(epoch, &whole); double whole_jd = whole + 2433281.5; /* Go out on a limb: if `epoch` has no decimal digits past the 8 decimal places stored in a TLE, then assume the user is trying to specify an exact decimal fraction. */ double epoch8 = epoch * 1e8; if (round(epoch8) == epoch8) { fraction = round(fraction * 1e8) / 1e8; } satrec.jdsatepoch = whole_jd; satrec.jdsatepochF = fraction; int y, m, d, H, M; double S, jan0jd, jan0fr /* always comes out 0.0 */; SGP4Funcs::invjday_SGP4(2433281.5, whole, y, m, d, H, M, S); SGP4Funcs::jday_SGP4(y, 1, 0, 0, 0, 0.0, jan0jd, jan0fr); satrec.epochyr = y % 100; satrec.epochdays = whole_jd - jan0jd + fraction; satrec.classification = 'U'; /* default to Unclassified, not '\0' */ /* Return true, like sgp4init does; check satrec.error for an error code */ Py_INCREF(Py_None); return Py_None; } static PyObject * Satrec_sgp4_tsince(PyObject *self, PyObject *args) { double tsince, r[3], v[3]; if (!PyArg_ParseTuple(args, "d:sgp4_tsince", &tsince)) return NULL; elsetrec &satrec = ((SatrecObject*) self)->satrec; SGP4Funcs::sgp4(satrec, tsince, r, v); if (satrec.error && satrec.error < 6) r[0] = r[1] = r[2] = v[0] = v[1] = v[2] = NAN; return Py_BuildValue("i(fff)(fff)", satrec.error, r[0], r[1], r[2], v[0], v[1], v[2]); } static PyObject * Satrec_sgp4(PyObject *self, PyObject *args) { double jd, fr, r[3], v[3]; if (!PyArg_ParseTuple(args, "dd:sgp4", &jd, &fr)) return NULL; elsetrec &satrec = ((SatrecObject*) self)->satrec; double tsince = (jd - satrec.jdsatepoch) * 1440.0 + (fr - satrec.jdsatepochF) * 1440.0; SGP4Funcs::sgp4(satrec, tsince, r, v); if (satrec.error && satrec.error < 6) r[0] = r[1] = r[2] = v[0] = v[1] = v[2] = NAN; return Py_BuildValue("i(fff)(fff)", satrec.error, r[0], r[1], r[2], v[0], v[1], v[2]); } static PyObject * Satrec__sgp4(PyObject *self, PyObject *args) { SatrecObject *obj = (SatrecObject*) self; elsetrec *raw_satrec_array = &(obj->satrec); Py_ssize_t imax = 1; return _vectorized_sgp4(args, raw_satrec_array, imax); } static PyMethodDef Satrec_methods[] = { {"twoline2rv", (PyCFunction)Satrec_twoline2rv, METH_VARARGS | METH_CLASS, PyDoc_STR("Initialize the record from two lines of TLE text and an optional gravity constant.")}, {"sgp4init", (PyCFunction)Satrec_sgp4init, METH_VARARGS, PyDoc_STR("Initialize the record from orbital elements.")}, {"sgp4", (PyCFunction)Satrec_sgp4, METH_VARARGS, PyDoc_STR("Given a modified julian date, return position and velocity.")}, {"_sgp4", (PyCFunction)Satrec__sgp4, METH_VARARGS, PyDoc_STR("Given an array of modified julian dates, return position and velocity arrays.")}, {"sgp4_tsince", (PyCFunction)Satrec_sgp4_tsince, METH_VARARGS, PyDoc_STR("Given minutes since epoch, return position and velocity.")}, {NULL, NULL} }; #define O(member) offsetof(SatrecObject, satrec.member) static PyMemberDef Satrec_members[] = { /* Listed in the order they appear in a TLE record. */ {"operationmode", T_CHAR, O(operationmode), READONLY, PyDoc_STR("Operation mode: 'a' legacy AFSPC, or 'i' improved.")}, {"jdsatepoch", T_DOUBLE, O(jdsatepoch), 0, PyDoc_STR("Julian date of epoch, day number (see jdsatepochF).")}, {"jdsatepochF", T_DOUBLE, O(jdsatepochF), 0, PyDoc_STR("Julian date of epoch, fraction of day (see jdsatepoch).")}, {"classification", T_CHAR, O(classification), 0, "Usually U=Unclassified, C=Classified, or S=Secret."}, /* intldesg: inline character array; see Satrec_getset. */ {"epochyr", T_INT, O(epochyr), 0, PyDoc_STR("Year of this element set's epoch (see epochdays). Not set by sgp4init().")}, {"epochdays", T_DOUBLE, O(epochdays), 0, PyDoc_STR("Day of the year of this element set's epoch (see epochyr). Not set by sgp4init().")}, {"ndot", T_DOUBLE, O(ndot), READONLY, PyDoc_STR("Ballistic Coefficient in radians/minute^2.")}, {"nddot", T_DOUBLE, O(nddot), READONLY, PyDoc_STR("Second Derivative of Mean Motion in radians/minute^3.")}, {"bstar", T_DOUBLE, O(bstar), READONLY, PyDoc_STR("Drag Term in inverse Earth radii.")}, {"ephtype", T_INT, O(ephtype), 0, PyDoc_STR("Ephemeris type (should be 0 in published TLEs).")}, {"elnum", T_LONG, O(elnum), 0, PyDoc_STR("Element set number.")}, {"inclo", T_DOUBLE, O(inclo), READONLY, PyDoc_STR("Inclination in radians.")}, {"nodeo", T_DOUBLE, O(nodeo), READONLY, PyDoc_STR("Right ascension of ascending node in radians.")}, {"ecco", T_DOUBLE, O(ecco), READONLY, PyDoc_STR("Eccentricity.")}, {"argpo", T_DOUBLE, O(argpo), READONLY, PyDoc_STR("Argument of perigee in radians.")}, {"mo", T_DOUBLE, O(mo), READONLY, PyDoc_STR("Mean anomaly in radians.")}, {"no_kozai", T_DOUBLE, O(no_kozai), READONLY, PyDoc_STR("Mean motion in radians per minute.")}, {"revnum", T_LONG, O(revnum), 0, PyDoc_STR("Integer revolution number at the epoch.")}, /* For compatibility with the old struct members, also accept the plain name "no". */ {"no", T_DOUBLE, O(no_kozai), READONLY, PyDoc_STR("Alias for the more carefully named ``no_kozai``.")}, /* Derived values that do not appear explicitly in the TLE. */ {"method", T_CHAR, O(method), READONLY, PyDoc_STR("Method, either 'n' near earth or 'd' deep space.")}, {"error", T_INT, O(error), READONLY, PyDoc_STR("Error code (1-6) documented in sgp4()")}, {"a", T_DOUBLE, O(a), READONLY, PyDoc_STR("semi-major axis")}, {"altp", T_DOUBLE, O(altp), READONLY, PyDoc_STR("altitude of perigee")}, {"alta", T_DOUBLE, O(alta), READONLY, PyDoc_STR("altitude of perigee")}, /* Single averaged mean elements */ {"am", T_DOUBLE, O(am), READONLY, PyDoc_STR("am: Average semi-major axis")}, {"em", T_DOUBLE, O(em), READONLY, PyDoc_STR("em: Average eccentricity")}, {"im", T_DOUBLE, O(im), READONLY, PyDoc_STR("im: Average inclination")}, {"Om", T_DOUBLE, O(Om), READONLY, PyDoc_STR("Om: Average right ascension of ascending node")}, {"om", T_DOUBLE, O(om), READONLY, PyDoc_STR("om: Average argument of perigee")}, {"mm", T_DOUBLE, O(mm), READONLY, PyDoc_STR("mm: Average mean anomaly")}, {"nm", T_DOUBLE, O(nm), READONLY, PyDoc_STR("nm: Average mean motion")}, /* Gravity-constant dependent values (initialized by sgp4init() */ {"tumin", T_DOUBLE, O(tumin), READONLY, PyDoc_STR("minutes in one time unit")}, {"mu", T_DOUBLE, O(mus), READONLY, PyDoc_STR("Earth gravitational parameter")}, {"radiusearthkm", T_DOUBLE, O(radiusearthkm), READONLY, PyDoc_STR("radius of the earth in km")}, {"xke", T_DOUBLE, O(xke), READONLY, PyDoc_STR("reciprocal of tumin")}, {"j2", T_DOUBLE, O(j2), READONLY, PyDoc_STR("un-normalized zonal harmonic j2 value")}, {"j3", T_DOUBLE, O(j3), READONLY, PyDoc_STR("un-normalized zonal harmonic j3 value")}, {"j4", T_DOUBLE, O(j4), READONLY, PyDoc_STR("un-normalized zonal harmonic j4 value")}, {"j3oj2", T_DOUBLE, O(j3oj2), READONLY, PyDoc_STR("j3 divided by j2")}, /* Other convenience variables (some required by propagation.py) */ {"t", T_DOUBLE, O(t), READONLY, PyDoc_STR("Last tsince input to sgp4()")}, {"mdot", T_DOUBLE, O(mdot), READONLY, PyDoc_STR("mean anomaly dot (rate)")}, {"argpdot", T_DOUBLE, O(argpdot), READONLY, PyDoc_STR("argument of perigee dot (rate)")}, {"nodedot", T_DOUBLE, O(nodedot), READONLY, PyDoc_STR("right ascension of ascending node dot (rate)")}, {"gsto", T_DOUBLE, O(gsto), READONLY, PyDoc_STR("gsto: greenwich sidereal time")}, {NULL} }; #undef O static PyObject * get_intldesg(SatrecObject *self, void *closure) { int length = 0; char *s = self->satrec.intldesg; while (length <= 7 && s[length]) length++; while (length && s[length-1] == ' ') length--; return PyUnicode_FromStringAndSize(s, length); } static int set_intldesg(SatrecObject *self, PyObject *value, void *closure) { const char *s = PyUnicode_AsUTF8(value); if (!s) return -1; strncpy(self->satrec.intldesg, s, 10); self->satrec.intldesg[10] = '\0'; return 0; } /* The official TLE code has switched `satnum` to a string, but to avoid a breaking change we make the string available as `satnum_str` and still return an integer for `satnum`. */ static PyObject * get_satnum(SatrecObject *self, void *closure) { char *s = self->satrec.satnum; long n; if (strlen(s) < 5 || s[0] <= '9') n = atol(s); else if (s[0] <= 'I') n = (s[0] - 'A' + 10) * 10000 + atol(s + 1); else if (s[0] <= 'O') n = (s[0] - 'A' + 9) * 10000 + atol(s + 1); else n = (s[0] - 'A' + 8) * 10000 + atol(s + 1); return PyLong_FromLong(n); } static PyObject * get_satnum_str(SatrecObject *self, void *closure) { return PyUnicode_FromString(self->satrec.satnum); } static int set_satnum_str(SatrecObject *self, PyObject *value, void *closure) { const char *s = PyUnicode_AsUTF8(value); if (!s) return -1; strncpy(self->satrec.satnum, s, 5); self->satrec.satnum[5] = '\0'; return 0; } static PyGetSetDef Satrec_getset[] = { {"intldesg", (getter)get_intldesg, (setter)set_intldesg, PyDoc_STR("International Designator: a string of up to 7 characters" " from the first line of the TLE that typically provides" " two digits for the launch year, a 3-digit launch number," " and one or two letters for which piece of the launch.")}, {"satnum", (getter)get_satnum, NULL, PyDoc_STR("Satellite number from characters 3-7 of each TLE line," " as an integer.")}, {"satnum_str", (getter)get_satnum_str, (setter)set_satnum_str, PyDoc_STR("Satellite number from characters 3-7 of each TLE line," " as a string.")}, {NULL}, }; static PyTypeObject SatrecType = { PyVarObject_HEAD_INIT(NULL, 0) /* See the module initialization function at the bottom of this file. */ }; /* Details of the SatrecArray. */ static Py_ssize_t Satrec_len(PyObject *self) { return ((SatrecArrayObject*)self)->ob_base.ob_size; } static PySequenceMethods SatrecArray_as_sequence = { Satrec_len }; static PyObject * SatrecArray_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *sequence; if (!PyArg_ParseTuple(args, "O:SatrecArray", &sequence)) return NULL; Py_ssize_t length = PySequence_Length(sequence); if (length == -1) return NULL; return type->tp_alloc(type, length); } static int SatrecArray_init(SatrecArrayObject *self, PyObject *args, PyObject *kwds) { PyObject *sequence; if (!PyArg_ParseTuple(args, "O:SatrecArray", &sequence)) return -1; Py_ssize_t length = PySequence_Length(sequence); if (length == -1) return -1; for (Py_ssize_t i=0; isatrec[i] = ((SatrecObject *)item)->satrec; Py_DECREF(item); } return 0; } static PyObject * SatrecArray_sgp4(PyObject *self, PyObject *args) { SatrecArrayObject *satrec_array = (SatrecArrayObject*) self; elsetrec *raw_satrec_array = &(satrec_array->satrec[0]); Py_ssize_t imax = satrec_array->ob_base.ob_size; return _vectorized_sgp4(args, raw_satrec_array, imax); } static PyMethodDef SatrecArray_methods[] = { {"_sgp4", (PyCFunction)SatrecArray_sgp4, METH_VARARGS, PyDoc_STR("Given array of minutes since epoch, write" " positions, velocities, and errors to arrays.")}, {NULL, NULL} }; static PyTypeObject SatrecArrayType = { PyVarObject_HEAD_INIT(NULL, sizeof(elsetrec)) /* See the module initialization function at the bottom of this file. */ }; /* The module that ties it all together. */ static PyModuleDef module = { PyModuleDef_HEAD_INIT, "sgp4.vallado_cpp", "Official C++ SGP4 implementation.", -1 }; #include PyMODINIT_FUNC PyInit_vallado_cpp(void) { SatrecType.tp_name = "sgp4.vallado_cpp.Satrec"; SatrecType.tp_basicsize = sizeof(SatrecObject); SatrecArrayType.tp_itemsize = 0; SatrecType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; SatrecType.tp_doc = "SGP4 satellite record."; SatrecType.tp_methods = Satrec_methods; SatrecType.tp_members = Satrec_members; SatrecType.tp_getset = Satrec_getset; SatrecType.tp_new = PyType_GenericNew; if (PyType_Ready(&SatrecType) < 0) return NULL; SatrecArrayType.tp_name = "sgp4.vallado_cpp.SatrecArray"; SatrecArrayType.tp_basicsize = sizeof(SatrecArrayObject); SatrecArrayType.tp_itemsize = sizeof(elsetrec); SatrecArrayType.tp_as_sequence = &SatrecArray_as_sequence; SatrecArrayType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; SatrecArrayType.tp_doc = "SGP4 array of satellites."; SatrecArrayType.tp_methods = SatrecArray_methods; SatrecArrayType.tp_init = (initproc) SatrecArray_init; SatrecArrayType.tp_new = SatrecArray_new; if (PyType_Ready(&SatrecArrayType) < 0) return NULL; PyObject *m = PyModule_Create(&module); if (m == NULL) return NULL; Py_INCREF(&SatrecType); if (PyModule_AddObject(m, "Satrec", (PyObject *) &SatrecType) < 0) { Py_DECREF(&SatrecType); Py_DECREF(m); return NULL; } Py_INCREF(&SatrecArrayType); if (PyModule_AddObject(m, "SatrecArray", (PyObject *) &SatrecArrayType) < 0) { Py_DECREF(&SatrecArrayType); Py_DECREF(&SatrecType); Py_DECREF(m); return NULL; } if (PyModule_AddIntConstant(m, "WGS72", (int)wgs72) || PyModule_AddIntConstant(m, "WGS72OLD", (int)wgs72old) || PyModule_AddIntConstant(m, "WGS84", (int)wgs84)) return NULL; return m; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1682599655.3394356 sgp4-2.22/setup.cfg0000644000175100001730000000004614422467347013553 0ustar00runnerdocker[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/setup.py0000644000175100001730000000471214422467341013442 0ustar00runnerdockerimport os import sys from distutils.core import setup, Extension import sgp4 description, long_description = sgp4.__doc__.split('\n', 1) # Force compilation on Travis CI + Python 3 to make sure it keeps working. optional = True if sys.version_info[0] != 2 and os.environ.get('TRAVIS') == 'true': optional = False # It is hard to write C extensions that support both Python 2 and 3, so # we opt here to support the acceleration only for Python 3. ext_modules = [] if sys.version_info[0] == 3: ext_modules.append(Extension( 'sgp4.vallado_cpp', optional=optional, sources=[ 'extension/SGP4.cpp', 'extension/wrapper.cpp', ], # TODO: can we safely figure out how to use a pair of options # like these, adapted to as many platforms as possible, to use # multiple processors when available? # extra_compile_args=['-fopenmp'], # extra_link_args=['-fopenmp'], extra_compile_args=['-ffloat-store'], )) # Read the package's "__version__" without importing it. path = 'sgp4/__init__.py' with open(path, 'rb') as f: text = f.read().decode('utf-8') text = text.replace('-*- coding: utf-8 -*-', '') # for Python 2.7 namespace = {} eval(compile(text, path, 'exec'), namespace) setup(name = 'sgp4', version = namespace['__version__'], description = description, long_description = long_description, license = 'MIT', author = 'Brandon Rhodes', author_email = 'brandon@rhodesmill.org', url = 'https://github.com/brandon-rhodes/python-sgp4', classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Topic :: Scientific/Engineering :: Astronomy', ], packages = ['sgp4'], package_data = {'sgp4': ['SGP4-VER.TLE', 'sample*', 'tcppver.out']}, ext_modules = ext_modules, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1682599655.3394356 sgp4-2.22/sgp4/0000755000175100001730000000000014422467347012607 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/SGP4-VER.TLE0000644000175100001730000002065014422467341014321 0ustar00runnerdocker# ------------------ Verification test cases ---------------------- # # TEME example 1 00005U 58002B 00179.78495062 .00000023 00000-0 28098-4 0 4753 2 00005 34.2682 348.7242 1859667 331.7664 19.3264 10.82419157413667 0.00 4320.0 360.00 # ## fig show lyddane fix error with gsfc ver 1 04632U 70093B 04031.91070959 -.00000084 00000-0 10000-3 0 9955 2 04632 11.4628 273.1101 1450506 207.6000 143.9350 1.20231981 44145 -5184.0 -4896.0 120.00 # DELTA 1 DEB # near earth normal drag equation # # perigee = 377.26km, so moderate drag case 1 06251U 62025E 06176.82412014 .00008885 00000-0 12808-3 0 3985 2 06251 58.0579 54.0425 0030035 139.1568 221.1854 15.56387291 6774 0.0 2880.0 120.00 # MOLNIYA 2-14 # 12h resonant ecc in 0.65 to 0.7 range 1 08195U 75081A 06176.33215444 .00000099 00000-0 11873-3 0 813 2 08195 64.1586 279.0717 6877146 264.7651 20.2257 2.00491383225656 0.0 2880.0 120.00 # MOLNIYA 1-36 ## fig 12h resonant ecc in 0.7 to 0.715 range 1 09880U 77021A 06176.56157475 .00000421 00000-0 10000-3 0 9814 2 09880 64.5968 349.3786 7069051 270.0229 16.3320 2.00813614112380 0.0 2880.0 120.00 # SMS 1 AKM # show the integrator problem with gsfc ver 1 09998U 74033F 05148.79417928 -.00000112 00000-0 00000+0 0 4480 2 09998 9.4958 313.1750 0270971 327.5225 30.8097 1.16186785 45878 -1440.0 -720.00 60.0 # # Original STR#3 SDP4 test 1 11801U 80230.29629788 .01431103 00000-0 14311-1 13 2 11801 46.7916 230.4354 7318036 47.4722 10.4117 2.28537848 13 0.0 1440.0 360.00 # EUTELSAT 1-F1 (ECS1)## fig lyddane choice in GSFC at 2080 min 1 14128U 83058A 06176.02844893 -.00000158 00000-0 10000-3 0 9627 2 14128 11.4384 35.2134 0011562 26.4582 333.5652 0.98870114 46093 0.0 2880.0 120.00 # SL-6 R/B(2) # Deep space, perigee = 82.48 (<98) for # # s4 > 20 mod 1 16925U 86065D 06151.67415771 .02550794 -30915-6 18784-3 0 4486 2 16925 62.0906 295.0239 5596327 245.1593 47.9690 4.88511875148616 0.0 1440.0 120.00 # SL-12 R/B # Shows Lyddane choice at 1860 and 4700 min 1 20413U 83020D 05363.79166667 .00000000 00000-0 00000+0 0 7041 2 20413 12.3514 187.4253 7864447 196.3027 356.5478 0.24690082 7978 1440.0 4320.0 120.00 # MOLNIYA 1-83 # 12h resonant, ecc > 0.715 (negative BSTAR) 1 21897U 92011A 06176.02341244 -.00001273 00000-0 -13525-3 0 3044 2 21897 62.1749 198.0096 7421690 253.0462 20.1561 2.01269994104880 0.0 2880.0 120.00 # SL-6 R/B(2) # last tle given, decayed 2006-04-04, day 94 1 22312U 93002D 06094.46235912 .99999999 81888-5 49949-3 0 3953 2 22312 62.1486 77.4698 0308723 267.9229 88.7392 15.95744531 98783 54.2028672 1440.0 20.00 # SL-6 R/B(2) # 12h resonant ecc in the > 0.715 range 1 22674U 93035D 06176.55909107 .00002121 00000-0 29868-3 0 6569 2 22674 63.5035 354.4452 7541712 253.3264 18.7754 1.96679808 93877 0.0 2880.0 120.00 # ARIANE 44L+ R/B # Lyddane bug at <= 70 min for atan2(), # # no quadrant fix 1 23177U 94040C 06175.45752052 .00000386 00000-0 76590-3 0 95 2 23177 7.0496 179.8238 7258491 296.0482 8.3061 2.25906668 97438 0.0 1440.0 120.00 # WIND # STR#3 Kepler failes past about 200 min 1 23333U 94071A 94305.49999999 -.00172956 26967-3 10000-3 0 15 2 23333 28.7490 2.3720 9728298 30.4360 1.3500 0.07309491 70 0.0 1600.0 120.00 # ARIANE 42P+3 R/B ## fig Lyddane bug at > 280.5 min for AcTan() 1 23599U 95029B 06171.76535463 .00085586 12891-6 12956-2 0 2905 2 23599 6.9327 0.2849 5782022 274.4436 25.2425 4.47796565123555 0.0 720.0 20.00 # ITALSAT 2 # 24h resonant GEO, inclination > 3 deg 1 24208U 96044A 06177.04061740 -.00000094 00000-0 10000-3 0 1600 2 24208 3.8536 80.0121 0026640 311.0977 48.3000 1.00778054 36119 0.0 1440.0 120.00 # AMC-4 ## fig low incl, show incl shift with # ## gsfc version from 240 to 1440 min 1 25954U 99060A 04039.68057285 -.00000108 00000-0 00000-0 0 6847 2 25954 0.0004 243.8136 0001765 15.5294 22.7134 1.00271289 15615 -1440.0 1440.0 120.00 # INTELSAT 902 # negative incl at 9313 min then # # 270 deg Lyddane bug at 37606 min 1 26900U 01039A 06106.74503247 .00000045 00000-0 10000-3 0 8290 2 26900 0.0164 266.5378 0003319 86.1794 182.2590 1.00273847 16981 9300.00 9400.00 60.00 # COSMOS 1024 DEB # 12h resonant ecc in 0.5 to 0.65 range 1 26975U 78066F 06174.85818871 .00000620 00000-0 10000-3 0 6809 2 26975 68.4714 236.1303 5602877 123.7484 302.5767 2.05657553 67521 0.0 2880.0 120.00 # CBERS 2 # Near Earth, ecc = 8.84E-5 (< 1.0e-4) # # drop certain normal drag terms 1 28057U 03049A 06177.78615833 .00000060 00000-0 35940-4 0 1836 2 28057 98.4283 247.6961 0000884 88.1964 271.9322 14.35478080140550 0.0 2880.0 120.00 # NAVSTAR 53 (USA 175)# 12h non-resonant GPS (ecc < 0.5 ecc) 1 28129U 03058A 06175.57071136 -.00000104 00000-0 10000-3 0 459 2 28129 54.7298 324.8098 0048506 266.2640 93.1663 2.00562768 18443 0.0 1440.0 120.00 # COSMOS 2405 # Near Earth, perigee = 127.20 (< 156) s4 mod 1 28350U 04020A 06167.21788666 .16154492 76267-5 18678-3 0 8894 2 28350 64.9977 345.6130 0024870 260.7578 99.9590 16.47856722116490 0.0 2880.0 120.00 # H-2 R/B # Deep space, perigee = 135.75 (<156) s4 mod 1 28623U 05006B 06177.81079184 .00637644 69054-6 96390-3 0 6000 2 28623 28.5200 114.9834 6249053 170.2550 212.8965 3.79477162 12753 0.0 1440.0 120.00 # XM-3 # 24h resonant geo, incl < 3 deg goes # # negative around 1130 min 1 28626U 05008A 06176.46683397 -.00000205 00000-0 10000-3 0 2190 2 28626 0.0019 286.9433 0000335 13.7918 55.6504 1.00270176 4891 0.0 1440.0 120.00 # MINOTAUR R/B # Sub-orbital case - Decayed 2005-11-29 # #(perigee = -51km), lost in 50 minutes 1 28872U 05037B 05333.02012661 .25992681 00000-0 24476-3 0 1534 2 28872 96.4736 157.9986 0303955 244.0492 110.6523 16.46015938 10708 0.0 60.0 5.00 # SL-14 DEB # Last stage of decay - lost in under 420 min 1 29141U 85108AA 06170.26783845 .99999999 00000-0 13519-0 0 718 2 29141 82.4288 273.4882 0015848 277.2124 83.9133 15.93343074 6828 0.0 440.0 20.00 # SL-12 DEB # Near Earth, perigee = 212.24 < 220 # # simplified drag eq 1 29238U 06022G 06177.28732010 .00766286 10823-4 13334-2 0 101 2 29238 51.5595 213.7903 0202579 95.2503 267.9010 15.73823839 1061 0.0 1440.0 120.00 # # Original STR#3 SGP4 test 1 88888U 80275.98708465 .00073094 13844-3 66816-4 0 87 2 88888 72.8435 115.9689 0086731 52.6988 110.5714 16.05824518 1058 0.0 1440.0 120.00 # # # check error code 4 1 33333U 05037B 05333.02012661 .25992681 00000-0 24476-3 0 1534 2 33333 96.4736 157.9986 9950000 244.0492 110.6523 4.00004038 10708 0.0 150.0 5.00 # # try and check error code 2 but this 1 33334U 78066F 06174.85818871 .00000620 00000-0 10000-3 0 6809 2 33334 68.4714 236.1303 5602877 123.7484 302.5767 0.00001000 67521 0.0 1440.0 1.00 # # try to check error code 3 looks like ep never goes below zero, tied close to ecc 1 33335U 05008A 06176.46683397 -.00000205 00000-0 10000-3 0 2190 2 33335 0.0019 286.9433 0000004 13.7918 55.6504 1.00270176 4891 0.0 1440.0 20.00 # SL-12 R/B # Shows Lyddane choice at 1860 and 4700 min 1 20413U 83020D 05363.79166667 .00000000 00000-0 00000+0 0 7041 2 20413 12.3514 187.4253 7864447 196.3027 356.5478 0.24690082 7978 1844000.0 1845100.0 5.00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/__init__.py0000644000175100001730000007254614422467341014730 0ustar00runnerdocker# -*- coding: utf-8 -*- """Track Earth satellites given TLE data, using up-to-date 2020 SGP4 routines. This package compiles the official C++ code from `Revisiting Spacetrack Report #3 `_ (AIAA 2006-6753) and uses it to compute the positions of satellites in Earth orbit. Orbital elements can be read from either a legacy TLE file or from a modern OMM element set, both of which you can fetch from a site like `CelesTrak `_. If your machine can’t install or compile the C++ code, then this package falls back to using a slower pure-Python implementation of SGP4. Tests make sure that its positions **agree to within 0.1 mm** with the standard version of the algorithm — an error far less than the 1–3 km/day by which satellites themselves deviate from the ideal orbits described in TLE files. An accelerated routine is available that, given a series of times and of satellites, computes a whole array of output positions using a fast C++ loop. See the “Array Acceleration” section below. Note that the SGP4 propagator returns raw *x,y,z* Cartesian coordinates in a “True Equator Mean Equinox” (TEME) reference frame that’s centered on the Earth but does not rotate with it — an “Earth centered inertial” (ECI) reference frame. The SGP4 propagator itself does not implement the math to convert these positions into more official ECI frames like J2000 or the ICRS, nor into any Earth-centered Earth-fixed (ECEF) frames like the ITRS, nor into latitudes and longitudes through an Earth ellipsoid like WGS84. For conversions into these other coordinate frames, look for a comprehensive astronomy library, like the `Skyfield `_ library that is built atop this one (see the `section on Earth satellites `_ in its documentation). Usage ----- You will probably first want to to check whether your machine has successfully installed the fast SGP4 C++ code, or is using the slow Python version (in which case this value will be false): >>> from sgp4.api import accelerated >>> print(accelerated) True This library uses the same function names as the official C++ code, to help users who are already familiar with SGP4 in other languages. Here is how to compute the x,y,z position and velocity for the International Space Station at 12:50:19 on 29 June 2000: >>> from sgp4.api import Satrec >>> >>> s = '1 25544U 98067A 19343.69339541 .00001764 00000-0 38792-4 0 9991' >>> t = '2 25544 51.6439 211.2001 0007417 17.6667 85.6398 15.50103472202482' >>> satellite = Satrec.twoline2rv(s, t) >>> >>> jd, fr = 2458827, 0.362605 >>> e, r, v = satellite.sgp4(jd, fr) >>> e 0 >>> print(r) # True Equator Mean Equinox position (km) (-6102.44..., -986.33..., -2820.31...) >>> print(v) # True Equator Mean Equinox velocity (km/s) (-1.45..., -5.52..., 5.10...) As input, you can provide either: * A simple floating-point Julian Date for ``jd`` and the value 0.0 for ``fr``, if you are happy with the precision of a 64-bit floating point number. Note that modern Julian Dates are greater than 2,450,000 which means that nearly half of the precision of a 64-bit float will be consumed by the whole part that specifies the day. The remaining digits will provide a precision for the fraction of around 20.1 µs. This should be no problem for the accuracy of your result — satellite positions usually off by a few kilometers anyway, far less than a satellite moves in 20.1 µs — but if you run a solver that dives down into the microseconds while searching for a rising or setting time, the solver might be bothered by the 20.1 µs plateau between each jump in the satellite’s position. * Or, you can provide a coarse date ``jd`` plus a very precise fraction ``fr`` that supplies the rest of the value. The Julian Date for which the satellite position is computed is the sum of the two values. One common practice is to provide the whole number as ``jd`` and the fraction as ``fr``; another is to have ``jd`` carry the fraction 0.5 since UTC midnight occurs halfway through each Julian Date. Either way, splitting the value allows a solver to run all the way down into the nanoseconds and still see SGP4 respond smoothly to tiny date adjustments with tiny changes in the resulting satellite position. Here is how to intrepret the results: * ``e`` will be a non-zero error code if the satellite position could not be computed for the given date. You can ``from sgp4.api import SGP4_ERRORS`` to access a dictionary mapping error codes to error messages explaining what each code means. * ``r`` measures the satellite position in **kilometers** from the center of the earth in the idiosyncratic True Equator Mean Equinox coordinate frame used by SGP4. * ``v`` velocity is the rate at which the position is changing, expressed in **kilometers per second**. If your application does not natively handle Julian dates, you can compute ``jd`` and ``fr`` from calendar dates using ``jday()``. >>> from sgp4.api import jday >>> jd, fr = jday(2019, 12, 9, 12, 0, 0) >>> jd 2458826.5 >>> fr 0.5 Double-checking your TLE lines ------------------------------ Because TLE is an old punch-card fixed-width format, it’s very sensitive to whether exactly the right number of spaces are positioned in exactly the right columns. If you suspect that your satellite elements aren’t getting loaded correctly, try calling the slow pure-Python version of ``twoline2rv()``, which performs extra checks that the fast C++ doesn’t: >>> from sgp4.earth_gravity import wgs72 >>> from sgp4.io import twoline2rv >>> assert twoline2rv(s, t, wgs72) Any TLE formatting errors will be raised as a ``ValueError``. Using OMM elements instead of TLE --------------------------------- The industry is migrating away from the original TLE format, because it will soon run out of satellite numbers. * Some TLE files now use a new “Alpha-5” convention that expands the range of satellite numbers by using an initial letter; for example, “E8493” means satellite 148493. This library supports the Alpha-5 convention and should return the correct integer in Python. * Some authorities are now distributing satellite elements in an “OMM” Orbit Mean Elements Message format that replaces the TLE format. You can learn about OMM in Dr. T.S. Kelso’s `“A New Way to Obtain GP Data” `_ at the CelesTrak site. You can already try out experimental support for OMM: >>> from sgp4 import omm Reading OMM data takes two steps, because OMM supports several different text formats. First, parse the input text to recover the field names and values that it stores; second, build a Python satellite object from those field values. For example, to load OMM from XML: >>> with open('sample_omm.xml') as f: ... fields = next(omm.parse_xml(f)) >>> sat = Satrec() >>> omm.initialize(sat, fields) Or, to load OMM from CSV: >>> with open('sample_omm.csv') as f: ... fields = next(omm.parse_csv(f)) >>> sat = Satrec() >>> omm.initialize(sat, fields) Either way, the satellite object should wind up properly initialized and ready to start producing positions. If you are interested in saving satellite parameters using the new OMM format, then read the section on “Export” below. Epoch ----- Over a given satellite’s lifetime, dozens or hundreds of different TLE records will be produced as its orbit evolves. Each TLE record specifies the “epoch date” for which it is most accurate. Typically a TLE is only useful for a couple of weeks to either side of its epoch date, beyond which its predictions become unreliable. Satellite objects natively provide their epoch as a two-digit year and then a fractional number of days into the year: >>> satellite.epochyr 19 >>> satellite.epochdays 343.69339541 Because Sputnik was launched in 1957, satellite element sets will never refer to an earlier year, so years 57 through 99 mean 1957–1999 while 0 through 56 mean 2000–2056. The TLE format will presumably be obsolete in 2057 and have to be upgraded to 4-digit years. To turn the number of days and its fraction into a calendar date and time, use the ``days2mdhms()`` function. >>> from sgp4.api import days2mdhms >>> month, day, hour, minute, second = days2mdhms(19, 343.69339541) >>> month 12 >>> day 9 >>> hour 16 >>> minute 38 >>> second 29.363424 The SGP4 library also translates those two numbers into a Julian date and fractional Julian date, since Julian dates are more commonly used in astronomy. >>> satellite.jdsatepoch 2458826.5 >>> satellite.jdsatepochF 0.69339541 Finally, a convenience function is available in the library if you need the epoch date and time as Python ``datetime``. >>> from sgp4.conveniences import sat_epoch_datetime >>> sat_epoch_datetime(satellite) datetime.datetime(2019, 12, 9, 16, 38, 29, 363423, tzinfo=UTC) Array Acceleration ------------------ To avoid the expense of running a Python loop when you have many dates and times for which you want a position, you can pass your Julian dates as arrays. The array routine is only faster if your machine has successfully installed or compiled the SGP4 C++ code, so you might want to check first: >>> from sgp4.api import accelerated >>> print(accelerated) True To call the array routine, make NumPy arrays for ``jd`` and ``fr`` that are the same length: >>> import numpy as np >>> np.set_printoptions(precision=2) >>> jd = np.array((2458826, 2458826, 2458826, 2458826)) >>> fr = np.array((0.0001, 0.0002, 0.0003, 0.0004)) >>> e, r, v = satellite.sgp4_array(jd, fr) >>> print(e) [0 0 0 0] >>> print(r) [[-3431.31 2620.15 -5252.97] [-3478.86 2575.14 -5243.87] [-3526.09 2529.89 -5234.28] [-3572.98 2484.41 -5224.19]] >>> print(v) [[-5.52 -5.19 1.02] [-5.49 -5.22 1.08] [-5.45 -5.25 1.14] [-5.41 -5.28 1.2 ]] To avoid the expense of Python loops when you have many satellites and dates, build a ``SatrecArray`` from several individual satellites. Its ``sgp4()`` method will expect both ``jd`` and ``fr`` to be NumPy arrays, so if you only have one date, be sure to provide NumPy arrays of length one. Here is a sample computation for 2 satellites and 4 dates: >>> u = '1 20580U 90037B 19342.88042116 .00000361 00000-0 11007-4 0 9996' >>> w = '2 20580 28.4682 146.6676 0002639 185.9222 322.7238 15.09309432427086' >>> satellite2 = Satrec.twoline2rv(u, w) >>> from sgp4.api import SatrecArray >>> a = SatrecArray([satellite, satellite2]) >>> e, r, v = a.sgp4(jd, fr) >>> np.set_printoptions(precision=2) >>> print(e) [[0 0 0 0] [0 0 0 0]] >>> print(r) [[[-3431.31 2620.15 -5252.97] [-3478.86 2575.14 -5243.87] [-3526.09 2529.89 -5234.28] [-3572.98 2484.41 -5224.19]] [[ 5781.85 2564. -2798.22] [ 5749.36 2618.59 -2814.63] [ 5716.35 2672.94 -2830.78] [ 5682.83 2727.05 -2846.68]]] >>> print(v) [[[-5.52 -5.19 1.02] [-5.49 -5.22 1.08] [-5.45 -5.25 1.14] [-5.41 -5.28 1.2 ]] [[-3.73 6.33 -1.91] [-3.79 6.3 -1.88] [-3.85 6.28 -1.85] [-3.91 6.25 -1.83]]] Export ------ If you have a ``Satrec`` you want to share with friends or persist to a file, there’s an export routine that will turn it back into a TLE: >>> from sgp4 import exporter >>> line1, line2 = exporter.export_tle(satellite) >>> line1 '1 25544U 98067A 19343.69339541 .00001764 00000-0 38792-4 0 9991' >>> line2 '2 25544 51.6439 211.2001 0007417 17.6667 85.6398 15.50103472202482' Happily, these are exactly the two TLE lines that we used to create this satellite object: >>> (s == line1) and (t == line2) True Another export routine is available that produces the fields defined by the new OMM format (see the “OMM” section above): >>> from pprint import pprint >>> fields = exporter.export_omm(satellite, 'ISS (ZARYA)') >>> pprint(fields) {'ARG_OF_PERICENTER': 17.6667, 'BSTAR': 3.8792e-05, 'CENTER_NAME': 'EARTH', 'CLASSIFICATION_TYPE': 'U', 'ECCENTRICITY': 0.0007417, 'ELEMENT_SET_NO': 999, 'EPHEMERIS_TYPE': 0, 'EPOCH': '2019-12-09T16:38:29.363423', 'INCLINATION': 51.6439, 'MEAN_ANOMALY': 85.6398, 'MEAN_ELEMENT_THEORY': 'SGP4', 'MEAN_MOTION': 15.501034720000002, 'MEAN_MOTION_DDOT': 0.0, 'MEAN_MOTION_DOT': 1.764e-05, 'NORAD_CAT_ID': 25544, 'OBJECT_ID': '1998-067A', 'OBJECT_NAME': 'ISS (ZARYA)', 'RA_OF_ASC_NODE': 211.2001, 'REF_FRAME': 'TEME', 'REV_AT_EPOCH': 20248, 'TIME_SYSTEM': 'UTC'} Gravity ------- The SGP4 algorithm operates atop a set of constants specifying how strong the Earth’s gravity is. The most recent official paper on SGP4 (see below) specifies that “We use WGS-72 as the default value”, so this Python module uses the same default. But in case you want to use either the old legacy version of the WGS-72 constants, or else the non-standard but more modern WGS-84 constants, the ``twoline2rv()`` constructor takes an optional argument: >>> from sgp4.api import WGS72OLD, WGS72, WGS84 >>> satellite3 = Satrec.twoline2rv(s, t, WGS84) You will in general get less accurate results if you choose WGS-84. Even though it reflects more recent and accurate measures of the Earth, satellite TLEs across the industry are most likely generated with WGS-72 as their basis. The positions you generate will better agree with the real positions of each satellite if you use the same underlying gravity constants as were used to generate the TLE. Providing your own elements --------------------------- If instead of parsing a TLE you want to specify orbital elements directly, you can pass them as floating point numbers to a satellite object’s ``sgp4init()`` method. For example, here’s how to build the same International Space Station orbit that we loaded from a TLE in the first code example above: >>> satellite2 = Satrec() >>> satellite2.sgp4init( ... WGS72, # gravity model ... 'i', # 'a' = old AFSPC mode, 'i' = improved mode ... 25544, # satnum: Satellite number ... 25545.69339541, # epoch: days since 1949 December 31 00:00 UT ... 3.8792e-05, # bstar: drag coefficient (1/earth radii) ... 0.0, # ndot: ballistic coefficient (radians/minute^2) ... 0.0, # nddot: mean motion 2nd derivative (radians/minute^3) ... 0.0007417, # ecco: eccentricity ... 0.3083420829620822, # argpo: argument of perigee (radians) ... 0.9013560935706996, # inclo: inclination (radians) ... 1.4946964807494398, # mo: mean anomaly (radians) ... 0.06763602333248933, # no_kozai: mean motion (radians/minute) ... 3.686137125541276, # nodeo: R.A. of ascending node (radians) ... ) These numbers don’t look the same as the numbers in the TLE, because the underlying ``sgp4init()`` routine uses different units: radians rather than degrees. But this is the same orbit and will produce the same positions. Note that ``ndot`` and ``nddot`` are ignored by the SGP4 propagator, so you can leave them ``0.0`` without any effect on the resulting satellite positions. But they do at least get saved to the satellite object, and written out if you write the parameters to a TLE or OMM file (see the “Export” section, above). To compute the “epoch” argument, take the epoch’s Julian date and subtract 2433281.5 days. While the underlying ``sgp4init()`` routine leaves the attributes ``epochyr``, ``epochdays``, ``jdsatepoch``, and ``jdsatepochF`` unset, this library goes ahead and sets them anyway for you, using the epoch you provided. See the next section for the complete list of attributes that are available from the satellite record once it has been initialized. Attributes ---------- There are several dozen ``Satrec`` attributes that expose data from the underlying C++ SGP4 record. They fall into the following categories. *Identification* These are copied directly from the TLE record but aren’t used by the propagation math. | ``satnum_str`` — Satellite number, as a 5-character string. | ``satnum`` — Satellite number, converted to an integer. | ``classification`` — ``'U'``, ``'C'``, or ``'S'`` indicating the element set is Unclassified, Classified, or Secret. | ``ephtype`` — Integer “ephemeris type”, used internally by space agencies to mark element sets that are not ready for publication; this field should always be ``0`` in published TLEs. | ``elnum`` — Element set number. | ``revnum`` — Satellite’s revolution number at the moment of the epoch, presumably counting from 1 following launch. *Orbital Elements* These are the orbital parameters, copied verbatim from the text of the TLE record. They describe the orbit at the moment of the TLE’s epoch and so remain constant even as the satellite record is used over and over again to propagate positions for different times. | ``epochyr`` — Epoch date: the last two digits of the year. | ``epochdays`` — Epoch date: the number of days into the year, including a decimal fraction for the UTC time of day. | ``ndot`` — First time derivative of the mean motion (loaded from the TLE, but otherwise ignored). | ``nddot`` — Second time derivative of the mean motion (loaded from the TLE, but otherwise ignored). | ``bstar`` — Ballistic drag coefficient B* (1/earth radii). | ``inclo`` — Inclination (radians). | ``nodeo`` — Right ascension of ascending node (radians). | ``ecco`` — Eccentricity. | ``argpo`` — Argument of perigee (radians). | ``mo`` — Mean anomaly (radians). | ``no_kozai`` — Mean motion (radians/minute). | ``no`` — Alias for ``no_kozai``, for compatibility with old code. You can also access the epoch as a Julian date: | ``jdsatepoch`` — Whole part of the epoch’s Julian date. | ``jdsatepochF`` — Fractional part of the epoch’s Julian date. *Computed Orbit Properties* These are computed when the satellite is first loaded, as a convenience for callers who might be interested in them. They aren’t used by the SGP4 propagator itself. | ``a`` — Semi-major axis (earth radii). | ``altp`` — Altitude of the satellite at perigee (earth radii, assuming a spherical Earth). | ``alta`` — Altitude of the satellite at apogee (earth radii, assuming a spherical Earth). | ``argpdot`` — Rate at which the argument of perigee is changing (radians/minute). | ``gsto`` — Greenwich Sidereal Time at the satellite’s epoch (radians). | ``mdot`` — Rate at which the mean anomaly is changing (radians/minute) | ``nodedot`` — Rate at which the right ascension of the ascending node is changing (radians/minute). *Propagator Mode* | ``operationmode`` — A single character that directs SGP4 to either operate in its modern ``'i'`` improved mode or in its legacy ``'a'`` AFSPC mode. | ``method`` — A single character, chosen automatically when the orbital elements were loaded, that indicates whether SGP4 has chosen to use its built-in ``'n'`` Near Earth or ``'d'`` Deep Space mode for this satellite. *Result of Most Recent Propagation* | ``t`` — The time you gave when you most recently asked SGP4 to compute this satellite’s position, measured in minutes before (negative) or after (positive) the satellite’s epoch. | ``error`` — Error code produced by the most recent SGP4 propagation you performed with this element set. The possible ``error`` codes are: 0. No error. 1. Mean eccentricity is outside the range 0 ≤ e < 1. 2. Mean motion has fallen below zero. 3. Perturbed eccentricity is outside the range 0 ≤ e ≤ 1. 4. Length of the orbit’s semi-latus rectum has fallen below zero. 5. (No longer used.) 6. Orbit has decayed: the computed position is underground. (The position is still returned, in case the vector is helpful to software that might be searching for the moment of re-entry.) *Mean Elements From Most Recent Propagation* Partway through each propagation, the SGP4 routine saves a set of “singly averaged mean elements” that describe the orbit’s shape at the moment for which a position is being computed. They are averaged with respect to the mean anomaly and include the effects of secular gravity, atmospheric drag, and — in Deep Space mode — of those pertubations from the Sun and Moon that SGP4 averages over an entire revolution of each of those bodies. They omit both the shorter-term and longer-term periodic pertubations from the Sun and Moon that SGP4 applies right before computing each position. | ``am`` — Average semi-major axis (earth radii). | ``em`` — Average eccentricity. | ``im`` — Average inclination (radians). | ``Om`` — Average right ascension of ascending node (radians). | ``om`` — Average argument of perigee (radians). | ``mm`` — Average mean anomaly (radians). | ``nm`` — Average mean motion (radians/minute). *Gravity Model Parameters* When the satellite record is initialized, your choice of gravity model results in a slate of eight constants being copied in: | ``tumin`` — Minutes in one “time unit”. | ``xke`` — The reciprocal of ``tumin``. | ``mu`` — Earth’s gravitational parameter (km³/s²). | ``radiusearthkm`` — Radius of the earth (km). | ``j2``, ``j3``, ``j4`` — Un-normalized zonal harmonic values J₂, J₃, and J₄. | ``j3oj2`` — The ratio J₃/J₂. Printing satellite attributes ----------------------------- If you want to print out a satellite, this library provides a convenient “attribute dump” routine that takes a satellite and generates lines that list its attributes:: from sys import stdout from sgp4.conveniences import dump_satrec stdout.writelines(dump_satrec(satellite)) If you want to compare two satellites, then simply pass a second argument; the second satellite’s attributes will be printed in a second column next to those of the first. :: stdout.writelines(dump_satrec(satellite, satellite2)) Validation against the official algorithm ----------------------------------------- This implementation passes all of the automated tests in the August 2010 release of the reference implementation of SGP4 by Vallado et al., who originally published their revision of SGP4 in 2006: Vallado, David A., Paul Crawford, Richard Hujsak, and T.S. Kelso, “Revisiting Spacetrack Report #3,” presented at the AIAA/AAS Astrodynamics Specialist Conference, Keystone, CO, 2006 August 21–24. If you would like to review the paper, it is `available online `_. You can always download the latest version of their code for comparison against this Python module (or other implementations) at `AIAA-2006-6753.zip `_. For developers -------------- Developers can check out this full project from GitHub: https://github.com/brandon-rhodes/python-sgp4 To run its unit tests, install Python 2, Python 3, and the ``tox`` testing tool. The tests runing in Python 2 will exercise the fallback pure-Python version of the routines, while Python 3 exercises the fast new C++ accelerated code:: cd python-sgp4 tox Legacy API ---------- Before this library pivoted to wrapping Vallado's official C++ code and was operating in pure Python only, it had a slightly quirkier API, which is still supported for compatibility with older clients. You can learn about it by reading the documentation from version 1.4 or earlier: https://pypi.org/project/sgp4/1.4/ Changelog --------- 2023-04-27 — 2.22 * Added a ``satnum_str`` attribute, exposing the fact that the C++ now stores the satellite number as a string; and check that ``satnum`` is never greater than 339999. * Fixed the units of the ``nddot`` attribute when the value is loaded from an OMM record. (Since the TLE computation itself ignores this attribute, this did not affect any satellite positions.) * Enhanced the fallback Python version of ``twoline2rv()`` to verify that TLE lines are ASCII, and added documentation using it to double-check TLEs that might suffer from non-ASCII characters. * If the user doesn’t set a satellite’s ``classification``, it now defaults to ``'U'`` for ‘unclassified’. 2022-04-06 — 2.21 * Added ``dump_satrec()`` to the ``sgp4.conveniences`` module. * Fixed the ``Satrec`` attribute ``.error``, which was previously building a nonsense integer from the wrong data in memory. * Removed ``.whichconst`` from Python ``Satrec``, to help users avoid writing code that will break when the C++ extension is available. 2021-07-01 — 2.20 * Taught ``sgp4init()`` to round both ``epochdays`` and ``jdsatepochF`` to the same 8 decimal places used for the date fraction in a TLE, if the user-supplied ``epoch`` itself has 8 or fewer digits behind the decimal point. This should make it easier to build satellites that round-trip to TLE format with perfect accuracy. * Fixed how ``export_tle()`` formats the BSTAR field when its value, if written in scientific notation, has a positive exponent. * Fixed the ``epochyr`` assigned by ``sgp4init()`` so years before 2000 have two digits instead of three (for example, so that 1980 produces an ``epochyr`` of 80 instead of 980). 2021-04-22 — 2.19 * Extended the documentation on the Python Package Index and in the module docstring so it lists every ``Satrec`` attribute that this library exposes; even the more obscure ones might be useful to folks working to analyze satellite orbits. 2021-03-08 — 2.18 * If a TLE satellite number lacks the required 5 digits, ``twoline2rv()`` now gives the underlying C++ library a little help so it can still parse the classification and international designator correctly. * The ``Satrec`` attributes ``jdsatepoch``, ``jdsatepochF``, ``epochyr``, and ``epochdays`` are now writeable, so users can adjust their values manually — which should make up for the fact that the ``sgp4init()`` method can’t set them with full floating point precision. | 2021-02-17 — 2.17 — Fixed where in the output array the ``sgp4_array()`` method writes NaN values when an SGP4 propagation fails. | 2021-02-12 — 2.16 — Fixed ``days2mdhms()`` rounding to always match TLE epoch. | 2021-01-08 — 2.15 — Fixed parsing of the ``satnum`` TLE field in the Python fallback code, when the field has a leading space; added OMM export routine. | 2020-12-16 — 2.14 — New data formats: added OMM message support for both XML and CSV, and added support for the new Alpha-5 extension to TLE files. | 2020-10-14 — 2.13 — Enhanced ``sgp4init()`` with custom code that also sets the ``epochdays`` and ``epochyr`` satellite attributes. | 2020-05-28 — 2.12 — Moved the decision of whether to set the locale during ``twoline2rv()`` from import time to runtime, for users who change locales after their application is up and running. | 2020-05-24 — 2.11 — Fixed a regression in how dates are split into hours, minutes, and seconds that would sometimes produce a time whose second=60, crashing the pure-Python version of the library. | 2020-05-22 — 2.10 — Switch the locale temporarily to ``C`` during the C++ accelerated ``twoline2rv()``, since it does not protect its ``sscanf()`` calls from locales that, like German, expect comma decimal points instead of the period decimal points always used in a TLE. | 2020-05-21 — 2.9 — Added ``sat_epoch_datetime()``, expanded documentation around converting a satellite epoch to a date and time, and started rounding the epoch to exactly the digits provided in the TLE; and removed the ``Satrec.epoch`` attribute from Python fallback code to better match the C++ version. | 2020-05-07 — 2.8 — New function ``jday_datetime()`` is now available in the ``sgp4.conveniences`` module, thanks to Egemen Imre. | 2020-04-24 — 2.7 — New method ``sgp4init()`` (thank you, Chris Lewicki!) is available. | 2020-04-20 — 2.6 — New routine ``export_tle()`` (thank you, Egemen Imre!) is available. Improved how the accelerated C++ backend parses the ``intldesg`` string and the ``revnum`` integer. | 2020-03-22 — 2.5 — Gave the new accelerated ``twoline2rv()`` an optional argument that lets the user choose a non-standard set of gravity constants. | 2020-02-25 — 2.4 — Improved the ``jday()`` docstring; made the old legacy Python resilient if the day of the month is out-of-range (past the end of the month) in a TLE; and Mark Rutten fixed the C++ so it compiles on Windows! | 2020-02-04 — 2.3 — Removed experimental code that caused performance problems for users with Numba installed. | 2020-02-02 — 2.2 — A second release on Palindrome Day: fix the Satrec ``.epochyr`` attribute so it behaves the same way in Python as it does in the official C library, where it is only the last 2 digits of the year; and make ``.no`` available in the Python fallback case as well. | 2020-02-02 — 2.1 — Add vectorized array method to Satrec object; add ``.no`` attribute to new Satrec object to support old code that has not migrated to the new name ``.no_kozai``; gave Python wrapper classes ``__slots__`` to avoid the expense of a per-object attribute dictionary. | 2020-01-30 — 2.0 — Rewrite API to use genuine Vallado C++ code on those systems where it can be compiled; add accelerated vectorized array interface; make ``gstime()`` a public function; clarify format error message. | 2015-01-15 — 1.4 — Display detailed help when TLE input does not match format. | 2014-06-26 — 1.3 — Return ``(NaN,NaN,NaN)`` vectors on error and set ``.error_message`` | 2013-11-29 — 1.2 — Made ``epochyr`` 4 digits; add ``datetime`` for ``.epoch`` | 2012-11-22 — 1.1 — Python 3 compatibility; more documentation | 2012-08-27 — 1.0 — Initial release """ __version__ = '2.22' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/alpha5.py0000644000175100001730000000113614422467341014326 0ustar00runnerdocker"""Alpha 5 encoding of satellite numbers to fit in 5 characters.""" def to_alpha5(n): if n < 100000: return '%05d' % n if n > 339999: raise ValueError('satellite number cannot exceed 339999,' " whose Alpha 5 encoding is 'Z9999'") i, n = divmod(n, 10000) i += ord('A') - 10 if i >= ord('I'): i += 1 if i >= ord('O'): i += 1 return '%c%04d' % (i, n) def from_alpha5(s): if not s[0].isalpha(): return int(s) c, s = s[0], s[1:] n = ord(c) - ord('A') + 10 n -= c > 'I' n -= c > 'O' return n * 10000 + int(s) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/api.py0000644000175100001730000000156214422467341013730 0ustar00runnerdocker"""Public API that tries to import C++ module, but falls back to Python.""" __all__ = ( 'SGP4_ERRORS', 'Satrec', 'SatrecArray', 'WGS72OLD', 'WGS72', 'WGS84', 'accelerated', 'jday', 'days2mdhms', ) from .functions import jday, days2mdhms SGP4_ERRORS = { 1: 'mean eccentricity is outside the range 0.0 to 1.0', 2: 'nm is less than zero', 3: 'perturbed eccentricity is outside the range 0.0 to 1.0', 4: 'semilatus rectum is less than zero', 5: '(error 5 no longer in use; it meant the satellite was underground)', 6: 'mrt is less than 1.0 which indicates the satellite has decayed', } try: from .wrapper import Satrec, SatrecArray accelerated = True except ImportError: from .model import Satrec, SatrecArray from .model import WGS72OLD, WGS72, WGS84 accelerated = False else: from .vallado_cpp import WGS72OLD, WGS72, WGS84 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/conveniences.py0000644000175100001730000000670714422467341015644 0ustar00runnerdocker"""Various conveniences. Higher-level libraries like Skyfield that use this one usually have their own date and time handling. But for folks using this library by itself, native Python datetime handling could be convenient. """ import datetime as dt import sgp4 from .functions import days2mdhms, jday class _UTC(dt.tzinfo): 'UTC' zero = dt.timedelta(0) def __repr__(self): return 'UTC' def dst(self, datetime): return self.zero def tzname(self, datetime): return 'UTC' def utcoffset(self, datetime): return self.zero UTC = _UTC() def jday_datetime(datetime): """Return two floats that, when added, produce the specified Julian date. The first float returned gives the date, while the second float provides an additional offset for the particular hour, minute, and second of that date. Because the second float is much smaller in magnitude it can, unlike the first float, be accurate down to very small fractions of a second. >>> jd, fr = jday(2020, 2, 11, 13, 57, 0) >>> jd 2458890.5 >>> fr 0.58125 Note that the first float, which gives the moment of midnight that commences the given calendar date, always carries the fraction ``.5`` because Julian dates begin and end at noon. This made Julian dates more convenient for astronomers in Europe, by making the whole night belong to a single Julian date. The input is a native `datetime` object. Timezone of the input is converted internally to UTC. """ u = datetime.astimezone(UTC) year = u.year mon = u.month day = u.day hr = u.hour minute = u.minute sec = u.second + u.microsecond * 1e-6 return jday(year, mon, day, hr, minute, sec) def sat_epoch_datetime(sat): """Return the epoch of the given satellite as a Python datetime.""" year = sat.epochyr year += 1900 + (year < 57) * 100 days = sat.epochdays month, day, hour, minute, second = days2mdhms(year, days) if month == 12 and day > 31: # for that time the ISS epoch was "Dec 32" year += 1 month = 1 day -= 31 second, fraction = divmod(second, 1.0) second = int(second) micro = int(fraction * 1e6) return dt.datetime(year, month, day, hour, minute, second, micro, UTC) _ATTRIBUTES = None def dump_satrec(sat, sat2=None): """Yield lines that list the attributes of one or two satellites.""" global _ATTRIBUTES if _ATTRIBUTES is None: _ATTRIBUTES = [] for line in sgp4.__doc__.splitlines(): if line.endswith('*'): title = line.strip('*') _ATTRIBUTES.append(title) elif line.startswith('| ``'): pieces = line.split('``') _ATTRIBUTES.append(pieces[1]) i = 2 while pieces[i] == ', ': _ATTRIBUTES.append(pieces[i+1]) i += 2 for item in _ATTRIBUTES: if item[0].isupper(): title = item yield '\n' yield '# -------- {0} --------\n'.format(title) else: name = item value = getattr(sat, item, '(not set)') line = '{0} = {1!r}\n'.format(item, value) if sat2 is not None: value2 = getattr(sat2, name, '(not set)') verdict = '==' if (value == value2) else '!=' line = '{0:39} {1} {2!r}\n'.format(line[:-1], verdict, value2) yield line ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/earth_gravity.py0000644000175100001730000000056714422467341016033 0ustar00runnerdocker"""Three earth-gravity models for use with SGP4.""" from collections import namedtuple from sgp4.propagation import getgravconst EarthGravity = namedtuple( 'EarthGravity', 'tumin mu radiusearthkm xke j2 j3 j4 j3oj2', ) wgs72old = EarthGravity(*getgravconst('wgs72old')) wgs72 = EarthGravity(*getgravconst('wgs72')) wgs84 = EarthGravity(*getgravconst('wgs84')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/exporter.py0000644000175100001730000001124514422467341015026 0ustar00runnerdocker"""Export orbit data to a Two-Line-Element representation. Contributed by Egemen Imre https://github.com/egemenimre """ from math import pi from sgp4.io import compute_checksum from sgp4.conveniences import sat_epoch_datetime # Define constants _deg2rad = pi / 180.0 # 0.0174532925199433 _xpdotp = 1440.0 / (2.0 * pi) # 229.1831180523293 def export_tle(satrec): """Generate the TLE for a given `Satrec` object; returns two strings.""" # --------------------- Start generating line 1 --------------------- # Build the list by appending successive items pieces = ['1 ', satrec.satnum_str] append = pieces.append # Add classification code (use "U" if empty) classification = getattr(satrec, 'classification', 'U') append(classification.strip() or 'U') append(' ') # Add int'l designator and pad to 8 chars intldesg = getattr(satrec, 'intldesg', '') append('{0:8} '.format(intldesg)) # Add epoch year and days in YYDDD.DDDDDDDD format epochyr = satrec.epochyr # Undo non-standard 4-digit year for old satrec objects epochyr %= 100 append(str(epochyr).zfill(2) + "{:012.8f}".format(satrec.epochdays) + " ") # Add First Time Derivative of the Mean Motion (don't use "+") append("{0: 8.8f}".format(satrec.ndot * (_xpdotp * 1440.0)).replace("0", "", 1) + " ") # Add Second Time Derivative of Mean Motion append(_abbreviate_rate(satrec.nddot * _xpdotp * 20736000.0, '-0')) # Add BSTAR append(_abbreviate_rate(satrec.bstar * 10.0, '+0')) # Add Ephemeris Type and Element Number ephtype = getattr(satrec, 'ephtype', 0) elnum = getattr(satrec, 'elnum', 0) append('{0} {1:4}'.format(ephtype, elnum)) # Join all the parts and add the Checksum line1 = ''.join(pieces) line1 += str(compute_checksum(line1)) # --------------------- Start generating line 2 --------------------- # Reset the str array pieces = ['2 ', satrec.satnum_str] append = pieces.append # Add the inclination (deg) if not 0 <= satrec.inclo <= pi: raise ValueError("Inclination must be between 0 and pi, got %r", satrec.inclo) append(' {0:8.4f} '.format(satrec.inclo / _deg2rad)) # Add the RAAN (deg) if not 0 <= satrec.nodeo <= 2 * pi: raise ValueError("RAAN must be between 0 and 2 pi, got %r", satrec.nodeo) append("{0:8.4f}".format(satrec.nodeo / _deg2rad).rjust(8, " ") + " ") # Add the eccentricity (delete the leading zero an decimal point) append("{0:8.7f}".format(satrec.ecco).replace("0.", "") + " ") # Add the Argument of Perigee (deg) if not 0 <= satrec.argpo <= 2 * pi: raise ValueError("Argument of Perigee must be between 0 and 2 pi, got %r", satrec.argpo) append("{0:8.4f}".format(satrec.argpo / _deg2rad).rjust(8, " ") + " ") # Add the Mean Anomaly (deg) if not 0 <= satrec.mo <= 2 * pi: raise ValueError("Mean Anomaly must be between 0 and 2 pi, got %r", satrec.mo) append("{0:8.4f}".format(satrec.mo / _deg2rad).rjust(8, " ") + " ") # Add the Mean Motion (revs/day) append("{0:11.8f}".format(satrec.no_kozai * _xpdotp).rjust(8, " ")) # Add the rev number at epoch append(str(satrec.revnum).rjust(5)) # Join all the parts and add the Checksum line2 = ''.join(pieces) line2 += str(compute_checksum(line2)) return line1, line2 def _abbreviate_rate(value, zero_exponent_string): return ( '{0: 4.4e} '.format(value) .replace('.', '') .replace('e+00', zero_exponent_string) .replace('e-0', '-') .replace('e+0', '+') ) def export_omm(satrec, object_name): launch_year = int(satrec.intldesg[:2]) launch_year += 1900 + (launch_year < 57) * 100 object_id = '{0}-{1}'.format(launch_year, satrec.intldesg[2:]) return { "OBJECT_NAME": object_name, "OBJECT_ID": object_id, "CENTER_NAME": "EARTH", "REF_FRAME": "TEME", "TIME_SYSTEM": "UTC", "MEAN_ELEMENT_THEORY": "SGP4", "EPOCH": sat_epoch_datetime(satrec).strftime('%Y-%m-%dT%H:%M:%S.%f'), "MEAN_MOTION": satrec.no_kozai * _xpdotp, "ECCENTRICITY": satrec.ecco, "INCLINATION": satrec.inclo / _deg2rad, "RA_OF_ASC_NODE": satrec.nodeo / _deg2rad, "ARG_OF_PERICENTER": satrec.argpo / _deg2rad, "MEAN_ANOMALY": satrec.mo / _deg2rad, "EPHEMERIS_TYPE": satrec.ephtype, "CLASSIFICATION_TYPE": satrec.classification, "NORAD_CAT_ID": satrec.satnum, "ELEMENT_SET_NO": satrec.elnum, "REV_AT_EPOCH": satrec.revnum, "BSTAR": satrec.bstar, "MEAN_MOTION_DOT": satrec.ndot * (_xpdotp * 1440.0), "MEAN_MOTION_DDOT": satrec.nddot * (_xpdotp * 1440.0 * 1440), } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/ext.py0000644000175100001730000004157414422467341013766 0ustar00runnerdocker# -*- coding: utf-8 -*- """Utility routines from "sgp4ext.cpp".""" from math import (acos, asinh, atan2, copysign, cos, fabs, fmod, pi, sin, sinh, sqrt, tan) from .functions import days2mdhms undefined = None """ /* ----------------------------------------------------------------------------- * * function mag * * this procedure finds the magnitude of a vector. the tolerance is set to * 0.000001, thus the 1.0e-12 for the squared test of underflows. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec - vector * * outputs : * vec - answer stored in fourth component * * locals : * none. * * coupling : * none. * --------------------------------------------------------------------------- */ """ def mag(x): return sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); """ /* ----------------------------------------------------------------------------- * * procedure cross * * this procedure crosses two vectors. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec1 - vector number 1 * vec2 - vector number 2 * * outputs : * outvec - vector result of a x b * * locals : * none. * * coupling : * mag magnitude of a vector ---------------------------------------------------------------------------- */ """ def cross(vec1, vec2, outvec): outvec[0]= vec1[1]*vec2[2] - vec1[2]*vec2[1]; outvec[1]= vec1[2]*vec2[0] - vec1[0]*vec2[2]; outvec[2]= vec1[0]*vec2[1] - vec1[1]*vec2[0]; """ /* ----------------------------------------------------------------------------- * * function dot * * this function finds the dot product of two vectors. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec1 - vector number 1 * vec2 - vector number 2 * * outputs : * dot - result * * locals : * none. * * coupling : * none. * * --------------------------------------------------------------------------- */ """ def dot(x, y): return (x[0]*y[0] + x[1]*y[1] + x[2]*y[2]); """ /* ----------------------------------------------------------------------------- * * procedure angle * * this procedure calculates the angle between two vectors. the output is * set to 999999.1 to indicate an undefined value. be sure to check for * this at the output phase. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * vec1 - vector number 1 * vec2 - vector number 2 * * outputs : * theta - angle between the two vectors -pi to pi * * locals : * temp - temporary real variable * * coupling : * dot dot product of two vectors * --------------------------------------------------------------------------- */ """ def angle(vec1, vec2): small = 0.00000001; undefined = 999999.1; magv1 = mag(vec1); magv2 = mag(vec2); if magv1*magv2 > small*small: temp= dot(vec1,vec2) / (magv1*magv2); if fabs(temp) > 1.0: temp = copysign(1.0, temp) return acos( temp ); else: return undefined; """ /* ----------------------------------------------------------------------------- * * function newtonnu * * this function solves keplers equation when the true anomaly is known. * the mean and eccentric, parabolic, or hyperbolic anomaly is also found. * the parabolic limit at 168° is arbitrary. the hyperbolic anomaly is also * limited. the hyperbolic sine is used because it's not double valued. * * author : david vallado 719-573-2600 27 may 2002 * * revisions * vallado - fix small 24 sep 2002 * * inputs description range / units * ecc - eccentricity 0.0 to * nu - true anomaly -2pi to 2pi rad * * outputs : * e0 - eccentric anomaly 0.0 to 2pi rad 153.02 ° * m - mean anomaly 0.0 to 2pi rad 151.7425 ° * * locals : * e1 - eccentric anomaly, next value rad * sine - sine of e * cose - cosine of e * ktr - index * * coupling : * asinh - arc hyperbolic sine * * references : * vallado 2007, 85, alg 5 * --------------------------------------------------------------------------- */ """ def newtonnu(ecc, nu): # --------------------- implementation --------------------- e0= 999999.9; m = 999999.9; small = 0.00000001; # --------------------------- circular ------------------------ if fabs(ecc) < small: m = nu; e0= nu; else: # ---------------------- elliptical ----------------------- if ecc < 1.0-small: sine= ( sqrt( 1.0 -ecc*ecc ) * sin(nu) ) / ( 1.0 +ecc*cos(nu) ); cose= ( ecc + cos(nu) ) / ( 1.0 + ecc*cos(nu) ); e0 = atan2( sine,cose ); m = e0 - ecc*sin(e0); else: # -------------------- hyperbolic -------------------- if ecc > 1.0 + small: if ecc > 1.0 and fabs(nu)+0.00001 < pi-acos(1.0 /ecc): sine= ( sqrt( ecc*ecc-1.0 ) * sin(nu) ) / ( 1.0 + ecc*cos(nu) ); e0 = asinh( sine ); m = ecc*sinh(e0) - e0; else: # ----------------- parabolic --------------------- if fabs(nu) < 168.0*pi/180.0: e0= tan( nu*0.5 ); m = e0 + (e0*e0*e0)/3.0; if ecc < 1.0: m = fmod( m,2.0 *pi ); if m < 0.0: m = m + 2.0 *pi; e0 = fmod( e0,2.0 *pi ); return e0, m """ /* ----------------------------------------------------------------------------- * * function rv2coe * * this function finds the classical orbital elements given the geocentric * equatorial position and velocity vectors. * * author : david vallado 719-573-2600 21 jun 2002 * * revisions * vallado - fix special cases 5 sep 2002 * vallado - delete extra check in inclination code 16 oct 2002 * vallado - add constant file use 29 jun 2003 * vallado - add mu 2 apr 2007 * * inputs description range / units * r - ijk position vector km * v - ijk velocity vector km / s * mu - gravitational parameter km3 / s2 * * outputs : * p - semilatus rectum km * a - semimajor axis km * ecc - eccentricity * incl - inclination 0.0 to pi rad * omega - longitude of ascending node 0.0 to 2pi rad * argp - argument of perigee 0.0 to 2pi rad * nu - true anomaly 0.0 to 2pi rad * m - mean anomaly 0.0 to 2pi rad * arglat - argument of latitude (ci) 0.0 to 2pi rad * truelon - true longitude (ce) 0.0 to 2pi rad * lonper - longitude of periapsis (ee) 0.0 to 2pi rad * * locals : * hbar - angular momentum h vector km2 / s * ebar - eccentricity e vector * nbar - line of nodes n vector * c1 - v**2 - u/r * rdotv - r dot v * hk - hk unit vector * sme - specfic mechanical energy km2 / s2 * i - index * e - eccentric, parabolic, * hyperbolic anomaly rad * temp - temporary variable * typeorbit - type of orbit ee, ei, ce, ci * * coupling : * mag - magnitude of a vector * cross - cross product of two vectors * angle - find the angle between two vectors * newtonnu - find the mean anomaly * * references : * vallado 2007, 126, alg 9, ex 2-5 * --------------------------------------------------------------------------- */ """ def rv2coe(r, v, mu): hbar = [None, None, None] nbar = [None, None, None] ebar = [None, None, None] typeorbit = [None, None, None]; twopi = 2.0 * pi; halfpi = 0.5 * pi; small = 0.00000001; undefined = 999999.1; infinite = 999999.9; # ------------------------- implementation ----------------- magr = mag( r ); magv = mag( v ); # ------------------ find h n and e vectors ---------------- cross( r,v, hbar ); magh = mag( hbar ); if magh > small: nbar[0]= -hbar[1]; nbar[1]= hbar[0]; nbar[2]= 0.0; magn = mag( nbar ); c1 = magv*magv - mu /magr; rdotv = dot( r,v ); for i in range(0, 3): ebar[i]= (c1*r[i] - rdotv*v[i])/mu; ecc = mag( ebar ); # ------------ find a e and semi-latus rectum ---------- sme= ( magv*magv*0.5 ) - ( mu /magr ); if fabs( sme ) > small: a= -mu / (2.0 *sme); else: a= infinite; p = magh*magh/mu; # ----------------- find inclination ------------------- hk= hbar[2]/magh; incl= acos( hk ); # -------- determine type of orbit for later use -------- # ------ elliptical, parabolic, hyperbolic inclined ------- typeorbit = 'ei' if ecc < small: # ---------------- circular equatorial --------------- if incl < small or fabs(incl-pi) < small: typeorbit = 'ce' else: # -------------- circular inclined --------------- typeorbit = 'ci' else: # - elliptical, parabolic, hyperbolic equatorial -- if incl < small or fabs(incl-pi) < small: typeorbit = 'ee' # ---------- find longitude of ascending node ------------ if magn > small: temp= nbar[0] / magn; if fabs(temp) > 1.0: temp = copysign(1.0, temp) omega= acos( temp ); if nbar[1] < 0.0: omega= twopi - omega; else: omega= undefined; # ---------------- find argument of perigee --------------- if typeorbit == 'ei': argp = angle( nbar,ebar); if ebar[2] < 0.0: argp= twopi - argp; else: argp= undefined; # ------------ find true anomaly at epoch ------------- if typeorbit[0] == 'e': nu = angle( ebar,r); if rdotv < 0.0: nu= twopi - nu; else: nu= undefined; # ---- find argument of latitude - circular inclined ----- if typeorbit == 'ci': arglat = angle( nbar,r ); if r[2] < 0.0: arglat= twopi - arglat; m = arglat; else: arglat= undefined; # -- find longitude of perigee - elliptical equatorial ---- if ecc > small and typeorbit == 'ee': temp= ebar[0]/ecc; if fabs(temp) > 1.0: temp = copysign(1.0, temp) lonper= acos( temp ); if ebar[1] < 0.0: lonper= twopi - lonper; if incl > halfpi: lonper= twopi - lonper; else: lonper= undefined; # -------- find true longitude - circular equatorial ------ if magr > small and typeorbit == 'ce': temp= r[0]/magr; if fabs(temp) > 1.0: temp = copysign(1.0, temp) truelon= acos( temp ); if r[1] < 0.0: truelon= twopi - truelon; if incl > halfpi: truelon= twopi - truelon; m = truelon; else: truelon= undefined; # ------------ find mean anomaly for all orbits ----------- if typeorbit[0] == 'e': e, m = newtonnu(ecc, nu); else: p = undefined; a = undefined; ecc = undefined; incl = undefined; omega= undefined; argp = undefined; nu = undefined; m = undefined; arglat = undefined; truelon= undefined; lonper = undefined; return p, a, ecc, incl, omega, argp, nu, m, arglat, truelon, lonper """ /* ----------------------------------------------------------------------------- * * procedure jday * * this procedure finds the julian date given the year, month, day, and time. * the julian date is defined by each elapsed day since noon, jan 1, 4713 bc. * * algorithm : calculate the answer in one step for efficiency * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * year - year 1900 .. 2100 * mon - month 1 .. 12 * day - day 1 .. 28,29,30,31 * hr - universal time hour 0 .. 23 * min - universal time min 0 .. 59 * sec - universal time sec 0.0 .. 59.999 * * outputs : * jd - julian date days from 4713 bc * * locals : * none. * * coupling : * none. * * references : * vallado 2007, 189, alg 14, ex 3-14 * * --------------------------------------------------------------------------- */ """ def jday(year, mon, day, hr, minute, sec): return (367.0 * year - 7.0 * (year + ((mon + 9.0) // 12.0)) * 0.25 // 1.0 + 275.0 * mon // 9.0 + day + 1721013.5 + ((sec / 60.0 + minute) / 60.0 + hr) / 24.0 # ut in days # - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5; ) """ /* ----------------------------------------------------------------------------- * * procedure invjday * * this procedure finds the year, month, day, hour, minute and second * given the julian date. tu can be ut1, tdt, tdb, etc. * * algorithm : set up starting values * find leap year - use 1900 because 2000 is a leap year * find the elapsed days through the year in a loop * call routine to find each individual value * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * jd - julian date days from 4713 bc * * outputs : * year - year 1900 .. 2100 * mon - month 1 .. 12 * day - day 1 .. 28,29,30,31 * hr - hour 0 .. 23 * min - minute 0 .. 59 * sec - second 0.0 .. 59.999 * * locals : * days - day of year plus fractional * portion of a day days * tu - julian centuries from 0 h * jan 0, 1900 * temp - temporary double values * leapyrs - number of leap years from 1900 * * coupling : * days2mdhms - finds month, day, hour, minute and second given days and year * * references : * vallado 2007, 208, alg 22, ex 3-13 * --------------------------------------------------------------------------- */ """ def invjday(jd): # --------------- find year and days of the year --------------- temp = jd - 2415019.5; tu = temp / 365.25; year = 1900 + int(tu // 1.0); leapyrs = int(((year - 1901) * 0.25) // 1.0); # optional nudge by 8.64x10-7 sec to get even outputs days = temp - ((year - 1900) * 365.0 + leapyrs) + 0.00000000001; # ------------ check for case of beginning of a year ----------- if (days < 1.0): year = year - 1; leapyrs = int(((year - 1901) * 0.25) // 1.0); days = temp - ((year - 1900) * 365.0 + leapyrs); # ----------------- find remaing data ------------------------- mon, day, hr, minute, sec = days2mdhms(year, days, None); sec = sec - 0.00000086400; return year, mon, day, hr, minute, sec ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/functions.py0000644000175100001730000000610414422467341015164 0ustar00runnerdocker"""General-purpose routines. It seemed a shame for the ``api`` module to have to import large legacy modules to offer simple date handling, so this small module holds the routines instead. """ def jday(year, mon, day, hr, minute, sec): """Return two floats that, when added, produce the specified Julian date. The first float returned gives the date, while the second float provides an additional offset for the particular hour, minute, and second of that date. Because the second float is much smaller in magnitude it can, unlike the first float, be accurate down to very small fractions of a second. >>> jd, fr = jday(2020, 2, 11, 13, 57, 0) >>> jd 2458890.5 >>> fr 0.58125 Note that the first float, which gives the moment of midnight that commences the given calendar date, always carries the fraction ``.5`` because Julian dates begin and end at noon. This made Julian dates more convenient for astronomers in Europe, by making the whole night belong to a single Julian date. This function is a simple translation to Python of the C++ routine ``jday()`` in Vallado's ``SGP4.cpp``. """ jd = (367.0 * year - 7 * (year + ((mon + 9) // 12.0)) * 0.25 // 1.0 + 275 * mon / 9.0 // 1.0 + day + 1721013.5) fr = (sec + minute * 60.0 + hr * 3600.0) / 86400.0; return jd, fr def days2mdhms(year, days, round_to_microsecond=6): """Convert a float point number of days into the year into date and time. Given the integer year plus the "day of the year" where 1.0 means the beginning of January 1, 2.0 means the beginning of January 2, and so forth, return the Gregorian calendar month, day, hour, minute, and floating point seconds. >>> days2mdhms(2000, 1.0) # January 1 (1, 1, 0, 0, 0.0) >>> days2mdhms(2000, 32.0) # February 1 (2, 1, 0, 0, 0.0) >>> days2mdhms(2000, 366.0) # December 31, since 2000 was a leap year (12, 31, 0, 0, 0.0) The floating point seconds are rounded to an even number of microseconds if ``round_to_microsecond`` is true. """ second = days * 86400.0 if round_to_microsecond: second = round(second, round_to_microsecond) minute, second = divmod(second, 60.0) if round_to_microsecond: second = round(second, round_to_microsecond) minute = int(minute) hour, minute = divmod(minute, 60) day_of_year, hour = divmod(hour, 24) is_leap = year % 400 == 0 or (year % 4 == 0 and year % 100 != 0) month, day = _day_of_year_to_month_day(day_of_year, is_leap) if month == 13: # behave like the original in case of overflow month = 12 day += 31 return month, day, int(hour), int(minute), second def _day_of_year_to_month_day(day_of_year, is_leap): """Core logic for turning days into months, for easy testing.""" february_bump = (2 - is_leap) * (day_of_year >= 60 + is_leap) august = day_of_year >= 215 month, day = divmod(2 * (day_of_year - 1 + 30 * august + february_bump), 61) month += 1 - august day //= 2 day += 1 return month, day ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/io.py0000644000175100001730000002454214422467341013571 0ustar00runnerdocker"""Read the TLE earth satellite file format. This is a minimally-edited copy of "sgp4io.cpp". """ import re from datetime import datetime from math import pi, pow from sgp4.ext import days2mdhms, invjday, jday from sgp4.propagation import sgp4init INT_RE = re.compile(r'[+-]?\d*') FLOAT_RE = re.compile(r'[+-]?\d*(\.\d*)?') LINE1 = '1 NNNNNC NNNNNAAA NNNNN.NNNNNNNN +.NNNNNNNN +NNNNN-N +NNNNN-N N NNNNN' LINE2 = '2 NNNNN NNN.NNNN NNN.NNNN NNNNNNN NNN.NNNN NNN.NNNN NN.NNNNNNNNNNNNNN' error_message = """TLE format error The Two-Line Element (TLE) format was designed for punch cards, and so is very strict about the position of every period, space, and digit. Your line does not quite match. Here is the official format for line {0} with an N where each digit should go, followed by the line you provided: {1} {2}""" """ /* ---------------------------------------------------------------- * * sgp4io.cpp * * this file contains a function to read two line element sets. while * not formerly part of the sgp4 mathematical theory, it is * required for practical implemenation. * * companion code for * fundamentals of astrodynamics and applications * 2007 * by david vallado * * (w) 719-573-2600, email dvallado@agi.com * * current : * 27 Aug 10 david vallado * fix input format and delete unused variables in twoline2rv * changes : * 3 sep 08 david vallado * add operationmode for afspc (a) or improved (i) * 9 may 07 david vallado * fix year correction to 57 * 27 mar 07 david vallado * misc fixes to manual inputs * 14 aug 06 david vallado * original baseline * ---------------------------------------------------------------- */ """ """ /* ----------------------------------------------------------------------------- * * function twoline2rv * * this function converts the two line element set character string data to * variables and initializes the sgp4 variables. several intermediate varaibles * and quantities are determined. note that the result is a structure so multiple * satellites can be processed simultaneously without having to reinitialize. the * verification mode is an important option that permits quick checks of any * changes to the underlying technical theory. this option works using a * modified tle file in which the start, stop, and delta time values are * included at the end of the second line of data. this only works with the * verification mode. the catalog mode simply propagates from -1440 to 1440 min * from epoch and is useful when performing entire catalog runs. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs : * longstr1 - first line of the tle * longstr2 - second line of the tle * typerun - type of run verification 'v', catalog 'c', * manual 'm' * typeinput - type of manual input mfe 'm', epoch 'e', dayofyr 'd' * opsmode - mode of operation afspc or improved 'a', 'i' * whichconst - which set of constants to use 72, 84 * * outputs : * satrec - structure containing all the sgp4 satellite information * * coupling : * getgravconst- * days2mdhms - conversion of days to month, day, hour, minute, second * jday - convert day month year hour minute second into julian date * sgp4init - initialize the sgp4 variables * * references : * norad spacetrack report #3 * vallado, crawford, hujsak, kelso 2006 --------------------------------------------------------------------------- */ """ def twoline2rv(longstr1, longstr2, whichconst, opsmode='i', satrec=None): """Return a Satellite imported from two lines of TLE data. Provide the two TLE lines as strings `longstr1` and `longstr2`, and select which standard set of gravitational constants you want by providing `gravity_constants`: `sgp4.earth_gravity.wgs72` - Standard WGS 72 model `sgp4.earth_gravity.wgs84` - More recent WGS 84 model `sgp4.earth_gravity.wgs72old` - Legacy support for old SGP4 behavior Normally, computations are made using various recent improvements to the algorithm. If you want to turn some of these off and go back into "opsmode" mode, then set `opsmode` to `a`. """ deg2rad = pi / 180.0; # 0.0174532925199433 xpdotp = 1440.0 / (2.0 *pi); # 229.1831180523293 # For compatibility with our 1.x API, build an old Satellite object # if the caller fails to supply a satrec. In that case we perform # the necessary import here to avoid an import loop. if satrec is None: from sgp4.model import Satellite satrec = Satellite() satrec.error = 0; line = longstr1.rstrip() try: longstr1.encode('ascii') longstr2.encode('ascii') except UnicodeEncodeError: r1 = repr(longstr1)[1:-1] r2 = repr(longstr2)[1:-1] raise ValueError('your TLE lines are broken because they contain' ' non-ASCII characters:\n\n%s\n%s' % (r1, r2)) if (len(line) >= 64 and line.startswith('1 ') and line[8] == ' ' and line[23] == '.' and line[32] == ' ' and line[34] == '.' and line[43] == ' ' and line[52] == ' ' and line[61] == ' ' and line[63] == ' '): satrec.satnum_str = line[2:7] satrec.classification = line[7] or 'U' satrec.intldesg = line[9:17].rstrip() two_digit_year = int(line[18:20]) satrec.epochdays = float(line[20:32]) satrec.ndot = float(line[33:43]) satrec.nddot = float(line[44] + '.' + line[45:50]) nexp = int(line[50:52]) satrec.bstar = float(line[53] + '.' + line[54:59]) ibexp = int(line[59:61]) satrec.ephtype = line[62] satrec.elnum = int(line[64:68]) else: raise ValueError(error_message.format(1, LINE1, line)) line = longstr2.rstrip() if (len(line) >= 69 and line.startswith('2 ') and line[7] == ' ' and line[11] == '.' and line[16] == ' ' and line[20] == '.' and line[25] == ' ' and line[33] == ' ' and line[37] == '.' and line[42] == ' ' and line[46] == '.' and line[51] == ' '): if satrec.satnum_str != line[2:7]: raise ValueError('Object numbers in lines 1 and 2 do not match') satrec.inclo = float(line[8:16]) satrec.nodeo = float(line[17:25]) satrec.ecco = float('0.' + line[26:33].replace(' ', '0')) satrec.argpo = float(line[34:42]) satrec.mo = float(line[43:51]) satrec.no_kozai = float(line[52:63]) satrec.revnum = line[63:68] #except (AssertionError, IndexError, ValueError): else: raise ValueError(error_message.format(2, LINE2, line)) # ---- find no, ndot, nddot ---- satrec.no_kozai = satrec.no_kozai / xpdotp; # rad/min satrec.nddot= satrec.nddot * pow(10.0, nexp); satrec.bstar= satrec.bstar * pow(10.0, ibexp); # ---- convert to sgp4 units ---- satrec.ndot = satrec.ndot / (xpdotp*1440.0); # ? * minperday satrec.nddot= satrec.nddot / (xpdotp*1440.0*1440); # ---- find standard orbital elements ---- satrec.inclo = satrec.inclo * deg2rad; satrec.nodeo = satrec.nodeo * deg2rad; satrec.argpo = satrec.argpo * deg2rad; satrec.mo = satrec.mo * deg2rad; """ // ---------------------------------------------------------------- // find sgp4epoch time of element set // remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch) // and minutes from the epoch (time) // ---------------------------------------------------------------- // ---------------- temp fix for years from 1957-2056 ------------------- // --------- correct fix will occur when year is 4-digit in tle --------- """ if two_digit_year < 57: year = two_digit_year + 2000; else: year = two_digit_year + 1900; mon,day,hr,minute,sec = days2mdhms(year, satrec.epochdays); sec_whole, sec_fraction = divmod(sec, 1.0) satrec.epochyr = year satrec.jdsatepoch = jday(year,mon,day,hr,minute,sec); try: satrec.epoch = datetime(year, mon, day, hr, minute, int(sec_whole), int(sec_fraction * 1000000.0 // 1.0)) except ValueError: # Sometimes a TLE says something like "2019 + 366.82137887 days" # which would be December 32nd which causes a ValueError. year, mon, day, hr, minute, sec = invjday(satrec.jdsatepoch) satrec.epoch = datetime(year, mon, day, hr, minute, int(sec_whole), int(sec_fraction * 1000000.0 // 1.0)) # ---------------- initialize the orbit at sgp4epoch ------------------- sgp4init(whichconst, opsmode, satrec.satnum_str, satrec.jdsatepoch-2433281.5, satrec.bstar, satrec.ndot, satrec.nddot, satrec.ecco, satrec.argpo, satrec.inclo, satrec.mo, satrec.no_kozai, satrec.nodeo, satrec) return satrec def verify_checksum(*lines): """Verify the checksum of one or more TLE lines. Raises `ValueError` if any of the lines fails its checksum, and includes the failing line in the error message. """ for line in lines: checksum = line[68:69] if not checksum.isdigit(): continue checksum = int(checksum) computed = compute_checksum(line) if checksum != computed: complaint = ('TLE line gives its checksum as {}' ' but in fact tallies to {}:\n{}') raise ValueError(complaint.format(checksum, computed, line)) def fix_checksum(line): """Return a new copy of the TLE `line`, with the correct checksum appended. This discards any existing checksum at the end of the line, if a checksum is already present. """ return line[:68].ljust(68) + str(compute_checksum(line)) def compute_checksum(line): """Compute the TLE checksum for the given line.""" return sum((int(c) if c.isdigit() else c == '-') for c in line[0:68]) % 10 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/model.py0000644000175100001730000001650214422467341014257 0ustar00runnerdocker"""The Satellite class.""" from sgp4.alpha5 import from_alpha5 from sgp4.earth_gravity import wgs72old, wgs72, wgs84 from sgp4.ext import invjday, jday from sgp4.io import twoline2rv from sgp4.propagation import sgp4, sgp4init WGS72OLD = 0 WGS72 = 1 WGS84 = 2 gravity_constants = wgs72old, wgs72, wgs84 # indexed using enum values above minutes_per_day = 1440. class Satrec(object): """Slow Python-only version of the satellite object.""" # Approximate the behavior of the C-accelerated class by locking # down attribute access, to avoid folks accidentally writing code # against this class and adding extra attributes, then moving to a # computer where the C-accelerated class is used and having their # code suddenly produce errors. __slots__ = ( 'Om', 'a', 'alta', 'altp', 'am', 'argpdot', 'argpo', 'atime', 'aycof', 'bstar', 'cc1', 'cc4', 'cc5', 'classification', 'con41', 'd2', 'd2201', 'd2211', 'd3', 'd3210', 'd3222', 'd4', 'd4410', 'd4422', 'd5220', 'd5232', 'd5421', 'd5433', 'dedt', 'del1', 'del2', 'del3', 'delmo', 'didt', 'dmdt', 'dnodt', 'domdt', 'e3', 'ecco', 'ee2', 'elnum', 'em', 'ephtype', 'epoch', 'epochdays', 'epochyr', 'error', 'error_message', 'eta', 'gsto', 'im', 'inclo', 'init', 'intldesg', 'irez', 'isimp', 'j2', 'j3', 'j3oj2', 'j4', 'jdsatepoch', 'mdot', 'method', 'mm', 'mo', 'mu', 'nddot', 'ndot', 'nm', 'no_kozai', 'no_unkozai', 'nodecf', 'nodedot', 'nodeo', 'om', 'omgcof', 'operationmode', 'peo', 'pgho', 'pho', 'pinco', 'plo', 'radiusearthkm', 'revnum', 'satnum_str', 'se2', 'se3', 'sgh2', 'sgh3', 'sgh4', 'sh2', 'sh3', 'si2', 'si3', 'sinmao', 'sl2', 'sl3', 'sl4', 't', 't2cof', 't3cof', 't4cof', 't5cof', 'tumin', 'x1mth2', 'x7thm1', 'xfact', 'xgh2', 'xgh3', 'xgh4', 'xh2', 'xh3', 'xi2', 'xi3', 'xke', 'xl2', 'xl3', 'xl4', 'xlamo', 'xlcof', 'xli', 'xmcof', 'xni', 'zmol', 'zmos', 'jdsatepochF' ) array = None # replaced, if needed, with NumPy array() @property def no(self): return self.no_kozai @property def satnum(self): return from_alpha5(self.satnum_str) @classmethod def twoline2rv(cls, line1, line2, whichconst=WGS72): whichconst = gravity_constants[whichconst] self = cls() twoline2rv(line1, line2, whichconst, 'i', self) # Expose the same attribute types as the C++ code. self.ephtype = int(self.ephtype.strip() or '0') self.revnum = int(self.revnum) # Install a fancy split JD of the kind the C++ natively supports. # We rebuild it from the TLE year and day to maintain precision. year = self.epochyr days, fraction = divmod(self.epochdays, 1.0) self.jdsatepoch = year * 365 + (year - 1) // 4 + days + 1721044.5 self.jdsatepochF = round(fraction, 8) # exact number of digits in TLE # Remove the legacy datetime "epoch", which is not provided by # the C++ version of the object. del self.epoch # Undo my non-standard 4-digit year self.epochyr %= 100 return self def sgp4init(self, whichconst, opsmode, satnum, epoch, bstar, ndot, nddot, ecco, argpo, inclo, mo, no_kozai, nodeo): whichconst = gravity_constants[whichconst] whole, fraction = divmod(epoch, 1.0) whole_jd = whole + 2433281.5 # Go out on a limb: if `epoch` has no decimal digits past the 8 # decimal places stored in a TLE, then assume the user is trying # to specify an exact decimal fraction. if round(epoch, 8) == epoch: fraction = round(fraction, 8) self.jdsatepoch = whole_jd self.jdsatepochF = fraction y, m, d, H, M, S = invjday(whole_jd) jan0 = jday(y, 1, 0, 0, 0, 0.0) self.epochyr = y % 100 self.epochdays = whole_jd - jan0 + fraction self.classification = 'U' sgp4init(whichconst, opsmode, satnum, epoch, bstar, ndot, nddot, ecco, argpo, inclo, mo, no_kozai, nodeo, self) def sgp4(self, jd, fr): tsince = ((jd - self.jdsatepoch) * minutes_per_day + (fr - self.jdsatepochF) * minutes_per_day) r, v = sgp4(self, tsince) return self.error, r, v def sgp4_tsince(self, tsince): r, v = sgp4(self, tsince) return self.error, r, v def sgp4_array(self, jd, fr): """Compute positions and velocities for the times in a NumPy array. Given NumPy arrays ``jd`` and ``fr`` of the same length that supply the whole part and the fractional part of one or more Julian dates, return a tuple ``(e, r, v)`` of three vectors: * ``e``: nonzero for any dates that produced errors, 0 otherwise. * ``r``: position vectors in kilometers. * ``v``: velocity vectors in kilometers per second. """ # Import NumPy the first time sgp4_array() is called. array = self.array if array is None: from numpy import array Satrec.array = array results = [] z = list(zip(jd, fr)) for jd_i, fr_i in z: results.append(self.sgp4(jd_i, fr_i)) elist, rlist, vlist = zip(*results) e = array(elist) r = array(rlist) v = array(vlist) r.shape = v.shape = len(jd), 3 return e, r, v class SatrecArray(object): """Slow Python-only version of the satellite array.""" __slots__ = ('_satrecs',) array = None # replaced with NumPy array(), if the user tries calling def __init__(self, satrecs): self._satrecs = satrecs # Import NumPy the first time a SatrecArray is instantiated. if self.array is None: from numpy import array SatrecArray.array = array def sgp4(self, jd, fr): """Compute positions and velocities for the satellites in this array. Given NumPy scalars or arrays ``jd`` and ``fr`` supplying the whole part and the fractional part of one or more Julian dates, return a tuple ``(e, r, v)`` of three vectors that are each as long as ``jd`` and ``fr``: * ``e``: nonzero for any dates that produced errors, 0 otherwise. * ``r``: (x,y,z) position vector in kilometers. * ``v``: (dx,dy,dz) velocity vector in kilometers per second. """ results = [] z = list(zip(jd, fr)) for satrec in self._satrecs: for jd_i, fr_i in z: results.append(satrec.sgp4(jd_i, fr_i)) elist, rlist, vlist = zip(*results) e = self.array(elist) r = self.array(rlist) v = self.array(vlist) jdlen = len(jd) mylen = len(self._satrecs) e.shape = (mylen, jdlen) r.shape = v.shape = (mylen, jdlen, 3) return e, r, v class Satellite(object): """The old Satellite object, for compatibility with sgp4 1.x.""" jdsatepochF = 0.0 # for compatibility with new Satrec; makes tests simpler def propagate(self, year, month=1, day=1, hour=0, minute=0, second=0.0): """Return a position and velocity vector for a given date and time.""" j = jday(year, month, day, hour, minute, second) m = (j - self.jdsatepoch) * minutes_per_day r, v = sgp4(self, m) return r, v no = Satrec.no satnum = Satrec.satnum ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/omm.py0000644000175100001730000000366414422467341013754 0ustar00runnerdocker"""Support for the new Orbit Mean-Elements Message format for TLE data.""" import csv import xml.etree.ElementTree as ET from datetime import datetime from math import pi from sgp4.api import WGS72 def parse_csv(file): return csv.DictReader(file) def parse_xml(file): root = ET.parse(file).getroot() for segment in root.findall('.//segment'): metadata = segment.find('metadata') data = segment.find('data') meanElements = data.find('meanElements') tleParameters = data.find('tleParameters') fields = {} for element in metadata, meanElements, tleParameters: fields.update((field.tag, field.text) for field in element) yield fields _epoch0 = datetime(1949, 12, 31) _to_radians = pi / 180.0 _ndot_units = 1036800.0 / pi # See SGP4.cpp for details. _nddot_units = 2985984000.0 / 2.0 / pi # See SGP4.cpp for details. def initialize(sat, fields): sat.classification = fields['CLASSIFICATION_TYPE'] sat.intldesg = fields['OBJECT_ID'][2:].replace('-', '') sat.ephtype = int(fields['EPHEMERIS_TYPE']) sat.elnum = int(fields['ELEMENT_SET_NO']) sat.revnum = int(fields['REV_AT_EPOCH']) epoch_datetime = datetime.strptime(fields['EPOCH'], '%Y-%m-%dT%H:%M:%S.%f') epoch = (epoch_datetime - _epoch0).total_seconds() / 86400.0 argpo = float(fields['ARG_OF_PERICENTER']) * _to_radians bstar = float(fields['BSTAR']) ecco = float(fields['ECCENTRICITY']) inclo = float(fields['INCLINATION']) * _to_radians mo = float(fields['MEAN_ANOMALY']) * _to_radians nddot = float(fields['MEAN_MOTION_DDOT']) / _nddot_units ndot = float(fields['MEAN_MOTION_DOT']) / _ndot_units no_kozai = float(fields['MEAN_MOTION']) / 720.0 * pi nodeo = float(fields['RA_OF_ASC_NODE']) * _to_radians satnum = int(fields['NORAD_CAT_ID']) sat.sgp4init(WGS72, 'i', satnum, epoch, bstar, ndot, nddot, ecco, argpo, inclo, mo, no_kozai, nodeo) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/propagation.py0000644000175100001730000022140114422467341015476 0ustar00runnerdocker"""The sgp4 procedures for analytical propagation of a satellite. I have made the rather unorthodox decision to leave as much of this C++ code alone as possible: if a line of code would run without change in Python, then I refused to re-indent it or remove its terminal semicolon, so that in the future it will be easier to keep updating this file as the original author's C++ continues to improve. Thus, 5-space indentation (!) prevails in this file. I have even kept all of the C++ block comments (by turning them into Python string constants) to make this easier to navigate and maintain, as well as to make it more informative for people who encounter this code for the first time here in its Python form. | - Brandon Rhodes | Common Grounds Coffee House, Bluffton, Ohio | On a very hot August day in 2012 """ from math import atan2, cos, fabs, pi, sin, sqrt from sgp4.alpha5 import to_alpha5 deg2rad = pi / 180.0; _nan = float('NaN') false = (_nan, _nan, _nan) true = True twopi = 2.0 * pi """ /* ---------------------------------------------------------------- * * sgp4unit.cpp * * this file contains the sgp4 procedures for analytical propagation * of a satellite. the code was originally released in the 1980 and 1986 * spacetrack papers. a detailed discussion of the theory and history * may be found in the 2006 aiaa paper by vallado, crawford, hujsak, * and kelso. * * companion code for * fundamentals of astrodynamics and applications * 2013 * by david vallado * * (w) 719-573-2600, email dvallado@agi.com, davallado@gmail.com * * current : * 7 dec 15 david vallado * fix jd, jdfrac * changes : * 3 nov 14 david vallado * update to msvs2013 c++ * 30 aug 10 david vallado * delete unused variables in initl * replace pow integer 2, 3 with multiplies for speed * 3 nov 08 david vallado * put returns in for error codes * 29 sep 08 david vallado * fix atime for faster operation in dspace * add operationmode for afspc (a) or improved (i) * performance mode * 16 jun 08 david vallado * update small eccentricity check * 16 nov 07 david vallado * misc fixes for better compliance * 20 apr 07 david vallado * misc fixes for constants * 11 aug 06 david vallado * chg lyddane choice back to strn3, constants, misc doc * 15 dec 05 david vallado * misc fixes * 26 jul 05 david vallado * fixes for paper * note that each fix is preceded by a * comment with "sgp4fix" and an explanation of * what was changed * 10 aug 04 david vallado * 2nd printing baseline working * 14 may 01 david vallado * 2nd edition baseline * 80 norad * original baseline * ---------------------------------------------------------------- */ """ """ /* ----------------------------------------------------------------------------- * * procedure dpper * * this procedure provides deep space long period periodic contributions * to the mean elements. by design, these periodics are zero at epoch. * this used to be dscom which included initialization, but it's really a * recurring function. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * e3 - * ee2 - * peo - * pgho - * pho - * pinco - * plo - * se2 , se3 , sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4 - * t - * xh2, xh3, xi2, xi3, xl2, xl3, xl4 - * zmol - * zmos - * ep - eccentricity 0.0 - 1.0 * inclo - inclination - needed for lyddane modification * nodep - right ascension of ascending node * argpp - argument of perigee * mp - mean anomaly * * outputs : * ep - eccentricity 0.0 - 1.0 * inclp - inclination * nodep - right ascension of ascending node * argpp - argument of perigee * mp - mean anomaly * * locals : * alfdp - * betdp - * cosip , sinip , cosop , sinop , * dalf - * dbet - * dls - * f2, f3 - * pe - * pgh - * ph - * pinc - * pl - * sel , ses , sghl , sghs , shl , shs , sil , sinzf , sis , * sll , sls * xls - * xnoh - * zf - * zm - * * coupling : * none. * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ """ def _dpper(satrec, inclo, init, ep, inclp, nodep, argpp, mp, opsmode): # Copy satellite attributes into local variables for convenience # and symmetry in writing formulae. e3 = satrec.e3 ee2 = satrec.ee2 peo = satrec.peo pgho = satrec.pgho pho = satrec.pho pinco = satrec.pinco plo = satrec.plo se2 = satrec.se2 se3 = satrec.se3 sgh2 = satrec.sgh2 sgh3 = satrec.sgh3 sgh4 = satrec.sgh4 sh2 = satrec.sh2 sh3 = satrec.sh3 si2 = satrec.si2 si3 = satrec.si3 sl2 = satrec.sl2 sl3 = satrec.sl3 sl4 = satrec.sl4 t = satrec.t xgh2 = satrec.xgh2 xgh3 = satrec.xgh3 xgh4 = satrec.xgh4 xh2 = satrec.xh2 xh3 = satrec.xh3 xi2 = satrec.xi2 xi3 = satrec.xi3 xl2 = satrec.xl2 xl3 = satrec.xl3 xl4 = satrec.xl4 zmol = satrec.zmol zmos = satrec.zmos # ---------------------- constants ----------------------------- zns = 1.19459e-5; zes = 0.01675; znl = 1.5835218e-4; zel = 0.05490; # --------------- calculate time varying periodics ----------- zm = zmos + zns * t; # be sure that the initial call has time set to zero if init == 'y': zm = zmos; zf = zm + 2.0 * zes * sin(zm); sinzf = sin(zf); f2 = 0.5 * sinzf * sinzf - 0.25; f3 = -0.5 * sinzf * cos(zf); ses = se2* f2 + se3 * f3; sis = si2 * f2 + si3 * f3; sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf; sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf; shs = sh2 * f2 + sh3 * f3; zm = zmol + znl * t; if init == 'y': zm = zmol; zf = zm + 2.0 * zel * sin(zm); sinzf = sin(zf); f2 = 0.5 * sinzf * sinzf - 0.25; f3 = -0.5 * sinzf * cos(zf); sel = ee2 * f2 + e3 * f3; sil = xi2 * f2 + xi3 * f3; sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf; sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf; shll = xh2 * f2 + xh3 * f3; pe = ses + sel; pinc = sis + sil; pl = sls + sll; pgh = sghs + sghl; ph = shs + shll; if init == 'n': pe = pe - peo; pinc = pinc - pinco; pl = pl - plo; pgh = pgh - pgho; ph = ph - pho; inclp = inclp + pinc; ep = ep + pe; sinip = sin(inclp); cosip = cos(inclp); """ /* ----------------- apply periodics directly ------------ */ // sgp4fix for lyddane choice // strn3 used original inclination - this is technically feasible // gsfc used perturbed inclination - also technically feasible // probably best to readjust the 0.2 limit value and limit discontinuity // 0.2 rad = 11.45916 deg // use next line for original strn3 approach and original inclination // if (inclo >= 0.2) // use next line for gsfc version and perturbed inclination """ if inclp >= 0.2: ph /= sinip pgh -= cosip * ph argpp += pgh nodep += ph mp += pl else: # ---- apply periodics with lyddane modification ---- sinop = sin(nodep); cosop = cos(nodep); alfdp = sinip * sinop; betdp = sinip * cosop; dalf = ph * cosop + pinc * cosip * sinop; dbet = -ph * sinop + pinc * cosip * cosop; alfdp = alfdp + dalf; betdp = betdp + dbet; nodep = nodep % twopi if nodep >= 0.0 else -(-nodep % twopi) # sgp4fix for afspc written intrinsic functions # nodep used without a trigonometric function ahead if nodep < 0.0 and opsmode == 'a': nodep = nodep + twopi; xls = mp + argpp + pl + pgh + (cosip - pinc * sinip) * nodep xnoh = nodep; nodep = atan2(alfdp, betdp); # sgp4fix for afspc written intrinsic functions # nodep used without a trigonometric function ahead if nodep < 0.0 and opsmode == 'a': nodep = nodep + twopi; if fabs(xnoh - nodep) > pi: if nodep < xnoh: nodep = nodep + twopi; else: nodep = nodep - twopi; mp += pl argpp = xls - mp - cosip * nodep; return ep, inclp, nodep, argpp, mp """ /*----------------------------------------------------------------------------- * * procedure dscom * * this procedure provides deep space common items used by both the secular * and periodics subroutines. input is provided as shown. this routine * used to be called dpper, but the functions inside weren't well organized. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * epoch - * ep - eccentricity * argpp - argument of perigee * tc - * inclp - inclination * nodep - right ascension of ascending node * np - mean motion * * outputs : * sinim , cosim , sinomm , cosomm , snodm , cnodm * day - * e3 - * ee2 - * em - eccentricity * emsq - eccentricity squared * gam - * peo - * pgho - * pho - * pinco - * plo - * rtemsq - * se2, se3 - * sgh2, sgh3, sgh4 - * sh2, sh3, si2, si3, sl2, sl3, sl4 - * s1, s2, s3, s4, s5, s6, s7 - * ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3 - * sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - * xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4 - * nm - mean motion * z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33 - * zmol - * zmos - * * locals : * a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 - * betasq - * cc - * ctem, stem - * x1, x2, x3, x4, x5, x6, x7, x8 - * xnodce - * xnoi - * zcosg , zsing , zcosgl , zsingl , zcosh , zsinh , zcoshl , zsinhl , * zcosi , zsini , zcosil , zsinil , * zx - * zy - * * coupling : * none. * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ """ def _dscom( epoch, ep, argpp, tc, inclp, nodep, np, e3, ee2, peo, pgho, pho, pinco, plo, se2, se3, sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4, xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4, zmol, zmos, ): # -------------------------- constants ------------------------- zes = 0.01675; zel = 0.05490; c1ss = 2.9864797e-6; c1l = 4.7968065e-7; zsinis = 0.39785416; zcosis = 0.91744867; zcosgs = 0.1945905; zsings = -0.98088458; # --------------------- local variables ------------------------ nm = np; em = ep; snodm = sin(nodep); cnodm = cos(nodep); sinomm = sin(argpp); cosomm = cos(argpp); sinim = sin(inclp); cosim = cos(inclp); emsq = em * em; betasq = 1.0 - emsq; rtemsq = sqrt(betasq); # ----------------- initialize lunar solar terms --------------- peo = 0.0; pinco = 0.0; plo = 0.0; pgho = 0.0; pho = 0.0; day = epoch + 18261.5 + tc / 1440.0; xnodce = (4.5236020 - 9.2422029e-4 * day) % twopi stem = sin(xnodce); ctem = cos(xnodce); zcosil = 0.91375164 - 0.03568096 * ctem; zsinil = sqrt(1.0 - zcosil * zcosil); zsinhl = 0.089683511 * stem / zsinil; zcoshl = sqrt(1.0 - zsinhl * zsinhl); gam = 5.8351514 + 0.0019443680 * day; zx = 0.39785416 * stem / zsinil; zy = zcoshl * ctem + 0.91744867 * zsinhl * stem; zx = atan2(zx, zy); zx = gam + zx - xnodce; zcosgl = cos(zx); zsingl = sin(zx); # ------------------------- do solar terms --------------------- zcosg = zcosgs; zsing = zsings; zcosi = zcosis; zsini = zsinis; zcosh = cnodm; zsinh = snodm; cc = c1ss; xnoi = 1.0 / nm; for lsflg in 1, 2: a1 = zcosg * zcosh + zsing * zcosi * zsinh; a3 = -zsing * zcosh + zcosg * zcosi * zsinh; a7 = -zcosg * zsinh + zsing * zcosi * zcosh; a8 = zsing * zsini; a9 = zsing * zsinh + zcosg * zcosi * zcosh; a10 = zcosg * zsini; a2 = cosim * a7 + sinim * a8; a4 = cosim * a9 + sinim * a10; a5 = -sinim * a7 + cosim * a8; a6 = -sinim * a9 + cosim * a10; x1 = a1 * cosomm + a2 * sinomm; x2 = a3 * cosomm + a4 * sinomm; x3 = -a1 * sinomm + a2 * cosomm; x4 = -a3 * sinomm + a4 * cosomm; x5 = a5 * sinomm; x6 = a6 * sinomm; x7 = a5 * cosomm; x8 = a6 * cosomm; z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3; z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4; z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4; z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq; z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq; z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq; z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7-6.0 * x3 * x5); z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * \ (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5)); z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6); z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7); z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * \ (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8)); z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8); z1 = z1 + z1 + betasq * z31; z2 = z2 + z2 + betasq * z32; z3 = z3 + z3 + betasq * z33; s3 = cc * xnoi; s2 = -0.5 * s3 / rtemsq; s4 = s3 * rtemsq; s1 = -15.0 * em * s4; s5 = x1 * x3 + x2 * x4; s6 = x2 * x3 + x1 * x4; s7 = x2 * x4 - x1 * x3; # ----------------------- do lunar terms ------------------- if lsflg == 1: ss1 = s1; ss2 = s2; ss3 = s3; ss4 = s4; ss5 = s5; ss6 = s6; ss7 = s7; sz1 = z1; sz2 = z2; sz3 = z3; sz11 = z11; sz12 = z12; sz13 = z13; sz21 = z21; sz22 = z22; sz23 = z23; sz31 = z31; sz32 = z32; sz33 = z33; zcosg = zcosgl; zsing = zsingl; zcosi = zcosil; zsini = zsinil; zcosh = zcoshl * cnodm + zsinhl * snodm; zsinh = snodm * zcoshl - cnodm * zsinhl; cc = c1l; zmol = (4.7199672 + 0.22997150 * day - gam) % twopi zmos = (6.2565837 + 0.017201977 * day) % twopi # ------------------------ do solar terms ---------------------- se2 = 2.0 * ss1 * ss6; se3 = 2.0 * ss1 * ss7; si2 = 2.0 * ss2 * sz12; si3 = 2.0 * ss2 * (sz13 - sz11); sl2 = -2.0 * ss3 * sz2; sl3 = -2.0 * ss3 * (sz3 - sz1); sl4 = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes; sgh2 = 2.0 * ss4 * sz32; sgh3 = 2.0 * ss4 * (sz33 - sz31); sgh4 = -18.0 * ss4 * zes; sh2 = -2.0 * ss2 * sz22; sh3 = -2.0 * ss2 * (sz23 - sz21); # ------------------------ do lunar terms ---------------------- ee2 = 2.0 * s1 * s6; e3 = 2.0 * s1 * s7; xi2 = 2.0 * s2 * z12; xi3 = 2.0 * s2 * (z13 - z11); xl2 = -2.0 * s3 * z2; xl3 = -2.0 * s3 * (z3 - z1); xl4 = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel; xgh2 = 2.0 * s4 * z32; xgh3 = 2.0 * s4 * (z33 - z31); xgh4 = -18.0 * s4 * zel; xh2 = -2.0 * s2 * z22; xh3 = -2.0 * s2 * (z23 - z21); return ( snodm, cnodm, sinim, cosim, sinomm, cosomm,day, e3, ee2, em, emsq, gam, peo, pgho, pho, pinco, plo, rtemsq, se2, se3, sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4, s1, s2, s3, s4, s5, s6, s7, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4, nm, z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33, zmol, zmos ) """ /*----------------------------------------------------------------------------- * * procedure dsinit * * this procedure provides deep space contributions to mean motion dot due * to geopotential resonance with half day and one day orbits. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * cosim, sinim- * emsq - eccentricity squared * argpo - argument of perigee * s1, s2, s3, s4, s5 - * ss1, ss2, ss3, ss4, ss5 - * sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33 - * t - time * tc - * gsto - greenwich sidereal time rad * mo - mean anomaly * mdot - mean anomaly dot (rate) * no - mean motion * nodeo - right ascension of ascending node * nodedot - right ascension of ascending node dot (rate) * xpidot - * z1, z3, z11, z13, z21, z23, z31, z33 - * eccm - eccentricity * argpm - argument of perigee * inclm - inclination * mm - mean anomaly * xn - mean motion * nodem - right ascension of ascending node * * outputs : * em - eccentricity * argpm - argument of perigee * inclm - inclination * mm - mean anomaly * nm - mean motion * nodem - right ascension of ascending node * irez - flag for resonance 0-none, 1-one day, 2-half day * atime - * d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - * dedt - * didt - * dmdt - * dndt - * dnodt - * domdt - * del1, del2, del3 - * ses , sghl , sghs , sgs , shl , shs , sis , sls * theta - * xfact - * xlamo - * xli - * xni * * locals : * ainv2 - * aonv - * cosisq - * eoc - * f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543 - * g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533 - * sini2 - * temp - * temp1 - * theta - * xno2 - * * coupling : * getgravconst * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ """ def _dsinit( # sgp4fix no longer needed pass in xke # whichconst, xke, cosim, emsq, argpo, s1, s2, s3, s4, s5, sinim, ss1, ss2, ss3, ss4, ss5, sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33, t, tc, gsto, mo, mdot, no, nodeo, nodedot, xpidot, z1, z3, z11, z13, z21, z23, z31, z33, ecco, eccsq, em, argpm, inclm, mm, nm, nodem, irez, atime, d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433, dedt, didt, dmdt, dnodt, domdt, del1, del2, del3, xfact, xlamo, xli, xni, ): q22 = 1.7891679e-6; q31 = 2.1460748e-6; q33 = 2.2123015e-7; root22 = 1.7891679e-6; root44 = 7.3636953e-9; root54 = 2.1765803e-9; rptim = 4.37526908801129966e-3; # equates to 7.29211514668855e-5 rad/sec root32 = 3.7393792e-7; root52 = 1.1428639e-7; x2o3 = 2.0 / 3.0; znl = 1.5835218e-4; zns = 1.19459e-5; # sgp4fix identify constants and allow alternate values # just xke is used here so pass it in rather than have multiple calls # xke = whichconst.xke # -------------------- deep space initialization ------------ irez = 0; if 0.0034906585 < nm < 0.0052359877: irez = 1; if 8.26e-3 <= nm <= 9.24e-3 and em >= 0.5: irez = 2; # ------------------------ do solar terms ------------------- ses = ss1 * zns * ss5; sis = ss2 * zns * (sz11 + sz13); sls = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq); sghs = ss4 * zns * (sz31 + sz33 - 6.0); shs = -zns * ss2 * (sz21 + sz23); # sgp4fix for 180 deg incl if inclm < 5.2359877e-2 or inclm > pi - 5.2359877e-2: shs = 0.0; if sinim != 0.0: shs = shs / sinim; sgs = sghs - cosim * shs; # ------------------------- do lunar terms ------------------ dedt = ses + s1 * znl * s5; didt = sis + s2 * znl * (z11 + z13); dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq); sghl = s4 * znl * (z31 + z33 - 6.0); shll = -znl * s2 * (z21 + z23); # sgp4fix for 180 deg incl if inclm < 5.2359877e-2 or inclm > pi - 5.2359877e-2: shll = 0.0; domdt = sgs + sghl; dnodt = shs; if sinim != 0.0: domdt = domdt - cosim / sinim * shll; dnodt = dnodt + shll / sinim; # ----------- calculate deep space resonance effects -------- dndt = 0.0; theta = (gsto + tc * rptim) % twopi em = em + dedt * t; inclm = inclm + didt * t; argpm = argpm + domdt * t; nodem = nodem + dnodt * t; mm = mm + dmdt * t; """ // sgp4fix for negative inclinations // the following if statement should be commented out //if (inclm < 0.0) // { // inclm = -inclm; // argpm = argpm - pi; // nodem = nodem + pi; // } """ # -------------- initialize the resonance terms ------------- if irez != 0: aonv = pow(nm / xke, x2o3); # ---------- geopotential resonance for 12 hour orbits ------ if irez == 2: cosisq = cosim * cosim; emo = em; em = ecco; emsqo = emsq; emsq = eccsq; eoc = em * emsq; g201 = -0.306 - (em - 0.64) * 0.440; if em <= 0.65: g211 = 3.616 - 13.2470 * em + 16.2900 * emsq; g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc; g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc; g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc; g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc; g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc; else: g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc; g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc; g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc; g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc; g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc; if em > 0.715: g520 =-5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc; else: g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq; if em < 0.7: g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc; g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc; g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc; else: g533 =-37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc; g521 =-51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc; g532 =-40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc; sini2= sinim * sinim; f220 = 0.75 * (1.0 + 2.0 * cosim+cosisq); f221 = 1.5 * sini2; f321 = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq); f322 = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq); f441 = 35.0 * sini2 * f220; f442 = 39.3750 * sini2 * sini2; f522 = 9.84375 * sinim * (sini2 * (1.0 - 2.0 * cosim- 5.0 * cosisq) + 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq) ); f523 = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + 10.0 * cosisq) + 6.56250012 * (1.0+2.0 * cosim - 3.0 * cosisq)); f542 = 29.53125 * sinim * (2.0 - 8.0 * cosim+cosisq * (-12.0 + 8.0 * cosim + 10.0 * cosisq)); f543 = 29.53125 * sinim * (-2.0 - 8.0 * cosim+cosisq * (12.0 + 8.0 * cosim - 10.0 * cosisq)); xno2 = nm * nm; ainv2 = aonv * aonv; temp1 = 3.0 * xno2 * ainv2; temp = temp1 * root22; d2201 = temp * f220 * g201; d2211 = temp * f221 * g211; temp1 = temp1 * aonv; temp = temp1 * root32; d3210 = temp * f321 * g310; d3222 = temp * f322 * g322; temp1 = temp1 * aonv; temp = 2.0 * temp1 * root44; d4410 = temp * f441 * g410; d4422 = temp * f442 * g422; temp1 = temp1 * aonv; temp = temp1 * root52; d5220 = temp * f522 * g520; d5232 = temp * f523 * g532; temp = 2.0 * temp1 * root54; d5421 = temp * f542 * g521; d5433 = temp * f543 * g533; xlamo = (mo + nodeo + nodeo-theta - theta) % twopi xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - no; em = emo; emsq = emsqo; # ---------------- synchronous resonance terms -------------- if irez == 1: g200 = 1.0 + emsq * (-2.5 + 0.8125 * emsq); g310 = 1.0 + 2.0 * emsq; g300 = 1.0 + emsq * (-6.0 + 6.60937 * emsq); f220 = 0.75 * (1.0 + cosim) * (1.0 + cosim); f311 = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim); f330 = 1.0 + cosim; f330 = 1.875 * f330 * f330 * f330; del1 = 3.0 * nm * nm * aonv * aonv; del2 = 2.0 * del1 * f220 * g200 * q22; del3 = 3.0 * del1 * f330 * g300 * q33 * aonv; del1 = del1 * f311 * g310 * q31 * aonv; xlamo = (mo + nodeo + argpo - theta) % twopi xfact = mdot + xpidot - rptim + dmdt + domdt + dnodt - no; # ------------ for sgp4, initialize the integrator ---------- xli = xlamo; xni = no; atime = 0.0; nm = no + dndt; return ( em, argpm, inclm, mm, nm, nodem, irez, atime, d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433, dedt, didt, dmdt, dndt, dnodt, domdt, del1, del2, del3, xfact, xlamo, xli, xni, ) """ /*----------------------------------------------------------------------------- * * procedure dspace * * this procedure provides deep space contributions to mean elements for * perturbing third body. these effects have been averaged over one * revolution of the sun and moon. for earth resonance effects, the * effects have been averaged over no revolutions of the satellite. * (mean motion) * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - * dedt - * del1, del2, del3 - * didt - * dmdt - * dnodt - * domdt - * irez - flag for resonance 0-none, 1-one day, 2-half day * argpo - argument of perigee * argpdot - argument of perigee dot (rate) * t - time * tc - * gsto - gst * xfact - * xlamo - * no - mean motion * atime - * em - eccentricity * ft - * argpm - argument of perigee * inclm - inclination * xli - * mm - mean anomaly * xni - mean motion * nodem - right ascension of ascending node * * outputs : * atime - * em - eccentricity * argpm - argument of perigee * inclm - inclination * xli - * mm - mean anomaly * xni - * nodem - right ascension of ascending node * dndt - * nm - mean motion * * locals : * delt - * ft - * theta - * x2li - * x2omi - * xl - * xldot - * xnddt - * xndt - * xomi - * * coupling : * none - * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ """ def _dspace( irez, d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433, dedt, del1, del2, del3, didt, dmdt, dnodt, domdt, argpo, argpdot, t, tc, gsto, xfact, xlamo, no, atime, em, argpm, inclm, xli, mm, xni, nodem, nm, ): fasx2 = 0.13130908; fasx4 = 2.8843198; fasx6 = 0.37448087; g22 = 5.7686396; g32 = 0.95240898; g44 = 1.8014998; g52 = 1.0508330; g54 = 4.4108898; rptim = 4.37526908801129966e-3; # equates to 7.29211514668855e-5 rad/sec stepp = 720.0; stepn = -720.0; step2 = 259200.0; # ----------- calculate deep space resonance effects ----------- dndt = 0.0; theta = (gsto + tc * rptim) % twopi em = em + dedt * t; inclm = inclm + didt * t; argpm = argpm + domdt * t; nodem = nodem + dnodt * t; mm = mm + dmdt * t; """ // sgp4fix for negative inclinations // the following if statement should be commented out // if (inclm < 0.0) // { // inclm = -inclm; // argpm = argpm - pi; // nodem = nodem + pi; // } /* - update resonances : numerical (euler-maclaurin) integration - */ /* ------------------------- epoch restart ---------------------- */ // sgp4fix for propagator problems // the following integration works for negative time steps and periods // the specific changes are unknown because the original code was so convoluted // sgp4fix take out atime = 0.0 and fix for faster operation """ ft = 0.0; if irez != 0: # sgp4fix streamline check if atime == 0.0 or t * atime <= 0.0 or fabs(t) < fabs(atime): atime = 0.0; xni = no; xli = xlamo; # sgp4fix move check outside loop if t > 0.0: delt = stepp; else: delt = stepn; iretn = 381; # added for do loop # iret = 0; # added for loop while iretn == 381: # ------------------- dot terms calculated ------------- # ----------- near - synchronous resonance terms ------- if irez != 2: xndt = del1 * sin(xli - fasx2) + del2 * sin(2.0 * (xli - fasx4)) + \ del3 * sin(3.0 * (xli - fasx6)); xldot = xni + xfact; xnddt = del1 * cos(xli - fasx2) + \ 2.0 * del2 * cos(2.0 * (xli - fasx4)) + \ 3.0 * del3 * cos(3.0 * (xli - fasx6)); xnddt = xnddt * xldot; else: # --------- near - half-day resonance terms -------- xomi = argpo + argpdot * atime; x2omi = xomi + xomi; x2li = xli + xli; xndt = (d2201 * sin(x2omi + xli - g22) + d2211 * sin(xli - g22) + d3210 * sin(xomi + xli - g32) + d3222 * sin(-xomi + xli - g32)+ d4410 * sin(x2omi + x2li - g44)+ d4422 * sin(x2li - g44) + d5220 * sin(xomi + xli - g52) + d5232 * sin(-xomi + xli - g52)+ d5421 * sin(xomi + x2li - g54) + d5433 * sin(-xomi + x2li - g54)); xldot = xni + xfact; xnddt = (d2201 * cos(x2omi + xli - g22) + d2211 * cos(xli - g22) + d3210 * cos(xomi + xli - g32) + d3222 * cos(-xomi + xli - g32) + d5220 * cos(xomi + xli - g52) + d5232 * cos(-xomi + xli - g52) + 2.0 * (d4410 * cos(x2omi + x2li - g44) + d4422 * cos(x2li - g44) + d5421 * cos(xomi + x2li - g54) + d5433 * cos(-xomi + x2li - g54))); xnddt = xnddt * xldot; # ----------------------- integrator ------------------- # sgp4fix move end checks to end of routine if fabs(t - atime) >= stepp: # iret = 0; iretn = 381; else: ft = t - atime; iretn = 0; if iretn == 381: xli = xli + xldot * delt + xndt * step2; xni = xni + xndt * delt + xnddt * step2; atime = atime + delt; nm = xni + xndt * ft + xnddt * ft * ft * 0.5; xl = xli + xldot * ft + xndt * ft * ft * 0.5; if irez != 1: mm = xl - 2.0 * nodem + 2.0 * theta; dndt = nm - no; else: mm = xl - nodem - argpm + theta; dndt = nm - no; nm = no + dndt; return ( atime, em, argpm, inclm, xli, mm, xni, nodem, dndt, nm, ) """ /*----------------------------------------------------------------------------- * * procedure initl * * this procedure initializes the spg4 propagator. all the initialization is * consolidated here instead of having multiple loops inside other routines. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * satn - satellite number - not needed, placed in satrec * xke - reciprocal of tumin * j2 - j2 zonal harmonic * ecco - eccentricity 0.0 - 1.0 * epoch - epoch time in days from jan 0, 1950. 0 hr * inclo - inclination of satellite * no - mean motion of satellite * * outputs : * ainv - 1.0 / a * ao - semi major axis * con41 - * con42 - 1.0 - 5.0 cos(i) * cosio - cosine of inclination * cosio2 - cosio squared * eccsq - eccentricity squared * method - flag for deep space 'd', 'n' * omeosq - 1.0 - ecco * ecco * posq - semi-parameter squared * rp - radius of perigee * rteosq - square root of (1.0 - ecco*ecco) * sinio - sine of inclination * gsto - gst at time of observation rad * no - mean motion of satellite * * locals : * ak - * d1 - * del - * adel - * po - * * coupling : * getgravconst- no longer used * gstime - find greenwich sidereal time from the julian date * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ """ def _initl( # not needeed. included in satrec if needed later # satn, # sgp4fix assin xke and j2 # whichconst, xke, j2, ecco, epoch, inclo, no, method, opsmode, ): # sgp4fix use old way of finding gst # ----------------------- earth constants ---------------------- # sgp4fix identify constants and allow alternate values # only xke and j2 are used here so pass them in directly # tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 = whichconst x2o3 = 2.0 / 3.0; # ------------- calculate auxillary epoch quantities ---------- eccsq = ecco * ecco; omeosq = 1.0 - eccsq; rteosq = sqrt(omeosq); cosio = cos(inclo); cosio2 = cosio * cosio; # ------------------ un-kozai the mean motion ----------------- ak = pow(xke / no, x2o3); d1 = 0.75 * j2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq); del_ = d1 / (ak * ak); adel = ak * (1.0 - del_ * del_ - del_ * (1.0 / 3.0 + 134.0 * del_ * del_ / 81.0)); del_ = d1/(adel * adel); no = no / (1.0 + del_); ao = pow(xke / no, x2o3); sinio = sin(inclo); po = ao * omeosq; con42 = 1.0 - 5.0 * cosio2; con41 = -con42-cosio2-cosio2; ainv = 1.0 / ao; posq = po * po; rp = ao * (1.0 - ecco); method = 'n'; # sgp4fix modern approach to finding sidereal time if opsmode == 'a': # sgp4fix use old way of finding gst # count integer number of days from 0 jan 1970 ts70 = epoch - 7305.0; ds70 = (ts70 + 1.0e-8) // 1.0; tfrac = ts70 - ds70; # find greenwich location at epoch c1 = 1.72027916940703639e-2; thgr70= 1.7321343856509374; fk5r = 5.07551419432269442e-15; c1p2p = c1 + twopi; gsto = (thgr70 + c1*ds70 + c1p2p*tfrac + ts70*ts70*fk5r) % twopi if gsto < 0.0: gsto = gsto + twopi; else: gsto = _gstime(epoch + 2433281.5); return ( no, method, ainv, ao, con41, con42, cosio, cosio2,eccsq, omeosq, posq, rp, rteosq,sinio , gsto, ) """ /*----------------------------------------------------------------------------- * * procedure sgp4init * * this procedure initializes variables for sgp4. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * opsmode - mode of operation afspc or improved 'a', 'i' * whichconst - which set of constants to use 72, 84 * satn - satellite number * bstar - sgp4 type drag coefficient kg/m2er * ecco - eccentricity * epoch - epoch time in days from jan 0, 1950. 0 hr * argpo - argument of perigee (output if ds) * inclo - inclination * mo - mean anomaly (output if ds) * no - mean motion * nodeo - right ascension of ascending node * * outputs : * satrec - common values for subsequent calls * return code - non-zero on error. * 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er * 2 - mean motion less than 0.0 * 3 - pert elements, ecc < 0.0 or ecc > 1.0 * 4 - semi-latus rectum < 0.0 * 5 - epoch elements are sub-orbital * 6 - satellite has decayed * * locals : * cnodm , snodm , cosim , sinim , cosomm , sinomm * cc1sq , cc2 , cc3 * coef , coef1 * cosio4 - * day - * dndt - * em - eccentricity * emsq - eccentricity squared * eeta - * etasq - * gam - * argpm - argument of perigee * nodem - * inclm - inclination * mm - mean anomaly * nm - mean motion * perige - perigee * pinvsq - * psisq - * qzms24 - * rtemsq - * s1, s2, s3, s4, s5, s6, s7 - * sfour - * ss1, ss2, ss3, ss4, ss5, ss6, ss7 - * sz1, sz2, sz3 * sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - * tc - * temp - * temp1, temp2, temp3 - * tsi - * xpidot - * xhdot1 - * z1, z2, z3 - * z11, z12, z13, z21, z22, z23, z31, z32, z33 - * * coupling : * getgravconst- * initl - * dscom - * dpper - * dsinit - * sgp4 - * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ """ def sgp4init( whichconst, opsmode, satn, epoch, xbstar, xndot, xnddot, xecco, xargpo, xinclo, xmo, xno_kozai, xnodeo, satrec, ): """ /* ------------------------ initialization --------------------- */ // sgp4fix divisor for divide by zero check on inclination // the old check used 1.0 + cos(pi-1.0e-9), but then compared it to // 1.5 e-12, so the threshold was changed to 1.5e-12 for consistency """ temp4 = 1.5e-12; # ----------- set all near earth variables to zero ------------ satrec.isimp = 0; satrec.method = 'n'; satrec.aycof = 0.0; satrec.con41 = 0.0; satrec.cc1 = 0.0; satrec.cc4 = 0.0; satrec.cc5 = 0.0; satrec.d2 = 0.0; satrec.d3 = 0.0; satrec.d4 = 0.0; satrec.delmo = 0.0; satrec.eta = 0.0; satrec.argpdot = 0.0; satrec.omgcof = 0.0; satrec.sinmao = 0.0; satrec.t = 0.0; satrec.t2cof = 0.0; satrec.t3cof = 0.0; satrec.t4cof = 0.0; satrec.t5cof = 0.0; satrec.x1mth2 = 0.0; satrec.x7thm1 = 0.0; satrec.mdot = 0.0; satrec.nodedot = 0.0; satrec.xlcof = 0.0; satrec.xmcof = 0.0; satrec.nodecf = 0.0; # ----------- set all deep space variables to zero ------------ satrec.irez = 0; satrec.d2201 = 0.0; satrec.d2211 = 0.0; satrec.d3210 = 0.0; satrec.d3222 = 0.0; satrec.d4410 = 0.0; satrec.d4422 = 0.0; satrec.d5220 = 0.0; satrec.d5232 = 0.0; satrec.d5421 = 0.0; satrec.d5433 = 0.0; satrec.dedt = 0.0; satrec.del1 = 0.0; satrec.del2 = 0.0; satrec.del3 = 0.0; satrec.didt = 0.0; satrec.dmdt = 0.0; satrec.dnodt = 0.0; satrec.domdt = 0.0; satrec.e3 = 0.0; satrec.ee2 = 0.0; satrec.peo = 0.0; satrec.pgho = 0.0; satrec.pho = 0.0; satrec.pinco = 0.0; satrec.plo = 0.0; satrec.se2 = 0.0; satrec.se3 = 0.0; satrec.sgh2 = 0.0; satrec.sgh3 = 0.0; satrec.sgh4 = 0.0; satrec.sh2 = 0.0; satrec.sh3 = 0.0; satrec.si2 = 0.0; satrec.si3 = 0.0; satrec.sl2 = 0.0; satrec.sl3 = 0.0; satrec.sl4 = 0.0; satrec.gsto = 0.0; satrec.xfact = 0.0; satrec.xgh2 = 0.0; satrec.xgh3 = 0.0; satrec.xgh4 = 0.0; satrec.xh2 = 0.0; satrec.xh3 = 0.0; satrec.xi2 = 0.0; satrec.xi3 = 0.0; satrec.xl2 = 0.0; satrec.xl3 = 0.0; satrec.xl4 = 0.0; satrec.xlamo = 0.0; satrec.zmol = 0.0; satrec.zmos = 0.0; satrec.atime = 0.0; satrec.xli = 0.0; satrec.xni = 0.0; # ------------------------ earth constants ----------------------- # sgp4fix identify constants and allow alternate values # this is now the only call for the constants (satrec.tumin, satrec.mu, satrec.radiusearthkm, satrec.xke, satrec.j2, satrec.j3, satrec.j4, satrec.j3oj2) = whichconst; # ------------------------------------------------------------------------- # The SGP4 library has changed `satn` from an integer to a string. # But to avoid breaking our API contract with existing Python code, # we are still willing to accept an integer. if isinstance(satn, int): satn = to_alpha5(satn) satrec.error = 0; satrec.operationmode = opsmode; satrec.satnum_str = satn; satrec.classification = 'U' # so attribute is not missing in Python """ // sgp4fix - note the following variables are also passed directly via satrec. // it is possible to streamline the sgp4init call by deleting the "x" // variables, but the user would need to set the satrec.* values first. we // include the additional assignments in case twoline2rv is not used. """ satrec.bstar = xbstar; # sgp4fix allow additional parameters in the struct satrec.ndot = xndot; satrec.nddot = xnddot; satrec.ecco = xecco; satrec.argpo = xargpo; satrec.inclo = xinclo; satrec.mo = xmo; # sgp4fix rename variables to clarify which mean motion is intended satrec.no_kozai= xno_kozai; satrec.nodeo = xnodeo; # single averaged mean elements satrec.am = 0.0 satrec.em = 0.0 satrec.im = 0.0 satrec.Om = 0.0 satrec.mm = 0.0 satrec.nm = 0.0 # ------------------------ earth constants ----------------------- */ # sgp4fix identify constants and allow alternate values no longer needed # getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); ss = 78.0 / satrec.radiusearthkm + 1.0; # sgp4fix use multiply for speed instead of pow qzms2ttemp = (120.0 - 78.0) / satrec.radiusearthkm; qzms2t = qzms2ttemp * qzms2ttemp * qzms2ttemp * qzms2ttemp; x2o3 = 2.0 / 3.0; satrec.init = 'y'; satrec.t = 0.0; # sgp4fix remove satn as it is not needed in initl ( satrec.no_unkozai, method, ainv, ao, satrec.con41, con42, cosio, cosio2,eccsq, omeosq, posq, rp, rteosq,sinio , satrec.gsto, ) = _initl( satrec.xke, satrec.j2, satrec.ecco, epoch, satrec.inclo, satrec.no_kozai, satrec.method, satrec.operationmode ); satrec.a = pow( satrec.no_unkozai*satrec.tumin , (-2.0/3.0) ); satrec.alta = satrec.a*(1.0 + satrec.ecco) - 1.0; satrec.altp = satrec.a*(1.0 - satrec.ecco) - 1.0; """ // sgp4fix remove this check as it is unnecessary // the mrt check in sgp4 handles decaying satellite cases even if the starting // condition is below the surface of te earth // if (rp < 1.0) // { // printf("# *** satn%d epoch elts sub-orbital ***\n", satn); // satrec.error = 5; // } """ if omeosq >= 0.0 or satrec.no_unkozai >= 0.0: satrec.isimp = 0; if rp < 220.0 / satrec.radiusearthkm + 1.0: satrec.isimp = 1; sfour = ss; qzms24 = qzms2t; perige = (rp - 1.0) * satrec.radiusearthkm; # - for perigees below 156 km, s and qoms2t are altered - if perige < 156.0: sfour = perige - 78.0; if perige < 98.0: sfour = 20.0; # sgp4fix use multiply for speed instead of pow qzms24temp = (120.0 - sfour) / satrec.radiusearthkm; qzms24 = qzms24temp * qzms24temp * qzms24temp * qzms24temp; sfour = sfour / satrec.radiusearthkm + 1.0; pinvsq = 1.0 / posq; tsi = 1.0 / (ao - sfour); satrec.eta = ao * satrec.ecco * tsi; etasq = satrec.eta * satrec.eta; eeta = satrec.ecco * satrec.eta; psisq = fabs(1.0 - etasq); coef = qzms24 * pow(tsi, 4.0); coef1 = coef / pow(psisq, 3.5); cc2 = coef1 * satrec.no_unkozai * (ao * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) + 0.375 * satrec.j2 * tsi / psisq * satrec.con41 * (8.0 + 3.0 * etasq * (8.0 + etasq))); satrec.cc1 = satrec.bstar * cc2; cc3 = 0.0; if satrec.ecco > 1.0e-4: cc3 = -2.0 * coef * tsi * satrec.j3oj2 * satrec.no_unkozai * sinio / satrec.ecco; satrec.x1mth2 = 1.0 - cosio2; satrec.cc4 = 2.0* satrec.no_unkozai * coef1 * ao * omeosq * \ (satrec.eta * (2.0 + 0.5 * etasq) + satrec.ecco * (0.5 + 2.0 * etasq) - satrec.j2 * tsi / (ao * psisq) * (-3.0 * satrec.con41 * (1.0 - 2.0 * eeta + etasq * (1.5 - 0.5 * eeta)) + 0.75 * satrec.x1mth2 * (2.0 * etasq - eeta * (1.0 + etasq)) * cos(2.0 * satrec.argpo))); satrec.cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * (etasq + eeta) + eeta * etasq); cosio4 = cosio2 * cosio2; temp1 = 1.5 * satrec.j2 * pinvsq * satrec.no_unkozai; temp2 = 0.5 * temp1 * satrec.j2 * pinvsq; temp3 = -0.46875 * satrec.j4 * pinvsq * pinvsq * satrec.no_unkozai; satrec.mdot = satrec.no_unkozai + 0.5 * temp1 * rteosq * satrec.con41 + 0.0625 * \ temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4); satrec.argpdot = (-0.5 * temp1 * con42 + 0.0625 * temp2 * (7.0 - 114.0 * cosio2 + 395.0 * cosio4) + temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4)); xhdot1 = -temp1 * cosio; satrec.nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio; xpidot = satrec.argpdot+ satrec.nodedot; satrec.omgcof = satrec.bstar * cc3 * cos(satrec.argpo); satrec.xmcof = 0.0; if satrec.ecco > 1.0e-4: satrec.xmcof = -x2o3 * coef * satrec.bstar / eeta; satrec.nodecf = 3.5 * omeosq * xhdot1 * satrec.cc1; satrec.t2cof = 1.5 * satrec.cc1; # sgp4fix for divide by zero with xinco = 180 deg if fabs(cosio+1.0) > 1.5e-12: satrec.xlcof = -0.25 * satrec.j3oj2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio); else: satrec.xlcof = -0.25 * satrec.j3oj2 * sinio * (3.0 + 5.0 * cosio) / temp4; satrec.aycof = -0.5 * satrec.j3oj2 * sinio; # sgp4fix use multiply for speed instead of pow delmotemp = 1.0 + satrec.eta * cos(satrec.mo); satrec.delmo = delmotemp * delmotemp * delmotemp; satrec.sinmao = sin(satrec.mo); satrec.x7thm1 = 7.0 * cosio2 - 1.0; # --------------- deep space initialization ------------- if 2*pi / satrec.no_unkozai >= 225.0: satrec.method = 'd'; satrec.isimp = 1; tc = 0.0; inclm = satrec.inclo; ( snodm, cnodm, sinim, cosim, sinomm, cosomm,day, satrec.e3, satrec.ee2, em, emsq, gam, satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, satrec.plo, rtemsq, satrec.se2, satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, satrec.sl2, satrec.sl3, satrec.sl4, s1, s2, s3, s4, s5, s6, s7, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, satrec.xl3, satrec.xl4, nm, z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33, satrec.zmol, satrec.zmos ) = _dscom( epoch, satrec.ecco, satrec.argpo, tc, satrec.inclo, satrec.nodeo, satrec.no_unkozai, satrec.e3, satrec.ee2, satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, satrec.plo, satrec.se2, satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, satrec.sl2, satrec.sl3, satrec.sl4, satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, satrec.xl3, satrec.xl4, satrec.zmol, satrec.zmos ); (satrec.ecco, satrec.inclo, satrec.nodeo, satrec.argpo, satrec.mo ) = _dpper( satrec, inclm, satrec.init, satrec.ecco, satrec.inclo, satrec.nodeo, satrec.argpo, satrec.mo, satrec.operationmode ); argpm = 0.0; nodem = 0.0; mm = 0.0; ( em, argpm, inclm, mm, nm, nodem, satrec.irez, satrec.atime, satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222, satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, satrec.d5421, satrec.d5433, satrec.dedt, satrec.didt, satrec.dmdt, dndt, satrec.dnodt, satrec.domdt, satrec.del1, satrec.del2, satrec.del3, satrec.xfact, satrec.xlamo, satrec.xli, satrec.xni ) = _dsinit( satrec.xke, cosim, emsq, satrec.argpo, s1, s2, s3, s4, s5, sinim, ss1, ss2, ss3, ss4, ss5, sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33, satrec.t, tc, satrec.gsto, satrec.mo, satrec.mdot, satrec.no_unkozai, satrec.nodeo, satrec.nodedot, xpidot, z1, z3, z11, z13, z21, z23, z31, z33, satrec.ecco, eccsq, em, argpm, inclm, mm, nm, nodem, satrec.irez, satrec.atime, satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222 , satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, satrec.d5421, satrec.d5433, satrec.dedt, satrec.didt, satrec.dmdt, satrec.dnodt, satrec.domdt, satrec.del1, satrec.del2, satrec.del3, satrec.xfact, satrec.xlamo, satrec.xli, satrec.xni ); #----------- set variables if not deep space ----------- if satrec.isimp != 1: cc1sq = satrec.cc1 * satrec.cc1; satrec.d2 = 4.0 * ao * tsi * cc1sq; temp = satrec.d2 * tsi * satrec.cc1 / 3.0; satrec.d3 = (17.0 * ao + sfour) * temp; satrec.d4 = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * \ satrec.cc1; satrec.t3cof = satrec.d2 + 2.0 * cc1sq; satrec.t4cof = 0.25 * (3.0 * satrec.d3 + satrec.cc1 * (12.0 * satrec.d2 + 10.0 * cc1sq)); satrec.t5cof = 0.2 * (3.0 * satrec.d4 + 12.0 * satrec.cc1 * satrec.d3 + 6.0 * satrec.d2 * satrec.d2 + 15.0 * cc1sq * (2.0 * satrec.d2 + cc1sq)); """ /* finally propogate to zero epoch to initialize all others. */ // sgp4fix take out check to let satellites process until they are actually below earth surface // if(satrec.error == 0) """ sgp4(satrec, 0.0, whichconst); satrec.init = 'n'; # sgp4fix return boolean. satrec.error contains any error codes return true; """ /*----------------------------------------------------------------------------- * * procedure sgp4 * * this procedure is the sgp4 prediction model from space command. this is an * updated and combined version of sgp4 and sdp4, which were originally * published separately in spacetrack report #3. this version follows the * methodology from the aiaa paper (2006) describing the history and * development of the code. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * satrec - initialised structure from sgp4init() call. * tsince - time eince epoch (minutes) * * outputs : * r - position vector km * v - velocity km/sec * return code - non-zero on error. * 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er * 2 - mean motion less than 0.0 * 3 - pert elements, ecc < 0.0 or ecc > 1.0 * 4 - semi-latus rectum < 0.0 * 5 - epoch elements are sub-orbital * 6 - satellite has decayed * * locals : * am - * axnl, aynl - * betal - * cosim , sinim , cosomm , sinomm , cnod , snod , cos2u , * sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip , * cosisq , cossu , sinsu , cosu , sinu * delm - * delomg - * dndt - * eccm - * emsq - * ecose - * el2 - * eo1 - * eccp - * esine - * argpm - * argpp - * omgadf - * pl - * r - * rtemsq - * rdotl - * rl - * rvdot - * rvdotl - * su - * t2 , t3 , t4 , tc * tem5, temp , temp1 , temp2 , tempa , tempe , templ * u , ux , uy , uz , vx , vy , vz * inclm - inclination * mm - mean anomaly * nm - mean motion * nodem - right asc of ascending node * xinc - * xincp - * xl - * xlm - * mp - * xmdf - * xmx - * xmy - * nodedf - * xnode - * nodep - * np - * * coupling : * getgravconst- * dpper * dpspace * * references : * hoots, roehrich, norad spacetrack report #3 1980 * hoots, norad spacetrack report #6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 ----------------------------------------------------------------------------*/ """ def sgp4(satrec, tsince, whichconst=None): mrt = 0.0 """ /* ------------------ set mathematical constants --------------- */ // sgp4fix divisor for divide by zero check on inclination // the old check used 1.0 + cos(pi-1.0e-9), but then compared it to // 1.5 e-12, so the threshold was changed to 1.5e-12 for consistency """ temp4 = 1.5e-12; twopi = 2.0 * pi; x2o3 = 2.0 / 3.0; # sgp4fix identify constants and allow alternate values # tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 = whichconst vkmpersec = satrec.radiusearthkm * satrec.xke/60.0; # --------------------- clear sgp4 error flag ----------------- satrec.t = tsince; satrec.error = 0; satrec.error_message = None # ------- update for secular gravity and atmospheric drag ----- xmdf = satrec.mo + satrec.mdot * satrec.t; argpdf = satrec.argpo + satrec.argpdot * satrec.t; nodedf = satrec.nodeo + satrec.nodedot * satrec.t; argpm = argpdf; mm = xmdf; t2 = satrec.t * satrec.t; nodem = nodedf + satrec.nodecf * t2; tempa = 1.0 - satrec.cc1 * satrec.t; tempe = satrec.bstar * satrec.cc4 * satrec.t; templ = satrec.t2cof * t2; if satrec.isimp != 1: delomg = satrec.omgcof * satrec.t; # sgp4fix use mutliply for speed instead of pow delmtemp = 1.0 + satrec.eta * cos(xmdf); delm = satrec.xmcof * \ (delmtemp * delmtemp * delmtemp - satrec.delmo); temp = delomg + delm; mm = xmdf + temp; argpm = argpdf - temp; t3 = t2 * satrec.t; t4 = t3 * satrec.t; tempa = tempa - satrec.d2 * t2 - satrec.d3 * t3 - \ satrec.d4 * t4; tempe = tempe + satrec.bstar * satrec.cc5 * (sin(mm) - satrec.sinmao); templ = templ + satrec.t3cof * t3 + t4 * (satrec.t4cof + satrec.t * satrec.t5cof); nm = satrec.no_unkozai; em = satrec.ecco; inclm = satrec.inclo; if satrec.method == 'd': tc = satrec.t; ( atime, em, argpm, inclm, xli, mm, xni, nodem, dndt, nm, ) = _dspace( satrec.irez, satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222, satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, satrec.d5421, satrec.d5433, satrec.dedt, satrec.del1, satrec.del2, satrec.del3, satrec.didt, satrec.dmdt, satrec.dnodt, satrec.domdt, satrec.argpo, satrec.argpdot, satrec.t, tc, satrec.gsto, satrec.xfact, satrec.xlamo, satrec.no_unkozai, satrec.atime, em, argpm, inclm, satrec.xli, mm, satrec.xni, nodem, nm ); if nm <= 0.0: satrec.error_message = ('mean motion {0:f} is less than zero' .format(nm)) satrec.error = 2; # sgp4fix add return return false, false; am = pow((satrec.xke / nm),x2o3) * tempa * tempa; nm = satrec.xke / pow(am, 1.5); em = em - tempe; # fix tolerance for error recognition # sgp4fix am is fixed from the previous nm check if em >= 1.0 or em < -0.001: # || (am < 0.95) satrec.error_message = ('mean eccentricity {0:f} not within' ' range 0.0 <= e < 1.0'.format(em)) satrec.error = 1; # sgp4fix to return if there is an error in eccentricity return false, false; # sgp4fix fix tolerance to avoid a divide by zero if em < 1.0e-6: em = 1.0e-6; mm = mm + satrec.no_unkozai * templ; xlm = mm + argpm + nodem; emsq = em * em; temp = 1.0 - emsq; nodem = nodem % twopi if nodem >= 0.0 else -(-nodem % twopi) argpm = argpm % twopi xlm = xlm % twopi mm = (xlm - argpm - nodem) % twopi # sgp4fix recover singly averaged mean elements satrec.am = am; satrec.em = em; satrec.im = inclm; satrec.Om = nodem; satrec.om = argpm; satrec.mm = mm; satrec.nm = nm; # ----------------- compute extra mean quantities ------------- sinim = sin(inclm); cosim = cos(inclm); # -------------------- add lunar-solar periodics -------------- ep = em; xincp = inclm; argpp = argpm; nodep = nodem; mp = mm; sinip = sinim; cosip = cosim; if satrec.method == 'd': ep, xincp, nodep, argpp, mp = _dpper( satrec, satrec.inclo, 'n', ep, xincp, nodep, argpp, mp, satrec.operationmode ); if xincp < 0.0: xincp = -xincp; nodep = nodep + pi; argpp = argpp - pi; if ep < 0.0 or ep > 1.0: satrec.error_message = ('perturbed eccentricity {0:f} not within' ' range 0.0 <= e <= 1.0'.format(ep)) satrec.error = 3; # sgp4fix add return return false, false; # -------------------- long period periodics ------------------ if satrec.method == 'd': sinip = sin(xincp); cosip = cos(xincp); satrec.aycof = -0.5*satrec.j3oj2*sinip; # sgp4fix for divide by zero for xincp = 180 deg if fabs(cosip+1.0) > 1.5e-12: satrec.xlcof = -0.25 * satrec.j3oj2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip); else: satrec.xlcof = -0.25 * satrec.j3oj2 * sinip * (3.0 + 5.0 * cosip) / temp4; axnl = ep * cos(argpp); temp = 1.0 / (am * (1.0 - ep * ep)); aynl = ep* sin(argpp) + temp * satrec.aycof; xl = mp + argpp + nodep + temp * satrec.xlcof * axnl; # --------------------- solve kepler's equation --------------- u = (xl - nodep) % twopi eo1 = u; tem5 = 9999.9; ktr = 1; # sgp4fix for kepler iteration # the following iteration needs better limits on corrections while fabs(tem5) >= 1.0e-12 and ktr <= 10: sineo1 = sin(eo1); coseo1 = cos(eo1); tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl; tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5; if fabs(tem5) >= 0.95: tem5 = 0.95 if tem5 > 0.0 else -0.95; eo1 = eo1 + tem5; ktr = ktr + 1; # ------------- short period preliminary quantities ----------- ecose = axnl*coseo1 + aynl*sineo1; esine = axnl*sineo1 - aynl*coseo1; el2 = axnl*axnl + aynl*aynl; pl = am*(1.0-el2); if pl < 0.0: satrec.error_message = ('semilatus rectum {0:f} is less than zero' .format(pl)) satrec.error = 4; # sgp4fix add return return false, false; else: rl = am * (1.0 - ecose); rdotl = sqrt(am) * esine/rl; rvdotl = sqrt(pl) / rl; betal = sqrt(1.0 - el2); temp = esine / (1.0 + betal); sinu = am / rl * (sineo1 - aynl - axnl * temp); cosu = am / rl * (coseo1 - axnl + aynl * temp); su = atan2(sinu, cosu); sin2u = (cosu + cosu) * sinu; cos2u = 1.0 - 2.0 * sinu * sinu; temp = 1.0 / pl; temp1 = 0.5 * satrec.j2 * temp; temp2 = temp1 * temp; # -------------- update for short period periodics ------------ if satrec.method == 'd': cosisq = cosip * cosip; satrec.con41 = 3.0*cosisq - 1.0; satrec.x1mth2 = 1.0 - cosisq; satrec.x7thm1 = 7.0*cosisq - 1.0; mrt = rl * (1.0 - 1.5 * temp2 * betal * satrec.con41) + \ 0.5 * temp1 * satrec.x1mth2 * cos2u; su = su - 0.25 * temp2 * satrec.x7thm1 * sin2u; xnode = nodep + 1.5 * temp2 * cosip * sin2u; xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u; mvt = rdotl - nm * temp1 * satrec.x1mth2 * sin2u / satrec.xke; rvdot = rvdotl + nm * temp1 * (satrec.x1mth2 * cos2u + 1.5 * satrec.con41) / satrec.xke; # --------------------- orientation vectors ------------------- sinsu = sin(su); cossu = cos(su); snod = sin(xnode); cnod = cos(xnode); sini = sin(xinc); cosi = cos(xinc); xmx = -snod * cosi; xmy = cnod * cosi; ux = xmx * sinsu + cnod * cossu; uy = xmy * sinsu + snod * cossu; uz = sini * sinsu; vx = xmx * cossu - cnod * sinsu; vy = xmy * cossu - snod * sinsu; vz = sini * cossu; # --------- position and velocity (in km and km/sec) ---------- _mr = mrt * satrec.radiusearthkm r = (_mr * ux, _mr * uy, _mr * uz) v = ((mvt * ux + rvdot * vx) * vkmpersec, (mvt * uy + rvdot * vy) * vkmpersec, (mvt * uz + rvdot * vz) * vkmpersec) # sgp4fix for decaying satellites if mrt < 1.0: satrec.error_message = ('mrt {0:f} is less than 1.0 indicating' ' the satellite has decayed'.format(mrt)) satrec.error = 6; return r, v; """ /* ----------------------------------------------------------------------------- * * function gstime * * this function finds the greenwich sidereal time. * * author : david vallado 719-573-2600 1 mar 2001 * * inputs description range / units * jdut1 - julian date in ut1 days from 4713 bc * * outputs : * gstime - greenwich sidereal time 0 to 2pi rad * * locals : * temp - temporary variable for doubles rad * tut1 - julian centuries from the * jan 1, 2000 12 h epoch (ut1) * * coupling : * none * * references : * vallado 2004, 191, eq 3-45 * --------------------------------------------------------------------------- */ """ def gstime(jdut1): tut1 = (jdut1 - 2451545.0) / 36525.0; temp = -6.2e-6* tut1 * tut1 * tut1 + 0.093104 * tut1 * tut1 + \ (876600.0*3600 + 8640184.812866) * tut1 + 67310.54841; # sec temp = (temp * deg2rad / 240.0) % twopi # 360/86400 = 1/240, to deg, to rad # ------------------------ check quadrants --------------------- if temp < 0.0: temp += twopi; return temp; # The routine was originally marked private, so make it available under # the old name for compatibility: _gstime = gstime """ /* ----------------------------------------------------------------------------- * * function getgravconst * * this function gets constants for the propagator. note that mu is identified to * facilitiate comparisons with newer models. the common useage is wgs72. * * author : david vallado 719-573-2600 21 jul 2006 * * inputs : * whichconst - which set of constants to use wgs72old, wgs72, wgs84 * * outputs : * tumin - minutes in one time unit * mu - earth gravitational parameter * radiusearthkm - radius of the earth in km * xke - reciprocal of tumin * j2, j3, j4 - un-normalized zonal harmonic values * j3oj2 - j3 divided by j2 * * locals : * * coupling : * none * * references : * norad spacetrack report #3 * vallado, crawford, hujsak, kelso 2006 --------------------------------------------------------------------------- */ """ def getgravconst(whichconst): if whichconst == 'wgs72old': mu = 398600.79964; # in km3 / s2 radiusearthkm = 6378.135; # km xke = 0.0743669161; tumin = 1.0 / xke; j2 = 0.001082616; j3 = -0.00000253881; j4 = -0.00000165597; j3oj2 = j3 / j2; # ------------ wgs-72 constants ------------ elif whichconst == 'wgs72': mu = 398600.8; # in km3 / s2 radiusearthkm = 6378.135; # km xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); tumin = 1.0 / xke; j2 = 0.001082616; j3 = -0.00000253881; j4 = -0.00000165597; j3oj2 = j3 / j2; elif whichconst == 'wgs84': # ------------ wgs-84 constants ------------ mu = 398600.5; # in km3 / s2 radiusearthkm = 6378.137; # km xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); tumin = 1.0 / xke; j2 = 0.00108262998905; j3 = -0.00000253215306; j4 = -0.00000161098761; j3oj2 = j3 / j2; return tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/sample_omm.csv0000644000175100001730000000055714422467341015456 0ustar00runnerdockerOBJECT_NAME,OBJECT_ID,EPOCH,MEAN_MOTION,ECCENTRICITY,INCLINATION,RA_OF_ASC_NODE,ARG_OF_PERICENTER,MEAN_ANOMALY,EPHEMERIS_TYPE,CLASSIFICATION_TYPE,NORAD_CAT_ID,ELEMENT_SET_NO,REV_AT_EPOCH,BSTAR,MEAN_MOTION_DOT,MEAN_MOTION_DDOT VANGUARD 1,1958-002B,2020-10-13T04:52:48.472320,10.84869164,.1845686,34.2443,225.5254,162.2516,205.2356,0,U,5,999,21814,-.22483E-4,-1.6E-7,0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/sample_omm.xml0000644000175100001730000000223114422467341015452 0ustar00runnerdocker
VANGUARD 11958-002BEARTHTEMEUTCSGP42020-10-13T04:52:48.47232010.84869164.184568634.2443225.5254162.2516205.23560U599921814-.22483E-4-1.6E-70
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/tcppver.out0000644000175100001730000042160214422467341015022 0ustar00runnerdocker5 xx 0.00000000 7022.46529266 -1400.08296755 0.03995155 1.893841015 6.405893759 4.534807250 360.00000000 -7154.03120202 -3783.17682504 -3536.19412294 4.741887409 -4.151817765 -2.093935425 8635.341424 0.185684 34.26805 347.97998 332.85746 252.46796 273.52819 2000 6 28 0:50:19.733571 720.00000000 -7134.59340119 6531.68641334 3260.27186483 -4.113793027 -2.911922039 -2.557327851 8635.861590 0.185142 34.27271 347.16975 334.22005 171.22619 167.48204 2000 6 28 6:50:19.733571 1080.00000000 5568.53901181 4492.06992591 3863.87641983 -4.209106476 5.159719888 2.744852980 8633.614993 0.185699 34.26281 346.44442 335.36006 82.20992 61.63454 2000 6 28 12:50:19.733571 1440.00000000 -938.55923943 -6268.18748831 -4294.02924751 7.536105209 -0.427127707 0.989878080 8632.098491 0.185801 34.25571 345.65357 336.33937 298.48507 315.94715 2000 6 28 18:50:19.733571 1800.00000000 -9680.56121728 2802.47771354 124.10688038 -0.905874102 -4.659467970 -3.227347517 8637.122332 0.185064 34.28086 344.88964 337.42106 201.32626 210.16351 2000 6 29 0:50:19.733571 2160.00000000 190.19796988 7746.96653614 5110.00675412 -6.112325142 1.527008184 -0.139152358 8633.131437 0.185639 34.25663 344.11473 338.71747 123.33032 104.17640 2000 6 29 6:50:19.733571 2520.00000000 5579.55640116 -3995.61396789 -1518.82108966 4.767927483 5.123185301 4.276837355 8637.302528 0.186337 34.27714 343.34125 339.73610 357.70207 358.45141 2000 6 29 12:50:19.733571 2880.00000000 -8650.73082219 -1914.93811525 -3007.03603443 3.067165127 -4.828384068 -2.515322836 8636.101255 0.185538 34.27261 342.61158 340.69038 234.10932 252.77706 2000 6 29 18:50:19.733571 3240.00000000 -5429.79204164 7574.36493792 3747.39305236 -4.999442110 -1.800561422 -2.229392830 8635.475338 0.185331 34.26974 341.80144 342.10905 156.39692 146.67615 2000 6 30 0:50:19.733571 3600.00000000 6759.04583722 2001.58198220 2783.55192533 -2.180993947 6.402085603 3.644723952 8635.195534 0.185973 34.27008 341.07931 343.22923 57.48219 40.84371 2000 6 30 6:50:19.733571 3960.00000000 -3791.44531559 -5712.95617894 -4533.48630714 6.668817493 -2.516382327 -0.082384354 8632.729753 0.185854 34.25654 340.29915 344.15875 274.30670 295.20327 2000 6 30 12:50:19.733571 4320.00000000 -9060.47373569 4658.70952502 813.68673153 -2.232832783 -4.110453490 -3.157345433 8637.006122 0.185080 34.28036 339.51733 345.34018 186.53394 189.32850 2000 6 30 18:50:19.733571 4632 xx 0.00000000 2334.11450085 -41920.44035349 -0.03867437 2.826321032 -0.065091664 0.570936053 -5184.00000000 -29020.02587128 13819.84419063 -5713.33679183 -1.768068390 -3.235371192 -0.395206135 37359.443192 0.145533 11.45906 273.26799 207.38255 34.36849 25.75029 2004 1 28 7:27:25.308584 -5064.00000000 -32982.56870101 -11125.54996609 -6803.28472771 0.617446996 -3.379240041 0.085954707 37359.437810 0.145510 11.45887 273.26406 207.40571 77.67793 61.81271 2004 1 28 9:27:25.308597 -4944.00000000 -22097.68730513 -31583.13829284 -4836.34329328 2.230597499 -2.166594667 0.426443070 37359.527360 0.145483 11.45906 273.26128 207.41088 113.78650 97.88090 2004 1 28 11:27:25.308611 -4896.00000000 -15129.94694545 -36907.74526221 -3487.56256701 2.581167187 -1.524204737 0.504805763 37359.552946 0.145472 11.45912 273.26070 207.41055 126.58633 112.31003 2004 1 28 12:15:25.308600 6251 xx 0.00000000 3988.31022699 5498.96657235 0.90055879 -3.290032738 2.357652820 6.496623475 120.00000000 -3935.69800083 409.10980837 5471.33577327 -3.374784183 -6.635211043 -1.942056221 6769.925529 0.002843 58.04264 53.67485 130.45323 336.79192 336.92003 2006 6 25 21:46:43.980124 240.00000000 -1675.12766915 -5683.30432352 -3286.21510937 5.282496925 1.508674259 -5.354872978 6778.150599 0.003376 58.06431 53.35235 131.72414 83.13296 82.74899 2006 6 25 23:46:43.980097 360.00000000 4993.62642836 2890.54969900 -3600.40145627 0.347333429 5.707031557 5.070699638 6777.272133 0.003545 58.06200 52.95532 133.43271 187.97156 188.02804 2006 6 26 1:46:43.980111 480.00000000 -1115.07959514 4015.11691491 5326.99727718 -5.524279443 -4.765738774 2.402255961 6770.645332 0.003600 58.04451 52.63634 140.69177 287.48220 287.87534 2006 6 26 3:46:43.980124 600.00000000 -4329.10008198 -5176.70287935 409.65313857 2.858408303 -2.933091792 -6.509690397 6782.699240 0.004248 58.07622 52.26287 135.50292 40.40320 40.08846 2006 6 26 5:46:43.980097 720.00000000 3692.60030028 -976.24265255 -5623.36447493 3.897257243 6.415554948 1.429112190 6769.424000 0.004551 58.04122 51.90123 125.49216 157.34330 157.14176 2006 6 26 7:46:43.980111 840.00000000 2301.83510037 5723.92394553 2814.61514580 -5.110924966 -0.764510559 5.662120145 6779.384007 0.003929 58.06755 51.57398 123.27602 266.00386 266.45313 2006 6 26 9:46:43.980124 960.00000000 -4990.91637950 -2303.42547880 3920.86335598 -0.993439372 -5.967458360 -4.759110856 6776.153797 0.003677 58.05907 51.17829 123.47669 13.34161 13.24463 2006 6 26 11:46:43.980097 1080.00000000 642.27769977 -4332.89821901 -5183.31523910 5.720542579 4.216573838 -2.846576139 6771.342290 0.003769 58.04641 50.86185 118.24808 125.93580 125.58552 2006 6 26 13:46:43.980111 1200.00000000 4719.78335752 4798.06938996 -943.58851062 -2.294860662 3.492499389 6.408334723 6782.318686 0.003095 58.07542 50.48240 122.06820 228.51683 228.78297 2006 6 26 15:46:43.980124 1320.00000000 -3299.16993602 1576.83168320 5678.67840638 -4.460347074 -6.202025196 -0.885874586 6768.899732 0.002843 58.04006 50.12834 137.68970 320.00900 320.21804 2006 6 26 17:46:43.980097 1440.00000000 -2777.14682335 -5663.16031708 -2462.54889123 4.915493146 0.123328992 -5.896495091 6780.123356 0.003546 58.06961 49.79571 137.17584 68.19805 67.82115 2006 6 26 19:46:43.980111 1560.00000000 4992.31573893 1716.62356770 -4287.86065581 1.640717189 6.071570434 4.338797931 6774.954049 0.003872 58.05597 49.40182 134.68716 177.32764 177.30689 2006 6 26 21:46:43.980124 1680.00000000 -8.22384755 4662.21521668 4905.66411857 -5.891011274 -3.593173872 3.365100460 6772.461420 0.003831 58.04939 49.08756 138.33630 280.34438 280.77597 2006 6 26 23:46:43.980097 1800.00000000 -4966.20137963 -4379.59155037 1349.33347502 1.763172581 -3.981456387 -6.343279443 6781.951019 0.004290 58.07436 48.70290 133.19973 33.19304 32.92461 2006 6 27 1:46:43.980111 1920.00000000 2954.49390331 -2080.65984650 -5754.75038057 4.895893306 5.858184322 0.375474825 6768.735395 0.004501 58.03953 48.35495 122.85039 150.59585 150.34188 2006 6 27 3:46:43.980124 2040.00000000 3363.28794321 5559.55841180 1956.05542266 -4.587378863 0.591943403 6.107838605 6781.069838 0.003728 58.07214 48.01619 120.75801 259.09703 259.51676 2006 6 27 5:46:43.980097 2160.00000000 -4856.66780070 -1107.03450192 4557.21258241 -2.304158557 -6.186437070 -3.956549542 6773.784729 0.003314 58.05298 47.62591 124.52772 2.77040 2.75210 2006 6 27 7:46:43.980111 2280.00000000 -497.84480071 -4863.46005312 -4700.81211217 5.960065407 2.996683369 -3.767123329 6773.294589 0.003476 58.05171 47.31217 122.26746 112.50185 112.13345 2006 6 27 9:46:43.980124 2400.00000000 5241.61936096 3910.75960683 -1857.93473952 -1.124834806 4.406213160 6.148161299 6781.190564 0.003063 58.07257 46.92300 128.10892 213.10746 213.29953 2006 6 27 11:46:43.980097 2520.00000000 -2451.38045953 2610.60463261 5729.79022069 -5.366560525 -5.500855666 0.187958716 6768.622659 0.003018 58.03943 46.58234 143.15752 305.04971 305.33247 2006 6 27 13:46:43.980111 2640.00000000 -3791.87520638 -5378.82851382 -1575.82737930 4.266273592 -1.199162551 -6.276154080 6781.613528 0.003799 58.07362 46.23717 140.09586 55.82869 55.46914 2006 6 27 15:46:43.980124 2760.00000000 4730.53958356 524.05006433 -4857.29369725 2.918056288 6.135412849 3.495115636 6772.724967 0.004172 58.05018 45.85052 133.91443 168.75679 168.66328 2006 6 27 17:46:43.980097 2880.00000000 1159.27802897 5056.60175495 4353.49418579 -5.968060341 -2.314790406 4.230722669 6774.610266 0.003961 58.05516 45.53659 134.85462 274.39399 274.84650 2006 6 27 19:46:43.980111 8195 xx 0.00000000 2349.89483350 -14785.93811562 0.02119378 2.721488096 -3.256811655 4.498416672 120.00000000 15223.91713658 -17852.95881713 25280.39558224 1.079041732 0.875187372 2.485682813 26564.959894 0.686668 64.17478 279.02552 264.80305 149.71445 80.31676 2006 6 25 9:58:18.143649 240.00000000 19752.78050009 -8600.07130962 37522.72921090 0.238105279 1.546110924 0.986410447 26565.004593 0.686729 64.17275 279.01498 264.80395 169.66007 140.46244 2006 6 25 11:58:18.143622 360.00000000 19089.29762968 3107.89495018 39958.14661370 -0.410308034 1.640332277 -0.306873818 26565.026844 0.686738 64.17218 279.00406 264.80930 185.29658 200.60234 2006 6 25 13:58:18.143636 480.00000000 13829.66070574 13977.39999817 32736.32082508 -1.065096849 1.279983299 -1.760166075 26564.625574 0.686690 64.17284 278.99292 264.81391 202.93892 260.74283 2006 6 25 15:58:18.143649 600.00000000 3333.05838525 18395.31728674 12738.25031238 -1.882432221 -0.611623333 -4.039586549 26566.244167 0.686599 64.17668 278.98254 264.80715 236.46989 320.89629 2006 6 25 17:58:18.143622 720.00000000 2622.13222207 -15125.15464924 474.51048398 2.688287199 -3.078426664 4.494979530 26574.895477 0.686659 64.17958 278.97819 264.81333 97.15363 21.03833 2006 6 25 19:58:18.143636 840.00000000 15320.56770017 -17777.32564586 25539.53198382 1.064346229 0.892184771 2.459822414 26564.950207 0.686625 64.17450 278.97313 264.79671 150.09217 81.20519 2006 6 25 21:58:18.143649 960.00000000 19769.70267785 -8458.65104454 37624.20130236 0.229304396 1.550363884 0.966993056 26565.006252 0.686686 64.17248 278.96261 264.79768 169.90203 141.35081 2006 6 25 23:58:18.143622 1080.00000000 19048.56201523 3260.43223119 39923.39143967 -0.418015536 1.639346953 -0.326094840 26565.022711 0.686696 64.17191 278.95173 264.80301 185.52861 201.49078 2006 6 26 1:58:18.143636 1200.00000000 13729.19205837 14097.70014810 32547.52799890 -1.074511043 1.270505211 -1.785099927 26564.616382 0.686647 64.17257 278.94062 264.80751 203.25527 261.63142 2006 6 26 3:58:18.143649 1320.00000000 3148.86165643 18323.19841703 12305.75195578 -1.895271701 -0.678343847 -4.086577951 26566.400900 0.686558 64.17648 278.93034 264.80031 237.38050 321.78542 2006 6 26 5:58:18.143622 1440.00000000 2890.80638268 -15446.43952300 948.77010176 2.654407490 -2.909344895 4.486437362 26574.377821 0.686612 64.17922 278.92626 264.80655 99.03224 21.92752 2006 6 26 7:58:18.143636 1560.00000000 15415.98410712 -17699.90714437 25796.19644689 1.049818334 0.908822332 2.434107329 26564.940797 0.686587 64.17410 278.92092 264.79010 150.46635 82.09418 2006 6 26 9:58:18.143649 1680.00000000 19786.00618538 -8316.74570581 37723.74539119 0.220539813 1.554518900 0.947601047 26565.007447 0.686648 64.17210 278.91042 264.79116 170.14356 142.23974 2006 6 26 11:58:18.143622 1800.00000000 19007.28688729 3412.85948715 39886.66579255 -0.425733568 1.638276809 -0.345353807 26565.018061 0.686658 64.17151 278.89955 264.79647 185.76116 202.37976 2006 6 26 13:58:18.143636 1920.00000000 13627.93015254 14216.95401307 32356.13706868 -1.083991976 1.260802347 -1.810193903 26564.606809 0.686609 64.17218 278.88845 264.80089 203.57412 262.52055 2006 6 26 15:58:18.143649 2040.00000000 2963.26486560 18243.85063641 11868.25797486 -1.908015447 -0.747870342 -4.134004492 26566.569776 0.686522 64.17617 278.87825 264.79325 238.31809 322.67510 2006 6 26 17:58:18.143622 2160.00000000 3155.85126036 -15750.70393364 1422.32496953 2.620085624 -2.748990396 4.473527039 26573.870612 0.686571 64.17873 278.87439 264.79955 100.82331 22.81727 2006 6 26 19:58:18.143636 2280.00000000 15510.15191770 -17620.71002219 26050.43525345 1.035454678 0.925111006 2.408534465 26564.931623 0.686555 64.17359 278.86878 264.78333 150.83708 82.98368 2006 6 26 21:58:18.143649 2400.00000000 19801.67198812 -8174.33337167 37821.38577439 0.211812700 1.558576937 0.928231880 26565.008175 0.686616 64.17159 278.85827 264.78449 170.38465 143.12917 2006 6 26 23:58:18.143622 2520.00000000 18965.46529379 3565.19666242 39847.97510998 -0.433459945 1.637120585 -0.364653213 26565.012894 0.686626 64.17101 278.84740 264.78981 185.99421 203.26924 2006 6 27 1:58:18.143636 2640.00000000 13525.88227400 14335.15978787 32162.13236536 -1.093537945 1.250868256 -1.835451681 26564.596866 0.686577 64.17169 278.83628 264.79416 203.89550 263.41016 2006 6 27 3:58:18.143649 2760.00000000 2776.30574260 18156.98538451 11425.73046481 -1.920632199 -0.820370733 -4.181839232 26566.751784 0.686492 64.17575 278.82615 264.78609 239.28409 323.56526 2006 6 27 5:58:18.143622 2880.00000000 3417.20931586 -16038.79510665 1894.74934058 2.585515864 -2.596818146 4.456882556 26573.377678 0.686536 64.17812 278.82248 264.79245 102.53328 23.70751 2006 6 27 7:58:18.143636 9880 xx 0.00000000 13020.06750784 -2449.07193500 1.15896030 4.247363935 1.597178501 4.956708611 120.00000000 19190.32482476 9249.01266902 26596.71345328 -0.624960193 1.324550562 2.495697637 26536.144492 0.707479 64.58105 349.33800 270.05274 149.73418 76.55800 2006 6 25 15:28:40.058423 240.00000000 11332.67806218 16517.99124008 38569.78482991 -1.400974747 0.710947006 0.923935636 26536.456359 0.707543 64.57927 349.32489 270.05570 169.23437 136.79719 2006 6 25 17:28:40.058396 360.00000000 328.74217398 19554.92047380 40558.26246145 -1.593281066 0.126772913 -0.359627307 26536.546319 0.707550 64.57908 349.31175 270.06234 184.14530 197.03195 2006 6 25 19:28:40.058410 480.00000000 -10684.90590680 18057.15728839 33158.75253886 -1.383205997 -0.582328999 -1.744412556 26536.216267 0.707502 64.58013 349.29861 270.06769 200.60417 257.26831 2006 6 25 21:28:40.058423 600.00000000 -17069.78000550 9944.86797897 13885.91649059 0.044133354 -1.853448464 -3.815303117 26537.598512 0.707414 64.58411 349.28637 270.06282 230.39343 317.51677 2006 6 25 23:28:40.058396 720.00000000 13725.09398980 -2180.70877090 863.29684523 3.878478111 1.656846496 4.944867241 26548.333034 0.707487 64.58751 349.28080 270.07012 93.86588 17.75424 2006 6 26 1:28:40.058410 840.00000000 19089.63879226 9456.29670247 27026.79562883 -0.656614299 1.309112636 2.449371941 26536.083726 0.707453 64.58130 349.27341 270.05293 150.35125 78.01690 2006 6 26 3:28:40.058423 960.00000000 11106.41248373 16627.60874079 38727.35140296 -1.409722680 0.698582526 0.891383535 26536.406111 0.707515 64.57959 349.26035 270.05600 169.61686 138.25614 2006 6 26 5:28:40.058396 1080.00000000 72.40958621 19575.08054144 40492.12544001 -1.593394604 0.113655142 -0.390556063 26536.485208 0.707520 64.57944 349.24727 270.06258 184.50420 198.49115 2006 6 26 7:28:40.058410 1200.00000000 -10905.89252576 17965.41205111 32850.07298244 -1.371396120 -0.601706604 -1.782817058 26536.148885 0.707469 64.58054 349.23420 270.06776 201.08065 258.72792 2006 6 26 9:28:40.058423 1320.00000000 -17044.61207568 9635.48491849 13212.59462953 0.129244030 -1.903551430 -3.884569098 26537.753741 0.707381 64.58467 349.22213 270.06223 231.67254 318.97731 2006 6 26 11:28:40.058396 1440.00000000 14369.90303735 -1903.85601062 1722.15319852 3.543393116 1.701687176 4.913881358 26547.006033 0.707440 64.58780 349.21714 270.06935 97.43575 19.21528 2006 6 26 13:28:40.058410 1560.00000000 18983.96210441 9661.12233804 27448.99557732 -0.687189304 1.293808870 2.403630759 26536.025321 0.707422 64.58162 349.20920 270.05262 150.95671 79.47751 2006 6 26 15:28:40.058423 1680.00000000 10878.79336704 16735.31433954 38879.23434264 -1.418239666 0.686235750 0.858951848 26536.356328 0.707481 64.57998 349.19620 270.05577 169.99758 139.71684 2006 6 26 17:28:40.058396 1800.00000000 -184.03743100 19593.09371709 40420.40606889 -1.593348925 0.100448697 -0.421571993 26536.424509 0.707483 64.57986 349.18320 270.06227 184.86453 199.95214 2006 6 26 19:28:40.058410 1920.00000000 -11125.12138631 17870.19488928 32534.21521208 -1.359116236 -0.621413776 -1.821629856 26536.082381 0.707430 64.58101 349.17020 270.06725 201.56409 260.18933 2006 6 26 21:28:40.058423 2040.00000000 -17004.43272827 9316.53926351 12526.11883812 0.220330736 -1.955594322 -3.955058575 26537.937268 0.707343 64.58528 349.15832 270.06103 233.01303 320.43971 2006 6 26 23:28:40.058396 2160.00000000 14960.06492693 -1620.68430805 2574.96359381 3.238634028 1.734723385 4.868880331 26545.757985 0.707389 64.58808 349.15385 270.06784 100.69458 20.67827 2006 6 27 1:28:40.058410 2280.00000000 18873.46347257 9863.57004586 27863.46574735 -0.716736981 1.278632817 2.358448535 26535.969116 0.707385 64.58199 349.14544 270.05170 151.55126 80.93998 2006 6 27 3:28:40.058423 2400.00000000 10649.86857581 16841.14172669 39025.48035006 -1.426527152 0.673901057 0.826632332 26536.307016 0.707442 64.58041 349.13251 270.05492 170.37668 141.17943 2006 6 27 5:28:40.058396 2520.00000000 -440.53459323 19608.95524423 40343.10675451 -1.593138597 0.087147884 -0.452680559 26536.364231 0.707443 64.58032 349.11959 270.06132 185.22637 201.41503 2006 6 27 7:28:40.058410 2640.00000000 -11342.45028909 17771.44223942 32211.12535721 -1.346344015 -0.641464291 -1.860864234 26536.016805 0.707388 64.58151 349.10667 270.06608 202.05475 261.65268 2006 6 27 9:28:40.058423 2760.00000000 -16948.06005711 8987.64254880 11826.28284367 0.318007297 -2.009693492 -4.026726648 26538.152748 0.707301 64.58594 349.09499 270.05912 234.42042 321.90410 2006 6 27 11:28:40.058396 2880.00000000 15500.53445068 -1332.90981042 3419.72315308 2.960917974 1.758331634 4.813698638 26544.607622 0.707336 64.58836 349.09097 270.06558 103.68403 22.14330 2006 6 27 13:28:40.058410 9998 xx 0.00000000 25532.98947267 -27244.26327953 -1.11572421 2.410283885 2.194175683 0.545888526 -1440.00000000 -11362.18265118 -35117.55867813 -5413.62537994 3.137861261 -1.011678260 0.267510059 38221.491160 0.027161 9.51133 313.16470 327.30370 331.26840 332.73819 2005 5 27 19: 3:37.089777 -1380.00000000 309.25349929 -36960.43090143 -4198.48007670 3.292429375 -0.002166046 0.402111628 38221.526676 0.027166 9.51133 313.16407 327.33196 349.58789 350.13941 2005 5 27 20: 3:37.089763 -1320.00000000 11949.04009077 -35127.37816804 -2565.89806468 3.119942784 1.012096444 0.497284100 38221.561326 0.027167 9.51133 313.16394 327.36254 7.96041 7.53783 2005 5 27 21: 3:37.089790 -1260.00000000 22400.45329336 -29798.63236321 -677.91515122 2.638533344 1.922477736 0.542792913 38221.583032 0.027163 9.51127 313.16418 327.39232 26.29054 24.93669 2005 5 27 22: 3:37.089777 -1200.00000000 30640.84752458 -21525.02340201 1277.34808722 1.903464941 2.634294312 0.534540934 38221.585627 0.027155 9.51113 313.16452 327.41777 44.48899 42.33979 2005 5 27 23: 3:37.089763 -1140.00000000 35899.56788035 -11152.71158138 3108.72535238 0.997393045 3.079858548 0.474873291 38221.571380 0.027144 9.51092 313.16464 327.43611 62.48274 59.75018 2005 5 28 0: 3:37.089790 -1080.00000000 37732.45438600 288.18821054 4643.87587495 0.016652226 3.225184410 0.371669746 38221.549210 0.027131 9.51067 313.16433 327.44619 80.22210 77.16923 2005 5 28 1: 3:37.089777 -1020.00000000 36045.92961699 11706.61816230 5746.32646574 -0.942409065 3.069888941 0.236662980 38221.530203 0.027118 9.51043 313.16355 327.44829 97.68426 94.59668 2005 5 28 2: 3:37.089763 -960.00000000 31076.77273609 22063.44379776 6325.93403705 -1.794027976 2.642072476 0.083556127 38221.523131 0.027106 9.51023 313.16243 327.44333 114.87345 112.03151 2005 5 28 3: 3:37.089790 -900.00000000 23341.26015320 30460.88002531 6342.91707895 -2.469409743 1.990861658 -0.073612096 38221.531831 0.027095 9.51011 313.16118 327.43216 131.81817 129.47266 2005 5 28 4: 3:37.089777 -840.00000000 13568.39733054 36204.45930900 5806.79548733 -2.919354203 1.178920217 -0.221646814 38221.554837 0.027086 9.51006 313.16007 327.41535 148.56644 146.91929 2005 5 28 5: 3:37.089763 -780.00000000 2628.58762420 38840.10855897 4771.91979854 -3.114400514 0.276239109 -0.348926401 38221.586600 0.027081 9.51004 313.15929 327.39366 165.18009 164.37049 2005 5 28 6: 3:37.089790 -720.00000000 -8535.81598158 38171.79073851 3331.00311285 -3.043839958 -0.644462527 -0.445808894 38221.619464 0.027078 9.51004 313.15891 327.36854 181.72917 181.82473 2005 5 28 7: 3:37.089777 11801 xx 0.00000000 7473.37102491 428.94748312 5828.74846783 5.107155391 6.444680305 -0.186133297 360.00000000 -3305.22148694 32410.84323331 -24697.16974954 -1.301137319 -1.151315600 -0.283335823 24302.998464 0.731602 46.74812 230.32944 47.61951 188.41997 216.32619 1980 8 17 13: 6:40.136822 720.00000000 14271.29083858 24110.44309009 -4725.76320143 -0.320504528 2.679841539 -2.084054355 24260.879269 0.730999 46.75721 230.25074 47.70178 145.49648 62.82214 1980 8 17 19: 6:40.136822 1080.00000000 -9990.05800009 22717.34212448 -23616.88515553 -1.016674392 -2.290267981 0.728923337 24216.350393 0.730514 46.74432 230.17836 47.76610 203.41634 269.87129 1980 8 18 1: 6:40.136822 1440.00000000 9787.87836256 33753.32249667 -15030.79874625 -1.094251553 0.923589906 -1.522311008 24174.266874 0.729877 46.75279 230.10704 47.83650 164.83770 117.47202 1980 8 18 7: 6:40.136822 14128 xx 0.00000000 34747.57932696 24502.37114079 -1.32832986 -1.731642662 2.452772615 0.608510081 120.00000000 18263.33439094 38159.96004751 4186.18304085 -2.744396611 1.255583260 0.528558932 42563.335575 0.001210 11.45711 35.19962 28.32899 1.38958 1.38622 2006 6 25 2:40:57.987566 240.00000000 -3023.38840703 41783.13186459 7273.03412906 -3.035574793 -0.271656544 0.309645251 42563.286498 0.001204 11.45707 35.19984 29.11706 30.32902 30.25940 2006 6 25 4:40:57.987539 360.00000000 -23516.34391907 34424.42065671 8448.49867693 -2.529120477 -1.726186020 0.009582303 42563.266606 0.001192 11.45713 35.19919 29.66338 59.49273 59.37511 2006 6 25 6:40:57.987553 480.00000000 -37837.46699511 18028.39727170 7406.25540271 -1.360069525 -2.725794686 -0.292555349 42563.306835 0.001176 11.45738 35.19852 29.91711 88.91814 88.78342 2006 6 25 8:40:57.987566 600.00000000 -42243.58460661 -3093.72887774 4422.91711801 0.163110919 -3.009980598 -0.517584362 42563.378963 0.001159 11.45773 35.19869 29.78001 118.69825 118.58175 2006 6 25 10:40:57.987539 720.00000000 -35597.57919549 -23407.91145393 282.09554383 1.641405246 -2.506773678 -0.606963478 42563.423811 0.001145 11.45799 35.19977 29.17604 148.91388 148.84611 2006 6 25 12:40:57.987553 840.00000000 -19649.19834455 -37606.11623860 -3932.71525948 2.689647056 -1.349150016 -0.537710698 42563.409025 0.001140 11.45805 35.20091 28.27993 179.40389 179.40253 2006 6 25 14:40:57.987566 960.00000000 1431.30912160 -41982.04949668 -7120.45467057 3.035263353 0.160882945 -0.327993994 42563.360304 0.001146 11.45799 35.20123 27.44408 209.83405 209.89943 2006 6 25 16:40:57.987539 1080.00000000 22136.97605384 -35388.19823762 -8447.62393401 2.587624889 1.630097136 -0.032349004 42563.336241 0.001158 11.45801 35.20064 26.88569 240.00468 240.11968 2006 6 25 18:40:57.987553 1200.00000000 37050.15790219 -19537.23321425 -7564.83463543 1.461844494 2.674654256 0.272202191 42563.371549 0.001174 11.45822 35.19994 26.65134 269.88144 270.01600 2006 6 25 20:40:57.987566 1320.00000000 42253.81760945 1431.81867593 -4699.87621174 -0.049247334 3.019518960 0.505890058 42563.442989 0.001191 11.45854 35.20004 26.80451 299.40514 299.52402 2006 6 25 22:40:57.987539 1440.00000000 36366.59147396 22023.54245720 -601.47121821 -1.549681546 2.571788981 0.607057418 42563.491561 0.001205 11.45879 35.20107 27.38673 328.53010 328.60214 2006 6 26 0:40:57.987553 1560.00000000 20922.12287985 36826.33975981 3654.91125886 -2.644070068 1.447521216 0.548722983 42563.480302 0.001210 11.45883 35.20224 28.23415 357.40864 357.41490 2006 6 26 2:40:57.987566 1680.00000000 -23.77224182 41945.51688402 6950.29891751 -3.043358385 -0.057417440 0.346112094 42563.431184 0.001205 11.45875 35.20263 29.04625 26.32488 26.26370 2006 6 26 4:40:57.987539 1800.00000000 -20964.17821076 36039.06206172 8418.91984963 -2.642795221 -1.546099886 0.052725852 42563.403442 0.001193 11.45873 35.20206 29.62920 55.45507 55.34250 2006 6 26 6:40:57.987553 1920.00000000 -36401.63863057 20669.75286162 7677.19769359 -1.549488154 -2.627052310 -0.254079652 42563.434989 0.001178 11.45890 35.20132 29.92669 84.84130 84.70690 2006 6 26 8:40:57.987566 2040.00000000 -42298.30327543 -119.03351118 4922.96388841 -0.052232768 -3.018152669 -0.493827331 42563.505293 0.001160 11.45920 35.20134 29.85054 114.56521 114.44424 2006 6 26 10:40:57.987539 2160.00000000 -37125.62383511 -20879.63058368 879.86971348 1.456499841 -2.619358421 -0.604081694 42563.556063 0.001146 11.45943 35.20230 29.30881 144.72439 144.64852 2006 6 26 12:40:57.987553 2280.00000000 -22250.12320553 -36182.74736487 -3393.15365183 2.583161226 -1.536647628 -0.556404555 42563.548278 0.001140 11.45946 35.20346 28.43156 175.19681 175.18586 2006 6 26 14:40:57.987566 2400.00000000 -1563.06258654 -42035.43179159 -6780.02161760 3.034917506 -0.052702046 -0.363395654 42563.499945 0.001144 11.45935 35.20388 27.56804 205.65334 205.71014 2006 6 26 16:40:57.987539 2520.00000000 19531.64069587 -36905.65470956 -8395.46892032 2.693682199 1.446079999 -0.075256054 42563.468338 0.001156 11.45930 35.20333 26.96596 235.86418 235.97386 2006 6 26 18:40:57.987553 2640.00000000 35516.53506142 -22123.71916638 -7815.04516935 1.646882125 2.568416058 0.232985912 42563.494530 0.001171 11.45943 35.20253 26.68392 265.78389 265.91776 2006 6 26 20:40:57.987566 2760.00000000 42196.03535976 -1547.32646751 -5187.39401981 0.166491841 3.019211549 0.480665780 42563.563210 0.001188 11.45970 35.20242 26.77785 295.36201 295.48503 2006 6 26 22:40:57.987539 2880.00000000 37802.25393045 19433.57330019 -1198.66634226 -1.359930580 2.677830903 0.602507466 42563.617115 0.001203 11.45992 35.20328 27.30484 324.53841 324.61834 2006 6 27 0:40:57.987553 16925 xx 0.00000000 5559.11686836 -11941.04090781 -19.41235206 3.392116762 -1.946985124 4.250755852 120.00000000 12339.83273749 -2771.14447871 18904.57603433 -0.871247614 2.600917693 0.581560002 14661.168567 0.558851 62.08305 294.96981 245.15626 184.99906 194.60193 2006 5 31 18:10:47.226141 240.00000000 -3385.00215658 7538.13955729 200.59008616 -2.023512865 -4.261808344 -6.856385787 14665.680807 0.558522 62.09661 294.91901 245.14027 293.28617 341.35494 2006 5 31 20:10:47.226115 360.00000000 12805.22442200 -10258.94667177 13780.16486738 0.619279224 1.821510542 2.507365975 14645.112935 0.558062 62.08843 294.88336 245.15354 161.54763 128.23331 2006 5 31 22:10:47.226128 480.00000000 5682.46556318 7199.30270473 15437.67134070 -2.474365406 2.087897336 -2.583767460 14633.894717 0.557848 62.08196 294.82586 245.20054 218.15594 275.17654 2006 6 1 0:10:47.226141 600.00000000 7628.94243982 -12852.72097492 2902.87208981 2.748131081 -0.740084579 4.125307943 14632.350201 0.557354 62.09577 294.78850 245.19066 127.26833 62.32236 2006 6 1 2:10:47.226115 720.00000000 11531.64866625 -858.27542736 19086.85993771 -1.170071901 2.660311986 0.096005705 14618.400478 0.557382 62.08201 294.74405 245.18361 190.26697 209.59661 2006 6 1 4:10:47.226128 840.00000000 -3866.98069515 2603.73442786 -4577.36484577 1.157257298 -8.453281164 -4.683959407 14609.950084 0.556751 62.08671 294.70316 245.19559 347.25738 356.96829 2006 6 1 6:10:47.226141 960.00000000 13054.77732721 -8707.92757730 15537.63259903 0.229846748 2.119467054 2.063396852 14602.295885 0.556633 62.08658 294.65799 245.17457 167.59678 144.51266 2006 6 1 8:10:47.226115 1080.00000000 3496.91064652 8712.83919778 12845.81838327 -2.782184997 1.552950644 -3.554436131 14591.212894 0.556266 62.08343 294.59790 245.22189 228.75852 292.09018 2006 6 1 10:10:47.226128 1200.00000000 9593.07424729 -13023.75963608 6250.46484931 2.072666376 0.278735334 3.778111073 14587.914744 0.555849 62.09368 294.56560 245.20049 138.87074 79.89273 2006 6 1 12:10:47.226141 1320.00000000 10284.79205084 1487.89914169 18824.37381327 -1.530335053 2.663107730 -0.542205966 14575.580204 0.555897 62.08105 294.51611 245.21323 196.99829 227.77813 2006 6 1 14:10:47.226115 1440.00000000 -984.62035146 -5187.03480813 -5745.59594144 4.340271916 -7.266811354 1.777668888 14567.926630 0.555320 62.08542 294.46033 245.19248 58.36949 15.80816 2006 6 1 16:10:47.226128 20413 xx 0.00000000 25123.29290741 -13225.49966286 3249.40351869 0.488683419 4.797897593 -0.961119693 1440.00000000 -151669.05280515 -5645.20454550 -2198.51592118 -0.869182889 -0.870759872 0.156508219 107329.432072 0.778767 11.46945 186.22560 197.88489 157.93798 84.35150 2005 12 30 19: 0: 0.000268 1560.00000000 -157497.71657495 -11884.99595074 -1061.44439402 -0.749657961 -0.864016715 0.157766101 107329.508122 0.778732 11.46619 186.21408 197.89244 160.17028 91.77011 2005 12 30 21: 0: 0.000282 1680.00000000 -162498.32255577 -18062.99733167 81.00915253 -0.638980378 -0.853687105 0.158098992 107329.571762 0.778698 11.46314 186.20285 197.89960 162.24325 99.18901 2005 12 30 23: 0: 0.000255 1800.00000000 -166728.76010920 -24155.99648299 1222.84128677 -0.535600687 -0.840455444 0.157680857 107329.625277 0.778667 11.46032 186.19193 197.90635 164.18719 106.60817 2005 12 31 1: 0: 0.000268 1920.00000000 -169935.81924592 -31767.29787964 2749.01540345 -0.430050431 -0.828904183 0.157812340 107329.670010 0.778636 11.45772 186.08880 198.56496 166.02584 114.02759 2005 12 31 3: 0: 0.000282 2040.00000000 -172703.07831815 -37662.95639336 3883.60052579 -0.338004891 -0.810277487 0.156020035 107329.707949 0.778608 11.45535 186.07803 198.57159 167.77827 121.44722 2005 12 31 5: 0: 0.000255 2160.00000000 -174823.19337404 -43417.55605219 5003.26312809 -0.250258622 -0.789828672 0.153764903 107329.739705 0.778582 11.45321 186.06765 198.57763 169.46004 128.86707 2005 12 31 7: 0: 0.000268 2280.00000000 -176324.63925775 -49018.51958648 6104.85025002 -0.166136613 -0.767706262 0.151092242 107329.766024 0.778557 11.45129 186.05765 198.58307 171.08420 136.28711 2005 12 31 9: 0: 0.000282 2400.00000000 -177231.42142458 -54454.12699497 7185.48661607 -0.085067854 -0.744001567 0.148033403 107329.787476 0.778535 11.44961 186.04805 198.58792 172.66187 143.70731 2005 12 31 11: 0: 0.000255 2520.00000000 -177563.73583232 -59713.14859144 8242.48472591 -0.006561730 -0.718760309 0.144608676 107329.804495 0.778515 11.44815 186.03884 198.59218 174.20274 151.12767 2005 12 31 13: 0: 0.000267 2640.00000000 -177338.48026483 -64784.54644698 9273.27220003 0.069809946 -0.691990238 0.140829236 107329.817407 0.778496 11.44692 186.03004 198.59585 175.71546 158.54815 2005 12 31 15: 0: 0.000281 2760.00000000 -176569.65151461 -69657.21976255 10275.33063459 0.144426878 -0.663665876 0.136698419 107329.826446 0.778480 11.44593 186.02165 198.59894 177.20787 165.96873 2005 12 31 17: 0: 0.000254 2880.00000000 -175268.65299073 -74319.77625463 11246.14177160 0.217631370 -0.633731091 0.132212491 107329.831764 0.778466 11.44516 186.01367 198.60144 178.68732 173.38940 2005 12 31 19: 0: 0.000267 3000.00000000 -173444.53039609 -78760.31560396 12183.13775212 0.289737325 -0.602099929 0.127361017 107329.833446 0.778454 11.44462 186.00610 198.60338 180.16078 180.81013 2005 12 31 21: 0: 0.000281 3120.00000000 -171104.14813653 -82966.21323591 13083.65278381 0.361037779 -0.568655903 0.122126889 107329.831507 0.778444 11.44430 185.99895 198.60474 181.63509 188.23090 2005 12 31 23: 0: 0.000254 3240.00000000 -168252.31543803 -86923.89363433 13944.87382716 0.431811396 -0.533249797 0.116486022 107329.825896 0.778437 11.44421 185.99222 198.60555 183.11712 195.65169 2006 1 1 1: 0: 0.000268 3360.00000000 -164891.86832887 -90618.58225954 14763.78794247 0.502328269 -0.495695896 0.110406725 107329.816495 0.778432 11.44434 185.98591 198.60580 184.61390 203.07247 2006 1 1 3: 0: 0.000282 3480.00000000 -161023.71139825 -94034.02398835 15537.12375729 0.572855321 -0.455766412 0.103848688 107329.803111 0.778429 11.44468 185.98002 198.60552 186.13287 210.49323 2006 1 1 5: 0: 0.000255 3600.00000000 -156646.82136726 -97152.15370791 16261.28409305 0.643661538 -0.413183688 0.096761524 107329.785464 0.778428 11.44524 185.97454 198.60471 187.68204 217.91394 2006 1 1 7: 0: 0.000268 3720.00000000 -151758.21285737 -99952.70098346 16932.26607548 0.715023254 -0.367609561 0.089082727 107329.763177 0.778430 11.44600 185.96947 198.60339 189.27027 225.33457 2006 1 1 9: 0: 0.000282 3840.00000000 -146352.86521283 -102412.70506284 17545.56394158 0.787229695 -0.318630913 0.080734873 107329.735753 0.778433 11.44698 185.96481 198.60156 190.90753 232.75511 2006 1 1 11: 0: 0.000255 3960.00000000 -140423.60777444 -104505.90799734 18096.04807097 0.860588979 -0.265739987 0.071621768 107329.702541 0.778439 11.44815 185.96056 198.59925 192.60535 240.17554 2006 1 1 13: 0: 0.000268 4080.00000000 -133960.95961851 -106201.98091318 18577.81121953 0.935434758 -0.208307307 0.061623110 107329.662699 0.778448 11.44952 185.95671 198.59647 194.37727 247.59582 2006 1 1 15: 0: 0.000282 4200.00000000 -126952.91860010 -107465.51906186 18983.96903112 1.012133628 -0.145543878 0.050587007 107329.615127 0.778458 11.45107 185.95326 198.59324 196.23957 255.01595 2006 1 1 17: 0: 0.000255 4320.00000000 -119384.69396454 -108254.71115372 19306.39581892 1.091093313 -0.076447479 0.038319282 107329.558377 0.778471 11.45281 185.95019 198.58958 198.21224 262.43589 2006 1 1 19: 0: 0.000268 21897 xx 0.00000000 -14464.72135182 -4699.19517587 0.06681686 -3.249312013 -3.281032707 4.007046940 120.00000000 -19410.46286123 -19143.03318969 23114.05522619 0.508602237 -1.156882269 2.379923455 26496.848378 0.741871 62.15077 197.99034 253.02470 153.97965 80.54281 2006 6 25 2:33:42.834827 240.00000000 -12686.06129708 -23853.75335645 35529.81733588 1.231633829 -0.221718202 1.118440291 26496.776778 0.741934 62.14759 197.97571 253.02600 171.17148 140.92615 2006 6 25 4:33:42.834800 360.00000000 -2775.46649359 -22839.64574119 39494.64689967 1.468963405 0.489481769 -0.023972788 26496.835891 0.741965 62.14587 197.96010 253.03207 184.73741 201.30254 2006 6 25 6:33:42.834814 480.00000000 7679.87883570 -16780.50760106 34686.21815555 1.364171080 1.211183897 -1.385151371 26496.289021 0.741948 62.14528 197.94355 253.03955 200.07775 261.67607 2006 6 25 8:33:42.834827 600.00000000 14552.40023028 -4819.50121461 17154.70672449 0.109201591 2.176124494 -3.854856805 26495.176345 0.741858 62.14830 197.92528 253.04131 229.46303 322.05488 2006 6 25 10:33:42.834800 720.00000000 -15302.38845375 -5556.43440300 1095.95088753 -2.838224312 -3.134231137 3.992596326 26506.323556 0.741895 62.15595 197.91858 253.04384 111.31264 22.43527 2006 6 25 12:33:42.834814 840.00000000 -19289.20066748 -19427.04851118 23759.45685636 0.552495087 -1.112499437 2.325112654 26496.940826 0.741877 62.14985 197.91054 253.03039 154.81314 82.83578 2006 6 25 14:33:42.834827 960.00000000 -12376.21976437 -23893.38020018 35831.33691892 1.246701529 -0.194294048 1.074867282 26496.907554 0.741938 62.14678 197.89586 253.03198 171.71102 143.21830 2006 6 25 16:33:42.834800 1080.00000000 -2400.55677665 -22698.62264640 39482.75964390 1.472582922 0.513555654 -0.069306561 26496.953751 0.741967 62.14513 197.88025 253.03816 185.25481 203.59408 2006 6 25 18:33:42.834814 1200.00000000 8031.66819252 -16455.77592085 34298.94391742 1.351357426 1.239633234 -1.448195324 26496.371944 0.741949 62.14462 197.86366 253.04563 200.78363 263.96715 2006 6 25 20:33:42.834827 1320.00000000 14559.48780372 -4238.43773813 16079.23154704 -0.026409655 2.218938770 -4.012628896 26495.430098 0.741856 62.14804 197.84539 253.04660 231.58431 324.34636 2006 6 25 22:33:42.834800 1440.00000000 -16036.04980660 -6372.51406468 2183.44834232 -2.485113443 -2.994994355 3.955891272 26505.102094 0.741884 62.15519 197.83969 253.04873 115.11318 24.72694 2006 6 26 0:33:42.834814 1560.00000000 -19156.71583814 -19698.89059957 24389.29473934 0.594278133 -1.069418599 2.271152044 26497.039709 0.741881 62.14912 197.83085 253.03611 155.62301 85.12611 2006 6 26 2:33:42.834827 1680.00000000 -12062.72925552 -23925.82362911 36120.66680667 1.261238798 -0.167201856 1.031478939 26497.039771 0.741942 62.14616 197.81614 253.03797 172.24585 145.50782 2006 6 26 4:33:42.834800 1800.00000000 -2024.96136966 -22551.56626703 39458.50085787 1.475816889 0.537615764 -0.114887472 26497.072294 0.741969 62.14458 197.80051 253.04425 185.77405 205.88299 2006 6 26 6:33:42.834814 1920.00000000 8379.80916204 -16123.95878459 33894.75123231 1.337468254 1.268432783 -1.512473301 26496.454529 0.741948 62.14417 197.78390 253.05170 201.50398 266.25560 2006 6 26 8:33:42.834827 2040.00000000 14527.86748873 -3646.33817120 14960.74306518 -0.180035839 2.261273515 -4.179355590 26495.757400 0.741854 62.14802 197.76565 253.05176 233.88700 326.63530 2006 6 26 10:33:42.834800 2160.00000000 -16680.12147335 -7149.80800425 3257.64227208 -2.178897351 -2.863927095 3.904876943 26504.063299 0.741875 62.15456 197.76082 253.05357 118.47275 27.01600 2006 6 26 12:33:42.834814 2280.00000000 -19013.58793448 -19958.93766022 25003.81778666 0.634100431 -1.027559823 2.218002685 26497.144400 0.741885 62.14859 197.75128 253.04184 156.41087 87.41374 2006 6 26 14:33:42.834827 2400.00000000 -11745.76155818 -23951.19438627 36397.87676581 1.275261813 -0.140425132 0.988259441 26497.173335 0.741945 62.14574 197.73654 253.04395 172.77631 147.79464 2006 6 26 16:33:42.834800 2520.00000000 -1648.81945070 -22398.50594576 39421.83273890 1.478660174 0.561671519 -0.160733093 26497.191441 0.741971 62.14423 197.72090 253.05032 186.29537 208.16920 2006 6 26 18:33:42.834814 2640.00000000 8723.97652795 -15784.99406275 33473.35215527 1.322433593 1.297602497 -1.578055493 26496.536697 0.741948 62.14391 197.70426 253.05773 202.23974 268.54135 2006 6 26 20:33:42.834827 2760.00000000 14452.25571587 -3043.42332645 13796.84870805 -0.355190169 2.302485443 -4.355767077 26496.183479 0.741852 62.14824 197.68605 253.05673 236.40222 328.92169 2006 6 26 22:33:42.834800 2880.00000000 -17246.31075678 -7890.72601508 4315.39410307 -1.910968458 -2.740945672 3.844722726 26503.192902 0.741869 62.15409 197.68196 253.05836 121.47363 29.30235 2006 6 27 0:33:42.834814 22312 xx 0.00000000 1442.10132912 6510.23625449 8.83145885 -3.475714837 0.997262768 6.835860345 54.20286720 306.10478453 -5816.45655525 -2979.55846068 3.950663855 3.415332543 -5.879974329 6642.712393 0.026751 62.15694 77.33613 267.89734 303.10361 305.64343 2006 4 4 12: 0: 0.000000 74.20286720 3282.82085464 2077.46972905 -5189.17988770 0.097342701 7.375135692 2.900196702 6624.819378 0.024397 62.13721 77.24656 266.29125 28.81974 27.49337 2006 4 4 12:20: 0.000009 94.20286720 530.82729176 6426.20790003 1712.37076793 -3.837120395 -1.252430637 6.561602577 6627.302374 0.023364 62.16344 77.21663 268.97389 107.89922 105.33791 2006 4 4 12:40: 0.000018 114.20286720 -3191.69170212 170.27219912 5956.29807775 -1.394956872 -7.438073471 -0.557553115 6604.492961 0.023646 62.13093 77.14529 268.36869 186.24800 186.54817 2006 4 4 13: 0: 0.000027 134.20286720 -1818.99222465 -6322.45146616 681.95247154 3.349795173 -1.530140265 -6.831522765 6610.594335 0.021003 62.16606 77.08669 265.98100 267.32341 269.72918 2006 4 4 13:19:59.999996 154.20286720 2515.66448634 -2158.83091224 -5552.13320544 2.571979660 7.311930509 -1.639865620 6586.953427 0.018745 62.13265 77.04340 269.10455 347.11960 347.59194 2006 4 4 13:40: 0.000004 174.20286720 2414.52833210 5749.10150922 -1998.59693165 -2.681032960 3.527589301 6.452951429 6591.204604 0.018928 62.16234 76.96310 269.04144 70.76660 68.72834 2006 4 4 14: 0: 0.000013 194.20286720 -1877.98944331 3862.27848302 5112.48435863 -3.261489804 -6.026859137 3.433254768 6572.294187 0.017738 62.13955 76.93610 265.71039 154.29604 153.40379 2006 4 4 14:20: 0.000022 214.20286720 -3117.36584395 -4419.74773864 3840.85960912 1.545479182 -5.475416581 -5.207913748 6568.284870 0.015684 62.15118 76.83990 269.11529 229.97683 231.36357 2006 4 4 14:40: 0.000031 234.20286720 815.32034678 -5231.67692249 -3760.04690354 3.870864200 4.455588552 -5.211082191 6559.508678 0.014817 62.15119 76.82210 269.22878 311.67848 312.93729 2006 4 4 15: 0: 0.000000 254.20286720 3269.54341810 3029.00081083 -4704.67969713 -0.526711345 6.812157950 3.929825087 6546.649263 0.013051 62.14224 76.72370 264.90505 39.89814 38.94603 2006 4 4 15:20: 0.000009 274.20286720 -10.18099756 6026.23341453 2643.50518407 -3.953623254 -2.616070012 6.145637500 6545.039189 0.011558 62.15933 76.70079 268.43457 118.58533 117.41752 2006 4 4 15:40: 0.000018 294.20286720 -3320.58819584 -1248.42679945 5563.06017927 -0.637046974 -7.417786044 -2.076120187 6525.176402 0.011656 62.13358 76.61292 270.70303 196.79045 197.17955 2006 4 4 16: 0: 0.000027 314.20286720 -1025.48974616 -6366.98945782 -911.23559153 3.811771909 0.438071490 -6.829260617 6530.230580 0.009674 62.16606 76.57180 263.90775 285.19541 286.26314 2006 4 4 16:19:59.999996 334.20286720 3003.75996128 -413.85708003 -5706.15591435 1.674350083 7.694169068 0.316915204 6505.803788 0.006811 62.13025 76.50361 266.53496 6.11366 6.03095 2006 4 4 16:40: 0.000004 354.20286720 1731.42816980 6258.27676925 -409.32527982 -3.400497806 1.447945424 6.904010052 6512.753987 0.006901 62.16689 76.44254 273.83621 82.08415 81.30142 2006 4 4 17: 0: 0.000013 374.20286720 -2582.52111460 2024.19020680 5647.55650268 -2.530348121 -7.221719393 1.438141553 6488.794923 0.006638 62.13168 76.39375 264.49316 173.49020 173.40353 2006 4 4 17:20: 0.000022 394.20286720 -2440.56848578 -5702.77311877 1934.81094689 2.731792947 -3.350576075 -6.527773339 6493.252420 0.003791 62.16296 76.31134 261.19573 259.12648 259.55338 2006 4 4 17:40: 0.000031 414.20286720 1951.22934391 -3423.59443045 -5121.67808201 3.249039133 6.465974362 -3.069806659 6473.394862 0.002271 62.13728 76.28059 284.12925 319.57136 319.73993 2006 4 4 18: 0: 0.000000 434.20286720 2886.50939356 4888.68626216 -3096.29885989 -1.973162139 4.877039020 5.832414910 6472.688808 0.001961 62.15632 76.18354 265.24222 61.97210 61.77383 2006 4 4 18:20: 0.000009 454.20286720 -1276.55532182 4553.26898463 4406.19787375 -3.715146421 -5.320176914 4.418210777 6459.006045 0.000745 62.14506 76.16223 208.56146 201.88650 201.91833 2006 4 4 18:40: 0.000018 474.20286720 -3181.54698042 -3831.29976506 4096.80242787 1.114159970 -6.104773578 -4.829967400 6451.404727 0.001204 62.14799 76.05860 64.89393 69.17243 69.04352 2006 4 4 19: 0: 0.000027 22674 xx 0.00000000 14712.22023280 -1443.81061850 0.83497888 4.418965470 1.629592098 4.115531802 120.00000000 25418.88807860 9342.60307989 23611.46690798 0.051284086 1.213127306 2.429004159 26907.446048 0.754417 63.47604 354.38565 253.38944 153.87316 77.66558 2006 6 25 15:25: 5.468479 240.00000000 21619.59550749 16125.24978864 36396.79365831 -0.963604380 0.685454965 1.177181937 26907.320792 0.754473 63.47280 354.37023 253.39043 170.50414 136.67028 2006 6 25 17:25: 5.468452 360.00000000 12721.50543331 19258.96193362 40898.47648359 -1.457448565 0.179955469 0.071502601 26907.384192 0.754499 63.47098 354.35397 253.39603 183.35229 195.66845 2006 6 25 19:25: 5.468465 480.00000000 1272.80760054 18458.41971897 37044.74742696 -1.674863386 -0.436454983 -1.201040990 26906.921814 0.754481 63.47015 354.33691 253.40308 197.36469 254.66385 2006 6 25 21:25: 5.468479 600.00000000 -10058.43188619 11906.60764454 21739.62097733 -1.245829683 -1.543789125 -3.324449221 26905.507820 0.754395 63.47189 354.31822 253.40665 221.31684 313.66201 2006 6 25 23:25: 5.468452 720.00000000 10924.40116466 -2571.92414170 -2956.34856294 6.071727751 1.349579102 3.898430260 26924.786210 0.754481 63.48004 354.30550 253.40881 90.05134 12.66261 2006 6 26 1:25: 5.468465 840.00000000 25332.14851525 8398.91099924 21783.90654357 0.222320754 1.272214306 2.580527192 26907.401993 0.754371 63.47512 354.30117 253.39435 151.57470 71.68609 2006 6 26 3:25: 5.468479 960.00000000 22317.71926039 15574.82086129 35495.77144092 -0.892750056 0.737383381 1.291738834 26907.131806 0.754428 63.47168 354.28600 253.39441 169.10125 130.69257 2006 6 26 5:25: 5.468452 1080.00000000 13795.68675885 19088.83051008 40803.69584385 -1.420277669 0.235599456 0.185517056 26907.218387 0.754456 63.46978 354.26988 253.39960 182.06939 189.69195 2006 6 26 7:25: 5.468465 1200.00000000 2515.17145049 18746.63776282 37864.58088636 -1.668016053 -0.360431458 -1.052854596 26906.830287 0.754443 63.46888 354.25300 253.40650 195.74699 248.68825 2006 6 26 9:25: 5.468479 1320.00000000 -9084.48602106 12982.62608646 24045.63900249 -1.378032363 -1.373184736 -3.013963835 26905.447050 0.754365 63.47013 354.23461 253.41092 217.63762 307.68622 2006 6 26 11:25: 5.468452 1440.00000000 5647.00909495 -3293.90518693 -5425.85235063 8.507977176 0.414560797 2.543322806 26916.290668 0.754396 63.47401 354.21856 253.40298 61.05276 6.69602 2006 6 26 13:25: 5.468465 1560.00000000 25111.63372210 7412.55109488 19844.25781729 0.416496290 1.332106006 2.739301737 26907.399792 0.754321 63.47443 354.21714 253.39867 149.06255 65.71096 2006 6 26 15:25: 5.468479 1680.00000000 22961.47461641 14985.74459578 34511.09257381 -0.816711048 0.789391108 1.407901804 26906.926757 0.754378 63.47076 354.20225 253.39768 167.66018 124.71943 2006 6 26 17:25: 5.468452 1800.00000000 14841.15301459 18876.91439870 40626.25901619 -1.380403341 0.290228810 0.298258120 26907.030950 0.754410 63.46879 354.18629 253.40242 180.79350 183.72010 2006 6 26 19:25: 5.468465 1920.00000000 3750.70174081 18978.57939698 38578.11783220 -1.656939412 -0.287930881 -0.910825599 26906.710968 0.754401 63.46780 354.16960 253.40914 194.19598 242.71741 2006 6 26 21:25: 5.468479 2040.00000000 -8027.30219489 13939.54436955 26136.49045637 -1.474476061 -1.222693624 -2.737178731 26905.414344 0.754332 63.46868 354.15151 253.41415 214.43331 301.71552 2006 6 26 23:25: 5.468452 2160.00000000 -1296.95657092 -2813.69369768 -5871.09587258 9.881929371 -1.978467207 -1.922261005 26883.528690 0.754076 63.46772 354.14317 253.40458 7.90472 0.72988 2006 6 27 1:25: 5.468465 2280.00000000 24738.60364819 6383.41644019 17787.27631900 0.639556952 1.392554379 2.906206324 26907.465635 0.754270 63.47397 354.13359 253.40239 146.28467 59.74053 2006 6 27 3:25: 5.468479 2400.00000000 23546.85388669 14358.15602832 33441.67679479 -0.734895006 0.841564851 1.526009909 26906.708322 0.754328 63.47004 354.11905 253.40022 166.17410 118.75117 2006 6 27 5:25: 5.468452 2520.00000000 15855.87696303 18624.05633582 40367.13420574 -1.337753546 0.343969522 0.410018472 26906.823807 0.754363 63.46798 354.10325 253.40448 179.52076 177.75324 2006 6 27 7:25: 5.468465 2640.00000000 4976.44933591 19156.75504042 39189.68603184 -1.642084365 -0.218525096 -0.774148204 26906.566313 0.754359 63.46693 354.08675 253.41097 192.70180 236.75162 2006 6 27 9:25: 5.468479 2760.00000000 -6909.20746210 14790.44707042 28034.46732222 -1.545152610 -1.088119523 -2.487447214 26905.379434 0.754297 63.46749 354.06895 253.41640 211.59122 295.75013 2006 6 27 11:25: 5.468452 2880.00000000 -7331.65006707 -604.17323419 -2723.51014575 6.168997265 -3.634011554 -5.963531682 26932.982781 0.754437 63.47616 354.06279 253.40079 309.43115 354.77141 2006 6 27 13:25: 5.468465 23177 xx 0.00000000 -8801.60046706 -0.03357557 -0.44522743 -3.835279101 -7.662552175 0.944561323 120.00000000 -1684.34352858 -31555.95196340 3888.99944319 2.023055719 -2.151306405 0.265065778 24533.544698 0.726309 7.02569 179.98604 295.86843 151.11298 76.24877 2006 6 24 12:58:49.772928 240.00000000 12325.51410155 -38982.15046244 4802.88832275 1.763224157 -0.102514446 0.012397139 24535.059510 0.726254 7.02627 179.93731 295.94436 171.54027 144.01600 2006 6 24 14:58:49.772902 360.00000000 22773.66831936 -34348.02176606 4228.77407391 1.067616787 1.352427865 -0.166956367 24535.087190 0.726257 7.02729 179.89316 296.01268 187.44062 211.78373 2006 6 24 16:58:49.772915 480.00000000 26194.40441089 -19482.94203672 2393.84774063 -0.313732186 2.808771328 -0.346204118 24533.740449 0.726320 7.02875 179.85325 296.07930 207.21934 279.55133 2006 6 24 18:58:49.772928 600.00000000 8893.50573448 5763.38890561 -713.69884164 -7.037399220 3.022613131 -0.370272416 24520.548544 0.726345 7.02924 179.84007 296.13720 277.16584 347.31839 2006 6 24 20:58:49.772902 720.00000000 -6028.75686537 -25648.99913786 3164.37107274 1.883159288 -3.177051976 0.390793162 24532.171198 0.726367 7.02732 179.79385 296.22242 140.85107 55.10759 2006 6 24 22:58:49.772915 840.00000000 8313.57299056 -38146.45710922 4697.80777535 1.905002133 -0.625883074 0.076098187 24534.782500 0.726296 7.02762 179.74233 296.30405 166.15697 122.87443 2006 6 25 0:58:49.772928 960.00000000 20181.29108622 -36842.60674073 4529.12568218 1.326244476 0.921916487 -0.114527455 24535.152485 0.726280 7.02857 179.69683 296.37408 182.45877 190.64203 2006 6 25 2:58:49.772902 1080.00000000 26302.61794569 -25173.39539436 3084.65309986 0.245398835 2.329974347 -0.287495880 24534.369133 0.726324 7.02989 179.65505 296.44116 199.94460 258.40971 2006 6 25 4:58:49.772915 1200.00000000 19365.07045602 -2700.00490122 317.42727417 -3.009733018 3.902496058 -0.478928582 24529.466218 0.726412 7.03179 179.62568 296.50569 235.87460 326.17655 2006 6 25 6:58:49.772928 1320.00000000 -9667.81878780 -16930.19112642 2095.87469034 1.279288285 -4.736005905 0.582878255 24529.319623 0.726417 7.02957 179.60155 296.57421 124.28038 33.96646 2006 6 25 8:58:49.772902 1440.00000000 4021.31438583 -36066.09209609 4442.91587411 2.007322354 -1.227461376 0.149383897 24534.337561 0.726341 7.02914 179.54665 296.66427 160.10044 101.73277 2006 6 25 10:58:49.772915 23333 xx 0.00000000 -9301.24542292 3326.10200382 2318.36441127 -8.729303005 -0.828225037 -0.122314827 120.00000000 -44672.91239680 -6213.11996581 -1738.80131727 -3.719475070 -1.336673022 -0.621888261 240974.904244 0.990604 30.27700 4.13167 29.05777 155.32433 2.42179 1994 11 1 13:59:59.999169 240.00000000 -67053.08885388 -14994.69685946 -5897.99072793 -2.860576613 -1.183771565 -0.568473909 241188.455558 0.990674 30.28101 4.15169 29.05234 160.71292 4.53570 1994 11 1 15:59:59.999142 360.00000000 -85227.84253168 -22897.08484471 -9722.59184564 -2.426469823 -1.078592475 -0.525341431 241281.310582 0.990736 30.28476 4.16382 29.05288 163.48883 6.64765 1994 11 1 17:59:59.999155 480.00000000 -100986.00419136 -30171.19698695 -13283.77044765 -2.147108978 -1.000530827 -0.491587582 241334.995602 0.990793 30.28821 4.17269 29.05598 165.29944 8.75802 1994 11 1 19:59:59.999169 600.00000000 -115093.00686387 -36962.56316477 -16634.15682929 -1.945446188 -0.938947736 -0.464199202 241370.592903 0.990845 30.29123 4.17959 29.06071 166.61941 10.86701 1994 11 1 21:59:59.999142 720.00000000 -127965.80064891 -43363.32967165 -19809.90480432 -1.789652016 -0.888278463 -0.441254468 241396.215034 0.990893 30.29375 4.18503 29.06667 167.64657 12.97474 1994 11 1 23:59:59.999155 840.00000000 -139863.28332207 -49436.45704153 -22836.80438139 -1.663762568 -0.845315913 -0.421548627 241415.704319 0.990937 30.29572 4.18925 29.07371 168.48089 15.08132 1994 11 2 1:59:59.999169 960.00000000 -150960.22978259 -55227.45413896 -25734.01408879 -1.558730986 -0.808061065 -0.404293846 241431.134912 0.990977 30.29708 4.19238 29.08170 169.17940 17.18685 1994 11 2 3:59:59.999142 1080.00000000 -161381.71414630 -60770.64040903 -28516.26290017 -1.468977174 -0.775190459 -0.388951810 241443.732852 0.991012 30.29782 4.19450 29.09061 169.77752 19.29141 1994 11 2 5:59:59.999155 1200.00000000 -171221.18736947 -66092.76474442 -31195.19847387 -1.390837596 -0.745785633 -0.375140398 241454.272978 0.991043 30.29790 4.19565 29.10039 170.29863 21.39510 1994 11 2 7:59:59.999169 1320.00000000 -180550.82888746 -71215.23290630 -33780.24938270 -1.321788672 -0.719184752 -0.362579495 241463.270793 0.991070 30.29731 4.19584 29.11101 170.75893 23.49801 1994 11 2 9:59:59.999142 1440.00000000 -189427.87533074 -76155.54943344 -36279.19882816 -1.260024473 -0.694896053 -0.351058133 241471.083479 0.991092 30.29602 4.19510 29.12247 171.17009 25.60022 1994 11 2 11:59:59.999155 1560.00000000 -197898.69401409 -80928.29015181 -38698.57972447 -1.204211888 -0.672544709 -0.340413731 241477.966779 0.991110 30.29403 4.19343 29.13474 171.54075 27.70182 1994 11 2 13:59:59.999169 1600.00000000 -200638.82986236 -82484.14969882 -39488.34331447 -1.186748462 -0.665472422 -0.337037582 241480.088691 0.991115 30.29321 4.19267 29.13901 171.65650 28.40224 1994 11 2 14:39:59.999146 23599 xx 0.00000000 9892.63794341 35.76144969 -1.08228838 3.556643237 6.456009375 0.783610890 20.00000000 11931.95642997 7340.74973750 886.46365987 0.308329116 5.532328972 0.672887281 15547.622905 0.578405 6.93653 0.26070 274.48704 117.04012 47.66168 2006 6 20 18:42: 6.640047 40.00000000 11321.71039205 13222.84749156 1602.40119049 -1.151973982 4.285810871 0.521919425 15548.637837 0.578320 6.93525 0.24878 274.51472 134.87362 70.04973 2006 6 20 19: 2: 6.640056 60.00000000 9438.29395675 17688.05450261 2146.59293402 -1.907904054 3.179955046 0.387692479 15549.179284 0.578245 6.93440 0.23242 274.54243 147.31620 92.43959 2006 6 20 19:22: 6.640025 80.00000000 6872.08634639 20910.11016811 2539.79945034 -2.323995367 2.207398462 0.269506121 15549.480633 0.578186 6.93388 0.21466 274.56891 157.14902 114.83065 2006 6 20 19:42: 6.640034 100.00000000 3933.37509798 23024.07662542 2798.25966746 -2.542860616 1.327134966 0.162450076 15549.637825 0.578144 6.93359 0.19650 274.59420 165.58555 137.22250 2006 6 20 20: 2: 6.640043 120.00000000 816.64091546 24118.98675475 2932.69459428 -2.626838010 0.504502763 0.062344306 15549.694828 0.578119 6.93348 0.17828 274.61863 173.27933 159.61486 2006 6 20 20:22: 6.640052 140.00000000 -2334.41705804 24246.86096326 2949.36448841 -2.602259646 -0.288058266 -0.034145135 15549.671364 0.578110 6.93351 0.16016 274.64256 180.65778 182.00752 2006 6 20 20:42: 6.640020 160.00000000 -5394.31798039 23429.42716149 2850.86832586 -2.474434068 -1.074055982 -0.129868366 15549.572685 0.578119 6.93368 0.14223 274.66633 188.06638 204.40029 2006 6 20 21: 2: 6.640029 180.00000000 -8233.35130237 21661.24480883 2636.51456118 -2.230845533 -1.875742344 -0.227528603 15549.391856 0.578145 6.93400 0.12463 274.69024 195.85810 226.79300 2006 6 20 21:22: 6.640038 200.00000000 -10693.96497348 18909.88168891 2302.33707548 -1.835912433 -2.716169865 -0.329931880 15549.106551 0.578187 6.93449 0.10761 274.71459 204.48744 249.18540 2006 6 20 21:42: 6.640047 220.00000000 -12553.89669904 15114.63990716 1840.93573231 -1.212478879 -3.619036996 -0.439970633 15548.667306 0.578247 6.93519 0.09173 274.73953 214.67449 271.57721 2006 6 20 22: 2: 6.640056 240.00000000 -13450.20591864 10190.57904289 1241.95958736 -0.189082511 -4.596701971 -0.559173899 15547.963560 0.578323 6.93616 0.07840 274.76483 227.80437 293.96798 2006 6 20 22:22: 6.640025 260.00000000 -12686.60437121 4079.31106161 498.27078614 1.664498211 -5.559889865 -0.676747779 15546.711990 0.578406 6.93733 0.07140 274.78871 247.19148 316.35697 2006 6 20 22:42: 6.640034 280.00000000 -8672.55867753 -2827.56823315 -342.59644716 5.515079852 -5.551222962 -0.676360044 15544.010993 0.578460 6.93732 0.07850 274.80676 283.29657 338.74359 2006 6 20 23: 2: 6.640043 300.00000000 1153.31498060 -6411.98692060 -779.87288941 9.689818102 1.388598425 0.167868798 15540.098871 0.578416 6.93363 0.04848 274.86265 5.21286 1.13692 2006 6 20 23:22: 6.640052 320.00000000 9542.79201056 -533.71253081 -65.73165428 3.926947087 6.459583539 0.785686755 15544.294010 0.578456 6.93773 0.03892 274.89936 81.83675 23.52881 2006 6 20 23:42: 6.640020 340.00000000 11868.80960100 6861.59590848 833.72780602 0.452957852 5.632811328 0.685262323 15546.620467 0.578393 6.93667 0.04257 274.91970 115.25337 45.91615 2006 6 21 0: 2: 6.640029 360.00000000 11376.23941678 12858.97121366 1563.40660172 -1.087665695 4.374693347 0.532207051 15547.691609 0.578308 6.93536 0.03111 274.94738 133.73131 68.30593 2006 6 21 0:22: 6.640038 380.00000000 9547.70300782 17421.48570758 2118.56907515 -1.876540262 3.253891728 0.395810243 15548.259173 0.578232 6.93448 0.01484 274.97527 146.46231 90.69758 2006 6 21 0:42: 6.640047 400.00000000 7008.51470263 20725.47471227 2520.56064289 -2.308703599 2.270724438 0.276138613 15548.575058 0.578171 6.93394 359.99708 275.00191 156.44481 113.09047 2006 6 21 1: 2: 6.640056 420.00000000 4082.28135104 22911.04184601 2786.37568309 -2.536665546 1.383670232 0.168153407 15548.741629 0.578128 6.93365 359.97890 275.02731 164.96310 135.48417 2006 6 21 1:22: 6.640025 440.00000000 969.17978149 24071.23673676 2927.31326579 -2.626695115 0.557172428 0.067536854 15548.805595 0.578101 6.93353 359.96067 275.05181 172.69842 157.87841 2006 6 21 1:42: 6.640034 460.00000000 -2184.71515444 24261.21671601 2950.08142825 -2.607072866 -0.236887607 -0.029125215 15548.788114 0.578092 6.93356 359.94255 275.07576 180.08944 180.27296 2006 6 21 2: 2: 6.640043 480.00000000 -5253.42223370 23505.37595671 2857.66120738 -2.484424544 -1.022255436 -0.124714444 15548.695438 0.578099 6.93373 359.92464 275.09949 187.48463 202.66765 2006 6 21 2:22: 6.640052 500.00000000 -8108.27961017 21800.81688388 2649.72981961 -2.247597251 -1.821159176 -0.221925624 15548.521637 0.578123 6.93404 359.90705 275.12334 195.23350 225.06227 2006 6 21 2:42: 6.640020 520.00000000 -10594.77795556 19117.80779221 2322.72136979 -1.863118484 -2.656426668 -0.323521502 15548.245869 0.578165 6.93453 359.89004 275.14758 203.77845 247.45662 2006 6 21 3: 2: 6.640029 540.00000000 -12497.32045995 15398.64085906 1869.69983897 -1.258130763 -3.551583368 -0.432338888 15547.821560 0.578224 6.93521 359.87414 275.17238 213.80987 269.85041 2006 6 21 3:22: 6.640038 560.00000000 -13467.92475245 10560.90147785 1280.78399181 -0.271870523 -4.520514224 -0.550016092 15547.145158 0.578298 6.93616 359.86065 275.19755 226.63566 292.24318 2006 6 21 3:42: 6.640047 580.00000000 -12848.18843590 4541.21901842 548.53826427 1.494157156 -5.489585384 -0.667472039 15545.954778 0.578381 6.93731 359.85308 275.22153 245.32752 314.63426 2006 6 21 4: 2: 6.640056 600.00000000 -9152.70552728 -2344.24950144 -287.98121970 5.127921095 -5.650383025 -0.685989008 15543.427373 0.578441 6.93752 359.85908 275.23996 279.36953 337.02292 2006 6 21 4:22: 6.640025 620.00000000 280.38490909 -6500.10264018 -790.36092984 9.779619614 0.581815811 0.074171345 15539.183949 0.578397 6.93356 359.83531 275.29040 357.32499 359.41697 2006 6 21 4:42: 6.640034 640.00000000 9166.25784315 -1093.12552651 -129.49428887 4.316668714 6.438636494 0.785116609 15543.127109 0.578439 6.93774 359.81927 275.33284 77.99879 21.81191 2006 6 21 5: 2: 6.640043 660.00000000 11794.48942915 6382.21138354 780.88439015 0.604412453 5.731729369 0.697574333 15545.613335 0.578381 6.93681 359.82453 275.35227 113.41906 44.20101 2006 6 21 5:22: 6.640052 680.00000000 11424.30138324 12494.26088864 1524.33165488 -1.021328075 4.463448968 0.542532698 15546.743618 0.578296 6.93546 359.81358 275.37991 132.57719 66.59253 2006 6 21 5:42: 6.640020 700.00000000 9652.09867350 17153.84762075 2090.48038336 -1.844516637 3.327522235 0.403915232 15547.338242 0.578219 6.93456 359.79741 275.40798 145.60776 88.98597 2006 6 21 6: 2: 6.640029 720.00000000 7140.41945884 20539.25485336 2501.21469368 -2.293173684 2.333507912 0.282716311 15547.669004 0.578157 6.93401 359.77965 275.43479 155.74449 111.38068 2006 6 21 6:22: 6.640038 24208 xx 0.00000000 7534.10987189 41266.39266843 -0.10801028 -3.027168008 0.558848996 0.207982755 120.00000000 -14289.19940414 39469.05530051 1428.62838591 -2.893205245 -1.045447840 0.179634249 42024.462667 0.002654 3.86558 79.65742 312.64347 77.65798 77.36100 2006 6 26 2:58:29.343360 240.00000000 -32222.92014955 26916.25425799 2468.59996594 -1.973007929 -2.359335071 0.102539376 42024.460259 0.002635 3.86588 79.65846 312.61947 107.90553 107.61807 2006 6 26 4:58:29.343334 360.00000000 -41413.95109398 7055.51656639 2838.90906671 -0.521665080 -3.029172207 -0.002066843 42024.461545 0.002619 3.86620 79.65863 312.38923 138.28220 138.08222 2006 6 26 6:58:29.343347 480.00000000 -39402.72251896 -14716.42475223 2441.32678358 1.066928187 -2.878714619 -0.105865729 42024.469934 0.002610 3.86660 79.65889 312.01255 168.75117 168.69272 2006 6 26 8:58:29.343360 600.00000000 -26751.08889828 -32515.13982431 1384.38865570 2.366228869 -1.951032799 -0.181018498 42024.481662 0.002611 3.86703 79.66015 311.58756 199.25170 199.35053 2006 6 26 10:58:29.343334 720.00000000 -6874.77975542 -41530.38329422 -46.60245459 3.027415087 -0.494671177 -0.207337260 42024.489587 0.002622 3.86741 79.66238 311.23353 229.70694 229.93639 2006 6 26 12:58:29.343347 840.00000000 14859.52039042 -39302.58907247 -1465.02482524 2.869609883 1.100123969 -0.177514425 42024.490266 0.002639 3.86772 79.66463 311.05370 260.05002 260.34804 2006 6 26 14:58:29.343360 960.00000000 32553.14863770 -26398.88401807 -2485.45866002 1.930064459 2.401574539 -0.099250520 42024.487467 0.002659 3.86799 79.66596 311.09429 290.25453 290.54016 2006 6 26 16:58:29.343334 1080.00000000 41365.67576837 -6298.09965811 -2828.05254033 0.459741276 3.051680214 0.006431872 42024.488505 0.002674 3.86829 79.66643 311.33514 320.33757 320.53287 2006 6 26 18:58:29.343347 1200.00000000 38858.83295070 15523.39314924 -2396.86850752 -1.140211488 2.867567143 0.110637217 42024.496806 0.002682 3.86866 79.66700 311.70927 350.34072 350.39219 2006 6 26 20:58:29.343360 1320.00000000 25701.46068162 33089.42617648 -1308.68556638 -2.428713821 1.897381431 0.184605907 42024.508270 0.002681 3.86906 79.66860 312.12116 20.31919 20.21272 2006 6 26 22:58:29.343334 1440.00000000 5501.08137100 41590.27784405 138.32522930 -3.050691874 0.409203052 0.207958133 42024.515451 0.002670 3.86942 79.67113 312.46070 50.33985 50.10466 2006 6 27 0:58:29.343347 25954 xx 0.00000000 8827.15660472 -41223.00971237 3.63482963 3.007087319 0.643701323 0.000941663 -1440.00000000 8118.18519221 -41368.40537378 4.11046687 3.017696741 0.591994297 0.000933016 42165.914638 0.000211 0.01826 263.28658 0.01042 17.80570 17.79830 2004 2 7 16:20: 1.494254 -1320.00000000 27766.34015328 -31724.97000557 9.93297846 2.314236153 2.024903193 0.000660861 42165.915761 0.000201 0.01827 263.55896 4.35639 43.27773 43.26192 2004 2 7 18:20: 1.494268 -1200.00000000 39932.57237973 -13532.60040454 13.12958252 0.987382819 2.911942843 0.000213298 42165.916883 0.000185 0.01828 263.82834 7.22430 70.22655 70.20659 2004 2 7 20:20: 1.494241 -1080.00000000 41341.01365441 8305.71681955 12.84988501 -0.605098224 3.014378268 -0.000291034 42165.918006 0.000166 0.01828 264.09508 7.50812 99.75671 99.73798 2004 2 7 22:20: 1.494254 -960.00000000 31614.99210558 27907.29155353 9.16618797 -2.034243523 2.305014102 -0.000718418 42165.919128 0.000149 0.01829 264.35996 4.12436 132.95128 132.93882 2004 2 8 0:20: 1.494268 -840.00000000 13375.75227587 39994.27017651 3.05416854 -2.915424366 0.975119874 -0.000955576 42165.920251 0.000139 0.01829 264.62314 357.12223 169.76254 169.75970 2004 2 8 2:20: 1.494241 -720.00000000 -8464.89963309 41312.93549892 -3.86622919 -3.011600615 -0.617275050 -0.000939664 42165.921373 0.000142 0.01828 264.88378 349.09793 207.59777 207.60532 2004 2 8 4:20: 1.494254 -600.00000000 -28026.23406158 31507.89995661 -9.76047869 -2.296840160 -2.043607595 -0.000674889 42165.922495 0.000156 0.01828 265.14051 343.62190 242.89064 242.90655 2004 2 8 6:20: 1.494268 -480.00000000 -40040.01314363 13218.00579413 -13.06594832 -0.963328772 -2.919827983 -0.000231414 42165.923617 0.000175 0.01827 265.39256 342.04855 274.28980 274.30978 2004 2 8 8:20: 1.494241 -360.00000000 -41268.43291976 -8632.06859693 -12.90661266 0.630042315 -3.009677376 0.000273163 42165.924740 0.000193 0.01826 265.64018 343.69520 302.47878 302.49745 2004 2 8 10:20: 1.494254 -240.00000000 -31377.85317015 -28156.13970334 -9.32605530 2.054021717 -2.288554158 0.000704959 42165.925862 0.000207 0.01825 265.88409 347.39803 328.62030 328.63263 2004 2 8 12:20: 1.494268 -120.00000000 -13031.41552688 -40092.33381029 -3.27636660 2.924657466 -0.950541167 0.000949381 42165.926984 0.000213 0.01824 266.12445 352.14502 353.72455 353.72722 2004 2 8 14:20: 1.494241 0.00000000 8827.15660472 -41223.00971237 3.63482963 3.007087319 0.643701323 0.000941663 42165.928106 0.000211 0.01823 266.36034 357.09671 18.62928 18.62157 2004 2 8 16:20: 1.494254 120.00000000 28306.85426674 -31243.80147394 9.57216891 2.279137743 2.064316875 0.000684127 42165.929228 0.000201 0.01821 266.59035 1.45235 44.13385 44.11783 2004 2 8 18:20: 1.494268 240.00000000 40159.05128805 -12845.39151157 12.96086316 0.937265422 2.928448287 0.000245505 42165.930350 0.000184 0.01820 266.81362 4.30035 71.14849 71.12848 2004 2 8 20:20: 1.494241 360.00000000 41192.55903455 9013.79606759 12.90495666 -0.656727442 3.003543458 -0.000257479 42165.931472 0.000165 0.01818 267.03031 4.52874 100.78392 100.76533 2004 2 8 22:20: 1.494254 480.00000000 31131.69755798 28445.55681731 9.42419238 -2.073484842 2.269770851 -0.000691233 42165.932594 0.000148 0.01816 267.24108 1.06703 134.11036 134.09818 2004 2 9 0:20: 1.494268 600.00000000 12687.81846530 40217.83324639 3.44726249 -2.931721827 0.924962230 -0.000940766 42165.933716 0.000139 0.01815 267.44605 354.03167 171.01297 171.01047 2004 2 9 2:20: 1.494241 720.00000000 -9172.23500245 41161.63475527 -3.43575757 -3.000571486 -0.668847508 -0.000940101 42165.934838 0.000143 0.01813 267.64430 346.10073 208.81720 208.82507 2004 2 9 4:20: 1.494254 840.00000000 -28562.51093192 31022.45987587 -9.39562161 -2.261449202 -2.082713897 -0.000689669 42165.935960 0.000156 0.01812 267.83437 340.81305 243.98848 244.00460 2004 2 9 6:20: 1.494268 960.00000000 -40260.77504549 12529.11484344 -12.84915105 -0.913097031 -2.935933528 -0.000256181 42165.937082 0.000175 0.01810 268.01532 339.43378 275.26481 275.28483 2004 2 9 8:20: 1.494241 1080.00000000 -41114.14376538 -9338.87194483 -12.87952404 0.681588815 -2.998432565 0.000245006 42165.938203 0.000194 0.01809 268.18725 341.24255 303.36751 303.38605 2004 2 9 10:20: 1.494254 1200.00000000 -30890.01512240 -28690.40750792 -9.48037212 2.092989805 -2.252978152 0.000680459 42165.939325 0.000207 0.01808 268.35079 345.07548 329.45943 329.47148 2004 2 9 12:20: 1.494268 1320.00000000 -12341.46194020 -40310.06316386 -3.55833201 2.940537098 -0.900219523 0.000934170 42165.940447 0.000213 0.01806 268.50607 349.92737 354.54389 354.54621 2004 2 9 14:20: 1.494241 1440.00000000 9533.27750818 -41065.52390214 3.30756482 2.995596171 0.695200236 0.000938525 42165.941569 0.000211 0.01805 268.65217 354.96241 19.45502 19.44699 2004 2 9 16:20: 1.494254 26900 xx 0.00000000 -42014.83795787 3702.34357772 -26.67500257 -0.269775247 -3.061854393 0.000336726 9300.00000000 40968.68133298 -9905.99156086 11.84946837 0.722756848 2.989645389 -0.000161261 42164.767027 0.000369 0.01639 245.84523 106.56838 353.99350 353.99792 2006 4 23 4:52:50.805439 9360.00000000 42135.66858481 1072.99195618 10.83481752 -0.078150602 3.074772455 -0.000380063 42164.764170 0.000369 0.01634 245.78302 108.14148 7.53423 7.52868 2006 4 23 5:52:50.805426 9400.00000000 41304.75156132 8398.27742944 9.74006214 -0.612515135 3.014117469 -0.000511575 42164.762265 0.000368 0.01631 245.74363 109.16958 16.57977 16.56774 2006 4 23 6:32:50.805444 26975 xx 0.00000000 -14506.92313768 -21613.56043281 10.05018894 2.212943308 1.159970892 3.020600202 120.00000000 7309.62197950 6076.00713664 6800.08705263 1.300543383 5.322579615 -4.788746312 26123.349324 0.560054 68.48502 236.11550 123.78252 17.50438 4.13572 2006 6 23 22:35:47.504573 240.00000000 -3882.62933791 11960.00543452 -25088.14383845 -2.146773699 -1.372461491 -2.579382089 26117.073879 0.560030 68.48255 236.11443 123.77229 130.16671 65.84328 2006 6 24 0:35:47.504546 360.00000000 -16785.45507465 -734.79159704 -34300.57085853 -1.386528125 -1.907762641 -0.220949641 26118.379541 0.560094 68.48218 236.10787 123.77789 161.35349 127.52802 2006 6 24 2:35:47.504559 480.00000000 -23524.16689356 -13629.45124622 -30246.27899200 -0.462846784 -1.586139830 1.269293624 26119.067338 0.560048 68.48302 236.10257 123.78345 183.14112 189.21586 2006 6 24 4:35:47.504573 600.00000000 -22890.23597092 -22209.35900155 -16769.91946116 0.704351342 -0.671112594 2.432433851 26120.011777 0.559971 68.48423 236.09846 123.78018 206.20323 250.91637 2006 6 24 6:35:47.504546 720.00000000 -11646.39698980 -19855.44222106 3574.00109607 2.626712727 1.815887329 2.960883901 26123.528580 0.559989 68.48478 236.09673 123.76923 245.72311 312.62852 2006 6 24 8:35:47.504559 840.00000000 7665.76124241 11159.78946577 345.93813117 -0.584818007 3.193514161 -5.750338922 26128.044712 0.560063 68.48452 236.09161 123.78106 54.64563 14.30872 2006 6 24 10:35:47.504573 960.00000000 -6369.35388112 10204.80073022 -27844.52150384 -2.050573276 -1.582940542 -2.076075232 26117.247803 0.560008 68.48025 236.08813 123.76091 136.91304 76.02300 2006 6 24 12:35:47.504546 1080.00000000 -18345.64763145 -2977.76684430 -34394.90760612 -1.243589864 -1.892050757 0.060372061 26118.503689 0.560049 68.48020 236.08183 123.76785 165.20101 137.70696 2006 6 24 14:35:47.504559 1200.00000000 -23979.74839255 -15436.44139571 -28616.50540218 -0.294973425 -1.482987916 1.478255628 26119.140795 0.559994 68.48109 236.07674 123.77220 186.64104 199.39678 2006 6 24 16:35:47.504573 1320.00000000 -21921.97167880 -22852.45147658 -13784.85308485 0.945455629 -0.428940995 2.596964378 26120.298445 0.559921 68.48230 236.07292 123.76705 210.82692 261.10003 2006 6 24 18:35:47.504546 1440.00000000 -8266.43821031 -17210.74590112 6967.95546070 3.082244069 2.665881872 2.712555075 26123.967825 0.559971 68.48211 236.07180 123.75862 257.86545 322.81023 2006 6 24 20:35:47.504559 1560.00000000 6286.85464535 13809.56328971 -6321.60663781 -1.615964016 1.383135377 -5.358719132 26122.866187 0.559936 68.48158 236.06767 123.76712 80.65139 24.49460 2006 6 24 22:35:47.504573 1680.00000000 -8730.87526788 8244.63344365 -30039.92372791 -1.935622871 -1.724162072 -1.631224738 26117.463964 0.559986 68.47788 236.06204 123.74972 142.76677 86.20372 2006 6 25 0:35:47.504546 1800.00000000 -19735.81883249 -5191.76593007 -34166.14974143 -1.097835530 -1.860148418 0.324401050 26118.598345 0.560007 68.47806 236.05598 123.75718 168.89497 147.88784 2006 6 25 2:35:47.504559 1920.00000000 -24232.73847703 -17112.08243255 -26742.88893252 -0.119786184 -1.364365317 1.680220468 26119.215758 0.559943 68.47901 236.05109 123.76017 190.20604 209.57986 2006 6 25 4:35:47.504573 2040.00000000 -20654.45640708 -23184.54386047 -10611.55144716 1.209238113 -0.144169639 2.748054938 26120.664170 0.559878 68.48021 236.04757 123.75312 215.90502 271.28593 2006 6 25 6:35:47.504546 2160.00000000 -4337.15988957 -13410.46817244 9870.45949215 3.532753095 3.772236461 2.088424247 26122.850548 0.559940 68.47877 236.04681 123.75116 274.31883 332.98979 2006 6 25 8:35:47.504559 2280.00000000 4074.62263523 14698.07548285 -12248.65327973 -2.053824693 0.203325817 -4.607867718 26119.058168 0.559863 68.47808 236.04261 123.74755 98.55763 34.68601 2006 6 25 10:35:47.504573 2400.00000000 -10950.23438984 6148.66879447 -31736.65532865 -1.809875605 -1.816179062 -1.233364913 26117.671278 0.559964 68.47548 236.03606 123.73846 147.97060 96.38601 2006 6 25 12:35:47.504546 2520.00000000 -20952.40702045 -7358.71507895 -33633.06643074 -0.948973031 -1.813594137 0.573893078 26118.668794 0.559966 68.47586 236.03022 123.74586 172.47958 158.07095 2006 6 25 14:35:47.504559 2640.00000000 -24273.48944134 -18637.15546906 -24633.27702390 0.064161440 -1.228537560 1.875728935 26119.300306 0.559897 68.47687 236.02552 123.74736 193.87344 219.76535 2006 6 25 16:35:47.504573 2760.00000000 -19057.55468077 -23148.29322082 -7269.38614178 1.500802809 0.195383037 2.879031237 26121.132971 0.559844 68.47804 236.02234 123.73848 221.59004 281.47421 2006 6 25 18:35:47.504546 2880.00000000 43.69305308 -8145.90299207 11634.57079913 3.780661682 5.105315423 0.714401345 26117.747202 0.559843 68.47478 236.02094 123.74584 297.96744 343.16752 2006 6 25 20:35:47.504559 28057 xx 0.00000000 -2715.28237486 -6619.26436889 -0.01341443 -1.008587273 0.422782003 7.385272942 120.00000000 -1816.87920942 -1835.78762132 6661.07926465 2.325140071 6.655669329 2.463394512 7141.716006 0.000734 98.43247 247.77409 190.16826 240.31625 240.38933 2006 6 26 20:52: 4.079709 240.00000000 1483.17364291 5395.21248786 4448.65907172 2.560540387 4.039025766 -5.736648561 7150.627872 0.001327 98.42718 247.86422 64.92748 76.08672 75.93917 2006 6 26 22:52: 4.079682 360.00000000 2801.25607157 5455.03931333 -3692.12865695 -0.595095864 -3.951923117 -6.298799125 7152.853077 0.000920 98.42585 247.93548 70.60413 140.82449 140.75784 2006 6 27 0:52: 4.079695 480.00000000 411.09332812 -1728.99769152 -6935.45548810 -2.935970964 -6.684085058 1.492800886 7140.462189 0.002672 98.43323 248.02387 100.30011 181.38082 181.38821 2006 6 27 2:52: 4.079709 600.00000000 -2506.52558454 -6628.98655094 -988.07784497 -1.390577189 -0.556164143 7.312736468 7157.425461 0.001029 98.42314 248.10462 67.58314 284.39271 284.50692 2006 6 27 4:52: 4.079682 720.00000000 -2090.79884266 -2723.22832193 6266.13356576 1.992640665 6.337529519 3.411803080 7143.567719 0.000886 98.43137 248.18007 166.10977 256.33563 256.43428 2006 6 27 6:52: 4.079695 840.00000000 1091.80560222 4809.88229503 5172.42897894 2.717483546 4.805518977 -5.030019896 7148.104201 0.001198 98.42868 248.27134 49.64708 83.33119 83.19482 2006 6 27 8:52: 4.079709 960.00000000 2811.14062300 5950.65707171 -2813.23705389 -0.159662742 -3.121215491 -6.775341949 7154.915561 0.000795 98.42463 248.34337 88.45427 114.95805 114.87539 2006 6 27 10:52: 4.079682 1080.00000000 805.72698304 -812.16627907 -7067.58483968 -2.798936020 -6.889265977 0.472770873 7139.798473 0.002771 98.43363 248.42943 93.17484 180.50142 180.50420 2006 6 27 12:52: 4.079695 1200.00000000 -2249.59837532 -6505.84890714 -1956.72365062 -1.731234729 -1.528750230 7.096660885 7156.391905 0.000858 98.42375 248.51302 75.03747 268.91702 269.01529 2006 6 27 14:52: 4.079709 1320.00000000 -2311.57375797 -3560.99112891 5748.16749600 1.626569751 5.890482233 4.293545048 7145.824255 0.001047 98.43003 248.58640 145.89038 268.51685 268.63682 2006 6 27 16:52: 4.079682 1440.00000000 688.16056594 4124.87618964 5794.55994449 2.810973665 5.479585563 -4.224866316 7145.630320 0.001046 98.43015 248.67804 32.16631 92.77487 92.65512 2006 6 27 18:52: 4.079695 1560.00000000 2759.94088230 6329.87271798 -1879.19518331 0.266930672 -2.222670878 -7.119390567 7156.499231 0.000865 98.42369 248.75157 105.04950 90.34410 90.24494 2006 6 27 20:52: 4.079709 1680.00000000 1171.50677137 125.82053748 -7061.96626202 -2.605687852 -6.958489749 -0.556333225 7139.826703 0.002767 98.43361 248.83494 85.94466 179.72728 179.72577 2006 6 27 22:52: 4.079682 1800.00000000 -1951.43708472 -6251.71945820 -2886.95472355 -2.024131483 -2.475214272 6.741537478 7154.763448 0.000797 98.42472 248.92120 92.12978 243.80606 243.88802 2006 6 28 0:52: 4.079695 1920.00000000 -2475.70722288 -4331.90569958 5117.31234924 1.235823539 5.322743371 5.091281211 7148.309000 0.001201 98.42856 248.99314 128.52047 277.84975 277.98604 2006 6 28 2:52: 4.079709 2040.00000000 281.46097847 3353.51057102 6302.87900650 2.840647273 6.047222485 -3.337085992 7143.399871 0.000887 98.43147 249.08435 11.88507 105.01812 104.91998 2006 6 28 4:52: 4.079682 2160.00000000 2650.33118860 6584.33434851 -908.29027134 0.675457235 -1.274044972 -7.323921567 7157.479518 0.001039 98.42311 249.15999 111.90557 75.46685 75.35165 2006 6 28 6:52: 4.079695 2280.00000000 1501.17226597 1066.31132756 -6918.71472952 -2.361891904 -6.889669974 -1.574718619 7140.544654 0.002662 98.43318 249.24051 78.83005 178.83747 178.83127 2006 6 28 8:52: 4.079709 2400.00000000 -1619.73468334 -5871.14051991 -3760.56587071 -2.264093975 -3.376316601 6.254622256 7152.668135 0.000933 98.42596 249.32906 109.69836 218.22152 218.28773 2006 6 28 10:52: 4.079682 2520.00000000 -2581.04202505 -5020.05572531 4385.92329047 0.829668458 4.645048038 5.789262667 7150.827394 0.001329 98.42706 249.40030 113.36970 284.96493 285.11207 2006 6 28 12:52: 4.079695 2640.00000000 -119.22080628 2510.90620488 6687.45615459 2.807575712 6.496549689 -2.384136661 7141.587336 0.000737 98.43255 249.49031 347.86242 121.00211 120.92975 2006 6 28 14:52: 4.079709 2760.00000000 2486.23806726 6708.18210028 80.43349581 1.057274905 -0.294294027 -7.384689123 7157.778701 0.001219 98.42293 249.56851 111.01680 68.33203 68.20226 2006 6 28 16:52: 4.079682 2880.00000000 1788.42334580 1990.50530957 -6640.59337725 -2.074169091 -6.683381288 -2.562777776 7141.897206 0.002463 98.43237 249.64625 72.08427 177.57827 177.56633 2006 6 28 18:52: 4.079695 28129 xx 0.00000000 21707.46412351 -15318.61752390 0.13551152 1.304029214 1.816904974 3.161919976 120.00000000 18616.75971861 3166.15177043 18833.41523210 -2.076122016 2.838457575 1.586210535 26559.609612 0.004641 54.72719 324.78767 265.85819 154.01896 153.78523 2006 6 24 15:41:49.461504 240.00000000 -3006.50596328 18522.20742011 18941.84078154 -3.375452789 1.032680773 -1.559324534 26559.578962 0.004639 54.72725 324.78155 266.56887 212.95207 213.24205 2006 6 24 17:41:49.461477 360.00000000 -21607.02086957 15432.59962630 206.62470309 -1.306049851 -1.817011568 -3.163725018 26562.088029 0.004629 54.72925 324.77940 265.56225 273.89165 274.42076 2006 6 24 19:41:49.461491 480.00000000 -18453.06134549 -3150.83256134 -18685.83030936 2.106017925 -2.860236337 -1.586151870 26559.602324 0.004611 54.72744 324.77734 266.55088 333.36818 333.60429 2006 6 24 21:41:49.461504 600.00000000 3425.11742384 -18514.73232706 -18588.67200557 3.394666340 -1.003072030 1.610061295 26559.630774 0.004616 54.72755 324.77120 265.84923 34.77421 34.47340 2006 6 24 23:41:49.461477 720.00000000 21858.23838148 -15101.51661554 387.34517048 1.247973967 1.856017403 3.161439948 26562.085763 0.004621 54.72951 324.76918 266.85519 94.16792 93.63964 2006 6 25 1:41:49.461491 840.00000000 18360.69935796 3506.55256762 19024.81678979 -2.122684184 2.830618605 1.537510677 26559.559560 0.004643 54.72767 324.76702 265.87367 155.01858 154.79317 2006 6 25 3:41:49.461504 960.00000000 -3412.84765409 18646.85269710 18748.00359987 -3.366815728 0.986039922 -1.607874972 26559.629458 0.004636 54.72781 324.76092 266.58044 213.95625 214.25386 2006 6 25 5:41:49.461477 1080.00000000 -21758.08331586 15215.44829478 -180.82181406 -1.250144680 -1.856490448 -3.163774870 26562.088483 0.004630 54.72977 324.75889 265.57964 274.89830 275.42679 2006 6 25 7:41:49.461491 1200.00000000 -18193.41290284 -3493.85876912 -18877.14757717 2.153326942 -2.852221264 -1.536617760 26559.550630 0.004608 54.72793 324.75676 266.56769 334.38316 334.61076 2006 6 25 9:41:49.461504 1320.00000000 3833.57386848 -18635.77026711 -18388.68722885 3.384748179 -0.955363841 1.658785020 26559.684002 0.004617 54.72812 324.75065 265.87116 35.78322 35.47471 2006 6 25 11:41:49.461477 1440.00000000 22002.20074562 -14879.72595593 774.32827099 1.191573619 1.894561165 3.159953047 26562.082259 0.004619 54.73003 324.74874 266.86759 95.17782 94.65052 2006 6 25 13:41:49.461491 28350 xx 0.00000000 6333.08123128 -1580.82852326 90.69355720 0.714634423 3.224246550 7.083128132 120.00000000 -3990.93845855 3052.98341907 4155.32700629 -5.909006188 -0.876307966 -5.039131404 6514.533010 0.001094 64.99789 345.26944 280.16817 215.14924 215.22144 2006 6 16 7:13:45.407419 240.00000000 -603.55232010 -2685.13474569 -5891.70274282 7.572519907 -1.975656726 0.121722605 6499.011250 0.000675 64.98059 344.96167 121.29549 149.70739 149.66836 2006 6 16 9:13:45.407392 360.00000000 4788.22345627 782.56169214 4335.14284621 -4.954509026 3.683346464 4.804645839 6499.559344 0.001075 64.99631 344.65400 214.64598 192.67757 192.70463 2006 6 16 11:13:45.407405 480.00000000 -6291.84601644 1547.82790772 -453.67116498 -0.308625588 -3.341538574 -7.082659115 6501.402918 0.000997 65.01469 344.30961 204.13051 340.28893 340.32744 2006 6 16 13:13:45.407419 600.00000000 4480.74573428 -3028.55200374 -3586.94343641 5.320920857 1.199736275 5.626350481 6488.183334 0.000573 65.00211 343.95864 209.39798 113.02357 112.96312 2006 6 16 15:13:45.407392 720.00000000 -446.42460916 2932.28872588 5759.19389757 -7.561000245 1.550975493 -1.374970885 6471.211254 0.001070 64.98172 343.63887 286.01526 175.14933 175.13896 2006 6 16 17:13:45.407405 840.00000000 -3713.79581831 -1382.66125130 -5122.45131136 6.090931626 -3.512629733 -3.467571746 6467.477224 0.001377 64.98864 343.33023 59.77643 181.00806 181.01084 2006 6 16 19:13:45.407419 960.00000000 6058.32017522 -827.47406722 2104.04678651 -1.798403024 3.787067272 6.641439744 6471.014530 0.001294 65.01057 342.99339 78.06727 302.97061 303.09495 2006 6 16 21:13:45.407392 1080.00000000 -5631.73659006 2623.70953644 1766.49125084 -3.216401578 -2.309140959 -6.788609120 6464.578757 0.001504 65.01192 342.63489 106.21713 56.22138 56.07825 2006 6 16 23:13:45.407405 1200.00000000 2776.84991560 -3255.36941953 -4837.19667790 6.748135564 -0.193044825 4.005718698 6447.542625 0.001645 64.99132 342.29217 117.75742 186.50124 186.52261 2006 6 17 1:13:45.407419 1320.00000000 1148.04430837 2486.07343386 5826.34075913 -7.420162295 2.589456382 0.356350006 6435.171751 0.000414 64.98033 341.97488 253.68628 193.44297 193.45401 2006 6 17 3:13:45.407392 1440.00000000 -4527.90871828 -723.29199041 -4527.44608319 5.121674217 -3.909895427 -4.500218556 6434.774399 0.001426 64.99416 341.65351 60.39417 170.43559 170.40841 2006 6 17 5:13:45.407405 28623 xx 0.00000000 -11665.70902324 24943.61433357 25.80543633 -1.596228621 -1.476127961 1.126059754 120.00000000 -11645.35454950 979.37668356 5517.89500058 3.407743502 -5.183094988 -0.492983277 17356.670112 0.625375 28.53335 114.91869 170.30118 253.05875 326.81165 2006 6 26 21:27:32.414976 240.00000000 5619.19252274 19651.44862280 -7261.38496765 -2.013634213 3.106842861 0.284235517 17356.637891 0.625206 28.53806 114.83270 170.44189 145.07208 80.69940 2006 6 26 23:27:32.414949 360.00000000 -9708.68629714 26306.14553149 -1204.29478856 -1.824164290 -0.931909596 1.113419052 17354.308840 0.624979 28.54525 114.78570 170.51013 184.33805 194.62715 2006 6 27 1:27:32.414963 480.00000000 -14394.03162892 6659.30765074 5593.38345858 1.556522911 -4.681657614 0.296912248 17349.390394 0.625102 28.53879 114.74400 170.58065 233.53987 308.58496 2006 6 27 3:27:32.414976 600.00000000 7712.09476270 15565.72627434 -7342.40465571 -1.646800364 4.070313571 -0.109483081 17346.109139 0.625001 28.53654 114.65582 170.72917 134.68739 62.56482 2006 6 27 5:27:32.414949 720.00000000 -7558.36739603 27035.11367962 -2385.12054184 -1.999583791 -0.393409283 1.078093515 17344.562691 0.624731 28.54585 114.60541 170.80625 178.98913 176.58319 2006 6 27 7:27:32.414963 840.00000000 -15495.61862220 11550.15897828 5053.83178121 0.469277336 -4.029761073 0.679054742 17340.566145 0.624804 28.54261 114.56467 170.86870 221.10114 290.64195 2006 6 27 9:27:32.414976 960.00000000 9167.02568222 10363.65204210 -6871.52576042 -0.881621027 5.223361510 -0.740696297 17334.780449 0.624783 28.53456 114.48188 171.01082 120.37404 44.71987 2006 6 27 11:27:32.414949 1080.00000000 -5275.80272094 27151.78486008 -3494.50687216 -2.129609388 0.150196480 1.021038089 17334.798205 0.624491 28.54619 114.42511 171.10197 173.69159 158.82687 2006 6 27 13:27:32.414963 1200.00000000 -15601.37656145 15641.29379850 4217.03266850 -0.249183123 -3.405238557 0.888214503 17331.224518 0.624507 28.54526 114.38403 171.16062 211.94210 272.98408 2006 6 27 15:27:32.414976 1320.00000000 9301.05872300 3883.15265574 -5477.86477017 0.871447821 6.493677331 -1.885545282 17321.818421 0.624520 28.53351 114.31465 171.28426 97.26227 27.16339 2006 6 27 17:27:32.414949 1440.00000000 -2914.31065828 26665.20392758 -4511.09814335 -2.216261909 0.710067769 0.940691824 17325.009247 0.624258 28.54628 114.24480 171.39711 168.29579 141.35834 2006 6 27 19:27:32.414963 28626 xx 0.00000000 42080.71852213 -2646.86387436 0.81851294 0.193105177 3.068688251 0.000438449 120.00000000 37740.00085593 18802.76872802 3.45512584 -1.371035206 2.752105932 0.000336883 42166.245516 0.000052 0.00784 349.69000 356.49546 40.29789 40.29405 2006 6 25 13:12:14.455025 240.00000000 23232.82515008 35187.33981802 4.98927428 -2.565776620 1.694193132 0.000163365 42166.250914 0.000038 0.00743 350.74515 12.41165 53.40798 53.40452 2006 6 25 15:12:14.454998 360.00000000 2467.44290178 42093.60909959 5.15062987 -3.069341800 0.179976276 -0.000031739 42166.256312 0.000021 0.00702 351.81369 31.17666 63.65492 63.65278 2006 6 25 17:12:14.455012 480.00000000 -18962.59052991 37661.66243819 4.04433258 -2.746151982 -1.382675777 -0.000197633 42166.261709 0.000004 0.00662 352.89609 92.59585 31.23325 31.23300 2006 6 25 19:12:14.455025 600.00000000 -35285.00095313 23085.44402778 2.08711880 -1.683277908 -2.572893625 -0.000296282 42166.267107 0.000016 0.00621 353.99260 217.47962 295.33279 295.33450 2006 6 25 21:12:14.454998 720.00000000 -42103.20138132 2291.06228893 -0.13274964 -0.166974816 -3.070104560 -0.000311007 42166.272504 0.000034 0.00580 355.10258 238.21722 303.56550 303.56870 2006 6 25 23:12:14.455012 840.00000000 -37580.31858370 -19120.40485693 -2.02755702 1.394367848 -2.740341612 -0.000248591 42166.277902 0.000049 0.00539 356.22456 254.44135 316.30053 316.30437 2006 6 26 1:12:14.455025 960.00000000 -22934.20761876 -35381.23870806 -3.16495932 2.580167539 -1.672360951 -0.000134907 42166.283299 0.000060 0.00498 357.35709 269.63485 330.05665 330.06010 2006 6 26 3:12:14.454998 1080.00000000 -2109.90332389 -42110.71508198 -3.36507889 3.070935369 -0.153808390 -0.000005855 42166.288696 0.000068 0.00457 358.49948 284.45334 344.17885 344.18097 2006 6 26 5:12:14.455012 1200.00000000 19282.77774728 -37495.59250598 -2.71861462 2.734400524 1.406220933 0.000103486 42166.294093 0.000071 0.00417 359.65183 299.12472 358.43875 358.43898 2006 6 26 7:12:14.455025 1320.00000000 35480.60990600 -22779.03375285 -1.52841859 1.661210676 2.587414593 0.000168300 42166.299490 0.000069 0.00376 0.81421 313.77342 12.71135 12.70961 2006 6 26 9:12:14.454998 1440.00000000 42119.96263499 -1925.77567263 -0.19827433 0.140521206 3.071541613 0.000179561 42166.304886 0.000062 0.00336 1.98591 328.51675 26.87953 26.87630 2006 6 26 11:12:14.455012 28872 xx 0.00000000 -6131.82730456 2446.52815528 -253.64211033 -0.144920228 0.995100963 7.658645067 5.00000000 -5799.24256134 2589.14811119 2011.54515100 2.325207364 -0.047125672 7.296234071 6532.131812 0.028892 96.46953 157.99929 243.05004 134.64086 132.24900 2005 11 29 0:33:58.939092 10.00000000 -4769.05061967 2420.46580562 4035.30855837 4.464585796 -1.060923209 6.070907874 6526.273486 0.029375 96.47228 158.00095 241.81874 155.49460 154.06995 2005 11 29 0:38:58.939114 15.00000000 -3175.45157340 1965.98738086 5582.12569607 6.049639376 -1.935777558 4.148607019 6519.457505 0.030322 96.47559 158.00479 241.88251 174.88643 174.56958 2005 11 29 0:43:58.939096 20.00000000 -1210.19024802 1281.54541294 6474.68172772 6.920746273 -2.580517337 1.748783868 6514.336564 0.030902 96.47802 158.01066 243.38375 192.80420 193.60708 2005 11 29 0:48:58.939118 25.00000000 896.73799533 447.12357305 6607.22400507 6.983396282 -2.925846168 -0.872655207 6512.862228 0.030569 96.47849 158.01759 245.19289 210.51094 212.32507 2005 11 29 0:53:58.939101 30.00000000 2896.99663534 -440.04738594 5954.92675486 6.211488246 -2.926949815 -3.433959806 6515.608034 0.029493 96.47675 158.02409 245.84813 229.59404 232.20474 2005 11 29 0:58:58.939123 35.00000000 4545.78970167 -1273.55952872 4580.16512984 4.656984233 -2.568711513 -5.638510954 6521.403980 0.028482 96.47351 158.02882 244.64993 250.85868 253.96339 2005 11 29 1: 3:58.939105 40.00000000 5627.43299371 -1947.94282469 2634.16714930 2.464141047 -1.873985161 -7.195743032 6527.502251 0.028288 96.47026 158.03113 242.66126 273.31432 276.54607 2005 11 29 1: 8:58.939127 45.00000000 5984.72318534 -2371.37691609 349.87996209 -0.121276950 -0.911981546 -7.859613894 6530.555444 0.028747 96.46863 158.03155 241.89724 294.97178 297.93068 2005 11 29 1:13:58.939109 50.00000000 5548.43325922 -2480.16469245 -1979.24314527 -2.763269534 0.199691915 -7.482796996 6528.353658 0.028906 96.46957 158.03163 242.90998 315.24831 317.54473 2005 11 29 1:18:58.939092 29141 xx 0.00000000 423.99295524 -6658.12256149 136.13040356 1.006373613 0.217309983 7.662587892 20.00000000 931.80883587 -1017.17852239 6529.19244527 -0.298847918 7.613891977 1.226399480 6654.859371 0.002792 82.42352 273.47441 254.48318 186.27472 186.30976 2006 6 19 6:45:41.242102 40.00000000 -83.44906141 6286.20208453 2223.49837161 -1.113515974 2.530970283 -7.219445568 6667.409852 0.000967 82.43311 273.45347 259.01762 261.32660 261.43621 2006 6 19 7: 5:41.242111 60.00000000 -958.57681221 3259.26005348 -5722.63732467 -0.101225813 -6.735338321 -3.804851872 6650.404442 0.001731 82.42598 273.44626 354.27502 245.88943 246.07057 2006 6 19 7:25:41.242079 80.00000000 -255.25619985 -5132.59762974 -4221.27233118 1.077709303 -4.905938824 5.892521264 6652.084920 0.000656 82.42981 273.42019 252.81771 67.36659 67.29720 2006 6 19 7:45:41.242088 100.00000000 867.44295097 -5038.40402933 4256.73810533 0.479447535 5.032326446 5.857126248 6646.445447 0.000943 82.42973 273.41562 212.21882 187.98298 187.99800 2006 6 19 8: 5:41.242097 120.00000000 559.16882013 3376.30587937 5699.22017391 -0.906749328 6.646149867 -3.852331832 6633.873397 0.002146 82.42602 273.38941 288.19218 191.94169 191.99264 2006 6 19 8:25:41.242106 140.00000000 -669.85184205 6196.00229484 -2281.95741770 -0.795804092 -2.752114827 -7.202478520 6639.351533 0.001666 82.43307 273.38226 276.79256 283.50264 283.68819 2006 6 19 8:45:41.242075 160.00000000 -784.20708019 -1278.53125553 -6449.19892596 0.636702380 -7.595425203 1.431090802 6615.185547 0.000988 82.42356 273.36071 80.31004 200.39880 200.43831 2006 6 19 9: 5:41.242084 180.00000000 406.15811659 -6607.03115799 148.33021477 1.009818575 0.231843765 7.692047844 6625.576066 0.000764 82.43444 273.34723 331.83273 29.46222 29.41915 2006 6 19 9:25:41.242093 200.00000000 916.34911813 -884.08649248 6491.09810362 -0.302163049 7.669887109 1.084336909 6596.784223 0.002757 82.42336 273.33273 254.08653 187.77997 187.82284 2006 6 19 9:45:41.242102 220.00000000 -104.02490970 6304.31821405 1960.08739882 -1.108873823 2.259522809 -7.351147710 6603.486694 0.000956 82.43346 273.31198 246.54178 276.03282 276.14180 2006 6 19 10: 5:41.242111 240.00000000 -944.61642849 2872.17248379 -5846.94103362 -0.051117686 -6.989747076 -3.413102600 6577.346070 0.001592 82.42534 273.30392 2.77756 240.87045 241.02990 2006 6 19 10:25:41.242079 260.00000000 -187.16569888 -5404.86163467 -3731.97057618 1.094696706 -4.412110995 6.326060952 6573.111994 0.000741 82.43077 273.27798 263.60955 61.43377 61.35924 2006 6 19 10:45:41.242088 280.00000000 884.59720467 -4465.74516163 4725.83632696 0.380656028 5.691554046 5.303910983 6553.914239 0.001257 82.42848 273.27324 213.21629 193.37953 193.41290 2006 6 19 11: 5:41.242097 300.00000000 446.40767236 4086.66839620 5093.05596650 -0.982424447 6.072965199 -4.791630682 6535.077554 0.001618 82.42746 273.24577 291.11394 197.16680 197.22159 2006 6 19 11:25:41.242106 320.00000000 -752.24467495 5588.35473301 -3275.04092573 -0.661161370 -4.016290740 -6.676898026 6523.150138 0.001608 82.43163 273.24054 287.85797 282.58332 282.76309 2006 6 19 11:45:41.242075 340.00000000 -643.72872525 -2585.02528560 -5923.01306608 0.807922142 -7.171597814 3.041115058 6490.083264 0.000695 82.42474 273.21509 123.03058 170.03884 170.02506 2006 6 19 12: 5:41.242084 360.00000000 584.40295819 -6202.35605817 1781.00536019 0.869250450 2.226927514 7.471676765 6481.796204 0.000373 82.43379 273.20643 7.31819 8.78009 8.77357 2006 6 19 12:25:41.242093 380.00000000 779.59211765 1100.73728301 6311.59529480 -0.599552305 7.721032522 -1.275153027 6437.508232 0.002601 82.42317 273.18521 272.09622 187.31813 187.35618 2006 6 19 12:45:41.242102 400.00000000 -403.03155588 6399.18000837 -364.12735875 -1.008861924 -0.516636615 -7.799812287 6427.949611 0.001475 82.43476 273.17168 235.94761 307.33127 307.46560 2006 6 19 13: 5:41.242111 420.00000000 -852.93910071 192.65232023 -6322.47054784 0.396006194 -7.882964919 -0.289331517 6375.610362 0.001229 82.42276 273.15527 61.88829 205.96299 206.02469 2006 6 19 13:25:41.242079 29238 xx 0.00000000 -5566.59512819 -3789.75991159 67.60382245 2.873759367 -3.825340523 6.023253926 120.00000000 4474.27915495 -1447.72286142 4619.83927235 4.712595822 5.668306153 -2.701606741 6722.575685 0.020855 51.54723 213.34037 94.40931 22.09810 21.21193 2006 6 26 8:53:44.456634 240.00000000 1922.17712474 5113.01138342 -4087.08470203 -6.490769651 -0.522350158 -3.896001154 6724.840619 0.020836 51.55602 212.95757 95.05339 134.84550 133.13386 2006 6 26 10:53:44.456607 360.00000000 -6157.93546882 -2094.70798790 -1941.63730960 0.149900661 -5.175192523 5.604262034 6729.860276 0.020524 51.57445 212.48491 94.57294 244.01244 246.14078 2006 6 26 12:53:44.456620 480.00000000 2482.64052411 -3268.45944555 5146.38006190 6.501814698 4.402848754 -0.350943511 6719.018114 0.020320 51.53923 212.07031 96.26478 356.94314 357.06545 2006 6 26 14:53:44.456634 600.00000000 4036.26455287 4827.43347201 -2507.99063955 -5.184409515 1.772280695 -5.331390168 6728.048056 0.020495 51.57078 211.66544 97.68432 110.52055 108.30924 2006 6 26 16:53:44.456607 720.00000000 -5776.81371622 -118.64155319 -3641.22052418 -2.539917207 -5.622701582 4.403125405 6724.820558 0.020547 51.56099 211.18821 97.21262 219.89135 221.41939 2006 6 26 18:53:44.456620 840.00000000 67.98699487 -4456.49213473 4863.71794283 7.183809420 2.418917791 2.015642495 6719.324890 0.020499 51.54373 210.80108 98.23244 332.06973 333.15521 2006 6 26 20:53:44.456634 960.00000000 5520.62207038 3782.38203554 -596.73193161 -3.027966069 3.754152525 -6.013506363 6729.578486 0.020759 51.57938 210.36070 99.82418 86.68512 84.31260 2006 6 26 22:53:44.456607 1080.00000000 -4528.05104455 1808.46273329 -4816.99727762 -4.808419763 -5.185789345 2.642104494 6719.734999 0.020988 51.54703 209.90441 98.71342 197.46314 198.19584 2006 6 27 0:53:44.456620 1200.00000000 -2356.61468078 -4852.51202272 3856.53816184 6.688446735 0.118520958 4.021854210 6722.408929 0.020953 51.55740 209.52106 98.53493 309.41224 311.24882 2006 6 27 2:53:44.456634 1320.00000000 6149.65800134 2173.59423261 1369.29488732 -0.345832777 5.109857861 -5.842951828 6727.916386 0.021118 51.57710 209.05199 100.14201 64.65457 62.48241 2006 6 27 4:53:44.456607 1440.00000000 -2629.55011449 3400.98040158 -5344.38217129 -6.368548448 -3.998963509 0.577253064 6716.496128 0.021225 51.53949 208.63001 98.79198 176.88483 176.75052 2006 6 27 6:53:44.456620 88888 xx 0.00000000 2328.96975262 -5995.22051338 1719.97297192 2.912073281 -0.983417956 -7.090816210 120.00000000 1020.69234558 2286.56260634 -6191.55565927 -3.746543902 6.467532721 1.827985678 6626.008292 0.010522 72.83280 115.75005 63.53918 220.46377 221.25094 1980 10 2 1:41:24.113771 240.00000000 -3226.54349155 3503.70977525 4532.80979343 1.000992116 -5.788042888 5.162585826 6633.568600 0.009051 72.84300 115.55580 59.76008 346.41743 346.65942 1980 10 2 3:41:24.113744 360.00000000 2456.10706533 -6071.93855503 1222.89768554 2.679390040 -0.448290811 -7.228792155 6642.303503 0.009521 72.85473 115.32544 59.25198 109.67444 108.64459 1980 10 2 5:41:24.113757 480.00000000 787.16457349 2719.91800946 -6043.86662024 -3.759883839 6.277439314 2.397897864 6626.659125 0.010283 72.83384 115.10965 63.34327 225.25694 226.09847 1980 10 2 7:41:24.113771 600.00000000 -3110.97648029 3121.73026235 4878.15217035 1.244916056 -6.124880425 4.700576353 6631.933076 0.008795 72.84100 114.91683 59.02796 351.92087 352.06159 1980 10 2 9:41:24.113744 720.00000000 2567.56229695 -6112.50383922 713.96374435 2.440245751 0.098109002 -7.319959258 6642.615358 0.009371 72.85532 114.68868 58.81484 114.75171 113.77366 1980 10 2 11:41:24.113757 840.00000000 556.05661780 3144.52288201 -5855.34636178 -3.754660143 6.044752775 2.957941672 6627.505506 0.010032 72.83515 114.46939 62.86103 230.37982 231.26958 1980 10 2 13:41:24.113771 960.00000000 -2982.47940539 2712.61663711 5192.32330472 1.475566773 -6.427737014 4.202420227 6630.339520 0.008547 72.83905 114.27748 57.92953 357.82813 357.86501 1980 10 2 15:41:24.113744 1080.00000000 2663.08964352 -6115.48290885 196.40072866 2.196121564 0.652415093 -7.362824152 6642.696880 0.009229 72.85560 114.05197 58.08826 120.14672 119.22898 1980 10 2 17:41:24.113757 1200.00000000 328.54999674 3557.09490552 -5626.21427211 -3.731193288 5.769341172 3.504058731 6628.528407 0.009780 72.83669 113.82932 62.06118 235.86432 236.79576 1980 10 2 19:41:24.113771 1320.00000000 -2842.06876757 2278.42343492 5472.33437150 1.691852635 -6.693216335 3.671022712 6628.832330 0.008322 72.83722 113.63775 56.45020 4.15293 4.08430 1980 10 2 21:41:24.113744 1440.00000000 2742.55398832 -6079.67009123 -326.39012649 1.948497651 1.211072678 -7.356193131 6642.539418 0.009109 72.85556 113.41525 57.08019 125.85183 125.00240 1980 10 2 23:41:24.113757 33333 xx 0.00000000 -12908.67135870 8084.56464378 22887.74960008 -0.076981979 0.252652062 1.837356358 5.00000000 836.36198558 3131.21861830 27739.12500595 0.806969092 -0.303613357 1.495581060 15591.703950 0.948291 96.38049 148.19713 273.67820 174.39430 116.59606 2005 11 29 0:33:58.939092 10.00000000 12529.16240012 -7305.76672566 24606.25882463 1.077046921 -0.832176467 0.734844393 15620.294215 0.956163 96.35544 138.86115 304.49417 175.41552 122.71671 2005 11 29 0:38:58.939114 15.00000000 17680.27781737 -19040.50274272 13889.53302171 0.838850492 -1.010897050 0.019845764 15735.072365 0.974320 96.11899 129.59336 334.76647 176.93090 128.70759 2005 11 29 0:43:58.939096 20.00000000 23876.96955477 -37275.65263893 -8113.95104473 0.589108130 -0.767768418 -0.260379679 23854.828071 0.998563 46.03989 112.46059 15.25388 179.25121 126.28606 2005 11 29 0:48:58.939118 33334 xx 0.00000000 23876.96955477 -37275.65263893 -8113.95104473 0.589108130 -0.767768418 -0.260379679 33335 xx 0.00000000 42081.34386081 -2649.18487875 0.81820315 0.193184518 3.068627007 0.000438443 20.00000000 42151.86113568 1038.56497521 1.31183638 -0.075730915 3.073768897 0.000428300 42166.241018 0.000038 0.00818 348.82102 11.29619 1.29419 1.29409 2006 6 25 11:32:14.455021 40.00000000 41899.82539501 4718.36752490 1.78786028 -0.344066764 3.055389800 0.000415234 42166.241918 0.000038 0.00811 348.99404 16.07338 1.35763 1.35753 2006 6 25 11:52:14.455030 60.00000000 41327.16536793 8362.06432379 2.24306194 -0.609769675 3.013630372 0.000399389 42166.242817 0.000038 0.00804 349.16745 20.86023 1.41100 1.41090 2006 6 25 12:12:14.454998 80.00000000 40438.26325401 11941.77323201 2.67443598 -0.870806448 2.948810178 0.000380927 42166.243717 0.000037 0.00797 349.34125 25.65723 1.45385 1.45374 2006 6 25 12:32:14.455007 100.00000000 39239.92118669 15430.10177531 3.07920420 -1.125179589 2.861425248 0.000360030 42166.244617 0.000037 0.00791 349.51544 30.46476 1.48578 1.48567 2006 6 25 12:52:14.455016 120.00000000 37741.30917901 18800.35675644 3.45483317 -1.370942600 2.752144282 0.000336890 42166.245516 0.000037 0.00784 349.69000 35.28315 1.50647 1.50636 2006 6 25 13:12:14.455025 140.00000000 35953.89494997 22026.74851504 3.79904972 -1.606214870 2.621803528 0.000311718 42166.246416 0.000037 0.00777 349.86493 40.11263 1.51569 1.51558 2006 6 25 13:32:14.454994 160.00000000 33891.35616861 25084.58827300 4.10985412 -1.829196068 2.471400388 0.000284732 42166.247316 0.000037 0.00770 350.04024 44.95337 1.51328 1.51317 2006 6 25 13:52:14.455003 180.00000000 31569.47578743 27950.47705519 4.38553102 -2.038179917 2.302085784 0.000256165 42166.248215 0.000037 0.00764 350.21591 49.80543 1.49918 1.49907 2006 6 25 14:12:14.455012 200.00000000 29006.02126614 30602.48473998 4.62465800 -2.231567255 2.115155347 0.000226253 42166.249115 0.000037 0.00757 350.39196 54.66878 1.47342 1.47331 2006 6 25 14:32:14.455021 220.00000000 26220.60860999 33020.31786944 4.82611168 -2.407878265 1.912039506 0.000195241 42166.250014 0.000037 0.00750 350.56837 59.54331 1.43611 1.43600 2006 6 25 14:52:14.455030 240.00000000 23234.55226321 35185.47493519 4.98907152 -2.565763805 1.694292541 0.000163378 42166.250914 0.000037 0.00743 350.74515 64.42880 1.38747 1.38737 2006 6 25 15:12:14.454998 260.00000000 20070.70200615 37081.38795177 5.11302111 -2.704015726 1.463580689 0.000130915 42166.251814 0.000037 0.00736 350.92231 69.32494 1.32781 1.32771 2006 6 25 15:32:14.455007 280.00000000 16753.26810433 38693.54923410 5.19774715 -2.821576121 1.221669394 0.000098102 42166.252713 0.000037 0.00730 351.09983 74.23133 1.25753 1.25743 2006 6 25 15:52:14.455016 300.00000000 13307.63604740 40009.62240917 5.24333607 -2.917545416 0.970409795 0.000065188 42166.253613 0.000037 0.00723 351.27773 79.14746 1.17712 1.17704 2006 6 25 16:12:14.455025 320.00000000 9760.17229554 41019.53681249 5.25016837 -2.991189257 0.711724566 0.000032419 42166.254513 0.000036 0.00716 351.45600 84.07275 1.08719 1.08711 2006 6 25 16:32:14.454994 340.00000000 6138.02252001 41715.56454704 5.21891075 -3.041944126 0.447593198 0.000000034 42166.255412 0.000036 0.00709 351.63466 89.00650 0.98841 0.98834 2006 6 25 16:52:14.455003 360.00000000 2468.90388143 42092.37961516 5.15050615 -3.069421652 0.180036856 -0.000031733 42166.256312 0.000036 0.00702 351.81369 93.94797 0.88153 0.88147 2006 6 25 17:12:14.455012 380.00000000 -1219.10706450 42147.09867100 5.04616179 -3.073411586 -0.088897090 -0.000062658 42166.257211 0.000036 0.00696 351.99312 98.89630 0.76740 0.76735 2006 6 25 17:32:14.455021 400.00000000 -4897.78921104 41879.30308168 4.90733536 -3.053883409 -0.357150730 -0.000092529 42166.258111 0.000036 0.00689 352.17293 103.85059 0.64693 0.64688 2006 6 25 17:52:14.455030 420.00000000 -8538.99285015 41291.04212849 4.73571938 -3.010986561 -0.622671362 -0.000121143 42166.259011 0.000036 0.00682 352.35313 108.80986 0.52108 0.52104 2006 6 25 18:12:14.454998 440.00000000 -12114.85507563 40386.81732367 4.53322412 -2.945049303 -0.883427197 -0.000148313 42166.259910 0.000036 0.00675 352.53372 113.77308 0.39089 0.39086 2006 6 25 18:32:14.455007 460.00000000 -15598.01299133 39173.54796277 4.30195895 -2.856576200 -1.137422908 -0.000173864 42166.260810 0.000036 0.00668 352.71471 118.73919 0.25742 0.25740 2006 6 25 18:52:14.455016 480.00000000 -18961.81309308 37660.51817630 4.04421255 -2.746244262 -1.382714901 -0.000197639 42166.261709 0.000036 0.00662 352.89609 123.70707 0.12178 0.12177 2006 6 25 19:12:14.455025 500.00000000 -22180.51522214 35859.30588575 3.76243190 -2.614897767 -1.617426179 -0.000219495 42166.262609 0.000036 0.00655 353.07787 128.67561 359.98509 359.98509 2006 6 25 19:32:14.454994 520.00000000 -25229.48952966 33783.69420777 3.45920052 -2.463541792 -1.839760715 -0.000239309 42166.263509 0.000036 0.00648 353.26004 133.64366 359.84849 359.84850 2006 6 25 19:52:14.455003 540.00000000 -28085.40494491 31449.56598423 3.13721591 -2.293334531 -2.048017187 -0.000256974 42166.264408 0.000036 0.00641 353.44260 138.61009 359.71312 359.71314 2006 6 25 20:12:14.455012 560.00000000 -30726.40770527 28874.78224541 2.79926643 -2.105578426 -2.240601999 -0.000272403 42166.265308 0.000036 0.00634 353.62555 143.57379 359.58009 359.58012 2006 6 25 20:32:14.455021 580.00000000 -33132.28858188 26079.04553622 2.44820796 -1.901710205 -2.416041476 -0.000285526 42166.266207 0.000036 0.00628 353.80889 148.53366 359.45051 359.45055 2006 6 25 20:52:14.455030 600.00000000 -35284.63752139 23083.74915120 2.08694032 -1.683289887 -2.572993142 -0.000296293 42166.267107 0.000036 0.00621 353.99260 153.48863 359.32545 359.32549 2006 6 25 21:12:14.454998 620.00000000 -37166.98452041 19911.81343196 1.71838379 -1.451988843 -2.710255987 -0.000304674 42166.268006 0.000036 0.00614 354.17670 158.43769 359.20591 359.20597 2006 6 25 21:32:14.455007 640.00000000 -38764.92565492 16587.51037972 1.34545586 -1.209577008 -2.826779663 -0.000310657 42166.268906 0.000036 0.00607 354.36116 163.37988 359.09288 359.09294 2006 6 25 21:52:14.455016 660.00000000 -40066.23330012 13136.27792487 0.97104837 -0.957909340 -2.921672518 -0.000314248 42166.269806 0.000036 0.00600 354.54599 168.31431 358.98724 358.98732 2006 6 25 22:12:14.455025 680.00000000 -41060.94969727 9584.52527475 0.59800531 -0.698911620 -2.994208421 -0.000315473 42166.270705 0.000036 0.00593 354.73117 173.24015 358.88984 358.88992 2006 6 25 22:32:14.454994 700.00000000 -41741.46315175 5959.43082914 0.22910131 -0.434565724 -3.043832317 -0.000314374 42166.271605 0.000037 0.00587 354.91671 178.15667 358.80141 358.80150 2006 6 25 22:52:14.455003 720.00000000 -42102.56627900 2288.73420969 -0.13297887 -0.166894449 -3.070164473 -0.000311012 42166.272504 0.000037 0.00580 355.10258 183.06320 358.72263 358.72273 2006 6 25 23:12:14.455012 740.00000000 -42141.49585277 -1399.47600560 -0.48565983 0.102053956 -3.073003389 -0.000305463 42166.273404 0.000037 0.00573 355.28879 187.95916 358.65408 358.65418 2006 6 25 23:32:14.455021 760.00000000 -41857.95395065 -5076.97721736 -0.82649380 0.370221472 -3.052327336 -0.000297818 42166.274303 0.000037 0.00566 355.47532 192.84409 358.59624 358.59635 2006 6 25 23:52:14.455030 780.00000000 -41254.11023517 -8715.62876702 -1.15317748 0.635556054 -3.008294522 -0.000288183 42166.275203 0.000037 0.00559 355.66217 197.71760 358.54951 358.54962 2006 6 26 0:12:14.454998 800.00000000 -40334.58535264 -12287.58727144 -1.46356754 0.896027331 -2.941241884 -0.000276676 42166.276102 0.000037 0.00553 355.84934 202.57939 358.51419 358.51430 2006 6 26 0:32:14.455007 820.00000000 -39106.41557705 -15765.51968317 -1.75569446 1.149642148 -2.851682510 -0.000263431 42166.277002 0.000037 0.00546 356.03680 207.42927 358.49047 358.49058 2006 6 26 0:52:14.455016 840.00000000 -37578.99896933 -19122.81244597 -2.02777480 1.394459813 -2.740301711 -0.000248586 42166.277902 0.000037 0.00539 356.22456 212.26714 358.47846 358.47857 2006 6 26 1:12:14.455025 860.00000000 -35764.02346385 -22333.77514503 -2.27822161 1.628606950 -2.607951779 -0.000232295 42166.278801 0.000037 0.00532 356.41261 217.09300 358.47818 358.47829 2006 6 26 1:32:14.454994 880.00000000 -33675.37743265 -25373.83709355 -2.50565327 1.850291834 -2.455645465 -0.000214716 42166.279701 0.000037 0.00525 356.60095 221.90692 358.48955 358.48966 2006 6 26 1:52:14.455003 900.00000000 -31329.04341132 -28219.73535130 -2.70890026 2.057818102 -2.284548228 -0.000196015 42166.280600 0.000037 0.00519 356.78957 226.70907 358.51241 358.51252 2006 6 26 2:12:14.455012 920.00000000 -28742.97580008 -30849.69273646 -2.88701028 2.249597731 -2.095969320 -0.000176361 42166.281500 0.000037 0.00512 356.97847 231.49970 358.54650 358.54661 2006 6 26 2:32:14.455021 940.00000000 -25936.96347556 -33243.58446856 -3.03925139 2.424163195 -1.891351766 -0.000155931 42166.282399 0.000038 0.00505 357.16764 236.27915 358.59151 358.59162 2006 6 26 2:52:14.455030 960.00000000 -22932.47836472 -35383.09216713 -3.16511333 2.580178691 -1.672261322 -0.000134899 42166.283299 0.000038 0.00498 357.35709 241.04782 358.64703 358.64713 2006 6 26 3:12:14.454998 980.00000000 -19752.51113952 -37251.84402776 -3.26430697 2.716450362 -1.440374493 -0.000113442 42166.284198 0.000038 0.00491 357.54680 245.80618 358.71258 358.71268 2006 6 26 3:32:14.455007 1000.00000000 -16421.39528965 -38835.54010283 -3.33676204 2.831935435 -1.197465704 -0.000091737 42166.285098 0.000038 0.00485 357.73679 250.55477 358.78763 358.78772 2006 6 26 3:52:14.455016 1020.00000000 -12964.62091949 -40122.06172807 -3.38262296 2.925750195 -0.945393726 -0.000069958 42166.285997 0.000038 0.00478 357.92706 255.29420 358.87157 358.87165 2006 6 26 4:12:14.455025 1040.00000000 -9408.63969423 -41101.56425770 -3.40224311 2.997176756 -0.686087446 -0.000048275 42166.286897 0.000038 0.00471 358.11759 260.02512 358.96375 358.96383 2006 6 26 4:32:14.454994 1060.00000000 -5780.66242756 -41766.55239827 -3.39617741 3.045668546 -0.421531112 -0.000026852 42166.287796 0.000038 0.00464 358.30840 264.74823 359.06347 359.06354 2006 6 26 4:52:14.455003 1080.00000000 -2108.45086007 -42111.93756495 -3.36517338 3.070854497 -0.153749147 -0.000005850 42166.288696 0.000038 0.00457 358.49948 269.46428 359.16996 359.17003 2006 6 26 5:12:14.455012 1100.00000000 1579.89477842 -42135.07682093 -3.31016077 3.072541880 0.115209344 0.000014580 42166.289595 0.000038 0.00451 358.69084 274.17406 359.28246 359.28251 2006 6 26 5:32:14.455021 1120.00000000 5256.15079690 -41835.79310235 -3.23223988 3.050717780 0.383286250 0.000034295 42166.290495 0.000038 0.00444 358.88248 278.87839 359.40012 359.40017 2006 6 26 5:52:14.455030 1140.00000000 8892.18601615 -41216.37657357 -3.13266867 3.005549198 0.648430207 0.000053160 42166.291394 0.000038 0.00437 359.07439 283.57812 359.52210 359.52214 2006 6 26 6:12:14.454998 1160.00000000 12460.17703381 -40281.56710259 -3.01284877 2.937381771 0.908612294 0.000071053 42166.292294 0.000038 0.00430 359.26659 288.27414 359.64752 359.64755 2006 6 26 6:32:14.455007 1180.00000000 15932.82113445 -39038.51799074 -2.87431064 2.846737129 1.161841559 0.000087861 42166.293193 0.000038 0.00424 359.45907 292.96734 359.77548 359.77550 2006 6 26 6:52:14.455016 1200.00000000 19283.54521514 -37496.74123395 -2.71869780 2.734308898 1.406180256 0.000103483 42166.294093 0.000038 0.00417 359.65183 297.65862 359.90507 359.90508 2006 6 26 7:12:14.455025 1220.00000000 22486.70912785 -35668.03473474 -2.54775052 2.600957401 1.639758669 0.000117831 42166.294992 0.000038 0.00410 359.84487 302.34890 0.03537 0.03537 2006 6 26 7:32:14.454994 1240.00000000 25517.80188259 -33566.39202175 -2.36328894 2.447703066 1.860789425 0.000130830 42166.295892 0.000038 0.00403 0.03819 307.03912 0.16547 0.16545 2006 6 26 7:52:14.455003 1260.00000000 28353.62920984 -31207.89516780 -2.16719590 2.275718622 2.067581166 0.000142418 42166.296791 0.000038 0.00396 0.23179 311.73020 0.29442 0.29440 2006 6 26 8:12:14.455012 1280.00000000 30972.49104691 -28610.59172582 -1.96139952 2.086320125 2.258551497 0.000152546 42166.297691 0.000038 0.00390 0.42566 316.42305 0.42133 0.42130 2006 6 26 8:32:14.455021 1300.00000000 33354.34759018 -25794.35662449 -1.74785572 1.880956885 2.432239090 0.000161178 42166.298590 0.000038 0.00383 0.61980 321.11859 0.54528 0.54524 2006 6 26 8:52:14.455030 1320.00000000 35480.97264231 -22780.74008043 -1.52853093 1.661200376 2.587314870 0.000168293 42166.299490 0.000038 0.00376 0.81421 325.81771 0.66538 0.66533 2006 6 26 9:12:14.454998 1340.00000000 37336.09308113 -19592.80269080 -1.30538495 1.428732211 2.722592184 0.000173883 42166.300389 0.000038 0.00369 1.00888 330.52129 0.78076 0.78070 2006 6 26 9:32:14.455007 1360.00000000 38905.51338297 -16254.93896825 -1.08035428 1.185331274 2.837035880 0.000177953 42166.301288 0.000038 0.00363 1.20381 335.23017 0.89058 0.89052 2006 6 26 9:52:14.455016 1380.00000000 40177.22424735 -12792.69066866 -0.85533591 0.932860106 2.929770230 0.000180519 42166.302188 0.000038 0.00356 1.39898 339.94517 0.99403 0.99396 2006 6 26 10:12:14.455025 1400.00000000 41141.49449212 -9232.55134025 -0.63217187 0.673250654 3.000085631 0.000181613 42166.303087 0.000038 0.00349 1.59440 344.66708 1.09033 1.09025 2006 6 26 10:32:14.454994 1420.00000000 41790.94551564 -5601.76358958 -0.41263443 0.408489486 3.047444033 0.000181274 42166.303987 0.000038 0.00342 1.79004 349.39665 1.17875 1.17866 2006 6 26 10:52:14.455003 1440.00000000 42120.60775638 -1928.11061608 -0.19841236 0.140602589 3.071483058 0.000179558 42166.304886 0.000038 0.00336 1.98591 354.13456 1.25859 1.25850 2006 6 26 11:12:14.455012 20413 xx 0.00000000 25123.29290741 -13225.49966286 3249.40351869 0.488683419 4.797897593 -0.961119693 1844000.00000000 -35697.35025451 -70749.92495964 14190.12461545 1.649636113 1.769993942 -0.576290053 107263.144179 0.962842 16.55445 100.26928 301.44758 200.33684 338.29866 2009 7 2 8:20: 0.000264 1844005.00000000 -35200.64824316 -70216.17362227 14016.77915662 1.657878275 1.786366861 -0.579577470 107262.539605 0.962840 16.55470 100.26926 301.44731 200.48680 338.60753 2009 7 2 8:25: 0.000286 1844010.00000000 -34701.45381520 -69677.45988703 13842.43709323 1.666228231 1.803062654 -0.582913655 107261.919737 0.962838 16.55494 100.26925 301.44705 200.63949 338.91639 2009 7 2 8:30: 0.000268 1844015.00000000 -34199.73419511 -69133.68506099 13667.08357914 1.674688808 1.820093010 -0.586300058 107261.283957 0.962837 16.55519 100.26923 301.44679 200.79501 339.22526 2009 7 2 8:35: 0.000250 1844020.00000000 -33695.45574304 -68584.74685089 13490.70332382 1.683262939 1.837470228 -0.589738194 107260.631614 0.962835 16.55544 100.26922 301.44653 200.95347 339.53413 2009 7 2 8:40: 0.000273 1844025.00000000 -33188.58392291 -68030.53917382 13313.28057302 1.691953664 1.855207259 -0.593229642 107259.962018 0.962833 16.55569 100.26921 301.44626 201.11497 339.84300 2009 7 2 8:45: 0.000255 1844030.00000000 -32679.08326923 -67470.95195529 13134.79908827 1.700764139 1.873317750 -0.596776055 107259.274441 0.962831 16.55594 100.26920 301.44600 201.27962 340.15187 2009 7 2 8:50: 0.000277 1844035.00000000 -32166.91735222 -66905.87091261 12955.24212519 1.709697636 1.891816094 -0.600379156 107258.568111 0.962829 16.55620 100.26920 301.44573 201.44754 340.46075 2009 7 2 8:55: 0.000259 1844040.00000000 -31652.04874147 -66335.17732309 12774.59241050 1.718757551 1.910717482 -0.604040751 107257.842211 0.962827 16.55645 100.26919 301.44547 201.61885 340.76962 2009 7 2 9: 0: 0.000282 1844045.00000000 -31134.43896798 -65758.74777552 12592.83211778 1.727947411 1.930037964 -0.607762726 107257.095873 0.962826 16.55670 100.26919 301.44520 201.79368 341.07850 2009 7 2 9: 5: 0.000264 1844050.00000000 -30614.04848454 -65176.45390327 12409.94284157 1.737270876 1.949794512 -0.611547059 107256.328175 0.962824 16.55695 100.26919 301.44494 201.97218 341.38737 2009 7 2 9:10: 0.000286 1844055.00000000 -30090.83662441 -64588.16209752 12225.90557016 1.746731748 1.970005085 -0.615395818 107255.538139 0.962822 16.55721 100.26919 301.44467 202.15449 341.69625 2009 7 2 9:15: 0.000268 1844060.00000000 -29564.76155793 -63993.73319837 12040.70065637 1.756333977 1.990688712 -0.619311176 107254.724723 0.962820 16.55746 100.26919 301.44441 202.34076 342.00513 2009 7 2 9:20: 0.000250 1844065.00000000 -29035.78024784 -63393.02216277 11854.30778690 1.766081663 2.011865571 -0.623295408 107253.886818 0.962818 16.55772 100.26920 301.44414 202.53115 342.31402 2009 7 2 9:25: 0.000273 1844070.00000000 -28503.84840188 -62785.87770518 11666.70594931 1.775979069 2.033557081 -0.627350903 107253.023241 0.962816 16.55797 100.26921 301.44387 202.72585 342.62290 2009 7 2 9:30: 0.000255 1844075.00000000 -27968.92042406 -62172.14191043 11477.87339723 1.786030623 2.055786004 -0.631480172 107252.132730 0.962814 16.55823 100.26922 301.44360 202.92503 342.93178 2009 7 2 9:35: 0.000277 1844080.00000000 -27430.94936367 -61551.64981438 11287.78761309 1.796240927 2.078576552 -0.635685852 107251.213935 0.962813 16.55849 100.26923 301.44333 203.12889 343.24067 2009 7 2 9:40: 0.000259 1844085.00000000 -26889.88686232 -60924.22895005 11096.42526856 1.806614763 2.101954513 -0.639970719 107250.265413 0.962811 16.55875 100.26924 301.44306 203.33764 343.54956 2009 7 2 9:45: 0.000282 1844090.00000000 -26345.68309880 -60289.69885481 10903.76218217 1.817157098 2.125947384 -0.644337692 107249.285617 0.962809 16.55901 100.26926 301.44278 203.55150 343.85845 2009 7 2 9:50: 0.000264 1844095.00000000 -25798.28673217 -59647.87053555 10709.77327429 1.827873095 2.150584520 -0.648789848 107248.272889 0.962807 16.55927 100.26929 301.44251 203.77071 344.16734 2009 7 2 9:55: 0.000286 1844100.00000000 -25247.64484245 -58998.54588611 10514.43251873 1.838768116 2.175897299 -0.653330430 107247.225447 0.962805 16.55953 100.26931 301.44223 203.99552 344.47623 2009 7 2 10: 0: 0.000268 1844105.00000000 -24693.70286998 -58341.51705293 10317.71289135 1.849847729 2.201919308 -0.657962859 107246.141374 0.962803 16.55979 100.26934 301.44196 204.22620 344.78513 2009 7 2 10: 5: 0.000250 1844110.00000000 -24136.40455244 -57676.56574206 10119.58631477 1.861117715 2.228686544 -0.662690746 107245.018605 0.962801 16.56006 100.26937 301.44168 204.46304 345.09402 2009 7 2 10:10: 0.000273 1844115.00000000 -23575.69186056 -57003.46246135 9920.02359927 1.872584071 2.256237646 -0.667517908 107243.854915 0.962799 16.56032 100.26941 301.44140 204.70634 345.40292 2009 7 2 10:15: 0.000255 1844120.00000000 -23011.50493242 -56321.96569019 9718.99437947 1.884253014 2.284614147 -0.672448379 107242.647894 0.962797 16.56059 100.26945 301.44111 204.95645 345.71182 2009 7 2 10:20: 0.000277 1844125.00000000 -22443.78200684 -55631.82096815 9516.46704636 1.896130986 2.313860763 -0.677486431 107241.394940 0.962795 16.56086 100.26950 301.44083 205.21372 346.02073 2009 7 2 10:25: 0.000259 1844130.00000000 -21872.45935608 -54932.75989218 9312.40867434 1.908224653 2.344025713 -0.682636585 107240.093227 0.962793 16.56113 100.26955 301.44054 205.47854 346.32963 2009 7 2 10:30: 0.000282 1844135.00000000 -21297.47121883 -54224.49901162 9106.78494287 1.920540902 2.375161082 -0.687903637 107238.739687 0.962791 16.56140 100.26961 301.44025 205.75132 346.63854 2009 7 2 10:35: 0.000264 1844140.00000000 -20718.74973403 -53506.73860734 8899.56005222 1.933086841 2.407323230 -0.693292673 107237.330982 0.962789 16.56167 100.26967 301.43995 206.03251 346.94745 2009 7 2 10:40: 0.000286 1844145.00000000 -20136.22487674 -52779.16134023 8690.69663286 1.945869783 2.440573257 -0.698809093 107235.863473 0.962787 16.56195 100.26974 301.43966 206.32260 347.25636 2009 7 2 10:45: 0.000268 1844150.00000000 -19549.82439734 -52041.43075119 8480.15564799 1.958897241 2.474977526 -0.704458636 107234.333182 0.962785 16.56222 100.26982 301.43935 206.62211 347.56527 2009 7 2 10:50: 0.000250 1844155.00000000 -18959.47376563 -51293.18959215 8267.89628842 1.972176899 2.510608267 -0.710247405 107232.735755 0.962783 16.56250 100.26991 301.43905 206.93163 347.87419 2009 7 2 10:55: 0.000273 1844160.00000000 -18365.09612269 -50534.05796487 8053.87585961 1.985716590 2.547544259 -0.716181895 107231.066412 0.962781 16.56278 100.27000 301.43874 207.25177 348.18311 2009 7 2 11: 0: 0.000255 1844165.00000000 -17766.61224263 -49763.63123890 7838.04965980 1.999524252 2.585871620 -0.722269025 107229.319897 0.962779 16.56307 100.27010 301.43842 207.58322 348.49203 2009 7 2 11: 5: 0.000277 1844170.00000000 -17163.94050833 -48981.47771614 7620.37084880 2.013607877 2.625684710 -0.728516169 107227.490411 0.962777 16.56335 100.27021 301.43810 207.92672 348.80095 2009 7 2 11:10: 0.000259 1844175.00000000 -16556.99690580 -48187.13600348 7400.79030672 2.027975437 2.667087175 -0.734931191 107225.571544 0.962774 16.56364 100.27033 301.43778 208.28311 349.10988 2009 7 2 11:15: 0.000282 1844180.00000000 -15945.69504290 -47380.11204687 7179.25648175 2.042634794 2.710193161 -0.741522483 107223.556186 0.962772 16.56393 100.27046 301.43744 208.65326 349.41880 2009 7 2 11:20: 0.000264 1844185.00000000 -15329.94620103 -46559.87577354 6955.71522690 2.057593576 2.755128724 -0.748299005 107221.436432 0.962770 16.56422 100.27060 301.43710 209.03820 349.72774 2009 7 2 11:25: 0.000286 1844190.00000000 -14709.65942851 -45725.85727497 6730.10962444 2.072859013 2.802033480 -0.755270324 107219.203462 0.962768 16.56452 100.27076 301.43675 209.43900 350.03667 2009 7 2 11:30: 0.000268 1844195.00000000 -14084.74168946 -44877.44245330 6502.37979807 2.088437732 2.851062542 -0.762446659 107216.847404 0.962765 16.56482 100.27092 301.43640 209.85690 350.34561 2009 7 2 11:35: 0.000250 1844200.00000000 -13455.09808433 -44013.96803490 6272.46271243 2.104335484 2.902388807 -0.769838921 107214.357170 0.962763 16.56512 100.27111 301.43603 210.29326 350.65455 2009 7 2 11:40: 0.000273 1844205.00000000 -12820.63216428 -43134.71583613 6040.29196035 2.120556786 2.956205671 -0.777458756 107211.720259 0.962761 16.56542 100.27131 301.43565 210.74959 350.96349 2009 7 2 11:45: 0.000255 1844210.00000000 -12181.24636732 -42238.90613844 5805.79753835 2.137104464 3.012730262 -0.785318582 107208.922519 0.962758 16.56573 100.27153 301.43526 211.22760 351.27244 2009 7 2 11:50: 0.000277 1844215.00000000 -11536.84261368 -41325.68999865 5568.90561221 2.153979041 3.072207323 -0.793431617 107205.947864 0.962756 16.56605 100.27177 301.43485 211.72921 351.58139 2009 7 2 11:55: 0.000259 1844220.00000000 -10887.32310987 -40394.14027737 5329.53827536 2.171177951 3.134913901 -0.801811902 107202.777924 0.962753 16.56637 100.27204 301.43443 212.25660 351.89035 2009 7 2 12: 0: 0.000282 1844225.00000000 -10232.59142737 -39443.24111540 5087.61330523 2.188694483 3.201165036 -0.810474295 107199.391616 0.962750 16.56669 100.27233 301.43399 212.81223 352.19931 2009 7 2 12: 5: 0.000264 1844230.00000000 -9572.55394393 -38471.87551671 4843.04392506 2.206516401 3.271320733 -0.819434438 107195.764621 0.962748 16.56701 100.27265 301.43353 213.39892 352.50827 2009 7 2 12:10: 0.000286 1844235.00000000 -8907.12176784 -37478.81060673 4595.73858344 2.224624089 3.345794555 -0.828708674 107191.868720 0.962745 16.56735 100.27300 301.43305 214.01991 352.81724 2009 7 2 12:15: 0.000268 1844240.00000000 -8236.21330715 -36462.68000983 4345.60076943 2.242988067 3.425064297 -0.838313893 107187.670970 0.962742 16.56768 100.27339 301.43254 214.67894 353.12622 2009 7 2 12:20: 0.000250 1844245.00000000 -7559.75771067 -35421.96263240 4092.52889178 2.261565621 3.509685388 -0.848267260 107183.132658 0.962739 16.56803 100.27382 301.43201 215.38035 353.43520 2009 7 2 12:25: 0.000273 1844250.00000000 -6877.69949423 -34354.95691398 3836.41626403 2.280296205 3.600307848 -0.858585776 107178.207951 0.962736 16.56837 100.27430 301.43143 216.12924 353.74418 2009 7 2 12:30: 0.000255 1844255.00000000 -6190.00479593 -33259.74931042 3577.15125966 2.299095084 3.697697981 -0.869285578 107172.842155 0.962732 16.56873 100.27483 301.43082 216.93161 354.05317 2009 7 2 12:35: 0.000277 1844260.00000000 -5496.66989517 -32134.17535485 3314.61773512 2.317844446 3.802766452 -0.880380840 107166.969427 0.962729 16.56909 100.27542 301.43016 217.79460 354.36217 2009 7 2 12:40: 0.000259 1844265.00000000 -4797.73291806 -30975.77105656 3048.69587160 2.336380825 3.916605048 -0.891882055 107160.509727 0.962725 16.56946 100.27609 301.42945 218.72678 354.67118 2009 7 2 12:45: 0.000282 1844270.00000000 -4093.29008842 -29781.71155368 2779.26366928 2.354477016 4.040535491 -0.903793358 107153.364709 0.962721 16.56984 100.27684 301.42867 219.73855 354.98019 2009 7 2 12:50: 0.000264 1844275.00000000 -3383.51857112 -28548.73271713 2506.19946418 2.371815647 4.176175206 -0.916108304 107145.412070 0.962717 16.57022 100.27769 301.42781 220.84268 355.28921 2009 7 2 12:55: 0.000286 1844280.00000000 -2668.70904438 -27273.02958541 2229.38606006 2.387949818 4.325527393 -0.928803170 107136.497643 0.962712 16.57061 100.27865 301.42686 222.05501 355.59824 2009 7 2 13: 0: 0.000268 1844285.00000000 -1949.31292724 -25950.12276772 1948.71744545 2.402243201 4.491106668 -0.941826145 107126.424100 0.962707 16.57101 100.27976 301.42580 223.39556 355.90729 2009 7 2 13: 5: 0.000250 1844290.00000000 -1226.01219539 -24574.67969914 1664.10971973 2.413776635 4.676117853 -0.955079559 107114.934413 0.962702 16.57141 100.28105 301.42459 224.88998 356.21634 2009 7 2 13:10: 0.000273 1844295.00000000 -499.82494656 -23140.27088532 1375.51902292 2.421198325 4.884716234 -0.968389967 107101.686955 0.962696 16.57181 100.28254 301.42322 226.57181 356.52541 2009 7 2 13:15: 0.000255 1844300.00000000 227.73070622 -21639.03026438 1082.97143381 2.422475651 5.122396027 -0.981456298 107086.216827 0.962689 16.57221 100.28430 301.42162 228.48591 356.83450 2009 7 2 13:20: 0.000277 1844305.00000000 954.37414156 -20061.17032355 786.61399449 2.414468102 5.396586724 -0.993756776 107067.873450 0.962681 16.57260 100.28640 301.41975 230.69381 357.14360 2009 7 2 13:25: 0.000259 1844310.00000000 1676.62598578 -18394.27054334 486.80451896 2.392158864 5.717597475 -1.004374559 107045.715250 0.962672 16.57296 100.28892 301.41751 233.28265 357.45273 2009 7 2 13:30: 0.000282 1844315.00000000 2389.05019358 -16622.20037093 184.27608369 2.347196726 6.100163738 -1.011653737 107018.321932 0.962661 16.57327 100.29202 301.41479 236.38060 357.76188 2009 7 2 13:35: 0.000264 1844320.00000000 3082.86422007 -14723.43238400 -119.54602920 2.264946104 6.566068142 -1.012476101 106983.436286 0.962647 16.57347 100.29586 301.41142 240.18503 358.07107 2009 7 2 13:40: 0.000286 1844325.00000000 3743.21501841 -12668.30537300 -421.89289454 2.118033246 7.148704873 -1.000616134 106937.218867 0.962629 16.57346 100.30071 301.40718 245.01826 358.38030 2009 7 2 13:45: 0.000268 1844330.00000000 4343.37719213 -10414.45480896 -717.19751285 1.850804312 7.900986048 -0.962613657 106872.512649 0.962605 16.57303 100.30687 301.40176 251.44720 358.68960 2009 7 2 13:50: 0.000250 1844335.00000000 4831.03777566 -7899.26116450 -993.48392108 1.337297849 8.906916366 -0.866084974 106774.174776 0.962568 16.57169 100.31447 301.39505 260.56996 358.99898 2009 7 2 13:55: 0.000273 1844340.00000000 5091.55546380 -5030.01134361 -1222.14210549 0.252792005 10.276493768 -0.621814132 106604.437813 0.962507 16.56837 100.32203 301.38830 274.78802 359.30853 2009 7 2 14: 0: 0.000255 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/tests.py0000644000175100001730000007563714422467341014337 0ustar00runnerdocker"""Test suite for SGP4.""" try: from unittest2 import TestCase, main except: from unittest import TestCase, main import datetime as dt import re import os import sys from doctest import DocTestSuite, ELLIPSIS from math import pi, isnan from pkgutil import get_data try: from io import StringIO except ImportError: from StringIO import StringIO import numpy as np from sgp4.api import WGS72OLD, WGS72, WGS84, Satrec, jday from sgp4.earth_gravity import wgs72 from sgp4.ext import invjday, newtonnu, rv2coe from sgp4.functions import days2mdhms, _day_of_year_to_month_day from sgp4.propagation import sgp4, sgp4init from sgp4 import api, conveniences, io, omm from sgp4.exporter import export_omm, export_tle import sgp4.model as model _testcase = TestCase('setUp') _testcase.maxDiff = 9999 assertEqual = _testcase.assertEqual assertAlmostEqual = _testcase.assertAlmostEqual assertRaises = _testcase.assertRaises assertRaisesRegex = getattr(_testcase, 'assertRaisesRegex', _testcase.assertRaisesRegexp) error = 2e-7 rad = 180.0 / pi LINE1 = '1 00005U 58002B 00179.78495062 .00000023 00000-0 28098-4 0 4753' LINE2 = '2 00005 34.2682 348.7242 1859667 331.7664 19.3264 10.82419157413667' BAD2 = '2 00007 34.2682 348.7242 1859667 331.7664 19.3264 10.82419157413669' VANGUARD_ATTRS = { # Identity 'satnum': 5, 'satnum_str': '00005', 'classification': 'U', 'operationmode': 'i', # Time 'epochyr': 0, 'epochdays': 179.78495062, 'jdsatepoch': 2451722.5, 'jdsatepochF': 0.78495062, # Orbit 'bstar': 2.8098e-05, 'ndot': 6.96919666594958e-13, 'nddot': 0.0, 'ecco': 0.1859667, 'argpo': 5.790416027488515, 'inclo': 0.5980929187319208, 'mo': 0.3373093125574321, 'no_kozai': 0.04722944544077857, 'nodeo': 6.08638547138321, } VANGUARD_EPOCH = 18441.78495062 # Handle deprecated assertRaisesRegexp, but allow its use Python 2.6 and 2.7 if sys.version_info[:2] == (2, 7) or sys.version_info[:2] == (2, 6): TestCase.assertRaisesRegex = TestCase.assertRaisesRegexp # ------------------------------------------------------------------------ # Core Attributes # def test_satrec_built_with_twoline2rv(): sat = Satrec.twoline2rv(LINE1, LINE2) verify_vanguard_1(sat) def test_legacy_built_with_twoline2rv(): sat = io.twoline2rv(LINE1, LINE2, wgs72) verify_vanguard_1(sat, legacy=True) def test_satrec_initialized_with_sgp4init(): sat = Satrec() sat.sgp4init( WGS72, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *sgp4init_args(VANGUARD_ATTRS) ) verify_vanguard_1(sat) def test_satrec_initialized_with_sgp4init_in_afspc_mode(): sat = Satrec() sat.sgp4init( WGS72, 'a', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *sgp4init_args(VANGUARD_ATTRS) ) assertEqual(sat.operationmode, 'a') def test_legacy_initialized_with_sgp4init(): sat = model.Satellite() sgp4init( wgs72, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *sgp4init_args(VANGUARD_ATTRS) + (sat,) ) verify_vanguard_1(sat, legacy=True) # ------------------------------------------------------------------------ # Test array API def test_whether_array_logic_writes_nan_values_to_correct_row(): # https://github.com/brandon-rhodes/python-sgp4/issues/87 l1 = "1 44160U 19006AX 20162.79712247 +.00816806 +19088-3 +34711-2 0 9997" l2 = "2 44160 095.2472 272.0808 0216413 032.6694 328.7739 15.58006382062511" sat = Satrec.twoline2rv(l1, l2) jd0 = np.array([2459054.5, 2459055.5]) jd1 = np.array([0.79712247, 0.79712247]) e, r, v = sat.sgp4_array(jd0, jd1) assert list(e) == [6, 1] assert np.isnan(r).tolist() == [[False, False, False], [True, True, True]] assert np.isnan(v).tolist() == [[False, False, False], [True, True, True]] # ------------------------------------------------------------------------ # Other Officially Supported Routines # def test_days2mdhms(): # See https://github.com/brandon-rhodes/python-sgp4/issues/64 tup = days2mdhms(2020, 133.35625) assertEqual(tup, (5, 12, 8, 33, 0.0)) def test_jday2(): jd, fr = jday(2019, 10, 9, 16, 57, 15) assertEqual(jd, 2458765.5) assertAlmostEqual(fr, 0.7064236111111111) def test_jday_datetime(): # define local time # UTC equivalent: 2011-11-03 20:05:23+00:00 class UTC_plus_4(dt.tzinfo): 'UTC' offset = dt.timedelta(hours=4) def utcoffset(self, datetime): return self.offset def tzname(self, datetime): return 'UTC plus 4' def dst(self, datetime): return self.offset datetime_local = dt.datetime(2011, 11, 4, 0, 5, 23, 0, UTC_plus_4()) jd, fr = conveniences.jday_datetime(datetime_local) # jd of this date is 2455868.5 + 0.8370717592592593 assertEqual(jd, 2455868.5) assertAlmostEqual(fr, 0.8370717592592593) def test_sat_epoch_datetime(): sat = Satrec.twoline2rv(LINE1, LINE2) datetime = conveniences.sat_epoch_datetime(sat) zone = conveniences.UTC assertEqual(datetime, dt.datetime(2000, 6, 27, 18, 50, 19, 733568, zone)) def test_good_tle_checksum(): for line in LINE1, LINE2: checksum = int(line[-1]) assertEqual(io.compute_checksum(line), checksum) assertEqual(io.fix_checksum(line[:68]), line) io.verify_checksum(line) def test_bad_tle_checksum(): checksum = LINE1[-1] assertEqual(checksum, '3') bad = LINE1[:68] + '7' assertRaises(ValueError, io.verify_checksum, bad) assertEqual(io.fix_checksum(bad), LINE1) def test_tle_export(): """Check `export_tle()` round-trip using all the TLEs in the test file. This iterates through the satellites in "SGP4-VER.TLE", generates `Satrec` objects and exports the TLEs. These exported TLEs are then compared to the original TLE, closing the loop (or the round-trip). """ data = get_data(__name__, 'SGP4-VER.TLE') tle_lines = iter(data.decode('ascii').splitlines()) # Skip these lines, known errors # Resulting TLEs are equivalent (same values in the Satrec object), but they are not the same # 25954: BSTAR = 0 results in a negative exp, not positive # 29141: BSTAR = 0.13519 results in a negative exp, not positive # 33333: Checksum error as expected on both lines # 33334: Checksum error as expected on line 1 # 33335: Checksum error as expected on line 1 expected_errs_line1 = set([25954, 29141, 33333, 33334, 33335]) expected_errs_line2 = set([33333, 33335]) # Non-standard: omits the ephemeris type integer. expected_errs_line1.add(11801) for line1 in tle_lines: if not line1.startswith('1'): continue line2 = next(tle_lines) # trim lines to normal TLE string size line1 = line1[:69] line2 = line2[:69] satrec = Satrec.twoline2rv(line1, line2) satrec_old = io.twoline2rv(line1, line2, wgs72) # Generate TLE from satrec actual_line1, actual_line2 = export_tle(satrec) actual_line1_old, actual_line2_old = export_tle(satrec_old) if satrec.satnum not in expected_errs_line1: assertEqual(actual_line1, line1) assertEqual(actual_line1_old, line1) if satrec.satnum not in expected_errs_line2: assertEqual(actual_line2, line2) assertEqual(actual_line2_old, line2) def test_export_tle_raises_error_for_out_of_range_angles(): # See https://github.com/brandon-rhodes/python-sgp4/issues/70 for angle in 'inclo', 'nodeo', 'argpo', 'mo': sat = Satrec() wrong_vanguard_attrs = VANGUARD_ATTRS.copy() wrong_vanguard_attrs[angle] = -1.0 sat.sgp4init( WGS84, 'i', wrong_vanguard_attrs['satnum'], VANGUARD_EPOCH, *sgp4init_args(wrong_vanguard_attrs) ) assertRaises(ValueError, export_tle, sat) def test_tle_import_export_round_trips(): for line1, line2 in [( '1 44542U 19061A 21180.78220369 -.00000015 00000-0 -66561+1 0 9997', '2 44542 54.7025 244.1098 0007981 318.8601 283.5781 1.86231125 12011', )]: sat = Satrec.twoline2rv(line1, line2) outline1, outline2 = export_tle(sat) assertEqual(line1, outline1) assertEqual(line2, outline2) def test_all_three_gravity_models_with_twoline2rv(): # The numbers below are those produced by Vallado's C++ code. # (Why does the Python version not produce the same values to # high accuracy, instead of agreeing to only 4 places?) assert_wgs72old(Satrec.twoline2rv(LINE1, LINE2, WGS72OLD)) assert_wgs72(Satrec.twoline2rv(LINE1, LINE2, WGS72)) assert_wgs84(Satrec.twoline2rv(LINE1, LINE2, WGS84)) # Not specifying a gravity model should select WGS72. assert_wgs72(Satrec.twoline2rv(LINE1, LINE2)) def test_all_three_gravity_models_with_sgp4init(): # Gravity models specified with sgp4init() should also change the # positions generated. sat = Satrec() args = sgp4init_args(VANGUARD_ATTRS) sat.sgp4init(WGS72OLD, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *args) assert_wgs72old(sat) sat.sgp4init(WGS72, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *args) assert_wgs72(sat) sat.sgp4init(WGS84, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *args) assert_wgs84(sat) GRAVITY_DIGITS = ( # Why don't Python and C agree more closely? 4 if not api.accelerated # Otherwise, try 10 digits. Note that at least 6 digits past the # decimal point are necessary to let the test distinguish between # WSG72OLD and WGS72. See: # https://github.com/conda-forge/sgp4-feedstock/pull/19 # https://github.com/brandon-rhodes/python-sgp4/issues/69 else 10 ) def assert_wgs72old(sat): e, r, v = sat.sgp4_tsince(309.67110720001529) assertAlmostEqual(r[0], -3754.251473242793, GRAVITY_DIGITS) assertAlmostEqual(r[1], 7876.346815095482, GRAVITY_DIGITS) assertAlmostEqual(r[2], 4719.220855042922, GRAVITY_DIGITS) def assert_wgs72(sat): e, r, v = sat.sgp4_tsince(309.67110720001529) assertAlmostEqual(r[0], -3754.2514743216166, GRAVITY_DIGITS) assertAlmostEqual(r[1], 7876.346817439062, GRAVITY_DIGITS) assertAlmostEqual(r[2], 4719.220856478582, GRAVITY_DIGITS) def assert_wgs84(sat): e, r, v = sat.sgp4_tsince(309.67110720001529) assertAlmostEqual(r[0], -3754.2437675772426, GRAVITY_DIGITS) assertAlmostEqual(r[1], 7876.3549956188945, GRAVITY_DIGITS) assertAlmostEqual(r[2], 4719.227897029576, GRAVITY_DIGITS) # ------------------------------------------------------------------------ # Special Cases # def test_satnum_leading_spaces(): # https://github.com/brandon-rhodes/python-sgp4/issues/81 # https://github.com/brandon-rhodes/python-sgp4/issues/90 l1 = '1 4859U 21001A 21007.63955392 .00000000 00000+0 00000+0 0 9990' l2 = '2 4859 000.0000 000.0000 0000000 000.0000 000.0000 01.00000000 09' sat = Satrec.twoline2rv(l1, l2) assertEqual(sat.satnum, 4859) assertEqual(sat.classification, 'U') assertEqual(sat.intldesg, '21001A') def test_satnum_alpha5_encoding(): def make_sat(satnum_string): return Satrec.twoline2rv(LINE1.replace('00005', satnum_string), LINE2.replace('00005', satnum_string)) # Test cases from https://www.space-track.org/documentation#tle-alpha5 cases = [(100000, 'A0000'), (148493, 'E8493'), (182931, 'J2931'), (234018, 'P4018'), (301928, 'W1928'), (339999, 'Z9999')] for satnum, satnum_string in cases: sat = make_sat(satnum_string) assertEqual(sat.satnum, satnum) assertEqual(sat.satnum_str, satnum_string) args = sgp4init_args(VANGUARD_ATTRS) for satnum, satnum_string in cases: sat.sgp4init(WGS72, 'i', satnum, VANGUARD_EPOCH, *args) assertEqual(sat.satnum, satnum) def test_satnum_that_is_too_large(): sat = Satrec() with assertRaisesRegex(ValueError, 'cannot exceed 339999'): sat.sgp4init( WGS72, 'i', 340000, VANGUARD_EPOCH, *sgp4init_args(VANGUARD_ATTRS) ) def test_intldesg_with_6_characters(): sat = Satrec.twoline2rv(LINE1, LINE2) assertEqual(sat.intldesg, '58002B') def test_intldesg_with_7_characters(): sat = Satrec.twoline2rv( '1 39444U 13066AE 20110.89708219 .00000236 00000-0' ' 35029-4 0 9992', '2 39444 97.5597 114.3769 0059573 102.0933 258.6965 ' '14.82098949344697', ) assertEqual(sat.intldesg, '13066AE') def test_1990s_satrec_initialized_with_sgp4init(): sat = Satrec() sat.sgp4init( WGS72, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH - 365.0, # change year 2000 to 1999 *sgp4init_args(VANGUARD_ATTRS) ) assertEqual(sat.epochyr, 99) def test_setters(): sat = Satrec() sat.classification = 'S' assert sat.classification == 'S' sat.intldesg = 'abcdefg' assert sat.intldesg == 'abcdefg' sat.ephtype = 23 assert sat.ephtype == 23 sat.elnum = 123 assert sat.elnum == 123 sat.revnum = 1234 assert sat.revnum == 1234 sat.satnum_str = 'abcde' assert sat.satnum_str == 'abcde' def test_hyperbolic_orbit(): # Exercise the newtonnu() code path with asinh() to see whether # we can replace it with the one from Python's math module. e0, m = newtonnu(1.0, 2.9) # parabolic assertAlmostEqual(e0, 8.238092752965605, places=12) assertAlmostEqual(m, 194.60069989482898, places=12) e0, m = newtonnu(1.1, 2.7) # hyperbolic assertAlmostEqual(e0, 4.262200676156417, places=12) assertAlmostEqual(m, 34.76134082028372, places=12) def test_correct_epochyr(): # Make sure that the non-standard four-digit epochyr I switched # to in the Python version of SGP4 is reverted back to the # official behavior when that code is used behind Satrec. sat = Satrec.twoline2rv(LINE1, LINE2) assertEqual(sat.epochyr, 0) def test_legacy_epochyr(): # Apparently I saw fit to change the meaning of this attribute # in the Python version of SGP4. sat = io.twoline2rv(LINE1, LINE2, wgs72) assertEqual(sat.epochyr, 2000) def test_support_for_old_no_attribute(): s = io.twoline2rv(LINE1, LINE2, wgs72) assert s.no == s.no_kozai def test_months_and_days(): # Make sure our hand-written months-and-days routine is perfect. month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] day_of_year = 1 for month, length in enumerate(month_lengths, 1): for day in range(1, length + 1): tup = _day_of_year_to_month_day(day_of_year, False) assertEqual((month, day), tup) day_of_year += 1 month_lengths[1] = 29 # February, during a leap year day_of_year = 1 for month, length in enumerate(month_lengths, 1): for day in range(1, length + 1): tup = _day_of_year_to_month_day(day_of_year, True) assertEqual((month, day), tup) day_of_year += 1 def test_december_32(): # ISS [Orbit 606], whose date is 2019 plus 366.82137887 days. # The core SGP4 routines handled this fine, but my hamfisted # attempt to provide a Python datetime for "convenience" ran # into an overflow. a = '1 25544U 98067A 19366.82137887 .00016717 00000-0 10270-3 0 9129' b = '2 25544 51.6392 96.6358 0005156 88.7140 271.4601 15.49497216 6061' correct_epoch = dt.datetime(2020, 1, 1, 19, 42, 47, 134368) # Legacy API. sat = io.twoline2rv(a, b, wgs72) assertEqual(sat.epoch, correct_epoch) correct_epoch = correct_epoch.replace(tzinfo=conveniences.UTC) # Modern API. sat = Satrec.twoline2rv(a, b) assertEqual(conveniences.sat_epoch_datetime(sat), correct_epoch) def test_non_ascii_first_line(): if sys.version_info < (3,): return with assertRaisesRegex(ValueError, re.escape("""your TLE lines are broken because they contain non-ASCII characters: 1 00005U 58002B 00179.78495062 .00000023\\xa0 00000-0 28098-4 0 4753 2 00005 34.2682 348.7242 1859667 331.7664 19.3264 10.82419157413667""")): io.twoline2rv(LINE1.replace('23 ', '23\xa0'), LINE2, wgs72) def test_non_ascii_second_line(): if sys.version_info < (3,): return with assertRaisesRegex(ValueError, re.escape("""your TLE lines are broken because they contain non-ASCII characters: 1 00005U 58002B 00179.78495062 .00000023 00000-0 28098-4 0 4753 2 00005 \\xa034.2682\\xa0348.7242 1859667 331.7664 19.3264 10.82419157413667\ """)): io.twoline2rv(LINE1, LINE2.replace(' 34', '\xa034'), wgs72) def test_bad_first_line(): with assertRaisesRegex(ValueError, re.escape("""TLE format error The Two-Line Element (TLE) format was designed for punch cards, and so is very strict about the position of every period, space, and digit. Your line does not quite match. Here is the official format for line 1 with an N where each digit should go, followed by the line you provided: 1 NNNNNC NNNNNAAA NNNNN.NNNNNNNN +.NNNNNNNN +NNNNN-N +NNNNN-N N NNNNN 1 00005U 58002B 00179.78495062 .000000234 00000-0 28098-4 0 4753""")): io.twoline2rv(LINE1.replace('23 ', '234'), LINE2, wgs72) def test_bad_second_line(): with assertRaisesRegex(ValueError, re.escape("""TLE format error The Two-Line Element (TLE) format was designed for punch cards, and so is very strict about the position of every period, space, and digit. Your line does not quite match. Here is the official format for line 2 with an N where each digit should go, followed by the line you provided: 2 NNNNN NNN.NNNN NNN.NNNN NNNNNNN NNN.NNNN NNN.NNNN NN.NNNNNNNNNNNNNN 2 00005 34 .268234 8.7242 1859667 331.7664 19.3264 10.82419157413667""")): io.twoline2rv(LINE1, LINE2.replace(' 34', '34 '), wgs72) def test_mismatched_lines(): msg = "Object numbers in lines 1 and 2 do not match" with assertRaisesRegex(ValueError, re.escape(msg)): io.twoline2rv(LINE1, BAD2, wgs72) # ------------------------------------------------------------------------ # Helper routines # def verify_vanguard_1(sat, legacy=False): attrs = VANGUARD_ATTRS if legacy: attrs = attrs.copy() del attrs['epochyr'] del attrs['epochdays'] del attrs['jdsatepoch'] del attrs['jdsatepochF'] for name, value in attrs.items(): try: assertEqual(getattr(sat, name), value) except AssertionError as e: message, = e.args e.args = ('for attribute %s, %s' % (name, message),) raise e def sgp4init_args(d): """Given a dict of orbital parameters, return them in sgp4init order.""" return (d['bstar'], d['ndot'], d['nddot'], d['ecco'], d['argpo'], d['inclo'], d['mo'], d['no_kozai'], d['nodeo']) # ---------------------------------------------------------------------- # INTEGRATION TEST # # This runs both new and old satellite objects against every example # computation in the official `tcppver.out` test case file. Instead of # trying to parse the file, it instead re-generates it using Python # satellite objects, then compares the resulting text with the file. def test_satrec_against_tcppver_using_julian_dates(): def invoke(satrec, tsince): whole, fraction = divmod(tsince / 1440.0, 1.0) jd = satrec.jdsatepoch + whole fr = satrec.jdsatepochF + fraction e, r, v = satrec.sgp4(jd, fr) assert e == satrec.error return e, r, v run_satellite_against_tcppver(Satrec.twoline2rv, invoke, [1,1,6,6,4,3,6]) def test_satrec_against_tcppver_using_tsince(): def invoke(satrec, tsince): e, r, v = satrec.sgp4_tsince(tsince) assert e == satrec.error return e, r, v run_satellite_against_tcppver(Satrec.twoline2rv, invoke, [1,1,6,6,4,3,6]) def test_legacy_against_tcppver(): def make_legacy_satellite(line1, line2): sat = io.twoline2rv(line1, line2, wgs72) return sat def run_legacy_sgp4(satrec, tsince): r, v = sgp4(satrec, tsince) return (satrec.error, satrec.error_message), r, v errs = [ (1, 'mean eccentricity -0.001329 not within range 0.0 <= e < 1.0'), (1, 'mean eccentricity -0.001208 not within range 0.0 <= e < 1.0'), (6, 'mrt 0.996159 is less than 1.0' ' indicating the satellite has decayed'), (6, 'mrt 0.996252 is less than 1.0' ' indicating the satellite has decayed'), (4, 'semilatus rectum -0.103223 is less than zero'), (3, 'perturbed eccentricity -122.217193' ' not within range 0.0 <= e <= 1.0'), (6, 'mrt 0.830534 is less than 1.0' ' indicating the satellite has decayed'), ] run_satellite_against_tcppver(make_legacy_satellite, run_legacy_sgp4, errs) def run_satellite_against_tcppver(twoline2rv, invoke, expected_errors): # Check whether this library can produce (at least roughly) the # output in tcppver.out. data = get_data(__name__, 'tcppver.out') data = data.replace(b'\r', b'') tcppver_lines = data.decode('ascii').splitlines(True) error_list = [] actual_lines = list(generate_test_output(twoline2rv, invoke, error_list)) assert len(tcppver_lines) == len(actual_lines) == 700 previous_data_line = None linepairs = zip(tcppver_lines, actual_lines) for lineno, (expected_line, actual_line) in enumerate(linepairs, start=1): if actual_line == '(Use previous data line)': actual_line = (' 0.00000000' + previous_data_line[17:107]) # Compare the lines. The first seven fields are printed # to very high precision, so we allow a small error due # to rounding differences; the rest are printed to lower # precision, and so can be compared textually. if 'xx' in actual_line: similar = (actual_line == expected_line) else: afields = actual_line.split() efields = expected_line.split() actual7 = [ float(a) for a in afields[:7] ] expected7 = [ float(e) for e in efields[:7] ] similar = ( len(actual7) == len(expected7) and all( -error < (a - e) < error for a, e in zip(actual7, expected7) ) and afields[7:] == efields[7:] # just compare text ) if not similar: raise ValueError( 'Line %d of output does not match:\n' '\n' 'Expected: %r\n' 'Got back: %r' % (lineno, expected_line, actual_line)) if 'xx' not in actual_line: previous_data_line = actual_line # Make sure we produced the correct list of errors. assertEqual(error_list, expected_errors) def generate_test_output(twoline2rv, invoke, error_list): """Generate lines like those in the test file tcppver.out. This iterates through the satellites in "SGP4-VER.TLE", which are each supplemented with a time start/stop/step over which we are supposed to print results. """ data = get_data(__name__, 'SGP4-VER.TLE') tle_lines = iter(data.decode('ascii').splitlines()) for line1 in tle_lines: if not line1.startswith('1'): continue line2 = next(tle_lines) satrec = twoline2rv(line1, line2) yield '%ld xx\n' % (satrec.satnum,) for line in generate_satellite_output( satrec, invoke, line2, error_list): yield line def generate_satellite_output(satrec, invoke, line2, error_list): """Print a data line for each time in line2's start/stop/step field.""" mu = wgs72.mu e, r, v = invoke(satrec, 0.0) if isnan(r[0]) and isnan(r[1]) and isnan(r[2]): error_list.append(e) yield '(Use previous data line)' return yield format_short_line(0.0, r, v) tstart, tend, tstep = (float(field) for field in line2[69:].split()) tsince = tstart while tsince <= tend: if tsince == tstart == 0.0: tsince += tstep continue # avoid duplicating the first line e, r, v = invoke(satrec, tsince) if e != 0 and e != (0, None): error_list.append(e) return yield format_long_line(satrec, tsince, mu, r, v) tsince += tstep if tsince - tend < tstep - 1e-6: # do not miss last line! e, r, v = invoke(satrec, tend) if e != 0 and e != (0, None): error_list.append(e) return yield format_long_line(satrec, tend, mu, r, v) def format_short_line(tsince, r, v): """Short line, using the same format string that testcpp.cpp uses.""" return ' %16.8f %16.8f %16.8f %16.8f %12.9f %12.9f %12.9f\n' % ( tsince, r[0], r[1], r[2], v[0], v[1], v[2]) def format_long_line(satrec, tsince, mu, r, v): """Long line, using the same format string that testcpp.cpp uses.""" short = format_short_line(tsince, r, v).strip('\n') jd = satrec.jdsatepoch + satrec.jdsatepochF + tsince / 1440.0 year, mon, day, hr, minute, sec = invjday(jd) (p, a, ecc, incl, node, argp, nu, m, arglat, truelon, lonper ) = rv2coe(r, v, mu) return short + ( ' %14.6f %8.6f %10.5f %10.5f %10.5f %10.5f %10.5f' ' %5i%3i%3i %2i:%2i:%9.6f\n' ) % ( a, ecc, incl*rad, node*rad, argp*rad, nu*rad, m*rad, year, mon, day, hr, minute, sec, ) # ---------------------------------------------------------------------- # NEW "OMM" FORMAT TESTS # https://celestrak.com/satcat/tle.php?CATNR=5 VANGUARD_TLE = """\ VANGUARD 1 \n\ 1 00005U 58002B 20287.20333880 -.00000016 00000-0 -22483-4 0 9998 2 00005 34.2443 225.5254 1845686 162.2516 205.2356 10.84869164218149 """ # The MARIO satellite was chosen by reading through stations.txt looking # for an element set with every field nonzero, since a zero in any field # would hide errors in our unit conversion: zero times any conversion # factor is zero. MARIO_TLE = """\ MARIO \n\ 1 55123U 98067UQ 23115.44827133 .00787702 29408-3 15680-2 0 9999 2 55123 51.6242 216.2930 0014649 331.8976 28.1241 15.99081912 18396 """ # https://celestrak.org/NORAD/elements/gp.php?CATNR=55123&FORMAT=XML MARIO_XML = """\
MARIO1998-067UQEARTHTEMEUTCSGP42023-04-25T10:45:30.64291215.99081912.001464951.6242216.2930331.897628.12410U551239991839.1568E-2.787702E-2.29408E-3
""" # https://celestrak.com/NORAD/elements/gp.php?CATNR=55123&FORMAT=CSV MARIO_CSV = """\ OBJECT_NAME,OBJECT_ID,EPOCH,MEAN_MOTION,ECCENTRICITY,INCLINATION,RA_OF_ASC_NODE,ARG_OF_PERICENTER,MEAN_ANOMALY,EPHEMERIS_TYPE,CLASSIFICATION_TYPE,NORAD_CAT_ID,ELEMENT_SET_NO,REV_AT_EPOCH,BSTAR,MEAN_MOTION_DOT,MEAN_MOTION_DDOT MARIO,1998-067UQ,2023-04-25T10:45:30.642912,15.99081912,.0014649,51.6242,216.2930,331.8976,28.1241,0,U,55123,999,1839,.1568E-2,.787702E-2,.29408E-3 """ def test_omm_xml_matches_old_tle(): line0, line1, line2 = MARIO_TLE.splitlines() sat1 = Satrec.twoline2rv(line1, line2) fields = next(omm.parse_xml(StringIO(MARIO_XML))) sat2 = Satrec() omm.initialize(sat2, fields) assert_satellites_match(sat1, sat2) def test_omm_csv_matches_old_tle(): line0, line1, line2 = MARIO_TLE.splitlines() sat1 = Satrec.twoline2rv(line1, line2) fields = next(omm.parse_csv(StringIO(MARIO_CSV))) sat2 = Satrec() omm.initialize(sat2, fields) assert_satellites_match(sat1, sat2) def assert_satellites_match(sat1, sat2): for attr in dir(sat1): if attr.startswith('_'): continue value1 = getattr(sat1, attr, None) if value1 is None: continue if callable(value1): continue value2 = getattr(sat2, attr) assertEqual(value1, value2, '%s %r != %r' % (attr, value1, value2)) # Live example of OMM: # https://celestrak.com/NORAD/elements/gp.php?INTDES=2020-025&FORMAT=JSON-PRETTY def test_omm_export(): line0, line1, line2 = VANGUARD_TLE.splitlines() sat = Satrec.twoline2rv(line1, line2) fields = export_omm(sat, 'VANGUARD 1') assertEqual(fields, { 'ARG_OF_PERICENTER': 162.2516, 'BSTAR': -2.2483e-05, 'CENTER_NAME': 'EARTH', 'CLASSIFICATION_TYPE': 'U', 'ECCENTRICITY': 0.1845686, 'ELEMENT_SET_NO': 999, 'EPHEMERIS_TYPE': 0, 'EPOCH': '2020-10-13T04:52:48.472320', 'INCLINATION': 34.2443, 'MEAN_ANOMALY': 205.2356, 'MEAN_ELEMENT_THEORY': 'SGP4', 'MEAN_MOTION': 10.84869164, 'MEAN_MOTION_DDOT': 0.0, 'MEAN_MOTION_DOT': -1.6e-07, 'NORAD_CAT_ID': 5, 'OBJECT_ID': '1958-002B', 'OBJECT_NAME': 'VANGUARD 1', 'RA_OF_ASC_NODE': 225.5254, 'REF_FRAME': 'TEME', 'REV_AT_EPOCH': 21814, 'TIME_SYSTEM': 'UTC', }) # ---------------------------------------------------------------------- def load_tests(loader, tests, ignore): """Run our main documentation as a test, plus all test functions.""" from sgp4.wulfgar import add_test_functions add_test_functions(loader, tests, __name__) # Python 2.6 formats floating-point numbers a bit differently and # breaks the doctest, so we only run the doctest on later versions. if sys.version_info >= (2, 7): def setUp(suite): suite.olddir = os.getcwd() os.chdir(os.path.dirname(__file__)) suite.oldaccel = api.accelerated api.accelerated = True # so doctest passes under 2.7 def tearDown(suite): os.chdir(suite.olddir) api.accelerated = suite.oldaccel options = dict(optionflags=ELLIPSIS, setUp=setUp, tearDown=tearDown) tests.addTests(DocTestSuite('sgp4', **options)) tests.addTests(DocTestSuite('sgp4.conveniences', **options)) tests.addTests(DocTestSuite('sgp4.functions', **options)) return tests if __name__ == '__main__': main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/wrapper.py0000644000175100001730000000435314422467341014640 0ustar00runnerdockerfrom . import vallado_cpp class Satrec(vallado_cpp.Satrec): """High-speed computation of satellite positions and velocities.""" __slots__ = () def sgp4_array(self, jd, fr): """Compute positions and velocities for the times in a NumPy array. Given NumPy arrays ``jd`` and ``fr`` of the same length that supply the whole part and the fractional part of one or more Julian dates, return a tuple ``(e, r, v)`` of three vectors: * ``e``: nonzero for any dates that produced errors, 0 otherwise. * ``r``: position vectors in kilometers. * ``v``: velocity vectors in kilometers per second. """ jd = jd.astype('float64', copy=False) fr = fr.astype('float64', copy=False) eshape = jd.shape fshape = eshape[0], 3 array = type(jd) e = array(eshape, 'uint8') r = array(fshape, 'float64') v = array(fshape, 'float64') self._sgp4(jd, fr, e, r, v) return e, r, v class SatrecArray(vallado_cpp.SatrecArray): """High-speed satellite array for computing positions and velocities.""" __slots__ = () def sgp4(self, jd, fr): """Compute positions and velocities for the satellites in this array. Given NumPy scalars or arrays ``jd`` and ``fr`` supplying the whole part and the fractional part of one or more Julian dates, return a tuple ``(e, r, v)`` of three vectors: * ``e``: nonzero for any dates that produced errors, 0 otherwise. * ``r``: position vectors in kilometers. * ``v``: velocity vectors in kilometers per second. The first dimension of each output vector has the same length as this satellite array, the second dimension the same length as the input date arrays, and the third dimension has length 3. """ jd = jd.astype('float64', copy=False) fr = fr.astype('float64', copy=False) ilength = len(self) jlength, = jd.shape eshape = ilength, jlength fshape = ilength, jlength, 3 array = type(jd) e = array(eshape, 'uint8') r = array(fshape, 'float64') v = array(fshape, 'float64') self._sgp4(jd, fr, e, r, v) return e, r, v ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599649.0 sgp4-2.22/sgp4/wulfgar.py0000644000175100001730000000145714422467341014631 0ustar00runnerdocker"""Support test functions, in a module small enough to carry inline.""" from importlib import import_module from unittest import TestCase __unittest = 1 # Tell unittest not to include run() in test tracebacks. def add_test_functions(loader, tests, module_name): """Run our main documentation as a test and test functions in this file.""" def wrap_test_function(test): def run(self): return test() return run module = import_module(module_name) test_methods = dict((name, wrap_test_function(getattr(module, name))) for name in dir(module) if name.startswith('test_')) TestFunctions = type('TestFunctions', (TestCase,), test_methods) TestFunctions.__module__ = module_name tests.addTest(loader.loadTestsFromTestCase(TestFunctions)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1682599655.3394356 sgp4-2.22/sgp4.egg-info/0000755000175100001730000000000014422467347014301 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599655.0 sgp4-2.22/sgp4.egg-info/PKG-INFO0000644000175100001730000007437314422467347015414 0ustar00runnerdockerMetadata-Version: 2.1 Name: sgp4 Version: 2.22 Summary: Track Earth satellites given TLE data, using up-to-date 2020 SGP4 routines. Home-page: https://github.com/brandon-rhodes/python-sgp4 Author: Brandon Rhodes Author-email: brandon@rhodesmill.org License: MIT Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Scientific/Engineering :: Astronomy License-File: LICENSE This package compiles the official C++ code from `Revisiting Spacetrack Report #3 `_ (AIAA 2006-6753) and uses it to compute the positions of satellites in Earth orbit. Orbital elements can be read from either a legacy TLE file or from a modern OMM element set, both of which you can fetch from a site like `CelesTrak `_. If your machine can’t install or compile the C++ code, then this package falls back to using a slower pure-Python implementation of SGP4. Tests make sure that its positions **agree to within 0.1 mm** with the standard version of the algorithm — an error far less than the 1–3 km/day by which satellites themselves deviate from the ideal orbits described in TLE files. An accelerated routine is available that, given a series of times and of satellites, computes a whole array of output positions using a fast C++ loop. See the “Array Acceleration” section below. Note that the SGP4 propagator returns raw *x,y,z* Cartesian coordinates in a “True Equator Mean Equinox” (TEME) reference frame that’s centered on the Earth but does not rotate with it — an “Earth centered inertial” (ECI) reference frame. The SGP4 propagator itself does not implement the math to convert these positions into more official ECI frames like J2000 or the ICRS, nor into any Earth-centered Earth-fixed (ECEF) frames like the ITRS, nor into latitudes and longitudes through an Earth ellipsoid like WGS84. For conversions into these other coordinate frames, look for a comprehensive astronomy library, like the `Skyfield `_ library that is built atop this one (see the `section on Earth satellites `_ in its documentation). Usage ----- You will probably first want to to check whether your machine has successfully installed the fast SGP4 C++ code, or is using the slow Python version (in which case this value will be false): >>> from sgp4.api import accelerated >>> print(accelerated) True This library uses the same function names as the official C++ code, to help users who are already familiar with SGP4 in other languages. Here is how to compute the x,y,z position and velocity for the International Space Station at 12:50:19 on 29 June 2000: >>> from sgp4.api import Satrec >>> >>> s = '1 25544U 98067A 19343.69339541 .00001764 00000-0 38792-4 0 9991' >>> t = '2 25544 51.6439 211.2001 0007417 17.6667 85.6398 15.50103472202482' >>> satellite = Satrec.twoline2rv(s, t) >>> >>> jd, fr = 2458827, 0.362605 >>> e, r, v = satellite.sgp4(jd, fr) >>> e 0 >>> print(r) # True Equator Mean Equinox position (km) (-6102.44..., -986.33..., -2820.31...) >>> print(v) # True Equator Mean Equinox velocity (km/s) (-1.45..., -5.52..., 5.10...) As input, you can provide either: * A simple floating-point Julian Date for ``jd`` and the value 0.0 for ``fr``, if you are happy with the precision of a 64-bit floating point number. Note that modern Julian Dates are greater than 2,450,000 which means that nearly half of the precision of a 64-bit float will be consumed by the whole part that specifies the day. The remaining digits will provide a precision for the fraction of around 20.1 µs. This should be no problem for the accuracy of your result — satellite positions usually off by a few kilometers anyway, far less than a satellite moves in 20.1 µs — but if you run a solver that dives down into the microseconds while searching for a rising or setting time, the solver might be bothered by the 20.1 µs plateau between each jump in the satellite’s position. * Or, you can provide a coarse date ``jd`` plus a very precise fraction ``fr`` that supplies the rest of the value. The Julian Date for which the satellite position is computed is the sum of the two values. One common practice is to provide the whole number as ``jd`` and the fraction as ``fr``; another is to have ``jd`` carry the fraction 0.5 since UTC midnight occurs halfway through each Julian Date. Either way, splitting the value allows a solver to run all the way down into the nanoseconds and still see SGP4 respond smoothly to tiny date adjustments with tiny changes in the resulting satellite position. Here is how to intrepret the results: * ``e`` will be a non-zero error code if the satellite position could not be computed for the given date. You can ``from sgp4.api import SGP4_ERRORS`` to access a dictionary mapping error codes to error messages explaining what each code means. * ``r`` measures the satellite position in **kilometers** from the center of the earth in the idiosyncratic True Equator Mean Equinox coordinate frame used by SGP4. * ``v`` velocity is the rate at which the position is changing, expressed in **kilometers per second**. If your application does not natively handle Julian dates, you can compute ``jd`` and ``fr`` from calendar dates using ``jday()``. >>> from sgp4.api import jday >>> jd, fr = jday(2019, 12, 9, 12, 0, 0) >>> jd 2458826.5 >>> fr 0.5 Double-checking your TLE lines ------------------------------ Because TLE is an old punch-card fixed-width format, it’s very sensitive to whether exactly the right number of spaces are positioned in exactly the right columns. If you suspect that your satellite elements aren’t getting loaded correctly, try calling the slow pure-Python version of ``twoline2rv()``, which performs extra checks that the fast C++ doesn’t: >>> from sgp4.earth_gravity import wgs72 >>> from sgp4.io import twoline2rv >>> assert twoline2rv(s, t, wgs72) Any TLE formatting errors will be raised as a ``ValueError``. Using OMM elements instead of TLE --------------------------------- The industry is migrating away from the original TLE format, because it will soon run out of satellite numbers. * Some TLE files now use a new “Alpha-5” convention that expands the range of satellite numbers by using an initial letter; for example, “E8493” means satellite 148493. This library supports the Alpha-5 convention and should return the correct integer in Python. * Some authorities are now distributing satellite elements in an “OMM” Orbit Mean Elements Message format that replaces the TLE format. You can learn about OMM in Dr. T.S. Kelso’s `“A New Way to Obtain GP Data” `_ at the CelesTrak site. You can already try out experimental support for OMM: >>> from sgp4 import omm Reading OMM data takes two steps, because OMM supports several different text formats. First, parse the input text to recover the field names and values that it stores; second, build a Python satellite object from those field values. For example, to load OMM from XML: >>> with open('sample_omm.xml') as f: ... fields = next(omm.parse_xml(f)) >>> sat = Satrec() >>> omm.initialize(sat, fields) Or, to load OMM from CSV: >>> with open('sample_omm.csv') as f: ... fields = next(omm.parse_csv(f)) >>> sat = Satrec() >>> omm.initialize(sat, fields) Either way, the satellite object should wind up properly initialized and ready to start producing positions. If you are interested in saving satellite parameters using the new OMM format, then read the section on “Export” below. Epoch ----- Over a given satellite’s lifetime, dozens or hundreds of different TLE records will be produced as its orbit evolves. Each TLE record specifies the “epoch date” for which it is most accurate. Typically a TLE is only useful for a couple of weeks to either side of its epoch date, beyond which its predictions become unreliable. Satellite objects natively provide their epoch as a two-digit year and then a fractional number of days into the year: >>> satellite.epochyr 19 >>> satellite.epochdays 343.69339541 Because Sputnik was launched in 1957, satellite element sets will never refer to an earlier year, so years 57 through 99 mean 1957–1999 while 0 through 56 mean 2000–2056. The TLE format will presumably be obsolete in 2057 and have to be upgraded to 4-digit years. To turn the number of days and its fraction into a calendar date and time, use the ``days2mdhms()`` function. >>> from sgp4.api import days2mdhms >>> month, day, hour, minute, second = days2mdhms(19, 343.69339541) >>> month 12 >>> day 9 >>> hour 16 >>> minute 38 >>> second 29.363424 The SGP4 library also translates those two numbers into a Julian date and fractional Julian date, since Julian dates are more commonly used in astronomy. >>> satellite.jdsatepoch 2458826.5 >>> satellite.jdsatepochF 0.69339541 Finally, a convenience function is available in the library if you need the epoch date and time as Python ``datetime``. >>> from sgp4.conveniences import sat_epoch_datetime >>> sat_epoch_datetime(satellite) datetime.datetime(2019, 12, 9, 16, 38, 29, 363423, tzinfo=UTC) Array Acceleration ------------------ To avoid the expense of running a Python loop when you have many dates and times for which you want a position, you can pass your Julian dates as arrays. The array routine is only faster if your machine has successfully installed or compiled the SGP4 C++ code, so you might want to check first: >>> from sgp4.api import accelerated >>> print(accelerated) True To call the array routine, make NumPy arrays for ``jd`` and ``fr`` that are the same length: >>> import numpy as np >>> np.set_printoptions(precision=2) >>> jd = np.array((2458826, 2458826, 2458826, 2458826)) >>> fr = np.array((0.0001, 0.0002, 0.0003, 0.0004)) >>> e, r, v = satellite.sgp4_array(jd, fr) >>> print(e) [0 0 0 0] >>> print(r) [[-3431.31 2620.15 -5252.97] [-3478.86 2575.14 -5243.87] [-3526.09 2529.89 -5234.28] [-3572.98 2484.41 -5224.19]] >>> print(v) [[-5.52 -5.19 1.02] [-5.49 -5.22 1.08] [-5.45 -5.25 1.14] [-5.41 -5.28 1.2 ]] To avoid the expense of Python loops when you have many satellites and dates, build a ``SatrecArray`` from several individual satellites. Its ``sgp4()`` method will expect both ``jd`` and ``fr`` to be NumPy arrays, so if you only have one date, be sure to provide NumPy arrays of length one. Here is a sample computation for 2 satellites and 4 dates: >>> u = '1 20580U 90037B 19342.88042116 .00000361 00000-0 11007-4 0 9996' >>> w = '2 20580 28.4682 146.6676 0002639 185.9222 322.7238 15.09309432427086' >>> satellite2 = Satrec.twoline2rv(u, w) >>> from sgp4.api import SatrecArray >>> a = SatrecArray([satellite, satellite2]) >>> e, r, v = a.sgp4(jd, fr) >>> np.set_printoptions(precision=2) >>> print(e) [[0 0 0 0] [0 0 0 0]] >>> print(r) [[[-3431.31 2620.15 -5252.97] [-3478.86 2575.14 -5243.87] [-3526.09 2529.89 -5234.28] [-3572.98 2484.41 -5224.19]] [[ 5781.85 2564. -2798.22] [ 5749.36 2618.59 -2814.63] [ 5716.35 2672.94 -2830.78] [ 5682.83 2727.05 -2846.68]]] >>> print(v) [[[-5.52 -5.19 1.02] [-5.49 -5.22 1.08] [-5.45 -5.25 1.14] [-5.41 -5.28 1.2 ]] [[-3.73 6.33 -1.91] [-3.79 6.3 -1.88] [-3.85 6.28 -1.85] [-3.91 6.25 -1.83]]] Export ------ If you have a ``Satrec`` you want to share with friends or persist to a file, there’s an export routine that will turn it back into a TLE: >>> from sgp4 import exporter >>> line1, line2 = exporter.export_tle(satellite) >>> line1 '1 25544U 98067A 19343.69339541 .00001764 00000-0 38792-4 0 9991' >>> line2 '2 25544 51.6439 211.2001 0007417 17.6667 85.6398 15.50103472202482' Happily, these are exactly the two TLE lines that we used to create this satellite object: >>> (s == line1) and (t == line2) True Another export routine is available that produces the fields defined by the new OMM format (see the “OMM” section above): >>> from pprint import pprint >>> fields = exporter.export_omm(satellite, 'ISS (ZARYA)') >>> pprint(fields) {'ARG_OF_PERICENTER': 17.6667, 'BSTAR': 3.8792e-05, 'CENTER_NAME': 'EARTH', 'CLASSIFICATION_TYPE': 'U', 'ECCENTRICITY': 0.0007417, 'ELEMENT_SET_NO': 999, 'EPHEMERIS_TYPE': 0, 'EPOCH': '2019-12-09T16:38:29.363423', 'INCLINATION': 51.6439, 'MEAN_ANOMALY': 85.6398, 'MEAN_ELEMENT_THEORY': 'SGP4', 'MEAN_MOTION': 15.501034720000002, 'MEAN_MOTION_DDOT': 0.0, 'MEAN_MOTION_DOT': 1.764e-05, 'NORAD_CAT_ID': 25544, 'OBJECT_ID': '1998-067A', 'OBJECT_NAME': 'ISS (ZARYA)', 'RA_OF_ASC_NODE': 211.2001, 'REF_FRAME': 'TEME', 'REV_AT_EPOCH': 20248, 'TIME_SYSTEM': 'UTC'} Gravity ------- The SGP4 algorithm operates atop a set of constants specifying how strong the Earth’s gravity is. The most recent official paper on SGP4 (see below) specifies that “We use WGS-72 as the default value”, so this Python module uses the same default. But in case you want to use either the old legacy version of the WGS-72 constants, or else the non-standard but more modern WGS-84 constants, the ``twoline2rv()`` constructor takes an optional argument: >>> from sgp4.api import WGS72OLD, WGS72, WGS84 >>> satellite3 = Satrec.twoline2rv(s, t, WGS84) You will in general get less accurate results if you choose WGS-84. Even though it reflects more recent and accurate measures of the Earth, satellite TLEs across the industry are most likely generated with WGS-72 as their basis. The positions you generate will better agree with the real positions of each satellite if you use the same underlying gravity constants as were used to generate the TLE. Providing your own elements --------------------------- If instead of parsing a TLE you want to specify orbital elements directly, you can pass them as floating point numbers to a satellite object’s ``sgp4init()`` method. For example, here’s how to build the same International Space Station orbit that we loaded from a TLE in the first code example above: >>> satellite2 = Satrec() >>> satellite2.sgp4init( ... WGS72, # gravity model ... 'i', # 'a' = old AFSPC mode, 'i' = improved mode ... 25544, # satnum: Satellite number ... 25545.69339541, # epoch: days since 1949 December 31 00:00 UT ... 3.8792e-05, # bstar: drag coefficient (1/earth radii) ... 0.0, # ndot: ballistic coefficient (radians/minute^2) ... 0.0, # nddot: mean motion 2nd derivative (radians/minute^3) ... 0.0007417, # ecco: eccentricity ... 0.3083420829620822, # argpo: argument of perigee (radians) ... 0.9013560935706996, # inclo: inclination (radians) ... 1.4946964807494398, # mo: mean anomaly (radians) ... 0.06763602333248933, # no_kozai: mean motion (radians/minute) ... 3.686137125541276, # nodeo: R.A. of ascending node (radians) ... ) These numbers don’t look the same as the numbers in the TLE, because the underlying ``sgp4init()`` routine uses different units: radians rather than degrees. But this is the same orbit and will produce the same positions. Note that ``ndot`` and ``nddot`` are ignored by the SGP4 propagator, so you can leave them ``0.0`` without any effect on the resulting satellite positions. But they do at least get saved to the satellite object, and written out if you write the parameters to a TLE or OMM file (see the “Export” section, above). To compute the “epoch” argument, take the epoch’s Julian date and subtract 2433281.5 days. While the underlying ``sgp4init()`` routine leaves the attributes ``epochyr``, ``epochdays``, ``jdsatepoch``, and ``jdsatepochF`` unset, this library goes ahead and sets them anyway for you, using the epoch you provided. See the next section for the complete list of attributes that are available from the satellite record once it has been initialized. Attributes ---------- There are several dozen ``Satrec`` attributes that expose data from the underlying C++ SGP4 record. They fall into the following categories. *Identification* These are copied directly from the TLE record but aren’t used by the propagation math. | ``satnum_str`` — Satellite number, as a 5-character string. | ``satnum`` — Satellite number, converted to an integer. | ``classification`` — ``'U'``, ``'C'``, or ``'S'`` indicating the element set is Unclassified, Classified, or Secret. | ``ephtype`` — Integer “ephemeris type”, used internally by space agencies to mark element sets that are not ready for publication; this field should always be ``0`` in published TLEs. | ``elnum`` — Element set number. | ``revnum`` — Satellite’s revolution number at the moment of the epoch, presumably counting from 1 following launch. *Orbital Elements* These are the orbital parameters, copied verbatim from the text of the TLE record. They describe the orbit at the moment of the TLE’s epoch and so remain constant even as the satellite record is used over and over again to propagate positions for different times. | ``epochyr`` — Epoch date: the last two digits of the year. | ``epochdays`` — Epoch date: the number of days into the year, including a decimal fraction for the UTC time of day. | ``ndot`` — First time derivative of the mean motion (loaded from the TLE, but otherwise ignored). | ``nddot`` — Second time derivative of the mean motion (loaded from the TLE, but otherwise ignored). | ``bstar`` — Ballistic drag coefficient B* (1/earth radii). | ``inclo`` — Inclination (radians). | ``nodeo`` — Right ascension of ascending node (radians). | ``ecco`` — Eccentricity. | ``argpo`` — Argument of perigee (radians). | ``mo`` — Mean anomaly (radians). | ``no_kozai`` — Mean motion (radians/minute). | ``no`` — Alias for ``no_kozai``, for compatibility with old code. You can also access the epoch as a Julian date: | ``jdsatepoch`` — Whole part of the epoch’s Julian date. | ``jdsatepochF`` — Fractional part of the epoch’s Julian date. *Computed Orbit Properties* These are computed when the satellite is first loaded, as a convenience for callers who might be interested in them. They aren’t used by the SGP4 propagator itself. | ``a`` — Semi-major axis (earth radii). | ``altp`` — Altitude of the satellite at perigee (earth radii, assuming a spherical Earth). | ``alta`` — Altitude of the satellite at apogee (earth radii, assuming a spherical Earth). | ``argpdot`` — Rate at which the argument of perigee is changing (radians/minute). | ``gsto`` — Greenwich Sidereal Time at the satellite’s epoch (radians). | ``mdot`` — Rate at which the mean anomaly is changing (radians/minute) | ``nodedot`` — Rate at which the right ascension of the ascending node is changing (radians/minute). *Propagator Mode* | ``operationmode`` — A single character that directs SGP4 to either operate in its modern ``'i'`` improved mode or in its legacy ``'a'`` AFSPC mode. | ``method`` — A single character, chosen automatically when the orbital elements were loaded, that indicates whether SGP4 has chosen to use its built-in ``'n'`` Near Earth or ``'d'`` Deep Space mode for this satellite. *Result of Most Recent Propagation* | ``t`` — The time you gave when you most recently asked SGP4 to compute this satellite’s position, measured in minutes before (negative) or after (positive) the satellite’s epoch. | ``error`` — Error code produced by the most recent SGP4 propagation you performed with this element set. The possible ``error`` codes are: 0. No error. 1. Mean eccentricity is outside the range 0 ≤ e < 1. 2. Mean motion has fallen below zero. 3. Perturbed eccentricity is outside the range 0 ≤ e ≤ 1. 4. Length of the orbit’s semi-latus rectum has fallen below zero. 5. (No longer used.) 6. Orbit has decayed: the computed position is underground. (The position is still returned, in case the vector is helpful to software that might be searching for the moment of re-entry.) *Mean Elements From Most Recent Propagation* Partway through each propagation, the SGP4 routine saves a set of “singly averaged mean elements” that describe the orbit’s shape at the moment for which a position is being computed. They are averaged with respect to the mean anomaly and include the effects of secular gravity, atmospheric drag, and — in Deep Space mode — of those pertubations from the Sun and Moon that SGP4 averages over an entire revolution of each of those bodies. They omit both the shorter-term and longer-term periodic pertubations from the Sun and Moon that SGP4 applies right before computing each position. | ``am`` — Average semi-major axis (earth radii). | ``em`` — Average eccentricity. | ``im`` — Average inclination (radians). | ``Om`` — Average right ascension of ascending node (radians). | ``om`` — Average argument of perigee (radians). | ``mm`` — Average mean anomaly (radians). | ``nm`` — Average mean motion (radians/minute). *Gravity Model Parameters* When the satellite record is initialized, your choice of gravity model results in a slate of eight constants being copied in: | ``tumin`` — Minutes in one “time unit”. | ``xke`` — The reciprocal of ``tumin``. | ``mu`` — Earth’s gravitational parameter (km³/s²). | ``radiusearthkm`` — Radius of the earth (km). | ``j2``, ``j3``, ``j4`` — Un-normalized zonal harmonic values J₂, J₃, and J₄. | ``j3oj2`` — The ratio J₃/J₂. Printing satellite attributes ----------------------------- If you want to print out a satellite, this library provides a convenient “attribute dump” routine that takes a satellite and generates lines that list its attributes:: from sys import stdout from sgp4.conveniences import dump_satrec stdout.writelines(dump_satrec(satellite)) If you want to compare two satellites, then simply pass a second argument; the second satellite’s attributes will be printed in a second column next to those of the first. :: stdout.writelines(dump_satrec(satellite, satellite2)) Validation against the official algorithm ----------------------------------------- This implementation passes all of the automated tests in the August 2010 release of the reference implementation of SGP4 by Vallado et al., who originally published their revision of SGP4 in 2006: Vallado, David A., Paul Crawford, Richard Hujsak, and T.S. Kelso, “Revisiting Spacetrack Report #3,” presented at the AIAA/AAS Astrodynamics Specialist Conference, Keystone, CO, 2006 August 21–24. If you would like to review the paper, it is `available online `_. You can always download the latest version of their code for comparison against this Python module (or other implementations) at `AIAA-2006-6753.zip `_. For developers -------------- Developers can check out this full project from GitHub: https://github.com/brandon-rhodes/python-sgp4 To run its unit tests, install Python 2, Python 3, and the ``tox`` testing tool. The tests runing in Python 2 will exercise the fallback pure-Python version of the routines, while Python 3 exercises the fast new C++ accelerated code:: cd python-sgp4 tox Legacy API ---------- Before this library pivoted to wrapping Vallado's official C++ code and was operating in pure Python only, it had a slightly quirkier API, which is still supported for compatibility with older clients. You can learn about it by reading the documentation from version 1.4 or earlier: https://pypi.org/project/sgp4/1.4/ Changelog --------- 2023-04-27 — 2.22 * Added a ``satnum_str`` attribute, exposing the fact that the C++ now stores the satellite number as a string; and check that ``satnum`` is never greater than 339999. * Fixed the units of the ``nddot`` attribute when the value is loaded from an OMM record. (Since the TLE computation itself ignores this attribute, this did not affect any satellite positions.) * Enhanced the fallback Python version of ``twoline2rv()`` to verify that TLE lines are ASCII, and added documentation using it to double-check TLEs that might suffer from non-ASCII characters. * If the user doesn’t set a satellite’s ``classification``, it now defaults to ``'U'`` for ‘unclassified’. 2022-04-06 — 2.21 * Added ``dump_satrec()`` to the ``sgp4.conveniences`` module. * Fixed the ``Satrec`` attribute ``.error``, which was previously building a nonsense integer from the wrong data in memory. * Removed ``.whichconst`` from Python ``Satrec``, to help users avoid writing code that will break when the C++ extension is available. 2021-07-01 — 2.20 * Taught ``sgp4init()`` to round both ``epochdays`` and ``jdsatepochF`` to the same 8 decimal places used for the date fraction in a TLE, if the user-supplied ``epoch`` itself has 8 or fewer digits behind the decimal point. This should make it easier to build satellites that round-trip to TLE format with perfect accuracy. * Fixed how ``export_tle()`` formats the BSTAR field when its value, if written in scientific notation, has a positive exponent. * Fixed the ``epochyr`` assigned by ``sgp4init()`` so years before 2000 have two digits instead of three (for example, so that 1980 produces an ``epochyr`` of 80 instead of 980). 2021-04-22 — 2.19 * Extended the documentation on the Python Package Index and in the module docstring so it lists every ``Satrec`` attribute that this library exposes; even the more obscure ones might be useful to folks working to analyze satellite orbits. 2021-03-08 — 2.18 * If a TLE satellite number lacks the required 5 digits, ``twoline2rv()`` now gives the underlying C++ library a little help so it can still parse the classification and international designator correctly. * The ``Satrec`` attributes ``jdsatepoch``, ``jdsatepochF``, ``epochyr``, and ``epochdays`` are now writeable, so users can adjust their values manually — which should make up for the fact that the ``sgp4init()`` method can’t set them with full floating point precision. | 2021-02-17 — 2.17 — Fixed where in the output array the ``sgp4_array()`` method writes NaN values when an SGP4 propagation fails. | 2021-02-12 — 2.16 — Fixed ``days2mdhms()`` rounding to always match TLE epoch. | 2021-01-08 — 2.15 — Fixed parsing of the ``satnum`` TLE field in the Python fallback code, when the field has a leading space; added OMM export routine. | 2020-12-16 — 2.14 — New data formats: added OMM message support for both XML and CSV, and added support for the new Alpha-5 extension to TLE files. | 2020-10-14 — 2.13 — Enhanced ``sgp4init()`` with custom code that also sets the ``epochdays`` and ``epochyr`` satellite attributes. | 2020-05-28 — 2.12 — Moved the decision of whether to set the locale during ``twoline2rv()`` from import time to runtime, for users who change locales after their application is up and running. | 2020-05-24 — 2.11 — Fixed a regression in how dates are split into hours, minutes, and seconds that would sometimes produce a time whose second=60, crashing the pure-Python version of the library. | 2020-05-22 — 2.10 — Switch the locale temporarily to ``C`` during the C++ accelerated ``twoline2rv()``, since it does not protect its ``sscanf()`` calls from locales that, like German, expect comma decimal points instead of the period decimal points always used in a TLE. | 2020-05-21 — 2.9 — Added ``sat_epoch_datetime()``, expanded documentation around converting a satellite epoch to a date and time, and started rounding the epoch to exactly the digits provided in the TLE; and removed the ``Satrec.epoch`` attribute from Python fallback code to better match the C++ version. | 2020-05-07 — 2.8 — New function ``jday_datetime()`` is now available in the ``sgp4.conveniences`` module, thanks to Egemen Imre. | 2020-04-24 — 2.7 — New method ``sgp4init()`` (thank you, Chris Lewicki!) is available. | 2020-04-20 — 2.6 — New routine ``export_tle()`` (thank you, Egemen Imre!) is available. Improved how the accelerated C++ backend parses the ``intldesg`` string and the ``revnum`` integer. | 2020-03-22 — 2.5 — Gave the new accelerated ``twoline2rv()`` an optional argument that lets the user choose a non-standard set of gravity constants. | 2020-02-25 — 2.4 — Improved the ``jday()`` docstring; made the old legacy Python resilient if the day of the month is out-of-range (past the end of the month) in a TLE; and Mark Rutten fixed the C++ so it compiles on Windows! | 2020-02-04 — 2.3 — Removed experimental code that caused performance problems for users with Numba installed. | 2020-02-02 — 2.2 — A second release on Palindrome Day: fix the Satrec ``.epochyr`` attribute so it behaves the same way in Python as it does in the official C library, where it is only the last 2 digits of the year; and make ``.no`` available in the Python fallback case as well. | 2020-02-02 — 2.1 — Add vectorized array method to Satrec object; add ``.no`` attribute to new Satrec object to support old code that has not migrated to the new name ``.no_kozai``; gave Python wrapper classes ``__slots__`` to avoid the expense of a per-object attribute dictionary. | 2020-01-30 — 2.0 — Rewrite API to use genuine Vallado C++ code on those systems where it can be compiled; add accelerated vectorized array interface; make ``gstime()`` a public function; clarify format error message. | 2015-01-15 — 1.4 — Display detailed help when TLE input does not match format. | 2014-06-26 — 1.3 — Return ``(NaN,NaN,NaN)`` vectors on error and set ``.error_message`` | 2013-11-29 — 1.2 — Made ``epochyr`` 4 digits; add ``datetime`` for ``.epoch`` | 2012-11-22 — 1.1 — Python 3 compatibility; more documentation | 2012-08-27 — 1.0 — Initial release ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599655.0 sgp4-2.22/sgp4.egg-info/SOURCES.txt0000644000175100001730000000101014422467347016155 0ustar00runnerdockerLICENSE MANIFEST.in README.md setup.py extension/SGP4.cpp extension/SGP4.h extension/wrapper.cpp sgp4/SGP4-VER.TLE sgp4/__init__.py sgp4/alpha5.py sgp4/api.py sgp4/conveniences.py sgp4/earth_gravity.py sgp4/exporter.py sgp4/ext.py sgp4/functions.py sgp4/io.py sgp4/model.py sgp4/omm.py sgp4/propagation.py sgp4/sample_omm.csv sgp4/sample_omm.xml sgp4/tcppver.out sgp4/tests.py sgp4/wrapper.py sgp4/wulfgar.py sgp4.egg-info/PKG-INFO sgp4.egg-info/SOURCES.txt sgp4.egg-info/dependency_links.txt sgp4.egg-info/top_level.txt././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599655.0 sgp4-2.22/sgp4.egg-info/dependency_links.txt0000644000175100001730000000000114422467347020347 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682599655.0 sgp4-2.22/sgp4.egg-info/top_level.txt0000644000175100001730000000000514422467347017026 0ustar00runnerdockersgp4