ObsUtils.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: ObsUtils.cpp 2741 2011-06-22 16:37:02Z nwu $"
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 #include "icd_200_constants.hpp"
00044 
00045 #include "ObsUtils.hpp"
00046 
00047 using namespace std;
00048 
00049 namespace gpstk
00050 {
00051    //---------------------------------------------------------------------------
00052    SvObsEpoch makeSvObsEpoch(const MDPObsEpoch& mdp) throw()
00053    {
00054       SvObsEpoch obs;
00055       MDPObsEpoch::ObsMap::const_iterator i;
00056       obs.svid = SatID(mdp.prn, SatID::systemGPS);
00057       obs.elevation = mdp.elevation;
00058       obs.azimuth = mdp.azimuth;
00059       for (i=mdp.obs.begin(); i!=mdp.obs.end(); i++)
00060       {
00061          CarrierCode cc = i->first.first;
00062          RangeCode rc = i->first.second;
00063          const MDPObsEpoch::Observation& mdp_obs = i->second;
00064 
00065          ObsID::CarrierBand cb;
00066          ObsID::TrackingCode tc;
00067 
00068          switch(cc)
00069          {
00070             case ccL1: cb = ObsID::cbL1; break;
00071             case ccL2: cb = ObsID::cbL2; break;
00072             case ccL5: cb = ObsID::cbL5; break;
00073             default:   cb = ObsID::cbUnknown;
00074          }
00075 
00076          switch (rc)
00077          {
00078             case rcCA:       tc = ObsID::tcCA; break;
00079             case rcPcode:    tc = ObsID::tcP; break;
00080             case rcYcode:    tc = ObsID::tcY; break;
00081             case rcCodeless: tc = ObsID::tcW; break;
00082             case rcCM:       tc = ObsID::tcC2M; break;
00083             case rcCL:       tc = ObsID::tcC2L; break;
00084             case rcMcode1:   tc = ObsID::tcM; break;
00085             case rcMcode2:   tc = ObsID::tcM; break;
00086             case rcCMCL:     tc = ObsID::tcC2LM; break;
00087             default:         tc = ObsID::tcUnknown;
00088          }
00089 
00090          obs[ObsID(ObsID::otRange,    cb, tc)] = mdp_obs.pseudorange;
00091          obs[ObsID(ObsID::otPhase,    cb, tc)] = mdp_obs.phase;
00092          obs[ObsID(ObsID::otDoppler,  cb, tc)] = mdp_obs.doppler;
00093          obs[ObsID(ObsID::otSNR,      cb, tc)] = mdp_obs.snr;
00094          obs[ObsID(ObsID::otTrackLen, cb, tc)] = mdp_obs.lockCount;
00095       }
00096       return obs;
00097    }
00098 
00099 
00100    //---------------------------------------------------------------------------
00101    SvObsEpoch makeSvObsEpoch(const RinexObsData::RinexObsTypeMap& rotm) throw()
00102    {
00103       SvObsEpoch soe;
00104 
00105       RinexObsData::RinexObsTypeMap::const_iterator rotm_itr;
00106       for (rotm_itr = rotm.begin(); rotm_itr != rotm.end(); rotm_itr++)
00107       {
00108          const RinexObsHeader::RinexObsType& rot = rotm_itr->first;
00109          const RinexObsData::RinexDatum& rd = rotm_itr->second;
00110          RinexObsID oid(rot);
00111          soe[oid] = rd.data;
00112          if (rd.ssi>0)
00113          {
00114             oid.type = ObsID::otSSI;
00115             soe[oid] = rd.ssi;
00116          }
00117          if (rd.lli>0)
00118          {
00119             oid.type = ObsID::otLLI;
00120             soe[oid] = rd.lli;
00121          }
00122       }
00123 
00124       return soe;
00125    }
00126 
00127 
00128    //---------------------------------------------------------------------------
00129    ObsEpoch makeObsEpoch(const RinexObsData& rod) throw()
00130    {
00131       ObsEpoch oe;
00132       oe.time = rod.time;
00133 
00134       RinexObsData::RinexSatMap::const_iterator rsm_itr;
00135       for (rsm_itr = rod.obs.begin(); rsm_itr != rod.obs.end(); rsm_itr++)
00136       {
00137          const SatID svid(rsm_itr->first);
00138          const RinexObsData::RinexObsTypeMap& rotm = rsm_itr->second;
00139          oe[svid] = makeSvObsEpoch(rotm);
00140       }
00141 
00142       return oe;
00143    }
00144 
00145 
00146    //---------------------------------------------------------------------------
00147    ObsEpoch makeObsEpoch(const MDPEpoch& mdp) throw()
00148    {
00149       ObsEpoch oe;
00150       oe.time = mdp.begin()->second.time;
00151 
00152       for (MDPEpoch::const_iterator i=mdp.begin(); i!=mdp.end(); i++)
00153       {
00154          const MDPObsEpoch& moe = i->second;
00155          SatID svid(moe.prn, SatID::systemGPS);
00156          oe[svid] = makeSvObsEpoch(moe);
00157       }
00158       return oe;
00159    }
00160 
00161 
00162    //---------------------------------------------------------------------------
00163    WxObservation makeWxObs(const SMODFData& smod) throw()
00164    {
00165       WxObservation wx;
00166 
00167       wx.t = smod.time;
00168 
00169       if (smod.tempSource)
00170       {
00171          wx.temperature = smod.temp;
00172          wx.temperatureSource = WxObservation::obsWx;
00173       }
00174       else
00175          wx.temperatureSource = WxObservation::noWx;;
00176 
00177       if (smod.pressSource)
00178       {
00179          wx.pressure = smod.pressure;
00180          wx.pressureSource = WxObservation::obsWx;
00181       }
00182       else
00183          wx.pressureSource = WxObservation::noWx;;
00184 
00185       if (smod.humidSource)
00186       {
00187          wx.humidity = smod.humidity;
00188          wx.humiditySource = WxObservation::obsWx;
00189       }
00190       else
00191          wx.humiditySource = WxObservation::noWx;
00192 
00193       return wx;
00194    }
00195 
00196 
00197    //---------------------------------------------------------------------------
00198    void addMDPObservation(MDPObsEpoch& moe,
00199                           const AshtechMBEN::code_block& cb,
00200                           CarrierCode cc,
00201                           RangeCode rc,
00202                           const MDPObsEpoch& moe_hint) throw()
00203    {
00204       // fixup the range code to match what is indicated by the goodbad flag
00205       if (rc != rcCA)
00206          switch (cb.goodbad)
00207          {
00208             case 22: rc = rcPcode; break; //0x16
00209             case 24: rc = rcYcode; break; //0x18
00210             case 25: rc = rcCodeless; break; //0x19
00211          }
00212 
00213       float chipRate=PY_CHIP_FREQ;
00214       if (rc == rcCA)
00215          chipRate = CA_CHIP_FREQ;
00216 
00217       MDPObsEpoch::Observation obs;
00218       obs.carrier = cc;
00219       obs.range = rc;
00220       obs.snr = cb.snr(chipRate);
00221       obs.pseudorange = cb.raw_range * C_GPS_M;
00222       obs.phase = cb.full_phase;
00223       obs.doppler = -cb.doppler; // yeah, the Ashtech sign is backwards
00224       obs.bw=1;
00225       obs.lockCount = 0;
00226 
00227       if (moe_hint.haveObservation(cc, rc))
00228       {
00229          MDPObsEpoch::Observation obs_hint = moe_hint.getObservation(cc, rc);
00230          obs.bw = obs_hint.bw;
00231 
00232          // if any bits in 3-5, 7,8 are set we are are questionable
00233          if (!(cb.warning & ~0x23))
00234             obs.lockCount = obs_hint.lockCount+1;
00235       }
00236 
00237       moe.obs[MDPObsEpoch::ObsKey(cc, rc)] = obs;
00238    }
00239 
00240 
00241    //---------------------------------------------------------------------------
00242    MDPObsEpoch makeMDPObsEpoch(
00243       const AshtechMBEN& mben,
00244       const MDPObsEpoch& hint) throw()
00245    {
00246       MDPObsEpoch moe;
00247 
00248       // Get the full time from the hint and make the sow match the MBEN
00249       moe.time = hint.time;
00250       double sow1 = moe.time.GPSsecond();
00251       int sow2 = static_cast<int>(sow1/1800);
00252       double sow3 = static_cast<double>(sow2 * 1800);
00253       double sow_mben = 0.05 * mben.seq;
00254       double sow4 = sow3 + sow_mben;
00255       long week = moe.time.GPSfullweek();
00256       if (sow4 < sow1) // Assume that time only moves forward
00257          sow4 += 1800;
00258       while (sow4 >= DayTime::FULLWEEK)
00259       {
00260          sow4 -= DayTime::FULLWEEK;
00261          week += 1;
00262       }
00263       moe.time.setGPS(week, sow4);
00264 
00265       moe.numSVs = hint.numSVs;
00266       moe.channel = mben.chid;
00267       moe.prn = mben.svprn;
00268       moe.status = hint.status;
00269       moe.elevation = mben.el;
00270       moe.azimuth = mben.az;
00271 
00272       addMDPObservation(moe, mben.ca, ccL1, rcCA, hint);
00273 
00274       if (mben.id == AshtechMBEN::mpcId)
00275       {
00276          addMDPObservation(moe, mben.p1, ccL1, rcPcode, hint);
00277          addMDPObservation(moe, mben.p2, ccL2, rcPcode, hint);
00278       }
00279       return moe;
00280    }
00281 
00282 
00283    //---------------------------------------------------------------------------
00284    MDPPVTSolution makeMDPPVTSolution(
00285       const AshtechPBEN& pben,
00286       const unsigned week) throw()
00287    {
00288       MDPPVTSolution pvt;
00289 
00290       pvt.x[0] = pben.navx;
00291       pvt.x[1] = pben.navy;
00292       pvt.x[2] = pben.navz;
00293       pvt.dtime = pben.navt / C_GPS_M;
00294       pvt.v[0] = pben.navxdot;
00295       pvt.v[1] = pben.navydot;
00296       pvt.v[2] = pben.navzdot;
00297       pvt.ddtime = pben.navtdot / C_GPS_M;
00298 
00299       pvt.time.setGPS(week, pben.sow);
00300       pvt.timep = pvt.time + pvt.dtime;
00301 
00302       pvt.fom = pben.pdop;
00303       pvt.numSVs = (int)pben.numSV;
00304       pvt.pvtMode = 0;
00305       pvt.corrections = 0;
00306 
00307       return pvt;
00308    }
00309 
00310    //---------------------------------------------------------------------------
00311    MDPEpoch makeMDPEpoch(const ATSData& ats, const MDPEpoch& hint) throw()
00312    {
00313       MDPEpoch me;
00314       DayTime t0(DayTime::BEGINNING_OF_TIME);
00315 
00316       for (int i=0; i < ats.channels.size(); i++)
00317       {
00318          const ATSData::ChannelBlock& cb = ats.channels[i];
00319          short week = static_cast<short>(cb.absTime / DayTime::FULLWEEK);
00320          // It appears that week 0 is output before a channel really starts
00321          // tracking.
00322          if (week==0)
00323             continue;
00324 
00325          double sow = cb.absTime - week * DayTime::FULLWEEK;
00326          DayTime t(week, sow);
00327          if (i==0 || t0 == DayTime(DayTime::BEGINNING_OF_TIME))
00328             t0 = t;
00329          else if (std::abs(t - t0) > 0.1)
00330          {
00331             if (ats.debugLevel>1)
00332                cout << "# Epoch with inconsistent times t:" << t
00333                     << ", t0:" << t0 << endl;
00334             continue;
00335          }
00336 
00337          MDPObsEpoch moe;
00338 
00339          moe.time = t;
00340          moe.prn = cb.svid.id;
00341          moe.status = 0;
00342          moe.elevation = 0;
00343          moe.azimuth = 0;
00344          moe.channel = i + 1;
00345 
00346          MDPObsEpoch moe_hint;
00347          MCIP mcip = hint.equal_range(cb.svid.id);
00348 
00349          MDPEpoch::const_iterator k;
00350          for (k=mcip.first; k != mcip.second; k++)
00351             if (k->second.channel == moe.channel)
00352             {
00353                moe_hint = k->second;
00354                break;
00355             }
00356 
00357          for (int j=0; j<ats.numSubChan; j++)
00358          {
00359             const ATSData::SubChannelBlock& scb=cb.subChannels[j];
00360 
00361             MDPObsEpoch::ObsKey obsKey;
00362             switch (j)
00363             {
00364                case 0: obsKey = MDPObsEpoch::ObsKey(ccL1, rcCA);     break;
00365                case 1: obsKey = MDPObsEpoch::ObsKey(ccL1, rcYcode);  break;
00366                case 2: obsKey = MDPObsEpoch::ObsKey(ccL2, rcYcode);  break;
00367                case 3: obsKey = MDPObsEpoch::ObsKey(ccL1, rcMcode1); break;
00368                case 4: obsKey = MDPObsEpoch::ObsKey(ccL2, rcMcode1); break;
00369             }
00370 
00371             MDPObsEpoch::Observation obs;
00372             obs.carrier = obsKey.first;
00373             obs.range = obsKey.second;
00374             obs.bw = 1;
00375             obs.snr = scb.cn0;
00376             obs.pseudorange = scb.pseudorange;
00377             obs.phase = scb.phase;
00378             obs.lockCount = 0;
00379             // bit0: loss of lock, bit1: code tracking, bit2 carrier tracking
00380             // bit3: gps time, bit4: tbd, bits5-7: Data rate
00381             // It appears that the M codes loss of lock bit doesn't work
00382             if (scb.flags & 0x1 && j<3)
00383                continue;  //Drop obs with loss of lock set
00384             else if (scb.cn0 < 20)
00385                continue;  //Drop obs with snr that indicates noise
00386             else if (moe_hint.haveObservation(obsKey))
00387             {
00388                MDPObsEpoch::Observation oh = moe_hint.getObservation(obsKey);
00389                obs.lockCount = oh.lockCount+1;
00390             }
00391 
00392             if (obs.carrier == ccL1)
00393                obs.doppler = scb.rangeRate ;
00394             else if (obs.carrier == ccL2)
00395                obs.doppler = scb.rangeRate;
00396 
00397             moe.obs[obsKey] = obs;
00398          }
00399 
00400          me.insert(pair<const int, MDPObsEpoch>(moe.prn, moe));
00401       }
00402       // now compute how many SVs were really tracked...
00403       int numSVs = me.size();
00404       MDPEpoch::iterator i;
00405       for (i=me.begin(); i != me.end(); i++)
00406          i->second.numSVs = numSVs;
00407       return me;
00408    }
00409 
00410 } // namespace gpstk

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