almanac.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 Swift Navigation Inc.
00003  * Contact: Fergus Noble <fergus@swift-nav.com>
00004  *
00005  * This source is subject to the license found in the file 'LICENSE' which must
00006  * be be distributed together with this source. All other rights reserved.
00007  *
00008  * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
00009  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
00010  * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
00011  */
00012 
00013 #include <math.h>
00014 
00015 #include "constants.h"
00016 #include "linear_algebra.h"
00017 #include "coord_system.h"
00018 #include "almanac.h"
00019 
00039 void calc_sat_state_almanac(almanac_t* alm, double t, s16 week,
00040                             double pos[3], double vel[3])
00041 {
00042   /* Seconds since the almanac reference epoch. */
00043   double dt = t - alm->toa;
00044 
00045   if (week < 0) {
00046     /* Week number unknown, correct time for beginning or end of week
00047      * crossovers and limit to +/- 302400 (i.e. assume dt is within a
00048      * half-week). */
00049     if (dt > 302400)
00050       dt -= 604800;
00051     else if (dt < -302400)
00052       dt += 604800;
00053   } else {
00054     /* Week number specified, correct time using week number difference. */
00055     s32 dweeks = week - alm->week;
00056     dt += dweeks * 604800;
00057   }
00058 
00059   /* Calculate position and velocity per ICD-GPS-200D Table 20-IV. */
00060 
00061   /* Calculate mean motion in radians/sec. */
00062   double ma_dot = sqrt (GPS_GM / (alm->a * alm->a * alm->a));
00063   /* Calculate corrected mean anomaly in radians. */
00064   double ma = alm->ma + ma_dot * dt;
00065 
00066   /* Iteratively solve for the Eccentric Anomaly
00067    * (from Keith Alter and David Johnston). */
00068   double ea = ma;  /* Starting value for E. */
00069   double ea_old;
00070   double temp;
00071   double ecc = alm->ecc;
00072   u32 count = 0;
00073 
00074   /* TODO: Implement convergence test using integer difference of doubles,
00075    * http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */
00076   do {
00077     ea_old = ea;
00078     temp = 1.0 - ecc * cos(ea_old);
00079     ea = ea + (ma - ea_old + ecc * sin(ea_old)) / temp;
00080     count++;
00081     if (count > 5)
00082       break;
00083   } while (fabs(ea - ea_old) > 1.0e-14);
00084 
00085   double ea_dot = ma_dot / temp;
00086 
00087   /* Begin calculation for True Anomaly and Argument of Latitude. */
00088   double temp2 = sqrt(1.0 - ecc * ecc);
00089   /* Argument of Latitude = True Anomaly + Argument of Perigee. */
00090   double al = atan2(temp2 * sin(ea), cos(ea) - ecc) + alm->argp;
00091   double al_dot = temp2 * ea_dot / temp;
00092 
00093   /* Calculate corrected radius based on argument of latitude. */
00094   double r = alm->a * temp;
00095   double r_dot = alm->a * ecc * sin(ea) * ea_dot;
00096 
00097   /* Calculate position and velocity in orbital plane. */
00098   double x = r * cos(al);
00099   double y = r * sin(al);
00100   double x_dot = r_dot * cos(al) - y * al_dot;
00101   double y_dot = r_dot * sin(al) + x * al_dot;
00102 
00103   /* Corrected longitude of ascending node. */
00104   double om_dot = alm->rora - GPS_OMEGAE_DOT;
00105   double om = alm->raaw + dt * om_dot - GPS_OMEGAE_DOT * alm->toa;
00106 
00107   /* Compute the satellite's position in Earth-Centered Earth-Fixed
00108    * coordinates. */
00109   pos[0] = x * cos(om) - y * cos(alm->inc) * sin(om);
00110   pos[1] = x * sin(om) + y * cos(alm->inc) * cos(om);
00111   pos[2] = y * sin(alm->inc);
00112 
00113   /* Compute the satellite's velocity in Earth-Centered Earth-Fixed
00114    * coordinates. */
00115   if (vel) {
00116     temp = y_dot * cos(alm->inc);
00117     vel[0] = -om_dot * pos[1] + x_dot * cos(om) - temp * sin(om);
00118     vel[1] =  om_dot * pos[0] + x_dot * sin(om) + temp * cos(om);
00119     vel[2] = y_dot * sin(alm->inc);
00120   }
00121 
00122 }
00123 
00137 void calc_sat_az_el_almanac(almanac_t* alm, double t, s16 week,
00138                             double ref[3], double* az, double* el)
00139 {
00140   double sat_pos[3];
00141   calc_sat_state_almanac(alm, t, week, sat_pos, 0);
00142   wgsecef2azel(sat_pos, ref, az, el);
00143 }
00144 
00157 double calc_sat_doppler_almanac(almanac_t* alm, double t, s16 week,
00158                                 double ref[3])
00159 {
00160   double sat_pos[3];
00161   double sat_vel[3];
00162   double vec_ref_sat[3];
00163 
00164   calc_sat_state_almanac(alm, t, week, sat_pos, sat_vel);
00165 
00166   /* Find the vector from the reference position to the satellite. */
00167   vector_subtract(3, sat_pos, ref, vec_ref_sat);
00168 
00169   /* Find the satellite velocity projected on the line of sight vector from the
00170    * reference position to the satellite. */
00171   double radial_velocity = vector_dot(3, vec_ref_sat, sat_vel) / \
00172                            vector_norm(3, vec_ref_sat);
00173 
00174   /* Return the Doppler shift. */
00175   return GPS_L1_HZ * radial_velocity / GPS_C;
00176 }
00177 


swiftnav
Author(s):
autogenerated on Sat Jun 8 2019 18:55:14