Skip to content

Vallado et al. Rev 3 (2006/2013): Final SGP4 Modernization

Rev 3 is the authoritative modern SGP4 reference. Every actively maintained implementation — satellite.js, python-sgp4, Skyfield, and pg_orrery — derives from or validates against the C++ source in this revision.

The revision chain:

2006 AIAA 2006-6753 Original conference paper
|
2008 Rev 1 First revision (our primary archive transcription)
|
~ Rev 2 Intermediate revision (undated)
|
2011 Rev 3 Final public revision. Code stamped 2011-12-30.

Where the original 2006 paper cataloged 25 years of SGP4 divergence and Rev 1 provided the corrected algorithms and 518 test vectors, Rev 3 addresses the questions Rev 1 left open: which mode is “official”? What happens when propagation fails? How fast can this run at catalog scale?

This page focuses on what changed. The theory, bug history, TEME definition, and test case design documented in Rev 1 are not repeated here.

The single most important addition in Rev 3 is the operationmode parameter, threaded through the entire call chain from sgp4init() down to dpper():

ModeCharacterGHA CalculationIntrinsic Function Handling
AFSPC'a'Jan 0, 1970 epoch formula (THGR70, C1, FK5R)Original FORTRAN MOD/ATAN semantics
Improved'i'Julian-century GMST1982 (Eq. 2 in paper)Modern fmod/atan2 semantics

GHA (Greenwich Hour Angle) calculation. In AFSPC mode, initl() computes the Greenwich sidereal time at epoch using the older 1970-epoch formula with combined constants. In improved mode, it uses the GMST1982 equation:

θGMST=67310.54841+(876600×3600+8640184.812866)TUT1+0.093104TUT126.2×106TUT13[seconds]\theta_{GMST} = 67\,310.548\,41 + (876\,600 \times 3600 + 8\,640\,184.812\,866)\,T_{UT1} + 0.093\,104\,T_{UT1}^2 - 6.2 \times 10^{-6}\,T_{UT1}^3 \quad \text{[seconds]}

The difference is on the order of arcseconds — small, but enough to cause disagreement in verification against AFSPC-generated test vectors.

Intrinsic function handling. In dpper(), when nodep (the perturbed node) goes negative, AFSPC mode adds 2π2\pi to match the behavior of FORTRAN’s MOD function. Improved mode relies on C/C++ fmod and atan2 to handle the quadrant correctly. The difference matters for deep-space objects where lunar-solar perturbations push orbital elements through zero crossings.

Rev 3’s source code changelog documents seven categories of changes accumulated between August 2006 and December 2011:

DateChangeImpact
Nov 2008Early return false on error codesPrevents silent garbage output after errors 1-4 and 6
Sep 2008DSPACE atime optimizationFaster deep-space propagation for epochs far from propagation time
Sep 2008operationmode parameter addedDual AFSPC/improved behavior (see above)
Jun 2008Small eccentricity threshold updatecc3 only computed when e>104e > 10^{-4}, prevents division issues
Aug 2010pow() replaced with direct multipliesx*x and x*x*x instead of pow(x, 2.0) and pow(x, 3.0)
Aug 2010Unused variable cleanup in initl()Eliminates compiler warnings
Rev 3Sub-orbital initialization check removedTLEs with perigee below Earth’s surface no longer rejected at init

Rev 1’s sgp4() function set error codes but continued processing, meaning the caller received a position/velocity vector that could be numerical noise. Rev 3 adds explicit return false; after each error condition:

  • Error 1: e1.0e \geq 1.0 or e < -0.001
  • Error 2: mean motion n0.0n \leq 0.0
  • Error 3: perturbed eccentricity outside [0,1][0, 1]
  • Error 4: semi-latus rectum p < 0
  • Error 6: distance from Earth center m_{rt} < 1.0 (satellite has decayed)

Rev 1 set error 5 and returned early when the initial perigee radius was below 1.0 Earth radii (r_p < 1.0). Rev 3 removes this check entirely. The rationale: a satellite whose TLE-epoch perigee is below the surface may still be above the surface at the requested propagation time. The runtime check (m_{rt} < 1.0 in sgp4()) catches actual decay. This matters for decaying satellites near end-of-life, when tracking accuracy is most critical.

Replacing pow(x, 2.0) with x*x throughout the propagator is not cosmetic. The general pow() function computes enlnxe^{n \ln x} — a transcendental function evaluation for what amounts to a single multiply. For catalog-scale batch processing (the whats_up query pattern), this accumulates to a measurable speedup across thousands of TLEs per call.

Appendix C is restructured to lead with the operational conversion path (TEME to Earth-fixed via GMST) rather than the academic path (TEME to J2000). The worked example is updated to use 6 April 2004 as the reference date with specific UT1-UTC, polar motion, and EOP values.

The transformation matrices (Eqs. C-1 through C-4) and the 23.6-meter “of date” vs. “of epoch” demonstration using the Vanguard 1 TLE are numerically identical to Rev 1.

A terminology update throughout: “CMOC” (Cheyenne Mountain Operations Center) becomes “JSPOC” (Joint Space Operations Center), reflecting the 2005 organizational name change. A new footnote references Koskela (1967) for the historical basis of the 4-term nutation approximation that defines the TEME frame.

The test suite retains the same 29 satellites as Rev 1. Two additions appear in the Rev 3 table descriptions:

SatelliteCategoryPurpose
09998SynchronousHigh-eccentricity GEO (e=0.027e = 0.027), exercises secular integrator
28129Deep SpaceGPS satellite, 12-hour non-resonant (e < 0.5)

The appendix header notes that satellite 23599 results differ from Rev 1 “as a result of the consistency with AFSPC option.” All Rev 3 test vectors are explicitly generated with 'a', '72' (AFSPC mode, WGS-72 constants), eliminating the mode ambiguity present in Rev 1.