JuliaSpace / SatelliteToolbox.jl

A toolbox for satellite analysis written in julia language.
MIT License
249 stars 33 forks source link

How to convert velocities from ECEF to ECI? #5

Closed tmamedzadeh closed 5 years ago

tmamedzadeh commented 6 years ago

I have converted the coordinates from ECEF to ECI. How to convert velocities also?

ronisbr commented 6 years ago

Hi @Tarlan0001 ,

Currently, SatelliteToolbox.jl has functions to compute the rotation description (DCM or Quaternion) between the coordinate frames supported. Hence, you can represent the velocity in ECEF using the same matrix. However, I think that what you want is to change the time-derivative so that it is computed also with respect to the ECEF. In this case, you have to account for the Earth rotation rate.

So, let's say you have a position and velocity vector in J2000 reference frame and want to convert to PEF. Then you can do the following:

r_j2000 = [5102.50960000; 6123.01152000; 6378.13630000]
v_j2000 = [-4.7432196000; 0.7905366000; 5.5337561900]

# Earth rotation rate.
w = 7.292115146706979e-5

# Compute the rotation between J2000 to PEF at 2004-04-06 7:51:28.386009 UTC.
D_PEF_J2000 = rECItoECEF(J2000(), PEF(), DatetoJD(2004, 4, 6, 7, 51, 28.386009))

# Compute the position represented in ECEF.
r_pef = D_PEF_J2000*r_j2000

# Compute the velocity represented in ECEF and measured w.r.t. the same reference frame.
v_pef = D_PEF_J2000*v_j2000 - [0;0;w] × r_pef

If you want more precision, then you need to use EOP data to compute the Earth rotation rate:

eop = get_iers_eop()
LOD = eop.LOD[DatetoJD(2004, 4, 6, 7, 51, 28.386009)]
w = 7.292115146706979e-5*(1-LOD/86400)

Notice that if your desired ECEF is not PEF, then you should convert to PEF first (because we know how the Earth rotation vector is represented in this reference frame) and then convert to ITRF using rECEFtoECEF.

I will leave your issue open so that I can add a function to automatically convert position, velocity, and acceleration between ECI and ECEF.

tmamedzadeh commented 6 years ago

Thank you! A few questions:

  1. How to convert velocity in rECEFtoECEF conversion?
  2. How to convert acceleration?
  3. Does your conversion to ECI (from PEF or ITRF) consider polar motion?
ronisbr commented 6 years ago
  1. How to convert velocity in rECEFtoECEF conversion?

In this case, you are converting PEF to ITRF, which are almost aligned. The difference is just the polar motion. Hence, you can neglect this movement and just convert using the rotation matrix, as if the relative angular velocity between both systems is zero.

  1. How to convert acceleration?

In this case, you just need to use the usual equation to convert the acceleration from one reference frame to another one in which there is relative angular movement between them. IIRC, this should be:

a_pef = D_PEF_J2000*a_j2000 - [0;0;w] × [0;0;w] × r_pef - 2*[0;0;w] × v_pef

(please, check this equation!)

  1. Does your conversion to ECI (from PEF or ITRF) consider polar motion?

This depends. If you are converting J2000 to PEF using rECItoECEF, then it will not consider the polar motion because it will use the original IAU-76/FK5 theory. However, if the ECI frame is GCRF, TOD, or MOD and/or the ECEF frame is ITRF, then the polar motion will be taken into account.

tmamedzadeh commented 6 years ago

Thanks a lot!

Also, y and ECEF_ECI(ECI_ECEF(y,date),date) gives slightly different velocities:

function harmonics(y,date)
  println(y,ECEF_ECI(ECI_ECEF(y,date),date))
end

function ECEF_ECI(y,date)
  LOD = eop.LOD[date]
  e_vel = 7.292115146706979e-5*(1-LOD/86400)

  D_GCRF_ITRF = rECEFtoECI(PEF(), GCRF(), date, eop)
  r_gcrf = D_GCRF_ITRF*y[1:3]
  v_gcrf = D_GCRF_ITRF*y[4:6] + [0;0;e_vel] × r_gcrf

  return [r_gcrf; v_gcrf]

end

function ECI_ECEF(y,date)

  LOD = eop.LOD[date]
  e_vel = 7.292115146706979e-5*(1-LOD/86400)

  D_GCRF_ITRF = rECItoECEF(GCRF(), PEF(), date, eop)
  r_gcrf = D_GCRF_ITRF*y[1:3]
  v_gcrf = D_GCRF_ITRF*y[4:6] - [0;0;e_vel] × r_gcrf

  return [r_gcrf; v_gcrf]

end

harmonics(y,date)

[-9.76307e5, -4.83563e6, -5.03173e6, -794.400, 5474.53, -5094.50] [-9.76307e5, -4.83563e6, -5.03173e6, -794.408, 5470.96, -5091.06]

ronisbr commented 6 years ago

