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 PositionSatStore.cpp 40 // Store a tabular list of ephemeris data (position, option velocity & acceleration) 41 // for several satellites, and compute values at any timetag from this table. 42 // Inherits TabularSatStore. 43 44 #include "PositionSatStore.hpp" 45 #include "MiscMath.hpp" 46 #include <vector> 47 48 using namespace std; 49 50 namespace gpstk 51 { 52 /** @addtogroup ephemstore */ 53 //@{ 54 55 // Output stream operator is used by dump() in TabularSatStore operator <<(ostream & os,const PositionRecord & rec)56 ostream& operator<<(ostream& os, const PositionRecord& rec) throw() 57 { 58 os << "Pos" << fixed << setprecision(6) 59 << " " << setw(13) << rec.Pos[0] 60 << " " << setw(13) << rec.Pos[1] 61 << " " << setw(13) << rec.Pos[2] 62 << " sigP" << scientific << setprecision(2) 63 << " " << setw(9) << rec.sigPos[0] 64 << " " << setw(9) << rec.sigPos[1] 65 << " " << setw(9) << rec.sigPos[2] 66 << " Vel" << fixed << setprecision(6) 67 << " " << setw(13) << rec.Vel[0] 68 << " " << setw(13) << rec.Vel[1] 69 << " " << setw(13) << rec.Vel[2] 70 << " sigV" << scientific << setprecision(2) 71 << " " << setw(9) << rec.sigVel[0] 72 << " " << setw(9) << rec.sigVel[1] 73 << " " << setw(9) << rec.sigVel[2] 74 //<< " Acc" << fixed << setprecision(6) 75 //<< " " << setw(13) << rec.Acc[0] 76 //<< " " << setw(13) << rec.Acc[1] 77 //<< " " << setw(13) << rec.Acc[2] 78 //<< " sigA" << scientific << setprecision(2) 79 //<< " " << setw(9) << rec.sigAcc[0] 80 //<< " " << setw(9) << rec.sigAcc[1] 81 //<< " " << setw(9) << rec.sigAcc[2] 82 ; 83 return os; 84 } 85 86 // Return value for the given satellite at the given time (usually via 87 // interpolation of the data table). This interface from TabularSatStore. 88 // @param[in] sat the SatID of the satellite of interest 89 // @param[in] ttag the time (CommonTime) of interest 90 // @return object of type PositionRecord containing the data value(s). 91 // @throw InvalidRequest if data value cannot be computed, for example because 92 // a) the time t does not lie within the time limits of the data table 93 // b) checkDataGap is true and there is a data gap 94 // c) checkInterval is true and the interval is larger than maxInterval getValue(const SatID & sat,const CommonTime & ttag) const95 PositionRecord PositionSatStore::getValue(const SatID& sat, const CommonTime& ttag) 96 const 97 { 98 try { 99 bool isExact; 100 int i; 101 PositionRecord rec; 102 DataTableIterator it1, it2, kt; // cf. TabularSatStore.hpp 103 104 isExact = getTableInterval(sat, ttag, Nhalf, it1, it2, haveVelocity); 105 if(isExact && haveVelocity) { 106 rec = it1->second; 107 return rec; 108 } 109 110 // pull data out of the data table 111 size_t n,Nlow(Nhalf-1),Nhi(Nhalf),Nmatch(Nhalf); 112 CommonTime ttag0(it1->first); 113 vector<double> times,P[3],V[3],A[3],sigP[3],sigV[3],sigA[3]; 114 115 kt = it1; n=0; 116 while(1) { 117 // find index matching ttag 118 if(isExact && ABS(kt->first - ttag) < 1.e-8) 119 Nmatch = n; 120 times.push_back(kt->first - ttag0); // sec 121 for(i=0; i<3; i++) { 122 P[i].push_back(kt->second.Pos[i]); 123 V[i].push_back(kt->second.Vel[i]); 124 A[i].push_back(kt->second.Acc[i]); 125 sigP[i].push_back(kt->second.sigPos[i]); 126 sigV[i].push_back(kt->second.sigVel[i]); 127 sigA[i].push_back(kt->second.sigAcc[i]); 128 } 129 if(kt == it2) break; 130 ++kt; 131 ++n; 132 }; 133 134 if(isExact && Nmatch == (int)(Nhalf-1)) { Nlow++; Nhi++; } 135 136 // Lagrange interpolation 137 rec.sigAcc = rec.Acc = Triple(0,0,0); // default 138 double dt(ttag-ttag0), err; // dt in seconds 139 if(haveVelocity) { 140 for(i=0; i<3; i++) { 141 // interpolate the positions 142 rec.Pos[i] = LagrangeInterpolation(times,P[i],dt,err); 143 if(haveAcceleration) { 144 // interpolate velocities and acclerations 145 rec.Vel[i] = LagrangeInterpolation(times,V[i],dt,err); 146 rec.Acc[i] = LagrangeInterpolation(times,A[i],dt,err); 147 } 148 else { 149 // interpolate velocities(dm/s) to get V and A 150 LagrangeInterpolation(times,V[i],dt,rec.Vel[i],rec.Acc[i]); 151 rec.Acc[i] *= 0.1; // dm/s/s -> m/s/s 152 } 153 154 if(isExact) { 155 rec.sigPos[i] = sigP[i][Nmatch]; 156 rec.sigVel[i] = sigV[i][Nmatch]; 157 if(haveAcceleration) rec.sigAcc[i] = sigA[i][Nmatch]; 158 } 159 else { 160 // TD is this sigma related to 'err' in the Lagrange call? 161 rec.sigPos[i] = RSS(sigP[i][Nhi],sigP[i][Nlow]); 162 rec.sigVel[i] = RSS(sigV[i][Nhi],sigV[i][Nlow]); 163 if(haveAcceleration) 164 rec.sigAcc[i] = RSS(sigA[i][Nhi],sigA[i][Nlow]); 165 } 166 // else Acc=sig_Acc=0 // TD can we do better? 167 } 168 } 169 else { // no V data - must interpolate position to get velocity 170 for(i=0; i<3; i++) { 171 // interpolate positions(km) to get P and V 172 LagrangeInterpolation(times,P[i],dt,rec.Pos[i],rec.Vel[i]); 173 rec.Vel[i] *= 10000.; // km/sec -> dm/sec 174 175 if(isExact) { 176 rec.sigPos[i] = sigP[i][Nmatch]; 177 } 178 else { 179 rec.sigPos[i] = RSS(sigP[i][Nhi],sigP[i][Nlow]); 180 } 181 // TD 182 rec.sigVel[i] = 0.0; 183 } 184 } 185 return rec; 186 } 187 catch(InvalidRequest& e) { GPSTK_RETHROW(e); } 188 } 189 190 // Return the position for the given satellite at the given time 191 // @param[in] sat the SatID of the satellite of interest 192 // @param[in] ttag the time (CommonTime) of interest 193 // @return Triple containing the position ECEF XYZ meters 194 // @throw InvalidRequest if result cannot be computed, for example because 195 // a) the time t does not lie within the time limits of the data table 196 // b) checkDataGap is true and there is a data gap 197 // c) checkInterval is true and the interval is larger than maxInterval getPosition(const SatID & sat,const CommonTime & ttag) const198 Triple PositionSatStore::getPosition(const SatID& sat, const CommonTime& ttag) 199 const 200 { 201 try { 202 int i; 203 DataTableIterator it1, it2, kt; 204 205 if(getTableInterval(sat, ttag, Nhalf, it1, it2, true)) { 206 // exact match 207 for(unsigned int i=0; i<Nhalf; i++) ++it1; 208 PositionRecord rec(it1->second); 209 return rec.Pos; 210 } 211 212 // pull data out of the data table 213 vector<double> times,P[3]; 214 CommonTime ttag0(it1->first); 215 kt = it1; 216 while(1) { 217 times.push_back(kt->first - ttag0); // sec 218 for(i=0; i<3; i++) 219 P[i].push_back(kt->second.Pos[i]); 220 if(kt == it2) break; 221 ++kt; 222 }; 223 224 // interpolate 225 Triple pos; 226 double dt(ttag-ttag0), err; 227 for(i=0; i<3; i++) 228 pos[i] = LagrangeInterpolation(times,P[i],dt,err); 229 230 return pos; 231 } 232 catch(InvalidRequest& e) { GPSTK_RETHROW(e); } 233 } 234 235 // Return the velocity for the given satellite at the given time 236 // @param[in] sat the SatID of the satellite of interest 237 // @param[in] ttag the time (CommonTime) of interest 238 // @return Triple containing the velocity ECEF XYZ meters/second 239 // @throw InvalidRequest if result cannot be computed, for example because 240 // a) the time t does not lie within the time limits of the data table 241 // b) checkDataGap is true and there is a data gap 242 // c) checkInterval is true and the interval is larger than maxInterval getVelocity(const SatID & sat,const CommonTime & ttag) const243 Triple PositionSatStore::getVelocity(const SatID& sat, const CommonTime& ttag) 244 const 245 { 246 try { 247 int i; 248 DataTableIterator it1, it2, kt; 249 250 bool isExact(getTableInterval(sat, ttag, Nhalf, it1, it2, haveVelocity)); 251 if(isExact && haveVelocity) { 252 for(unsigned int i=0; i<Nhalf; i++) ++it1; 253 PositionRecord rec(it1->second); 254 return rec.Vel; 255 } 256 257 // pull data out of the data table 258 CommonTime ttag0(it1->first); 259 vector<double> times,D[3]; // D will be either Pos or Vel 260 261 kt = it1; 262 while(1) { 263 times.push_back(kt->first - ttag0); // sec 264 for(i=0; i<3; i++) 265 D[i].push_back(haveVelocity ? kt->second.Vel[i] : kt->second.Pos[i]); 266 if(kt == it2) break; 267 ++kt; 268 }; 269 270 // interpolate 271 Triple Vel; 272 double dt(ttag-ttag0), err; 273 for(i=0; i<3; i++) { 274 if(haveVelocity) 275 Vel[i] = LagrangeInterpolation(times,D[i],dt,err); 276 else { 277 // interpolate positions(km) to get velocity // err is dummy 278 LagrangeInterpolation(times,D[i],dt,err,Vel[i]); 279 Vel[i] *= 10000.; // km/s -> dm/s 280 } 281 } 282 283 return Vel; 284 } 285 catch(InvalidRequest& e) { GPSTK_RETHROW(e); } 286 } 287 288 // Return the acceleration for the given satellite at the given time 289 // @param[in] sat the SatID of the satellite of interest 290 // @param[in] ttag the time (CommonTime) of interest 291 // @return Triple containing the acceleration ECEF XYZ meters/second/second 292 // @throw InvalidRequest if result cannot be computed, for example because 293 // a) the time t does not lie within the time limits of the data table 294 // b) checkDataGap is true and there is a data gap 295 // c) checkInterval is true and the interval is larger than maxInterval 296 // d) neither velocity nor acceleration data are present getAcceleration(const SatID & sat,const CommonTime & ttag) const297 Triple PositionSatStore::getAcceleration(const SatID& sat, const CommonTime& ttag) 298 const 299 { 300 if(!haveVelocity && !haveAcceleration) { 301 InvalidRequest e("Neither velocity nor acceleration data are present"); 302 GPSTK_THROW(e); 303 } 304 305 try { 306 int i; 307 DataTableIterator it1, it2, kt; 308 309 bool isExact(getTableInterval(sat,ttag,Nhalf,it1,it2,haveAcceleration)); 310 if(isExact && haveAcceleration) { 311 // exact match, and have acceleration data 312 for(unsigned int i=0; i<Nhalf; i++) ++it1; 313 PositionRecord rec(it1->second); 314 return rec.Acc; 315 } 316 317 // pull data out of the data table 318 vector<double> times,D[3]; // D will be either Vel or Acc 319 CommonTime ttag0(it1->first); 320 kt = it1; 321 while(1) { 322 times.push_back(kt->first - ttag0); // sec 323 for(i=0; i<3; i++) 324 D[i].push_back(haveAcceleration ? kt->second.Acc[i]:kt->second.Vel[i]); 325 if(kt == it2) break; 326 ++kt; 327 }; 328 329 // interpolate 330 Triple Acc; 331 double dt(ttag-ttag0), err; 332 for(i=0; i<3; i++) { 333 if(haveAcceleration) { 334 Acc[i] = LagrangeInterpolation(times,D[i],dt,err); 335 } 336 else { 337 LagrangeInterpolation(times,D[i],dt,err,Acc[i]); // err is dummy 338 Acc[i] *= 0.1; // dm/s/s -> m/s/s 339 } 340 } 341 342 return Acc; 343 } 344 catch(InvalidRequest& e) { GPSTK_RETHROW(e); } 345 } 346 347 // Add a PositionRecord to the store. addPositionRecord(const SatID & sat,const CommonTime & ttag,const PositionRecord & rec)348 void PositionSatStore::addPositionRecord(const SatID& sat, const CommonTime& ttag, 349 const PositionRecord& rec) 350 { 351 try { 352 checkTimeSystem(ttag.getTimeSystem()); 353 354 int i; 355 if(!haveVelocity) 356 for(i=0; i<3; i++) 357 if(rec.Vel[i] != 0.0) { haveVelocity = true; break; } 358 if(!haveAcceleration) 359 for(i=0; i<3; i++) 360 if(rec.Acc[i] != 0.0) { haveAcceleration = true; break; } 361 362 if(tables.find(sat) != tables.end() && 363 tables[sat].find(ttag) != tables[sat].end()) { 364 // record already exists in table 365 PositionRecord& oldrec(tables[sat][ttag]); 366 oldrec.Pos = rec.Pos; 367 oldrec.sigPos = rec.sigPos; 368 if(haveVelocity) { oldrec.Vel = rec.Vel; oldrec.sigVel = rec.sigVel; } 369 if(haveAcceleration) { oldrec.Acc = rec.Acc; oldrec.sigAcc = rec.sigAcc; } 370 } 371 else { // create a new entry in the table 372 tables[sat][ttag] = rec; 373 } 374 } 375 catch(InvalidRequest& ir) { GPSTK_RETHROW(ir); } 376 } 377 378 // Add position data (only) to the store addPositionData(const SatID & sat,const CommonTime & ttag,const Triple & Pos,const Triple & Sig)379 void PositionSatStore::addPositionData(const SatID& sat, const CommonTime& ttag, 380 const Triple& Pos, const Triple& Sig) 381 { 382 try { 383 checkTimeSystem(ttag.getTimeSystem()); 384 385 if(tables.find(sat) != tables.end() && 386 tables[sat].find(ttag) != tables[sat].end()) { 387 // record already exists in table 388 PositionRecord& oldrec(tables[sat][ttag]); 389 oldrec.Pos = Pos; 390 oldrec.sigPos = Sig; 391 } 392 else { // create a new entry in the table 393 PositionRecord rec; 394 rec.Pos = Pos; 395 rec.sigPos = Sig; 396 rec.Vel = rec.sigVel = rec.Acc = rec.sigAcc = Triple(0,0,0); 397 398 tables[sat][ttag] = rec; 399 } 400 } 401 catch(InvalidRequest& ir) { GPSTK_RETHROW(ir); } 402 } 403 404 // Add velocity data (only) to the store addVelocityData(const SatID & sat,const CommonTime & ttag,const Triple & Vel,const Triple & Sig)405 void PositionSatStore::addVelocityData(const SatID& sat, const CommonTime& ttag, 406 const Triple& Vel, const Triple& Sig) 407 { 408 try { 409 checkTimeSystem(ttag.getTimeSystem()); 410 411 haveVelocity = true; 412 413 if(tables.find(sat) != tables.end() && 414 tables[sat].find(ttag) != tables[sat].end()) { 415 // record already exists in table 416 PositionRecord& oldrec(tables[sat][ttag]); 417 oldrec.Vel = Vel; 418 oldrec.sigVel = Sig; 419 } 420 else { // create a new entry in the table 421 PositionRecord rec; 422 rec.Vel = Vel; 423 rec.sigVel = Sig; 424 rec.Pos = rec.sigPos = rec.Acc = rec.sigAcc = Triple(0,0,0); 425 426 tables[sat][ttag] = rec; 427 } 428 } 429 catch(InvalidRequest& ir) { GPSTK_RETHROW(ir); } 430 } 431 432 // Add acceleration data (only) to the store addAccelerationData(const SatID & sat,const CommonTime & ttag,const Triple & Acc,const Triple & Sig)433 void PositionSatStore::addAccelerationData(const SatID& sat, 434 const CommonTime& ttag, const Triple& Acc, const Triple& Sig) 435 { 436 try { 437 checkTimeSystem(ttag.getTimeSystem()); 438 439 haveAcceleration = true; 440 441 if(tables.find(sat) != tables.end() && 442 tables[sat].find(ttag) != tables[sat].end()) { 443 // record already exists in table 444 PositionRecord& oldrec(tables[sat][ttag]); 445 oldrec.Acc = Acc; 446 oldrec.sigAcc = Sig; 447 } 448 else { // create a new entry in the table 449 PositionRecord rec; 450 rec.Acc = Acc; 451 rec.sigAcc = Sig; 452 rec.Vel = rec.sigVel = rec.Pos = rec.sigPos = Triple(0,0,0); 453 454 tables[sat][ttag] = rec; 455 } 456 } 457 catch(InvalidRequest& ir) { GPSTK_RETHROW(ir); } 458 } 459 460 //@} 461 462 } // End of namespace gpstk 463