int main(int argc, char* argv[]) { try { // if no options are given on command line, print syntax and quit if (argc < 2 || string(argv[1]) == "-h" || string(argv[1]) == "--help") { cout << "Program CalcDOPs reads an FIC, FICA or a Rinex Nav file" << endl << "Usage: CalcDOPs -i <inputfile> input file for day to be calculated (required)" << endl << " -p <inputfile> input file for previous day (optional, ephemeris mode only)" << endl << " -o <outputfile> grid output file [DOPs.out]" << endl << " -sf <outputfile> stats output file [DOPs.stat]" << endl << " -tf <outputfile> time steps output file [DOPs.times]" << endl << " -l <outputfile> log output file [DOPs.log]" << endl << " -rs read from stats file" << endl << " -a work in almanac mode [ephemeris mode is default]" << endl << " -w <week> -s <sow> starting time tag" << endl << " -x <prn> exclude satellite PRN" << endl << " -t <dt> time spacing" << endl << " -na do North America only" << endl << " -d dump grid results at each time step (time-intensive)" << endl << " -h, --help output options info and exit" << endl << " -v print version info and exit" << endl << endl; return 0; } int i, j, ii; // parse command line i = 1; while (i < argc) { if (string(argv[i]) == "-i" ) inputfile = string(argv[++i]); else if (string(argv[i]) == "-p" ) previnputfile = string(argv[++i]); else if (string(argv[i]) == "-o" ) outputfile = string(argv[++i]); else if (string(argv[i]) == "-l" ) logfile = string(argv[++i]); else if (string(argv[i]) == "-tf") timesfile = string(argv[++i]); else if (string(argv[i]) == "-a" ) ephmode = false; else if (string(argv[i]) == "-w" ) week = atoi(argv[++i]); else if (string(argv[i]) == "-s" ) sow = atof(argv[++i]); else if (string(argv[i]) == "-x" ) ExPRN.push_back(atoi(argv[++i])); else if (string(argv[i]) == "-t" ) dt = atof(argv[++i]); else if (string(argv[i]) == "-sf") statsfile = string(argv[++i]); else if (string(argv[i]) == "-rs") readStats = true; else if (string(argv[i]) == "-na") NAonly = true; else if (string(argv[i]) == "-d" ) dumpeach = true; else if (string(argv[i]) == "-v" ) { cout << "CalcDOPs version " << fixed << setprecision(1) << setw(3) << version << endl; return 0; } else cout << "Unrecognized option: " << argv[i] << endl; i++; } lofs.open(logfile.c_str(),ios_base::out); if (!lofs) return -8; tofs.open(timesfile.c_str(),ios_base::out); if (!tofs) return -8; // reassurance print lofs << "Program visible with:" << endl << "current-day input file " << inputfile << endl; if ( previnputfile != "" ) lofs << "and previous-day input file " << previnputfile << endl; lofs << "and output file " << outputfile << endl; if (week > 0) lofs << " Input time tag: " << week << " " << sow << endl; if (ExPRN.size() > 0) { lofs << " Exclude satellite PRNs"; for(i=0; i<ExPRN.size(); i++) lofs << " " << ExPRN[i]; lofs << "." << endl; } // compute the number of time steps from the time spacing nt = int(86400.0/dt); // 86400 = 60*60*24 = sec/day // open and read the previous day's input data file first, if specified and in Eph mode if ( previnputfile != "" && ephmode ) { lofs << "Reading in previous-day input file..." << endl; i = ReadDataFile(previnputfile); if (i) { if (i == -1) lofs << "Previous-day input file does not exist. Abort." << endl; if (i == -2) lofs << "Cannot identify previous-day file type. Abort." << endl; return i; } } // open and read the current day's input data file lofs << "Reading in current-day input file..." << endl; i = ReadDataFile(inputfile); if (i) { if (i == -1) lofs << "Current-day input file does not exist. Abort." << endl; if (i == -2) lofs << "Cannot identify current-day file type. Abort." << endl; return i; } // build the spatial grid, and store it in vector<GridData> Grid; BuildGrid(); // get a list of the available satellite PRNs and the initial timetag bool ok; DayTime tt, starttime; bool initialTimeSet = false; if ( ephmode ) // ephemeris mode { try { DayTime earliest = ges.getInitialTime(); DayTime latest = ges.getFinalTime(); // DayTime start = latest - gpstk::DayTime::SEC_DAY/2; /* make sure you're in the right day */ DayTime start = latest - 6*3600.0; /* go back 6 h: covers any 4 h ephemeris going into the next day */ tt = DayTime( start.year(), start.month(), start.day(), 0, 0, 0.0 ); starttime = tt; lofs << " Initial time tag is " << tt.printf("%4F %8.1g") << endl; initialTimeSet = true; } catch(InvalidRequest) { i = -100; lofs << "Initial Time or Final Time missing. Abort." << endl; return i; } for (i=1; i<33; i++) { for (ok=true,j=0; j<ExPRN.size(); j++) { if (ExPRN[j] == i) { ok=false; break; } } if (!ok) continue; // skip this satellite Sats.push_back(i); // save this satellite } } else // almanac mode (original version) { DayTime start(DayTime::BEGINNING_OF_TIME); // Declare and initialize to something guaranteed to be early. for (i=1; i<33; i++) // # of SVs hard-wired to 32 { if (aomap.find(i) == aomap.end()) continue; // satellite not found in almanac for (ok=true,j=0; j<ExPRN.size(); j++) { if (ExPRN[j] == i) { ok=false; break; } } if (!ok) continue; // skip this satellite if not ok Sats.push_back(i); // save this satellite otherwise // store latest transmit time tag of the set. if (aomap[i].getTransmitTime()>start) start = aomap[i].getTransmitTime(); } // Set starting time to beginning of day in which majority of almanac was collected. tt = DayTime( start.year(), start.month(), start.day(), 0, 0, 0.0 ); starttime = tt; lofs << " Initial time tag is " << tt.printf("%4F %8.1g") << endl; initialTimeSet = true; } if (Sats.size() < 4) { lofs << "Fewer than 4 satellite almanacs are available - abort." << endl; return -3; } // allocate Stats objects for each grid point's DOPs GGridStats = new Stats<double>[Grid.size()]; PGridStats = new Stats<double>[Grid.size()]; HGridStats = new Stats<double>[Grid.size()]; VGridStats = new Stats<double>[Grid.size()]; TGridStats = new Stats<double>[Grid.size()]; NGridStats = new Stats<double>[Grid.size()]; BadPDOP = (double*)calloc(Grid.size(),sizeof(double)); if (!GGridStats || !PGridStats || !HGridStats || !VGridStats || !TGridStats || !NGridStats ) { lofs << "Failed to allocate GridStats" << endl; return -4; } // initialize storage of 'worsts' and 'peaks' IworstN = IworstG = IworstP = IworstH = IworstV = IworstT = -1; // indexes of worst Number and worst DOPs NtrofN = NpeakG = NpeakP = NpeakH = NpeakV = NpeakT = 0; // number of cells with DOP > 10, # with < 5 sats // if reading a stats file (-rs), initialize stats using data from a file if (readStats) { i = ReadStatsFile(statsfile); if (i) { lofs << "Could not open stats file for input. Abort." << endl; return i; } } // compute away dlon = 360.0/double(MaxNLon); for (j=0; j<nt; j++) // LOOP OVER TIMES { SVs.clear(); // clear SV position array for (i=0; i<Sats.size(); i++) // LOOP OVER SVs -- get positions at each time step { if (ephmode) // ephemeris mode { SatID sid(Sats[i],SatID::systemGPS); try { if (ges.getSatHealth(sid,tt)!=0) continue; SVPVT = ges.getXvt(sid,tt); } catch(InvalidRequest& e) { continue; } SV.setECEF(SVPVT.x[0],SVPVT.x[1],SVPVT.x[2]); // get SV position SVs.push_back(SV); // add to the vector } else // almanac mode { SVPVT = aomap[Sats[i]].svXvt(tt); SV.setECEF(SVPVT.x[0],SVPVT.x[1],SVPVT.x[2]); // get SV position SVs.push_back(SV); // add to the vector } } // zero worst-site DOPs (worst #SVs to large #) for this time step StepWorstG = StepWorstP = StepWorstH = StepWorstV = StepWorstT = 0.; StepWorstN = 10000.; for (i=0; i<Grid.size(); i++) // LOOP OVER GRID POSITIONS { if ( j == 0 ) // set up grid position vector only on first time step { // transform XYZT to UENT: R*Vector(XYZT) = Vector(UENT) double ca,sa,co,so; Position Rx(Grid[i].lat,Grid[i].lon,0.0,Position::Geodetic); // grid position ca = cos(Rx.geodeticLatitude()*DEG_TO_RAD); sa = sin(Rx.geodeticLatitude()*DEG_TO_RAD); co = cos(Rx.longitude()*DEG_TO_RAD); so = sin(Rx.longitude()*DEG_TO_RAD); M4 Rtemp; Rtemp(0,0) = ca*co ; Rtemp(0,1) = ca*so ; Rtemp(0,2) = sa ; Rtemp(0,3) = 0.0; Rtemp(1,0) = -so ; Rtemp(1,1) = co ; Rtemp(1,2) = 0.0; Rtemp(1,3) = 0.0; Rtemp(2,0) = -sa*co; Rtemp(2,1) = -sa*so; Rtemp(2,2) = ca ; Rtemp(2,3) = 0.0; Rtemp(3,0) = 0.0 ; Rtemp(3,1) = 0.0 ; Rtemp(3,2) = 0.0; Rtemp(3,3) = 1.0; Rmat.push_back(Rtemp); // add this grid point's R matrix to the stack } ComputeDOPs(tt,Grid[i],SVs,Rmat[i]); // compute DOPs BadPDOP[i] = BadPDOP[i] + Grid[i].bdop; // adds up each grid pt.'s BDOP over all times // BDOP for a single pt. is 0 or 1 for PDOP <= v. > 6 // add to stats -- each GridStats object ends up holding all times for a grid point GGridStats[i].Add(Grid[i].gdop); PGridStats[i].Add(Grid[i].pdop); HGridStats[i].Add(Grid[i].hdop); VGridStats[i].Add(Grid[i].vdop); TGridStats[i].Add(Grid[i].tdop); NGridStats[i].Add(Grid[i].nsvs); // save the worst and the peaks if (Grid[i].gdop > StepWorstG) { StepWorstG = Grid[i].gdop; } if (Grid[i].pdop > StepWorstP) { StepWorstP = Grid[i].pdop; } if (Grid[i].hdop > StepWorstH) { StepWorstH = Grid[i].hdop; } if (Grid[i].vdop > StepWorstV) { StepWorstV = Grid[i].vdop; } if (Grid[i].tdop > StepWorstT) { StepWorstT = Grid[i].tdop; } if (Grid[i].nsvs < StepWorstN) { StepWorstN = Grid[i].nsvs; } if (IworstG == -1 || Grid[i].gdop > WorstG) { IworstG = i; WorstG = Grid[i].gdop; TworstG = tt; } if (IworstP == -1 || Grid[i].pdop > WorstP) { IworstP = i; WorstP = Grid[i].pdop; TworstP = tt; } if (IworstH == -1 || Grid[i].hdop > WorstH) { IworstH = i; WorstH = Grid[i].hdop; TworstH = tt; } if (IworstV == -1 || Grid[i].vdop > WorstV) { IworstV = i; WorstV = Grid[i].vdop; TworstV = tt; } if (IworstT == -1 || Grid[i].tdop > WorstT) { IworstT = i; WorstT = Grid[i].tdop; TworstT = tt; } if (IworstN == -1 || Grid[i].nsvs < WorstN) { IworstN = i; WorstN = Grid[i].nsvs; TworstN = tt; } if (Grid[i].nsvs < 5) NtrofN++; if (Grid[i].pdop > 10.) { NpeakP++; lofs << "PDS " << NpeakP << " " << setw(4) << j+1 // time << fixed << setprecision(2) << " " << setw(7) << Grid[i].lon << " " << setw(7) << Grid[i].lat << endl; } if (Grid[i].hdop > 10.) { NpeakH++; lofs << "HDS " << NpeakH << " " << setw(4) << j+1 // time << fixed << setprecision(2) << " " << setw(7) << Grid[i].lon << " " << setw(7) << Grid[i].lat << endl; } } // end loop over grid // write timestep results to timesfile tofs << " " << tt.printf("%4F %8.1g") << " " << " " << setw(7) << StepWorstG << " " << setw(7) << StepWorstP << " " << setw(7) << StepWorstH << " " << setw(7) << StepWorstV << " " << setw(7) << StepWorstT << " " << setw(6) << StepWorstN << endl; // dump grid results to file for each time step if enabled if (dumpeach) { stringstream ss; ss << j; dumpfile = outputfile + ".t-" + ss.str(); cout << dumpfile << endl; ii = DumpGrid(tt, dumpfile); if (ii) { lofs << "Could not dump grid file for writing. Abort." << endl; return i; } } // record worst-site DOPs at each time step WGTimeStats.push_back(StepWorstG); WPTimeStats.push_back(StepWorstP); WHTimeStats.push_back(StepWorstH); WVTimeStats.push_back(StepWorstV); WTTimeStats.push_back(StepWorstT); WNTimeStats.push_back(StepWorstN); tt += dt; // increment time tag } // end loop over times // get day's average of worst-site (grid) DOPs for (i=0; i<nt; i++) { AvgWorstSiteDOP.wgdop += WGTimeStats[i]; AvgWorstSiteDOP.wpdop += WPTimeStats[i]; AvgWorstSiteDOP.whdop += WHTimeStats[i]; AvgWorstSiteDOP.wvdop += WVTimeStats[i]; AvgWorstSiteDOP.wtdop += WTTimeStats[i]; AvgWorstSiteDOP.wnsvs += WNTimeStats[i]; } AvgWorstSiteDOP.wgdop /= nt; AvgWorstSiteDOP.wpdop /= nt; AvgWorstSiteDOP.whdop /= nt; AvgWorstSiteDOP.wvdop /= nt; AvgWorstSiteDOP.wtdop /= nt; AvgWorstSiteDOP.wnsvs /= nt; // output the grid itself and the stats - for use later i = OutputGrid(outputfile); // output average and worst-site DOP results over the grid if (i) { lofs << "Could not output file for writing. Abort." << endl; return i; } i = WriteStatsFile(statsfile); if (i) { lofs << "Could not open stats file for output. Abort." << endl; return i; } // clean up delete[] GGridStats; delete[] PGridStats; delete[] HGridStats; delete[] VGridStats; delete[] TGridStats; delete[] NGridStats; lofs.close(); } catch(Exception& e) { lofs << "Caught an exception" << endl << e << endl; } return 0; }