gps.c

Go to the documentation of this file.
00001 /**
00002 \file    gps.c
00003 \brief   GNSS core 'c' function library: GPS specific functions.
00004 \author  Glenn D. MacGougan (GDM)
00005 \date    2005-08-14
00006 \since   2005-07-31
00007 
00008 \b "LICENSE INFORMATION" \n
00009 Copyright (c) 2007, refer to 'author' doxygen tags \n
00010 All rights reserved. \n
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided the following conditions are met: \n
00014 
00015 - Redistributions of source code must retain the above copyright
00016   notice, this list of conditions and the following disclaimer. \n
00017 - Redistributions in binary form must reproduce the above copyright
00018   notice, this list of conditions and the following disclaimer in the
00019   documentation and/or other materials provided with the distribution. \n
00020 - The name(s) of the contributor(s) may not be used to endorse or promote 
00021   products derived from this software without specific prior written 
00022   permission. \n
00023 
00024 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00025 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00026 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00028 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00030 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00031 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00032 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00033 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00034 SUCH DAMAGE.
00035 */
00036 
00037 
00038 #include <math.h>
00039 #include "gnss_error.h"
00040 #include "gps.h"
00041 #include "constants.h"
00042 #include "geodesy.h"
00043 
00044 
00045 /*************************************************************************************************/
00046 // local preprocessor constant definitions, any related enumerations and descriptors
00047 
00048 #ifndef  GPS_CLOCK_CORRECTION_RELATIVISTIC_CONSTANT_F
00049 #define  GPS_CLOCK_CORRECTION_RELATIVISTIC_CONSTANT_F  (-4.442807633e-10)  //!< combined constant defined in ICD-GPS-200C p. 88     [s]/[sqrt(m)]
00050 #endif
00051 #ifndef  GPS_UNIVERSAL_GRAVITY_CONSTANT
00052 #define  GPS_UNIVERSAL_GRAVITY_CONSTANT                (3.986005e14)       //!< gravity constant defined on ICD-GPS-200C p. 98      [m^3/s^2]
00053 #endif
00054 #ifndef  GPS_RATIO_OF_SQUARED_FREQUENCIES_L1_OVER_L2   
00055 #define  GPS_RATIO_OF_SQUARED_FREQUENCIES_L1_OVER_L2   (1.6469444444444444444444444444444) //!< (f_L1/f_L2)^2 = (1575.42/1227.6)^2 = (77/60)^2
00056 #endif
00057 #ifndef  GPS_WGS84_EARTH_ROTATION_RATE
00058 #define  GPS_WGS84_EARTH_ROTATION_RATE                 (7.2921151467e-05)  //!< constant defined on ICD-GPS-200C p. 98            [rad/s]
00059 #endif
00060 
00061 #define TWO_TO_THE_POWER_OF_55  (36028797018963968.0)
00062 #define TWO_TO_THE_POWER_OF_43  (8796093022208.0)
00063 #define TWO_TO_THE_POWER_OF_33  (8589934592.0)
00064 #define TWO_TO_THE_POWER_OF_31  (2147483648.0)
00065 #define TWO_TO_THE_POWER_OF_29  (536870912.0)
00066 #define TWO_TO_THE_POWER_OF_19  (524288.0)
00067 
00068 //
00069 /*************************************************************************************************/
00070 
00071 
00072 
00073 void GPS_ComputeSatelliteClockCorrectionAndDrift(
00074   const unsigned short transmission_gpsweek,   //!< GPS week when signal was transmit (0-1024+)            [weeks]
00075   const double         transmission_gpstow,    //!< GPS time of week when signal was transmit              [s]  
00076   const unsigned short ephem_week,             //!< ephemeris: GPS week (0-1024+)                          [weeks]
00077   const unsigned       toe,                    //!< ephemeris: time of week                                [s]
00078   const unsigned       toc,                    //!< ephemeris: clock reference time of week                [s]
00079   const double         af0,                    //!< ephemeris: polynomial clock correction coefficient     [s],   Note: parameters from ephemeris preferred vs almanac (22 vs 11 bits)
00080   const double         af1,                    //!< ephemeris: polynomial clock correction coefficient     [s/s], Note: parameters from ephemeris preferred vs almanac (16 vs 11 bits)
00081   const double         af2,                    //!< ephemeris: polynomial clock correction coefficient     [s/s^2]  
00082   const double         ecc,                    //!< ephemeris: eccentricity of satellite orbit             []
00083   const double         sqrta,                  //!< ephemeris: square root of the semi-major axis of orbit [m^(1/2)]
00084   const double         delta_n,                //!< ephemeris: mean motion difference from computed value  [rad]
00085   const double         m0,                     //!< ephemeris: mean anomaly at reference time              [rad]
00086   const double         tgd,                    //!< ephemeris: group delay differential between L1 and L2  [s]
00087   const unsigned char  mode,                   //!< 0=L1 only, 1=L2 only (see p. 90, ICD-GPS-200C)
00088   double*  clock_correction,  //!< satellite clock correction       [m]
00089   double*  clock_drift        //!< satellite clock drift correction [m/s]
00090    )
00091 {               
00092   unsigned char i; // counter 
00093 
00094   double tot;    // time of transmission (including gps week) [s] 
00095   double tk;     // time from ephemeris reference epoch       [s]
00096   double tc;     // time from clock reference epoch           [s]
00097   double d_tr;   // relativistic correction term              [s]
00098   double d_tsv;  // SV PRN code phase time offset             [s]
00099   double a;      // semi-major axis of orbit                  [m]
00100   double n;      // corrected mean motion                     [rad/s]
00101   double M;      // mean anomaly,                             [rad]   (Kepler's equation for eccentric anomaly, solved by iteration)
00102   double E;      // eccentric anomaly                         [rad]      
00103 
00104   // compute the times from the reference epochs 
00105   // By including the week in the calculation, week rollover and old ephmeris bugs are mitigated
00106   // The result should be between -302400 and 302400 if the ephemeris is within one week of transmission   
00107   tot = transmission_gpsweek*SECONDS_IN_WEEK + transmission_gpstow;
00108   tk  = tot - (ephem_week*SECONDS_IN_WEEK + toe);
00109   tc  = tot - (ephem_week*SECONDS_IN_WEEK + toc);
00110 
00111   // compute the corrected mean motion term
00112   a = sqrta*sqrta;
00113   n = sqrt( GPS_UNIVERSAL_GRAVITY_CONSTANT / (a*a*a) ); // computed mean motion
00114   n += delta_n; // corrected mean motion
00115   
00116   // Kepler's equation for eccentric anomaly 
00117   M = m0 + n*tk; // mean anomaly
00118   E = M;
00119   for( i = 0; i < 7; i++ )
00120   {
00121     E = M + ecc * sin(E);
00122   }
00123  
00124   // relativistic correction
00125   d_tr = GPS_CLOCK_CORRECTION_RELATIVISTIC_CONSTANT_F * ecc * sqrta * sin(E); // [s]
00126   d_tr *= LIGHTSPEED;
00127 
00128   // clock correcton 
00129   d_tsv = af0 + af1*tc + af2*tc*tc; // [s]
00130         
00131   if( mode == 0 ) 
00132   {
00133     // L1 only
00134     d_tsv -= tgd; // [s]
00135   }
00136   else if( mode == 1 ) 
00137   {
00138     // L2 only
00139     d_tsv -= tgd*GPS_RATIO_OF_SQUARED_FREQUENCIES_L1_OVER_L2; // [s]
00140   }
00141 
00142   // clock correction
00143   *clock_correction = d_tsv*LIGHTSPEED + d_tr; // [m]
00144 
00145   // clock drift
00146   *clock_drift = (af1 + 2.0*af2*tc) * LIGHTSPEED; // [m/s]
00147 }
00148 
00149 
00150 
00151 
00152 void GPS_ComputeSatellitePositionAndVelocity( 
00153   const unsigned short transmission_gpsweek,   //!< GPS week when signal was transmit (0-1024+)                                              [weeks]
00154   const double         transmission_gpstow,    //!< GPS time of week when signal was transmit                                                [s]  
00155   const unsigned short ephem_week,             //!< ephemeris: GPS week (0-1024+)                                                            [weeks]
00156   const unsigned       toe,                    //!< ephemeris: time of week                                                                  [s]
00157   const double         m0,                     //!< ephemeris: mean anomaly at reference time                                                [rad]
00158   const double         delta_n,                //!< ephemeris: mean motion difference from computed value                                    [rad]
00159   const double         ecc,                    //!< ephemeris: eccentricity                                                                  []
00160   const double         sqrta,                  //!< ephemeris: square root of the semi-major axis                                            [m^(1/2)]
00161   const double         omega0,                 //!< ephemeris: longitude of ascending node of orbit plane at weekly epoch                    [rad]
00162   const double         i0,                     //!< ephemeris: inclination angle at reference time                                           [rad]
00163   const double         w,                      //!< ephemeris: argument of perigee                                                           [rad]
00164   const double         omegadot,               //!< ephemeris: rate of right ascension                                                       [rad/s]
00165   const double         idot,                   //!< ephemeris: rate of inclination angle                                                     [rad/s]
00166   const double         cuc,                    //!< ephemeris: amplitude of the cosine harmonic correction term to the argument of latitude  [rad]
00167   const double         cus,                    //!< ephemeris: amplitude of the sine   harmonic correction term to the argument of latitude  [rad]
00168   const double         crc,                    //!< ephemeris: amplitude of the cosine harmonic correction term to the orbit radius          [m]
00169   const double         crs,                    //!< ephemeris: amplitude of the sine   harmonic correction term to the orbit radius          [m]
00170   const double         cic,                    //!< ephemeris: amplitude of the cosine harmonic correction term to the angle of inclination  [rad]
00171   const double         cis,                    //!< ephemeris: amplitude of the sine   harmonic correction term to the angle of inclination  [rad]
00172   const double         estimateOfTrueRange,    //!< best estimate of the signal propagation time (in m) for Sagnac effect compensation       [m]
00173   const double         estimteOfRangeRate,     //!< best estimate of the true signal Doppler (in m/s)   for Sagnac effect compensation       [m/s]
00174   double* x,  //!< satellite x            [m]
00175   double* y,  //!< satellite y            [m]
00176   double* z,  //!< satellite z            [m] 
00177   double* vx, //!< satellite velocity x   [m/s]
00178   double* vy, //!< satellite velocity y   [m/s]
00179   double* vz  //!< satellite velocity z   [m/s]
00180  )
00181 {
00182   unsigned char j; // counter 
00183 
00184   double tot;        // time of transmission (including gps week) [s] 
00185   double tk;         // time from ephemeris reference epoch       [s]
00186   double a;          // semi-major axis of orbit                  [m]
00187   double n;          // corrected mean motion                     [rad/s]
00188   double M;          // mean anomaly,                             [rad]   (Kepler's equation for eccentric anomaly, solved by iteration)
00189   double E;          // eccentric anomaly                         [rad]      
00190   double v;          // true anomaly                              [rad]
00191   double u;          // argument of latitude, corrected           [rad]
00192   double r;          // radius in the orbital plane               [m]
00193   double i;          // orbital inclination                       [rad]
00194   double cos2u;      // cos(2*u)                                  []
00195   double sin2u;      // sin(2*u)                                  []
00196   double d_u;        // argument of latitude correction           [rad]
00197   double d_r;        // radius correction                         [m]
00198   double d_i;        // inclination correction                    [rad]
00199   double x_op;       // x position in the orbital plane           [m]
00200   double y_op;       // y position in the orbital plane           [m]
00201   double omegak;     // corrected longitude of the ascending node [rad]
00202   double cos_omegak; // cos(omegak)
00203   double sin_omegak; // sin(omegak)
00204   double cosu;       // cos(u)
00205   double sinu;       // sin(u)
00206   double cosi;       // cos(i)
00207   double sini;       // sin(i)
00208   double cosE;       // cos(E)
00209   double sinE;       // sin(E)
00210   double omegadotk;  // corrected rate of right ascension         [rad/s]
00211   double edot;       // edot = n/(1.0 - ecc*cos(E)),              [rad/s] 
00212   double vdot;       // d/dt of true anomaly                      [rad/s]
00213   double udot;       // d/dt of argument of latitude              [rad/s]
00214   double idotdot;    // d/dt of the rate of the inclination angle [rad/s^2]
00215   double rdot;       // d/dt of the radius in the orbital plane   [m/s]
00216   double tmpa;       // temp
00217   double tmpb;       // temp
00218   double vx_op;      // x velocity in the orbital plane           [m/s]
00219   double vy_op;      // y velocity in the orbital plane           [m/s]
00220          
00221 
00222   // compute the times from the reference epochs 
00223   // By including the week in the calculation, week rollover and older ephemeris bugs are mitigated
00224   // The result should be between -302400 and 302400 if the ephemeris is within one week of transmission   
00225   tot = transmission_gpsweek*SECONDS_IN_WEEK + transmission_gpstow;
00226   tk  = tot - (ephem_week*SECONDS_IN_WEEK + toe);
00227   
00228   // compute the corrected mean motion term
00229   a = sqrta*sqrta;
00230   n = sqrt( GPS_UNIVERSAL_GRAVITY_CONSTANT / (a*a*a) ); // computed mean motion
00231   n += delta_n; // corrected mean motion
00232   
00233   // Kepler's equation for eccentric anomaly 
00234   M = m0 + n*tk; // mean anomaly
00235   E = M;
00236   for( j = 0; j < 7; j++ )
00237   {
00238     E = M + ecc * sin(E);
00239   }
00240 
00241   cosE = cos(E);
00242   sinE = sin(E);
00243  
00244   // true anomaly
00245   v = atan2( (sqrt(1.0 - ecc*ecc)*sinE),  (cosE - ecc) );
00246 
00247   // argument of latitude
00248   u = v + w;
00249   // radius in orbital plane
00250   r = a * (1.0 - ecc * cos(E)); 
00251   // orbital inclination
00252   i = i0;
00253 
00254   // second harmonic perturbations
00255   //
00256   cos2u = cos(2.0*u);
00257   sin2u = sin(2.0*u);
00258   // argument of latitude correction  
00259   d_u = cuc * cos2u  +  cus * sin2u; 
00260   // radius correction  
00261   d_r = crc * cos2u  +  crs * sin2u; 
00262   // correction to inclination
00263   d_i = cic * cos2u  +  cis * sin2u;
00264 
00265   // corrected argument of latitude
00266   u += d_u;
00267   // corrected radius
00268   r += d_r;
00269   // corrected inclination
00270   i += d_i + idot * tk;
00271 
00272   // positions in orbital plane
00273   cosu = cos(u);
00274   sinu = sin(u);
00275   x_op = r * cosu;
00276   y_op = r * sinu;
00277 
00278 
00279   // compute the corrected longitude of the ascending node
00280   // This equation deviates from that in Table 20-IV p. 100 GPSICD200C with the inclusion of the 
00281   // signal propagation time (estimateOfTrueRange/LIGHTSPEED) term. This compensates for the Sagnac effect.
00282   // The omegak term is thus sensitive to the estimateOfTrueRange term which is usually unknown without
00283   // prior information. The average signal propagation time/range (70ms * c) can be used on first use
00284   // and this function must be called again to iterate this term. The sensitivity of the omegak term
00285   // typically requires N iterations - GDM_DEBUG{find out how many iterations are needed, how sensitive to the position?}
00286   omegak = omega0 + (omegadot - GPS_WGS84_EARTH_ROTATION_RATE)*tk - GPS_WGS84_EARTH_ROTATION_RATE*(toe + estimateOfTrueRange/LIGHTSPEED );
00287 
00288   // compute the WGS84 ECEF coordinates, 
00289   // vector r with components x & y is now rotated using, R3(-omegak)*R1(-i)
00290   cos_omegak = cos(omegak);
00291   sin_omegak = sin(omegak);
00292   cosi = cos(i);
00293   sini = sin(i);
00294   *x = x_op * cos_omegak - y_op * sin_omegak * cosi;
00295   *y = x_op * sin_omegak + y_op * cos_omegak * cosi;
00296   *z = y_op * sini;
00297 
00298   
00299   // Satellite Velocity Computations are below
00300   // see Reference
00301   // Remodi, B. M (2004). GPS Tool Box: Computing satellite velocities using the broadcast ephemeris. 
00302   // GPS Solutions. Volume 8(3), 2004. pp. 181-183 
00303   //
00304   // example source code was available at [http://www.ngs.noaa.gov/gps-toolbox/bc_velo/bc_velo.c]  
00305 
00306   // recomputed the cos and sin of the corrected argument of latitude
00307   cos2u = cos(2.0*u);
00308   sin2u = sin(2.0*u);
00309     
00310   edot  = n / (1.0 - ecc*cosE);
00311   vdot  = sinE*edot*(1.0 + ecc*cos(v)) / ( sin(v)*(1.0-ecc*cosE) );  
00312   udot  = vdot + 2.0*(cus*cos2u - cuc*sin2u)*vdot;
00313   rdot  = a*ecc*sinE*n/(1.0-ecc*cosE) + 2.0*(crs*cos2u - crc*sin2u)*vdot;
00314   idotdot = idot + (cis*cos2u - cic*sin2u)*2.0*vdot;    
00315     
00316   vx_op = rdot*cosu - y_op*udot;
00317   vy_op = rdot*sinu + x_op*udot;
00318 
00319   // corrected rate of right ascension including similarily as above, for omegak, 
00320   // compensation for the Sagnac effect
00321   omegadotk = omegadot - GPS_WGS84_EARTH_ROTATION_RATE*( 1.0 + estimteOfRangeRate/LIGHTSPEED );
00322   
00323   tmpa = vx_op - y_op*cosi*omegadotk;  
00324   tmpb = x_op*omegadotk + vy_op*cosi - y_op*sini*idotdot;
00325     
00326   *vx = tmpa * cos_omegak - tmpb * sin_omegak;  
00327   *vy = tmpa * sin_omegak + tmpb * cos_omegak;  
00328   *vz = vy_op*sini + y_op*cosi*idotdot;  
00329 }
00330 
00331 
00332 void GPS_ComputeUserToSatelliteRange( 
00333   const double userX,    //!< user X position WGS84 ECEF         [m]
00334   const double userY,    //!< user Y position WGS84 ECEF         [m]
00335   const double userZ,    //!< user Z position WGS84 ECEF         [m]
00336   const double satX,     //!< satellite X position WGS84 ECEF    [m]
00337   const double satY,     //!< satellite Y positoin WGS84 ECEF    [m]
00338   const double satZ,     //!< satellite Z position WGS84 ECEF    [m] 
00339   double* range          //!< user to satellite range            [m]
00340   )
00341 {
00342   double dx;
00343   double dy;
00344   double dz;
00345          
00346   dx = satX - userX;
00347   dy = satY - userY;
00348   dz = satZ - userZ;
00349 
00350   // compute the range
00351   *range = sqrt( dx*dx + dy*dy + dz*dz );
00352 }
00353 
00354 
00355 void GPS_ComputeUserToSatelliteRangeAndRangeRate( 
00356   const double userX,    //!< user X position WGS84 ECEF         [m]
00357   const double userY,    //!< user Y position WGS84 ECEF         [m]
00358   const double userZ,    //!< user Z position WGS84 ECEF         [m]
00359   const double userVx,   //!< user X velocity WGS84 ECEF         [m/s]
00360   const double userVy,   //!< user Y velocity WGS84 ECEF         [m/s]
00361   const double userVz,   //!< user Z velocity WGS84 ECEF         [m/s]
00362   const double satX,     //!< satellite X position WGS84 ECEF    [m]
00363   const double satY,     //!< satellite Y positoin WGS84 ECEF    [m]
00364   const double satZ,     //!< satellite Z position WGS84 ECEF    [m] 
00365   const double satVx,    //!< satellite X velocity WGS84 ECEF    [m/s]
00366   const double satVy,    //!< satellite Y velocity WGS84 ECEF    [m/s]
00367   const double satVz,    //!< satellite Z velocity WGS84 ECEF    [m/s]
00368   double* range,         //!< user to satellite range            [m]
00369   double* range_rate     //!< user to satellite range rate       [m/s]
00370   )
00371 {
00372   double dx;
00373   double dy;
00374   double dz;
00375          
00376   dx = satX - userX;
00377   dy = satY - userY;
00378   dz = satZ - userZ;
00379 
00380   // compute the range
00381   *range = sqrt( dx*dx + dy*dy + dz*dz );
00382   
00383   // compute the range rate
00384   // this method uses the NovAtel style sign convention!
00385   *range_rate = (userVx - satVx)*dx + (userVy - satVy)*dy + (userVz - satVz)*dz;
00386   *range_rate /= *range;      
00387 }
00388 
00389 
00390 
00391 void GPS_ComputeSatellitePositionVelocityAzimuthElevationDoppler_BasedOnAlmanacData(
00392   const double         userX,        //!< user X position WGS84 ECEF                                   [m]
00393   const double         userY,        //!< user Y position WGS84 ECEF                                   [m]
00394   const double         userZ,        //!< user Z position WGS84 ECEF                                   [m]
00395   const unsigned short gpsweek,      //!< user gps week (0-1024+)                                      [week]
00396   const double         gpstow,       //!< user time of week                                            [s]
00397   const double         toa,          //!< time of applicability                                        [s]  
00398   const unsigned short almanac_week, //!< gps week of almanac (0-1024+)                                [week]
00399   const unsigned short prn,          //!< GPS prn number                                               []
00400   const double         ecc,          //!< eccentricity                                                 []
00401   const double         i0,           //!< orbital inclination at reference time                        [rad]
00402   const double         omegadot,     //!< rate of right ascension                                      [rad/s]
00403   const double         sqrta,        //!< square root of the semi-major axis                           [m^(1/2)]
00404   const double         omega0,       //!< longitude of ascending node of orbit plane at weekly epoch   [rad]
00405   const double         w,            //!< argument of perigee                                          [rad]
00406   const double         m0,           //!< mean anomaly at reference time                               [rad]
00407   const double         af0,          //!< polynomial clock correction coefficient (clock bias)         [s],   Note: parameters from ephemeris preferred vs almanac (22 vs 11 bits)
00408   const double         af1,          //!< polynomial clock correction coefficient (clock drift)        [s/s], Note: parameters from ephemeris preferred vs almanac (16 vs 11 bits)
00409   double* clock_correction,  //!< clock correction for this satellite for this epoch           [m]
00410   double* clock_drift,       //!< clock drift correction for this satellite for this epoch     [m/s]
00411   double* satX,              //!< satellite X position WGS84 ECEF                              [m]
00412   double* satY,              //!< satellite Y position WGS84 ECEF                              [m]
00413   double* satZ,              //!< satellite Z position WGS84 ECEF                              [m]
00414   double* satVx,             //!< satellite X velocity WGS84 ECEF                              [m/s]
00415   double* satVy,             //!< satellite Y velocity WGS84 ECEF                              [m/s]
00416   double* satVz,             //!< satellite Z velocity WGS84 ECEF                              [m/s]
00417   double* azimuth,           //!< satelilte azimuth                                            [rad]
00418   double* elevation,         //!< satelilte elevation                                          [rad]
00419   double* doppler            //!< satellite doppler with respect to the user position          [m/s], Note: User must convert to Hz
00420   )
00421 {
00422   double tow;        // user time of week adjusted with the clock corrections [s]
00423   double range;      // range estimate between user and satellite             [m]
00424   double range_rate; // range_rate esimate between user and satellite         [m/s]
00425   double x;          // sat X position [m]
00426   double y;          // sat Y position [m]
00427   double z;          // sat Z position [m]
00428   double vx;         // sat X velocity [m/s]
00429   double vy;         // sat Y velocity [m/s]
00430   double vz;         // sat Z velocity [m/s]
00431 
00432   unsigned short week; // user week adjusted with the clock correction if needed [week]
00433 
00434   unsigned char i; // counter
00435 
00436   i = (unsigned char)prn; // get rid of a debug msg :)
00437 
00438   // initialize to zero
00439   x = y = z = vx = vy = vz = 0.0;
00440 
00441   GPS_ComputeSatelliteClockCorrectionAndDrift(
00442     gpsweek,
00443     gpstow,
00444     almanac_week,
00445     (unsigned)toa,
00446     (unsigned)toa,
00447     af0,
00448     af1,
00449     0.0,
00450     ecc,
00451     sqrta,
00452     0.0,
00453     m0,
00454     0.0,
00455     0,
00456     clock_correction,
00457     clock_drift );
00458 
00459   // adjust for week rollover  
00460   week = gpsweek;
00461   tow = gpstow + (*clock_correction)/LIGHTSPEED;
00462   if( tow < 0.0 )
00463   {
00464     tow += SECONDS_IN_WEEK;
00465     week--;
00466   }
00467   if( tow > 604800.0 )
00468   {
00469     tow -= SECONDS_IN_WEEK;
00470     week++;
00471   }
00472 
00473   // iterate to include the Sagnac correction
00474   // since the range is unknown, an approximate of 70 ms is good enough 
00475   // to start the iterations so that 2 iterations are enough
00476   range = 0.070*LIGHTSPEED; 
00477   range_rate = 0.0;
00478   for( i = 0; i < 2; i++ )
00479   {
00480     GPS_ComputeSatellitePositionAndVelocity(
00481       week,
00482       tow,
00483       almanac_week,
00484       (unsigned)toa,
00485       m0,
00486       0.0,
00487       ecc,
00488       sqrta,
00489       omega0,
00490       i0,
00491       w,
00492       omegadot,
00493       0.0,
00494       0.0,
00495       0.0,
00496       0.0,
00497       0.0,
00498       0.0,
00499       0.0,
00500       range,
00501       range_rate,
00502       &x,
00503       &y,
00504       &z,
00505       &vx,
00506       &vy,
00507       &vz );
00508 
00509     GPS_ComputeUserToSatelliteRangeAndRangeRate(
00510       userX,
00511       userY,
00512       userZ,
00513       0.0,
00514       0.0,
00515       0.0,
00516       x,
00517       y,
00518       z,
00519       vx,
00520       vy,
00521       vz,
00522       &range,
00523       &range_rate );    
00524   }
00525 
00526   GEODESY_ComputeAzimuthAndElevationAnglesBetweenToPointsInTheEarthFixedFrame(
00527     GEODESY_REFERENCE_ELLIPSE_WGS84,
00528     userX,
00529     userY,
00530     userZ,
00531     x,
00532     y,
00533     z,
00534     elevation, // sets the elevation 
00535     azimuth ); // sets the azimuth
00536 
00537   *satX = x;
00538   *satY = y;
00539   *satZ = z;
00540   *satVx = vx;
00541   *satVy = vy;
00542   *satVz = vz;
00543   
00544   *doppler = range_rate;
00545 
00546 }
00547 
00548 
00549 
00550 void GPS_ComputeSatellitePositionVelocityAzimuthElevationDoppler_BasedOnEphmerisData(
00551   const double         userX,        //!< user X position WGS84 ECEF  [m]
00552   const double         userY,        //!< user Y position WGS84 ECEF  [m]
00553   const double         userZ,        //!< user Z position WGS84 ECEF  [m]
00554   const unsigned short gpsweek,      //!< gps week of signal transmission (0-1024+)                              [week]
00555   const double         gpstow,       //!< time of week of signal transmission  (gpstow-psr/c)                    [s]
00556   const unsigned short ephem_week,   //!< ephemeris: GPS week (0-1024+)                                          [weeks]
00557   const unsigned       toe,          //!< ephemeris: time of week                                                [s]
00558   const unsigned       toc,          //!< ephemeris: clock reference time of week                                [s]
00559   const double         af0,          //!< ephemeris: polynomial clock correction coefficient                     [s],   Note: parameters from ephemeris preferred vs almanac (22 vs 11 bits)
00560   const double         af1,          //!< ephemeris: polynomial clock correction coefficient                     [s/s], Note: parameters from ephemeris preferred vs almanac (16 vs 11 bits)
00561   const double         af2,          //!< ephemeris: polynomial clock correction coefficient                     [s/s^2]  
00562   const double         tgd,          //!< ephemeris: group delay differential between L1 and L2                  [s]
00563   const double         m0,           //!< ephemeris: mean anomaly at reference time                              [rad]
00564   const double         delta_n,      //!< ephemeris: mean motion difference from computed value                  [rad/s]
00565   const double         ecc,          //!< ephemeris: eccentricity                                                []
00566   const double         sqrta,        //!< ephemeris: square root of the semi-major axis                          [m^(1/2)]
00567   const double         omega0,       //!< ephemeris: longitude of ascending node of orbit plane at weekly epoch  [rad]
00568   const double         i0,           //!< ephemeris: inclination angle at reference time                         [rad]
00569   const double         w,            //!< ephemeris: argument of perigee                                         [rad]
00570   const double         omegadot,     //!< ephemeris: rate of right ascension                                     [rad/s]
00571   const double         idot,         //!< ephemeris: rate of inclination angle                                   [rad/s]
00572   const double         cuc,          //!< ephemeris: amplitude of the cosine harmonic correction term to the argument of latitude  [rad]
00573   const double         cus,          //!< ephemeris: amplitude of the sine   harmonic correction term to the argument of latitude  [rad]
00574   const double         crc,          //!< ephemeris: amplitude of the cosine harmonic correction term to the orbit radius          [m]
00575   const double         crs,          //!< ephemeris: amplitude of the sine   harmonic correction term to the orbit radius          [m]
00576   const double         cic,          //!< ephemeris: amplitude of the cosine harmonic correction term to the angle of inclination  [rad]
00577   const double         cis,          //!< ephemeris: amplitude of the sine   harmonic correction term to the angle of inclination  [rad]
00578   double* clock_correction,  //!< clock correction for this satellite for this epoch           [m]
00579   double* clock_drift,       //!< clock drift correction for this satellite for this epoch     [m/s]
00580   double* satX,              //!< satellite X position WGS84 ECEF                              [m]
00581   double* satY,              //!< satellite Y position WGS84 ECEF                              [m]
00582   double* satZ,              //!< satellite Z position WGS84 ECEF                              [m]
00583   double* satVx,             //!< satellite X velocity WGS84 ECEF                              [m/s]
00584   double* satVy,             //!< satellite Y velocity WGS84 ECEF                              [m/s]
00585   double* satVz,             //!< satellite Z velocity WGS84 ECEF                              [m/s]
00586   double* azimuth,           //!< satelilte azimuth                                            [rad]
00587   double* elevation,         //!< satelilte elevation                                          [rad]
00588   double* doppler            //!< satellite doppler with respect to the user position          [m/s], Note: User must convert to Hz
00589   )
00590 {
00591   double tow;         // user time of week adjusted with the clock corrections [s]
00592   double range;       // range estimate between user and satellite             [m]
00593   double range_rate;  // range_rate esimate between user and satellite         [m/s]
00594   double x;           // sat X position [m]
00595   double y;           // sat Y position [m]
00596   double z;           // sat Z position [m]
00597   double vx;          // sat X velocity [m/s]
00598   double vy;          // sat Y velocity [m/s]
00599   double vz;          // sat Z velocity [m/s]
00600 
00601   unsigned short week; // user week adjusted with the clock correction if needed [week]
00602 
00603   unsigned char i; // counter
00604 
00605   // initialize to zero
00606   x = y = z = vx = vy = vz = 0.0;
00607 
00608   GPS_ComputeSatelliteClockCorrectionAndDrift(
00609     gpsweek,
00610     gpstow,
00611     ephem_week,
00612     toe,
00613     toc,
00614     af0,
00615     af1,
00616     af2,
00617     ecc,
00618     sqrta,
00619     delta_n,
00620     m0,
00621     tgd,
00622     0,
00623     clock_correction,
00624     clock_drift );
00625 
00626   // adjust for week rollover  
00627   week = gpsweek;
00628   tow = gpstow + (*clock_correction)/LIGHTSPEED;
00629   if( tow < 0.0 )
00630   {
00631     tow += SECONDS_IN_WEEK;
00632     week--;
00633   }
00634   if( tow > 604800.0 )
00635   {
00636     tow -= SECONDS_IN_WEEK;
00637     week++;
00638   }
00639 
00640   // iterate to include the Sagnac correction
00641   // since the range is unknown, an approximate of 70 ms is good enough to start 
00642   // the iterations so that 2 iterations are enough for sub mm accuracy
00643   range = 0.070*LIGHTSPEED; 
00644   range_rate = 0.0;
00645   for( i = 0; i < 2; i++ )
00646   {
00647     GPS_ComputeSatellitePositionAndVelocity(
00648       week,
00649       tow,
00650       ephem_week,
00651       toe,
00652       m0,
00653       delta_n,
00654       ecc,
00655       sqrta,
00656       omega0,
00657       i0,
00658       w,
00659       omegadot,
00660       idot,
00661       cuc,
00662       cus,
00663       crc,
00664       crs,
00665       cic,
00666       cis,
00667       range,
00668       range_rate,
00669       &x,
00670       &y,
00671       &z,
00672       &vx,
00673       &vy,
00674       &vz );
00675 
00676     GPS_ComputeUserToSatelliteRangeAndRangeRate(
00677       userX,
00678       userY,
00679       userZ,
00680       0.0,
00681       0.0,
00682       0.0,
00683       x,
00684       y,
00685       z,
00686       vx,
00687       vy,
00688       vz,
00689       &range,
00690       &range_rate );    
00691   }
00692 
00693   GEODESY_ComputeAzimuthAndElevationAnglesBetweenToPointsInTheEarthFixedFrame(
00694     GEODESY_REFERENCE_ELLIPSE_WGS84,
00695     userX,
00696     userY,
00697     userZ,
00698     x,
00699     y,
00700     z,
00701     elevation, // sets the elevation 
00702     azimuth ); // sets the azimuth
00703 
00704   *satX = x;
00705   *satY = y;
00706   *satZ = z;
00707   *satVx = vx;
00708   *satVy = vy;
00709   *satVz = vz;
00710   
00711   *doppler = range_rate;
00712 }
00713 
00714 
00715 BOOL GPS_DecodeRawGPSEphemeris( 
00716   const unsigned char subframe1[30],  //!< subframe 1 data, 30 bytes * 8bits/byte = 240 bits, thus parity bits have been removed
00717   const unsigned char subframe2[30],  //!< subframe 2 data, 30 bytes * 8bits/byte = 240 bits, thus parity bits have been removed
00718   const unsigned char subframe3[30],  //!< subframe 3 data, 30 bytes * 8bits/byte = 240 bits, thus parity bits have been removed
00719   unsigned short  prn,                //!< GPS PRN number (helps with debugging)
00720   unsigned*       tow,                //!< time of week in subframe1, the time of the leading bit edge of subframe 2     [s]
00721   unsigned short* iodc,               //!< 10 bit issue of data (clock), 8 LSB bits will match the iode                  []    
00722   unsigned char*  iode,               //!< 8 bit  issue of data (ephemeris)                                              []
00723   unsigned*       toe,                //!< reference time ephemeris (0-604800)                                           [s]
00724   unsigned*       toc,                //!< reference time (clock)   (0-604800)                                           [s]      
00725   unsigned short* week,               //!< 10 bit gps week 0-1023 (user must account for week rollover )                 [week]    
00726   unsigned char*  health,             //!< 6 bit health parameter, 0 if healthy, unhealth othersize                      [0=healthy]    
00727   unsigned char*  alert_flag,         //!< 1 = URA may be worse than indicated                                           [0,1]
00728   unsigned char*  anti_spoof,         //!< anti-spoof flag from 0=off, 1=on                                              [0,1]    
00729   unsigned char*  code_on_L2,         //!< 0=reserved, 1=P code on L2, 2=C/A on L2                                       [0,1,2]
00730   unsigned char*  ura,                //!< User Range Accuracy lookup code, 0 is excellent, 15 is use at own risk        [0-15], see p. 83 GPSICD200C
00731   unsigned char*  L2_P_data_flag,     //!< flag indicating if P is on L2 1=true                                          [0,1]
00732   unsigned char*  fit_interval_flag,  //!< fit interval flag (four hour interval or longer) 0=4 fours, 1=greater         [0,1]
00733   unsigned short* age_of_data_offset, //!< age of data offset                                                            [s]
00734   double* tgd,                //!< group delay                                                                   [s]
00735   double* af2,                //!< polynomial clock correction coefficient (rate of clock drift)                 [s/s^2]
00736   double* af1,                //!< polynomial clock correction coefficient (clock drift)                         [s/s]
00737   double* af0,                //!< polynomial clock correction coefficient (clock bias)                          [s]    
00738   double* m0,                 //!< mean anomaly at reference time                                                [rad]
00739   double* delta_n,            //!< mean motion difference from computed value                                    [rad/s]
00740   double* ecc,                //!< eccentricity                                                                  []
00741   double* sqrta,              //!< square root of the semi-major axis                                            [m^(1/2)]
00742   double* omega0,             //!< longitude of ascending node of orbit plane at weekly epoch                    [rad]
00743   double* i0,                 //!< inclination angle at reference time                                           [rad]
00744   double* w,                  //!< argument of perigee                                                           [rad]
00745   double* omegadot,           //!< rate of right ascension                                                       [rad/s]
00746   double* idot,               //!< rate of inclination angle                                                     [rad/s]
00747   double* cuc,                //!< amplitude of the cosine harmonic correction term to the argument of latitude  [rad]
00748   double* cus,                //!< amplitude of the sine harmonic correction term to the argument of latitude    [rad]
00749   double* crc,                //!< amplitude of the cosine harmonic correction term to the orbit radius          [m]
00750   double* crs,                //!< amplitude of the sine harmonic correction term to the orbit radius            [m]
00751   double* cic,                //!< amplitude of the cosine harmonic correction term to the angle of inclination  [rad]
00752   double* cis                 //!< amplitude of the sine harmonic correction term to the angle of inclination    [rad]
00753    )
00754 {
00755 /*
00756 ------------------------------------------------------------------
00757                            SUBFRAME1
00758 ------------------------------------------------------------------
00759 TERM,               NR BITS,    BITS NO PARITY,   BITS WITH PARITY
00760 preamble,           8,          1-8,              1-8,
00761 TLM,                14,         9-22,             9-22
00762 reserved,           2,          23-24,            23-24
00763 --PARITY--          6,          -----             25-30
00764 TOW,                17,         25-41,            31-47
00765 alert_flag,         1,          42,               48
00766 anti_spoof_flag,    1,          43,               49
00767 subframeID,         3,          44-46,            50-52
00768 parity_related,     2,          47-48,            53-54
00769 --PARITY--          6,          -----             25-30
00770 week,               10,         49-58,            61-70
00771 code_on_L2,         2,          59,60,            71-72
00772 ura,                4,          61-64,            73-76
00773 health,             6,          65-70,            77-82
00774 iodc_MSB,           2,          71-72,            83-84
00775 --PARITY--          6,          -----             85-90
00776 L2_P_data_flag,     1,          73,               91
00777 reserved,           23,         74-96,            92-114
00778 --PARITY--          6,          -----             115-120
00779 reserved,           24,         97-120,           121-144
00780 --PARITY--          6,          -----             25-30
00781 reserved,           24,         121-144,          151-174
00782 --PARITY--          6,          -----             25-30
00783 reserved,           16,         145-160,          181-196
00784 tgd,                8,          161-168,          197-204
00785 --PARITY--          6,          -----             205-210
00786 iodc_LSB,           8,          169-176,          211-218
00787 toc,                16,         177-192,          219-234
00788 --PARITY--          6,          -----             235-240
00789 af2,                8,          193-200,          241-248
00790 af1,                16,         201-216,          249-264
00791 --PARITY--          6,          -----             265-270
00792 af0,                22,         217-238,          271-292
00793 parity_related,     2,          239-240,          293-294
00794 --PARITY--          6,          -----             295-300
00795 ------------------------------------------------------------------
00796                            SUBFRAME2
00797 ------------------------------------------------------------------
00798 TERM,               NR BITS,    BITS NO PARITY,   BITS WITH PARITY
00799 preamble,           8,          1-8,              1-8,
00800 TLM,                14,         9-22,             9-22
00801 reserved,           2,          23-24,            23-24
00802 --PARITY--          6,          -----             25-30
00803 TOW,                17,         25-41,            31-47
00804 alert_flag,         1,          42,               48
00805 anti_spoof_flag,    1,          43,               49
00806 subframeID,         3,          44-46,            50-52
00807 parity_related,     2,          47-48,            53-54
00808 --PARITY--          6,          -----             25-30
00809 iode,               8,          49-56,            61-68
00810 crs,                16,         57-72,            69-84
00811 --PARITY--          6,          -----             95-90
00812 delta_n,            16,         73-88,            91-106
00813 m0_MSB,             8,          89-96,            107-114
00814 --PARITY--          6,          -----             115-120
00815 m0_LSB,             24,         97-120,           121-144
00816 --PARITY--          6,          -----             145-150
00817 cuc,                16,         121-136,          151-166
00818 ecc_MSB,            8,          137-144,          167-174
00819 --PARITY--          6,          -----             175-180
00820 ecc_LSB,            24,         145-168,          181-204
00821 --PARITY--          6,          -----             205-210
00822 cus,                16,         169-184,          211-226
00823 sqrta_MSB,          8,          185-192,          227-234
00824 --PARITY--          6,          -----             235-240
00825 sqrta_LSB,          24,         193-216,          241-264
00826 --PARITY--          6,          -----             265-270
00827 toe,                16,         217-232,          271-286
00828 fit_interval_flag,  1,          233,              287
00829 age_of_data_offset, 5,          234-238,          288-292
00830 parity_related,     2,          239-240,          293-294
00831 --PARITY--          6,          -----             295-300
00832 ------------------------------------------------------------------
00833                            SUBFRAME3
00834 ------------------------------------------------------------------
00835 TERM,               NR BITS,    BITS NO PARITY,   BITS WITH PARITY
00836 preamble,           8,          1-8,              1-8,
00837 TLM,                14,         9-22,             9-22
00838 reserved,           2,          23-24,            23-24
00839 --PARITY--          6,          -----             25-30
00840 TOW,                17,         25-41,            31-47
00841 alert_flag,         1,          42,               48
00842 anti_spoof_flag,    1,          43,               49
00843 subframeID,         3,          44-46,            50-52
00844 parity_related,     2,          47-48,            53-54
00845 --PARITY--          6,          -----             25-30
00846 cic,                16,         49-64,            61-76
00847 omega0_MSB,         8,          65-72,            77-84
00848 --PARITY--          6,          -----             85-90
00849 omega0_LSB,         24,         73-96,            91-114
00850 --PARITY--          6,          -----             115-120
00851 cis,                16,         97-112,           121-136
00852 i0_MSB,             8,          113-120,          137-144
00853 --PARITY--          6,          -----             145-150
00854 i0_LSB,             24,         121-144,          151-174
00855 --PARITY--          6,          -----             175-180
00856 crc,                16,         145-160,          181-196
00857 w_MSB,              8,          161-168,          197-204
00858 --PARITY--          6,          -----             205-210
00859 w_LSB,              24,         169-192,          211-234
00860 --PARITY--          6,          -----             235-240
00861 omegadot,           24,         193-216,          241-264
00862 --PARITY--          6,          -----             265-270
00863 iode,               8,          217-224,          271-278
00864 idot,               14,         225-238,          279-292
00865 parity_related,     2,          239-240,          293-294
00866 ------------------------------------------------------------------
00867 */
00868   unsigned char subframe_id;    // subrame id
00869   unsigned char iode_subframe1; // 8 LSB bits of the iodc in subframe 1
00870   unsigned char iode_subframe2; // subframe2 iode
00871   unsigned char iode_subframe3; // subframe3 iode
00872   
00873   // temporary variables of different size
00874   char  s8;
00875   short s16;
00876   int   s32;
00877   unsigned short u16a, u16b;
00878   unsigned u32a, u32b, u32c, u32d;
00879 
00880   u16a = prn; // gets rid of a debug msg :)
00881     
00882   //------------------------------------------------------------------
00883   //                         SUBFRAME1
00884   //------------------------------------------------------------------
00885 
00886   // time of week,  actually a 19 bit value, 17 MSBs are available, 2 LSB bits are always zero
00887   u32a = subframe1[3] << 11;
00888   u32b = subframe1[4] << 3;
00889   u32c = (subframe1[5] & 0x80) >> 5;
00890   *tow = (u32a | u32b | u32c); // [z-count 1.5s intervals]
00891   *tow = (*tow * 3) / 2; // converted to [s]
00892 
00893   // alert_flag
00894   *alert_flag = (unsigned char)( (subframe1[5] & 0x40) >> 6 );
00895 
00896   // anti-spoof
00897   *anti_spoof = (unsigned char)( (subframe1[5] & 0x20) >> 5 );
00898 
00899   // confirm that this is subframe 1  
00900   subframe_id = (unsigned char)( (subframe1[5] & 0x1C) >> 2 );
00901   if( subframe_id != 1 )
00902   {
00903     GNSS_ERROR_MSG( "if( subframe_id != 1 )" );
00904     return FALSE;
00905   }
00906 
00907   // GPS Week
00908   u16a  = (unsigned short)( subframe1[6] << 2 );
00909   u16b  = (unsigned short)( subframe1[7] >> 6 );
00910   *week = (unsigned short)( u16a | u16b );
00911   
00912   /// code_on_L2
00913   *code_on_L2 = (unsigned char)( (subframe1[7] & 0x30) >> 4 );
00914 
00915   // ura
00916   *ura = (unsigned char)( (subframe1[7] & 0x0F) );
00917 
00918   // health
00919   *health = (unsigned char)( subframe1[8] >> 2 );
00920 
00921   // issue of data clock
00922   u16a  = (unsigned short)( (subframe1[8] & 0x03) << 8 );
00923   u16b  = (unsigned short)( subframe1[21] );
00924   *iodc = (unsigned short)( u16a | u16b ); // []
00925   
00926   // iode subframe1 for consistency checking
00927   iode_subframe1 = subframe1[21];
00928 
00929   // L2_P_data_flag 
00930   *L2_P_data_flag = (unsigned char)( (subframe1[9] & 0x80) >> 7 );
00931 
00932   // tgd
00933   s8   = subframe1[20]; // signed
00934   *tgd = s8 / TWO_TO_THE_POWER_OF_31;
00935 
00936   // toc
00937   u16a = (unsigned short)( subframe1[22] << 8 );
00938   u16b = (unsigned short)( subframe1[23] );
00939   *toc = (unsigned)( (u16a | u16b) ) * 16;  
00940   
00941   // af2
00942   s8  = subframe1[24]; // signed
00943   *af2 = s8;
00944   *af2 /= TWO_TO_THE_POWER_OF_55;
00945   
00946   // af1
00947   u16a = (unsigned short)( subframe1[25] << 8 );
00948   u16b = subframe1[26];   
00949   s16 = (unsigned short)( u16a | u16b ); // signed value
00950   *af1 = s16;
00951   *af1 /= TWO_TO_THE_POWER_OF_43;
00952   
00953   // af0
00954   u32a = subframe1[27] << 24;
00955   u32b = subframe1[28] << 16;
00956   u32c = subframe1[29] & 0xFC;
00957   u32c <<= 8; // align to the sign bit (two's complement integer)
00958   u32d = (u32a | u32b | u32c);
00959   s32 = (int)(u32d);
00960   s32 >>= 10; // 22 bit value
00961   *af0  = s32;
00962   *af0 /= TWO_TO_THE_POWER_OF_31;
00963 
00964   //------------------------------------------------------------------
00965   //                         SUBFRAME2
00966   //------------------------------------------------------------------
00967 
00968   // confirm that this is subframe 2
00969   subframe_id = (unsigned char)( (subframe2[5] & 0x1C) >> 2 );
00970   if( subframe_id != 2 )
00971   {
00972     GNSS_ERROR_MSG( "if( subframe_id != 2 )" );
00973     return FALSE;
00974   }
00975 
00976   // iode subframe2
00977   iode_subframe2 = subframe2[6];
00978 
00979   // crs
00980   u16a = (unsigned short)( subframe2[7] << 8 );
00981   u16b = subframe2[8];
00982   s16  = (unsigned short)( u16a | u16b ); // signed value
00983   *crs = s16;
00984   *crs /= 32.0; // [m]
00985 
00986   // delta_n
00987   u16a = (unsigned short)( subframe2[9] << 8 );
00988   u16b = subframe2[10];  
00989   s16  = (short)( u16a | u16b ); // signed value
00990   *delta_n  = s16;
00991   *delta_n *= PI / TWO_TO_THE_POWER_OF_43; // [rad/s]
00992 
00993   // m0
00994   u32a = subframe2[11] << 24;
00995   u32b = subframe2[12] << 16;
00996   u32c = subframe2[13] << 8;
00997   u32d = subframe2[14];
00998   s32 = (u32a | u32b | u32c | u32d); // signed value
00999   *m0  = s32;
01000   *m0 *= PI / TWO_TO_THE_POWER_OF_31; // [rad]
01001 
01002   // cuc
01003   u16a = (unsigned short)( subframe2[15] << 8 );
01004   u16b = subframe2[16];
01005   s16  = (short)( u16a | u16b ); // signed value
01006   *cuc  = s16;
01007   *cuc /= TWO_TO_THE_POWER_OF_29; // [rad]
01008   
01009   // ecc
01010   u32a = subframe2[17] << 24;
01011   u32b = subframe2[18] << 16;
01012   u32c = subframe2[19] << 8;
01013   u32d = subframe2[20];
01014   *ecc  = u32a | u32b | u32c | u32d;
01015   *ecc /= TWO_TO_THE_POWER_OF_33;  // []
01016 
01017   // cus
01018   u16a = (unsigned short)( subframe2[21] << 8 );
01019   u16b = subframe2[22];
01020   s16  = (short)( u16a | u16b );
01021   *cus  = s16;
01022   *cus /= TWO_TO_THE_POWER_OF_29; // [rad]
01023   
01024   // sqrta
01025   u32a = subframe2[23] << 24;
01026   u32b = subframe2[24] << 16;
01027   u32c = subframe2[25] << 8;
01028   u32d = subframe2[26];
01029   *sqrta = u32a | u32b | u32c | u32d; 
01030   *sqrta /= TWO_TO_THE_POWER_OF_19; // [sqrt(m)]
01031 
01032   // toe
01033   u16a = (unsigned short)( subframe2[27] << 8 );
01034   u16b = subframe2[28];
01035   *toe = (unsigned)( (u16a | u16b) ) * 16; // [s]
01036 
01037   // fit_interval_flag
01038   *fit_interval_flag  = (unsigned char)( subframe2[29] >> 7 );
01039 
01040   // age_of_data_offset
01041   *age_of_data_offset = (unsigned short)( (subframe2[29] & 0x74) >> 2 );
01042   *age_of_data_offset *= 900; // [s]
01043 
01044   //------------------------------------------------------------------
01045   //                         SUBFRAME3
01046   //------------------------------------------------------------------
01047 
01048   // confirm that this is subframe 3
01049   subframe_id = (unsigned char)( (subframe3[5] & 0x1C) >> 2 );
01050   if( subframe_id != 3 )
01051   {
01052     GNSS_ERROR_MSG( "if( subframe_id != 3 )" );
01053     return FALSE;
01054   }
01055 
01056   // cic
01057   u16a  = (unsigned short)( subframe3[6] << 8 );
01058   u16b  = subframe3[7];
01059   s16   = (short)( u16a | u16b ); // signed value
01060   *cic  = s16;
01061   *cic /= TWO_TO_THE_POWER_OF_29; // [rad]
01062 
01063   // omego0
01064   u32a = subframe3[8] << 24;
01065   u32b = subframe3[9] << 16;
01066   u32c = subframe3[10] << 8;
01067   u32d = subframe3[11];
01068   s32  = u32a | u32b | u32c | u32d; // signed value
01069   *omega0  = s32;
01070   *omega0 *= PI / TWO_TO_THE_POWER_OF_31; // [rad]
01071 
01072   // cis
01073   u16a  = (unsigned short)( subframe3[12] << 8 );
01074   u16b  = subframe3[13];
01075   s16   = (short)( u16a | u16b ); // signed value
01076   *cis  = s16;
01077   *cis /= TWO_TO_THE_POWER_OF_29; // [rad]
01078 
01079   // i0
01080   u32a = subframe3[14] << 24;
01081   u32b = subframe3[15] << 16;
01082   u32c = subframe3[16] << 8;
01083   u32d = subframe3[17];
01084   s32  = u32a | u32b | u32c | u32d;
01085   *i0  = s32;
01086   *i0 *= PI / TWO_TO_THE_POWER_OF_31; // [rad]
01087   
01088   // crc
01089   u16a  = (unsigned short)( subframe3[18] << 8 );
01090   u16b  = subframe3[19];
01091   s16   = (short)( u16a | u16b ); // signed value
01092   *crc  = s16;
01093   *crc /= 32.0; // [m]
01094 
01095   // w
01096   u32a = subframe3[20] << 24;
01097   u32b = subframe3[21] << 16;
01098   u32c = subframe3[22] << 8;
01099   u32d = subframe3[23];
01100   s32  = u32a | u32b | u32c | u32d; // signed value
01101   *w   = s32;
01102   *w  *= PI / TWO_TO_THE_POWER_OF_31; // [rad]
01103 
01104   // omegadot
01105   u32a = subframe3[24] << 24;
01106   u32b = subframe3[25] << 16;
01107   u32c = subframe3[26] << 8;  
01108   s32  = u32a | u32b | u32c; // signed value
01109   s32  = s32 >> 8;
01110   *omegadot  = s32;
01111   *omegadot *= PI / TWO_TO_THE_POWER_OF_43; // [rad/s]
01112 
01113   // iode subframe3
01114   iode_subframe3 = subframe3[27];
01115 
01116   // idot
01117   u16a  = (unsigned short)( subframe3[28] << 8 );
01118   u16b  = (unsigned short)( subframe3[29] & 0xFC );
01119   s16   = (short)( u16a | u16b ); // signed value
01120   s16   = (short)( s16 >> 2 );
01121   *idot = s16;
01122   *idot *= PI / TWO_TO_THE_POWER_OF_43; // [rad/s]  
01123 
01124   // check that the IODE values match for all three subframes  
01125   if( (iode_subframe1 == iode_subframe2) && (iode_subframe1 == iode_subframe3) )
01126   {
01127     *iode = iode_subframe1;
01128     return TRUE;
01129   }
01130   else
01131   {
01132     *iode = 0;
01133     GNSS_ERROR_MSG( "inconsistent subframe dataset" );
01134     return FALSE; // inconsistent subframe dataset
01135   }
01136 }
01137 
01138 
SourceForge.net Logo