Also, y and ECEF_ECI(ECI_ECEF(y,date),date) gives slightly different velocities:

Notice that the vectors in the operation [0;0;e_vel] × r_gcrf must be represented in PEF. In ECI_ECEF this is right. However, in ECEF_ECI you are mixing vectors represented in PEF with vectors represented in GCRF inside the operations. In this case, the velocity equation must be:

v_gcrf = D_GCRF_ITRF*(y[4:6] + [0;0;e_vel] × y[1:3])

In this case:

[-976307.0, -4.83563e6, -5.03173e6, -794.4, 5474.53, -5094.5]
[-976307.0, -4.83563e6, -5.03173e6, -794.4, 5474.53, -5094.5]
tmamedzadeh commented 6 years ago

If acceleration conversion to ECEf is a_pef = D_PEF_J2000*a_j2000 - [0;0;w] × [0;0;w] × r_pef - 2*[0;0;w] × v_pef

Then acceleration to ECI is a_j2000 = D_J2000_PEF*(y[7:9] + [0;0;w] × [0;0;w] × y[1:3] + 2*[0;0;w] × y[4:6])

Probably, the equation is wrong. It gave me -1.09E-2 acceleration, conversion to ECI even gave -8.1E-1, but it should be less.. I couldn't check the equation...

When converting ECEFtoECEF acceleration also wouldn't change?

ronisbr commented 6 years ago

Your equations seem right. Can you please post a working code so that I can analyze?

When converting ECEFtoECEF acceleration also wouldn't change?

No, because you can consider that there is no relative angular velocity between PEF and ITRF.

tmamedzadeh commented 6 years ago

Your equations seem right. Can you please post a working code so that I can analyze?

Yes. I would explain what I'm going to do: I'm calculating the acceleration by zonal harmonics (J2). I'm converting the state to ECEF, calculate acceleration and convert it back to ECI.

function harmonics(y,date)
  y_ecef=ECI_ECEF([y;[0,0,0]],date)[1:6]
  re2=y_ecef[1]^2 + y_ecef[2]^2 + y_ecef[3]^2
  re3=re2^(3/2)
  w  = 1.5*J2*(Req^2/re2)*(1 - 5*y_ecef[3]^2/re2)
  w2 = 1.5*J2*(Req^2/re2)*(3 - 5*y_ecef[3]^2/re2)
  acc= [-GMe*y_ecef[1]*w/re3, -GMe*y_ecef[2]*w/re3, -GMe*y_ecef[3]*w2/re3]

  return ECEF_ECI([y_ecef;acc],date)[7:9]
end

function ECEF_ECI(y,date)

  LOD = eop.LOD[date]
  e_vel = 7.292115146706979e-5*(1-LOD/86400)

  D = rECEFtoECI(PEF(), GCRF(), date, eop)
  r = D*y[1:3]
  v = D*(y[4:6] + [0;0;e_vel] × y[1:3])
  a = D*(y[7:9] + [0;0;e_vel] × [0;0;e_vel] × y[1:3] + 2*[0;0;e_vel] × y[4:6])  

  return [r;v;a]

end

function ECI_ECEF(y,date)

  LOD = eop.LOD[date]
  e_vel = 7.292115146706979e-5*(1-LOD/86400)

  D = rECItoECEF(GCRF(), PEF(), date, eop)
  r = D*y[1:3]
  v = D*y[4:6] - [0;0;e_vel] × r
  a = D*y[7:9] - [0;0;e_vel] × [0;0;e_vel] × r - 2*[0;0;e_vel] × v

  return [r;v;a]

end
ronisbr commented 6 years ago

Your equations seem fine. What is the problem you are seeing?

EDIT: Ops, if I am correct, this acceleration you are computing is measured in inertial reference frame. Hence, you only need to convert the representation to ECI. I mean, the observed acceleration due to ECEF rotation is not taken into account there, only the gravitational acceleration by J2 zonal harmonic. My conclusion was obtained by thinking in a satellite on geostationary orbit. In this case, the acceleration of this satellite as seen by an observer on the Equator would be 0 (the satellite will not move with respect to the observer). However, your equations in ECEF will not be 0.

tmamedzadeh commented 6 years ago

Sorry, I didn't understand. The equation a = D*(y[7:9] + [0;0;e_vel] × [0;0;e_vel] × y[1:3] + 2*[0;0;e_vel] × y[4:6]) considers the ECEF rotation when converting to ECI.

What change do you suggest in the code?

ronisbr commented 6 years ago

Yes. The last two terms basically convert an acceleration measured by an observer in ECEF to what an observer in ECI would have measured. Since your equation is computing the gravitational force due to Earth mass, it is already measured in an inertial frame, but represented in the ECEF. Then, if I am right, you just need to:

a = D*y[7:9]

