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 AntexData.hpp 40 /// Encapsulate data from ANTEX (Antenna Exchange) format files, including both 41 /// receiver and satellite antennas, ANTEX file I/O, discrimination between different 42 /// satellite antennas based on system, PRN and time, and computation of phase center 43 /// offsets and variations. 44 45 #ifndef ANTEX_DATA_HPP 46 #define ANTEX_DATA_HPP 47 48 #include <string> 49 #include <vector> 50 #include <map> 51 52 #include "AntexBase.hpp" 53 #include "FFStream.hpp" 54 #include "CommonTime.hpp" 55 #include "Triple.hpp" 56 #include "CivilTime.hpp" 57 58 namespace gpstk 59 { 60 /// @ingroup Antex 61 //@{ 62 63 /// Antex antenna data record: PCOs and PCVs for one antenna. 64 /// Do not attempt to use an object that is not valid (cf. isValid()). 65 /// 66 /// NB. Optional data should be accessed only if the corresponding 'valid' 67 /// string is true; e.g. if(valid & validFromValid) then validFrom may be used. 68 /// 69 /// NB. In calls to the 'get' routines, 70 /// freq = string("G01"); 71 /// double total_PCO = getTotalPhaseCenterOffset(freq, az, el_nad); 72 /// Triple PCO = getPhaseCenterOffset(freq); 73 /// double PCV = getPhaseCenterVariation(freq, az, el_nad); 74 /// receivers and satellites (transmitters) are treated differently, in that 75 /// receivers call with elevation angle (from North-East plane toward Up) while 76 /// satellites call with nadir angle (from Z axis - the bore-sight direction). 77 /// 78 /// NB. The return value of getPhaseCenterOffset is a vector (Triple) PCO, in 79 /// the appropriate coordinate system (NEU for Rx, XYZ or body for SV), that is 80 /// defined as the vector from the reference point (RP) to the actual phase 81 /// center (PC). The RP is the ARP (Antenna Reference Point) for receivers and 82 /// the COM (Center Of Mass) for satellites. 83 /// 84 /// NB. The PCV and total_PCO value returned by the other two routines has the 85 /// same sense as the PCO vector; that is the total offset is defined as 86 /// PCO vector - PCV * LOS 87 /// where LOS is a unit vector along the line of sight (defined by the azimuth 88 /// and elevation/nadir angle passed into the routines), all in the appropriate 89 /// coordinate system (receiver NEU or satellite body XYZ). 90 /// 91 /// NB. Thus when correcting a measured range for the Receiver's total phase 92 /// center offset one would subtract the total_PCO value (along the line of 93 /// sight) from the measured range, that is (scalar equation, millimeters): 94 /// Range(corr) = Range(meas) + total_PCO; // OR 95 /// --> --> 96 /// Range(corr) = Range(meas) + [PCO dot LOS - PCV]; 97 /// however when correcting the satellite (COM) position for the Satellite's 98 /// total phase center offset one would add the total vector offset 99 /// (PCO - PCV*LOS) to the satellite COM (vector) position (in a consistent 100 /// coordinate system, e.g. ECEF XYZ), that is (vector equation): 101 /// --> --> --> --> 102 /// SV(corr) = SV(COM) + [PCO - PCV * LOS] 103 /// 104 /// NB. the PCV data is stored in a map <zenith angle, value> and the 105 /// getPhaseCenterVariation() routine simply interpolates this map WITHOUT 106 /// changing the sign of the value - it is the same as that in the ANTEX file. 107 /// 108 /// @sa gpstk::AntexStream and gpstk::AntexHeader. 109 class AntexData : public AntexBase 110 { 111 public: 112 /// @name AntexDataFormatStrings 113 /// ANTEX Data Formatting Strings 114 //@{ 115 static const std::string startAntennaString; ///< "START OF ANTENNA" 116 static const std::string typeSerNumString; ///< "TYPE / SERIAL NO" 117 static const std::string methodString; ///< "METH / BY / # / DATE" 118 static const std::string daziString; ///< "DAZI" 119 static const std::string zenithString; ///< "ZEN1 / ZEN2 / DZEN" 120 static const std::string numFreqString; ///< "# OF FREQUENCIES" 121 static const std::string validFromString; ///< "VALID FROM" 122 static const std::string validUntilString; ///< "VALID UNTIL" 123 static const std::string sinexCodeString; ///< "SINEX CODE" 124 static const std::string dataCommentString; ///< "COMMENT" 125 static const std::string startFreqString; ///< "START OF FREQUENCY" 126 static const std::string neuFreqString; ///< "NORTH / EAST / UP" 127 static const std::string endOfFreqString; ///< "END OF FREQUENCY" 128 static const std::string startFreqRMSString; ///< "START OF FREQ RMS" 129 static const std::string neuFreqRMSString; ///< "NORTH / EAST / UP" 130 static const std::string endOfFreqRMSString; ///< "END OF FREQ RMS" 131 static const std::string endOfAntennaString; ///< "END OF ANTENNA" 132 //@} 133 134 /// Validity bits for the ANTEX Data 135 /// NB. if version is updated, add allValid<ver> and update isValid() 136 enum validBits 137 { 138 startAntennaValid = 0x00001, ///< "START OF ANTENNA" Required 139 typeSerNumValid = 0x00002, ///< "TYPE / SERIAL NO" Required 140 methodValid = 0x00004, ///< "METH / BY / # / DATE" Required 141 daziValid = 0x00008, ///< "DAZI" Required 142 zenithValid = 0x00010, ///< "ZEN1 / ZEN2 / DZEN" Required 143 numFreqValid = 0x00020, ///< "# OF FREQUENCIES" Required 144 validFromValid = 0x00040, ///< "VALID FROM" 145 validUntilValid = 0x00080, ///< "VALID UNTIL" 146 sinexCodeValid = 0x00100, ///< "SINEX CODE" 147 dataCommentValid = 0x00200, ///< "COMMENT" 148 startFreqValid = 0x00400, ///< "START OF FREQUENCY" Required 149 neuFreqValid = 0x00800, ///< "NORTH / EAST / UP" Required 150 endOfFreqValid = 0x01000, ///< "END OF FREQUENCY" Required 151 startFreqRMSValid = 0x02000, ///< "START OF FREQ RMS" 152 neuFreqRMSValid = 0x04000, ///< "NORTH / EAST / UP" 153 endOfFreqRMSValid = 0x08000, ///< "END OF FREQ RMS" 154 endOfAntennaValid = 0x10000, ///< "END OF ANTENNA" Required 155 allValid13 = 0x11C3F ///< mask for all required valid fields 156 }; 157 158 /// Values of 'type' that are satellites 159 /// NB. keep this updated from the IGS file 'rcvr_ant.tab' 160 static const std::vector<std::string> SatelliteTypes; 161 162 /// map from zenith angle (degrees) to PC offset (millimeters) 163 typedef std::map<double, double> zenOffsetMap; 164 165 /// map from azimuth angle (deg) to zenOffsetMap 166 /// the zenOffsetMap WITHOUT azimuth dependence (NOAZI) will be 167 /// azimZenMap[-1.0] (this may be the only entry) 168 typedef std::map<double, zenOffsetMap> azimZenMap; 169 170 /// class encapsulating the PCOs and PCVs of the antenna. See the ANTEX 171 /// documentation for discussion of how the PCO/Vs are defined, sign conventions 172 /// and how to apply the PCOs. 173 class antennaPCOandPCVData { 174 public: 175 /// nominal phase center offsets in mm, and RMS values, 176 /// in NEU coordinates (for Receiver antennas) 177 /// or XYZ (for Satellite antennas); from "NORTH / EAST / UP" record 178 /// RMS values are OPTIONAL 179 double PCOvalue[3],PCOrms[3]; 180 181 /// if false, there is no azimuth dependence in the PCVs 182 /// and only PCV[0.0] is defined. 183 bool hasAzimuth; 184 185 /// map from azimuth to <zenith,offset> map: 186 /// PCVvalues[azim][zen] = offset in mm from the nominal 187 /// PCVrms[azim][zen] = RMS of these values, also in mm. 188 /// if there is no azimuth dependence, there will be 189 /// only one entry in this map, with azimuth = -1.0 190 /// RMS values are OPTIONAL 191 azimZenMap PCVvalue, PCVrms; 192 193 }; // end of class antennaPCOandPCVData 194 195 // member data 196 /// Bits of valid are set when corresponding labels are found and data defined 197 unsigned long valid; 198 199 /// if true, PCOs are absolute, else they are relative to another antenna 200 bool absolute; 201 202 /// if true, this is a receiver antenna, otherwise its a satellite; 203 /// this flag is set based on the IGS codes kept in array SatelliteTypes. 204 /// NB. this flag need not be used, if you know which antenna you have; 205 /// however if used, the array SatelliteTypes must be kept updated. 206 bool isRxAntenna; 207 208 /// PRN and SVN numbers; used only in the case of satellite antennas, and 209 /// may not be present, in which case these are both -1. 210 /// NB. PRNs apply to GLONASS as well as GPS 211 int PRN, SVN; 212 213 /// system character: G or blank GPS, R GLONASS, E GALILEO, etc 214 /// used only in the case of satellite antennas 215 char systemChar; 216 217 /// number of frequencies stored, equal to number of keys in map 218 /// from "# OF FREQUENCIES" record 219 unsigned int nFreq; 220 221 /// delta azimuth (degrees) stored in azimZenMap 222 /// equal to 0 if there is no azimuth dependence 223 /// from "DAZI" record 224 double azimDelta; 225 226 /// minimum, maximum and delta zenith (degrees) stored in zenOffsetMap 227 /// from "ZEN1 / ZEN2 / DZEN" record 228 double zenRange[3]; 229 230 /// time limits of validity (OPTIONAL); otherwise set to BEGINNING and END 231 /// from "VALID FROM" and "VALID UNTIL" records 232 /// keep the string version for file I/O b/c sometimes the time is of the form 233 /// 1994 4 17 23 59 59.9999999 VALID UNTIL 234 /// and converting this to CommonTime replaces it with ... 24 0 0.000 235 CommonTime validFrom,validUntil; 236 std::string stringValidFrom, stringValidUntil; 237 238 /// map from frequency to antennaPCOandPCVData 239 std::map<std::string, antennaPCOandPCVData> freqPCVmap; 240 241 std::string type; ///< antenna type from "TYPE / SERIAL NO" 242 std::string serialNo; ///< antenna serial number from "TYPE / SERIAL NO" 243 std::string satCode; ///< satellite code from "TYPE / SERIAL NO" 244 std::string cospar; ///< satellite COSPAR ID from "TYPE / SERIAL NO" 245 std::string method; ///< calibration method from "METH / BY / # / DATE" 246 std::string agency; ///< agency from "METH / BY / # / DATE" 247 int noAntCalibrated; ///< num. of ant. calibrated from "METH / BY / # / DATE" 248 std::string date; ///< date from "METH / BY / # / DATE" 249 std::string sinexCode;///< name of ant. cal. model from "SINEX CODE" OPTIONAL 250 251 /// comments found in the data portion of the file 252 std::vector<std::string> commentList; ///< Comments in data (OPTIONAL) 253 254 //------------------------------------------------------------------------------ 255 // member functions 256 257 /// Constructor. AntexData()258 AntexData() : valid(0), absolute(true), PRN(0), SVN(0), nFreq(0), 259 validFrom(CommonTime::BEGINNING_OF_TIME), 260 validUntil(CommonTime::END_OF_TIME) {} 261 /// Destructor ~AntexData()262 virtual ~AntexData() {} 263 264 /// AntexData is a "data", so this function always returns true. isData() const265 virtual bool isData() const {return true;} 266 267 /// Convenience function returns true only if a valid object isValid(void) const268 bool isValid(void) const { return ((valid & allValid13) == allValid13); } 269 270 /// @return true if the antenna object is valid at the given time. 271 /// Base on the 'validFrom' and 'validUntil' fields. 272 /// @return true if the input time is either BEGINNING_ or END_OF_TIME 273 /// @return true if the 'valid' time limits are not given. 274 /// NB. useful when adding satellite antennas for processing with a dataset; 275 /// pass any time tag from the dataset. 276 bool isValid(CommonTime& time) const throw(); 277 278 /// Generate a name from type and serial number 279 std::string name(void) const throw(); 280 281 /// Compute the total phase center offset at the given azimuth and elev_nadir, 282 /// including both nominal offset (PCO) and variation (PCV). 283 /// NB. see documentation of the class for coordinates, signs and application. 284 /// @param freq frequency e.g. G01 285 /// @param azimuth the azimuth angle in degrees, from N going toward E for 286 /// receivers, or from X going toward Y for satellites 287 /// @param elev_nadir elevation in deg from horizontal (North-East) plane for 288 // receivers, or nadir angle in degrees from Z axis for satellites 289 /// @return total phase center offset in millimeters 290 /// @throw Exception if this object is invalid 291 /// if frequency does not exist for this data 292 /// if azimuth is out of range; azimuth is replaced with azim mod 360 293 double getTotalPhaseCenterOffset(const std::string freq, 294 const double azimuth, 295 const double elevation) const; 296 297 /// Get the PC offset values in mm (only, NOT the phase center variations, which 298 /// should be computed using getPhaseCenterVariations() and added to the PCOs 299 /// to get the total phase center offset). 300 /// NB. see documentation of the class for coordinates, signs and application. 301 /// @param freq frequency (usually G01 or G02) 302 /// @return Triple containing offsets in millimeters, in appropriate coordinate 303 /// system (satellite-based XYZ or receiver-based NEU). 304 /// @throw Exception if this object is invalid 305 /// if frequency does not exist for this data 306 Triple getPhaseCenterOffset(const std::string freq) const; 307 308 /// Compute the phase center variation at the given azimuth and elev_nadir 309 /// NB. see documentation of the class for coordinates, signs and application. 310 /// @param freq frequency (usually G01 or G02) 311 /// @param azimuth the azimuth angle in degrees, from N going toward E for 312 /// receivers, or from X going toward Y for satellites 313 /// @param elev_nadir elevation in deg from horizontal (North-East) plane for 314 // receivers, or nadir angle in degrees from Z axis for satellites 315 /// @return phase center offset in millimeters 316 /// @throw Exception if this object is invalid 317 /// if frequency does not exist for this data 318 /// if azimuth is out of range, azimuth is replaced with azim % 360 319 double getPhaseCenterVariation(const std::string freq, 320 const double azimuth, 321 const double elev_nadir) const; 322 323 /// Dump AntexData. Set detail = 0 for type, serial no., sat codes only; 324 /// = 1 for all information except phase center offsets, = 2 for all data. 325 #pragma clang diagnostic push 326 #pragma clang diagnostic ignored "-Woverloaded-virtual" 327 virtual void dump(std::ostream& s, int detail=0) const; 328 #pragma clang diagnostic pop 329 protected: 330 /// Find zenith angles bracketing the input zenith angle within the given map, 331 /// and the corresponding PCOs. 332 void evaluateZenithMap(const double& zen, 333 const zenOffsetMap& eomap, 334 double& zen_lo, double& zen_hi, 335 double& pco_lo, double& pco_hi) const throw(); 336 337 /** Writes a correctly formatted record from this data to stream \a s. 338 * @throw std::exception 339 * @throw FFStreamError 340 * @throw StringUtils::StringException 341 */ 342 virtual void reallyPutRecord(FFStream& s) const; 343 344 /// This functions obtains Antex antenna record from the given FFStream. 345 /// If there is an error in reading from the stream, it is reset 346 /// to its original position and its fail-bit is set. 347 /// @throw std::exception 348 /// @throw StringException when a StringUtils function fails 349 /// @throw FFStreamError when exceptions(failbit) is set and 350 /// a read or formatting error occurs. This also resets the 351 /// stream to its pre-read position. 352 virtual void reallyGetRecord(FFStream& s); 353 354 private: 355 /// helper routine to throw when records are out of order 356 /// throws if valid contains test (test & valid), otherwise does nothing 357 void throwRecordOutOfOrder(unsigned long test, std::string& label); 358 359 /** parse a line from the Antex file, filling the data object 360 * @throw FFStreamError 361 */ 362 void ParseDataRecord(std::string& line); 363 364 /// Writes the CommonTime object into Antex ('VALID FROM') format. 365 /// If it's a bad time, it will return blanks. 366 /// @throw StringUtils::StringException 367 std::string writeTime(const CommonTime& dt) const; 368 369 /// This function constructs a CommonTime object from the line for VALID FROM 370 /// and VALID UNTIL records; default is to return BEGINNING_OF_TIME 371 /// @param line the encoded time string found in the Antex record. 372 /// @throw FFStreamError 373 CommonTime parseTime(const std::string& line) const; 374 375 }; // class AntexData 376 377 //@} 378 379 } // namespace 380 381 #endif 382