title: ECEF from Azimuth, Elevation, Range and Observer Lat,Lon,Alt
body: <p>I'm trying to write a basic python script that will track a given satellite, defined with tle's, from a given location. I'm not a asto/orbital person but am trying to become smarter on it.</p>
  
  <p>I am running into a problem when I try to convert the azimuth, elevation, range values to a ECEF position. I'm using PyEphem to get the observation values and spg4 to get the real location to verify. I'm also using the website, <a href="http://www.n2yo.com/?s=25544" rel="nofollow noreferrer">http://www.n2yo.com/?s=25544</a>, the verify the values.</p>
  
  <p>I'm getting the observed azimuth, elevation and range with: </p>
  
  <pre><code>def get_ob(epoch, sv, obsLoc):
      site = ephem.Observer()
      site.lon = str(obsLoc.lat)   # +E -104.77 here
      site.lat = str(obsLoc.lon)   # +N 38.95   here
      site.elevation = obsLoc.alt # meters    0 here
      #epoch = time.time()
      site.date = datetime.datetime.utcfromtimestamp(epoch)
  
      sat = ephem.readtle(sv.name,sv.tle1,sv.tle2)
      sat.compute(site)
  
      az       = degrees(sat.az)
      el       = degrees(sat.alt)
      #range in m
      range    = sat.range
      sat_lat  = degrees(sat.sublat)
      sat_long = degrees(sat.sublong)
      # elevation of sat in m
      sat_elev = sat.elevation
  
      x, y, z    = aer2ecef(az,el,range,38.95,-104.77,80 / 1000)
  </code></pre>
  
  <p>The reported azimuth, elevation and range match the website. I'm converting to ECEF positions with:</p>
  
  <pre><code>def aer2ecef(azimuthDeg, elevationDeg, slantRange, obs_lat, obs_long, obs_alt):
  
      #site ecef in meters
      sitex, sitey, sitez = llh2ecef(obs_lat,obs_long,obs_alt)
  
      #some needed calculations
      slat = sin(radians(obs_lat))
      slon = sin(radians(obs_long))
      clat = cos(radians(obs_lat))
      clon = cos(radians(obs_long))
  
      azRad = radians(azimuthDeg)
      elRad = radians(elevationDeg)
  
      # az,el,range to sez convertion
      south  = -slantRange * cos(elRad) * cos(azRad)
      east   =  slantRange * cos(elRad) * sin(azRad)
      zenith =  slantRange * sin(elRad)
  
  
      x = ( slat * clon * south) + (-slon * east) + (clat * clon * zenith) + sitex
      y = ( slat * slon * south) + ( clon * east) + (clat * slon * zenith) + sitey
      z = (-clat *        south) + ( slat * zenith) + sitez
  
      return x, y, z
  </code></pre>
  
  <p>When I plot that though, the position is way off (wrong side of globe). The position I get from the website and from spg4 match so I believe those to be the correct.</p>
  
  <p>I'm not sure if the error is in my conversion method or I'm using the wrong data for the conversion. I found the method in a answer here: <a href="https://stackoverflow.com/questions/3612749/get-ecef-xyz-given-starting-coordinates-range-azimuth-and-elevation">Get ECEF XYZ given starting coordinates, range, azimuth, and elevation</a></p>
  
  <p>Any advice or suggestions for where I'm getting off would be very appreciated. Below is test input/outputs:</p>
  
  <p>The satellites I'm testing with are the ISS and directv10 (one fixed, one moving- with internet tracking available for verification):</p>
  
  <pre><code>0 Direct10
  1 31862U 07032A   13099.15996183 -.00000126  00000-0  10000-3 0  1194
  2 31862 000.0489 046.9646 0000388 001.7833 103.5813 01.00271667 21104
  0 ISS
  1 25544U 98067A   13112.50724749  .00016717  00000-0  10270-3 0  9148
  2 25544  51.6465  24.5919 0009906 171.1474 188.9854 15.52429950 26067
  </code></pre>
  
  <p>Observer site lla:</p>
  
  <pre><code>[38.95 -104.77 0.0]
  </code></pre>
  
  <p>results:</p>
  
  <pre><code>sv: ISS ephem observed response(km)              @ epoch: 1365630559.000000 : [344.067992722211, -72.38297754053431, 12587.123][degrees(sat.az), degrees(sat.alt), sat.range]
  sv: ISS ephem reported llh location(km)          @ epoch: 1365630559.000000 : [-41.678271938092195, -129.16682754513502, 421.06290625][degrees(sat.sublat0, degrees(sat.sublong), sat.elevation]
  sv: ISS ephem calculated xyz location(km)        @ epoch: 1365630559.000000 : [688.24385373837845, 6712.2004971137103, -704.83633267710866][aer2ecef(az,el,range,obsLoc.lat,obsLoc.lon,obsLoc.alt)]
  sv: ISS ephem llh from calc xyz location(km)     @ epoch: 1365630559.000000 : [-6.001014287867631, 84.1455657632957, 12587.123][ecef2llh()]
  sv: ISS ephem xyz from reported llh location(km) @ epoch: 1365630559.000000 :[-3211.7910504146325, -3942.7032969856118, -4498.9656030253745][llh2ecef(lat,long,elev)]
  sv: ISS spg84 ecef position(m) @ epoch: 1365630559.000000 : [-3207667.3380003194, -3936704.823960199, -4521293.5388663234]
  sv: ISS spg84 ecef2llh(m)      @ epoch: 1365630559.000000 : [-41.68067424524357, -129.17349987675482, 6792812.8704163525]
  sv: Direct10 ephem observed response(km)              @ epoch: 1365630559.000000 : [320.8276456938389, -19.703680198781303, 43887.572][degrees(sat.az), degrees(sat.alt), sat.range]
  sv: Direct10 ephem reported llh location(km)          @ epoch: 1365630559.000000 : [0.004647324660923812, -102.8070784813048, 35784.688][degrees(sat.sublat0, degrees(sat.sublong), sat.elevation]
  sv: Direct10 ephem calculated xyz location(km)        @ epoch: 1365630559.000000 : [-18435.237655222769, 32449.238763035213, 19596.893001978762][aer2ecef(az,el,range,obsLoc.lat,obsLoc.lon,obsLoc.alt)]
  sv: Direct10 ephem llh from calc xyz location(km)     @ epoch: 1365630559.000000 : [27.727834453026748, 119.60200825103102, 43887.572][ecef2llh()]
  sv: Direct10 ephem xyz from reported llh location(km) @ epoch: 1365630559.000000 :[-9346.1899009219123, -41113.897098582587, 3.4164105611003754][llh2ecef(lat,long,elev)]
  sv: Direct10 spg84 ecef position(m) @ epoch: 1365630559.000000 : [-9348605.9260040354, -41113193.982686974, -14060.29781505302]
  sv: Direct10 spg84 ecef2llh(m)      @ epoch: 1365630559.000000 : [-0.019106864351793953, -102.81049179145006, 42156299.077687651]
  </code></pre>