1 //==============================================================================
2 //
3 //  This file is part of GPSTk, the GPS Toolkit.
4 //
5 //  The GPSTk is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU Lesser General Public License as published
7 //  by the Free Software Foundation; either version 3.0 of the License, or
8 //  any later version.
9 //
10 //  The GPSTk is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Lesser General Public License for more details.
14 //
15 //  You should have received a copy of the GNU Lesser General Public
16 //  License along with GPSTk; if not, write to the Free Software Foundation,
17 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 //  This software was developed by Applied Research Laboratories at the
20 //  University of Texas at Austin.
21 //  Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 //  This software was developed by Applied Research Laboratories at the
28 //  University of Texas at Austin, under contract to an agency or agencies
29 //  within the U.S. Department of Defense. The U.S. Government retains all
30 //  rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 //  Pursuant to DoD Directive 523024
33 //
34 //  DISTRIBUTION STATEMENT A: This software has been approved for public
35 //                            release, distribution is unlimited.
36 //
37 //==============================================================================
38 
39 /// @file SatPassIterator.cpp
40 /// Iterate over a vector of SatPass in time order.
41 
42 #include "SatPassIterator.hpp"
43 #include "logstream.hpp"
44 
45 using namespace std;
46 using namespace gpstk::StringUtils;
47 namespace gpstk {
48 
49 // -------------------------------------------------------------------------------
50 // only constructor
SatPassIterator(vector<SatPass> & splist,bool rev,bool dbug)51 SatPassIterator::SatPassIterator(vector<SatPass>& splist, bool rev, bool dbug)
52       : SPList(splist), timeReverse(rev), debug(dbug)
53 {
54    if(SPList.size() == 0) {
55       Exception e("Empty list");
56       GPSTK_THROW(e);
57    }
58 
59    int i,j;
60 
61    // ensure time order
62    std::sort(SPList.begin(), SPList.end());
63 
64    // copy the list of obs types, and check that each is registered
65    vector<string> otlist;
66    for(i=0; i<SPList[0].labelForIndex.size(); i++) {
67       otlist.push_back(SPList[0].labelForIndex[i]);
68       //if(RinexObsHeader::convertObsType(SPList[0].labelForIndex[i])
69       //      == RinexObsHeader::UN)
70       //{
71       //   Exception e("Unregistered observation type : "+SPList[0].labelForIndex[i]);
72       //   GPSTK_THROW(e);
73       //}
74    }
75 
76    // copy the data from the first SatPass in the list, for comparison with the rest
77    DT = SPList[0].dt;
78    FirstTime = SPList[0].getFirstTime();
79    LastTime = SPList[0].getLastTime();
80 
81    // loop over the list
82    for(i=0; i<SPList.size(); i++) {
83       // check for consistency of dt
84       if(SPList[i].dt != DT) {
85          Exception e("Inconsistent time intervals: " + asString(SPList[i].dt)
86             + " != " + asString(DT));
87          GPSTK_THROW(e);
88       }
89 
90       // find the earliest and latest time
91       if(SPList[i].getFirstTime() < FirstTime) FirstTime = SPList[i].getFirstTime();
92       if(SPList[i].getLastTime() > LastTime) LastTime = SPList[i].getLastTime();
93 
94    }  // end loop over the list
95 
96    reset(timeReverse,debug);
97 }
98 
99 // -------------------------------------------------------------------------------
100 // restart the iteration
reset(bool rev,bool dbug)101 void SatPassIterator::reset(bool rev, bool dbug) throw()
102 {
103    timeReverse = rev;
104    debug = dbug;
105    // clear out the old
106    currentN = 0;
107    listIndex.clear();
108    dataIndex.clear();
109    countOffset.clear();
110    indexStatus = vector<int>(SPList.size(),-1);
111    // loop over the list
112    int i = (timeReverse ? SPList.size()-1 : 0);
113    while((timeReverse && i >= 0) || (!timeReverse && i<SPList.size())) {
114 
115       for(;;) {
116          // ignore passes with negative Status
117          if(SPList[i].Status < 0) break;
118 
119          // define latest epoch when time reversed
120          if(timeReverse && currentN == 0)
121             currentN = int((SPList[i].firstTime - FirstTime)/DT + 0.5)
122                                  + SPList[i].spdvector[SPList[i].size()-1].ndt;
123 
124          // (re)build the maps
125          if(listIndex.find(SPList[i].sat) == listIndex.end()) {
126             indexStatus[i] = 0;
127             listIndex[SPList[i].sat] = i;
128             dataIndex[SPList[i].sat] = (timeReverse ? SPList[i].size()-1 : 0);
129             countOffset[SPList[i].sat]
130                = int((SPList[i].firstTime - FirstTime)/DT + 0.5);
131             LOG(DEBUG4) << "reset - define map " << i <<" for sat " << SPList[i].sat
132                << " at time " << SPList[i].firstTime.printf("%4F %10.3g")
133                << " offset " << countOffset[SPList[i].sat];
134          }
135          else {
136             indexStatus[i] = -1;
137             LOG(DEBUG4)<< "reset - turn off pass "<< i <<" for sat " << SPList[i].sat
138                << " at time " << SPList[i].firstTime.printf("%4F %10.3g");
139          }
140 
141          break;      // mandatory
142       }
143 
144       if(timeReverse) i--; else i++;
145    }  // end loop over the list
146 
147 }
148 
149 // -------------------------------------------------------------------------------
150 // return 1 for success, 0 at end of data
151 // Access (all of) the data for the next epoch. As long as this function
152 // returns non-zero, there is more data to be accessed. Ignore passes with
153 // Status less than zero.
154 // @param indexMap  map<unsigned int, unsigned int> defined so that all the
155 //                  data in the current iteration is found at
156 //                  SatPassList[i].data(j) where indexMap[i] = j.
157 // @return 1 for success, 0 at the end of the dataset.
158 // @throw if time tags are out of order.
next(map<unsigned int,unsigned int> & indexMap)159 int SatPassIterator::next(map<unsigned int, unsigned int>& indexMap)
160 {
161    int i,j,k,numsvs;
162    RinexSatID sat;
163 
164    numsvs = 0;
165    indexMap.clear();
166    nextIndexMap.clear();
167 
168    if(debug) LOG(INFO) << "SPIterator::next(map) - time "
169       << (FirstTime+currentN*DT).printf("%4F %10.3g")
170       << " size of listIndex " << listIndex.size();
171 
172    while(numsvs == 0) {
173       if(listIndex.size() == 0) {
174          if(debug) LOG(INFO) << "Return 0 from next()";
175          return 0;
176       }
177 
178       // loop over active SatPass's
179       map<RinexSatID,int>::iterator kt;
180 
181       // debugging - dump the listIndex
182 
183       if(debug) for(kt = listIndex.begin(); kt != listIndex.end(); kt++)
184          LOG(INFO) << "   listIndex: " << kt->first << " " << kt->second;
185 
186       kt = listIndex.begin();
187       while(kt != listIndex.end()) {
188          sat = kt->first;
189          i = kt->second;
190          j = dataIndex[sat];
191          if(debug) LOG(INFO) << "Loop over listIndex: " << sat << " " << i <<" "<< j;
192 
193          if(SPList[i].Status < 0) {
194             listIndex.erase(kt++);  // erasing a map - do exactly this and no more
195             if(debug) LOG(INFO) << " Erase this pass for bad status: index "
196                << i << " sat " << sat << " size is now " << listIndex.size();
197             continue;
198          }
199 
200          if(countOffset[sat] + SPList[i].spdvector[j].ndt == currentN) {
201             // found active sat at this count - add to map
202             nextIndexMap[i] = j;
203             numsvs++;
204             if(debug) LOG(INFO) << "SPIterator::next(map) found sat " << sat
205                << " at index " << i;
206 
207             // increment data index
208             if((timeReverse && --j < 0) ||
209                (!timeReverse && ++j == SPList[i].spdvector.size()))
210             {
211                if(debug) LOG(INFO) << " This pass for sat " << sat << " is done ...";
212                indexStatus[i] = 1;
213 
214                // find the next pass for this sat
215                k = i + (timeReverse ? -1 : 1);
216                while((timeReverse && k>=0) || (!timeReverse && k<SPList.size()))
217                //for(k=i+1; k<SPList.size(); k++)
218                {
219                   if(debug) LOG(INFO) << " ... consider next pass " << k
220                      << " " << SPList[k].sat
221                      << " " << SPList[k].firstTime.printf("%4F %10.3g");
222                   bool found(false);
223                   for(;;) {
224                      if(SPList[k].Status < 0)      // bad pass
225                         break;
226                      if(SPList[k].sat != sat)      // wrong sat
227                         break;
228                      if(indexStatus[k] > 0)        // already done
229                         break;
230 
231                      // take this one
232                      indexStatus[k] = 0;
233                      i = listIndex[sat] = k;
234                      dataIndex[sat] = (timeReverse ? SPList[i].size()-1 : 0);
235                      countOffset[sat] = int((SPList[i].firstTime-FirstTime)/DT + 0.5);
236                      found = true;
237                      break;   // mandatory
238                   }
239                   if(found) break;
240                   if(timeReverse) k--; else k++;
241                }  // end while loop over next passes
242 
243                if(indexStatus[i] == 0) {
244                   if(debug) LOG(INFO) << " ... new pass for sat " << SPList[i].sat
245                   << " at index " << i << " and time "
246                   << SPList[i].firstTime.printf("%4F %10.3g");
247                }
248             }
249             else {
250                dataIndex[sat] = j;
251             }
252 
253          }  // end if found active sat at this count
254 
255          // increment the iterator
256          if(indexStatus[i] > 0) {                // a new one was not found
257             listIndex.erase(kt++);  // erasing a map - do exactly this and no more
258             if(debug) LOG(INFO) << " Erase this pass: index " << i << " sat " << sat
259                << " size is now " << listIndex.size();
260          }
261          else kt++;
262 
263       }  // end while loop over active SatPass's
264       if(debug) LOG(INFO) << "End while loop over active SatPasses";
265 
266       //if(robs.numSvs == 0) cout << "Gap at " << currentN << endl;
267       if(timeReverse) currentN--; else currentN++;
268 
269    }  // end while robs.numSvs==0
270 
271    indexMap = nextIndexMap;
272    if(debug) LOG(INFO) << "Return 1 from next()";
273 
274    return 1;
275 }
276 
277 // -------------------------------------------------------------------------------
278 // return 1 for success, 0 at end of data
279 // NB This assumes all the passes have the same obstypes in the same order, AND
280 //   it knows nothing of the obstypes in the header....
281 // TD perhaps better design is to pass this (SatPassIterator) a vector of obstypes
282 //   from the header and have it fill the robs parallel to that, inserting 0 as nec.
next(RinexObsData & robs)283 int SatPassIterator::next(RinexObsData& robs)
284 {
285    if(listIndex.size() == 0) return 0;
286 
287    map<unsigned int, unsigned int> indexMap;
288    map<unsigned int, unsigned int>::const_iterator kt;
289    int iret = next(indexMap);
290    if(iret == 0) return iret;
291 
292    robs.obs.clear();
293    robs.epochFlag = 0;
294    robs.clockOffset = 0.0;
295    robs.numSvs = 0;
296 
297    // get the time tag.
298    // NB there is an assumption here, that all that SatPass'es in indexMap are
299    // consistent w.r.t. time tag - clearly ok if SPList was created in the usual ways.
300    kt = indexMap.begin();
301    robs.time = SPList[kt->first].time(kt->second);
302 
303    // loop over the map
304    for(kt = indexMap.begin(); kt != indexMap.end(); kt++) {
305       int i = kt->first;
306       int j = kt->second;
307       RinexSatID sat = SPList[i].getSat();
308       //LOG(DEBUG2) << "SPIterator::next(robs) found sat " << sat
309       //   << " at index " << i << " and time " << SPList[i].time(j);
310 
311       bool found = false;
312       bool flag = (SPList[i].spdvector[j].flag != SatPass::BAD);
313       for(int k=0; k<SPList[i].labelForIndex.size(); k++) {
314          RinexObsType ot;
315          ot = RinexObsHeader::convertObsType(SPList[i].labelForIndex[k]);
316          if(ot == RinexObsHeader::UN) {
317             ; //LOG(DEBUG1) << " Error - this sat has UN obstype"; // TD warn?
318          }
319          else {
320             found = true;
321             // NO some obs may be zero b/c they are not collected (e.g. C2) -> bad
322             //robs.obs[sat][ot].data = flag ? SPList[i].spdvector[j].data[k] : 0.;
323             //robs.obs[sat][ot].lli  = flag ? SPList[i].spdvector[j].lli[k] : 0;
324             //robs.obs[sat][ot].ssi  = flag ? SPList[i].spdvector[j].ssi[k] : 0;
325             robs.obs[sat][ot].data = SPList[i].spdvector[j].data[k];
326             robs.obs[sat][ot].lli  = SPList[i].spdvector[j].lli[k];
327             robs.obs[sat][ot].ssi  = SPList[i].spdvector[j].ssi[k];
328          }
329       }
330       if(found) robs.numSvs++;
331    }
332 
333    return 1;
334 }
335 
336 }  // end namespace
337 
338 // -------------------------------------------------------------------------------
339 // -------------------------------------------------------------------------------
340