RinexConverters.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: RinexConverters.cpp 2400 2010-04-20 13:04:18Z ocibu $"
00002 
00003 //============================================================================
00004 //
00005 //  This file is part of GPSTk, the GPS Toolkit.
00006 //
00007 //  The GPSTk is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU Lesser General Public License as published
00009 //  by the Free Software Foundation; either version 2.1 of the License, or
00010 //  any later version.
00011 //
00012 //  The GPSTk is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU Lesser General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU Lesser General Public
00018 //  License along with GPSTk; if not, write to the Free Software Foundation,
00019 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //  
00021 //  Copyright 2004, The University of Texas at Austin
00022 //
00023 //============================================================================
00024 
00025 //============================================================================
00026 //
00027 //This software developed by Applied Research Laboratories at the University of
00028 //Texas at Austin, under contract to an agency or agencies within the U.S. 
00029 //Department of Defense. The U.S. Government retains all rights to use,
00030 //duplicate, distribute, disclose, or release this software. 
00031 //
00032 //Pursuant to DoD Directive 523024 
00033 //
00034 // DISTRIBUTION STATEMENT A: This software has been approved for public 
00035 //                           release, distribution is unlimited.
00036 //
00037 //=============================================================================
00038 
00041 #include "StringUtils.hpp"
00042 #include "RinexObsID.hpp"
00043 
00044 #include "RinexConverters.hpp"
00045 
00046 using namespace std;
00047 
00048 namespace gpstk
00049 {
00050    short snr2ssi(float x)
00051    {
00052       // These values were obtained from the comments in a RINEX obs file that was
00053       // generated from a TurboBinary file recorded on an AOA Benchmark  receiver
00054       if (x>316) return 9;
00055       if (x>100) return 8;
00056       if (x>31.6) return 7;
00057       if (x>10) return 6;
00058       if (x>3.2) return 5;
00059       if (x>0) return 4;
00060       return 0;
00061    }
00062 
00063    RinexObsData::RinexObsTypeMap makeRinexObsTypeMap(const MDPObsEpoch& moe) throw()
00064    {
00065       gpstk::RinexObsData::RinexObsTypeMap rotm;
00066       MDPObsEpoch::ObsMap ol=moe.obs;
00067       MDPObsEpoch::ObsMap::const_iterator j;
00068 
00069       // The C1 Rinex obs is easy
00070       j = ol.find(MDPObsEpoch::ObsKey(ccL1,rcCA));
00071       if (j!=ol.end())
00072       {
00073          short lli = j->second.lockCount ? 0 : 1;
00074          short ssi = snr2ssi(j->second.snr);
00075          rotm[gpstk::RinexObsHeader::C1].data = j->second.pseudorange;
00076          rotm[gpstk::RinexObsHeader::C1].lli = lli;
00077          rotm[gpstk::RinexObsHeader::C1].ssi = ssi;
00078 
00079          rotm[gpstk::RinexObsHeader::L1].data = j->second.phase;
00080          rotm[gpstk::RinexObsHeader::L1].lli = lli;
00081          rotm[gpstk::RinexObsHeader::L1].ssi = ssi;
00082 
00083          rotm[gpstk::RinexObsHeader::D1].data = j->second.doppler;
00084          rotm[gpstk::RinexObsHeader::D1].lli = lli;
00085          rotm[gpstk::RinexObsHeader::D1].ssi = ssi;
00086 
00087          rotm[gpstk::RinexObsHeader::S1].data = j->second.snr;
00088       }
00089 
00090       // Now get the P1, L1, D1, S1 obs
00091       j = ol.find(MDPObsEpoch::ObsKey(ccL1, rcYcode));
00092       if (j == ol.end())
00093          j = ol.find(MDPObsEpoch::ObsKey(ccL1, rcPcode));
00094       if (j == ol.end())
00095          j = ol.find(MDPObsEpoch::ObsKey(ccL1, rcCodeless));
00096       if (j != ol.end())
00097       {
00098          short lli = j->second.lockCount ? 0 : 1;
00099          short ssi = snr2ssi(j->second.snr);
00100          rotm[gpstk::RinexObsHeader::P1].data = j->second.pseudorange;
00101          rotm[gpstk::RinexObsHeader::P1].lli  = lli;
00102          rotm[gpstk::RinexObsHeader::P1].ssi  = ssi;
00103 
00104          rotm[gpstk::RinexObsHeader::L1].data = j->second.phase;
00105          rotm[gpstk::RinexObsHeader::L1].lli  = lli;
00106          rotm[gpstk::RinexObsHeader::L1].ssi  = ssi;
00107 
00108          rotm[gpstk::RinexObsHeader::D1].data = j->second.doppler;
00109          rotm[gpstk::RinexObsHeader::D1].lli  = lli;
00110          rotm[gpstk::RinexObsHeader::D1].ssi  = ssi;
00111 
00112          rotm[gpstk::RinexObsHeader::S1].data = j->second.snr;
00113       }
00114       
00115       // Now get the P2, L2, D2, S2 obs
00116       j = ol.find(MDPObsEpoch::ObsKey(ccL2, rcYcode));
00117       if (j == ol.end())
00118          j = ol.find(MDPObsEpoch::ObsKey(ccL2, rcPcode));
00119       if (j == ol.end())
00120          j = ol.find(MDPObsEpoch::ObsKey(ccL2, rcCodeless));
00121       if (j != ol.end())
00122       {
00123          short lli = j->second.lockCount ? 0 : 1;
00124          short ssi = snr2ssi(j->second.snr);
00125          rotm[gpstk::RinexObsHeader::P2].data = j->second.pseudorange;
00126          rotm[gpstk::RinexObsHeader::P2].lli  = lli;
00127          rotm[gpstk::RinexObsHeader::P2].ssi  = ssi;
00128 
00129          rotm[gpstk::RinexObsHeader::L2].data = j->second.phase;
00130          rotm[gpstk::RinexObsHeader::L2].lli  = lli;
00131          rotm[gpstk::RinexObsHeader::L2].ssi  = ssi;
00132 
00133          rotm[gpstk::RinexObsHeader::D2].data = j->second.doppler;
00134          rotm[gpstk::RinexObsHeader::D2].lli  = lli;
00135          rotm[gpstk::RinexObsHeader::D2].ssi  = ssi;
00136 
00137          rotm[gpstk::RinexObsHeader::S2].data = j->second.snr;
00138       }
00139 
00140       // Now get the C2
00141       j = ol.find(MDPObsEpoch::ObsKey(ccL2, rcCM));
00142       if (j == ol.end())
00143          j = ol.find(MDPObsEpoch::ObsKey(ccL2, rcCL));
00144       if (j == ol.end())
00145          j = ol.find(MDPObsEpoch::ObsKey(ccL2, rcCMCL));
00146       if (j != ol.end())
00147       {
00148          short lli = j->second.lockCount ? 0 : 1;
00149          short ssi = snr2ssi(j->second.snr);
00150          rotm[gpstk::RinexObsHeader::C2].data = j->second.pseudorange;
00151          rotm[gpstk::RinexObsHeader::C2].lli  = lli;
00152          rotm[gpstk::RinexObsHeader::C2].ssi  = ssi;
00153       }
00154       return rotm;
00155    }
00156 
00157    RinexObsData makeRinexObsData(const gpstk::MDPEpoch& mdp)
00158    {
00159       RinexObsData rod;
00160 
00161       rod.clockOffset=0;
00162       rod.numSvs = mdp.size();
00163       rod.epochFlag = 0;
00164       rod.time = mdp.begin()->second.time;
00165 
00166       for (MDPEpoch::const_iterator i=mdp.begin(); i!=mdp.end(); i++)
00167       {
00168          const MDPObsEpoch& moe = i->second;
00169          gpstk::SatID svid(moe.prn, gpstk::SatID::systemGPS);
00170          rod.obs[svid] = makeRinexObsTypeMap(moe);
00171       }
00172       return rod;
00173    }
00174 
00175    // Try to convert the given pages into an EngAlmanc object. Returns true
00176    // upon success. This routine is tuned for two different types of nav data.
00177    //
00178    // The first is for a receiver that outputs all 4/5 subframes from a given
00179    // code/carrier. Basically it looks for a 12.5 minute cycle that starts
00180    // with page 1 from subframe 4. It makes sure that there hasn't been a
00181    // cutover during it by checking that all sv pages (i.e. svid 1-32) have
00182    // the same toa as the last page 25 (svid 51). This mode is the default and
00183    // is set with the requireFull parameter.
00184    //
00185    // The second is for a receiver that only puts out a set of 4/5 subframes
00186    // that "should" be a complete almanac. Note that it doesn't output pages
00187    // for SVs that are set to the default data.
00188    //
00189    // The only receiver that this has been tested on is the Ashtech Z(Y)12.
00190    // 
00191    // In the IS-GPS-200D, see pages 72-79, 82, 105
00192    bool makeEngAlmanac(EngAlmanac& alm,
00193                        const AlmanacPages& pages,
00194                        bool requireFull) throw()
00195    {
00196       AlmanacPages::const_iterator sf4p1  = pages.find(SubframePage(4,  1));
00197       AlmanacPages::const_iterator sf4p18 = pages.find(SubframePage(4, 18));
00198       AlmanacPages::const_iterator sf4p25 = pages.find(SubframePage(4, 25));
00199       AlmanacPages::const_iterator sf5p25 = pages.find(SubframePage(5, 25));
00200 
00201       // These pages are required for a reasonable alm
00202       if (sf4p18==pages.end() || sf4p25==pages.end() || sf5p25==pages.end())
00203          return false;
00204 
00205       long sf4p1sow=0;
00206       if (requireFull)
00207       {
00208          if (sf4p1==pages.end())
00209             return false;
00210          else
00211             sf4p1sow = sf4p1->second.getHOWTime();
00212       }
00213 
00214       int week=sf4p18->second.time.GPSfullweek();
00215       
00216       for (int p=1; p<=25; p++)
00217       {
00218          for (int sf=4; sf<=5; sf++)
00219          {
00220             AlmanacPages::const_iterator i = pages.find(SubframePage(sf, p));
00221             if (i == pages.end())
00222             {
00223                if (requireFull)
00224                   return false;
00225                else
00226                   continue;
00227             }
00228 
00229             // All pages have to be contingious for the full alm mode.
00230             if (requireFull)
00231             {
00232                long sow = i->second.getHOWTime(); 
00233                if (sow != sf4p1sow + (sf-4)*6 + (p-1)*30)
00234                   return false;
00235             }
00236 
00237             long sfa[10];
00238             long long_sfa[10];
00239             i->second.fillArray(sfa);
00240             copy( &sfa[0], &sfa[10], long_sfa);
00241             if (!alm.addSubframe(long_sfa, week))
00242                return false;
00243          }
00244       }
00245       return true;
00246    }
00247 
00248    // Try to convert the given pages into an EngEphemeris object. Returns true
00249    // upon success.
00250    bool makeEngEphemeris(EngEphemeris& eph, const EphemerisPages& pages)
00251    {
00252       EphemerisPages::const_iterator sf[4];
00253 
00254       sf[1] = pages.find(1);
00255       if (sf[1] == pages.end())
00256          return false;
00257       
00258       sf[2] = pages.find(2);
00259       if (sf[2] == pages.end())
00260          return false;
00261 
00262       sf[3] = pages.find(3);
00263       if (sf[3] == pages.end())
00264          return false;
00265 
00266       long t1 = sf[1]->second.getHOWTime();
00267       long t2 = sf[2]->second.getHOWTime();
00268       long t3 = sf[3]->second.getHOWTime();
00269       if (t2 != t1+6 || t3 != t1+12)
00270          return false;
00271 
00272       int prn = sf[1]->second.prn;
00273       int week = sf[1]->second.time.GPSfullweek();
00274       long sfa[10];
00275       long long_sfa[10];
00276 
00277       for (int i=1; i<=3; i++)
00278       {
00279          sf[i]->second.fillArray(sfa);
00280          for( int j = 0; j < 10; j++ )
00281             long_sfa[j] = static_cast<long>( sfa[j] );
00282          if (!eph.addSubframe(long_sfa, week, prn, 0))
00283             return false;
00284       }
00285 
00286       if (eph.isData(1) && eph.isData(2) && eph.isData(3))
00287          return true;
00288 
00289       return false;
00290    }
00291 } // end of namespace gpstk

Generated on Wed Feb 8 03:31:02 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1