To make this clear: the equation that computes a provides a non-zero vector. On the other hand, for an observer in ECEF on the equator, a geostationary satellite (with inclination 0) would have a = [0;0;0] and v = [0;0;0]. Hence, it am almost sure that your equation that computes the acceleration is already measuring it with respect to ECI but it is represented in ECEF.

tmamedzadeh commented 6 years ago

You are great!

ronisbr commented 6 years ago

Thanks :) If you need something, please ask! I will let this bug open to add a function to automatically convert r and v between reference frames.

tmamedzadeh commented 6 years ago

And a, please) When are you planning this?

ronisbr commented 6 years ago

Sorry @Tarlan0001 , did not see your comment.

I am a little confused how to add the acceleration. The conversion between position and velocity is well known. You convert the orbit elements to state-vector (r and v), which are represented in ECI, and then transform to ECEF. The acceleration is a little trick. One problem is what you saw. Normally, the acceleration is measured in ECI but just represented in ECEF. I am not sure how to handle this. Any ideas?

tmamedzadeh commented 6 years ago

I just make like this: a_pef = D*y[7:9] for ITRF->PEF It gives, as I think, correct result.

ronisbr commented 6 years ago

@Tarlan0001

I talked to some friends and this is not really the default. Sometimes people will want to convert not only the representation, but also the frame in which the acceleration is measured, sometimes not. Hence, the result is correct for your case, but I am not sure if everyone will use this conversion as you are. I have to think more about it. Maybe, I need to add options for the user select if he/she wants to change the frame in which the derivative is being obtained.

tmamedzadeh commented 5 years ago

Hi! Have you worked on the direct transformation of J2000->ITRF? Currently, the function transforms to PEF.

ronisbr commented 5 years ago

Hi @Tarlan0001 ,

I am not sure if I understood your question. The J2000 -> ITRF is working for rotating vectors:

eop = get_iers_eop_iau_1980("https://datacenter.iers.org/data/latestVersion/222_EOP_C04_14.XX.IAU1980222.txt")
D = rECItoECEF(J2000(), ITRF(), DatetoJD(2017,1,1,0,0,0), eop)

r_j2000 = [100;100;100]
r_itrf = D*r_j2000
tmamedzadeh commented 5 years ago

Previously You suggested me to convert to PEF first and then from PEF to ITRF. Something changed?

ronisbr commented 5 years ago

Ah, I suggested you to convert to PEF first in order to change the reference frame in which the velocity is measured. I think I understood what you asked now.

No, we still do not have an automatic conversion of the velocity vectors considering the change in the reference frame used to take the derivative.

This will be a little bit difficult, I think, because of the high number of reference frames we need to account for. I will think a little bit about it.

Do you want a function in which you pass the position, velocity, and acceleration in a ECI frame and it converts everything to an ECEF frame right? By converting I mean represent the vectors in the new frame and also change the reference frame in which the derivatives are take.

tmamedzadeh commented 5 years ago

Yes, I need to convert the velocity and acceleration vectors from ECEF to ECI and vice versa.

ronisbr commented 5 years ago

Hi @Tarlan0001 !

After a very long wait (sorry...) I finally had time to implement this feature. We now have a structure to store the satellite state vector: SatelliteStateVector, which has the position, velocity, and acceleration. Thus, the conversion between frames can now be done by:

julia> orb = Orbit(DatetoJD(2018,3,22,0,0,0), 42164e3, 0.0, 0.0, 0.0, 0.0, 0.0);

julia> sv_J2000 = kepler_to_sv(orb);

julia> sv_J2000.a = -m0/(norm(sv_J2000.r)^3)*sv_J2000.r
3-element SArray{Tuple{3},Float64,1,3}:
 -0.22420958065533492
 -0.0
 -0.0

julia> sv_PEF = svECItoECEF(sv_J2000, J2000(), PEF(), sv_J2000.t);

julia> sv_PEF.r
3-element SArray{Tuple{3},Float64,1,3}:
      -4.216000453942691e7
 -575759.6147109803
   73580.57875642928

julia> sv_PEF.v
3-element SArray{Tuple{3},Float64,1,3}:
  0.0001549895587729111
 -0.02353402210155764
 -0.0953455261482022

julia> sv_PEF.a
3-element SArray{Tuple{3},Float64,1,3}:
 -6.828454350002497e-7
  1.4943389583025247e-8
 -0.0003912691088927961

Notice that kepler_to_sv, which converts orbit elements to position and velocity does not compute the acceleration.

If you can, please, test and let me know if everything is working. You can convert between any frame that is supported in this package using the functions svECItoECI, svECItoECEF, svECEFtoECI, and sECEFtoECEF.

trufanov-nok commented 1 year ago

Would like to mention here that SatelliteStateVector is seems to be renamed to OrbitStateVector.

ronisbr commented 1 year ago

Yes! We renamed it sometime ago :)

Actually, SatelliteToolbox is still going through a bump road :D API will change more often than I like. In this case, try to stick to a version (we follow semantic versioning here).