Giter VIP home page Giter VIP logo

python-sgp4's Introduction

python-sgp4's People

Contributors

asellappen avatar asfaltboy avatar astrojuanlu avatar brandon-rhodes avatar ckuethe avatar egemenimre avatar gavinhofer avatar glangford avatar interplanetarychris avatar mgrutten avatar mworion avatar pfandzelter avatar rzimmerman avatar signaleleven avatar zouhairm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-sgp4's Issues

sgp4.wrapper.Satrec objects can't be pickled

...but sgp4.model.Satrec objects can:

In [1]: from sgp4.api import Satrec

In [2]: Satrec
Out[2]: sgp4.wrapper.Satrec

In [3]: line1, line2 = (
   ...:   "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",
   ...: )
   ...: sat = Satrec.twoline2rv(line1, line2)
   ...: 

In [4]: sat
Out[4]: <sgp4.wrapper.Satrec at 0x5649605d0430>

In [5]: import pickle

In [6]: with open("/tmp/save.pkl", "wb") as fp:
   ...:     pickle.dump(sat, fp)
   ...: 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-f3c37eb8fd19> in <module>
      1 with open("/tmp/save.pkl", "wb") as fp:
----> 2     pickle.dump(sat, fp)
      3 

TypeError: cannot pickle 'Satrec' object

In [7]: from sgp4.model import Satrec

In [8]: sat = Satrec.twoline2rv(line1, line2)

In [9]: with open("/tmp/save.pkl", "wb") as fp:
   ...:     pickle.dump(sat, fp)

Coordinate mismatch between PyEphem/SSCWeb and this library

# TLE for ISS
t1 = '1 25544U 98067A   12035.27140256  .00008132  00000-0  10934-3 0  9453'
t2 = '2 25544 051.6417 073.7902 0020652 004.6179 085.0245 15.58669131757138'
tle = twoline2rv(t1, t2, wgs72)
position, _ = tle.propagate(2012,2,4,7,55,00)
print position
# (-2395.0416350887344, 4440.7514261050846, 4492.3844513630256)

When I use http://sscweb.gsfc.nasa.gov/ I get the following coordinates:
-2377.74 4447.21 4495.19

These agree with the ones I get when using PyEphem for the same data.

Any ideas?

numba acceleration not working?

I am giving the master branch a try to see if my usage of sgp4 could be sped up. I am getting a "numba lowering error" (traceback below).

I suspect this is actually a numba bug rather than a problem with sgp4, but I haven't spent enough time with numba to know for sure. Have you been able to successfully use numba with sgp4? Have you considered using cython instead?

Failed at object (object mode frontend)
Caused By:
Traceback (most recent call last):
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/compiler.py", line 238, in run
    stage()
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/compiler.py", line 599, in stage_objectmode_backend
    self._backend(lowerfn, objectmode=True)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/compiler.py", line 576, in _backend
    lowered = lowerfn()
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/compiler.py", line 550, in backend_object_mode
    self.flags)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/compiler.py", line 882, in py_lowering_stage
    lower.lower()
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/lowering.py", line 135, in lower
    self.lower_normal_function(self.fndesc)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/lowering.py", line 176, in lower_normal_function
    entry_block_tail = self.lower_function_body()
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/lowering.py", line 201, in lower_function_body
    self.lower_block(block)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/lowering.py", line 216, in lower_block
    self.lower_inst(inst)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/contextlib.py", line 35, in __exit__
    self.gen.throw(type, value, traceback)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/errors.py", line 249, in new_error_context
    six.reraise(type(newerr), newerr, sys.exc_info()[2])
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/errors.py", line 243, in new_error_context
    yield
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/lowering.py", line 216, in lower_block
    self.lower_inst(inst)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/objmode.py", line 131, in lower_inst
    self.delvar(inst.value)
  File "/home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/numba/objmode.py", line 534, in delvar
    self._live_vars.remove(name)
LoweringError: 'sineo1'
File "../../scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/sgp4/propagation.py", line 1742
[1] During: lowering "del sineo1" at /home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/sgp4/propagation.py (1742)

Failed at object (object mode backend)
'sineo1'
File "../../scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/sgp4/propagation.py", line 1742
[1] During: lowering "del sineo1" at /home/broot/scratch/miniconda/envs/floodmappy4/lib/python2.7/site-packages/sgp4/propagation.py (1742)

Units of Bstar coefficient

Hello,
I have a doubt about your documentation concerning the Bstar term. Your comments say that it is in units kg / (m2 ER). But the TLE documentation says it is in ER^-1 units.
The definition of Bstar is Bstar = rho_0 * CD * A / (2 * m), if I am not wrong

I went to the function twoline2rv() and it seems that there is no conversion made. I hope you can enlighten me

Thank you

Am I using the wrong function to project satellites?

Hello,
Pardon my lack of proper terminology as I'm more of an artist than a satellite guru. As a result, I'll visualize as much as I can below.

sos

I'm having some starting success plotting 15,147 orbiting objects around Earth, projected for a volunteer Science On a Sphere project at the museum setting at my office.

preview1

Cool!

The next challenge: Working on some alignment, comparing with ISS tle data, the orbit seems too "circular"/"ring-like", overlapping the same orbit over and over like this:

preview2-orbit-issue

