// Get the SourceID of the rinex observation file SourceID NetworkObsStreams::sourceIDOfRinexObsFile(std::string obsFile) { try { RinexObsStream rin; rin.exceptions(std::ios::failbit); rin.open(obsFile, std::ios::in); gnssRinex gRin; rin >> gRin; rin.close(); return gRin.header.source; } catch(...) { // Problem opening the file // Maybe it doesn't exist or you don't have proper read permissions Exception e("Problem opening the file " + obsFile + "Maybe it doesn't exist or you don't have proper read permissions"); GPSTK_THROW(e); } } // End of method 'NetworkObsStreams::sourceIDOfRinexObsFile'
//------------------------------------------------------------------------------------ int OpenFiles(void) throw(Exception) { try { string filename; if(InputDirectory.empty()) filename = NovatelFile; else filename = InputDirectory + string("/") + NovatelFile; instr.open(filename.c_str(),ios::in | ios::binary); if(!instr.is_open()) { cerr << "Failed to open input file " << NovatelFile << endl; return -1; } if(verbose) cout << "Opened input file " << NovatelFile << endl; instr.exceptions(fstream::failbit); TempFileName = GetTempFileName(); rostr.open(TempFileName.c_str(),ios::out); if(!rostr.is_open()) { cerr << "Failed to open temporary output file " << TempFileName << endl; return -2; } rostr.exceptions(fstream::failbit); rnstr.open(RinexNavFile.c_str(),ios::out); if(!rnstr.is_open()) { cerr << "Failed to open output nav file " << RinexNavFile << endl; return -3; } if(verbose) cout << "Opened output nav file " << RinexNavFile << endl; rnstr.exceptions(fstream::failbit); return 0; } catch(Exception& e) { GPSTK_RETHROW(e); } catch(exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); } catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); } }
// Method that will really process information void example9::process() { // We will read each section name, which is equivalent to station name // Station names will be read in alphabetical order string station; while ( (station = confReader.getEachSection()) != "" ) { // We will skip 'DEFAULT' section because we are waiting for // a specific section for each receiver. However, if data is // missing we will look for it in 'DEFAULT' (see how we use method // 'setFallback2Default()' of 'ConfDataReader' object in 'spinUp()' if( station == "DEFAULT" ) { continue; } // Show a message indicating that we are starting with this station cout << "Starting processing for station: '" << station << "'." << endl; // Create input observation file stream RinexObsStream rin; // Enable exceptions rin.exceptions(ios::failbit); // Try to open Rinex observations file try { // Open Rinex observations file in read-only mode rin.open( confReader("rinexObsFile", station), std::ios::in ); } catch(...) { cerr << "Problem opening file '" << confReader.getValue("rinexObsFile", station) << "'." << endl; cerr << "Maybe it doesn't exist or you don't have " << "proper read permissions." << endl; cerr << "Skipping receiver '" << station << "'." << endl; // Close current Rinex observation stream rin.close(); continue; } // End of 'try-catch' block // Declare a "SP3EphemerisStore" object to handle precise ephemeris SP3EphemerisStore SP3EphList; // Set flags to reject satellites with bad or absent positional // values or clocks SP3EphList.rejectBadPositions(true); SP3EphList.rejectBadClocks(true); // Read if we should check for data gaps. if ( confReader.getValueAsBoolean( "checkGaps", station ) ) { SP3EphList.enableDataGapCheck(); SP3EphList.setGapInterval( confReader.getValueAsDouble("SP3GapInterval",station) ); } // Read if we should check for too wide interpolation intervals if ( confReader.getValueAsBoolean( "checkInterval", station ) ) { SP3EphList.enableIntervalCheck(); SP3EphList.setMaxInterval( confReader.getValueAsDouble("maxSP3Interval",station) ); } // Load all the SP3 ephemerides files from variable list string sp3File; while ( (sp3File = confReader.fetchListValue("SP3List",station) ) != "" ) { // Try to load each ephemeris file try { SP3EphList.loadFile( sp3File ); } catch (FileMissingException& e) { // If file doesn't exist, issue a warning cerr << "SP3 file '" << sp3File << "' doesn't exist or you don't " << "have permission to read it. Skipping it." << endl; continue; } } // End of 'while ( (sp3File = confReader.fetchListValue( ... " // Load station nominal position double xn(confReader.fetchListValueAsDouble("nominalPosition",station)); double yn(confReader.fetchListValueAsDouble("nominalPosition",station)); double zn(confReader.fetchListValueAsDouble("nominalPosition",station)); // The former peculiar code is possible because each time we // call a 'fetchListValue' method, it takes out the first element // and deletes it from the given variable list. Position nominalPos( xn, yn, zn ); // Create a 'ProcessingList' object where we'll store // the processing objects in order ProcessingList pList; // This object will check that all required observables are present RequireObservables requireObs; requireObs.addRequiredType(TypeID::P2); requireObs.addRequiredType(TypeID::L1); requireObs.addRequiredType(TypeID::L2); // This object will check that code observations are within // reasonable limits SimpleFilter pObsFilter; pObsFilter.setFilteredType(TypeID::P2); // Read if we should use C1 instead of P1 bool usingC1( confReader.getValueAsBoolean( "useC1", station ) ); if ( usingC1 ) { requireObs.addRequiredType(TypeID::C1); pObsFilter.addFilteredType(TypeID::C1); } else { requireObs.addRequiredType(TypeID::P1); pObsFilter.addFilteredType(TypeID::P1); } // Add 'requireObs' to processing list (it is the first) pList.push_back(requireObs); // IMPORTANT NOTE: // It turns out that some receivers don't correct their clocks // from drift. // When this happens, their code observations may drift well beyond // what it is usually expected from a pseudorange. In turn, this // effect causes that "SimpleFilter" objects start to reject a lot of // satellites. // Thence, the "filterCode" option allows you to deactivate the // "SimpleFilter" object that filters out C1, P1 and P2, in case you // need to. bool filterCode( confReader.getValueAsBoolean( "filterCode", station ) ); // Check if we are going to use this "SimpleFilter" object or not if( filterCode ) { pList.push_back(pObsFilter); // Add to processing list } // This object defines several handy linear combinations LinearCombinations comb; // Object to compute linear combinations for cycle slip detection ComputeLinear linear1; // Read if we should use C1 instead of P1 if ( usingC1 ) { linear1.addLinear(comb.pdeltaCombWithC1); linear1.addLinear(comb.mwubbenaCombWithC1); } else { linear1.addLinear(comb.pdeltaCombination); linear1.addLinear(comb.mwubbenaCombination); } linear1.addLinear(comb.ldeltaCombination); linear1.addLinear(comb.liCombination); pList.push_back(linear1); // Add to processing list // Objects to mark cycle slips LICSDetector2 markCSLI2; // Checks LI cycle slips pList.push_back(markCSLI2); // Add to processing list MWCSDetector markCSMW; // Checks Merbourne-Wubbena cycle slips pList.push_back(markCSMW); // Add to processing list // Object to keep track of satellite arcs SatArcMarker markArc; markArc.setDeleteUnstableSats(true); markArc.setUnstablePeriod(151.0); pList.push_back(markArc); // Add to processing list // Object to decimate data Decimate decimateData( confReader.getValueAsDouble( "decimationInterval", station ), confReader.getValueAsDouble( "decimationTolerance", station ), SP3EphList.getInitialTime() ); pList.push_back(decimateData); // Add to processing list // Declare a basic modeler BasicModel basic(nominalPos, SP3EphList); // Set the minimum elevation basic.setMinElev(confReader.getValueAsDouble("cutOffElevation",station)); // If we are going to use P1 instead of C1, we must reconfigure 'basic' if ( !usingC1 ) { basic.setDefaultObservable(TypeID::P1); } // Add to processing list pList.push_back(basic); // Object to remove eclipsed satellites EclipsedSatFilter eclipsedSV; pList.push_back(eclipsedSV); // Add to processing list // Object to compute gravitational delay effects GravitationalDelay grDelay(nominalPos); pList.push_back(grDelay); // Add to processing list // Vector from monument to antenna ARP [UEN], in meters double uARP(confReader.fetchListValueAsDouble( "offsetARP", station ) ); double eARP(confReader.fetchListValueAsDouble( "offsetARP", station ) ); double nARP(confReader.fetchListValueAsDouble( "offsetARP", station ) ); Triple offsetARP( uARP, eARP, nARP ); // Declare some antenna-related variables Triple offsetL1( 0.0, 0.0, 0.0 ), offsetL2( 0.0, 0.0, 0.0 ); AntexReader antexReader; Antenna receiverAntenna; // Check if we want to use Antex information bool useantex( confReader.getValueAsBoolean( "useAntex", station ) ); if( useantex ) { // Feed Antex reader object with Antex file antexReader.open( confReader.getValue( "antexFile", station ) ); // Get receiver antenna parameters receiverAntenna = antexReader.getAntenna( confReader.getValue( "antennaModel", station ) ); } // Object to compute satellite antenna phase center effect ComputeSatPCenter svPcenter(nominalPos); if( useantex ) { // Feed 'ComputeSatPCenter' object with 'AntexReader' object svPcenter.setAntexReader( antexReader ); } pList.push_back(svPcenter); // Add to processing list // Declare an object to correct observables to monument CorrectObservables corr(SP3EphList); corr.setNominalPosition(nominalPos); corr.setMonument( offsetARP ); // Check if we want to use Antex patterns bool usepatterns(confReader.getValueAsBoolean("usePCPatterns", station )); if( useantex && usepatterns ) { corr.setAntenna( receiverAntenna ); // Should we use elevation/azimuth patterns or just elevation? corr.setUseAzimuth(confReader.getValueAsBoolean("useAzim", station)); } else { // Fill vector from antenna ARP to L1 phase center [UEN], in meters offsetL1[0] = confReader.fetchListValueAsDouble("offsetL1", station); offsetL1[1] = confReader.fetchListValueAsDouble("offsetL1", station); offsetL1[2] = confReader.fetchListValueAsDouble("offsetL1", station); // Vector from antenna ARP to L2 phase center [UEN], in meters offsetL2[0] = confReader.fetchListValueAsDouble("offsetL2", station); offsetL2[1] = confReader.fetchListValueAsDouble("offsetL2", station); offsetL2[2] = confReader.fetchListValueAsDouble("offsetL2", station); corr.setL1pc( offsetL1 ); corr.setL2pc( offsetL2 ); } pList.push_back(corr); // Add to processing list // Object to compute wind-up effect ComputeWindUp windup( SP3EphList, nominalPos, confReader.getValue( "satDataFile", station ) ); pList.push_back(windup); // Add to processing list // Declare a NeillTropModel object, setting its parameters NeillTropModel neillTM( nominalPos.getAltitude(), nominalPos.getGeodeticLatitude(), confReader.getValueAsInt("dayOfYear", station) ); // We will need this value later for printing double drytropo( neillTM.dry_zenith_delay() ); // Object to compute the tropospheric data ComputeTropModel computeTropo(neillTM); pList.push_back(computeTropo); // Add to processing list // Object to compute ionosphere-free combinations to be used // as observables in the PPP processing ComputeLinear linear2; // Read if we should use C1 instead of P1 if ( usingC1 ) { // WARNING: When using C1 instead of P1 to compute PC combination, // be aware that instrumental errors will NOT cancel, // introducing a bias that must be taken into account by // other means. This won't be taken into account in this // example. linear2.addLinear(comb.pcCombWithC1); } else { linear2.addLinear(comb.pcCombination); } linear2.addLinear(comb.lcCombination); pList.push_back(linear2); // Add to processing list // Declare a simple filter object to screen PC SimpleFilter pcFilter; pcFilter.setFilteredType(TypeID::PC); // IMPORTANT NOTE: // Like in the "filterCode" case, the "filterPC" option allows you to // deactivate the "SimpleFilter" object that filters out PC, in case // you need to. bool filterPC( confReader.getValueAsBoolean( "filterPC", station ) ); // Check if we are going to use this "SimpleFilter" object or not if( filterPC ) { pList.push_back(pcFilter); // Add to processing list } // Object to align phase with code measurements PhaseCodeAlignment phaseAlign; pList.push_back(phaseAlign); // Add to processing list // Object to compute prefit-residuals ComputeLinear linear3(comb.pcPrefit); linear3.addLinear(comb.lcPrefit); pList.push_back(linear3); // Add to processing list // Declare a base-changing object: From ECEF to North-East-Up (NEU) XYZ2NEU baseChange(nominalPos); // We always need both ECEF and NEU data for 'ComputeDOP', so add this pList.push_back(baseChange); // Object to compute DOP values ComputeDOP cDOP; pList.push_back(cDOP); // Add to processing list // Get if we want results in ECEF or NEU reference system bool isNEU( confReader.getValueAsBoolean( "USENEU", station ) ); // Declare solver objects SolverPPP pppSolver(isNEU); SolverPPPFB fbpppSolver(isNEU); // Get if we want 'forwards-backwards' or 'forwards' processing only int cycles( confReader.getValueAsInt("forwardBackwardCycles", station) ); // Get if we want to process coordinates as white noise bool isWN( confReader.getValueAsBoolean( "coordinatesAsWhiteNoise", station ) ); // White noise stochastic model WhiteNoiseModel wnM(100.0); // 100 m of sigma // Decide what type of solver we will use for this station if ( cycles > 0 ) { // In this case, we will use the 'forwards-backwards' solver // Check about coordinates as white noise if ( isWN ) { // Reconfigure solver fbpppSolver.setCoordinatesModel(&wnM); } // Add solver to processing list pList.push_back(fbpppSolver); } else { // In this case, we will use the 'forwards-only' solver // Check about coordinates as white noise if ( isWN ) { // Reconfigure solver pppSolver.setCoordinatesModel(&wnM); } // Add solver to processing list pList.push_back(pppSolver); } // End of 'if ( cycles > 0 )' // Object to compute tidal effects SolidTides solid; // Configure ocean loading model OceanLoading ocean; ocean.setFilename( confReader.getValue( "oceanLoadingFile", station ) ); // Numerical values (xp, yp) are pole displacements (arcsec). double xp( confReader.fetchListValueAsDouble( "poleDisplacements", station ) ); double yp( confReader.fetchListValueAsDouble( "poleDisplacements", station ) ); // Object to model pole tides PoleTides pole; pole.setXY( xp, yp ); // This is the GNSS data structure that will hold all the // GNSS-related information gnssRinex gRin; // Prepare for printing int precision( confReader.getValueAsInt( "precision", station ) ); // Let's open the output file string outName(confReader.getValue( "outputFile", station ) ); ofstream outfile; outfile.open( outName.c_str(), ios::out ); // Let's check if we are going to print the model bool printmodel( confReader.getValueAsBoolean( "printModel", station ) ); string modelName; ofstream modelfile; // Prepare for model printing if( printmodel ) { modelName = confReader.getValue( "modelFile", station ); modelfile.open( modelName.c_str(), ios::out ); } //// *** Now comes the REAL forwards processing part *** //// // Loop over all data epochs while(rin >> gRin) { // Store current epoch DayTime time(gRin.header.epoch); // Compute solid, oceanic and pole tides effects at this epoch Triple tides( solid.getSolidTide( time, nominalPos ) + ocean.getOceanLoading( station, time ) + pole.getPoleTide( time, nominalPos ) ); // Update observable correction object with tides information corr.setExtraBiases(tides); try { // Let's process data. Thanks to 'ProcessingList' this is // very simple and compact: Just one line of code!!!. gRin >> pList; } catch(DecimateEpoch& d) { // If we catch a DecimateEpoch exception, just continue. continue; } catch(Exception& e) { cerr << "Exception for receiver '" << station << "' at epoch: " << time << "; " << e << endl; continue; } catch(...) { cerr << "Unknown exception for receiver '" << station << " at epoch: " << time << endl; continue; } // Ask if we are going to print the model if ( printmodel ) { printModel( modelfile, gRin ); } // Check what type of solver we are using if ( cycles < 1 ) { // This is a 'forwards-only' filter. Let's print to output // file the results of this epoch printSolution( outfile, pppSolver, time, cDOP, isNEU, gRin.numSats(), drytropo, precision ); } // End of 'if ( cycles < 1 )' // The given epoch hass been processed. Let's get the next one } // End of 'while(rin >> gRin)' // Close current Rinex observation stream rin.close(); // If we printed the model, we must close the file if ( printmodel ) { // Close model file for this station modelfile.close(); } // Clear content of SP3 ephemerides object SP3EphList.clear(); //// *** Forwards processing part is over *** //// // Now decide what to do: If solver was a 'forwards-only' version, // then we are done and should continue with next station. if ( cycles < 1 ) { // Close output file for this station outfile.close(); // We are done with this station. Let's show a message cout << "Processing finished for station: '" << station << "'. Results in file: '" << outName << "'." << endl; // Go process next station continue; } //// *** If we got here, it is a 'forwards-backwards' solver *** //// // Now, let's do 'forwards-backwards' cycles try { fbpppSolver.ReProcess(cycles); } catch(Exception& e) { // If problems arose, issue an message and skip receiver cerr << "Exception at reprocessing phase: " << e << endl; cerr << "Skipping receiver '" << station << "'." << endl; // Close output file for this station outfile.close(); // Go process next station continue; } // End of 'try-catch' block // Reprocess is over. Let's finish with the last processing // Loop over all data epochs, again, and print results while( fbpppSolver.LastProcess(gRin) ) { DayTime time(gRin.header.epoch); printSolution( outfile, fbpppSolver, time, cDOP, isNEU, gRin.numSats(), drytropo, precision ); } // End of 'while( fbpppSolver.LastProcess(gRin) )' // We are done. Close and go for next station // Close output file for this station outfile.close(); // We are done with this station. Let's show a message cout << "Processing finished for station: '" << station << "'. Results in file: '" << outName << "'." << endl; } // end of 'while ( (station = confReader.getEachSection()) != "" )' return; } // End of 'example9::process()'
//------------------------------------------------------------------------------------ int AfterReadingFiles(int reading) throw(Exception) { try { int i,j,iret=0; double dt; if(reading == 1) { // compute data interval for this file for(j=0,i=1; i<9; i++) { if(PIC.ndt[i]>PIC.ndt[j]) j=i; } PIC.DT = PIC.estdt[j]; PIC.oflog << endl; PIC.oflog << "Estimated data interval is " << PIC.DT << " seconds.\n"; PIC.oflog << "Interpolate to " << PIC.irate << " times the input data rate\n"; PIC.oflog << "Last data epoch is " << PIC.LastEpoch.printf("%04Y/%02m/%02d %02H:%02M:%06.3f = %4F %.3g") << endl; if(TimePositionMap.size() == 0) { cout << "No position information was found in the input file! Abort.\n"; PIC.oflog << "No position information was found in the input file! Abort.\n"; return -1; } PIC.oflog << endl; // dump the map of positions if(PIC.DumpMap) { PIC.oflog << "Here is all the Time/Position information:\n"; map<DayTime,PosInfo>::const_iterator itr; itr = TimePositionMap.begin(); i = 0; while(itr != TimePositionMap.end()) { PIC.oflog << setw(4) << i << " " << itr->first.printf("%04Y/%02m/%02d %02H:%02M:%6.3f %4F %10.3g") << fixed << setprecision(3) << " " << setw(2) << itr->second.N << " " << setw(13) << itr->second.X << " " << setw(13) << itr->second.Y << " " << setw(13) << itr->second.Z << " " << setw(13) << itr->second.T << " " << setw(7) << itr->second.rms << endl; itr++; i++; } PIC.oflog << "End of the Time/Position information.\n\n"; } // open output file if(!PIC.OutRinexObs.empty()) { ofstr.open(PIC.OutRinexObs.c_str(), ios::out); if(ofstr.fail()) { PIC.oflog << "Failed to open output file " << PIC.OutRinexObs << ". Abort.\n"; return 1; } else PIC.oflog << "Opened output file " << PIC.OutRinexObs << endl; ofstr.exceptions(ios::failbit); } } else if(reading==2) { PIC.oflog << "Close the output file\n"; ofstr.close(); } return iret; } catch(Exception& e) { GPSTK_RETHROW(e); } catch(exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); } catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); } }
//------------------------------------------------------------------------------------ // open the file, read header and check for data; then loop over the epochs // Return 0 ok, <0 fatal error, >0 non-fatal error (ie skip this file) // 0 ok, 1 couldn't open file, 2 file doesn't have required data int ReadFile(int nfile, int reading) throw(Exception) { try { int i,iret; RinexObsData rodata; RinexObsStream ifstr; // open input file ifstr.open(PIC.InputObsName[nfile].c_str(),ios::in); if(ifstr.fail()) { PIC.oflog << "(" << reading << ") Failed to open input file " << PIC.InputObsName[nfile] << ". Abort.\n"; return 1; } else PIC.oflog << "(" << reading << ") Opened input file " << PIC.InputObsName[nfile] << endl; ifstr.exceptions(ios::failbit); // read header and (on 2nd reading) output iret = ProcessHeader(ifstr, nfile, reading); if(iret) return iret; // loop over epochs in the file if(reading == 2) LastInterpolated = DayTime::BEGINNING_OF_TIME; while(1) { try { ifstr >> rodata; } catch(Exception& e) { GPSTK_RETHROW(e); } catch(...) { Exception e("Unknown exception in ReadFile() from operator>>"); GPSTK_THROW(e); break; } if(ifstr.eof()) break; if(ifstr.bad()) { Exception e("Bad read in ReadFile() from operator>>"); GPSTK_THROW(e); } iret = ProcessOneEntireEpoch(rodata,reading); if(iret < -1) break; if(iret == -1) { iret=0; break; } // end of file if(iret == 1) continue; // ignore this epoch } ifstr.clear(); ifstr.close(); PIC.oflog << endl << "Finished reading (" << reading << ") file " << PIC.InputObsName[nfile] << endl; return iret; } catch(Exception& e) { GPSTK_RETHROW(e); } catch(exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); } catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); } }