orbital icon indicating copy to clipboard operation
orbital copied to clipboard

Elements from state vectors does not work for Orbits with 180° inclination.

Open jj314 opened this issue 5 years ago • 1 comments

jj314 avatar Jul 29 '20 06:07 jj314

I'm years late but I found the same bug. You get NaN if invoking the utility function elements_from_state_vector, but a crash with an AssertionError if using KeplerianElements.from_state_vector.

Here is a repro case:

from numpy import sqrt
from orbital import Position, Velocity, elements_from_state_vector, \
                    KeplerianElements, earth
RADIUS = 10000000.0
R = Position(RADIUS, 0, 0)
V = Velocity(0, -sqrt(earth.mu / RADIUS), 0)
print(elements_from_state_vector(R, V, earth.mu))
print(KeplerianElements.from_state_vector(R, V, body=earth))

(i.e. a circular retrograde orbit - the position is +X and the velocity is -Y with the correct velocity to establish a circular orbit.)

This doesn't require a circular orbit to trigger. It happens when the orbit is flat (no Z axis) and retrograde (inclination is exactly 180°).

Expected output:

OrbitalElements(a=np.float64(10000000.0), e=np.float64(0.0), i=np.float64(3.141592653589793), raan=0, arg_pe=0, f=0.0)
KeplerianElements:
    Semimajor axis (a)                           =  10000.000 km
    Eccentricity (e)                             =      0.000000
    Inclination (i)                              =    180.0 deg
    Right ascension of the ascending node (raan) =      0.0 deg
    Argument of perigee (arg_pe)                 =      0.0 deg
    Mean anomaly at reference epoch (M0)         =      0.0 deg
    Period (T)                                   = 2:45:52.014054
    Reference epoch (ref_epoch)                  = J2000.000
        Mean anomaly (M)                         =      0.0 deg
        Time (t)                                 = 0:00:00
        Epoch (epoch)                            = J2000.000

Actual output:

orbital/utilities.py:284: RuntimeWarning: invalid value encountered in scalar divide
  raan = acos(n.x / norm(n))
orbital/utilities.py:290: RuntimeWarning: invalid value encountered in scalar divide
  arg_pe = acos(dot(n, ev) / (norm(n) * norm(ev)))
orbital/utilities.py:302: RuntimeWarning: invalid value encountered in scalar divide
  f = acos(dot(n, r) / (norm(n) * norm(r)))
OrbitalElements(a=np.float64(10000000.0), e=np.float64(0.0), i=np.float64(3.141592653589793), raan=np.float64(nan), arg_pe=np.float64(nan), f=np.float64(nan))
Traceback (most recent call last):
  File "test-fsv.py", line 8, in <module>
    print(KeplerianElements.from_state_vector(R, V, body=earth))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "orbital/elements.py", line 139, in from_state_vector
    assert self.M0 == oldM0
           ^^^^^^^^^^^^^^^^
AssertionError

Analysis

I am working on a fix along with some other bugs I've found in from_state_vector.

The problem is with the line in elements_from_state_vector:

if abs(i) < SMALL_NUMBER:

This only triggers when i is close to 0, but it should also go into the special case for non-inclined orbits when i is close to 180°. (However, it isn't as simple as just updating this check, because arg_pe will be calculated incorrectly in the retrograde case.) I will upload a PR fixing this soon.

mgiuca avatar Jul 17 '25 06:07 mgiuca