Here's what it looks like when I skip the re-projections and show in 3D space based on the values sgp4 is producing (a nice ring):

screen shot 2015-01-12 at 9 44 13 am

I'm used to seeing it look something like this (from a JavaScript project using this library):

screen shot 2015-01-12 at 9 35 30 am

Is it possible that I'm using the wrong values or functions to project this?

Here's a simplified version of the script with how I'm producing the position values:

from sgp4.earth_gravity import wgs72
from sgp4.io import twoline2rv
import datetime

def sat_pos_vel(sat, y, m, d, h, i, s):
    position, velocity = sat.propagate(y, m, d, h, i, s)
    return {"p":position, "v":velocity}

line1 = "1 25544U 98067A   15011.54761787  .00015493  00000-0  24903-3 0  7129"
line2 = "2 25544 051.6471 145.9316 0006026 238.8534 213.9008 15.53184119923669"
sat = twoline2rv(line1, line2, wgs72)

when = datetime.datetime.now()

for i in range(300):
    sat_prop = sat_pos_vel(sat, when.year, when.month, when.day, when.hour, when.minute, when.second)
    when = when + datetime.timedelta(0,100) #add 100 seconds

    print(sat_prop)

I'm using Python 3.4

Let me know if I can provide additional information.

Thanks for taking a look in advance! I truly appreciate it.

Out of range produce invalid TLEs

The TLE FAQ specifies that:

Fields 2.3, 2.4, 2.6, and 2.7 all have units of degrees and can range from 0 up to 360 degrees—field 2.3 (inclination) only goes up to 180 degrees.

However, if one creates a Satrec object with, say, argpo=-1.90861:

  • sgp4init does not complain
  • rv2twoline produces an invalid TLE!

For example:

1 99510U 20999B   20311.53996093  .00007856  00000-0  10000-4 0  9995  
2 99510  97.2675  23.7519 0007535 -109.3554278.9614 15.31068184    67 

Should python-sgp4 perform any sort of validation?

Question about python3.9 support in wheels.

@brandon-rhodes,

as I heavily rely on skyfield and the linked sgp4 package and I would like to move the on top build applications to support python3.9. Is there any planning, when the sgp4 distro also brings the precompiled packages with it?

many thanks for this great packages.
Michel

io.py: IndexError: list index out of range processing Vanguard 1 example

In a3c8da1, executing the Vanguard 1 example in __init__.py:

>>> from sgp4.earth_gravity import wgs72
>>> from sgp4.io import twoline2rv
>>>
>>> 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')
>>>
>>> satellite = twoline2rv(line1, line2, wgs72)
IndexError                                Traceback (most recent call last)
<ipython-input-12-8ec3d1719ba6> in <module>()
----> 1 satellite = twoline2rv(line1, line2, wgs72)

/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sgp4/io.pyc in twoline2rv(longstr1, longstr2, whichconst, afspc_mode)
    150        if longstr1[62] == ' ':
    151            longstr1[62] = '0';
--> 152        if longstr1[68] == ' ':
    153            longstr1[68] = '0';
    154

IndexError: list index out of range

Works in v1.3 (4266bfc ), but haven't bisected to find culprit.

2.0 jday returns incorrect result

The following function returns a fractional number (apparently ending in 0.5) for jd, which probably means that the fr is wrong too.

