GNSS_Estimator.cpp

Go to the documentation of this file.
00001 /**
00002 \file    GNSS_Estimator.cpp
00003 \brief   The implementation file for the Esimtator class.
00004 
00005 \author  Glenn D. MacGougan (GDM)
00006 \date    2007-11-29
00007 \since   2006-11-16
00008 
00009 \b "LICENSE INFORMATION" \n
00010 Copyright (c) 2007, refer to 'author' doxygen tags \n
00011 All rights reserved. \n
00012 
00013 Redistribution and use in source and binary forms, with or without
00014 modification, are permitted provided the following conditions are met: \n
00015 
00016 - Redistributions of source code must retain the above copyright
00017   notice, this list of conditions and the following disclaimer. \n
00018 - Redistributions in binary form must reproduce the above copyright
00019   notice, this list of conditions and the following disclaimer in the
00020   documentation and/or other materials provided with the distribution. \n
00021 - The name(s) of the contributor(s) may not be used to endorse or promote 
00022   products derived from this software without specific prior written 
00023   permission. \n
00024 
00025 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00026 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00027 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00028 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00029 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00030 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00031 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00032 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00033 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00034 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00035 SUCH DAMAGE.
00036 */
00037 
00038 #include <math.h>
00039 #include <memory.h>
00040 #include <list>
00041 
00042 #include "GNSS_Estimator.h"
00043 #include "GNSS_RxData.h"
00044 #include "constants.h"
00045 #include "geodesy.h"
00046 #include "gps.h"
00047 #include "ionosphere.h"
00048 #include "navigation.h"
00049 #include "troposphere.h"
00050 #include "time_conversion.h"
00051 
00052 #define DEBUG_THE_ESTIMATOR
00053 #define GNSS_CYCLESLIP_THREADHOLD 1.5
00054 
00055 using namespace std;
00056 
00057 
00058 namespace GNSS
00059 {
00060 
00061   /// The critical values of the chi-squared distribution with an alpha of .005 with v: 01..30 (31 values).
00062   /// \b REFERENCE \n
00063   /// Walpole, R. E, R. H Myers (1993), Probability and Statistics for Engineers and 
00064   /// Scientists, Prentice Hall Inc. ISBN 0-02-424301-2.
00065   #define GNSS_CHISQUARE_00_5 { \
00066    0.000,  7.879, 10.597, 12.838, 14.860, 16.750, 18.548, 20.278, 21.955, 23.589, \
00067   25.188, 26.757, 28.300, 29.819, 31.319, 32.801, 34.267, 35.718, 37.156, 38.582, \
00068   39.997, 41.401, 42.796, 44.181, 45.558, 46.928, 48.290, 49.645, 50.993, 52.336, 53.672 }
00069 
00070 
00071   GNSS_Estimator::GNSS_Estimator()
00072    : m_debug(NULL)
00073   {    
00074   }
00075 
00076 
00077   GNSS_Estimator::~GNSS_Estimator()
00078   {
00079     if( m_debug )
00080     {
00081       fclose(m_debug);
00082     }
00083   }
00084 
00085 
00086   bool GNSS_Estimator::PerformLeastSquares_8StatePVT(
00087     GNSS_RxData *rxData,       //!< A pointer to the rover receiver data. This must be a valid pointer.
00088     GNSS_RxData *rxBaseData,   //!< A pointer to the reference receiver data if available. NULL if not available.
00089     bool &wasPositionComputed, //!< A boolean to indicate if a position solution was computed.    
00090     bool &wasVelocityComputed  //!< A boolean to indicate if a velocity solution was computed.    
00091     )
00092   {
00093     unsigned i = 0;
00094     unsigned j = 0;
00095     //unsigned k = 0;
00096     unsigned iter = 0;
00097     unsigned n = 0; 
00098     unsigned nrValidEph = 0; // The number of channels with valid ephemeris.
00099     unsigned nrP = 0;        // The number of valid pseudorange measurements. 
00100     unsigned nrP_base = 0;   // The number of valid pseudorange measurements (base station).
00101     unsigned nrD = 0;        // The number of valid Doppler measurements.
00102     //unsigned nrD_base = 0;   // The number of valid Doppler measurements (base station).    
00103     unsigned nrDifferentialPsr = 0;     // The number of valid differntial pseudorange measurements.
00104     unsigned nrDifferentialDoppler = 0; // the number of valid differential Doppler measurements.
00105 
00106     //unsigned char isGood = 0; // A helper value.
00107 
00108     double dtmp1 = 0;     // A temp double.
00109     double lat = 0;       // latitude [rad].
00110     double lon = 0;       // longitude [rad].
00111     double hgt = 0;       // height [m].
00112     double clk = 0;       // rx clock bias [m].
00113     double clkdrift = 0;  // rx clock drift [m/s].
00114     double vn = 0;        // rx velocity north [m/s].
00115     double ve = 0;        // rx velocity east [m/s].
00116     double vup = 0;       // rx velocity up [m/s].
00117     double M = 0;   // The computed meridian radius of curvature [m].
00118     double N = 0;   // The computed prime vertical radius of curvature [m].
00119     
00120     Matrix dx_p(4);  // The iterative update to the position, clock states,         [4  x  1].   
00121     Matrix dx_v(4);  // The iterative update to the velocity, clk drift states,     [4  x  1].   
00122     Matrix P_p(4,4); // The position, clk, state variance covariance matrix,        [4  x  4].
00123     Matrix P_v(4,4); // The velocity, clk drift, state variance covariance matrix,  [4  x  4].
00124     Matrix H_p;      // The position design matrix                                  [nP x  4].
00125     Matrix Ht_p;     // The position design matrix transposed                       [4  x nP].
00126     Matrix HtW_p;    // An intermediate result                                      [4  x nP].
00127     Matrix H_v;      // The velocity design matrix                                  [nD x  4].
00128     Matrix Ht_v;     // The velocity design matrix transposed                       [4  x nD].
00129     Matrix HtW_v;    // An intermediate result                                      [4  x nD].
00130     Matrix W_p;      // The weight matrix for the psr observations,                 [nP x nP].
00131     Matrix R_p;      // The variance-covariance matrix for the psr observations,    [nP x nP].
00132     Matrix W_v;      // The weight matrix for the Doppler observations,             [nD x nD].
00133     Matrix R_v;      // The variance-covariance matrix for the Doppler observations,[nD x nD].
00134     Matrix w_p;      // The psr misclosures vector,                                 [nP x  1].
00135     Matrix w_v;      // The Doppler misclosure vector,                              [nD x  1].    
00136     Matrix r_p;      // The psr residuals vector,                                   [nP x  1].
00137     Matrix r_v;      // The Doppler residuals vector,                               [nD x  1].
00138 
00139     double avf_p = 0; // The a-posteriori variance factor for the position solution.
00140     //double avf_v = 0; // The a-posteriori variance factor for the velocity solution.
00141 
00142     bool isGlobalTestPassed_p = false; // This indicates if the Global Reliability Test passed for the position solution.
00143     //bool isGlobalTestPassed_v = false; // This indicates if the Global Reliability Test passed for the velocity solution.
00144 
00145     bool hasRejectionOccurred_p = false; // This indicates if a pseudorange measurement was rejected.
00146     //bool hasRejectionOccurred_v = false; // This indicates if a Doppler measurement was rejected.
00147 
00148     unsigned char indexOfRejected = 0; // The index into rxData.m_ObsArray of a rejected measurement.
00149     
00150     bool result = false;
00151 
00152     if( rxData == NULL )
00153       return false;
00154 
00155     // Store the current input pvt as the previous pvt since we are updating.
00156     rxData->m_prev_pvt = rxData->m_pvt;
00157 
00158     lat       = rxData->m_pvt.latitude;
00159     lon       = rxData->m_pvt.longitude;
00160     hgt       = rxData->m_pvt.height;
00161     clk       = rxData->m_pvt.clockOffset;
00162 
00163     vn        = rxData->m_pvt.vn;
00164     ve        = rxData->m_pvt.ve;
00165     vup       = rxData->m_pvt.vup;
00166     clkdrift  = rxData->m_pvt.clockDrift;
00167 
00168     wasPositionComputed = false;
00169     wasVelocityComputed = false;
00170        
00171     // Perform very basic uniqueness check.
00172     n = rxData->m_nrGPSL1Obs;
00173     if( rxData->m_pvt.isPositionConstrained )
00174     {
00175       n += 3;
00176     }
00177     else if( rxData->m_pvt.isHeightConstrained )
00178     {
00179       n += 1;
00180     }
00181     if( n < 4 )    
00182     {
00183       return true;
00184     }
00185 
00186     // Update the receiver time information (UTC and day of year)
00187     result = UpdateTime( *rxData );
00188     if( !result )
00189       return false;    
00190     if( rxBaseData != NULL )
00191     {
00192       result = UpdateTime( *rxBaseData );
00193       if( !result )
00194         return false;    
00195     }
00196 
00197     
00198 
00199 
00200     result = DetermineSatellitePVT_GPSL1( rxData, rxBaseData, nrValidEph );
00201     if( !result )
00202       return false;
00203 
00204     result = DetermineAtmosphericCorrections_GPSL1( *rxData );
00205     if( !result )
00206       return false;
00207     if( rxBaseData != NULL )
00208     {
00209       result = DetermineAtmosphericCorrections_GPSL1( *rxBaseData );
00210       if( !result )
00211         return false;
00212     }
00213     
00214     // Check uniqueness
00215     n = nrValidEph;
00216     if( rxData->m_pvt.isPositionConstrained )
00217     {
00218       n += 3;
00219     }
00220     else if( rxData->m_pvt.isHeightConstrained )
00221     {
00222       n += 1;
00223     }
00224     if( n < 4 )    
00225     {
00226       return true;
00227     }
00228   
00229 
00230     // Iterate through the solution
00231     for( iter = 0; iter < 7; iter++ )
00232     {
00233       if( !DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxData, nrP ) )
00234         return false;
00235 
00236       // Check uniqueness
00237       n = nrP;
00238       if( rxData->m_pvt.isPositionConstrained )
00239       {
00240         n += 3;
00241       }
00242       else if( rxData->m_pvt.isHeightConstrained )
00243       {
00244         n += 1;
00245       }
00246       if( n < 4 )    
00247       {
00248         return true;
00249       }
00250   
00251       if( rxBaseData != NULL )
00252       {
00253         if( !DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxBaseData, nrP_base ) )
00254           return false;
00255 
00256         result = DetermineBetweenReceiverDifferentialIndex(
00257           rxData,
00258           rxBaseData,
00259           true
00260           );
00261         if( !result )
00262           return false;
00263 
00264         nrDifferentialPsr = 0;
00265         for( i = 0; i < rxData->m_nrValidObs; i++ )
00266         {
00267           if( rxData->m_ObsArray[i].system == GNSS_GPS &&
00268             rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
00269             rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
00270           {
00271             nrDifferentialPsr++;
00272           }
00273         }
00274 
00275         nrP = nrDifferentialPsr;
00276         n = nrP;
00277         if( rxData->m_pvt.isPositionConstrained )
00278         {
00279           n += 3;
00280         }
00281         else if( rxData->m_pvt.isHeightConstrained )
00282         {
00283           n += 1;
00284         }
00285         if( n < 4 )    
00286         {
00287           return true;
00288         }
00289       }
00290   
00291       result = DetermineDesignMatrixForThePositionSolution_GPSL1(
00292         *rxData,
00293         n,
00294         H_p );
00295       if( !result )
00296         return false;
00297       
00298       result = DetermineMeasurementWeightMatrixForThePositionSolution_GPSL1(
00299         *rxData,
00300         n,
00301         W_p );
00302       if( !result )
00303         return false;
00304 
00305       result = DetermineMeasurementVarianceCovarianceMatrixForThePositionSolution_GPSL1(
00306         *rxData,
00307         n,
00308         R_p );
00309       if( !result )
00310         return false;
00311 
00312       result = DeterminePseudorangeMisclosures_GPSL1( 
00313         rxData, 
00314         rxBaseData,
00315         n, 
00316         w_p );
00317       if( !result )
00318         return false;
00319 
00320       // Compute Ht_p.
00321       Ht_p = H_p;
00322       if( !Ht_p.Inplace_Transpose() )
00323         return false;
00324 
00325       // Compute HtW_p.
00326       if( !HtW_p.Multiply( Ht_p, W_p ) )
00327         return false;
00328 
00329       // Compute P_p.
00330       if( !P_p.Multiply( HtW_p, H_p ) )
00331         return false;
00332       if( !P_p.Inplace_Invert() )
00333         return false;
00334 
00335       // Compute dx_p.
00336       if( !dx_p.Multiply( P_p, HtW_p ) )
00337         return false;
00338       if( !dx_p.Inplace_PostMultiply( w_p ) )
00339         return false;
00340 
00341       // Update the position and clock states
00342       // Update height first as it is need to reduce the corrections for lat and lon.
00343       hgt += dx_p[2];
00344       clk += dx_p[3];
00345      
00346       // The corrections for lat and lon, dx_p, must be converted to [rad] from [m].
00347       GEODESY_ComputePrimeVerticalRadiusOfCurvature(
00348         GEODESY_REFERENCE_ELLIPSE_WGS84, 
00349         rxData->m_pvt.latitude,
00350         &N );
00351       GEODESY_ComputeMeridianRadiusOfCurvature(
00352         GEODESY_REFERENCE_ELLIPSE_WGS84, 
00353         rxData->m_pvt.latitude,
00354         &M );
00355 
00356       lat += dx_p[0] / ( M + hgt );             // convert from meters to radians.
00357       lon += dx_p[1] / (( N + hgt )*cos(lat));  // convert from meters to radians.
00358 
00359       result = rxData->UpdatePositionAndRxClock(
00360         lat,
00361         lon,
00362         hgt,
00363         clk,
00364         sqrt(P_p[0][0]),
00365         sqrt(P_p[1][1]),
00366         sqrt(P_p[2][2]),
00367         sqrt(P_p[3][3])
00368         );
00369       if( !result )
00370         return false;
00371 
00372       dtmp1 = fabs(dx_p[0]) + fabs(dx_p[1]) + fabs(dx_p[2]) + fabs(dx_p[3]);
00373       if( dtmp1 < 0.0001 )
00374       {
00375         if( 0 )
00376         {
00377           // Test the residuals
00378           result = PerformGlobalTestAndTestForMeasurementFaults( 
00379             *rxData,
00380             true,
00381             H_p,
00382             Ht_p,      
00383             W_p,
00384             R_p,
00385             w_p, // misclosures at convergence are the residuals.
00386             P_p,
00387             n,
00388             4,
00389             avf_p,      
00390             isGlobalTestPassed_p,
00391             hasRejectionOccurred_p,
00392             indexOfRejected
00393             );
00394           if( !result )
00395             return false;
00396 
00397           if( hasRejectionOccurred_p )
00398           {
00399             hasRejectionOccurred_p = false;
00400             j = 0; // restart the iterative loop.
00401             continue;
00402           }
00403           else
00404           {
00405             // converged to solution.
00406             break;
00407           }
00408         }
00409         else
00410         {
00411           // converged to solution.
00412           break;
00413         }
00414 
00415       }
00416     }
00417     wasPositionComputed = true;
00418 
00419 
00420     // compute the DOP
00421     Matrix Q;
00422     Q = H_p;
00423     Q.Inplace_Transpose();
00424     Q.Inplace_PostMultiply( H_p );
00425     if( !Q.Inplace_Invert() )
00426       return false;
00427 
00428     rxData->m_pvt.dop.ndop = static_cast<float>( sqrt( Q[0][0] ) );
00429     rxData->m_pvt.dop.edop = static_cast<float>( sqrt( Q[1][1] ) );
00430     rxData->m_pvt.dop.vdop = static_cast<float>( sqrt( Q[2][2] ) );
00431     rxData->m_pvt.dop.tdop = static_cast<float>( sqrt( Q[3][3] ) );
00432     rxData->m_pvt.dop.hdop = rxData->m_pvt.dop.ndop * rxData->m_pvt.dop.ndop + rxData->m_pvt.dop.edop * rxData->m_pvt.dop.edop;
00433     rxData->m_pvt.dop.pdop = rxData->m_pvt.dop.hdop + rxData->m_pvt.dop.vdop * rxData->m_pvt.dop.vdop;
00434     rxData->m_pvt.dop.gdop = rxData->m_pvt.dop.pdop + rxData->m_pvt.dop.tdop * rxData->m_pvt.dop.tdop;
00435     rxData->m_pvt.dop.hdop = sqrt(rxData->m_pvt.dop.hdop);
00436     rxData->m_pvt.dop.pdop = sqrt(rxData->m_pvt.dop.pdop);
00437     rxData->m_pvt.dop.gdop = sqrt(rxData->m_pvt.dop.gdop);
00438 
00439 
00440     //
00441     ////
00442 
00443 
00444     ////
00445     // Velocity
00446 
00447     for( iter = 0; iter < 7; iter++ )
00448     {
00449       result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1(
00450         *rxData,
00451         nrD );
00452       if( !result )
00453         return false;
00454 
00455       // Check uniqueness
00456       n = nrD;
00457       if( rxData->m_pvt.isPositionConstrained )
00458       {
00459         n += 3;
00460       }
00461       else if( rxData->m_pvt.isHeightConstrained )
00462       {
00463         n += 1;
00464       }
00465       if( n < 4 )    
00466       {
00467         return true;
00468       }
00469 
00470       
00471       if( rxBaseData != NULL )
00472       {
00473         if( !DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxBaseData, nrP_base ) )
00474           return false;
00475 
00476         result = DetermineBetweenReceiverDifferentialIndex(
00477           rxData,
00478           rxBaseData,
00479           true
00480           );
00481         if( !result )
00482           return false;
00483 
00484         nrDifferentialDoppler = 0;
00485         for( i = 0; i < rxData->m_nrValidObs; i++ )
00486         {
00487           if( rxData->m_ObsArray[i].system == GNSS_GPS &&
00488             rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
00489             rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
00490           {
00491             nrDifferentialDoppler++;
00492           }
00493         }
00494 
00495         // Check uniqueness.
00496         nrD = nrDifferentialDoppler;
00497         n = nrD;
00498         if( rxData->m_pvt.isPositionConstrained )
00499         {
00500           n += 3;
00501         }
00502         else if( rxData->m_pvt.isHeightConstrained )
00503         {
00504           n += 1;
00505         }
00506         if( n < 4 )    
00507         {
00508           return true;
00509         }
00510       }
00511 
00512 
00513       // Need to update the rxData->m_ObsArray[i].rangerate values.
00514       for( i = 0; i < rxData->m_nrValidObs; i++ )
00515       {
00516         if( rxData->m_ObsArray[i].flags.isActive )
00517         {
00518           if( rxData->m_ObsArray[i].system == GNSS_GPS && rxData->m_ObsArray[i].freqType == GNSS_GPSL1 )
00519           {
00520             if( rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
00521             {
00522               GPS_ComputeUserToSatelliteRangeAndRangeRate(
00523                 rxData->m_pvt.x,
00524                 rxData->m_pvt.y,
00525                 rxData->m_pvt.z,
00526                 rxData->m_pvt.vx,
00527                 rxData->m_pvt.vy,
00528                 rxData->m_pvt.vz,
00529                 rxData->m_ObsArray[i].satellite.x,
00530                 rxData->m_ObsArray[i].satellite.y,
00531                 rxData->m_ObsArray[i].satellite.z,
00532                 rxData->m_ObsArray[i].satellite.vx,
00533                 rxData->m_ObsArray[i].satellite.vy,
00534                 rxData->m_ObsArray[i].satellite.vz,
00535                 &rxData->m_ObsArray[i].range,
00536                 &rxData->m_ObsArray[i].rangerate
00537                 );
00538             }
00539           }
00540         }
00541       }
00542 
00543       result = DetermineDesignMatrixForTheVelocitySolution_GPSL1(
00544         *rxData,
00545         n,
00546         H_v );
00547       if( !result )
00548         return false;
00549 
00550       result = DetermineMeasurementWeightMatrixForTheVelocitySolution_GPSL1(
00551         *rxData,
00552         n,
00553         W_v );
00554       if( !result )
00555         return false;
00556 
00557       result = DetermineMeasurementVarianceCovarianceMatrixForTheVelocitySolution_GPSL1(
00558         *rxData,
00559         n,
00560         R_v );
00561       if( !result )
00562         return false;
00563 
00564       result = DetermineDopplerMisclosures_GPSL1(
00565         rxData,
00566         rxBaseData,
00567         n,
00568         w_v );
00569       if( !result )
00570         return false;
00571 
00572       // Compute Ht_v.
00573       Ht_v = H_v;
00574       if( !Ht_v.Inplace_Transpose() )
00575         return false;
00576 
00577       // Compute HtW_v.
00578       if( !HtW_v.Multiply( Ht_v, W_v ) )
00579         return false;
00580 
00581       // Compute P_v.
00582       if( !P_v.Multiply( HtW_v, H_v ) )
00583         return false;
00584       if( !P_v.Inplace_Invert() )
00585         return false;
00586 
00587       // Compute dx_v.
00588       if( !dx_v.Multiply( P_v, HtW_v ) )
00589         return false;
00590       if( !dx_v.Inplace_PostMultiply( w_v ) )
00591         return false;
00592 
00593       // Update the velocity and clock drift states.
00594       vn        += dx_v[0];
00595       ve        += dx_v[1];
00596       vup       += dx_v[2];
00597       clkdrift  += dx_v[3];
00598 
00599       result = rxData->UpdateVelocityAndClockDrift(
00600         vn,
00601         ve,
00602         vup,
00603         clkdrift,
00604         P_v[0][0],
00605         P_v[1][1],
00606         P_v[2][2],
00607         P_v[3][3] );
00608       if( !result )
00609         return false;
00610 
00611       dtmp1 = fabs(dx_v[0]) + fabs(dx_v[1]) + fabs(dx_v[2]) + fabs(dx_v[3]);
00612       if( dtmp1 < 1.0e-10 )
00613         break;
00614     }
00615     wasVelocityComputed = true;
00616 
00617     return true;
00618   }
00619 
00620 
00621   bool GNSS_Estimator::UpdateTime(
00622     GNSS_RxData &rxData  //!< The receiver data. The m_pvt.time struct is updated.    
00623     )
00624   {
00625     TIMECONV_GetUTCTimeFromGPSTime(
00626       rxData.m_pvt.time.gps_week,
00627       rxData.m_pvt.time.gps_tow,
00628       &rxData.m_pvt.time.utc_year,
00629       &rxData.m_pvt.time.utc_month,
00630       &rxData.m_pvt.time.utc_day,
00631       &rxData.m_pvt.time.utc_hour,
00632       &rxData.m_pvt.time.utc_minute,
00633       &rxData.m_pvt.time.utc_seconds
00634       );
00635 
00636     TIMECONV_GetDayOfYear(
00637       rxData.m_pvt.time.utc_year,
00638       rxData.m_pvt.time.utc_month,
00639       rxData.m_pvt.time.utc_day,
00640       &rxData.m_pvt.time.day_of_year );
00641       
00642     return true;
00643   }
00644     
00645 
00646   bool GNSS_Estimator::DetermineSatellitePVT_GPSL1( 
00647     GNSS_RxData *rxData,      //!< The pointer to the receiver data.    
00648     GNSS_RxData *rxBaseData,  //!< The pointer to the reference receiver data. NULL if not available.
00649     unsigned &nrValidEph      //!< The number of GPS L1 channels with valid ephemeris for the rover.
00650     )
00651   {
00652     unsigned i = 0;
00653     double psr = 0;
00654     double dtmp1 = 0;
00655     double dtmp2 = 0;
00656     bool isEphAvailable = false;
00657     GPS_structEphemeris eph;
00658 
00659     memset( &eph, 0, sizeof(eph) );
00660 
00661     if( rxData == NULL )
00662       return false;
00663 
00664     if( rxBaseData != NULL )
00665     {
00666       // Evaluate the satellite PVT for all channels with GPS L1 observations 
00667       // for the reference station.
00668       for( i = 0; i < rxBaseData->m_nrValidObs; i++ )
00669       {
00670         if( rxBaseData->m_ObsArray[i].flags.isActive )
00671         {
00672           if( rxBaseData->m_ObsArray[i].system == GNSS_GPS && rxBaseData->m_ObsArray[i].freqType == GNSS_GPSL1 )
00673           {
00674             // Obtain the transmit time. Use an approximate psr measurement if one is not present.
00675             // The true transmit time includes compensatation for the satellite clock effects.            
00676             // p. 88 ICD-GPS-200C      
00677 
00678             rxBaseData->m_ObsArray[i].week = rxBaseData->m_pvt.time.gps_week;
00679 
00680             // first determine rough transmit time
00681             if( rxBaseData->m_ObsArray[i].flags.isCodeLocked & rxBaseData->m_ObsArray[i].flags.isPsrValid )
00682             { 
00683               psr = rxBaseData->m_ObsArray[i].psr;
00684             }
00685             else
00686             {
00687               psr = 0.070*LIGHTSPEED; // 0.070 rough transmission time
00688             }
00689             // Compute the rough transmit time.
00690             rxBaseData->m_ObsArray[i].tow = rxBaseData->m_pvt.time.gps_tow - psr/LIGHTSPEED;
00691 
00692             // Adjust for week rollover.
00693             if( rxBaseData->m_ObsArray[i].tow < 0 )
00694             {
00695               rxBaseData->m_ObsArray[i].tow += SECONDS_IN_WEEK;
00696               rxBaseData->m_ObsArray[i].week = rxBaseData->m_pvt.time.gps_week - 1;
00697             }
00698             else if( rxBaseData->m_ObsArray[i].tow > SECONDS_IN_WEEK )
00699             {
00700               rxBaseData->m_ObsArray[i].tow -= SECONDS_IN_WEEK;
00701               rxBaseData->m_ObsArray[i].week = rxBaseData->m_pvt.time.gps_week + 1;
00702             }
00703 
00704             // Get the ephemeris.
00705             if( !rxBaseData->m_EphAlmArray.GetEphemeris( rxBaseData->m_ObsArray[i].id, eph, isEphAvailable ) )
00706               return false;
00707             if( !isEphAvailable )
00708             {
00709               rxBaseData->m_ObsArray[i].satellite.isValid = false;
00710               rxBaseData->m_ObsArray[i].flags.isEphemerisValid = false;
00711               continue;
00712             }
00713 
00714             // Account for week rollover if needed.
00715             if( eph.week < 1024 )
00716               eph.week += 1024;
00717 
00718 
00719             // Check the age of the clock information for the ephemeris.
00720             dtmp1 = rxBaseData->m_ObsArray[i].week*SECONDS_IN_WEEK + rxBaseData->m_ObsArray[i].tow;
00721             dtmp2 = eph.week*SECONDS_IN_WEEK + eph.toe;
00722             rxBaseData->m_ObsArray[i].satellite.ageOfEph = static_cast<int>(dtmp1 - dtmp2);
00723             if( rxBaseData->m_ObsArray[i].satellite.ageOfEph > static_cast<int>(rxBaseData->m_maxAgeEphemeris) )
00724             {
00725               rxBaseData->m_ObsArray[i].satellite.isValid = false;
00726               rxBaseData->m_ObsArray[i].flags.isEphemerisValid = false; // old ephemeris data
00727               continue;
00728             }
00729             else
00730             {
00731               rxBaseData->m_ObsArray[i].satellite.isValid = true;
00732             }
00733 
00734             rxBaseData->m_ObsArray[i].flags.isEphemerisValid = true;
00735 
00736             // Compute the satellite clock corrections, position, velocity, etc.
00737             GPS_ComputeSatellitePositionVelocityAzimuthElevationDoppler_BasedOnEphmerisData(
00738               rxBaseData->m_pvt.x,
00739               rxBaseData->m_pvt.y,
00740               rxBaseData->m_pvt.z,
00741               rxBaseData->m_ObsArray[i].week,
00742               rxBaseData->m_ObsArray[i].tow,              
00743               eph.week,
00744               eph.toe,
00745               eph.toc,
00746               eph.af0,
00747               eph.af1,
00748               eph.af2,
00749               eph.tgd,
00750               eph.m0, 
00751               eph.delta_n,
00752               eph.ecc, 
00753               eph.sqrta, 
00754               eph.omega0,
00755               eph.i0,    
00756               eph.w,     
00757               eph.omegadot,
00758               eph.idot,    
00759               eph.cuc,     
00760               eph.cus,     
00761               eph.crc,     
00762               eph.crs,     
00763               eph.cic,     
00764               eph.cis,     
00765               &rxBaseData->m_ObsArray[i].satellite.clk,
00766               &rxBaseData->m_ObsArray[i].satellite.clkdrift,
00767               &rxBaseData->m_ObsArray[i].satellite.x,
00768               &rxBaseData->m_ObsArray[i].satellite.y,
00769               &rxBaseData->m_ObsArray[i].satellite.z,
00770               &rxBaseData->m_ObsArray[i].satellite.vx,
00771               &rxBaseData->m_ObsArray[i].satellite.vy,
00772               &rxBaseData->m_ObsArray[i].satellite.vz,
00773               &rxBaseData->m_ObsArray[i].satellite.azimuth,
00774               &rxBaseData->m_ObsArray[i].satellite.elevation,
00775               &rxBaseData->m_ObsArray[i].satellite.doppler
00776               );
00777 
00778             rxBaseData->m_ObsArray[i].corrections.prcSatClk = static_cast<float>(rxBaseData->m_ObsArray[i].satellite.clk);
00779             rxBaseData->m_ObsArray[i].corrections.rrcSatClkDrift = static_cast<float>(rxBaseData->m_ObsArray[i].satellite.clkdrift);
00780 
00781             // Compute the reference station geometric range and range rate.
00782             GPS_ComputeUserToSatelliteRangeAndRangeRate(
00783               rxBaseData->m_pvt.x,
00784               rxBaseData->m_pvt.y,
00785               rxBaseData->m_pvt.z,
00786               rxBaseData->m_pvt.vx,
00787               rxBaseData->m_pvt.vy,
00788               rxBaseData->m_pvt.vz,
00789               rxBaseData->m_ObsArray[i].satellite.x,
00790               rxBaseData->m_ObsArray[i].satellite.y,
00791               rxBaseData->m_ObsArray[i].satellite.z,
00792               rxBaseData->m_ObsArray[i].satellite.vx,
00793               rxBaseData->m_ObsArray[i].satellite.vy,
00794               rxBaseData->m_ObsArray[i].satellite.vz,
00795               &rxBaseData->m_ObsArray[i].range,
00796               &rxBaseData->m_ObsArray[i].rangerate );
00797           }
00798         }
00799       }
00800     }
00801 
00802     // Evaluate the satellite PVT for all channesl with GPS L1 observations       
00803     // for the rover station using the reference station ephemeris if available.   
00804     nrValidEph = 0;
00805     for( i = 0; i < rxData->m_nrValidObs; i++ )
00806     {
00807       if( rxData->m_ObsArray[i].flags.isActive )
00808       {
00809         if( rxData->m_ObsArray[i].system == GNSS_GPS && rxData->m_ObsArray[i].freqType == GNSS_GPSL1 )
00810         {
00811           // Obtain the transmit time. Use an approximate psr measurement if one is not present.
00812           // The true transmit time includes compensatation for the satellite clock effects.            
00813           // p. 88 ICD-GPS-200C      
00814 
00815           rxData->m_ObsArray[i].week = rxData->m_pvt.time.gps_week;
00816 
00817           // first determine rough transmit time
00818           if( rxData->m_ObsArray[i].flags.isCodeLocked & rxData->m_ObsArray[i].flags.isPsrValid )
00819           { 
00820             psr = rxData->m_ObsArray[i].psr;
00821           }
00822           else
00823           {
00824             psr = 0.070*LIGHTSPEED; // 0.070 rough transmission time
00825           }
00826           // Compute the rough transmit time.
00827           rxData->m_ObsArray[i].tow = rxData->m_pvt.time.gps_tow - psr/LIGHTSPEED;
00828 
00829           // Adjust for week rollover.
00830           if( rxData->m_ObsArray[i].tow < 0 )
00831           {
00832             rxData->m_ObsArray[i].tow += SECONDS_IN_WEEK;
00833             rxData->m_ObsArray[i].week = rxData->m_pvt.time.gps_week - 1;
00834           }
00835           else if( rxData->m_ObsArray[i].tow > SECONDS_IN_WEEK )
00836           {
00837             rxData->m_ObsArray[i].tow -= SECONDS_IN_WEEK;
00838             rxData->m_ObsArray[i].week = rxData->m_pvt.time.gps_week + 1;
00839           }
00840 
00841           if( rxBaseData != NULL )
00842           {
00843             // Get the ephemeris using the reference station if available.
00844             if( !rxBaseData->m_EphAlmArray.GetEphemeris( rxData->m_ObsArray[i].id, eph, isEphAvailable ) )
00845               return false;
00846             if( !isEphAvailable )
00847             {
00848               // Get the ephemeris using the rover station then.
00849               if( !rxData->m_EphAlmArray.GetEphemeris( rxData->m_ObsArray[i].id, eph, isEphAvailable ) )
00850                 return false;
00851               if( !isEphAvailable )
00852               {
00853                 rxData->m_ObsArray[i].satellite.isValid = false;
00854                 rxData->m_ObsArray[i].flags.isEphemerisValid = false; // no reference station ephemeris data
00855                 continue;
00856               }
00857             }
00858           }
00859           else
00860           {
00861             // Get the ephemeris using the rover station then.
00862             if( !rxData->m_EphAlmArray.GetEphemeris( rxData->m_ObsArray[i].id, eph, isEphAvailable ) )
00863               return false;
00864             if( !isEphAvailable )
00865             {
00866               rxData->m_ObsArray[i].satellite.isValid = false;
00867               rxData->m_ObsArray[i].flags.isEphemerisValid = false; // no reference station ephemeris data
00868               continue;
00869             }
00870           }
00871 
00872           rxData->m_ObsArray[i].flags.isEphemerisValid = true;
00873 
00874           // Account for week rollover if needed.
00875           if( eph.week < 1024 )
00876             eph.week += 1024;
00877 
00878           // Check the age of the clock information for the ephemeris.
00879           dtmp1 = rxData->m_ObsArray[i].week*SECONDS_IN_WEEK + rxData->m_ObsArray[i].tow;
00880           dtmp2 = eph.week*SECONDS_IN_WEEK + eph.toe;
00881           rxData->m_ObsArray[i].satellite.ageOfEph = static_cast<int>(dtmp1 - dtmp2);
00882           if( rxData->m_ObsArray[i].satellite.ageOfEph > static_cast<int>(rxData->m_maxAgeEphemeris) )
00883           {
00884             rxData->m_ObsArray[i].satellite.isValid = false;
00885             rxData->m_ObsArray[i].flags.isEphemerisValid = false; // old ephemeris data
00886             continue;
00887           }
00888           else
00889           {
00890             rxData->m_ObsArray[i].satellite.isValid = true;
00891           }
00892 
00893           // Compute the satellite clock corrections, position, velocity, etc.
00894           GPS_ComputeSatellitePositionVelocityAzimuthElevationDoppler_BasedOnEphmerisData(
00895             rxData->m_pvt.x,
00896             rxData->m_pvt.y,
00897             rxData->m_pvt.z,
00898             rxData->m_ObsArray[i].week,
00899             rxData->m_ObsArray[i].tow,              
00900             eph.week,
00901             eph.toe,
00902             eph.toc,
00903             eph.af0,
00904             eph.af1,
00905             eph.af2,
00906             eph.tgd,
00907             eph.m0, 
00908             eph.delta_n,
00909             eph.ecc, 
00910             eph.sqrta, 
00911             eph.omega0,
00912             eph.i0,    
00913             eph.w,     
00914             eph.omegadot,
00915             eph.idot,    
00916             eph.cuc,     
00917             eph.cus,     
00918             eph.crc,     
00919             eph.crs,     
00920             eph.cic,     
00921             eph.cis,     
00922             &rxData->m_ObsArray[i].satellite.clk,
00923             &rxData->m_ObsArray[i].satellite.clkdrift,
00924             &rxData->m_ObsArray[i].satellite.x,
00925             &rxData->m_ObsArray[i].satellite.y,
00926             &rxData->m_ObsArray[i].satellite.z,
00927             &rxData->m_ObsArray[i].satellite.vx,
00928             &rxData->m_ObsArray[i].satellite.vy,
00929             &rxData->m_ObsArray[i].satellite.vz,
00930             &rxData->m_ObsArray[i].satellite.azimuth,
00931             &rxData->m_ObsArray[i].satellite.elevation,
00932             &rxData->m_ObsArray[i].satellite.doppler
00933             );
00934 
00935           rxData->m_ObsArray[i].corrections.prcSatClk = static_cast<float>(rxData->m_ObsArray[i].satellite.clk);
00936           rxData->m_ObsArray[i].corrections.rrcSatClkDrift = static_cast<float>(rxData->m_ObsArray[i].satellite.clkdrift);
00937 
00938           // Compute the rover station geometric range and range rate.
00939           GPS_ComputeUserToSatelliteRangeAndRangeRate(
00940             rxData->m_pvt.x,
00941             rxData->m_pvt.y,
00942             rxData->m_pvt.z,
00943             rxData->m_pvt.vx,
00944             rxData->m_pvt.vy,
00945             rxData->m_pvt.vz,
00946             rxData->m_ObsArray[i].satellite.x,
00947             rxData->m_ObsArray[i].satellite.y,
00948             rxData->m_ObsArray[i].satellite.z,
00949             rxData->m_ObsArray[i].satellite.vx,
00950             rxData->m_ObsArray[i].satellite.vy,
00951             rxData->m_ObsArray[i].satellite.vz,
00952             &rxData->m_ObsArray[i].range,
00953             &rxData->m_ObsArray[i].rangerate );
00954 
00955           nrValidEph++;
00956         }
00957       }
00958     }
00959     return true;
00960   }
00961 
00962   bool GNSS_Estimator::DetermineAtmosphericCorrections_GPSL1( 
00963     GNSS_RxData &rxData  //!< The receiver data.        
00964     )
00965   {
00966     unsigned i = 0;
00967     double zenith_dry_delay = 0;
00968     double zenith_wet_delay = 0;
00969     double dtmp1 = 0;
00970     double dtmp2 = 0;
00971 
00972     // Compute the tropospheric delays.
00973     TROPOSPHERE_DetermineZenithDelayValues_WAAS_Model(
00974       rxData.m_pvt.latitude,
00975       rxData.m_pvt.height,
00976       rxData.m_pvt.time.day_of_year,
00977       &zenith_dry_delay,
00978       &zenith_wet_delay
00979       );
00980 
00981     for( i = 0; i < rxData.m_nrValidObs; i++ )
00982     {
00983       if( rxData.m_ObsArray[i].flags.isActive )
00984       {
00985         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
00986         {
00987           if( rxData.m_ObsArray[i].flags.isEphemerisValid )
00988           {
00989             // Always compute the tropospheric correction (it may not be applied though).
00990             TROPOSPHERE_GetDryAndWetDelay_UsingThe_UNBabc_MappingFunction(
00991               zenith_dry_delay, 
00992               zenith_wet_delay, 
00993               rxData.m_ObsArray[i].satellite.elevation,
00994               rxData.m_pvt.latitude,              
00995               rxData.m_pvt.height,
00996               &dtmp1,
00997               &dtmp2
00998               );
00999             
01000             rxData.m_ObsArray[i].corrections.prcTropoDry = static_cast<float>(dtmp1);
01001             rxData.m_ObsArray[i].corrections.prcTropoWet = static_cast<float>(dtmp2);
01002 
01003             if( rxData.m_klobuchar.isValid )
01004             {
01005               // Always compute the ionospheric correction (it may not be applied though).
01006               IONOSPHERE_GetL1KlobucharCorrection(
01007                 rxData.m_klobuchar.alpha0,
01008                 rxData.m_klobuchar.alpha1,
01009                 rxData.m_klobuchar.alpha2,
01010                 rxData.m_klobuchar.alpha3,
01011                 rxData.m_klobuchar.beta0,
01012                 rxData.m_klobuchar.beta1,
01013                 rxData.m_klobuchar.beta2,
01014                 rxData.m_klobuchar.beta3,
01015                 rxData.m_pvt.latitude,
01016                 rxData.m_pvt.longitude, 
01017                 rxData.m_ObsArray[i].satellite.elevation,
01018                 rxData.m_ObsArray[i].satellite.azimuth,
01019                 rxData.m_pvt.time.gps_tow,
01020                 &dtmp1
01021                 );
01022               rxData.m_ObsArray[i].corrections.prcIono = static_cast<float>(dtmp1);
01023             }
01024           }
01025         }
01026       }
01027     }
01028     return true;
01029   }
01030 
01031 
01032 
01033   bool GNSS_Estimator::DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( 
01034     GNSS_RxData &rxData,            //!< The receiver data.
01035     unsigned &nrUsablePseudoranges  //!< the number of usable GPS L1 pseudorange measurements.
01036     )
01037   {
01038     unsigned i = 0;
01039     unsigned char isGood = 0;
01040 
01041     rxData.m_pvt.nrPsrObsAvailable = 0;
01042     rxData.m_pvt.nrPsrObsUsed = 0;
01043     rxData.m_pvt.nrPsrObsRejected = 0;
01044 
01045     nrUsablePseudoranges = 0;    
01046     for( i = 0; i < rxData.m_nrValidObs; i++ )
01047     {
01048       if( rxData.m_ObsArray[i].flags.isActive )
01049       {
01050         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
01051         {
01052           if( rxData.m_ObsArray[i].satellite.elevation < rxData.m_elevationMask )              
01053           {
01054             rxData.m_ObsArray[i].flags.isAboveElevationMask = 0;
01055           }
01056           else
01057           {
01058             rxData.m_ObsArray[i].flags.isAboveElevationMask = 1;
01059           }
01060 
01061           if( rxData.m_ObsArray[i].cno < rxData.m_cnoMask )
01062           {
01063             rxData.m_ObsArray[i].flags.isAboveCNoMask = 0;
01064           }
01065           else
01066           {
01067             rxData.m_ObsArray[i].flags.isAboveCNoMask = 1;
01068           }
01069 
01070           if( rxData.m_ObsArray[i].locktime < rxData.m_locktimeMask )
01071           {
01072             rxData.m_ObsArray[i].flags.isAboveLockTimeMask = 0;
01073           }
01074           else
01075           {
01076             rxData.m_ObsArray[i].flags.isAboveLockTimeMask = 1;
01077           }
01078 
01079           isGood = 
01080             rxData.m_ObsArray[i].flags.isCodeLocked         & 
01081             rxData.m_ObsArray[i].flags.isPsrValid           &
01082             rxData.m_ObsArray[i].flags.isAboveElevationMask &
01083             rxData.m_ObsArray[i].flags.isAboveCNoMask       &
01084             rxData.m_ObsArray[i].flags.isAboveLockTimeMask  &
01085             rxData.m_ObsArray[i].flags.isNotUserRejected    &
01086             rxData.m_ObsArray[i].flags.isNotPsrRejected     &
01087             rxData.m_ObsArray[i].flags.isEphemerisValid;
01088           if( isGood )
01089           {
01090             rxData.m_ObsArray[i].flags.isPsrUsedInSolution = 1;
01091             nrUsablePseudoranges++;            
01092           }
01093           else
01094           {
01095             rxData.m_ObsArray[i].flags.isPsrUsedInSolution = 0;
01096           }
01097         }
01098       }
01099     }
01100     rxData.m_pvt.nrPsrObsAvailable = nrUsablePseudoranges;
01101     return true;
01102   }
01103 
01104 
01105   bool GNSS_Estimator::DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( 
01106     GNSS_RxData &rxData,       //!< The receiver data.
01107     unsigned &nrUsableDopplers //!< the number of usable GPS L1 Doppler measurements.
01108     )
01109   {
01110     unsigned i = 0;
01111     unsigned char isGood = 0;
01112 
01113     rxData.m_pvt.nrDopplerObsAvailable = 0;
01114     rxData.m_pvt.nrDopplerObsUsed = 0;
01115     rxData.m_pvt.nrDopplerObsRejected = 0;
01116 
01117     nrUsableDopplers = 0;    
01118     for( i = 0; i < rxData.m_nrValidObs; i++ )
01119     {
01120       if( rxData.m_ObsArray[i].flags.isActive )
01121       {
01122         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
01123         {
01124           isGood = 
01125             rxData.m_ObsArray[i].flags.isCodeLocked         & 
01126             rxData.m_ObsArray[i].flags.isDopplerValid       &
01127             rxData.m_ObsArray[i].flags.isAboveElevationMask &
01128             rxData.m_ObsArray[i].flags.isAboveCNoMask       &
01129             rxData.m_ObsArray[i].flags.isAboveLockTimeMask  &
01130             rxData.m_ObsArray[i].flags.isNotUserRejected    &
01131             rxData.m_ObsArray[i].flags.isNotDopplerRejected &
01132             rxData.m_ObsArray[i].flags.isEphemerisValid;
01133           if( isGood )
01134           {
01135             rxData.m_ObsArray[i].flags.isDopplerUsedInSolution = 1;
01136             nrUsableDopplers++;            
01137           }
01138           else
01139           {
01140             rxData.m_ObsArray[i].flags.isDopplerUsedInSolution = 0;
01141           }
01142         }
01143       }
01144     }
01145     rxData.m_pvt.nrDopplerObsAvailable = nrUsableDopplers;
01146     return true;
01147   }
01148 
01149 
01150   bool GNSS_Estimator::DetermineUsableAdrMeasurements_GPSL1( 
01151     GNSS_RxData &rxData,   //!< The receiver data.
01152     unsigned &nrUsableAdr  //!< The number of usable GPS L1 adr measurements.
01153     )
01154   {
01155     unsigned i = 0;
01156     unsigned char isGood = 0;
01157 
01158     rxData.m_pvt.nrAdrObsAvailable = 0;
01159     rxData.m_pvt.nrAdrObsUsed = 0;
01160     rxData.m_pvt.nrAdrObsRejected = 0;
01161 
01162     // Check for cycle slips.
01163     rxData.CheckForCycleSlips_UsingPhaseRatePrediction( GNSS_CYCLESLIP_THREADHOLD );
01164 
01165     nrUsableAdr = 0;    
01166     for( i = 0; i < rxData.m_nrValidObs; i++ )
01167     {
01168       if( rxData.m_ObsArray[i].flags.isActive )
01169       {
01170         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
01171         {
01172           if( rxData.m_ObsArray[i].satellite.elevation < rxData.m_elevationMask )              
01173             rxData.m_ObsArray[i].flags.isAboveElevationMask = 0;
01174           else
01175             rxData.m_ObsArray[i].flags.isAboveElevationMask = 1;
01176 
01177           if( rxData.m_ObsArray[i].cno < rxData.m_cnoMask )
01178             rxData.m_ObsArray[i].flags.isAboveCNoMask = 0;
01179           else
01180             rxData.m_ObsArray[i].flags.isAboveCNoMask = 1;
01181 
01182           if( rxData.m_ObsArray[i].locktime < rxData.m_locktimeMask )
01183             rxData.m_ObsArray[i].flags.isAboveLockTimeMask = 0;
01184           else
01185             rxData.m_ObsArray[i].flags.isAboveLockTimeMask = 1;
01186 
01187           isGood = 
01188             rxData.m_ObsArray[i].flags.isCodeLocked         &
01189             rxData.m_ObsArray[i].flags.isPhaseLocked        &
01190             rxData.m_ObsArray[i].flags.isParityValid        & // if not, there is a half cycle amibiguity.
01191             rxData.m_ObsArray[i].flags.isAdrValid           &
01192             rxData.m_ObsArray[i].flags.isAboveElevationMask &
01193             rxData.m_ObsArray[i].flags.isAboveCNoMask       &
01194             rxData.m_ObsArray[i].flags.isAboveLockTimeMask  &
01195             rxData.m_ObsArray[i].flags.isNotUserRejected    &
01196             rxData.m_ObsArray[i].flags.isNotAdrRejected     &
01197             rxData.m_ObsArray[i].flags.isEphemerisValid;
01198           if( isGood )
01199           {
01200             rxData.m_ObsArray[i].flags.isAdrUsedInSolution = 1;
01201             nrUsableAdr++;            
01202           }
01203           else
01204           {
01205             rxData.m_ObsArray[i].flags.isAdrUsedInSolution = 0;
01206           }
01207         }
01208       }
01209     }
01210     rxData.m_pvt.nrAdrObsAvailable = nrUsableAdr;
01211     return true;
01212   }
01213 
01214 
01215   bool GNSS_Estimator::DetermineDesignMatrixForThePositionSolution_GPSL1( 
01216     GNSS_RxData &rxData,      //!< The receiver data.
01217     const unsigned nrRowsInH, //!< The number of valid rows in H.
01218     Matrix &H                 //!< The position & rx clock design matrix [n x 4].
01219     )
01220   {
01221     unsigned i = 0;
01222     unsigned j = 0;
01223 
01224     // Check the dimension of H.
01225     if( H.GetNrRows() != nrRowsInH || H.GetNrCols() != 4 )
01226     {
01227       if( !H.Resize( nrRowsInH, 4 ) )
01228         return false;
01229     }
01230     // Compute the design matrix for the position solution.
01231     for( i = 0; i < rxData.m_nrValidObs; i++ )
01232     {
01233       if( rxData.m_ObsArray[i].flags.isActive )
01234       {
01235         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
01236         {
01237           if( rxData.m_ObsArray[i].flags.isPsrUsedInSolution )
01238           {
01239             // Sanity index check.            
01240             if( j >= nrRowsInH )
01241               return false;
01242             
01243             NAVIGATION_ComputeDerivativesOf_Range_WithRespectToLatitudeLongitudeHeight(
01244               rxData.m_pvt.latitude,
01245               rxData.m_pvt.longitude, 
01246               rxData.m_pvt.height,
01247               rxData.m_ObsArray[i].satellite.x,
01248               rxData.m_ObsArray[i].satellite.y,
01249               rxData.m_ObsArray[i].satellite.z,
01250               &H[j][0],
01251               &H[j][1],
01252               &H[j][2],
01253               &rxData.m_ObsArray[i].range
01254               );
01255             H[j][3] = 1.0;
01256 
01257             // copy the row of the design matrix 
01258             rxData.m_ObsArray[i].H_p[0] = H[j][0];
01259             rxData.m_ObsArray[i].H_p[1] = H[j][1];
01260             rxData.m_ObsArray[i].H_p[2] = H[j][2];
01261 
01262             j++;
01263           }
01264         }
01265       }
01266     }
01267 
01268     // Constraint rows of the design matrix.
01269     if( rxData.m_pvt.isPositionConstrained )
01270     {
01271       if( j + 3 > nrRowsInH )
01272         return false;
01273             
01274       H[j][0] = 1.0; 
01275       H[j][1] = 0.0; 
01276       H[j][2] = 0.0; 
01277       H[j][3] = 0.0; 
01278       j++;
01279       H[j][0] = 0.0; 
01280       H[j][1] = 1.0; 
01281       H[j][2] = 0.0; 
01282       H[j][3] = 0.0;       
01283       j++;
01284       H[j][0] = 0.0; 
01285       H[j][1] = 0.0; 
01286       H[j][2] = 1.0; 
01287       H[j][3] = 0.0;       
01288       j++;      
01289     }
01290     else if( rxData.m_pvt.isHeightConstrained )
01291     {
01292       if( j + 1 > nrRowsInH )
01293         return false;
01294             
01295       H[j][0] = 0.0; 
01296       H[j][1] = 0.0; 
01297       H[j][2] = 1.0; 
01298       H[j][3] = 0.0;             
01299       j++;
01300     }
01301 
01302     return true;
01303   }
01304 
01305 
01306   bool GNSS_Estimator::DetermineMeasurementWeightMatrixForThePositionSolution_GPSL1( 
01307     GNSS_RxData &rxData,  //!< The receiver data.
01308     const unsigned n,     //!< The number of measurements and pseudo-measurements (constraints).
01309     Matrix &W             //!< The inverse of the pseudorange measurement variance-coraiance matrix [n x n].
01310     )
01311   {
01312     unsigned i = 0;
01313     unsigned j = 0;
01314 
01315     // Check the dimension of W.
01316     if( W.GetNrRows() != n || W.GetNrCols() != n )
01317     {
01318       if( !W.Resize( n, n ) )
01319         return false;
01320     }
01321     // Set the weight matrix.
01322     for( i = 0; i < rxData.m_nrValidObs; i++ )
01323     {
01324       if( rxData.m_ObsArray[i].flags.isActive )
01325       {
01326         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
01327         {
01328           if( rxData.m_ObsArray[i].flags.isPsrUsedInSolution )
01329           {
01330             // Sanity index check.
01331             if( j >= n )
01332               return false;
01333 
01334             // Check divide by zero.
01335             if( rxData.m_ObsArray[i].stdev_psr == 0.0 )
01336               return false;
01337 
01338             W[j][j] = 1.0/(rxData.m_ObsArray[i].stdev_psr*rxData.m_ObsArray[i].stdev_psr);
01339             j++;
01340           }
01341         }
01342       }
01343     }
01344 
01345     // Deal with constraints.
01346     if( rxData.m_pvt.isPositionConstrained )
01347     {
01348       if( j + 3 > n )
01349         return false;
01350             
01351       W[j][j] = 1.0/(rxData.m_pvt.std_lat*rxData.m_pvt.std_lat); 
01352       j++;
01353       W[j][j] = 1.0/(rxData.m_pvt.std_lon*rxData.m_pvt.std_lon); 
01354       j++;
01355       W[j][j] = 1.0/(rxData.m_pvt.std_hgt*rxData.m_pvt.std_hgt); 
01356       j++;      
01357     }
01358     else if( rxData.m_pvt.isHeightConstrained )
01359     {
01360       if( j + 1 > n )
01361         return false;
01362             
01363       W[j][j] = 1.0/(rxData.m_pvt.std_hgt*rxData.m_pvt.std_hgt); 
01364       j++;
01365     }
01366 
01367     return true;
01368   }
01369 
01370 
01371   bool GNSS_Estimator::DetermineMeasurementVarianceCovarianceMatrixForThePositionSolution_GPSL1( 
01372     GNSS_RxData &rxData,  //!< The receiver data.
01373     const unsigned n,     //!< The number of measurements and pseudo-measurements (constraints).
01374     Matrix &R             //!< The pseudorange measurement variance-covariance matrix [n x n].
01375     )
01376   {
01377     unsigned i = 0;
01378     unsigned j = 0;
01379 
01380     // Check the dimension of W.
01381     if( R.GetNrRows() != n || R.GetNrCols() != n )
01382     {
01383       if( !R.Resize( n, n ) )
01384         return false;
01385     }
01386     // Set the weight matrix.
01387     for( i = 0; i < rxData.m_nrValidObs; i++ )
01388     {
01389       if( rxData.m_ObsArray[i].flags.isActive )
01390       {
01391         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
01392         {
01393           if( rxData.m_ObsArray[i].flags.isPsrUsedInSolution )
01394           {
01395             // Sanity index check.
01396             if( j >= n )
01397               return false;
01398 
01399             // Check divide by zero.
01400             if( rxData.m_ObsArray[i].stdev_psr == 0.0 )
01401               return false;
01402 
01403             R[j][j] = rxData.m_ObsArray[i].stdev_psr*rxData.m_ObsArray[i].stdev_psr;
01404             j++;
01405           }
01406         }
01407       }
01408     }
01409 
01410     // Deal with constraints.
01411     if( rxData.m_pvt.isPositionConstrained )
01412     {
01413       if( j + 3 > n )
01414         return false;
01415             
01416       R[j][j] = rxData.m_pvt.std_lat*rxData.m_pvt.std_lat; 
01417       j++;
01418       R[j][j] = rxData.m_pvt.std_lon*rxData.m_pvt.std_lon; 
01419       j++;
01420       R[j][j] = rxData.m_pvt.std_hgt*rxData.m_pvt.std_hgt; 
01421       j++;      
01422     }
01423     else if( rxData.m_pvt.isHeightConstrained )
01424     {
01425       if( j + 1 > n )
01426         return false;
01427             
01428       R[j][j] = rxData.m_pvt.std_hgt*rxData.m_pvt.std_hgt; 
01429       j++;
01430     }
01431 
01432     return true;
01433   }
01434 
01435 
01436 
01437   bool GNSS_Estimator::DeterminePseudorangeMisclosures_GPSL1( 
01438     GNSS_RxData *rxData,     //!< The pointer to the receiver data.    
01439     GNSS_RxData *rxBaseData, //!< The pointer to the reference receiver data. NULL if not available.    
01440     const unsigned n,        //!< The number of misclosures.
01441     Matrix &w                //!< The pseudorange misclosure vector [n x 1].
01442     )
01443   {
01444     unsigned i = 0;
01445     unsigned j = 0;
01446     int k = 0;
01447     double psr_base = 0;
01448     double range_base = 0;
01449     double psr_measured = 0;
01450     double psr_computed = 0;
01451 
01452     // Check the dimension of w.
01453     if( w.GetNrRows() != n || w.GetNrCols() != 1 )
01454     {
01455       if( !w.Resize( n, 1 ) )
01456         return false;
01457     }
01458 
01459     for( i = 0; i < rxData->m_nrValidObs; i++ )
01460     {
01461       if( rxData->m_ObsArray[i].flags.isActive )
01462       {
01463         if( rxData->m_ObsArray[i].system == GNSS_GPS && rxData->m_ObsArray[i].freqType == GNSS_GPSL1 )
01464         {
01465           // allows compute the misclosure value (regardless of whether it is used in solution
01466           psr_measured = rxData->m_ObsArray[i].psr;
01467 
01468           // Add the satellite clock correction.
01469           psr_measured += rxData->m_ObsArray[i].satellite.clk;
01470 
01471           // Compensate for the ionospheric delay if indicated.
01472           // The corrections must be determined beforehand.
01473           if( rxData->m_ObsArray[i].flags.useBroadcastIonoCorrection )
01474           {
01475             // Compensate for the ionospheric delay
01476             psr_measured -= rxData->m_ObsArray[i].corrections.prcIono;
01477           }
01478 
01479           // Compensate for the tropospheric delay if indicated.
01480           // The corrections must be determined beforehand.
01481           if( rxData->m_ObsArray[i].flags.useTropoCorrection )
01482           {
01483             // Compensate for the tropospheric delay
01484             psr_measured -= rxData->m_ObsArray[i].corrections.prcTropoDry;
01485             psr_measured -= rxData->m_ObsArray[i].corrections.prcTropoWet;
01486           }
01487 
01488           range_base = 0;
01489           if( rxBaseData != NULL )
01490           {    
01491             if( rxData->m_ObsArray[i].flags.isDifferentialPsrAvailable )
01492             {
01493               k = rxData->m_ObsArray[i].index_differential;
01494               if( k != -1 )
01495               {
01496                 psr_base  = rxBaseData->m_ObsArray[k].psr;
01497                 psr_base += rxBaseData->m_ObsArray[k].satellite.clk;
01498 
01499                 // Compensate for the ionospheric delay if indicated.
01500                 // The corrections must be determined beforehand.
01501                 if( rxBaseData->m_ObsArray[k].flags.useBroadcastIonoCorrection )
01502                 {
01503                   // Compensate for the ionospheric delay
01504                   psr_base -= rxBaseData->m_ObsArray[k].corrections.prcIono;
01505                 }
01506 
01507                 // Compensate for the tropospheric delay if indicated.
01508                 // The corrections must be determined beforehand.
01509                 if( rxBaseData->m_ObsArray[k].flags.useTropoCorrection )
01510                 {
01511                   // Compensate for the tropospheric delay
01512                   psr_base -= rxBaseData->m_ObsArray[k].corrections.prcTropoDry;
01513                   psr_base -= rxBaseData->m_ObsArray[k].corrections.prcTropoWet;
01514                 }                  
01515 
01516                 range_base = rxBaseData->m_ObsArray[k].range;
01517 
01518                 // Compute the differential pseudorange.
01519                 psr_measured -= psr_base;
01520               }
01521             }
01522           }
01523 
01524           // Calculate the computed pseudorange = geometric range + clock offset (m)
01525           // The range value and the clock offset must be determined beforehand.
01526           // If differential, range_base != 0, it is the computed psuedorange difference.
01527           psr_computed = rxData->m_ObsArray[i].range - range_base + rxData->m_pvt.clockOffset;
01528 
01529           // The misclosure is the corrected measured value minus the computed valid.
01530           rxData->m_ObsArray[i].psr_misclosure = psr_measured - psr_computed;            
01531 
01532           if( rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
01533           {
01534             // Sanity index check.
01535             if( j >= n )
01536               return false;
01537 
01538             w[j] = rxData->m_ObsArray[i].psr_misclosure;
01539             j++;
01540           }
01541         }
01542         else
01543         {
01544           rxData->m_ObsArray[i].psr_misclosure = 0.0;            
01545         }
01546       }
01547     }
01548 
01549     // Deal with constraints.
01550     if( rxData->m_pvt.isPositionConstrained )
01551     {
01552       if( j + 3 > n )
01553         return false;
01554 
01555       double N;
01556       double M;
01557       double diff;
01558 
01559       GEODESY_ComputePrimeVerticalRadiusOfCurvature(
01560         GEODESY_REFERENCE_ELLIPSE_WGS84,
01561         rxData->m_prev_pvt.latitude,
01562         &N );
01563       GEODESY_ComputeMeridianRadiusOfCurvature( 
01564         GEODESY_REFERENCE_ELLIPSE_WGS84,
01565         rxData->m_prev_pvt.latitude,
01566         &M );
01567             
01568       diff = (rxData->m_prev_pvt.latitude - rxData->m_pvt.latitude);
01569       diff *= ( M + rxData->m_prev_pvt.height ); // convert to meters.
01570       w[j] = diff;
01571       j++;
01572       diff = (rxData->m_prev_pvt.longitude - rxData->m_pvt.longitude );
01573       diff *= (N + rxData->m_prev_pvt.height)*cos(rxData->m_prev_pvt.latitude); // convert to meters.
01574       w[j] = diff;
01575       j++;
01576       w[j] = rxData->m_prev_pvt.height - rxData->m_pvt.height;
01577       j++;      
01578     }
01579     else if( rxData->m_pvt.isHeightConstrained )
01580     {
01581       if( j + 1 > n )
01582         return false;
01583             
01584       w[j] = rxData->m_prev_pvt.height - rxData->m_pvt.height;
01585       j++;
01586     }
01587 
01588 
01589     return true;
01590   }
01591 
01592 
01593   bool GNSS_Estimator::DetermineBetweenReceiverDifferentialIndex(
01594     GNSS_RxData *rxData,                 //!< (input) The pointer to the receiver data.    
01595     GNSS_RxData *rxBaseData,             //!< (input) The pointer to the reference receiver data. NULL if not available.        
01596     const bool setToUseOnlyDifferential  //!< (input) This indicates that only differential measurements should be used.    
01597     )
01598   {
01599     unsigned i = 0;
01600     unsigned j = 0;
01601     //unsigned char isGood = 0;
01602 
01603     // Initial the indices of the corresponding differential measurements.
01604     for( i = 0; i < rxData->m_nrValidObs; i++ ) 
01605     { 
01606       rxData->m_ObsArray[i].index_differential = -1; 
01607       rxData->m_ObsArray[i].flags.isDifferentialPsrAvailable = 0;      
01608       rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable = 0;      
01609       rxData->m_ObsArray[i].flags.isDifferentialDopplerAvailable = 0;      
01610     }
01611     for( i = 0; i < rxBaseData->m_nrValidObs; i++ ) 
01612     { 
01613       rxBaseData->m_ObsArray[i].index_differential = -1; 
01614       rxBaseData->m_ObsArray[i].flags.isDifferentialPsrAvailable = 0;
01615       rxBaseData->m_ObsArray[i].flags.isDifferentialAdrAvailable = 0;
01616       rxBaseData->m_ObsArray[i].flags.isDifferentialDopplerAvailable = 0;
01617     }
01618     if( rxBaseData == NULL )
01619       return true;
01620 
01621     for( i = 0; i < rxData->m_nrValidObs; i++ )
01622     {
01623       if( rxData->m_ObsArray[i].flags.isActive )
01624       {
01625         // Look for a matching differential channel in the base station data.
01626         for( j = 0; j < rxBaseData->m_nrValidObs; j++ )
01627         {
01628           if( rxBaseData->m_ObsArray[j].flags.isActive )
01629           {
01630             if( rxData->m_ObsArray[i].system == rxBaseData->m_ObsArray[j].system &&
01631               rxData->m_ObsArray[i].codeType == rxBaseData->m_ObsArray[j].codeType &&
01632               rxData->m_ObsArray[i].freqType == rxBaseData->m_ObsArray[j].freqType &&
01633               rxData->m_ObsArray[i].id       == rxBaseData->m_ObsArray[j].id )
01634             {
01635               rxData->m_ObsArray[i].index_differential     = j;
01636               rxBaseData->m_ObsArray[j].index_differential = i;
01637 
01638               if( rxData->m_ObsArray[i].flags.isPsrUsedInSolution &&
01639                 rxBaseData->m_ObsArray[j].flags.isPsrUsedInSolution )
01640               {
01641                 rxData->m_ObsArray[i].flags.isDifferentialPsrAvailable = 1;
01642                 rxBaseData->m_ObsArray[j].flags.isDifferentialPsrAvailable = 1;
01643               }
01644 
01645               if( rxData->m_ObsArray[i].flags.isDopplerUsedInSolution &&
01646                 rxBaseData->m_ObsArray[j].flags.isDopplerUsedInSolution )
01647               {
01648                 rxData->m_ObsArray[i].flags.isDifferentialDopplerAvailable = 1;
01649                 rxBaseData->m_ObsArray[j].flags.isDifferentialDopplerAvailable = 1;
01650               }
01651 
01652               if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution &&
01653                 rxBaseData->m_ObsArray[j].flags.isAdrUsedInSolution )
01654               {
01655                 rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable = 1;
01656                 rxBaseData->m_ObsArray[j].flags.isDifferentialAdrAvailable = 1;
01657               }
01658 
01659               break;
01660             }
01661           }
01662         }
01663       }
01664     }
01665 
01666     if( setToUseOnlyDifferential )
01667     {
01668       for( i = 0; i < rxData->m_nrValidObs; i++ )
01669       {
01670 
01671         if( rxData->m_ObsArray[i].flags.isActive )
01672         {
01673 
01674           if( rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
01675           {
01676             if( !rxData->m_ObsArray[i].flags.isDifferentialPsrAvailable )
01677             {
01678               rxData->m_ObsArray[i].flags.isPsrUsedInSolution = 0;              
01679             }
01680           }
01681 
01682           if( rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
01683           {
01684             if( !rxData->m_ObsArray[i].flags.isDifferentialDopplerAvailable )
01685             {
01686               rxData->m_ObsArray[i].flags.isDifferentialDopplerAvailable = 0;              
01687             }
01688           }
01689 
01690           if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
01691           {
01692             if( !rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable )
01693             {
01694               rxData->m_ObsArray[i].flags.isAdrUsedInSolution = 0;              
01695             }
01696           }
01697 
01698         }
01699 
01700       }
01701     }
01702 
01703     return true;
01704   }
01705 
01706 
01707   bool GNSS_Estimator::DetermineSingleDifferenceADR_Misclosures_GPSL1( 
01708     GNSS_RxData *rxData,     //!< The pointer to the receiver data.    
01709     GNSS_RxData *rxBaseData, //!< The pointer to the reference receiver data. NULL if not available.    
01710     const unsigned n,        //!< The number of misclosures.
01711     Matrix &w                //!< The adr misclosure vector [n x 1].
01712     )
01713   {
01714     unsigned i = 0;
01715     unsigned j = 0;
01716     int k = 0;
01717     double adr_base = 0;
01718     double range_base = 0;
01719     double adr_measured = 0;
01720     double adr_computed = 0;
01721 
01722     if( n == 0 )
01723       return true;
01724 
01725     // Check the dimension of w.
01726     if( w.GetNrRows() != n || w.GetNrCols() != 1 )
01727     {
01728       if( !w.Resize( n, 1 ) )
01729         return false;
01730     }
01731 
01732     for( i = 0; i < rxData->m_nrValidObs; i++ )
01733     {
01734       if( rxData->m_ObsArray[i].flags.isActive )
01735       {
01736         if( rxData->m_ObsArray[i].system == GNSS_GPS && rxData->m_ObsArray[i].freqType == GNSS_GPSL1 )
01737         {
01738           // allows computation of the misclosure value (regardless of whether it is used in solution
01739           adr_measured = rxData->m_ObsArray[i].adr * GPS_WAVELENGTHL1;
01740 
01741           // Add the satellite clock correction.
01742           adr_measured += rxData->m_ObsArray[i].satellite.clk;
01743 
01744           // Compensate for the ionospheric delay if indicated.
01745           // The corrections must be determined beforehand.
01746           if( rxData->m_ObsArray[i].flags.useBroadcastIonoCorrection )
01747           {
01748             // Compensate for the ionospheric delay
01749             adr_measured += rxData->m_ObsArray[i].corrections.prcIono;
01750           }
01751 
01752           // Compensate for the tropospheric delay if indicated.
01753           // The corrections must be determined beforehand.
01754           if( rxData->m_ObsArray[i].flags.useTropoCorrection )
01755           {
01756             // Compensate for the tropospheric delay
01757             adr_measured -= rxData->m_ObsArray[i].corrections.prcTropoDry;
01758             adr_measured -= rxData->m_ObsArray[i].corrections.prcTropoWet;
01759           }
01760 
01761           range_base = 0;
01762           if( rxBaseData != NULL )
01763           {    
01764             if( rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable )
01765             {
01766               k = rxData->m_ObsArray[i].index_differential;
01767               if( k != -1 )
01768               {
01769                 adr_base  = rxBaseData->m_ObsArray[k].adr * GPS_WAVELENGTHL1;
01770                 adr_base += rxBaseData->m_ObsArray[k].satellite.clk;
01771                 
01772                 // Compensate for the ionospheric delay if indicated.
01773                 // The corrections must be determined beforehand.
01774                 if( rxBaseData->m_ObsArray[k].flags.useBroadcastIonoCorrection )
01775                 {
01776                   // Compensate for the ionospheric delay
01777                   adr_base += rxBaseData->m_ObsArray[k].corrections.prcIono;
01778                 }
01779 
01780                 // Compensate for the tropospheric delay if indicated.
01781                 // The corrections must be determined beforehand.
01782                 if( rxBaseData->m_ObsArray[k].flags.useTropoCorrection )
01783                 {
01784                   // Compensate for the tropospheric delay
01785                   adr_base -= rxBaseData->m_ObsArray[k].corrections.prcTropoDry;
01786                   adr_base -= rxBaseData->m_ObsArray[k].corrections.prcTropoWet;
01787                 }                  
01788 
01789                 range_base = rxBaseData->m_ObsArray[k].range;
01790 
01791                 // Compute the differential adr.
01792                 adr_measured -= adr_base;
01793               }
01794             }
01795           }
01796 
01797           // Calculate the computed adr = geometric range + clock offset (m)
01798           // The range value and the clock offset must be determined beforehand.
01799           // If differential, range_base != 0, and the ambiguity is the single differnce ambiguity [m].
01800           adr_computed = rxData->m_ObsArray[i].range - range_base;
01801           adr_computed += rxData->m_pvt.clockOffset;          
01802           adr_computed += rxData->m_ObsArray[i].ambiguity; 
01803 
01804           // The misclosure is the corrected measured value minus the computed valid.
01805           rxData->m_ObsArray[i].adr_misclosure = adr_measured - adr_computed;            
01806 
01807           if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
01808           {
01809             // Sanity index check.
01810             if( j >= n )
01811               return false;
01812 
01813             w[j] = rxData->m_ObsArray[i].adr_misclosure;
01814             j++;
01815           }
01816         }
01817         else
01818         {
01819           rxData->m_ObsArray[i].adr_misclosure = 0.0;            
01820         }
01821       }
01822     }
01823     return true;
01824   }
01825 
01826   bool GNSS_Estimator::DetermineDoubleDifferenceADR_Misclosures_GPSL1( 
01827     GNSS_RxData *rxData,     //!< The pointer to the receiver data.    
01828     GNSS_RxData *rxBaseData, //!< The pointer to the reference receiver data. NULL if not available. 
01829     Matrix &subB,             //!< The matrix that describes the differencing from SD to DD adr measurements
01830     const unsigned n,        //!< The number of DD misclosures required.
01831     Matrix &w                //!< The adr misclosure vector [n x 1].
01832     )
01833   {
01834     unsigned i = 0;
01835     unsigned j = 0;
01836     int k = 0;
01837     double adr_base = 0;
01838     double range_base = 0;
01839     double adr_measured = 0;
01840     double adr_computed = 0;
01841 
01842     if( n == 0 )
01843       return true;
01844 
01845     // Check the dimension of w.
01846     if( w.GetNrRows() != n || w.GetNrCols() != 1 )
01847     {
01848       if( !w.Resize( n, 1 ) )
01849         return false;
01850     }
01851 
01852     for( i = 0; i < rxData->m_nrValidObs; i++ )
01853     {
01854       if( rxData->m_ObsArray[i].flags.isActive )
01855       {
01856         if( rxData->m_ObsArray[i].system == GNSS_GPS && rxData->m_ObsArray[i].freqType == GNSS_GPSL1 )
01857         {
01858           // allows computation of the misclosure value (regardless of whether it is used in solution
01859           adr_measured = rxData->m_ObsArray[i].adr * GPS_WAVELENGTHL1;
01860 
01861           // Add the satellite clock correction.
01862           adr_measured += rxData->m_ObsArray[i].satellite.clk;
01863 
01864           // Compensate for the ionospheric delay if indicated.
01865           // The corrections must be determined beforehand.
01866           if( rxData->m_ObsArray[i].flags.useBroadcastIonoCorrection )
01867           {
01868             // Compensate for the ionospheric delay
01869             adr_measured += rxData->m_ObsArray[i].corrections.prcIono;
01870           }
01871 
01872           // Compensate for the tropospheric delay if indicated.
01873           // The corrections must be determined beforehand.
01874           if( rxData->m_ObsArray[i].flags.useTropoCorrection )
01875           {
01876             // Compensate for the tropospheric delay
01877             adr_measured -= rxData->m_ObsArray[i].corrections.prcTropoDry;
01878             adr_measured -= rxData->m_ObsArray[i].corrections.prcTropoWet;
01879           }
01880 
01881           range_base = 0;
01882           if( rxBaseData != NULL )
01883           {    
01884             if( rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable )
01885             {
01886               k = rxData->m_ObsArray[i].index_differential;
01887               if( k != -1 )
01888               {
01889                 adr_base  = rxBaseData->m_ObsArray[k].adr * GPS_WAVELENGTHL1;
01890                 adr_base += rxBaseData->m_ObsArray[k].satellite.clk;
01891                 
01892                 // Compensate for the ionospheric delay if indicated.
01893                 // The corrections must be determined beforehand.
01894                 if( rxBaseData->m_ObsArray[k].flags.useBroadcastIonoCorrection )
01895                 {
01896                   // Compensate for the ionospheric delay
01897                   adr_base += rxBaseData->m_ObsArray[k].corrections.prcIono;
01898                 }
01899 
01900                 // Compensate for the tropospheric delay if indicated.
01901                 // The corrections must be determined beforehand.
01902                 if( rxBaseData->m_ObsArray[k].flags.useTropoCorrection )
01903                 {
01904                   // Compensate for the tropospheric delay
01905                   adr_base -= rxBaseData->m_ObsArray[k].corrections.prcTropoDry;
01906                   adr_base -= rxBaseData->m_ObsArray[k].corrections.prcTropoWet;
01907                 }                  
01908 
01909                 range_base = rxBaseData->m_ObsArray[k].range;
01910 
01911                 // Compute the differential adr.
01912                 adr_measured -= adr_base;
01913               }
01914             }
01915           }
01916 
01917           // Calculate the computed adr = geometric range + clock offset (m)
01918           // The range value and the clock offset must be determined beforehand.
01919           // If differential, range_base != 0, and the ambiguity is the single differnce ambiguity [m].
01920           adr_computed = rxData->m_ObsArray[i].range - range_base;
01921           adr_computed += rxData->m_pvt.clockOffset;          
01922           adr_computed += rxData->m_ObsArray[i].ambiguity; 
01923 
01924           // The misclosure is the corrected measured value minus the computed valid.
01925           rxData->m_ObsArray[i].adr_misclosure = adr_measured - adr_computed;            
01926 
01927           if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
01928           {
01929             // Sanity index check.
01930             if( j >= n )
01931               return false;
01932 
01933             w[j] = rxData->m_ObsArray[i].adr_misclosure;
01934             j++;
01935           }
01936         }
01937         else
01938         {
01939           rxData->m_ObsArray[i].adr_misclosure = 0.0;            
01940         }
01941       }
01942     }
01943     return true;
01944   }
01945 
01946   bool GNSS_Estimator::DetermineDopplerMisclosures_GPSL1( 
01947     GNSS_RxData *rxData,     //!< The pointer to the receiver data.    
01948     GNSS_RxData *rxBaseData, //!< The pointer to the reference receiver data. NULL if not available.    
01949     const unsigned n,        //!< The number of misclosures.
01950     Matrix &w                //!< The pseudorange misclosure vector [n x 1].
01951     )
01952   {
01953     unsigned i = 0;
01954     unsigned j = 0;
01955     int k = 0;
01956     double doppler_base = 0;
01957     double rangerate_base = 0;
01958     double doppler_measured = 0;
01959     double doppler_computed = 0;
01960 
01961     if( n == 0 )
01962       return true;
01963 
01964     // Check the dimension of w.
01965     if( w.GetNrRows() != n || w.GetNrCols() != 1 )
01966     {
01967       if( !w.Resize( n, 1 ) )
01968         return false;
01969     }
01970     for( i = 0; i < rxData->m_nrValidObs; i++ )
01971     {
01972       if( rxData->m_ObsArray[i].flags.isActive )
01973       {
01974         rxData->m_ObsArray[i].doppler_misclosure = 0.0;            
01975 
01976         if( rxData->m_ObsArray[i].system == GNSS_GPS && rxData->m_ObsArray[i].freqType == GNSS_GPSL1 )
01977         {
01978           // always compute the misclosure regardless of whether it is used in solution.
01979           
01980           // Compute the pseudorange misclosures in meters/second!
01981           doppler_measured = rxData->m_ObsArray[i].doppler * GPS_WAVELENGTHL1;
01982 
01983           // Add the satellite clock drift.        
01984           doppler_measured += rxData->m_ObsArray[i].satellite.clkdrift;
01985           
01986           rangerate_base = 0;
01987           if( rxBaseData != NULL )
01988           {
01989             doppler_base = 0;
01990             if( rxData->m_ObsArray[i].flags.isDifferentialDopplerAvailable )
01991             {
01992               k = rxData->m_ObsArray[i].index_differential;
01993               if( k != -1 )
01994               {
01995                 doppler_base   = rxBaseData->m_ObsArray[k].doppler * GPS_WAVELENGTHL1;
01996                 rangerate_base = rxBaseData->m_ObsArray[k].rangerate;
01997               }
01998               doppler_measured -= doppler_base;
01999             }
02000           }
02001 
02002           // Calculate the computed doppler = geometric range rate + rx clock drift [m/s]
02003           doppler_computed = rxData->m_ObsArray[i].rangerate - rangerate_base + rxData->m_pvt.clockDrift;
02004 
02005           // The misclosure is the corrected measured value minus the computed valid.            
02006           rxData->m_ObsArray[i].doppler_misclosure = doppler_measured - doppler_computed;
02007 
02008           if( rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
02009           {
02010             if( j >= n )
02011               return false;
02012             
02013             w[j] = rxData->m_ObsArray[i].doppler_misclosure;
02014             j++;
02015           }
02016         }
02017       }
02018     }
02019 
02020     if( rxData->m_pvt.isPositionConstrained )
02021     {
02022       if( j + 3 > n )
02023         return false;
02024 
02025       w[j] = 0.0;
02026       j++;
02027       w[j] = 0.0;
02028       j++;
02029       w[j] = 0.0;
02030       j++;
02031     }
02032     else if( rxData->m_pvt.isHeightConstrained )
02033     {
02034       if( j + 1 > n )
02035         return false;
02036      
02037       w[j] = 0.0;
02038       j++;
02039     }
02040 
02041     return true;
02042   }
02043 
02044 
02045   bool GNSS_Estimator::DetermineDesignMatrixForTheVelocitySolution_GPSL1( 
02046     GNSS_RxData &rxData, //!< The receiver data.
02047     const unsigned n,    //!< The number of rows in the design matrix.
02048     Matrix &H            //!< The velocity & rx clock drift design matrix [n x 4].
02049     )
02050   {
02051     unsigned i = 0;
02052     unsigned j = 0;
02053 
02054     if( n == 0 )
02055       return true;
02056 
02057     // Check the dimension of H.
02058     if( H.GetNrRows() != n || H.GetNrCols() != 4 )
02059     {
02060       if( !H.Resize( n, 4 ) )
02061         return false;
02062     }
02063     // Compute the design matrix for the position solution.
02064     for( i = 0; i < rxData.m_nrValidObs; i++ )
02065     {
02066       if( rxData.m_ObsArray[i].flags.isActive )
02067       {
02068         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
02069         {
02070           if( rxData.m_ObsArray[i].flags.isDopplerUsedInSolution )
02071           {
02072             // Sanity index check.            
02073             if( j >= n )
02074               return false;
02075             
02076             NAVIGATION_ComputeDerivativesOf_Range_WithRespectToLatitudeLongitudeHeight(
02077               rxData.m_pvt.latitude,
02078               rxData.m_pvt.longitude, 
02079               rxData.m_pvt.height,
02080               rxData.m_ObsArray[i].satellite.x,
02081               rxData.m_ObsArray[i].satellite.y,
02082               rxData.m_ObsArray[i].satellite.z,
02083               &H[j][0],
02084               &H[j][1],
02085               &H[j][2],
02086               &rxData.m_ObsArray[i].range
02087               );
02088             H[j][0] *= -1.0; // Doppler sign convention, NovAtel convention, increasing psr means negative Doppler
02089             H[j][1] *= -1.0;
02090             H[j][2] *= -1.0;
02091             H[j][3] = 1.0;
02092 
02093             // copy the row of the design matrix 
02094             rxData.m_ObsArray[i].H_v[0] = H[j][0];
02095             rxData.m_ObsArray[i].H_v[1] = H[j][1];
02096             rxData.m_ObsArray[i].H_v[2] = H[j][2];
02097 
02098             j++;
02099           }
02100         }
02101       }
02102     }
02103 
02104     if( rxData.m_pvt.isPositionConstrained )
02105     {
02106       if( j + 3 > n )
02107         return false;
02108 
02109       H[j][0] = 1.0;
02110       H[j][1] = 0.0;
02111       H[j][2] = 0.0;      
02112       H[j][3] = 0.0;      
02113       j++;
02114       H[j][0] = 0.0;
02115       H[j][1] = 1.0;
02116       H[j][2] = 0.0;      
02117       H[j][3] = 0.0;            
02118       j++;
02119       H[j][0] = 0.0;
02120       H[j][1] = 0.0;
02121       H[j][2] = 1.0;      
02122       H[j][3] = 0.0;            
02123       j++;
02124     }
02125     else if( rxData.m_pvt.isHeightConstrained )
02126     {
02127       if( j + 1 > n )
02128         return false;
02129      
02130       H[j][0] = 0.0;
02131       H[j][1] = 0.0;
02132       H[j][2] = 1.0;      
02133       H[j][3] = 0.0;            
02134       j++;
02135     }
02136 
02137     return true;
02138   }
02139 
02140 
02141   bool GNSS_Estimator::DetermineMeasurementWeightMatrixForTheVelocitySolution_GPSL1( 
02142     GNSS_RxData &rxData,  //!< The receiver data.
02143     const unsigned n,     //!< The number of rows in W.
02144     Matrix &W             //!< The inverse of the Doppler measurement variance-coraiance matrix [n x n].
02145     )
02146   {
02147     unsigned i = 0;
02148     unsigned j = 0;
02149     double std_ms = 0.0; // stdev in m/s
02150 
02151     // Check the dimension of W.
02152     if( W.GetNrRows() != n || W.GetNrCols() != n )
02153     {
02154       if( !W.Resize( n, n ) )
02155         return false;
02156     }
02157     // Set the weight matrix.
02158     for( i = 0; i < rxData.m_nrValidObs; i++ )
02159     {
02160       if( rxData.m_ObsArray[i].flags.isActive )
02161       {
02162         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
02163         {
02164           if( rxData.m_ObsArray[i].flags.isDopplerUsedInSolution )
02165           {
02166             // Sanity index check.
02167             if( j >= n )
02168               return false;
02169 
02170             // Check divide by zero.
02171             if( rxData.m_ObsArray[i].stdev_doppler == 0.0 )
02172               return false;
02173 
02174             std_ms = rxData.m_ObsArray[i].stdev_doppler * GPS_WAVELENGTHL1;
02175             W[j][j] = 1.0/(std_ms*std_ms);            
02176             j++;
02177           }
02178         }
02179       }
02180     }
02181 
02182     if( rxData.m_pvt.isPositionConstrained )
02183     {
02184       if( j + 3 > n )
02185         return false;
02186 
02187       W[j][j] = 1.0/(1.0e-10);
02188       j++;
02189       W[j][j] = 1.0/(1.0e-10);
02190       j++;
02191       W[j][j] = 1.0/(1.0e-10);
02192       j++;
02193     }
02194     else if( rxData.m_pvt.isHeightConstrained )
02195     {
02196       if( j + 1 > n )
02197         return false;
02198      
02199       W[j][j] = 1.0/(1.0e-10);
02200       j++;
02201     }
02202 
02203     return true;
02204   }
02205 
02206 
02207   bool GNSS_Estimator::DetermineMeasurementVarianceCovarianceMatrixForTheVelocitySolution_GPSL1( 
02208     GNSS_RxData &rxData,  //!< The receiver data.
02209     const unsigned n,     //!< The number of rows in R.
02210     Matrix &R             //!< The inverse of the Doppler measurement variance-coraiance matrix [n x n].
02211     )
02212   {
02213     unsigned i = 0;
02214     unsigned j = 0;
02215     double std_ms = 0; // stdev in m/s
02216 
02217     // Check the dimension of R.
02218     if( R.GetNrRows() != n || R.GetNrCols() != n )
02219     {
02220       if( !R.Resize( n, n ) )
02221         return false;
02222     }
02223     // Set the weight matrix.
02224     for( i = 0; i < rxData.m_nrValidObs; i++ )
02225     {
02226       if( rxData.m_ObsArray[i].flags.isActive )
02227       {
02228         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
02229         {
02230           if( rxData.m_ObsArray[i].flags.isDopplerUsedInSolution )
02231           {
02232             // Sanity index check.
02233             if( j >= n )
02234               return false;
02235 
02236             // Check divide by zero.
02237             if( rxData.m_ObsArray[i].stdev_doppler == 0.0 )
02238               return false;
02239 
02240             // Convert to meters/second!
02241             std_ms = rxData.m_ObsArray[i].stdev_doppler * GPS_WAVELENGTHL1;
02242 
02243             R[j][j] = std_ms*std_ms;
02244             j++;
02245           }
02246         }
02247       }
02248     }
02249 
02250     if( rxData.m_pvt.isPositionConstrained )
02251     {
02252       if( j + 3 > n )
02253         return false;
02254 
02255       R[j][j] = 1.0e-10;
02256       j++;
02257       R[j][j] = 1.0e-10;
02258       j++;
02259       R[j][j] = 1.0e-10;
02260       j++;
02261     }
02262     else if( rxData.m_pvt.isHeightConstrained )
02263     {
02264       if( j + 1 > n )
02265         return false;
02266      
02267       R[j][j] = 1.0e-10;
02268       j++;
02269     }
02270 
02271     return true;
02272   }
02273 
02274 
02275 
02276   /// \brief    Perform the Global Internal Reliability Test, followed by a 
02277   ///           search using local testing for a single measurement fault if 
02278   ///           the global test fails.
02279   ///
02280   /// The Global Internal Reliability Test: \n
02281   /// The aposteriori variance factor is computed and compared to the value 
02282   /// generated using Chi^2 lookup table. The aposerteriori variance factor 
02283   /// indicates the following: \n
02284   /// if( apv ~= 1 ) \n
02285   ///   solution and observations are well modelled. \n
02286   /// if( apv < 1 ) \n
02287   ///   observation variance matrix is pessimistic. \n
02288   ///   (observations are better than what you said). \n
02289   /// if( apv > 1 ) \n
02290   ///   (1) The math model incorrect, (not likely) \n
02291   ///   (2) The weight matrix/observation variance matrix is optimistic 
02292   ///      (observations are worse than what you said). \n
02293   ///   (3) Their is a blunder in the observations that is skewing the normality 
02294   ///       of the solution, and a local test for blunder my be needed. \n
02295   ///
02296   bool GNSS_Estimator::PerformGlobalTestAndTestForMeasurementFaults( 
02297     GNSS_RxData &rxData,           //!< The receiver data object.
02298     bool testPsrOrDoppler,         //!< This indicates if the psr misclosures are checked, otherwise the Doppler misclosures are checked. 
02299     Matrix& H,                     //!< The design matrix, H,                           [n x u].
02300     Matrix& Ht,                    //!< The design matrix transposed, H,                [n x u].
02301     Matrix& W,                     //!< The observation weight matrix, W,               [n x n].
02302     Matrix& R,                     //!< The observation variance-covariance matrix, R,  [n x n].
02303     Matrix& r,                     //!< The observation residual vector,                [n x 1].
02304     Matrix& P,                     //!< The state variance-covariance matrix,           [u x u].
02305     const unsigned char n,         //!< The number of observations, n.
02306     const unsigned char u,         //!< The number of unknowns, u.
02307     double &avf,                   //!< The computed a-posteriori variance factor is returned.
02308     bool &isGlobalTestPassed,      //!< This indicates if the global test passed.    
02309     bool &hasRejectionOccurred,    //!< This indicates if a rejection occurred. Only one measurement is flagged.
02310     unsigned char &indexOfRejected //!< This is the index of the rejected observation.
02311     )
02312   {
02313     double v = n-u; // The degree of freedom.
02314 
02315     unsigned i = 0;
02316     unsigned j = 0; 
02317     unsigned indexvec[GNSS_RXDATA_NR_CHANNELS]; // An array with the indices measurements that are used in solution.
02318 
02319     double rv = 0;           // An unsigned standardized residual value.
02320     double largest_rv = 0.0; // The largest unsigned standardized residual value.    
02321     unsigned char indexOfLargest = 0; // The index of the largest standardized residual value.  
02322 
02323     double chiSquaredValue = 0;                     // The chi squared test value = look up table value / degrees of freedom.
02324     double chiSquared005[31] = GNSS_CHISQUARE_00_5; // The chi squared look up table for alpha = 0.005.
02325     
02326     // Initial output values.
02327     isGlobalTestPassed = false;
02328     hasRejectionOccurred = false;      
02329     
02330     Matrix Cr;             // The variance-covariance matrix of the residuals [n x n].
02331     Matrix rT;             // The residuals vector transposed,                [1 x n]
02332     Matrix r_standardized; // The standardized residuals,                     [n x 1].
02333     Matrix tmpM;
02334 
02335     PrintMatToDebug( "P", P );
02336 
02337     i = static_cast<unsigned>(v);
02338     if( i == 0 )
02339       return true; 
02340     
02341     rT = r;
02342     if( !rT.Inplace_Transpose() )
02343       return false;
02344 
02345     // Compute the a-posteriori variance factor.
02346     tmpM = rT * W * r;
02347     avf = tmpM[0] / v;
02348     
02349     // Determine the chi squared test statistic value.
02350     i = static_cast<unsigned>(v);
02351     if( i < 0 || i > 30 )
02352       return false;
02353     chiSquaredValue = chiSquared005[i];
02354     chiSquaredValue /= v;
02355     
02356     // Perform the Global Test.
02357     if( avf < chiSquaredValue )
02358     {
02359       // The Global test passes. No local test will be performed.
02360       isGlobalTestPassed = true;
02361       return true;
02362     }
02363 
02364     // Check that there is enough redudancy to remove outliers.
02365     i = static_cast<unsigned>(v);
02366     if( i <= 0 )
02367     {
02368       return true;
02369     }
02370 
02371     
02372     ////
02373     // Perform the local test.
02374 
02375     // Determine the indices of the observations that match the
02376     // values in the residuals vector.
02377     j = 0;
02378     for( i = 0; i < rxData.m_nrValidObs; i++ )
02379     {
02380       if( rxData.m_ObsArray[i].flags.isActive )
02381       {
02382         if( rxData.m_ObsArray[i].system == GNSS_GPS && rxData.m_ObsArray[i].freqType == GNSS_GPSL1 )
02383         {
02384           if( testPsrOrDoppler )
02385           {
02386             if( rxData.m_ObsArray[i].flags.isPsrUsedInSolution )
02387             {
02388               indexvec[j] = i;
02389               j++;
02390             }
02391           }
02392           else
02393           {
02394             if( rxData.m_ObsArray[i].flags.isDopplerUsedInSolution )
02395             {
02396               indexvec[j] = i;
02397               j++;
02398             }
02399           }
02400         }        
02401       }
02402     }
02403     
02404     
02405     // Compute the variance-covariance of the residuals.
02406     Cr = R - H * P * Ht;
02407 
02408     PrintMatToDebug( "Cr", Cr );
02409 
02410 
02411     // Check the diagonal of Cr for zero and negative values, an error condition.
02412     for( i = 0; i < Cr.GetNrRows(); i++ )
02413     {
02414       if( Cr[i][i] <= 0.0 )
02415       {
02416         return false;
02417       }
02418     }
02419 
02420     
02421     if( !r_standardized.Resize( Cr.GetNrRows(), 1) )
02422       return false;
02423 
02424     // Compute the standardized residuals, r(i) /= Cr(i,i).
02425     // Determine the largest standardized residual value.
02426     for( i = 0; i < Cr.GetNrRows(); i++ )
02427     {
02428       r_standardized[i] = r[i] / sqrt( Cr[i][i] );
02429 
02430       rv = fabs( r_standardized[i] );
02431 
02432       // don't allow the position constraint to be rejected.
02433       if( rxData.m_pvt.isPositionConstrained )
02434       {
02435         if( i >= Cr.GetNrRows() -3 )
02436           continue;
02437       }
02438 
02439       if( rv > largest_rv )
02440       {
02441         largest_rv = rv;
02442         indexOfLargest = i; // This is the index into r.
02443       }
02444     }
02445     indexOfLargest = indexvec[indexOfLargest]; // This is the index into the observation array.
02446 
02447     // sanity index check
02448     if( indexOfLargest >= rxData.m_nrValidObs )
02449       return false;
02450 
02451     PrintMatToDebug( "r", r );
02452     PrintMatToDebug( "r_standardized", r_standardized );
02453     
02454     // In reliability testing, alpha = 0.005, n_(1-alpha/2) = 4.57
02455     if( largest_rv > 4.57 ) // reject only clear blunders
02456     {
02457       // An observation will be rejected.
02458       hasRejectionOccurred = true;      
02459 
02460       if( testPsrOrDoppler ) // true is pseudorange
02461         rxData.m_ObsArray[indexOfLargest].flags.isNotPsrRejected = 0;
02462       else
02463         rxData.m_ObsArray[indexOfLargest].flags.isNotDopplerRejected = 0;      
02464     }
02465 
02466     return true;
02467   }
02468 
02469 
02470   bool GNSS_Estimator::ComputeTransitionMatrix_8StatePVGM(
02471     const double dT,  //!< The change in time since the last update [s].
02472     Matrix &T         //!< The transition matrix [8 x 8].
02473     )
02474   {
02475     const double betaVn       = 1.0/m_KF.alphaVn;       // The Gauss Markov beta for northing velocity [1/s].
02476     const double betaVe       = 1.0/m_KF.alphaVe;       // The Gauss Markov beta for easting velocity [1/s].
02477     const double betaVup      = 1.0/m_KF.alphaVup;      // The Gauss Markov beta for up velocity [1/s].
02478     const double betaClkDrift = 1.0/m_KF.alphaClkDrift; // The Gauss Markov beta for the clock drift [1/s].
02479 
02480     double eVn = 0;
02481     double eVe = 0;
02482     double eVup = 0;
02483     double eClkDrift = 0;
02484 
02485     
02486     if( T.GetNrRows() != 8 || T.GetNrCols() != 8 )
02487     {
02488       if( !T.Resize(8,8) )
02489         return false;
02490     }    
02491     
02492     eVn  = exp( -betaVn  * dT );
02493     eVe  = exp( -betaVe  * dT );
02494     eVup = exp( -betaVup * dT );
02495 
02496     eClkDrift = exp( -betaClkDrift * dT );
02497 
02498     T.Zero();
02499     
02500     T[0][0] = 1.0;
02501     T[0][3] = (1.0 - eVn) / betaVn;
02502 
02503     T[1][1] = 1.0;
02504     T[1][4] = (1.0 - eVe) / betaVe;
02505 
02506     T[2][2] = 1.0;
02507     T[2][5] = (1.0 - eVup) / betaVup;
02508     
02509     T[3][3] = eVn;
02510     T[4][4] = eVe;
02511     T[5][5] = eVup;
02512 
02513     T[6][6] = 1.0;
02514     T[6][7] = (1.0 - eClkDrift) / betaClkDrift;
02515 
02516     T[7][7] = eClkDrift;
02517 
02518     return true;
02519   }
02520 
02521   bool GNSS_Estimator::ComputeTransitionMatrix_8StatePVGM_Float(
02522     const double dT,  //!< The change in time since the last update [s].
02523     Matrix &T         //!< The transition matrix [(8 + nrAmb) x (8 + nrAmb)]. 
02524     )
02525   {
02526     const double betaVn       = 1.0/m_KF.alphaVn;       // The Gauss Markov beta for northing velocity [1/s].
02527     const double betaVe       = 1.0/m_KF.alphaVe;       // The Gauss Markov beta for easting velocity [1/s].
02528     const double betaVup      = 1.0/m_KF.alphaVup;      // The Gauss Markov beta for up velocity [1/s].
02529     const double betaClkDrift = 1.0/m_KF.alphaClkDrift; // The Gauss Markov beta for the clock drift [1/s].
02530 
02531     double eVn = 0;
02532     double eVe = 0;
02533     double eVup = 0;
02534     double eClkDrift = 0;
02535     const unsigned int u = 8 + static_cast<unsigned int>(m_ActiveAmbiguitiesList.size());
02536 
02537     T.Identity( u );
02538     
02539     eVn  = exp( -betaVn  * dT );
02540     eVe  = exp( -betaVe  * dT );
02541     eVup = exp( -betaVup * dT );
02542 
02543     eClkDrift = exp( -betaClkDrift * dT );
02544 
02545     T[0][0] = 1.0;
02546     T[0][3] = (1.0 - eVn) / betaVn;
02547 
02548     T[1][1] = 1.0;
02549     T[1][4] = (1.0 - eVe) / betaVe;
02550 
02551     T[2][2] = 1.0;
02552     T[2][5] = (1.0 - eVup) / betaVup;
02553     
02554     T[3][3] = eVn;
02555     T[4][4] = eVe;
02556     T[5][5] = eVup;
02557 
02558     T[6][6] = 1.0;
02559     T[6][7] = (1.0 - eClkDrift) / betaClkDrift;
02560 
02561     T[7][7] = eClkDrift;
02562 
02563     return true;
02564   }
02565 
02566   bool GNSS_Estimator::ComputeTransitionMatrix_6StatePVGM_Float(
02567     const double dT, //!< The change in time since the last update [s].
02568     Matrix &T        //!< The transition matrix [(8 + nrAmb) x (8 + nrAmb)]. 
02569     )
02570   {
02571     const double betaVn       = 1.0/m_KF.alphaVn;       // The Gauss Markov beta for northing velocity [1/s].
02572     const double betaVe       = 1.0/m_KF.alphaVe;       // The Gauss Markov beta for easting velocity [1/s].
02573     const double betaVup      = 1.0/m_KF.alphaVup;      // The Gauss Markov beta for up velocity [1/s].
02574     const double betaClkDrift = 1.0/m_KF.alphaClkDrift; // The Gauss Markov beta for the clock drift [1/s].
02575 
02576     //double dN = 0;
02577     double eVn = 0;
02578     double eVe = 0;
02579     double eVup = 0;
02580     //double eClkDrift = 0;
02581     
02582     //Need to check this, when there are no dd ambiguities, T should by 6x6, when there are ambiguities, they should be added
02583     const unsigned int u = 6;
02584 
02585     T.Redim(u,u);
02586 
02587     eVn  = exp( -betaVn  * dT );
02588     eVe  = exp( -betaVe  * dT );
02589     eVup = exp( -betaVup * dT );
02590 
02591     //eClkDrift = exp( -betaClkDrift * dT );
02592 
02593     T[0][0] = 1.0;
02594     T[0][3] = (1.0 - eVn) / betaVn;
02595 
02596     T[1][1] = 1.0;
02597     T[1][4] = (1.0 - eVe) / betaVe;
02598 
02599     T[2][2] = 1.0;
02600     T[2][5] = (1.0 - eVup) / betaVup;
02601     
02602     T[3][3] = eVn;
02603     T[4][4] = eVe;
02604     T[5][5] = eVup;
02605 
02606     //T[6][6] = 1.0;
02607     //T[6][7] = (1.0 - eClkDrift) / betaClkDrift;
02608 
02609     //T[7][7] = eClkDrift;
02610 
02611     return true;
02612   }
02613 
02614 
02615 
02616   bool GNSS_Estimator::ComputeProcessNoiseMatrix_8StatePVGM(
02617     const double dT,  //!< The change in time since the last update [s].
02618     Matrix &Q         //!< The process noise matrix [8 x 8].
02619     )
02620   {
02621     const double betaVn       = 1.0/m_KF.alphaVn;       // The Gauss Markov beta for northing velocity [1/s].
02622     const double betaVe       = 1.0/m_KF.alphaVe;       // The Gauss Markov beta for easting velocity [1/s].
02623     const double betaVup      = 1.0/m_KF.alphaVup;      // The Gauss Markov beta for up velocity [1/s].
02624     const double betaClkDrift = 1.0/m_KF.alphaClkDrift; // The Gauss Markov beta for the clock drift [1/s].
02625 
02626     const double qVn       = 2 * m_KF.sigmaVn  * m_KF.sigmaVn  * betaVn;  // The process noise value for northing velocity.
02627     const double qVe       = 2 * m_KF.sigmaVe  * m_KF.sigmaVe  * betaVe;  // The process noise value for easting  velocity.
02628     const double qVup      = 2 * m_KF.sigmaVup * m_KF.sigmaVup * betaVup; // The process noise value for up       velocity.
02629     const double qClkDrift = 2 * m_KF.sigmaClkDrift * m_KF.sigmaClkDrift * betaClkDrift; // The process noise value for clock drift.
02630 
02631     double eVn = 0;
02632     double eVe = 0;
02633     double eVup = 0;
02634     double eClkDrift = 0;
02635     double eVn2 = 0;
02636     double eVe2 = 0;
02637     double eVup2 = 0;
02638     double eClkDrift2 = 0;
02639 
02640     const unsigned int u = 8;
02641 
02642     if( Q.nrows() != u )
02643     {
02644       if( !Q.Resize( u, u ) )
02645       {
02646         return false;
02647       }
02648     }
02649     
02650     
02651     eVn        = exp( -betaVn  * dT );
02652     eVe        = exp( -betaVe  * dT );
02653     eVup       = exp( -betaVup * dT );
02654     eClkDrift  = exp( -betaClkDrift * dT );
02655 
02656     eVn2       = exp( -2.0 * betaVn  * dT );
02657     eVe2       = exp( -2.0 * betaVe  * dT );
02658     eVup2      = exp( -2.0 * betaVup * dT );
02659     eClkDrift2 = exp( -2.0 * betaClkDrift * dT );
02660 
02661     Q[0][0]  = qVn / (betaVn*betaVn);
02662     Q[0][0] *= dT - 2.0*(1.0 - eVn)/(betaVn) + (1.0 - eVn2)/(2.0*betaVn);
02663 
02664     Q[1][1]  = qVe / (betaVe*betaVe);
02665     Q[1][1] *= dT - 2.0*(1.0 - eVe)/(betaVe) + (1.0 - eVe2)/(2.0*betaVe);
02666 
02667     Q[2][2]  = qVn / (betaVup*betaVup);
02668     Q[2][2] *= dT - 2.0*(1.0 - eVup)/(betaVup) + (1.0 - eVup2)/(2.0*betaVup);
02669 
02670     Q[3][3]  = qVn * (1.0 - eVn2) / (2.0*betaVn);
02671     
02672     Q[4][4]  = qVe * (1.0 - eVe2) / (2.0*betaVe);
02673 
02674     Q[5][5]  = qVup * (1.0 - eVup2) / (2.0*betaVup);
02675 
02676     Q[6][6]  = qClkDrift / (betaClkDrift*betaClkDrift);
02677     Q[6][6] *= dT - 2.0*(1.0 - eClkDrift)/(betaClkDrift) + (1.0 - eClkDrift2)/(2.0*betaClkDrift);
02678     
02679     Q[7][7]  = qClkDrift * (1.0 - eClkDrift2) / (2.0*betaClkDrift);
02680 
02681     Q[0][3]  = qVn / betaVn;
02682     Q[0][3] *= (1.0 - eVn)/betaVn - (1.0 - eVn2)/(2.0*betaVn);
02683     Q[3][0]  = Q[0][3];
02684 
02685     Q[1][4]  = qVe / betaVe;
02686     Q[1][4] *= (1.0 - eVe)/betaVe - (1.0 - eVe2)/(2.0*betaVe);
02687     Q[4][1]  = Q[1][4];
02688 
02689     Q[2][5]  = qVup / betaVup;
02690     Q[2][5] *= (1.0 - eVup)/betaVup - (1.0 - eVup2)/(2.0*betaVup);
02691     Q[5][2]  = Q[2][5];
02692 
02693     Q[6][7]  = qClkDrift / betaClkDrift;
02694     Q[6][7] *= (1.0 - eClkDrift)/betaClkDrift - (1.0 - eClkDrift2)/(2.0*betaClkDrift);
02695     Q[7][6]  = Q[6][7];
02696 
02697     return true;
02698   }
02699 
02700   
02701   bool GNSS_Estimator::ComputeProcessNoiseMatrix_8StatePVGM_Float(
02702     const double dT,  //!< The change in time since the last update [s].
02703     Matrix &Q         //!< The process noise matrix [(8 + nrAmb) x (8 + nrAmb)].
02704     )
02705   {
02706     const double betaVn       = 1.0/m_KF.alphaVn;       // The Gauss Markov beta for northing velocity [1/s].
02707     const double betaVe       = 1.0/m_KF.alphaVe;       // The Gauss Markov beta for easting velocity [1/s].
02708     const double betaVup      = 1.0/m_KF.alphaVup;      // The Gauss Markov beta for up velocity [1/s].
02709     const double betaClkDrift = 1.0/m_KF.alphaClkDrift; // The Gauss Markov beta for the clock drift [1/s].
02710 
02711     const double qVn       = 2 * m_KF.sigmaVn  * m_KF.sigmaVn  * betaVn;  // The process noise value for northing velocity.
02712     const double qVe       = 2 * m_KF.sigmaVe  * m_KF.sigmaVe  * betaVe;  // The process noise value for easting  velocity.
02713     const double qVup      = 2 * m_KF.sigmaVup * m_KF.sigmaVup * betaVup; // The process noise value for up       velocity.
02714     const double qClkDrift = 2 * m_KF.sigmaClkDrift * m_KF.sigmaClkDrift * betaClkDrift; // The process noise value for clock drift.
02715 
02716     double eVn = 0;
02717     double eVe = 0;
02718     double eVup = 0;
02719     double eClkDrift = 0;
02720     double eVn2 = 0;
02721     double eVe2 = 0;
02722     double eVup2 = 0;
02723     double eClkDrift2 = 0;
02724 
02725     const unsigned int u = 8 + static_cast<unsigned int>(m_ActiveAmbiguitiesList.size());
02726 
02727     if( Q.nrows() != u )
02728     {
02729       if( !Q.Resize( u, u ) )
02730       {
02731         return false;
02732       }
02733     }
02734     
02735     eVn        = exp( -betaVn  * dT );
02736     eVe        = exp( -betaVe  * dT );
02737     eVup       = exp( -betaVup * dT );
02738     eClkDrift  = exp( -betaClkDrift * dT );
02739 
02740     eVn2       = exp( -2.0 * betaVn  * dT );
02741     eVe2       = exp( -2.0 * betaVe  * dT );
02742     eVup2      = exp( -2.0 * betaVup * dT );
02743     eClkDrift2 = exp( -2.0 * betaClkDrift * dT );
02744 
02745     Q[0][0]  = qVn / (betaVn*betaVn);
02746     Q[0][0] *= dT - 2.0*(1.0 - eVn)/(betaVn) + (1.0 - eVn2)/(2.0*betaVn);
02747 
02748     Q[1][1]  = qVe / (betaVe*betaVe);
02749     Q[1][1] *= dT - 2.0*(1.0 - eVe)/(betaVe) + (1.0 - eVe2)/(2.0*betaVe);
02750 
02751     Q[2][2]  = qVn / (betaVup*betaVup);
02752     Q[2][2] *= dT - 2.0*(1.0 - eVup)/(betaVup) + (1.0 - eVup2)/(2.0*betaVup);
02753 
02754     Q[3][3]  = qVn * (1.0 - eVn2) / (2.0*betaVn);
02755     
02756     Q[4][4]  = qVe * (1.0 - eVe2) / (2.0*betaVe);
02757 
02758     Q[5][5]  = qVup * (1.0 - eVup2) / (2.0*betaVup);
02759 
02760     Q[6][6]  = qClkDrift / (betaClkDrift*betaClkDrift);
02761     Q[6][6] *= dT - 2.0*(1.0 - eClkDrift)/(betaClkDrift) + (1.0 - eClkDrift2)/(2.0*betaClkDrift);
02762     
02763     Q[7][7]  = qClkDrift * (1.0 - eClkDrift2) / (2.0*betaClkDrift);
02764 
02765     Q[0][3]  = qVn / betaVn;
02766     Q[0][3] *= (1.0 - eVn)/betaVn - (1.0 - eVn2)/(2.0*betaVn);
02767     Q[3][0]  = Q[0][3];
02768 
02769     Q[1][4]  = qVe / betaVe;
02770     Q[1][4] *= (1.0 - eVe)/betaVe - (1.0 - eVe2)/(2.0*betaVe);
02771     Q[4][1]  = Q[1][4];
02772 
02773     Q[2][5]  = qVup / betaVup;
02774     Q[2][5] *= (1.0 - eVup)/betaVup - (1.0 - eVup2)/(2.0*betaVup);
02775     Q[5][2]  = Q[2][5];
02776 
02777     Q[6][7]  = qClkDrift / betaClkDrift;
02778     Q[6][7] *= (1.0 - eClkDrift)/betaClkDrift - (1.0 - eClkDrift2)/(2.0*betaClkDrift);
02779     Q[7][6]  = Q[6][7];
02780 
02781     return true;
02782   }
02783 
02784   bool GNSS_Estimator::ComputeProcessNoiseMatrix_6StatePVGM_Float(
02785     const double dT,  //!< The change in time since the last update [s].
02786     Matrix &Q         //!< The process noise matrix [(8 + nrAmb) x (8 + nrAmb)].
02787     )
02788   {
02789     const double betaVn       = 1.0/m_KF.alphaVn;       // The Gauss Markov beta for northing velocity [1/s].
02790     const double betaVe       = 1.0/m_KF.alphaVe;       // The Gauss Markov beta for easting velocity [1/s].
02791     const double betaVup      = 1.0/m_KF.alphaVup;      // The Gauss Markov beta for up velocity [1/s].
02792     const double betaClkDrift = 1.0/m_KF.alphaClkDrift; // The Gauss Markov beta for the clock drift [1/s].
02793 
02794     const double qVn       = 2 * m_KF.sigmaVn  * m_KF.sigmaVn  * betaVn;  // The process noise value for northing velocity.
02795     const double qVe       = 2 * m_KF.sigmaVe  * m_KF.sigmaVe  * betaVe;  // The process noise value for easting  velocity.
02796     const double qVup      = 2 * m_KF.sigmaVup * m_KF.sigmaVup * betaVup; // The process noise value for up       velocity.
02797     const double qClkDrift = 2 * m_KF.sigmaClkDrift * m_KF.sigmaClkDrift * betaClkDrift; // The process noise value for clock drift.
02798 
02799     //const double dT2 = dT*dT;
02800     double eVn = 0;
02801     double eVe = 0;
02802     double eVup = 0;
02803     //double eClkDrift = 0;
02804     double eVn2 = 0;
02805     double eVe2 = 0;
02806     double eVup2 = 0;
02807     //double eClkDrift2 = 0;
02808 
02809   //Same problem with dimensions. m_ActiveAmbiguitiesList.size has the be the DD size now.
02810     const unsigned int u = 6;
02811 
02812     if( Q.nrows() != u )
02813     {
02814       if( !Q.Resize( u, u ) )
02815       {
02816         return false;
02817       }
02818     }
02819     
02820     eVn        = exp( -betaVn  * dT );
02821     eVe        = exp( -betaVe  * dT );
02822     eVup       = exp( -betaVup * dT );
02823     //eClkDrift  = exp( -betaClkDrift * dT );
02824 
02825     eVn2       = exp( -2.0 * betaVn  * dT );
02826     eVe2       = exp( -2.0 * betaVe  * dT );
02827     eVup2      = exp( -2.0 * betaVup * dT );
02828     //eClkDrift2 = exp( -2.0 * betaClkDrift * dT );
02829 
02830     Q[0][0]  = qVn / (betaVn*betaVn);
02831     Q[0][0] *= dT - 2.0*(1.0 - eVn)/(betaVn) + (1.0 - eVn2)/(2.0*betaVn);
02832 
02833     Q[1][1]  = qVe / (betaVe*betaVe);
02834     Q[1][1] *= dT - 2.0*(1.0 - eVe)/(betaVe) + (1.0 - eVe2)/(2.0*betaVe);
02835 
02836     Q[2][2]  = qVn / (betaVup*betaVup);
02837     Q[2][2] *= dT - 2.0*(1.0 - eVup)/(betaVup) + (1.0 - eVup2)/(2.0*betaVup);
02838 
02839     Q[3][3]  = qVn * (1.0 - eVn2) / (2.0*betaVn);
02840     
02841     Q[4][4]  = qVe * (1.0 - eVe2) / (2.0*betaVe);
02842 
02843     Q[5][5]  = qVup * (1.0 - eVup2) / (2.0*betaVup);
02844 
02845     // GDM_HACK added the 0.009
02846     //Q[6][6]  = 0.3*dT + qClkDrift / (betaClkDrift*betaClkDrift);
02847     //Q[6][6]  = qClkDrift / (betaClkDrift*betaClkDrift);
02848     //Q[6][6] *= dT - 2.0*(1.0 - eClkDrift)/(betaClkDrift) + (1.0 - eClkDrift2)/(2.0*betaClkDrift);
02849     
02850     //Q[7][7]  = qClkDrift * (1.0 - eClkDrift2) / (2.0*betaClkDrift);
02851 
02852     Q[0][3]  = qVn / betaVn;
02853     Q[0][3] *= (1.0 - eVn)/betaVn - (1.0 - eVn2)/(2.0*betaVn);
02854     Q[3][0]  = Q[0][3];
02855 
02856     Q[1][4]  = qVe / betaVe;
02857     Q[1][4] *= (1.0 - eVe)/betaVe - (1.0 - eVe2)/(2.0*betaVe);
02858     Q[4][1]  = Q[1][4];
02859 
02860     Q[2][5]  = qVup / betaVup;
02861     Q[2][5] *= (1.0 - eVup)/betaVup - (1.0 - eVup2)/(2.0*betaVup);
02862     Q[5][2]  = Q[2][5];
02863 
02864     //Q[6][7]  = qClkDrift / betaClkDrift;
02865     //Q[6][7] *= (1.0 - eClkDrift)/betaClkDrift - (1.0 - eClkDrift2)/(2.0*betaClkDrift);
02866     //Q[7][6]  = Q[6][7];
02867 
02868     return true;
02869   }
02870 
02871 
02872 
02873   bool GNSS_Estimator::PredictAhead_8StatePVGM(
02874     GNSS_RxData &rxData, //!< The receiver data.
02875     const double dT,     //!< The change in time since the last update [s].
02876     Matrix &T,           //!< The transition matrix                                 [8 x 8] (output).
02877     Matrix &Q,           //!< The process noise matrix                              [8 x 8] (output).
02878     Matrix &P            //!< The state variance covariance matrix                  [8 x 8] (input/output).      
02879     )
02880   {
02881     double M = 0; // The meridian radius of curvature.
02882     double N = 0; // The prime vertical radius of curvature.
02883     bool result = false;
02884     Matrix tmpMat;
02885     double lat = 0;
02886     double h = 0;
02887 
02888     GEODESY_ComputeMeridianRadiusOfCurvature(
02889       GEODESY_REFERENCE_ELLIPSE_WGS84,
02890       rxData.m_pvt.latitude,
02891       &M );
02892 
02893     GEODESY_ComputePrimeVerticalRadiusOfCurvature(
02894       GEODESY_REFERENCE_ELLIPSE_WGS84,
02895       rxData.m_pvt.latitude,
02896       &N );
02897 
02898     // Get the transition Matrix
02899     result = ComputeTransitionMatrix_8StatePVGM( dT, T );
02900     if( result == false )
02901       return false;
02902 
02903     // Set the process noise Matrix
02904     result = ComputeProcessNoiseMatrix_8StatePVGM( dT, Q );      
02905     if( result == false )
02906       return false;
02907 
02908     
02909     ////
02910     // predict the states ahead    
02911     
02912     // for use of use
02913     lat = rxData.m_pvt.latitude;
02914     h   = rxData.m_pvt.height;
02915     
02916     rxData.m_pvt.latitude  += T[0][3] * rxData.m_pvt.vn / (M+h);  // for small dT, this should be: lat += dT * vn / M
02917     rxData.m_pvt.longitude += T[1][4] * rxData.m_pvt.ve / ((N+h)*cos(lat));  // for small dT, this should be: lon += dT * ve / ((N+h)*cos(lat))
02918     rxData.m_pvt.height    += T[2][5] * rxData.m_pvt.vup;  // for small dT, this should be: hgt += dT * vup    
02919     
02920     rxData.m_pvt.vn  *= T[3][3];  // for small dT, this should be vn = vn    
02921     rxData.m_pvt.ve  *= T[4][4];  // for small dT, this should be ve = ve
02922     rxData.m_pvt.vup *= T[5][5];  // for small dT, this should be vup = vup
02923 
02924     rxData.m_pvt.clockOffset += T[6][7] * rxData.m_pvt.clockDrift;  // for small dT, this should be: clk += dT * clkrate
02925     rxData.m_pvt.clockDrift  *= T[7][7];  // for small dT, this should be clkdrift = clkdrift
02926 
02927     //
02928     ////
02929 
02930 
02931     ////
02932     // predict the new state variance/covariance
02933 
02934     // It can be done this way:
02935     // P = T * P * T.transpose() + Q;
02936     // but the following is more efficient
02937     tmpMat = T;
02938     if( !tmpMat.Inplace_Transpose() )
02939       return false;
02940 
02941     if( !P.Inplace_PreMultiply( T ) )
02942       return false;
02943 
02944     if( !P.Inplace_PostMultiply( tmpMat ) )
02945       return false;
02946 
02947     if( !P.Inplace_Add( Q ) )
02948       return false;
02949     //
02950     ////
02951 
02952     return true;    
02953   }
02954 
02955 
02956   bool GNSS_Estimator::PredictAhead_8StatePVGM_Float(
02957     GNSS_RxData &rxData, //!< The receiver data.
02958     const double dT,     //!< The change in time since the last update [s].
02959     Matrix &T,           //!< The transition matrix                                 [(8 + nrAmb) x (8 + nrAmb)] (output).
02960     Matrix &Q,           //!< The process noise matrix                              [(8 + nrAmb) x (8 + nrAmb)] (output).
02961     Matrix &P            //!< The state variance covariance matrix                  [(8 + nrAmb) x (8 + nrAmb)] (input/output).      
02962     )
02963   {
02964     double M = 0; // The meridian radius of curvature.
02965     double N = 0; // The prime vertical radius of curvature.
02966     bool result = false;
02967     Matrix tmpMat;
02968     double lat = 0;
02969     double h = 0;
02970 
02971     GEODESY_ComputeMeridianRadiusOfCurvature(
02972       GEODESY_REFERENCE_ELLIPSE_WGS84,
02973       rxData.m_pvt.latitude,
02974       &M );
02975 
02976     GEODESY_ComputePrimeVerticalRadiusOfCurvature(
02977       GEODESY_REFERENCE_ELLIPSE_WGS84,
02978       rxData.m_pvt.latitude,
02979       &N );
02980 
02981     // Get the transition Matrix
02982     result = ComputeTransitionMatrix_8StatePVGM_Float( dT, T );
02983     if( result == false )
02984       return false;
02985 
02986     PrintMatToDebug( "T", T );
02987 
02988     // Set the process noise Matrix
02989     result = ComputeProcessNoiseMatrix_8StatePVGM_Float( dT, Q );
02990     if( result == false )
02991       return false;
02992 
02993     PrintMatToDebug( "Q", Q );
02994     
02995     ////
02996     // predict the states ahead    
02997     
02998     // for use of use
02999     lat = rxData.m_pvt.latitude;
03000     h   = rxData.m_pvt.height;
03001     
03002     rxData.m_pvt.latitude  += T[0][3] * rxData.m_pvt.vn / (M+h);  // for small dT, this should be: lat += dT * vn / M
03003     rxData.m_pvt.longitude += T[1][4] * rxData.m_pvt.ve / ((N+h)*cos(lat));  // for small dT, this should be: lon += dT * ve / ((N+h)*cos(lat))
03004     rxData.m_pvt.height    += T[2][5] * rxData.m_pvt.vup;  // for small dT, this should be: hgt += dT * vup    
03005     
03006     rxData.m_pvt.vn  *= T[3][3];  // for small dT, this should be vn = vn    
03007     rxData.m_pvt.ve  *= T[4][4];  // for small dT, this should be ve = ve
03008     rxData.m_pvt.vup *= T[5][5];  // for small dT, this should be vup = vup
03009 
03010     rxData.m_pvt.clockOffset += T[6][7] * rxData.m_pvt.clockDrift;  // for small dT, this should be: clk += dT * clkrate
03011     rxData.m_pvt.clockDrift  *= T[7][7];  // for small dT, this should be clkdrift = clkdrift
03012 
03013    
03014 
03015     //
03016     ////
03017 
03018 
03019     ////
03020     // predict the new state variance/covariance
03021 
03022     // It can be done this way:
03023     // P = T * P * T.transpose() + Q;
03024     // but the following is more efficient
03025     tmpMat = T;
03026     if( !tmpMat.Inplace_Transpose() )
03027       return false;
03028 
03029     if( !P.Inplace_PreMultiply( T ) )
03030       return false;
03031 
03032     if( !P.Inplace_PostMultiply( tmpMat ) )
03033       return false;
03034 
03035     if( !P.Inplace_Add( Q ) )
03036       return false;
03037     //
03038     ////
03039 
03040     result = rxData.UpdatePositionAndRxClock(
03041       rxData.m_pvt.latitude,
03042       rxData.m_pvt.longitude,
03043       rxData.m_pvt.height,
03044       rxData.m_pvt.clockOffset,
03045       sqrt( P[0][0] ),
03046       sqrt( P[1][1] ),
03047       sqrt( P[2][2] ),
03048       sqrt( P[6][6] )
03049       );
03050     if( !result )
03051       return false;   
03052 
03053     result = rxData.UpdateVelocityAndClockDrift(
03054       rxData.m_pvt.vn,
03055       rxData.m_pvt.ve,
03056       rxData.m_pvt.vup,
03057       rxData.m_pvt.clockDrift,
03058       sqrt( P[3][3] ),
03059       sqrt( P[4][4] ),
03060       sqrt( P[5][5] ),
03061       sqrt( P[7][7] )
03062       );
03063     if( !result )
03064       return false;   
03065 
03066     PrintMatToDebug( "P", P );
03067 
03068     return true;    
03069   }
03070 
03071   bool GNSS_Estimator::PredictAhead_6StatePVGM_Float(
03072     GNSS_RxData &rxData, //!< The receiver data.
03073     const double dT,     //!< The change in time since the last update [s].
03074     Matrix &T,           //!< The transition matrix                                 [(8 + nrAmb) x (8 + nrAmb)] (output).
03075     Matrix &Q,           //!< The process noise matrix                              [(8 + nrAmb) x (8 + nrAmb)] (output).
03076     Matrix &P            //!< The state variance covariance matrix                  [(8 + nrAmb) x (8 + nrAmb)] (input/output).      
03077     )
03078   {
03079     unsigned i = 0;
03080     unsigned j = 0;
03081     double M = 0; // The meridian radius of curvature.
03082     double N = 0; // The prime vertical radius of curvature.
03083     bool result = false;
03084     Matrix tmpMat;
03085     double lat = 0;
03086     double h = 0;
03087 
03088     GEODESY_ComputeMeridianRadiusOfCurvature(
03089       GEODESY_REFERENCE_ELLIPSE_WGS84,
03090       rxData.m_pvt.latitude,
03091       &M );
03092 
03093     GEODESY_ComputePrimeVerticalRadiusOfCurvature(
03094       GEODESY_REFERENCE_ELLIPSE_WGS84,
03095       rxData.m_pvt.latitude,
03096       &N );
03097 
03098     // Get the transition Matrix
03099     result = ComputeTransitionMatrix_6StatePVGM_Float( dT, T );
03100     if( result == false )
03101       return false;
03102 
03103     PrintMatToDebug( "T", T );
03104 
03105     // Set the process noise Matrix
03106     result = ComputeProcessNoiseMatrix_6StatePVGM_Float( dT, Q );
03107     if( result == false )
03108       return false;
03109 
03110     PrintMatToDebug( "Q", Q );
03111     
03112     ////
03113     // predict the states ahead    
03114     
03115     // for use of use
03116     lat = rxData.m_pvt.latitude;
03117     h   = rxData.m_pvt.height;
03118     
03119     rxData.m_pvt.latitude  += T[0][3] * rxData.m_pvt.vn / (M+h);  // for small dT, this should be: lat += dT * vn / M
03120     rxData.m_pvt.longitude += T[1][4] * rxData.m_pvt.ve / ((N+h)*cos(lat));  // for small dT, this should be: lon += dT * ve / ((N+h)*cos(lat))
03121     rxData.m_pvt.height    += T[2][5] * rxData.m_pvt.vup;  // for small dT, this should be: hgt += dT * vup    
03122     
03123     rxData.m_pvt.vn  *= T[3][3];  // for small dT, this should be vn = vn    
03124     rxData.m_pvt.ve  *= T[4][4];  // for small dT, this should be ve = ve
03125     rxData.m_pvt.vup *= T[5][5];  // for small dT, this should be vup = vup
03126 
03127     //
03128     ////
03129 
03130 
03131     ////
03132     // predict the new state variance/covariance
03133 
03134     // It can be done this way:
03135     // P = T * P * T.transpose() + Q;
03136     // but the following is more efficient
03137 
03138     if( !T.Redim( P.nrows(), P.ncols() ) )
03139       return false;
03140 
03141     for( i = 6; i < T.nrows(); i++ )
03142     {
03143       for( j = 6; j < T.ncols(); j++ )
03144       {
03145         T[i][j] = 1.0;
03146       }
03147     }
03148 
03149     tmpMat = T;
03150     if( !tmpMat.Inplace_Transpose() )
03151       return false;
03152 
03153     if( !P.Inplace_PreMultiply( T ) )
03154       return false;
03155 
03156     if( !P.Inplace_PostMultiply( tmpMat ) )
03157       return false;
03158 
03159     if( !Q.Redim( P.nrows(), P.ncols() ) )
03160       return false;
03161 
03162     if( !P.Inplace_Add( Q ) )
03163       return false;
03164     //
03165     ////
03166 
03167     PrintMatToDebug( "P", P );
03168 
03169     return true;    
03170   }
03171 
03172 
03173 
03174 
03175 
03176 
03177   bool GNSS_Estimator::InitializeStateVarianceCovariance_8StatePVGM(
03178     const double std_lat,        //!< The standard deviation uncertainty in the latitude [m].
03179     const double std_lon,        //!< The standard deviation uncertainty in the longitude [m]. 
03180     const double std_hgt,        //!< The standard deviation uncertainty in the height [m].
03181     const double std_vn,         //!< The standard deviation uncertainty in the northing velocity [m/s].
03182     const double std_ve,         //!< The standard deviation uncertainty in the easting velocity [m/s].
03183     const double std_vup,        //!< The standard deviation uncertainty in the up velocity [m/s].
03184     const double std_clk,        //!< The standard deviation uncertainty in the clock offset [m].
03185     const double std_clkdrift,   //!< The standard deviation uncertainty in the clock drift [m/s].    
03186     Matrix &P                    //!< The variance covariance of the states [8x8].
03187     )
03188   {
03189     if( P.GetNrRows() != 8 || P.GetNrCols() != 8 )
03190     {
03191       if( !P.Resize( 8, 8 ) )
03192       {
03193         return false;
03194       }
03195     }
03196 
03197     P[0][0] = std_lat*std_lat;
03198     P[1][1] = std_lon*std_lon;
03199     P[2][2] = std_hgt*std_hgt;
03200     P[3][3] = std_vn*std_vn;
03201     P[4][4] = std_ve*std_ve;
03202     P[5][5] = std_vup*std_vup;
03203     P[6][6] = std_clk*std_clk;
03204     P[7][7] = std_clkdrift*std_clkdrift;
03205 
03206     PrintMatToDebug( "P", P );
03207 
03208     return true;
03209   }
03210 
03211   bool GNSS_Estimator::InitializeStateVarianceCovariance_6StatePVGM(
03212     const double std_lat,        //!< The standard deviation uncertainty in the latitude [m].
03213     const double std_lon,        //!< The standard deviation uncertainty in the longitude [m]. 
03214     const double std_hgt,        //!< The standard deviation uncertainty in the height [m].
03215     const double std_vn,         //!< The standard deviation uncertainty in the northing velocity [m/s].
03216     const double std_ve,         //!< The standard deviation uncertainty in the easting velocity [m/s].
03217     const double std_vup,        //!< The standard deviation uncertainty in the up velocity [m/s].  
03218     Matrix &P                    //!< The variance covariance of the states [8x8].
03219     )
03220   {
03221     if( P.GetNrRows() != 6 || P.GetNrCols() != 6 )
03222     {
03223       if( !P.Resize( 6, 6 ) )
03224       {
03225         return false;
03226       }
03227     }
03228 
03229     P[0][0] = std_lat*std_lat;
03230     P[1][1] = std_lon*std_lon;
03231     P[2][2] = std_hgt*std_hgt;
03232     P[3][3] = std_vn*std_vn;
03233     P[4][4] = std_ve*std_ve;
03234     P[5][5] = std_vup*std_vup;
03235    
03236     PrintMatToDebug( "P", P );
03237 
03238     return true;
03239   }
03240 
03241 
03242   bool GNSS_Estimator::Kalman_Update_8StatePVGM(
03243     GNSS_RxData *rxData,      //!< A pointer to the rover receiver data. This must be a valid pointer.
03244     GNSS_RxData *rxBaseData,  //!< A pointer to the reference receiver data if available. NULL if not available.
03245     Matrix &P                 //!< The variance-covariance of the states.
03246     )
03247   {
03248     bool result = false;
03249     unsigned i = 0;
03250     unsigned j = 0;
03251     unsigned n = 0;
03252     unsigned nrP = 0;           // The number of valid psr.
03253     unsigned nrP_base = 0;      // The number of valid psr for the reference station.
03254     unsigned nrD = 0;           // The number of valid Doppler.
03255     unsigned nrD_base = 0;      // The number of valid Doppler for the reference station.
03256     unsigned nrValidEph = 0;    // The number of valid ephemeris.
03257     unsigned nrDifferentialPsr = 0;     // The number of differential psr.
03258     unsigned nrDifferentialDoppler = 0; // The number of differential Doppler.
03259     bool isDifferential = false;
03260 
03261     double lat = 0;
03262     double lon = 0;
03263     double hgt = 0;
03264     double clk = 0;
03265     double vn = 0;
03266     double ve = 0;
03267     double vup = 0;
03268     double clkdrift = 0;
03269     double M = 0;   // The computed meridian radius of curvature [m].
03270     double N = 0;   // The computed prime vertical radius of curvature [m].
03271 
03272     Matrix H_p;
03273     Matrix H_v;
03274     Matrix H;
03275     Matrix Ht;
03276     Matrix R_p;
03277     Matrix R_v;
03278     Matrix R;
03279     Matrix w_p;
03280     Matrix w_v;
03281     Matrix w;
03282     Matrix K;
03283     Matrix tmpMat;
03284     Matrix tmpMatP;
03285     Matrix dx(8);
03286     Matrix I;
03287 
03288     
03289     dx.Zero();
03290     
03291     // Store the current input pvt as the previous pvt since we are updating.
03292     rxData->m_prev_pvt = rxData->m_pvt;
03293 
03294     lat = rxData->m_pvt.latitude;
03295     lon = rxData->m_pvt.longitude;
03296     hgt = rxData->m_pvt.height;
03297     clk = rxData->m_pvt.clockOffset;
03298     vn  = rxData->m_pvt.vn;
03299     ve  = rxData->m_pvt.ve;
03300     vup = rxData->m_pvt.vup;
03301     clkdrift = rxData->m_pvt.clockDrift; 
03302 
03303 
03304     if( rxBaseData != NULL )
03305       isDifferential = true;
03306 
03307 #ifdef CONSTRAINPOS
03308     rxData->m_pvt.isPositionConstrained = 1;
03309 #else
03310     rxData->m_pvt.isPositionConstrained = 0;
03311 #endif
03312     
03313     
03314     ////
03315     // Perform operations specific to the rover.
03316 
03317     // Update the receiver time information (UTC and day of year)
03318     result = UpdateTime( *rxData );
03319     if( !result )
03320       return false;    
03321     if( isDifferential )
03322     {
03323       result = UpdateTime( *rxBaseData );
03324       if( !result )
03325         return false;    
03326     }
03327 
03328     result = DetermineSatellitePVT_GPSL1( rxData, rxBaseData, nrValidEph );
03329     if( !result )
03330       return false;
03331 
03332 
03333     result = DetermineAtmosphericCorrections_GPSL1( *rxData );
03334     if( !result )
03335       return false;
03336     result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxData, nrP );
03337     if( !result )
03338       return false;    
03339     result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxData, nrD );
03340     if( !result )
03341       return false;    
03342     
03343 
03344     if( isDifferential )
03345     {
03346       result = DetermineAtmosphericCorrections_GPSL1( *rxBaseData );
03347       if( !result )
03348         return false;
03349       result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxBaseData, nrP_base );
03350       if( !result )
03351         return false;
03352       result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxBaseData, nrD_base );
03353       if( !result )
03354         return false;
03355 
03356       // When in differential mode, only differntial measurements will be used
03357       result = DetermineBetweenReceiverDifferentialIndex( 
03358         rxData,
03359         rxBaseData,
03360         true 
03361         );
03362       if( !result )
03363         return false;
03364 
03365        nrDifferentialPsr = 0;
03366         for( i = 0; i < rxData->m_nrValidObs; i++ )
03367         {
03368           if( rxData->m_ObsArray[i].system == GNSS_GPS &&
03369             rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
03370             rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
03371           {
03372             nrDifferentialPsr++;
03373           }
03374         }
03375 
03376 #ifdef CONSTRAINPOS
03377       nrP = nrDifferentialPsr+3;
03378 #else
03379       nrP = nrDifferentialPsr;
03380 #endif
03381 
03382       nrDifferentialDoppler = 0;
03383       for( i = 0; i < rxData->m_nrValidObs; i++ )
03384       {
03385         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
03386           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
03387           rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
03388         {
03389           nrDifferentialDoppler++;
03390         }
03391       }
03392 
03393 #ifdef CONSTRAINPOS
03394       nrD = nrDifferentialPsr+3;
03395 #else
03396       nrD = nrDifferentialPsr;
03397 #endif
03398     }
03399 
03400     result = DetermineDesignMatrixForThePositionSolution_GPSL1(
03401       *rxData,
03402       nrP,
03403       H_p );
03404     if( !result )
03405       return false;
03406     
03407     result = DetermineDesignMatrixForTheVelocitySolution_GPSL1(
03408       *rxData,
03409       nrD,
03410       H_v );
03411     if( !result )
03412       return false;
03413 
03414 
03415     result = DetermineMeasurementVarianceCovarianceMatrixForThePositionSolution_GPSL1(
03416       *rxData,
03417       nrP,
03418       R_p );
03419     if( !result )
03420       return false;
03421 
03422 
03423     result = DetermineMeasurementVarianceCovarianceMatrixForTheVelocitySolution_GPSL1(
03424       *rxData,
03425       nrD,
03426       R_v );
03427     if( !result )
03428       return false;
03429 
03430 
03431     result = DeterminePseudorangeMisclosures_GPSL1(
03432       rxData,
03433       rxBaseData,
03434       nrP,
03435       w_p );
03436     if( !result )
03437       return false;
03438 
03439     result = DetermineDopplerMisclosures_GPSL1(
03440       rxData,
03441       rxBaseData,
03442       nrD,
03443       w_v );
03444     if( !result )
03445       return false;
03446 
03447     // Form the combined design matrix.
03448     n = H_p.GetNrRows() + H_v.GetNrRows();
03449 
03450     result = H.Resize( n, 8 );
03451     if( !result )
03452       return false;
03453 
03454     for( i = 0; i < n; i++ )
03455     {
03456       if( i < nrP )
03457       {
03458         for( j = 0; j < 3; j++ )
03459           H[i][j] = H_p[i][j];
03460 #ifdef CONSTRAINPOS
03461         if( i < nrP-3 )
03462           H[i][6] = 1.0;
03463 #else
03464         H[i][6] = 1.0;
03465 #endif
03466       }
03467       else
03468       {
03469         for( j = 0; j < 3; j++ )
03470           H[i][j+3] = H_v[i-nrP][j];
03471 #ifdef CONSTRAINPOS
03472         if( i < n-3 )
03473           H[i][7] = 1.0;
03474 #else
03475         H[i][7] = 1.0;
03476 #endif
03477       }
03478     }
03479     PrintMatToDebug( "H", H );
03480     
03481     
03482     result = R.Resize( n, n );
03483     if( !result )
03484       return false;
03485 
03486     // Form the combined measurement variance-covariance matrix.
03487     for( i = 0; i < n; i++ )
03488     {
03489       if( i < nrP )
03490       {
03491         for( j = 0; j < nrP; j++ )
03492           R[i][j] = R_p[i][j];
03493       }
03494       else
03495       {
03496         for( j = 0; j < nrD; j++ )
03497           R[i][j+nrD] = R_v[i-nrP][j];
03498       }
03499     }
03500     PrintMatToDebug( "R", R );
03501 
03502 
03503     // Form the combined misclosure vector.
03504     result = w.Resize( n, 1 );
03505     if( !result )
03506       return false;
03507     for( i = 0; i < n; i++ )
03508     {
03509       if( i < nrP )
03510       {
03511         w[i] = w_p[i];
03512       }
03513       else
03514       {
03515         w[i] = w_v[i-nrP];
03516       }
03517     }
03518 
03519     
03520     // Form H transposed.
03521     Ht = H;
03522     result = Ht.Inplace_Transpose();
03523     if( !result )
03524       return false;
03525 
03526 
03527     PrintMatToDebug( "H", H );
03528     PrintMatToDebug( "R", R );
03529     PrintMatToDebug( "w", w );
03530     PrintMatToDebug( "P", P );
03531 
03532     // Compute the Kalman gain matrix.
03533     // K = P*Ht*(H*P*Ht+R)^-1
03534     // do (H*P*Ht+R)^-1 first
03535     tmpMat = H*P*Ht + R;
03536     result = tmpMat.Inplace_Invert();
03537     if( !result )
03538       return false;    
03539     K = P*Ht*tmpMat;
03540     
03541 
03542     // Compute the change in states due to the innovations (misclosures).
03543     dx = K*w;
03544 
03545     
03546 
03547     // Compute the updated state variance-covariance matrix, P.
03548     result = I.Resize( 8, 8 );
03549     if( !result )
03550       return false;
03551     result = I.Identity();
03552     if( !result )
03553       return false;
03554 
03555     P = (I - K * H)*P;
03556     
03557     PrintMatToDebug( "dx", dx );
03558     PrintMatToDebug( "P", P );
03559     PrintMatToDebug( "K", K );
03560 
03561     
03562     // Update the position and clock states
03563     // Update height first as it is need to reduce the corrections for lat and lon.
03564     hgt += dx[2];
03565     clk += dx[6];
03566 
03567     // The corrections for lat and lon, dx_p, must be converted to [rad] from [m].
03568     GEODESY_ComputePrimeVerticalRadiusOfCurvature(
03569       GEODESY_REFERENCE_ELLIPSE_WGS84, 
03570       lat,
03571       &N );
03572     GEODESY_ComputeMeridianRadiusOfCurvature(
03573       GEODESY_REFERENCE_ELLIPSE_WGS84, 
03574       lat,
03575       &M );
03576 
03577      lat += dx[0] / ( M + hgt );             // convert from meters to radians.
03578      lon += dx[1] / (( N + hgt )*cos(lat));  // convert from meters to radians.
03579 
03580      result = rxData->UpdatePositionAndRxClock(
03581        lat,
03582        lon,
03583        hgt,
03584        clk,
03585        sqrt(P[0][0]),
03586        sqrt(P[1][1]),
03587        sqrt(P[2][2]),
03588        sqrt(P[6][6])
03589        );
03590      if( !result )
03591        return false;
03592 
03593 
03594      // Update the velocity and clock drift states.
03595      vn        += dx[3];
03596      ve        += dx[4];
03597      vup       += dx[5];
03598      clkdrift  += dx[7];
03599 
03600      result = rxData->UpdateVelocityAndClockDrift(
03601        vn,
03602        ve,
03603        vup,
03604        clkdrift,
03605        sqrt(P[3][3]),
03606        sqrt(P[4][4]),
03607        sqrt(P[5][5]),
03608        sqrt(P[7][7]) );
03609      if( !result )
03610        return false;
03611 
03612      /*
03613      // GDM - recomputing the misclosures after adjustment!
03614     result = DeterminePseudorangeMisclosures_GPSL1(
03615       rxData,
03616       rxBaseData,
03617       nrP,
03618       w_p );
03619     if( !result )
03620       return false;
03621 
03622     result = DetermineDopplerMisclosures_GPSL1(
03623       rxData,
03624       rxBaseData,
03625       nrD,
03626       w_v );
03627     if( !result )
03628       return false;
03629       */
03630 
03631 
03632     return true;
03633   }
03634 
03635 
03636 
03637   bool GNSS_Estimator::Kalman_Update_6StatePVGM_FloatSolution(
03638     GNSS_RxData *rxData,      //!< A pointer to the rover receiver data. This must be a valid pointer.
03639     GNSS_RxData *rxBaseData,  //!< A pointer to the reference receiver data if available. NULL if not available.
03640     Matrix &P                 //!< The variance-covariance of the states.
03641   )
03642   {
03643     bool result = false;
03644     unsigned index = 0;
03645     unsigned i = 0;
03646     unsigned j = 0;
03647     unsigned k = 0; 
03648     unsigned m = 0; // counter
03649     unsigned n = 0;
03650     unsigned nrP = 0;           // The number of valid psr.
03651     unsigned nrP_base = 0;      // The number of valid psr for the reference station.
03652     unsigned nrD = 0;           // The number of valid Doppler.
03653     unsigned nrD_base = 0;      // The number of valid Doppler for the reference station.
03654     unsigned nrValidEph = 0;    // The number of valid ephemeris.
03655     unsigned nrUsableAdr = 0;      // The number of valid adr.
03656     unsigned nrUsableAdr_base = 0; // The number of valid adr for the reference station.
03657     unsigned nrDifferentialPsr = 0;     // The number of differential psr.
03658     unsigned nrDifferentialDoppler = 0; // The number of differential Doppler.
03659     unsigned nrDifferentialAdr = 0;     // The number of differntial adr.
03660   unsigned nDD = 0;
03661   unsigned nrPDD = 0;
03662   unsigned nrDDD = 0;
03663   unsigned nrDifferentialAdrDD = 0;
03664     bool isDifferential = false;
03665     unsigned u = 0;
03666     bool setToUseOnlyDifferential = true;
03667 
03668     double lat = 0;
03669     double lon = 0;
03670     double hgt = 0;
03671     double clk = 0;
03672     double vn = 0;
03673     double ve = 0;
03674     double vup = 0;
03675     double clkdrift = 0;
03676     double M = 0;   // The computed meridian radius of curvature [m].
03677     double N = 0;   // The computed prime vertical radius of curvature [m].
03678 
03679     Matrix H_p;
03680     Matrix H_v;
03681     Matrix H;
03682     Matrix r; // A vector corresponding to the diagonal elements of R.
03683     Matrix R_p;
03684     Matrix R_v;
03685     Matrix w_p;
03686     Matrix w_v;
03687     Matrix w_adr;
03688     Matrix w;
03689     Matrix K;
03690     Matrix tmpMat;
03691     Matrix tmpMatP;
03692     Matrix dx(8);
03693     Matrix I;
03694 
03695     dx.Zero();
03696     
03697     
03698     lat = rxData->m_pvt.latitude;
03699     lon = rxData->m_pvt.longitude;
03700     hgt = rxData->m_pvt.height;
03701     clk = rxData->m_pvt.clockOffset;
03702     vn  = rxData->m_pvt.vn;
03703     ve  = rxData->m_pvt.ve;
03704     vup = rxData->m_pvt.vup;
03705     clkdrift = rxData->m_pvt.clockDrift;
03706         
03707     if( rxBaseData != NULL )
03708       isDifferential = true;
03709 
03710 #ifdef CONSTRAINPOS
03711     rxData->m_pvt.isPositionConstrained = 1;
03712 #else
03713     rxData->m_pvt.isPositionConstrained = 0;
03714 #endif
03715     
03716     
03717     ////
03718     // Perform operations specific to the rover.
03719 
03720     // Update the receiver time information (UTC and day of year)
03721     result = UpdateTime( *rxData );
03722     if( !result )
03723       return false;
03724 
03725     if( isDifferential )
03726     {
03727       result = UpdateTime( *rxBaseData );
03728       if( !result )
03729       {
03730         return false;
03731       }
03732     }
03733 
03734     result = DetermineSatellitePVT_GPSL1( rxData, rxBaseData, nrValidEph );
03735     if( !result )
03736     {
03737       return false;
03738     }
03739 
03740 
03741     result = DetermineAtmosphericCorrections_GPSL1( *rxData );
03742     if( !result )
03743     {
03744       return false;
03745     }
03746     result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxData, nrP );
03747     if( !result )
03748     {
03749       return false;
03750     }
03751     result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxData, nrD );
03752     if( !result )
03753     {
03754       return false;
03755     }
03756     result = DetermineUsableAdrMeasurements_GPSL1( *rxData, nrUsableAdr );
03757     if( !result )
03758     {
03759       return false;
03760     }
03761     
03762     if( isDifferential )
03763     {
03764       result = DetermineAtmosphericCorrections_GPSL1( *rxBaseData );
03765       if( !result )
03766         return false;
03767       result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxBaseData, nrP_base );
03768       if( !result )
03769         return false;
03770       result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxBaseData, nrD_base );
03771       if( !result )
03772         return false;
03773       result = DetermineUsableAdrMeasurements_GPSL1( *rxBaseData, nrUsableAdr_base );
03774       if( !result )
03775       {
03776         return false;
03777       }
03778 
03779       // When in differential mode, only differntial measurements will be used
03780       result = DetermineBetweenReceiverDifferentialIndex(
03781         rxData,
03782         rxBaseData,
03783         true
03784         );
03785       if( !result )      
03786         return false;
03787 
03788       nrDifferentialPsr = 0;
03789       for( i = 0; i < rxData->m_nrValidObs; i++ )
03790       {
03791         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
03792           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
03793           rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
03794         {
03795           nrDifferentialPsr++;
03796         }
03797       }
03798       
03799 #ifdef CONSTRAINPOS
03800       nrP = nrDifferentialPsr+3;
03801 #else
03802       nrP = nrDifferentialPsr;
03803 #endif
03804 
03805       nrDifferentialDoppler = 0;
03806       for( i = 0; i < rxData->m_nrValidObs; i++ )
03807       {
03808         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
03809           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
03810           rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
03811         {
03812           nrDifferentialDoppler++;
03813         }
03814       }
03815 
03816 #ifdef CONSTRAINPOS
03817       nrD = nrDifferentialDoppler+3;
03818 #else
03819       nrD = nrDifferentialDoppler;
03820 #endif
03821 
03822       nrDifferentialAdr = 0;
03823       for( i = 0; i < rxData->m_nrValidObs; i++ )
03824       {
03825         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
03826           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
03827           rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
03828         {
03829           nrDifferentialAdr++;
03830         }
03831       }
03832 
03833     }
03834     else
03835     {
03836       return false;
03837     }
03838 
03839     result = DetermineDesignMatrixForThePositionSolution_GPSL1(
03840       *rxData,
03841       nrP,
03842       H_p );
03843     if( !result )
03844     {
03845       return false;
03846     }
03847     
03848     result = DetermineDesignMatrixForTheVelocitySolution_GPSL1(
03849       *rxData,
03850       nrD,
03851       H_v );
03852     if( !result )
03853     {
03854       return false;
03855     }
03856 
03857     result = DeterminePseudorangeMisclosures_GPSL1(
03858       rxData,
03859       rxBaseData,
03860       nrP,
03861       w_p );
03862     if( !result )
03863     {
03864       return false;
03865     }
03866 
03867     result = DetermineDopplerMisclosures_GPSL1(
03868       rxData,
03869       rxBaseData,
03870       nrD,
03871       w_v );
03872     if( !result )
03873     {
03874       return false;
03875     }
03876 
03877     bool hasAmbiguityChangeOccurred = false;
03878     result = DetermineAmbiguitiesChanges(
03879       rxData,
03880       rxBaseData,
03881       P,
03882       hasAmbiguityChangeOccurred );
03883     if( !result )
03884       return false;
03885 
03886     if( hasAmbiguityChangeOccurred )
03887       int gagagagag=101;
03888 
03889     
03890     //KO Debug: We need to replace this with a DD misclosure forming function that uses the current
03891     //DD misclosure estimate and the B matrix to determine the new DD misclosure.
03892     result = DetermineSingleDifferenceADR_Misclosures_GPSL1(
03893       rxData,
03894       rxBaseData,
03895       nrDifferentialAdr,
03896       w_adr );
03897     if( !result )
03898     {
03899       return false;
03900     }
03901 
03902     
03903     // Form the combined design matrix.
03904     n = nrP + nrD + nrDifferentialAdr;
03905 
03906     if( hasAmbiguityChangeOccurred )
03907       int gg=99; // place breakpoint here to debug issues related to changes in ambiguities.
03908 
03909     result = H.Resize( n, 8 + nrDifferentialAdr );
03910     if( !result )
03911     {
03912       return false;
03913     }
03914 
03915     result = r.Resize( n );
03916     if( !result )
03917     {
03918       return false;
03919     }
03920 
03921     unsigned int iP = 0; // A counter for the pseudorange.
03922     unsigned int iD = 0; // A counter for the Doppler.
03923     unsigned int iA = 0; // A counter for the ADR.
03924     double stdev; // a temporary double.
03925     for( k = 0; k < rxData->m_nrValidObs; k++ )
03926     {
03927       if( rxData->m_ObsArray[k].flags.isActive )
03928       {
03929         if( rxData->m_ObsArray[k].flags.isPsrUsedInSolution )
03930         {
03931           H[iP][0] = rxData->m_ObsArray[k].H_p[0];
03932           H[iP][1] = rxData->m_ObsArray[k].H_p[1];
03933           H[iP][2] = rxData->m_ObsArray[k].H_p[2];
03934           H[iP][6] = 1.0;
03935 
03936           stdev = rxData->m_ObsArray[k].stdev_psr;  // KO not differential obs error (need to change)
03937           r[iP] = stdev*stdev;
03938           iP++;
03939         }
03940         if( rxData->m_ObsArray[k].flags.isDopplerUsedInSolution )
03941         {
03942           H[iD+nrP][3] = rxData->m_ObsArray[k].H_v[0];
03943           H[iD+nrP][4] = rxData->m_ObsArray[k].H_v[1];
03944           H[iD+nrP][5] = rxData->m_ObsArray[k].H_v[2];
03945           H[iD+nrP][7] = 1.0;
03946           stdev = rxData->m_ObsArray[k].stdev_doppler * GPS_WAVELENGTHL1; // Change from cycles/s to meters/s.
03947           r[iD+nrP] = stdev*stdev;          
03948           iD++;
03949         }
03950         if( rxData->m_ObsArray[k].flags.isAdrUsedInSolution )
03951         {          
03952           H[iA+nrP+nrD][0] = rxData->m_ObsArray[k].H_p[0];
03953           H[iA+nrP+nrD][1] = rxData->m_ObsArray[k].H_p[1];
03954           H[iA+nrP+nrD][2] = rxData->m_ObsArray[k].H_p[2];
03955           H[iA+nrP+nrD][6] = 1.0;
03956 
03957       //
03958           //H[iA+nrP+nrD][rxData->m_ObsArray[k].index_ambiguity_state] = 1.0;
03959 
03960           stdev = rxData->m_ObsArray[k].stdev_adr * GPS_WAVELENGTHL1; // Change from cycles to meters.
03961           r[iA+nrP+nrD] = stdev*stdev;          
03962           iA++;
03963         }
03964       }
03965     }
03966 
03967     Matrix timeMat(1);
03968     timeMat[0] = rxData->m_pvt.time.gps_tow;
03969     PrintMatToDebug( "gpstime", timeMat );
03970     PrintMatToDebug( "H", H );
03971 
03972     
03973     //KO Debug: Can still use the code to form the combined code and Doppler misclosure, but then the phase
03974     //misclosure needs to be added after the code and Doppler w is differenced using B.
03975 
03976     // Form the combined misclosure vector.
03977     result = w.Resize( n, 1 );
03978     if( !result )
03979     {
03980       return false;
03981     }
03982     for( i = 0; i < n; i++ )
03983     {
03984       if( i < nrP )
03985       {
03986         w[i] = w_p[i];
03987       }
03988       else if ( i < nrP+nrD )
03989       {
03990         w[i] = w_v[i-nrP];
03991       }
03992       else
03993       {
03994         w[i] = w_adr[i-nrP-nrD];
03995       }
03996     }
03997 
03998     PrintMatToDebug( "w", w );
03999     
04000     
04001   //KO Dec 18. Now that the design matrix, covariance matrix and misclosure vector are formed for the SD case time to DD them
04002 
04003   if(nrP == 0) 
04004     nrPDD = 0;
04005   else
04006     nrPDD = nrP - 1;
04007   if(nrD == 0)
04008     nrDDD = 0;
04009   else
04010     nrDDD = nrD - 1;
04011   if(nrDifferentialAdr == 0)
04012     nrDifferentialAdrDD = 0;
04013   else
04014     nrDifferentialAdrDD = nrDifferentialAdr - 1;
04015 
04016   nDD = nrPDD + nrDDD + nrDifferentialAdrDD;
04017 
04018   
04019   //At this point, the B matrix exists. Now we have to apply it to H, Cl and w
04020   
04021   // This line needs to be removed, once we have a DD phase misclosure forming function that works
04022   // Could still use something like this to form the code and doppler misclosure sub vector
04023   w = m_RTKDD.B*w;
04024   
04025 
04026   H = m_RTKDD.B*H;
04027 
04028   //Need to remove the dt column of H, and also the dtdot columns.
04029 
04030   Matrix R(r.nrows(),r.nrows());
04031   for (i = 0; i < r.nrows(); i++)
04032     R[i][i] = r[i];
04033   R = m_RTKDD.B * R * m_RTKDD.B.Transpose();
04034 
04035   //At this point have DD format H, w and R matrices, as well as Transition and Process noise
04036   //However now we have to replace the sequential estimator with a batch one because the observations are correlated
04037 
04038   //Need to remove columns 6 and 7 from H and also one ambiguity column,
04039   //and also replace the ambiguity column for the ADR rows with the identity matrix
04040 
04041   H.RemoveColumn(6);
04042   H.RemoveColumn(6);
04043   if( nrDifferentialAdrDD > 0 )
04044   {
04045     H.RemoveColumn(6);
04046     for (i = 0; i < nrDifferentialAdrDD; i++)
04047       H[i + nrPDD + nrDDD][6 + i] = 1.0;
04048   }
04049 
04050 
04051    // Compute the Kalman gain matrix.
04052     // K = P*Ht*(H*P*Ht+R)^-1
04053     // do (H*P*Ht+R)^-1 first
04054   tmpMat = H*m_RTKDD.P*H.Transpose() + R;
04055     result = tmpMat.Inplace_Invert();
04056     if( !result )
04057       return false;    
04058   K = m_RTKDD.P*H.Transpose()*tmpMat;
04059     
04060 
04061     // Compute the change in states due to the innovations (misclosures).
04062     dx = K*w;
04063 
04064     
04065 
04066     // Compute the updated state variance-covariance matrix, P.
04067   result = I.Resize( K.nrows(), K.nrows() );
04068     if( !result )
04069       return false;
04070     result = I.Identity();
04071     if( !result )
04072       return false;
04073 
04074     m_RTKDD.P = (I - K * H)*m_RTKDD.P;
04075     
04076     PrintMatToDebug( "dx", dx );
04077     PrintMatToDebug( "P", m_RTKDD.P );
04078     PrintMatToDebug( "K", K );
04079 
04080     
04081     // Update the position and clock states
04082     // Update height first as it is need to reduce the corrections for lat and lon.
04083     hgt += dx[2];
04084     //clk += dx[6];
04085 
04086   // The corrections for lat and lon, dx_p, must be converted to [rad] from [m].
04087     GEODESY_ComputePrimeVerticalRadiusOfCurvature(
04088       GEODESY_REFERENCE_ELLIPSE_WGS84, 
04089       lat,
04090       &N );
04091     GEODESY_ComputeMeridianRadiusOfCurvature(
04092       GEODESY_REFERENCE_ELLIPSE_WGS84, 
04093       lat,
04094       &M );
04095 
04096      lat += dx[0] / ( M + hgt );             // convert from meters to radians.
04097      lon += dx[1] / (( N + hgt )*cos(lat));  // convert from meters to radians.
04098 
04099      result = rxData->UpdatePositionAndRxClock(
04100        lat,
04101        lon,
04102        hgt,
04103        0.0,
04104        sqrt(m_RTKDD.P[0][0]),
04105        sqrt(m_RTKDD.P[1][1]),
04106        sqrt(m_RTKDD.P[2][2]),
04107        0.0
04108        );
04109      if( !result )
04110        return false;
04111 
04112 
04113      // Update the velocity and clock drift states.
04114      vn        += dx[3];
04115      ve        += dx[4];
04116      vup       += dx[5];
04117      //clkdrift  += dx[7];
04118 
04119      result = rxData->UpdateVelocityAndClockDrift(
04120        vn,
04121        ve,
04122        vup,
04123        0.0,
04124        sqrt(m_RTKDD.P[3][3]),
04125        sqrt(m_RTKDD.P[4][4]),
04126        sqrt(m_RTKDD.P[5][5]),
04127        0.0 );
04128      if( !result )
04129        return false;
04130 
04131    //KO: Update the ambiguities: Here is where it gets tricky, 
04132    //How/where were the original values set and how are they indexed?
04133 
04134     
04135     Matrix amb;
04136     if( nrDifferentialAdrDD > 0 )
04137       amb.Resize(nrDifferentialAdrDD);
04138        
04139       j = 0;
04140       for( i = 0; i < rxData->m_nrValidObs; i++ )
04141       {
04142         if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution && rxData->m_ObsArray[i].index_between_satellite_differential != -1 )
04143         {
04144           rxData->m_ObsArray[i].ambiguity_dd += dx[rxData->m_ObsArray[i].index_ambiguity_state_dd];
04145           amb[j] = rxData->m_ObsArray[i].ambiguity_dd;
04146           j++;
04147         }
04148       }
04149     
04150       PrintMatToDebug( "amb", amb );
04151 
04152     //for( i = 0; i < rxData->m_nrValidObs; i++ )
04153     //{
04154     //  if( rxData->m_ObsArray[i].flags.isUsedInPosSolution )
04155     //    rxData->m_pvt.nrPsrObsUsed++;
04156     //  if( rxData->m_ObsArray[i].flags.isUsedInVelSolution )
04157     //    rxData->m_pvt.nrDopplerObsUsed++;
04158     //  if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
04159     //    rxData->m_pvt.nrAdrObsUsed++;
04160     //}
04161 
04162     
04163 #ifdef DEBUG_THE_ESTIMATOR
04164     char supermsg[8192];
04165     unsigned nrBytesInBuffer = 0;
04166     rxData->Debug_WriteSuperMsg80CharsWide( 
04167       supermsg,
04168       8192,
04169       51.0916666667*DEG2RAD,
04170       -114.0000000000*DEG2RAD,
04171       1000.000,
04172       nrBytesInBuffer );
04173     printf( supermsg );
04174 #endif
04175    
04176     return true;
04177   }
04178 
04179   bool GNSS_Estimator::FixAmbiguities()
04180   {
04181     return true;
04182   }
04183 
04184   
04185   
04186   bool GNSS_Estimator::Kalman_Update_8StatePVGM_SequentialMode(
04187     GNSS_RxData *rxData,      //!< A pointer to the rover receiver data. This must be a valid pointer.
04188     GNSS_RxData *rxBaseData,  //!< A pointer to the reference receiver data if available. NULL if not available.
04189     Matrix &P                 //!< The variance-covariance of the states.
04190   )
04191   {
04192     bool result = false;
04193     unsigned index = 0;
04194     unsigned i = 0;
04195     unsigned j = 0;
04196     unsigned n = 0;
04197     unsigned nrP = 0;           // The number of valid psr.
04198     unsigned nrP_base = 0;      // The number of valid psr for the reference station.
04199     unsigned nrD = 0;           // The number of valid Doppler.
04200     unsigned nrD_base = 0;      // The number of valid Doppler for the reference station.
04201     unsigned nrValidEph = 0;    // The number of valid ephemeris.
04202     unsigned nrDifferentialPsr = 0;     // The number of differential psr.
04203     unsigned nrDifferentialDoppler = 0; // The number of differential Doppler.
04204     bool isDifferential = false;
04205     unsigned u = 0;
04206 
04207     double lat = 0;
04208     double lon = 0;
04209     double hgt = 0;
04210     double clk = 0;
04211     double vn = 0;
04212     double ve = 0;
04213     double vup = 0;
04214     double clkdrift = 0;
04215     double M = 0;   // The computed meridian radius of curvature [m].
04216     double N = 0;   // The computed prime vertical radius of curvature [m].
04217 
04218     Matrix H_p;
04219     Matrix H_v;
04220     Matrix H;
04221     Matrix R_p;
04222     Matrix R_v;
04223     Matrix R;
04224     Matrix w_p;
04225     Matrix w_v;
04226     Matrix w;
04227     Matrix K;
04228     Matrix tmpMat;
04229     Matrix tmpMatP;
04230     Matrix dx(8);
04231     Matrix I;
04232 
04233     dx.Zero();
04234     
04235     // Store the current input pvt as the previous pvt since we are updating.
04236     rxData->m_prev_pvt = rxData->m_pvt;
04237         
04238     lat = rxData->m_pvt.latitude;
04239     lon = rxData->m_pvt.longitude;
04240     hgt = rxData->m_pvt.height;
04241     clk = rxData->m_pvt.clockOffset;
04242     vn  = rxData->m_pvt.vn;
04243     ve  = rxData->m_pvt.ve;
04244     vup = rxData->m_pvt.vup;
04245     clkdrift = rxData->m_pvt.clockDrift;
04246         
04247     if( rxBaseData != NULL )
04248       isDifferential = true;
04249 
04250 #ifdef CONSTRAINPOS
04251     rxData->m_pvt.isPositionConstrained = 1;
04252 #else
04253     rxData->m_pvt.isPositionConstrained = 0;
04254 #endif
04255     
04256     
04257     ////
04258     // Perform operations specific to the rover.
04259 
04260     // Update the receiver time information (UTC and day of year)
04261     result = UpdateTime( *rxData );
04262     if( !result )
04263       return false;
04264 
04265     if( isDifferential )
04266     {
04267       result = UpdateTime( *rxBaseData );
04268       if( !result )
04269       {
04270         return false;
04271       }
04272     }
04273 
04274     result = DetermineSatellitePVT_GPSL1( rxData, rxBaseData, nrValidEph );
04275     if( !result )
04276     {
04277       return false;
04278     }
04279 
04280 
04281     result = DetermineAtmosphericCorrections_GPSL1( *rxData );
04282     if( !result )
04283     {
04284       return false;
04285     }
04286     result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxData, nrP );
04287     if( !result )
04288     {
04289     return false;
04290     }
04291     result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxData, nrD );
04292     if( !result )
04293     {
04294       return false;
04295     }
04296 
04297     if( isDifferential )
04298     {
04299       result = DetermineAtmosphericCorrections_GPSL1( *rxBaseData );
04300       if( !result )
04301         return false;
04302       result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxBaseData, nrP_base );
04303       if( !result )
04304         return false;
04305       result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxBaseData, nrD_base );
04306       if( !result )
04307         return false;
04308 
04309 
04310       // When in differential mode, only differntial measurements will be used
04311       result = DetermineBetweenReceiverDifferentialIndex(
04312         rxData,
04313         rxBaseData,
04314         true 
04315         );
04316       if( !result )      
04317         return false;
04318 
04319       nrDifferentialPsr = 0;
04320       for( i = 0; i < rxData->m_nrValidObs; i++ )
04321       {
04322         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
04323           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
04324           rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
04325         {
04326           nrDifferentialPsr++;
04327         }
04328       }
04329 
04330       
04331 #ifdef CONSTRAINPOS
04332       nrP = nrDifferentialPsr+3;
04333 #else
04334       nrP = nrDifferentialPsr;
04335 #endif
04336 
04337       nrDifferentialDoppler = 0;
04338       for( i = 0; i < rxData->m_nrValidObs; i++ )
04339       {
04340         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
04341           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
04342           rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
04343         {
04344           nrDifferentialDoppler++;
04345         }
04346       }
04347 
04348 #ifdef CONSTRAINPOS
04349       nrD = nrDifferentialDoppler+3;
04350 #else
04351       nrD = nrDifferentialDoppler;
04352 #endif
04353     }
04354 
04355     result = DetermineDesignMatrixForThePositionSolution_GPSL1(
04356       *rxData,
04357       nrP,
04358       H_p );
04359     if( !result )
04360     {
04361       return false;
04362     }
04363     
04364     result = DetermineDesignMatrixForTheVelocitySolution_GPSL1(
04365       *rxData,
04366       nrD,
04367       H_v );
04368     if( !result )
04369     {
04370       return false;
04371     }
04372 
04373 
04374     result = DetermineMeasurementVarianceCovarianceMatrixForThePositionSolution_GPSL1(
04375       *rxData,
04376       nrP,
04377       R_p );
04378     if( !result )
04379     {
04380       return false;
04381     }
04382 
04383 
04384     result = DetermineMeasurementVarianceCovarianceMatrixForTheVelocitySolution_GPSL1(
04385       *rxData,
04386       nrD,
04387       R_v );
04388     if( !result )
04389     {
04390       return false;
04391     }
04392 
04393 
04394     result = DeterminePseudorangeMisclosures_GPSL1(
04395       rxData,
04396       rxBaseData,
04397       nrP,
04398       w_p );
04399     if( !result )
04400     {
04401       return false;
04402     }
04403 
04404     result = DetermineDopplerMisclosures_GPSL1(
04405       rxData,
04406       rxBaseData,
04407       nrD,
04408       w_v );
04409     if( !result )
04410     {
04411       return false;
04412     }
04413 
04414     // Form the combined design matrix.
04415     n = H_p.GetNrRows() + H_v.GetNrRows();
04416 
04417     result = H.Resize( n, 8 );
04418     if( !result )
04419     {
04420       return false;
04421     }
04422 
04423     for( i = 0; i < n; i++ )
04424     {
04425       if( i < nrP )
04426       {
04427         for( j = 0; j < 3; j++ )
04428         {
04429           H[i][j] = H_p[i][j];
04430         }
04431 #ifdef CONSTRAINPOS
04432         if( i < nrP-3 )
04433         {
04434           H[i][6] = 1.0;
04435         }
04436 #else
04437         H[i][6] = 1.0;
04438 #endif
04439       }
04440       else
04441       {
04442         for( j = 0; j < 3; j++ )
04443         {
04444           H[i][j+3] = H_v[i-nrP][j];
04445         }
04446 #ifdef CONSTRAINPOS
04447         if( i < n-3 )
04448         {
04449           H[i][7] = 1.0;
04450         }
04451 #else
04452         H[i][7] = 1.0;
04453 #endif
04454       }
04455     }
04456     
04457     
04458     result = R.Resize( n, n );
04459     if( !result )
04460     {
04461       return false;
04462     }
04463 
04464     // Form the combined measurement variance-covariance matrix.
04465     for( i = 0; i < n; i++ )
04466     {
04467       if( i < nrP )
04468       {
04469         for( j = 0; j < nrP; j++ )
04470         {
04471           R[i][j] = R_p[i][j];
04472         }
04473       }
04474       else
04475       {
04476         for( j = 0; j < nrD; j++ )
04477         {
04478           R[i][j+nrD] = R_v[i-nrP][j];
04479         }
04480       }
04481     }
04482     
04483 
04484     // Form the combined misclosure vector.
04485     result = w.Resize( n, 1 );
04486     if( !result )
04487     {
04488       return false;
04489     }
04490     for( i = 0; i < n; i++ )
04491     {
04492       if( i < nrP )
04493       {
04494         w[i] = w_p[i];
04495       }
04496       else
04497       {
04498         w[i] = w_v[i-nrP];
04499       }
04500     }
04501     
04502     // The corrections for lat and lon, dx_p, must be converted to [rad] from [m].
04503     GEODESY_ComputePrimeVerticalRadiusOfCurvature(
04504       GEODESY_REFERENCE_ELLIPSE_WGS84,
04505       lat,
04506       &N );
04507     GEODESY_ComputeMeridianRadiusOfCurvature(
04508       GEODESY_REFERENCE_ELLIPSE_WGS84,
04509       lat,
04510       &M );
04511     double dlat = M + hgt;
04512     double dlon = (N + hgt) * cos(lat);
04513 
04514     u = 8;
04515     // Now the sequential measurement update section
04516     // For each measurement
04517     for( index = 0; index < n; index++ )
04518     {
04519       Matrix h(1,u);  // The i'th row of the design matrix, [ux1].
04520       Matrix ht(u,1); // The transpose of the i'th row of the design matrix, [ux1].
04521       Matrix pht;     // pht = P ht, [ux1].
04522       Matrix C;       // C = (h P ht + R_{ii}), [1x1].
04523       Matrix k_i;     // The i'th kalman gain. k_i = pht/C
04524       Matrix D;       // D = k_i h * P.
04525       
04526       // Copy out a row of the design matrix.
04527       for( j = 0; j < u; j++ )
04528       {
04529         h[0][j] = H[index][j];
04530         ht[j][0] = H[index][j];
04531       }
04532       //PrintMatToDebug( "h", h );
04533 
04534       // Compute pht
04535       pht = P;
04536       if( !pht.Inplace_PostMultiply( ht ) )
04537         return false;
04538       
04539       // Compute C = (h P h^T + R_{ii})
04540       C = h * pht;
04541       C[0] += R[index][index];
04542       
04543       // Compute k_i
04544       k_i = pht / C[0];
04545 
04546       //PrintMatToDebug( "k_i", k_i );
04547 
04548       // Update the state variance-coveriance;
04549       D = k_i;
04550       if( !D.Inplace_PostMultiply( h ) )
04551         return false;
04552       if( !D.Inplace_PostMultiply( P ) )
04553         return false;
04554       P -= D;
04555 
04556       
04557       double innovation = w[index];
04558       k_i.Inplace_MultiplyScalar( innovation );
04559       dx = k_i;
04560       //PrintMatToDebug( "dx", dx );
04561 
04562       // Update the position and clock states
04563       // Update height first as it is need to reduce the corrections for lat and lon.
04564       hgt += dx[2];
04565       clk += dx[6];
04566 
04567       // The corrections for lat and lon, dx_p, must be converted to [rad] from [m].
04568       lat += dx[0] / dlat;  // convert from meters to radians.
04569       lon += dx[1] / dlon;  // convert from meters to radians.
04570 
04571       result = rxData->UpdatePositionAndRxClock(
04572         lat,
04573         lon,
04574         hgt,
04575         clk,
04576         sqrt(P[0][0]),
04577         sqrt(P[1][1]),
04578         sqrt(P[2][2]),
04579         sqrt(P[6][6])
04580         );
04581       if( !result )
04582       {
04583         return false;
04584       }
04585 
04586       // Update the velocity and clock drift states.
04587       vn        += dx[3];
04588       ve        += dx[4];
04589       vup       += dx[5];
04590       clkdrift  += dx[7];
04591 
04592       result = rxData->UpdateVelocityAndClockDrift(
04593         vn,
04594         ve,
04595         vup,
04596         clkdrift,
04597         sqrt(P[3][3]),
04598         sqrt(P[4][4]),
04599         sqrt(P[5][5]),
04600         sqrt(P[7][7]) );
04601       if( !result )
04602       {
04603         return false;
04604       }
04605 
04606       result = DeterminePseudorangeMisclosures_GPSL1(
04607         rxData,
04608         rxBaseData,
04609         nrP,
04610         w_p );
04611       if( !result )
04612       {
04613         return false;
04614       }
04615 
04616       result = DetermineDopplerMisclosures_GPSL1(
04617         rxData,
04618         rxBaseData,
04619         nrD,
04620         w_v );
04621       if( !result )
04622       {
04623         return false;
04624       }
04625 
04626       for( i = 0; i < n; i++ )
04627       {
04628         if( i < nrP )
04629         {
04630           w[i] = w_p[i];
04631         }
04632         else
04633         {
04634           w[i] = w_v[i-nrP];
04635         }
04636       }            
04637     }
04638     return true;
04639   }
04640 
04641 
04642 
04643   bool GNSS_Estimator::Kalman_Update_8StatePVGM_SequentialMode_FloatSolution(
04644     GNSS_RxData *rxData,      //!< A pointer to the rover receiver data. This must be a valid pointer.
04645     GNSS_RxData *rxBaseData,  //!< A pointer to the reference receiver data if available. NULL if not available.
04646     Matrix &P                 //!< The variance-covariance of the states.
04647   )
04648   {
04649     bool result = false;
04650     unsigned index = 0;
04651     unsigned i = 0;
04652     unsigned j = 0;
04653     unsigned k = 0; 
04654     unsigned m = 0; // counter
04655     unsigned n = 0;
04656     unsigned nrP = 0;           // The number of valid psr.
04657     unsigned nrP_base = 0;      // The number of valid psr for the reference station.
04658     unsigned nrD = 0;           // The number of valid Doppler.
04659     unsigned nrD_base = 0;      // The number of valid Doppler for the reference station.
04660     unsigned nrValidEph = 0;    // The number of valid ephemeris.
04661     unsigned nrUsableAdr = 0;      // The number of valid adr.
04662     unsigned nrUsableAdr_base = 0; // The number of valid adr for the reference station.
04663     unsigned nrDifferentialPsr = 0;     // The number of differential psr.
04664     unsigned nrDifferentialDoppler = 0; // The number of differential Doppler.
04665     unsigned nrDifferentialAdr = 0;     // The number of differntial adr.
04666     bool isDifferential = false;
04667     unsigned u = 0;
04668     bool setToUseOnlyDifferential = true;
04669 
04670     double lat = 0;
04671     double lon = 0;
04672     double hgt = 0;
04673     double clk = 0;
04674     double vn = 0;
04675     double ve = 0;
04676     double vup = 0;
04677     double clkdrift = 0;
04678     double M = 0;   // The computed meridian radius of curvature [m].
04679     double N = 0;   // The computed prime vertical radius of curvature [m].
04680 
04681     Matrix H_p;
04682     Matrix H_v;
04683     Matrix H;
04684     Matrix r; // A vector corresponding to the diagonal elements of R.
04685     Matrix R_p;
04686     Matrix R_v;
04687     Matrix w_p;
04688     Matrix w_v;
04689     Matrix w_adr;
04690     Matrix w;
04691     Matrix K;
04692     Matrix tmpMat;
04693     Matrix tmpMatP;
04694     Matrix dx(8);
04695     Matrix I;
04696 
04697     dx.Zero();
04698     
04699     
04700     lat = rxData->m_pvt.latitude;
04701     lon = rxData->m_pvt.longitude;
04702     hgt = rxData->m_pvt.height;
04703     clk = rxData->m_pvt.clockOffset;
04704     vn  = rxData->m_pvt.vn;
04705     ve  = rxData->m_pvt.ve;
04706     vup = rxData->m_pvt.vup;
04707     clkdrift = rxData->m_pvt.clockDrift;
04708         
04709     if( rxBaseData != NULL )
04710       isDifferential = true;
04711 
04712 #ifdef CONSTRAINPOS
04713     rxData->m_pvt.isPositionConstrained = 1;
04714 #else
04715     rxData->m_pvt.isPositionConstrained = 0;
04716 #endif
04717     
04718     
04719     ////
04720     // Perform operations specific to the rover.
04721 
04722     // Update the receiver time information (UTC and day of year)
04723     result = UpdateTime( *rxData );
04724     if( !result )
04725       return false;
04726 
04727     if( isDifferential )
04728     {
04729       result = UpdateTime( *rxBaseData );
04730       if( !result )
04731       {
04732         return false;
04733       }
04734     }
04735 
04736     result = DetermineSatellitePVT_GPSL1( rxData, rxBaseData, nrValidEph );
04737     if( !result )
04738     {
04739       return false;
04740     }
04741 
04742 
04743     result = DetermineAtmosphericCorrections_GPSL1( *rxData );
04744     if( !result )
04745     {
04746       return false;
04747     }
04748     result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxData, nrP );
04749     if( !result )
04750     {
04751       return false;
04752     }
04753     result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxData, nrD );
04754     if( !result )
04755     {
04756       return false;
04757     }
04758     result = DetermineUsableAdrMeasurements_GPSL1( *rxData, nrUsableAdr );
04759     if( !result )
04760     {
04761       return false;
04762     }
04763     
04764     if( isDifferential )
04765     {
04766       result = DetermineAtmosphericCorrections_GPSL1( *rxBaseData );
04767       if( !result )
04768         return false;
04769       result = DetermineUsablePseudorangeMeasurementsForThePositionSolution_GPSL1( *rxBaseData, nrP_base );
04770       if( !result )
04771         return false;
04772       result = DetermineUsableDopplerMeasurementsForTheVelocitySolution_GPSL1( *rxBaseData, nrD_base );
04773       if( !result )
04774         return false;
04775       result = DetermineUsableAdrMeasurements_GPSL1( *rxBaseData, nrUsableAdr_base );
04776       if( !result )
04777       {
04778         return false;
04779       }
04780 
04781       // When in differential mode, only differntial measurements will be used
04782       result = DetermineBetweenReceiverDifferentialIndex(
04783         rxData,
04784         rxBaseData,
04785         true
04786         );
04787       if( !result )      
04788         return false;
04789 
04790       nrDifferentialPsr = 0;
04791       for( i = 0; i < rxData->m_nrValidObs; i++ )
04792       {
04793         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
04794           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
04795           rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
04796         {
04797           nrDifferentialPsr++;
04798         }
04799       }
04800       
04801 #ifdef CONSTRAINPOS
04802       nrP = nrDifferentialPsr+3;
04803 #else
04804       nrP = nrDifferentialPsr;
04805 #endif
04806 
04807       nrDifferentialDoppler = 0;
04808       for( i = 0; i < rxData->m_nrValidObs; i++ )
04809       {
04810         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
04811           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
04812           rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
04813         {
04814           nrDifferentialDoppler++;
04815         }
04816       }
04817 
04818 #ifdef CONSTRAINPOS
04819       nrD = nrDifferentialDoppler+3;
04820 #else
04821       nrD = nrDifferentialDoppler;
04822 #endif
04823 
04824       nrDifferentialAdr = 0;
04825       for( i = 0; i < rxData->m_nrValidObs; i++ )
04826       {
04827         if( rxData->m_ObsArray[i].system == GNSS_GPS &&
04828           rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
04829           rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
04830         {
04831           nrDifferentialAdr++;
04832         }
04833       }
04834 
04835     }
04836     else
04837     {
04838       return false;
04839     }
04840 
04841     result = DetermineDesignMatrixForThePositionSolution_GPSL1(
04842       *rxData,
04843       nrP,
04844       H_p );
04845     if( !result )
04846     {
04847       return false;
04848     }
04849     
04850     result = DetermineDesignMatrixForTheVelocitySolution_GPSL1(
04851       *rxData,
04852       nrD,
04853       H_v );
04854     if( !result )
04855     {
04856       return false;
04857     }
04858 
04859     result = DeterminePseudorangeMisclosures_GPSL1(
04860       rxData,
04861       rxBaseData,
04862       nrP,
04863       w_p );
04864     if( !result )
04865     {
04866       return false;
04867     }
04868 
04869     result = DetermineDopplerMisclosures_GPSL1(
04870       rxData,
04871       rxBaseData,
04872       nrD,
04873       w_v );
04874     if( !result )
04875     {
04876       return false;
04877     }
04878 
04879     bool hasAmbiguityChangeOccurred = false;
04880     result = DetermineAmbiguitiesChanges(
04881       rxData,
04882       rxBaseData,
04883       P,
04884       hasAmbiguityChangeOccurred );
04885     if( !result )
04886       return false;
04887 
04888     result = DetermineSingleDifferenceADR_Misclosures_GPSL1(
04889       rxData,
04890       rxBaseData,
04891       nrDifferentialAdr,
04892       w_adr );
04893     if( !result )
04894     {
04895       return false;
04896     }
04897 
04898     
04899     // Form the combined design matrix.
04900     n = nrP + nrD + nrDifferentialAdr;
04901 
04902     if( hasAmbiguityChangeOccurred )
04903       int gg=99; // place breakpoint here to debug issues related to changes in ambiguities.
04904 
04905     result = H.Resize( n, 8 + nrDifferentialAdr );
04906     if( !result )
04907     {
04908       return false;
04909     }
04910 
04911     result = r.Resize( n );
04912     if( !result )
04913     {
04914       return false;
04915     }
04916 
04917     unsigned int iP = 0; // A counter for the pseudorange.
04918     unsigned int iD = 0; // A counter for the Doppler.
04919     unsigned int iA = 0; // A counter for the ADR.
04920     double stdev; // a temporary double.
04921     for( k = 0; k < rxData->m_nrValidObs; k++ )
04922     {
04923       if( rxData->m_ObsArray[k].flags.isActive )
04924       {
04925         if( rxData->m_ObsArray[k].flags.isPsrUsedInSolution )
04926         {
04927           H[iP][0] = rxData->m_ObsArray[k].H_p[0];
04928           H[iP][1] = rxData->m_ObsArray[k].H_p[1];
04929           H[iP][2] = rxData->m_ObsArray[k].H_p[2];
04930           H[iP][6] = 1.0;
04931 
04932           stdev = rxData->m_ObsArray[k].stdev_psr;  // KO not differential obs error (need to change)
04933           r[iP] = stdev*stdev;
04934           iP++;
04935         }
04936         if( rxData->m_ObsArray[k].flags.isDopplerUsedInSolution )
04937         {
04938           H[iD+nrP][3] = rxData->m_ObsArray[k].H_v[0];
04939           H[iD+nrP][4] = rxData->m_ObsArray[k].H_v[1];
04940           H[iD+nrP][5] = rxData->m_ObsArray[k].H_v[2];
04941           H[iD+nrP][7] = 1.0;
04942           stdev = rxData->m_ObsArray[k].stdev_doppler * GPS_WAVELENGTHL1; // Change from cycles/s to meters/s.
04943           r[iD+nrP] = stdev*stdev;          
04944           iD++;
04945         }
04946         if( rxData->m_ObsArray[k].flags.isAdrUsedInSolution )
04947         {          
04948           H[iA+nrP+nrD][0] = rxData->m_ObsArray[k].H_p[0];
04949           H[iA+nrP+nrD][1] = rxData->m_ObsArray[k].H_p[1];
04950           H[iA+nrP+nrD][2] = rxData->m_ObsArray[k].H_p[2];
04951           H[iA+nrP+nrD][6] = 1.0;
04952 
04953           H[iA+nrP+nrD][rxData->m_ObsArray[k].index_ambiguity_state] = 1.0;
04954 
04955           stdev = rxData->m_ObsArray[k].stdev_adr * GPS_WAVELENGTHL1; // Change from cycles to meters.
04956           r[iA+nrP+nrD] = stdev*stdev;          
04957           iA++;
04958         }
04959       }
04960     }
04961 
04962     Matrix timeMat(1);
04963     timeMat[0] = rxData->m_pvt.time.gps_tow;
04964     PrintMatToDebug( "gpstime", timeMat );
04965     PrintMatToDebug( "H", H );
04966 
04967     // Form the combined misclosure vector.
04968     result = w.Resize( n, 1 );
04969     if( !result )
04970     {
04971       return false;
04972     }
04973     for( i = 0; i < n; i++ )
04974     {
04975       if( i < nrP )
04976       {
04977         w[i] = w_p[i];
04978       }
04979       else if ( i < nrP+nrD )
04980       {
04981         w[i] = w_v[i-nrP];
04982       }
04983       else
04984       {
04985         w[i] = w_adr[i-nrP-nrD];
04986       }
04987     }
04988 
04989     PrintMatToDebug( "w", w );
04990     
04991     // The corrections for lat and lon, dx_p, must be converted to [rad] from [m].
04992     GEODESY_ComputePrimeVerticalRadiusOfCurvature(
04993       GEODESY_REFERENCE_ELLIPSE_WGS84,
04994       lat,
04995       &N );
04996     GEODESY_ComputeMeridianRadiusOfCurvature(
04997       GEODESY_REFERENCE_ELLIPSE_WGS84,
04998       lat,
04999       &M );
05000     double dlat = M + hgt;
05001     double dlon = (N + hgt) * cos(lat);
05002 
05003     Matrix amb;
05004     if( nrDifferentialAdr > 0 )
05005       amb.Resize(nrDifferentialAdr);
05006 
05007     u = 8 + nrDifferentialAdr;
05008     // Now the sequential measurement update section
05009     // For each measurement
05010     for( index = 0; index < n; index++ )
05011     {
05012       Matrix h(1,u);  // The i'th row of the design matrix, [ux1].
05013       Matrix ht(u,1); // The transpose of the i'th row of the design matrix, [ux1].
05014       Matrix pht;     // pht = P ht, [ux1].
05015       Matrix C;       // C = (h P ht + R_{ii}), [1x1].
05016       Matrix k_i;     // The i'th kalman gain. k_i = pht/C
05017       Matrix D;       // D = k_i h * P.
05018       
05019       // Copy out a row of the design matrix.
05020       for( j = 0; j < u; j++ )
05021       {
05022         h[0][j] = H[index][j];
05023         ht[j][0] = H[index][j];
05024       }
05025       //PrintMatToDebug( "h", h );
05026 
05027       // Compute pht
05028       pht = P;
05029       if( !pht.Inplace_PostMultiply( ht ) )
05030         return false;
05031       
05032       // Compute C = (h P h^T + R_{ii})
05033       C = h * pht;
05034       C[0] += r[index];
05035       
05036       // Compute k_i
05037       k_i = pht / C[0];
05038 
05039       //PrintMatToDebug( "k_i", k_i );
05040 
05041       // Update the state variance-coveriance;
05042       D = k_i;
05043       if( !D.Inplace_PostMultiply( h ) )
05044         return false;
05045       if( !D.Inplace_PostMultiply( P ) )
05046         return false;
05047       P -= D;
05048       
05049       double innovation = w[index];
05050       k_i.Inplace_MultiplyScalar( innovation );
05051       dx = k_i;
05052       //PrintMatToDebug( "dx", dx );
05053 
05054       // Update the position and clock states
05055       // Update height first as it is need to reduce the corrections for lat and lon.
05056       hgt += dx[2];
05057       clk += dx[6];
05058 
05059       // The corrections for lat and lon, dx_p, must be converted to [rad] from [m].
05060       lat += dx[0] / dlat;  // convert from meters to radians.
05061       lon += dx[1] / dlon;  // convert from meters to radians.
05062 
05063       result = rxData->UpdatePositionAndRxClock(
05064         lat,
05065         lon,
05066         hgt,
05067         clk,
05068         sqrt(P[0][0]),
05069         sqrt(P[1][1]),
05070         sqrt(P[2][2]),
05071         sqrt(P[6][6])
05072         );
05073       if( !result )
05074       {
05075         return false;
05076       }
05077 
05078       // Update the velocity and clock drift states.
05079       vn        += dx[3];
05080       ve        += dx[4];
05081       vup       += dx[5];
05082       clkdrift  += dx[7];
05083 
05084       result = rxData->UpdateVelocityAndClockDrift(
05085         vn,
05086         ve,
05087         vup,
05088         clkdrift,
05089         sqrt(P[3][3]),
05090         sqrt(P[4][4]),
05091         sqrt(P[5][5]),
05092         sqrt(P[7][7]) );
05093       if( !result )
05094       {
05095         return false;
05096       }
05097 
05098     // KO recompute misclosures based on the single update (theoretically could redo design matrix too, but very small).
05099     result = DetermineDesignMatrixForThePositionSolution_GPSL1(
05100         *rxData,
05101         nrP,
05102         H_p );
05103       if( !result )
05104       {
05105         return false;
05106       }
05107 
05108       result = DetermineDesignMatrixForTheVelocitySolution_GPSL1(
05109         *rxData,
05110         nrD,
05111         H_v );
05112       if( !result )
05113       {
05114         return false;
05115       }
05116 
05117       result = DeterminePseudorangeMisclosures_GPSL1(
05118         rxData,
05119         rxBaseData,
05120         nrP,
05121         w_p );
05122       if( !result )
05123       {
05124         return false;
05125       }
05126 
05127       result = DetermineDopplerMisclosures_GPSL1(
05128         rxData,
05129         rxBaseData,
05130         nrD,
05131         w_v );
05132       if( !result )
05133       {
05134         return false;
05135       }
05136 
05137       j = 0;
05138       for( i = 0; i < rxData->m_nrValidObs; i++ )
05139       {
05140         if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
05141         {
05142           rxData->m_ObsArray[i].ambiguity += dx[rxData->m_ObsArray[i].index_ambiguity_state];
05143           amb[j] = rxData->m_ObsArray[i].ambiguity;
05144           j++;
05145         }
05146       }
05147 
05148       result = DetermineSingleDifferenceADR_Misclosures_GPSL1(
05149         rxData,
05150         rxBaseData,
05151         nrDifferentialAdr,
05152         w_adr );
05153 
05154       for( i = 0; i < n; i++ )
05155       {
05156         if( i < nrP )
05157         {
05158           w[i] = w_p[i];
05159         }
05160         else if( i < nrP+nrD )
05161         {
05162           w[i] = w_v[i-nrP];
05163         }
05164         else
05165         {
05166           w[i] = w_adr[i-nrP-nrD];
05167         }
05168       }            
05169     }
05170 
05171     for( i = 0; i < rxData->m_nrValidObs; i++ )
05172     {
05173       if( rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
05174         rxData->m_pvt.nrPsrObsUsed++;
05175       if( rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
05176         rxData->m_pvt.nrDopplerObsUsed++;
05177       if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
05178         rxData->m_pvt.nrAdrObsUsed++;
05179     }
05180 
05181     
05182 #ifdef DEBUG_THE_ESTIMATOR
05183     char supermsg[8192];
05184     unsigned nrBytesInBuffer = 0;
05185     rxData->Debug_WriteSuperMsg80CharsWide( 
05186       supermsg,
05187       8192,
05188       51.0916666667*DEG2RAD,
05189       -114.0000000000*DEG2RAD,
05190       1000.000,
05191       nrBytesInBuffer );
05192     printf( supermsg );
05193 #endif
05194    
05195     return true;
05196   }
05197 
05198 
05199   bool GNSS_Estimator::PrintMatToDebug( const char *name, Matrix& M )
05200   {
05201 #ifdef DEBUG_THE_ESTIMATOR
05202 
05203     char buffer[8192];
05204     if( name == NULL )
05205       return false;
05206     if( !M.PrintToBuffer( buffer, 8192, 7 ) )
05207       return 1;
05208     printf( "%s = \n%s\n", name, buffer );
05209 
05210     if( m_debug == NULL )
05211     {
05212       m_debug = fopen( "debug.txt", "w" );
05213       if( !m_debug )
05214       {
05215         return false;
05216       }
05217     }
05218     else
05219     {
05220       fprintf( m_debug, "%s = \n%s\n", name, buffer );      
05221       fflush( m_debug );
05222     }
05223 #endif
05224     return true;
05225   }
05226 
05227 
05228 
05229   bool GNSS_Estimator::DetermineAmbiguitiesChanges( 
05230     GNSS_RxData *rxData,     //!< The receiver data.
05231     GNSS_RxData *rxBaseData, //!< The reference receiver data if any (NULL if not available).
05232     Matrix &P,               //!< The state variance-covariance matrix.
05233     bool& changeOccured 
05234     )
05235   {
05236     unsigned i = 0;
05237     unsigned j = 0;
05238     unsigned k = 0;
05239     unsigned m = 0;
05240     unsigned iP = 0;
05241     unsigned iD = 0;
05242     unsigned iA = 0;
05243     unsigned nP = 0; // The number of valid pseudoranges used in solution.
05244     unsigned nD = 0; // The number of valid Doppler used in solution.
05245     unsigned nA = 0; // The number of valid adr used in solution.
05246     // First look for ambiguities that are no longer active.
05247     bool isAmbiguityActive = false;      
05248     std::list<stAmbiguityInfo>::iterator iter;
05249     std::list<stAmbiguityInfo>::iterator check_iter;
05250     std::list<stAmbiguityInfo>::iterator remove_iter;
05251     std::list<unsigned int> remove_list;
05252     std::list<unsigned int>::const_iterator list_iter;
05253 
05254     changeOccured = false;
05255 
05256     // At this point the active ambiguities are those that were included in the 
05257     // estimation of the previous epoch. This will change if some of those ambiguites
05258     // are no longer included in the observations.
05259     for( iter = m_ActiveAmbiguitiesList.begin(); iter != m_ActiveAmbiguitiesList.end();  )
05260     {
05261       isAmbiguityActive = false;
05262       
05263       // For the active ambiguity (iter), search through the observation array to see
05264       // if the ambiguity is still present and if it is to be estimated.      
05265       for( i = 0; i < rxData->m_nrValidObs; i++ )
05266       {
05267         if( // iter->channel == rxData->m_ObsArray[i].channel && // GDM - NO CHANNEL MATCHING FOR RINEX DATA!
05268           iter->id        == rxData->m_ObsArray[i].id &&
05269           iter->system    == rxData->m_ObsArray[i].system && 
05270           iter->freqType  == rxData->m_ObsArray[i].freqType &&
05271           rxData->m_ObsArray[i].flags.isAdrUsedInSolution &&
05272           rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable )
05273         {
05274           // This ambiguity is already actively estimated.
05275           isAmbiguityActive = true;
05276           break;
05277         }
05278       }
05279 
05280       if( !isAmbiguityActive )
05281       {
05282         changeOccured = true;
05283 
05284         // Add the state_index to the list of indices to be
05285         // removed from state variance covariance matrix.        
05286         remove_list.push_back( iter->state_index );
05287 
05288         remove_iter = iter;
05289         ++iter;
05290         m_ActiveAmbiguitiesList.erase( remove_iter );        
05291       }
05292       else
05293       {
05294         ++iter;
05295       }
05296     }
05297 
05298     // Deal with removing ambiguities from P.
05299     if( remove_list.size() > 0 )
05300     {
05301       unsigned int *rows = NULL;    
05302       unsigned int nrows = static_cast<unsigned int>(remove_list.size());
05303       rows = new unsigned int[nrows];
05304       if( rows == NULL )
05305       {
05306         return false;
05307       }
05308 
05309       i = 0;
05310       for( list_iter = remove_list.begin(); list_iter != remove_list.end(); ++list_iter )
05311       {
05312         rows[i] = *list_iter;
05313         i++;
05314       }
05315 
05316       //P.Print( "P.now.txt", 10 );
05317       if( !P.RemoveRowsAndColumns( nrows, rows, nrows, rows ) )
05318       {
05319         return false;
05320       }
05321       //P.Print( "P.after.txt", 10 );
05322 
05323       delete [] rows;      
05324     }
05325 
05326       // The indices of the ambiguities in the list are now incorrect due to the removals and must be corrected.
05327       // Update the ambiguities list first, then the state indices contained in rxData->m_ObsArray
05328       for( iter = m_ActiveAmbiguitiesList.begin(); iter != m_ActiveAmbiguitiesList.end(); ++iter )
05329       {
05330         for( list_iter = remove_list.begin(); list_iter != remove_list.end(); ++list_iter )
05331         {
05332           if( iter->state_index > (int)(*list_iter) )
05333           {
05334             iter->state_index -= 1;
05335           }
05336         }
05337         // Update the observation array with the new info.
05338         for( i = 0; i < rxData->m_nrValidObs; i++ )
05339         {
05340           if( // iter->channel == rxData->m_ObsArray[i].channel  && // GDM - NO CHANNEL MATCHING FOR RINEX DATA!
05341             iter->id        == rxData->m_ObsArray[i].id       &&
05342             iter->system    == rxData->m_ObsArray[i].system   && 
05343             iter->freqType  == rxData->m_ObsArray[i].freqType &&
05344             rxData->m_ObsArray[i].flags.isAdrUsedInSolution   &&
05345             rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable )
05346           {
05347             rxData->m_ObsArray[i].index_ambiguity_state = iter->state_index;
05348             break;
05349           }
05350         }      
05351       }
05352       remove_list.clear();
05353     
05354 
05355 
05356     // Add new ambiguities if any.
05357     for( i = 0; i < rxData->m_nrValidObs; i++ )
05358     {
05359       isAmbiguityActive = false;
05360       if( rxData->m_ObsArray[i].system == GNSS_GPS && rxData->m_ObsArray[i].freqType == GNSS_GPSL1 )
05361       {
05362         if( rxData->m_ObsArray[i].flags.isActive )
05363         {
05364           if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
05365           {
05366             // Look for this ambiguity in the ambiguities list.
05367             for( iter = m_ActiveAmbiguitiesList.begin(); iter != m_ActiveAmbiguitiesList.end(); ++iter )
05368             {
05369               if( // iter->channel == rxData->m_ObsArray[i].channel && // GDM - NO CHANNEL MATCHING FOR RINEX DATA!
05370                 iter->id        == rxData->m_ObsArray[i].id      &&
05371                 iter->system    == rxData->m_ObsArray[i].system  && 
05372                 iter->freqType  == rxData->m_ObsArray[i].freqType &&
05373                 rxData->m_ObsArray[i].flags.isDifferentialAdrAvailable )
05374               {
05375                 // This ambiguity is already actively estimated.
05376                 isAmbiguityActive = true;
05377                 break;
05378               }
05379             } 
05380 
05381             if( !isAmbiguityActive )
05382             {              
05383               changeOccured = true;
05384 
05385               // Update the active amibguities list.
05386               stAmbiguityInfo amb_info;
05387 
05388               amb_info.channel     = rxData->m_ObsArray[i].channel;
05389               amb_info.id          = rxData->m_ObsArray[i].id;
05390               amb_info.system      = rxData->m_ObsArray[i].system;
05391               amb_info.freqType    = rxData->m_ObsArray[i].freqType;
05392               amb_info.state_index = P.nrows(); // This will be the index of the row and column in P for this ambiguity.
05393 
05394               rxData->m_ObsArray[i].index_ambiguity_state = amb_info.state_index;
05395               
05396               m_ActiveAmbiguitiesList.push_back( amb_info );
05397 
05398               // Add a new row and columgn to the state variance-covariance matrix.
05399               if( !P.Redim( P.nrows()+1, P.ncols()+1 ) )
05400                 return false;
05401 
05402               // Set the initial variance of the ambiguity state [m].
05403               P[amb_info.state_index][amb_info.state_index] = 125; // KO Arbitrary value, to improve
05404 
05405               // Initialize the ambiguity state [m].
05406               // Compute the single difference adr measurement [m].
05407               double sd_adr_measured = rxData->m_ObsArray[i].adr - rxBaseData->m_ObsArray[rxData->m_ObsArray[i].index_differential].adr;
05408               sd_adr_measured *= GPS_WAVELENGTHL1;
05409 
05410               // Compute the single difference psr measurement.
05411               double sd_psr_measured = rxData->m_ObsArray[i].psr - rxBaseData->m_ObsArray[rxData->m_ObsArray[i].index_differential].psr;
05412 
05413               // Initialize the ambiguity to the difference between the single difference adr
05414               // and the single difference pseudorange.
05415 
05416               rxData->m_ObsArray[i].ambiguity =  sd_adr_measured - sd_psr_measured; // in meters!  //KO possibly replace psr with position derived range plus clock offset
05417 
05418               //double sd_computed = rxData->m_ObsArray[i].range - rxBaseData->m_ObsArray[rxData->m_ObsArray[i].index_differential_adr].range;
05419               //sd_computed += rxData->m_pvt.clockOffset;
05420               //rxData->m_ObsArray[i].ambiguity =  sd_adr_measured - sd_computed;
05421             }
05422           }
05423           else
05424           {
05425             rxData->m_ObsArray[i].index_ambiguity_state = -1;
05426             rxData->m_ObsArray[i].ambiguity = 0.0;
05427           }
05428         }
05429       }
05430     }
05431 
05432     // Check for errors.
05433     i = 0;
05434     j = 0;
05435     for( iter = m_ActiveAmbiguitiesList.begin(); iter != m_ActiveAmbiguitiesList.end(); ++iter )
05436     {
05437       j=0;
05438       for( check_iter = m_ActiveAmbiguitiesList.begin(); check_iter != m_ActiveAmbiguitiesList.end(); ++check_iter )
05439       {
05440         if( i != j )
05441         {
05442           if( check_iter->state_index == iter->state_index )
05443             return false;
05444         }
05445         j++;
05446       }
05447       i++;      
05448     }
05449 
05450 
05451     if( changeOccured )
05452     {
05453       // KO_DEBUG  For now use the first active channel as the base satellite and differnce the others.
05454       int ch_index_base = -1;
05455 
05456       // Loop through and look for the first active channel with a 
05457       // valid adr (ready for use in the single difference solution).
05458       for( i = 0; i < rxData->m_nrValidObs; i++ )
05459       {
05460         if( rxData->m_ObsArray[i].flags.isActive )
05461         {
05462           if( rxData->m_ObsArray[i].system == GNSS_GPS &&
05463             rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
05464             rxData->m_ObsArray[i].flags.isAdrValid &&
05465             rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
05466           {
05467             ch_index_base = i;
05468             break;
05469           }
05470         }
05471       }
05472       if( ch_index_base == -1 )
05473       {
05474         // KO_TODO set B to 0x0
05475         return true;
05476       }
05477 
05478       // Set the differencing indices between channels.
05479       for( i = 0; i < rxData->m_nrValidObs; i++ )
05480       {
05481         rxData->m_ObsArray[i].index_between_satellite_differential = -1; // initialize to not used.
05482         if( rxData->m_ObsArray[i].flags.isActive )
05483         {
05484           if( rxData->m_ObsArray[i].system == GNSS_GPS &&
05485             rxData->m_ObsArray[i].freqType == GNSS_GPSL1 &&
05486             rxData->m_ObsArray[i].flags.isAdrValid &&
05487             rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
05488           {
05489             if( i != ch_index_base )
05490             {
05491               rxData->m_ObsArray[i].index_between_satellite_differential = ch_index_base;
05492             }
05493           }
05494         }
05495       }
05496 
05497       for( i = 0; i < rxData->m_nrValidObs; i++ )
05498       {
05499         rxData->m_ObsArray[i].index_psr_B = -1;
05500         if( rxData->m_ObsArray[i].flags.isActive )
05501         {
05502           if( rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
05503           {
05504             rxData->m_ObsArray[i].index_psr_B = nP;
05505             nP++;
05506           }          
05507         }
05508       }
05509 
05510       for( i = 0; i < rxData->m_nrValidObs; i++ )
05511       {
05512         rxData->m_ObsArray[i].index_Doppler_B = -1;
05513         if( rxData->m_ObsArray[i].flags.isActive )
05514         {
05515           if( rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
05516           {
05517             rxData->m_ObsArray[i].index_Doppler_B = nP + nD;
05518             nD++;
05519           }          
05520         }
05521       }
05522 
05523       for( i = 0; i < rxData->m_nrValidObs; i++ )
05524       {
05525         rxData->m_ObsArray[i].index_adr_B = -1;
05526         if( rxData->m_ObsArray[i].flags.isActive )
05527         {
05528           if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
05529           {
05530             rxData->m_ObsArray[i].index_adr_B = nP + nD + nA;
05531             nA++;
05532           }
05533         }
05534       }
05535 
05536       unsigned n=0;
05537       
05538       j = 0;
05539       if( nP > 0 )
05540       {
05541         n += nP - 1;
05542         j++;
05543       }
05544       if( nD > 0 )
05545       {
05546         n += nD - 1;
05547         j++;
05548       }
05549       if( nA > 0 )
05550       {
05551         n += nA - 1;
05552         j++;
05553       }
05554 
05555       // Dimension B and set to zero.
05556       if( !m_RTKDD.B.Resize( n, n+j ) )
05557         return false;
05558 
05559       // Form the double difference operator matrix.
05560       for( i = 0; i < rxData->m_nrValidObs; i++ )
05561       {
05562         if( rxData->m_ObsArray[i].flags.isActive )
05563         {
05564           if( rxData->m_ObsArray[i].flags.isPsrUsedInSolution )
05565           {
05566             if( rxData->m_ObsArray[i].index_between_satellite_differential != -1 )
05567             {
05568               if( rxData->m_ObsArray[ rxData->m_ObsArray[i].index_between_satellite_differential ].index_psr_B == -1 )
05569               {
05570                 return false;
05571               }
05572               m_RTKDD.B[iP][ rxData->m_ObsArray[ rxData->m_ObsArray[i].index_between_satellite_differential ].index_psr_B ] = -1.0;
05573               m_RTKDD.B[iP][ rxData->m_ObsArray[i].index_psr_B ] = 1.0;
05574               iP++;
05575             }
05576           }
05577         }
05578       }
05579 
05580 
05581       for( i = 0; i < rxData->m_nrValidObs; i++ )
05582       {
05583         if( rxData->m_ObsArray[i].flags.isActive )
05584         {      
05585           if( rxData->m_ObsArray[i].flags.isDopplerUsedInSolution )
05586           {
05587             if( rxData->m_ObsArray[i].index_between_satellite_differential != -1 )
05588             {
05589               if( rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].index_Doppler_B == -1 )
05590               {
05591                 return false;
05592               }
05593               m_RTKDD.B[iD+iP][ rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].index_Doppler_B ] = -1.0;
05594               m_RTKDD.B[iD+iP][ rxData->m_ObsArray[i].index_Doppler_B ] = 1.0;
05595               iD++;
05596             }            
05597           }
05598         }
05599       }
05600 
05601       if( !m_RTKDD.B.isEmpty() )
05602         m_RTKDD.prevB    = m_RTKDD.B;
05603       if( !m_RTKDD.SubB.isEmpty() )
05604         m_RTKDD.prevSubB = m_RTKDD.SubB;
05605 
05606       for( i = 0; i < rxData->m_nrValidObs; i++ )
05607       {
05608         if( rxData->m_ObsArray[i].flags.isActive )
05609         {      
05610           if( rxData->m_ObsArray[i].flags.isAdrUsedInSolution )
05611           {
05612             if( rxData->m_ObsArray[i].index_between_satellite_differential != -1 )
05613             {
05614               if( rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].index_adr_B == -1 )
05615               {
05616                 return false;
05617               }
05618               m_RTKDD.B[iA+iP+iD][ rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].index_adr_B ] = -1.0;
05619               m_RTKDD.B[iA+iP+iD][ rxData->m_ObsArray[i].index_adr_B ] = 1.0;
05620               
05621               
05622               //Assign an initial value to the DD ambiguity based on the initial value of the SD ambiguity set above
05623               // Initialize the ambiguity state [m].
05624               // Compute the single difference adr measurement [m].
05625               double sd_adr_current = rxData->m_ObsArray[i].adr - rxBaseData->m_ObsArray[rxData->m_ObsArray[i].index_differential].adr;
05626               sd_adr_current *= GPS_WAVELENGTHL1;
05627               double sd_psr_current = rxData->m_ObsArray[i].psr - rxBaseData->m_ObsArray[rxData->m_ObsArray[i].index_differential].psr;
05628               
05629               double sd_ambiguity_current =  sd_adr_current - sd_psr_current; // in meters!  //KO possibly replace psr with position derived range plus clock offset
05630 
05631               // Initialize the ambiguity state [m].
05632               // Compute the single difference adr measurement [m].
05633               double sd_adr_base = rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].adr - rxBaseData->m_ObsArray[rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].index_differential].adr;
05634               sd_adr_base *= GPS_WAVELENGTHL1;
05635               
05636               double sd_psr_base = rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].psr - rxBaseData->m_ObsArray[rxData->m_ObsArray[rxData->m_ObsArray[i].index_between_satellite_differential].index_differential].psr;
05637               double sd_ambiguity_base =  sd_adr_base - sd_psr_base;
05638 
05639               // Initial double difference ambiugity is the difference difference between the adr and phase of the 4 observations involved in the DD
05640               rxData->m_ObsArray[i].ambiguity_dd = sd_ambiguity_current - sd_ambiguity_base;
05641               iA++;
05642             }            
05643           }
05644         }
05645       }
05646       if( iA < 1 )
05647       {
05648         // KO_TODO anything else?
05649         return true;
05650       }
05651 
05652       PrintMatToDebug( "B", m_RTKDD.B );
05653 
05654       if( !m_RTKDD.SubB.Resize(iA,iA+1)  )
05655         return false;
05656 
05657       for( i = 0; i < iA; i++ )
05658       {
05659         for( j = 0; j < iA+1; j++ )
05660         {
05661           m_RTKDD.SubB[i][j] = m_RTKDD.B[i+iP+iD][j+nP+nD];
05662         }
05663       }
05664 
05665       PrintMatToDebug( "subB", m_RTKDD.SubB );
05666 
05667       if( m_RTKDD.prevSubB.isEmpty() )
05668       {
05669         // Just build dd P
05670         Matrix subP(nA,nA);
05671         for( i = 0; i < nA; i++ )
05672         {
05673           for( j = 0; j < nA; j++ )
05674           {          
05675             subP[i][j] = P[i+6][j+6];            
05676           }
05677         }
05678 
05679         m_RTKDD.P = P;
05680         P.Redim( 6, 6 );
05681         P.Redim( 6+iA, 6+iA );
05682         
05683         subP = m_RTKDD.SubB*subP*m_RTKDD.SubB.T();
05684         for( i = 0; i < iA; i++ )
05685         {
05686           for( j = 0; j < iA; j++ )
05687           {          
05688             P[i+6][j+6] = subP[i][j];
05689           }
05690         }       
05691         PrintMatToDebug( "subP", subP );
05692       }
05693       
05694       PrintMatToDebug( "P", m_RTKDD.P );
05695 
05696       //m_RTKDD.P = 
05697 
05698 
05699 
05700       /*
05701       for( iter = m_ActiveAmbiguitiesList.begin(); iter != m_ActiveAmbiguitiesList.end(); ++iter )
05702       {
05703         if( rxData->m_ObsArray[iter->channel].index_between_satellite_differential != -1 )
05704         {
05705 
05706         }
05707       }
05708       */
05709       
05710 
05711 
05712 
05713       // Form the double differnce state variance covariance matrix.
05714 
05715     }
05716 
05717     return true;
05718   }
05719       
05720 
05721 
05722 
05723 
05724 } // end namespace GNSS
05725 
05726 
05727