jd = (367.0 * year
- 7 * (year + ((mon + 9) // 12.0)) * 0.25 // 1.0
+ 275 * mon / 9.0 // 1.0
+ day
+ 1721013.5)

Have a fix (based on ext.jday) in an incoming PR.

sgp4() should take tsince() as an argument

In the 2.0 extension, sgp4 has been modified (perhaps too conveniently) to take arguments of a different from from the previous python version, and the SGP4.CPP function itself.

double tsince = (jd - satrec.jdsatepoch) * 1440.0
+ (fr - satrec.jdsatepochF) * 1440.0;

This could be preserved as an "sgp4_jd()" convenience function.

I have an incoming PR which reverts this.

Additionally, the proliferation of the jd, fr separation for julian dates perhaps creates more problems than it solves. Opening a separate Issue to discuss that.

Insensitivity to Inclination, RAAN

TLEs that only differ in inclination or RAAN of very small angles (~0.001 degrees or less) when propagated using SGP4 seem to yield identical positions. Inclination or RAAN has to be adjusted to greater degree to yield a change. Seems like there's some loss of precision somewhere...

Will add example code to recreate error tomorrow.

test suite does not work properly when unittest is loaded instead of unittest2

Hi, I'm getting this output when executing sgp4/tests.py without unittest2 installed,

❯ python tests.py
EE...E..
======================================================================
ERROR: test_bad_first_line (__main__.Tests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests.py", line 135, in test_bad_first_line
    with self.assertRaisesRegex(ValueError, re.escape("""TLE format error
AttributeError: 'Tests' object has no attribute 'assertRaisesRegex'

======================================================================
ERROR: test_bad_second_line (__main__.Tests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests.py", line 147, in test_bad_second_line
    with self.assertRaisesRegex(ValueError, re.escape("""TLE format error
AttributeError: 'Tests' object has no attribute 'assertRaisesRegex'

======================================================================
ERROR: test_mismatched_lines (__main__.Tests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests.py", line 160, in test_mismatched_lines
    with self.assertRaisesRegex(ValueError, re.escape(msg)):
AttributeError: 'Tests' object has no attribute 'assertRaisesRegex'

----------------------------------------------------------------------
Ran 8 tests in 0.036s

FAILED (errors=3)

However, everything is fine when test suite loads unittest2 package,

❯ python tests.py
........
----------------------------------------------------------------------
Ran 8 tests in 0.039s

OK

THX

Return state for decayed satellites?

In your implementation of sgp4, in propagation.py, you have the following "fix":

 #  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 false, false;

Returning (false,false) discards the calculated values, a behavior I find to be rather unhelpful - although the state is invalid, it is still useful, e.g. for solving for impact time and location via Newton's method. Could you return the calculated values instead? You are already indicating the error condition via error and error_message.

epochyr isn't 4-digit

The docs say epochyr: Full four-digit year of this element set's epoch moment. but in fact it just uses the TLE number, which is 2 digits, for example instead of 2007, epochyr is just 7.

Apart from that, it would be nice to get the epoch date as a simple datetime object.

Cannot Generate Valid TLE from sgp4init

I was trying to use sgp4 to construct tles from orbital parameters using latest version (2.12)

I am getting invalid tles back, however. This seems to be because export_tle expects epochyr and epochdays to be set, but they don't seem to be set by sgp4init.

Maybe this is user error, but I couldn't quite figure it out.

Here's the test I constructed (using the sgp4init example from the documentation):

from sgp4.api import WGS72, Satrec
from sgp4.exporter import export_tle

satrec = Satrec()

satrec.sgp4init(
    WGS72,           # gravity model
    'i',             # 'a' = old AFSPC mode, 'i' = improved mode
    5,               # satnum: Satellite number
    18441.785,       # epoch: days since 1949 December 31 00:00 UT
    2.8098e-05,      # bstar: drag coefficient (/earth radii)
    6.969196665e-13, # ndot: ballistic coefficient (revs/day)
    0.0,             # nddot: second derivative of mean motion (revs/day^3)
    0.1859667,       # ecco: eccentricity
    5.7904160274885, # argpo: argument of perigee (radians)
    0.5980929187319, # inclo: inclination (radians)
    0.3373093125574, # mo: mean anomaly (radians)
    0.0472294454407, # no_kozai: mean motion (radians/minute)
    6.0863854713832, # nodeo: right ascension of ascending node (radians)
)

tle = export_tle(satrec)

assert tle[0][18:32] != '00000.00000000'

No "ToGeodetic" Method Available (for calculating latitude/longitude from ephemeris)?

The sgp4 C++ reference library has a very useful Eci::ToGeodetic() method (see https://github.com/dnwrnr/sgp4/blob/0cc181ee50c707d1a433e97be98de2b925dd78a4/libsgp4/Eci.cpp).

This is very useful for converting a propagated ephemeris into latitude/longitude values. As far as I can see, this functionality does not exist in this python version. Is there any plan to, or was there a specific reason why this was not incorporated?

The Javascript version also has this functionality (https://github.com/shashwatak/satellite-js).

TEME to ECEF conversion

Hello,

I am developing an orbit propagator for a thesis and i am trying to check the result i am getting with STK propagator.

I am finding that the results not match, and i have seen that SGP4.propagate returns the position and velocity vectors in TEME reference system. I am trying to get it in the ECEF reference system but i am quite new at this, and i am not getting it.

Is there any way to perform that conversion directly through sgp4 or some other library ?

Any help is more than welcome.

Thank you so much in advance.

Conda package?

Hi,

Not sure where else to ask about this, but here goes. I see that this package is listed on PyPI, but it would be useful for me to have it accessible with Conda (i.e. conda install sgp4) -- specifically, for my Julia wrapper of this package. Apparently there is a way to do this, but it requires that someone hosts the Conda package once it's created.

I am happy to try and figure this out and host it, but it's not clear to me that you (as the original author) or this Github repository is clearly indicated once it's hosted on the "Anaconda cloud" (formerly binstar, I think?). So, I figured I'd give you the chance to do it yourself, if you'd like. Thanks, either way.

Chris

Semi-major axis

How can I get a semi-major axis of the satellite? I have found a wrapper method called "initl" on "propagation.py", but did not understand how to use it in order to get the ao. Could you, please, give an example?

Improper initialization of averaged mean element variables

I believe the following is a bug in the Vallado source code, when initializing Satrec() variables in sgp4init():

python-sgp4/extension/SGP4.cpp

Lines 1449 to 1450 in 2a365a3

// single averaged mean elements
satrec.am = satrec.em = satrec.im = satrec.Om = satrec.mm = satrec.nm = 0.0;

These variables aren't used elsewhere within the code, so the fact that they all take the last-set value as follows doesn't cause any internal problems:

satrec.nm = nm;

However, anyone accessing them externally (for example, to reset the epoch of the osculating elements) will find that they all equal satrec.nm

Difference between SGP4 1.4 and Pyhem

Hello,

I started to play with tracking the ISS space station.
Have approached it with Pyhem and SGP4 1.4.
When I do the calculation I get a different answer for the longitude.
I have checked the results with a tracker found on the internet, and the value of the calculation with Pyephem are the same!

I use the ECEF routine to convert the (x,y,z) to lat,lon and alt.

Thanks for any support,or help.

Jan Kromhout
Hellevoetsluis-NL

import urllib.request
from sgp4.earth_gravity import wgs84
from sgp4.io import twoline2rv
from datetime import datetime
from math import sqrt, atan2, sin, cos, pi
import ephem

def ecef(x, y, z): #Convert (x,y,z) to (lat,lon,alt)
a = 6378137
e = 8.1819190842622e-2
b = sqrt(a ** 2 * (1 - e ** 2))
ep = sqrt((a ** 2 - b ** 2) / (b ** 2))
p = sqrt(x ** 2 + y ** 2)
th = atan2(a * z, b * p)
lon = atan2(y,x)
lat = atan2((z + ep ** 2 * b * sin(th) ** 3), (p - e ** 2 * a * cos(th) ** 3))
n = a / sqrt(1 - e ** 2 * sin(lat) ** 2)
alt = p / cos(lat) - n
lon = lon % (2 * pi)
return lat_180/pi, lon_180/pi, alt

def update_tle():
data=[]
#Schrijf data tijdelijk in file
urllib.request.urlretrieve('http://www.celestrak.com/NORAD/elements/stations.txt','test.dat')
f=open('test.dat','r')
data=f.read()
data=data.split('\n')
return data[0],data[1],data[2] #Gegevens International Space Station

print('Read stations data')
name,line1,line2=update_tle()

print(name)
print(line1)
print(line2)

satellite = twoline2rv(line1, line2, wgs84)
now=datetime.utcnow()
print ('UTC time ',now)
print('Calculate with sgp4 1.4')
position, velocity = satellite.propagate(now.year,now.month,now.day,now.hour,now.minute,now.second)
lat,lon,alt=ecef(position[0]_1000,position[1]_1000,position[2]_1000)
speed=sqrt(velocity[0]__2+velocity[1]__2+velocity[2]__2)_3600
print('epochyr ',satellite.epochyr)
print('epochdays ',satellite.epochdays)
print('jdsatepoch ',satellite.jdsatepoch)
print('epoch ',satellite.epoch)
print('position (km) ',position)
print('velocity (km/s) ',velocity)
print('orbital speed (km/h) ',speed)
print()
print('Position of ISS at time ',now)
print('Latitude (deg) ',lat)
print('Longitude(deg) ',lon)
print('Height ',alt)

home = ephem.Observer()
home.lon = '52' # +E
home.lat = '05' # +N

iss= ephem.readtle(name, line1, line2)
iss.compute(now)
lat=ephem.degrees(iss.sublat)
lon=ephem.degrees(iss.sublong)
print('Calculate with Ephem')
print('Latitude (deg) ',float(lat)_180/pi)
print('Longitude (deg) ',float(lon)_180/pi)

Acceptable API breakage to support Numba acceleration?

While investigating skyfielders/python-skyfield#30 I found a few places where an API break would be necessary to fully accelerate the function. In particular, passing in a string as a flag and comparing it to a constant eg. _dpper does not optimize well. Potentially better results could be obtained by using integer or boolean parameters.

Also, Numba doesn't support try-except in jitted code. That might not be a big problem if sgp4 is compiled early rather than lazy, since numba is only needed at build time and not runtime. That may also save some of the horrible compilation time.

Thoughts?

Language settings influence TLE two-line import

All versions run in accelerated mode (always True)
Situation could be replicated just with that script. So we could move to SGP4 issues

Mac Terminal says:
LANG=de_DE.UTF-8

PyCharm says:
LC_CTYPE=de_DE.UTF-8

I had a conversation with the user with the division by zero error. As soon as he switched his language setting from German to English, the problem went away.

Another interesting point about: The error is visible only when running pytest with this script from the terminal. If I start the python interpreter and paste the script manually and let it run in the terminal, It succeeds without problems.

precision tests too tight for "exotic" platforms

Cf. skyfielders/python-skyfield#411

  • i586
[   37s] ________________ test_all_three_gravity_models_with_twoline2rv _________________

[   37s] >       assert_wgs72old(Satrec.twoline2rv(LINE1, LINE2, WGS72OLD))
[   37s] E       AssertionError: -3754.2514732427567 != -3754.251473242793 within 12 places (3.637978807091713e-11 difference)


[   37s] _________________ test_all_three_gravity_models_with_sgp4init __________________
[   37s]         sat.sgp4init(WGS72OLD, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *args)
[   37s] >       assert_wgs72old(sat)
[   37s] E       AssertionError: -3754.2514732427567 != -3754.251473242793 within 12 places (3.637978807091713e-11 difference)
  • aarch64, ppc64, ppc64le, s390x all produce the same numbers for WGS84
[   50s] >       assert_wgs84(Satrec.twoline2rv(LINE1, LINE2, WGS84))
[   50s] E       AssertionError: 4719.227897029575 != 4719.227897029576 within 12 places (9.094947017729282e-13 difference)

[   50s]         sat.sgp4init(WGS84, 'i', VANGUARD_ATTRS['satnum'], VANGUARD_EPOCH, *args)
[   50s] >       assert_wgs84(sat)
[   50s] E       AssertionError: 4719.227897029575 != 4719.227897029576 within 12 places (9.094947017729282e-13 difference)

GRACE-1 and GRACE-2 TLE returning NaN's

Hi,
the Grace-1 and Grace-2 TLE are returning NaN's.

`
from sgp4.earth_gravity import wgs72,wgs72old,wgs84
from sgp4.io import twoline2rv
import sgp4

line1 = ('1 27392U 02012B 17317.13935224 .00120532 42499-5 34060-3 0 9998')
line2 = ('2 27392 88.9800 298.9359 0008907 105.9560 254.2707 15.93313173881025')
satellite = twoline2rv(line1, line2, wgs72)
position, velocity = satellite.propagate(2000, 6, 29, 12, 50, 20.1)

print(position)
print(velocity)
print(satellite.error_message)

(nan, nan, nan)
(nan, nan, nan)
mean eccentricity -0.025182 not within range 0.0 <= e < 1.0
`

I confirmed the TLE from multiple sources online. I'm using this for a 3d visualisation and am very much out of my depth as to what is going on under the hood to figure out where the error could originate.

Best regards,
Fabian

Last release is broken, cannot be downloaded bcs of missing tar.gz

STEPS TO REPRODUCE

  • Put to the project requirements (I am using Pipfile) sgp4 with version 2.4
  • Build docker to download requirements and install them
#11 96.93 ERROR: Could not find a version that satisfies the requirement sgp4==2.4 (from -r /tmp/requirements.txt (line 73)) (from versions: 1.0, 1.1, 1.3, 1.4, 2.0, 2.2, 2.3)
#11 97.35 ERROR: No matching distribution found for sgp4==2.4 (from -r /tmp/requirements.txt (line 73))
#11 ERROR: executor failed running [bash -c export FROM_DOCKERFILE=1;     export PIP_FIND_LINKS=wheels/alpine;     pushd /run/secrets &&         cp .env.tmp /.env &&     popd &&     chmod a+x ./helper.sh &&     apk add --no-cache --virtual .build-deps         gcc g++ libffi-dev linux-headers make musl-dev openssl-dev pcre-dev         postgresql-dev python3-dev &&     ./helper.sh build-and-sync-wheels &&     pip install         -r /tmp/requirements.txt         -r /tmp/requirements-dev.txt         &&     pip install docker-compose==1.25.0 &&     pip install pyyaml==5.1.2 &&     apk --purge del .build-deps &&     rm -fv .env]: runc did not terminate sucessfully
------
 > [evp-pp-helper 5/6] RUN --mount=type=cache,target=./wheels     --mount=type=secret,id=.env.tmp     export FROM_DOCKERFILE=1;     export PIP_FIND_LINKS=wheels/alpine;     pushd /run/secrets &&         cp .env.tmp /.env &&     popd &&     chmod a+x ./helper.sh &&     apk add --no-cache --virtual .build-deps         gcc g++ libffi-dev linux-headers make musl-dev openssl-dev pcre-dev         postgresql-dev python3-dev &&     ./helper.sh build-and-sync-wheels &&     pip install         -r /tmp/requirements.txt         -r /tmp/requirements-dev.txt         &&     pip install docker-compose==1.25.0 &&     pip install pyyaml==5.1.2 &&     apk --purge del .build-deps &&     rm -fv .env:
------
failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to solve with frontend gateway.v0: rpc error: code = Unknown desc = failed to build LLB: executor failed running [bash -c export FROM_DOCKERFILE=1;     export PIP_FIND_LINKS=wheels/alpine;     pushd /run/secrets &&         cp .env.tmp /.env &&     popd &&     chmod a+x ./helper.sh &&     apk add --no-cache --virtual .build-deps         gcc g++ libffi-dev linux-headers make musl-dev openssl-dev pcre-dev         postgresql-dev python3-dev &&     ./helper.sh build-and-sync-wheels &&     pip install         -r /tmp/requirements.txt         -r /tmp/requirements-dev.txt         &&     pip install docker-compose==1.25.0 &&     pip install pyyaml==5.1.2 &&     apk --purge del .build-deps &&     rm -fv .env]: runc did not terminate sucessfully

I realized for last release tar gz file is missing:
Screenshot 2020-03-04 17 45 26

epochs datetime missing

The sgp4 model used to have a property .epoch that returned a python datetime object. This seems to have been removed. It's also been removed from releases of 2.3 so it's not available if I install a past version. There doesn't seem to be any function for getting a datetime from the jsatepoch and jsatepochF. Sorry if the issue is at my end

jdsatepoch = jd + fr. Why?

In the v2.0 updates, the epoch has been split to its integer and fractional components, apparently in an effort to maintain compatibility with the SGP.CPP code. However, that code also doesn't consistently use it -- and the separation of the pieces have no apparent benefit (to me at least).

Is there a reason that the user must be made to manage these variables in their day and day-fraction components?

io.py, 'TypeError: startswith first arg must be bytes or a tuple of bytes, not str'

Hello, this may be a fairly simple question, as I'm just starting Python, coming from Matlab, but here goes:

I get the error:

File "C:\ProgramData\Anaconda3\lib\site-packages\sgp4\io.py", line 131, in twoline2rv
assert line.startswith('1 ')
TypeError: startswith first arg must be bytes or a tuple of bytes, not str

When trying to run the code. I have tried to change the '1' in the startswith function to a different type by adding a b before the '1', by using bytes('1'), by using tuple('1'), and by using str.encode('1'), but I continue to get the exact same error.

Any ideas? Thanks!

Alpha5 support

The format of TLEs has changed because the space fence is going to rapidly overwhelm the 5-digit numbers available in the old format. This needs to be supported by all the satellite libraries that support TLEs.

For example, catalog number 270000 (which is an analyst object seen by the space fence) has a catnum field of T00000 as in:

1 T0000U          20341.14572529  .00000446  00000-0  15605-2 0  9998
2 T0000  90.2902 300.0888 0031941  22.1325 338.1165 12.95152933 48676

This range is in given by the RESTFUL link https://www.space-track.org/basicspacedata/query/class/gp/EPOCH/%3Enow-30/NORAD_CAT_ID/270000--339999/orderby/NORAD_CAT_ID/format/tle

From space-track:

Alpha-5 is a stopgap object numbering schema from the United States Space Force that increases the satellite catalog’s capacity to display up to 339,999 objects in the GP/GP_History API classes using legacy fixed-width Two and Three Line Element Set (TLE/3LE) formats.

Replacing the 1st digit of the 5-digit object number with an alphanumeric character makes it possible to represent 240,000 more numbers. Objects less than 100,000 are unaffected by Alpha-5, as are users who download elsets from the GP and GP_History API classes in other formats like XML, JSON, KVN, and CSV. In order to preserve legacy operations that depend on 5-digit integers, our legacy API Classes tle, tle_latest, and tle_publish will not change to Alpha-5.

Only capital letters and numbers are used in Alpha-5. The letters “I” and “O” are omitted to avoid confusion with the numbers “1” and “0”.

export_tle roundtrip issues

While studying #70, I discovered a roundtrip problem with export_tle:

>>> lines = """1 46272U 20061A   20311.82207422  .00000083  00000-0  68546-5 0  9999
... 2 46272  97.3995  23.7575 0006827 352.5560   7.5569 15.20743438  9810"""
>>> print(lines)
1 46272U 20061A   20311.82207422  .00000083  00000-0  68546-5 0  9999
2 46272  97.3995  23.7575 0006827 352.5560   7.5569 15.20743438  9810
>>> sat = twoline2rv(*lines.splitlines(), wgs84)
>>> print("\n".join(export_tle(sat)))
1 46272U 20061A   2020311.82207422  .00000083  00000-0  68546-5 0  9993
2 46272  97.3995  23.7575 0006827 352.5560   7.5569 15.20743438  9810

And I think it also happens with other examples in https://github.com/brandon-rhodes/python-sgp4/blob/master/sgp4/SGP4-VER.TLE.

numba makes sgp4 slower

I still didn't have time to craft a proper reproducible example, but we observed a noticeable slowdown when using sgp4 2.2, which is entirely consistent with this observation by @rirze:

In my course of using this library, I have found Numba to be increasing my runtimes for the sgp4 routine, rather than decreasing it. [...] In fact, on my machine, Numba compilation increases sgp4 runtime by 2-3x! (Ubuntu 18.04 Windows Subsystem Linux, Python 3.6.4)

We are also observing a large number of warnings:

tests/test_full_pipeline.py::test_orbit_assigners_are_recovered
  /home/juanlu/.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/sgp4/propagation.py:1698: NumbaWarning: 
  Compilation is falling back to object mode WITH looplifting enabled because Function "sgp4" failed type inference due to: Untyped global name '_dpper': cannot determine Numba type of <class 'function'>
  
  File "../../../../.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/sgp4/propagation.py", line 1838:
  def sgp4(satrec, tsince, whichconst=None):
      <source elided>
  
           ep, xincp, nodep, argpp, mp = _dpper(
           ^
  
    @jit(cache=True)

tests/test_full_pipeline.py::test_orbit_assigners_are_recovered
  /home/juanlu/.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/sgp4/propagation.py:1698: NumbaWarning: 
  Compilation is falling back to object mode WITHOUT looplifting enabled because Function "sgp4" failed type inference due to: Untyped global name '_dpper': cannot determine Numba type of <class 'function'>
  
  File "../../../../.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/sgp4/propagation.py", line 1838:
  def sgp4(satrec, tsince, whichconst=None):
      <source elided>
  
           ep, xincp, nodep, argpp, mp = _dpper(
           ^
  
    @jit(cache=True)

tests/test_full_pipeline.py::test_orbit_assigners_are_recovered
  /home/juanlu/.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/numba/object_mode_passes.py:178: NumbaWarning: Function "sgp4" was compiled in object mode without forceobj=True, but has lifted loops.
  
  File "../../../../.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/sgp4/propagation.py", line 1700:
  #@jit
  def sgp4(satrec, tsince, whichconst=None):
  ^
  
    state.func_ir.loc))

tests/test_full_pipeline.py::test_orbit_assigners_are_recovered
  /home/juanlu/.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/numba/object_mode_passes.py:187: NumbaDeprecationWarning: 
  Fall-back from the nopython compilation path to the object mode compilation path has been detected, this is deprecated behaviour.
  
  For more information visit http://numba.pydata.org/numba-doc/latest/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit
  
  File "../../../../.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/sgp4/propagation.py", line 1700:
  #@jit
  def sgp4(satrec, tsince, whichconst=None):
  ^
  
    warnings.warn(errors.NumbaDeprecationWarning(msg, state.func_ir.loc))

tests/test_full_pipeline.py::test_orbit_assigners_are_recovered
  /home/juanlu/.pyenv/versions/3.7.4/envs/mbp37_4/lib/python3.7/site-packages/sgp4/propagation.py:1698: NumbaWarning: Cannot cache compiled function "sgp4" as it uses lifted loops
    @jit(cache=True)

sgp4 own tests do take much longer now, but this is somewhat to be expected because the compilation step takes some time:

$ time python -m sgp4.tests 2> /dev/null 

real	0m12,655s
user	0m12,631s
sys	0m0,537s
$ export NUMBA_DISABLE_JIT=1
$ time python -m sgp4.tests
...............
----------------------------------------------------------------------
Ran 15 tests in 0.080s

OK

real	0m0,678s
user	0m0,724s
sys	0m0,228s

`propagate(self, year, month=1, day=1, hour=0, minute=0, second=0.0)` seems kind of wrong and easy to misuse

in particular, one might try to do something like propagate(608400) which might seem reasonable given that the sgp4 function is called assgp4(satrec, seconds_since_epoch) and instead of propagating the satellite a week from the epoch, propagate will try compute for the year 608400.

of course I'd never do something like that... 🤨

Perhaps a better interface for propagate would be propagate(self, obs_time=None, second_since_epoch=None).

If neither obs_time nor seconds_since epoch are given, then propagate would compute at obs_time=datetime.datetime.now() - at the time the function was called. If obs_time is None, and seconds_since_epoch is a real number, then compute based on the epoch of the TLE. If both are given... that should probably be an error because it's not immediately clear what's supposed to happen.

Consider accepting timezone-aware datetimes in calls to propagate

The fix would be pretty minimal, and it would be convenient, but I wasn't sure if there was a reason not to.

if isinstance(year, datetime):
    year, month, day, hour, minute, second  = year.timetuple([:6]) 
    second += year.microsecond / 1.0e6

This would go here in the model propagate function. month, day, hour, minute, second would all be optional with defaults.

sgp4init() missing from wrapper.cpp

While Satrec.twoline2rv() allows creating a record from TLEs, CPP-accelerated functionality is missing for creating records directly from element variables.

Failure running some tests in a different time zone

When running tests in a different time zone (I am in CET), some tests fail:

Failed tests: testNextSatPass(uk.me.g4dpz.satellite.PassPredictorTest): expected:<2009-01-05T0[4:28:10+00]00> but was:<2009-01-05T0[5:28:10+01]00>
testNextSatPassWithWindBack(uk.me.g4dpz.satellite.PassPredictorTest): expected:<2009-01-05T0[4:28:10+00]00> but was:<2009-01-05T0[5:28:10+01]00>
correctToStringResult(uk.me.g4dpz.satellite.PassPredictorTest): expected:<...5, 2009(..)
poleIsPassed(uk.me.g4dpz.satellite.PassPredictorTest): expected:<2009-01-05T0[7:42:45+00]00, north> but was:<2009-01-05T0[8:42:45+01]00, north>

Tests run: 32, Failures: 4, Errors: 0, Skipped: 0

Cannot find the module sgp4.earth_gravity

[root@docs orbital]# pip install sgp4
Requirement already satisfied: sgp4 in /usr/lib/python2.7/site-packages
[root@docs orbital]# python sgp4.py
Traceback (most recent call last):
  File "sgp4.py", line 4, in <module>
    from sgp4.earth_gravity import wgs84
  File "/usr/share/nginx/html/orbital/sgp4.py", line 4, in <module>
    from sgp4.earth_gravity import wgs84
ImportError: No module named earth_gravity

What could be the problem?

days2hms can return seconds = 60.0

In unaccelerated version, the days2mdhms() function can return a value with the previous minute and 60 seconds. for example, day=133.35625 should give a time of 08:33:00 but instead gives 08:32:60. And the 60 is not 59.99999999 but a solid 60. When used in a TLE, this causes TLE interpretation to break.

In [1]: from sgp4.api import accelerated, days2mdhms

In [2]: print(accelerated)
False

In [3]: print(days2mdhms(2020, 133.35625))
(5, 12, 8, 32, 60.0)

In [4]: _,_,_,_,s = days2mdhms(2020, 133.35625)

In [5]: print(s, s==60)
60.0 True

Therefore, in Skyfield

EarthSatellite('1 00000U 00000ZZ  20133.35625000  .00000000  00000-0  00000-0 0  9990',
                        '2 00000  24.6020  12.0680 3978520  69.4580 328.0792  0.99945723    08')

gives ValueError: second must be in 0..59:

Traceback (most recent call last):
  File ".../lib/python3.8/site-packages/sgp4/io.py", line 101, in twoline2rv
    def twoline2rv(longstr1, longstr2, whichconst, opsmode='i', satrec=None):
ValueError: second must be in 0..59
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File ".../lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3293, in run_code
    async def run_code(self, code_obj, result=None, *, async_=False):
  File "<ipython-input-24-830190fd66c5>", line 1, in <module>
    EarthSatellite('1 00000U 00000ZZ  20133.35625000  .00000000  00000-0  00000-0 0  9990',
  File ".../lib/python3.8/site-packages/skyfield/sgp4lib.py", line 89, in __init__
    def __init__(self, line1, line2, name=None, ts=None):
  File ".../lib/python3.8/site-packages/sgp4/model.py", line 49, in twoline2rv
    @classmethod
  File ".../lib/python3.8/site-packages/sgp4/io.py", line 101, in twoline2rv
    def twoline2rv(longstr1, longstr2, whichconst, opsmode='i', satrec=None):
ValueError: second must be in 0..59

The error is where days2mdhms rounds off the seconds to 6 digits, which can round upwards from 59.99... .

Issue with Molniya satellite

I've implemented the SGP4 algorithm. It works OK for LEO satellites.

However, for Molniya 1-29 satellite there is a strange trajectory: it's not elliptic, looks like 8.

Do you have any idea?

Allow change of gravity model in Satrec

The new Satrec class uses the WGS-72 gravity model:

SGP4Funcs::twoline2rv(line1, line2, ' ', ' ', 'i', wgs72,

twoline2rv(line1, line2, wgs72, 'i', self)

There is some discussion in Vallado et al. "Revisiting Spacetrack Report #3: Rev 1" but I haven't fully understood it yet. Do you have any supporting documentation that says that WGS-72 should always be used, or do you think it could be left as a parameter?

Better handling of possibly busted TLEs from celestrak

# Retrieved from http://celestrak.com/NORAD/elements/supplemental/iss.txt
# "Last-modified" header = Mon, 30 Dec 2019 15:36:08 GMT
>>> l0 = 'ISS [Orbit 606]'
>>> l1 = '1 25544U 98067A   19366.82137887  .00016717  00000-0  10270-3 0  9129'
>>> l2 = '2 25544  51.6392  96.6358 0005156  88.7140 271.4601 15.49497216  6061'
>>> rv = twoline2rv(l1, l2, wgs72)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-26-09487e861a12> in <module>()
      5 l2 = '2 25544  51.6392  96.6358 0005156  88.7140 271.4601 15.49497216  6061'
      6 
----> 7 rv = twoline2rv(l1, l2, wgs72)

/usr/local/lib/python3.7/dist-packages/sgp4/io.py in twoline2rv(longstr1, longstr2, whichconst, opsmode, satrec)
    225     satrec.jdsatepoch = jday(year,mon,day,hr,minute,sec);
    226     satrec.epoch = datetime(year, mon, day, hr, minute, int(sec_whole),
--> 227                             int(sec_fraction * 1000000.0 // 1.0))
    228 
    229     #  ---------------- initialize the orbit at sgp4epoch -------------------

ValueError: day is out of range for month

Whaaaaa? I generally trust Celestrak to not produce broken files (this is literally the first time I've seen this), a bunch of other TLEs from that file do parse correctly, and the error doesn't tell me exactly what the invalid value is, just that I now have to go break out the TLE definition to try figure it out.

>>> from sgp4.ext import days2mdhms, jday
>>> jd = 19366.82137887
>>> day = jd % 1000
>>> year = 2000 + int(jd/1000)
>>> print(days2mdhms(year, day))
(12, 32, 19, 42, 47.13436799909687)

Oh. December 32nd. This is fine. When if I fix the year and day by hand it works.

>>> print(days2mdhms(year+1, day-365))
(1, 1, 19, 42, 47.13436811696738)

Would it make sense to wrap the datetime() in an exception handler to say what parameter was invalid ? Would it make sense to include that end-of-year handling inside days2mdhms?

Support OMM file format

As documented at Celestrak's website, an XML/JSON based format called OMM (spec: https://public.ccsds.org/Pubs/502x0b2c1.pdf) is being pushed as a more modern replacement for the TLE format. Since the parameters are still reported in terms of sgp4 elements, and given the dominance of CelesTrak as a source of orbit information, it seems reasonable imo to add support to this project for the OMM format.

I'd be happy to open a PR for this with some guidance on how you'd like this structured. Would it be more reasonable to:

  1. Add this functionality into io.py?
  2. Create a new submodule, omm.py or something similar?
  3. Something else?

This is my first time trying to contribute to an open-source project, so apologies if there's something I'm missing.

Brouwer vs. Kozai mean motion

I have an application for which I need to be able to produce TLE's from the mean elements in the "model" member of a Skyfield EarthSatellite object. After implementing the text-rendering function, I tried round-tripping a TLE through it and noted that the code didn't reproduce the mean-motion term correctly.

Tracing through twoline2rv() eventually led to the section of the sgp4.propagation._initl() function that "un-Kozai's" the mean motion, which explained the difference. I tried copying the calculation of the "del_" scale factor into my routine to "undo" the Kozai --> Brouwer transformation, but unfortunately it's a non-conservative transform b/c the first intermediate variable in the del_ calculation ("ak") depends on the input mean-motion value.

Would it be possible to add a utility function to perform the inverse (Brouwer --> Kozai) transformation on mean motion?

Add license to source repository

I see in the PyPI package that python-sgp4 is licensed under MIT, but it would be useful to state it in the README and even include a LICENSE or COPYING file.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.