📄 tropmodel.cpp
字号:
// normalize double norm=(ho-height)/5; return map/norm; } // end GGHeightTropModel::dry_mapping_function(elevation) // Compute and return the mapping function for wet component // of the troposphere // @param elevation Elevation of satellite as seen at receiver, // in degrees double GGHeightTropModel::wet_mapping_function(double elevation) const throw(TropModel::InvalidTropModel) { if(!valid) { if(!validWeather) GPSTK_THROW(InvalidTropModel("Invalid GGH trop model: Weather")); if(!validHeights) GPSTK_THROW(InvalidTropModel("Invalid GGH trop model: Heights")); if(!validRxHeight) GPSTK_THROW(InvalidTropModel("Invalid GGH trop model: Rx Height")); } if(elevation < 0.0) return 0.0; double hrate=6.5e-3; double Ts=temp+hrate*htemp; double rs=(371900.0e-3/Ts-12.92e-3)/Ts; double ho=11.385*(1255/Ts+0.05)/rs; double se=std::sin(elevation*DEG_TO_RAD); if(se < 0.0) se=0.0; GPSGeoid geoid; double rt,a,b,rn[8],al[8],er=geoid.a(); rt = (er+ho)/(er+height); rt = rt*rt - (1.0-se*se); if(rt < 0) rt=0.0; rt = (er+height)*(SQRT(rt)-se); a = -se/(ho-height); b = -(1.0-se*se)/(2.0*er*(ho-height)); rn[0] = rt*rt; for(int i=1; i<8; i++) rn[i]=rn[i-1]*rt; al[0] = 2*a; al[1] = 2*a*a+4*b/3; al[2] = a*(a*a+3*b); al[3] = a*a*a*a/5+2.4*a*a*b+1.2*b*b; al[4] = 2*a*b*(a*a+3*b)/3; al[5] = b*b*(6*a*a+4*b)*0.1428571; if(b*b > 1.0e-35) { al[6] = a*b*b*b/2; al[7] = b*b*b*b/9; } else { al[6] = 0.0; al[7] = 0.0; } double map=rt; for(int j=0; j<8; j++) map += al[j]*rn[j]; // normalize map function double norm=(ho-height)/5; return map/norm; } // end GGHeightTropModel::wet_mapping_function(elevation) // Re-define the weather data. // Typically called just before correction(). // @param T temperature in degrees Celsius // @param P atmospheric pressure in millibars // @param H relative humidity in percent void GGHeightTropModel::setWeather(const double& T, const double& P, const double& H) throw(InvalidParameter) { try { TropModel::setWeather(T,P,H); validWeather = true; valid = validWeather && validHeights && validRxHeight; } catch(InvalidParameter& e) { valid = validWeather = false; GPSTK_RETHROW(e); } } // end GGHeightTropModel::setWeather(T,P,H) // Re-define the tropospheric model with explicit weather data. // Typically called just before correction(). // @param wx the weather to use for this correction void GGHeightTropModel::setWeather(const WxObservation& wx) throw(InvalidParameter) { try { TropModel::setWeather(wx); validWeather = true; valid = validWeather && validHeights && validRxHeight; } catch(InvalidParameter& e) { valid = validWeather = false; GPSTK_RETHROW(e); } } // Re-define the heights at which the weather parameters apply. // Typically called just before correction(). // @param hT height (m) at which temperature applies // @param hP height (m) at which atmospheric pressure applies // @param hH height (m) at which relative humidity applies void GGHeightTropModel::setHeights(const double& hT, const double& hP, const double& hH) { htemp = hT; // height (m) at which temp applies hpress = hP; // height (m) at which press applies hhumid = hH; // height (m) at which humid applies validHeights = true; valid = validWeather && validHeights && validRxHeight; } // end GGHeightTropModel::setHeights(hT,hP,hH) // Define the receiver height; this required before calling // correction() or any of the zenith_delay or mapping_function routines. void GGHeightTropModel::setReceiverHeight(const double& ht) { height = ht; validRxHeight = true; if(!validHeights) { htemp = hpress = hhumid = ht; validHeights = true; } valid = validWeather && validHeights && validRxHeight; } // end GGHeightTropModel::setReceiverHeight(const double& ht) // ------------------------------------------------------------------------------- // Tropospheric model developed by University of New Brunswick and described in // "A Tropospheric Delay Model for the User of the Wide Area Augmentation // System," J. Paul Collins and Richard B. Langley, Technical Report No. 187, // Dept. of Geodesy and Geomatics Engineering, University of New Brunswick, // 1997. See particularly Appendix C. // // This model includes a wet and dry component, and was designed for the user // without access to measurements of temperature, pressure and relative humidity // at ground level. It requires input of the latitude, day of year and height // above the ellipsoid, and it interpolates a table of values, using these // inputs, to get the ground level weather parameters plus other parameters and // the mapping function constants. // // NB in this model, units of temp are degrees Celsius, and humid is the water // vapor partial pressure. static const double NBRd=287.054; // J/kg/K = m*m*K/s*s static const double NBg=9.80665; // m/s*s static const double NBk1=77.604; // K/mbar static const double NBk3p=382000; // K*K/mbar static const double NBLat[5]={ 15.0, 30.0, 45.0, 60.0, 75.0}; // zenith delays, averages static const double NBZP0[5]={1013.25,1017.25,1015.75,1011.75,1013.00}; static const double NBZT0[5]={ 299.65, 294.15, 283.15, 272.15, 263.65}; static const double NBZW0[5]={ 26.31, 21.79, 11.66, 6.78, 4.11}; static const double NBZB0[5]={6.30e-3,6.05e-3,5.58e-3,5.39e-3,4.53e-3}; static const double NBZL0[5]={ 2.77, 3.15, 2.57, 1.81, 1.55}; // zenith delays, amplitudes static const double NBZPa[5]={ 0.0, -3.75, -2.25, -1.75, -0.50}; static const double NBZTa[5]={ 0.0, 7.0, 11.0, 15.0, 14.5}; static const double NBZWa[5]={ 0.0, 8.85, 7.24, 5.36, 3.39}; static const double NBZBa[5]={ 0.0,0.25e-3,0.32e-3,0.81e-3,0.62e-3}; static const double NBZLa[5]={ 0.0, 0.33, 0.46, 0.74, 0.30}; // mapping function, dry, averages static const double NBMad[5]={1.2769934e-3,1.2683230e-3,1.2465397e-3,1.2196049e-3, 1.2045996e-3}; static const double NBMbd[5]={2.9153695e-3,2.9152299e-3,2.9288445e-3,2.9022565e-3, 2.9024912e-3}; static const double NBMcd[5]={62.610505e-3,62.837393e-3,63.721774e-3,63.824265e-3, 64.258455e-3}; // mapping function, dry, amplitudes static const double NBMaa[5]={0.0,1.2709626e-5,2.6523662e-5,3.4000452e-5, 4.1202191e-5}; static const double NBMba[5]={0.0,2.1414979e-5,3.0160779e-5,7.2562722e-5, 11.723375e-5}; static const double NBMca[5]={0.0,9.0128400e-5,4.3497037e-5,84.795348e-5, 170.37206e-5}; // mapping function, wet, averages (there are no amplitudes for wet) static const double NBMaw[5]={5.8021897e-4,5.6794847e-4,5.8118019e-4,5.9727542e-4, 6.1641693e-4}; static const double NBMbw[5]={1.4275268e-3,1.5138625e-3,1.4572752e-3,1.5007428e-3, 1.7599082e-3}; static const double NBMcw[5]={4.3472961e-2,4.6729510e-2,4.3908931e-2,4.4626982e-2, 5.4736038e-2}; // labels for use with the interpolation routine enum TableEntry { ZP=1, ZT, ZW, ZB, ZL, Mad, Mbd, Mcd, Maw, Mbw, Mcw }; // the interpolation routine static double NB_Interpolate(double lat, int doy, TableEntry entry) { const double *pave, *pamp; double ret, day=double(doy); // assign pointer to the right array switch(entry) { case ZP: pave=&NBZP0[0]; pamp=&NBZPa[0]; break; case ZT: pave=&NBZT0[0]; pamp=&NBZTa[0]; break; case ZW: pave=&NBZW0[0]; pamp=&NBZWa[0]; break; case ZB: pave=&NBZB0[0]; pamp=&NBZBa[0]; break; case ZL: pave=&NBZL0[0]; pamp=&NBZLa[0]; break; case Mad: pave=&NBMad[0]; pamp=&NBMaa[0]; break; case Mbd: pave=&NBMbd[0]; pamp=&NBMba[0]; break; case Mcd: pave=&NBMcd[0]; pamp=&NBMca[0]; break; case Maw: pave=&NBMaw[0]; break; case Mbw: pave=&NBMbw[0]; break; case Mcw: pave=&NBMcw[0]; break; } // find the index i such that NBLat[i] <= lat < NBLat[i+1] int i = int(ABS(lat)/15.0)-1; if(i>=0 && i<=3) { // mid-latitude -> regular interpolation double m=(ABS(lat)-NBLat[i])/(NBLat[i+1]-NBLat[i]); ret = pave[i]+m*(pave[i+1]-pave[i]); if(entry < Maw) ret -= (pamp[i]+m*(pamp[i+1]-pamp[i])) * std::cos(TWO_PI*(day-28.0)/365.25); } else { // < 15 or > 75 -> simpler interpolation if(i<0) i=0; else i=4; ret = pave[i]; if(entry < Maw) ret -= pamp[i]*std::cos(TWO_PI*(day-28.0)/365.25); } return ret; } // end double NB_Interpolate(lat,doy,entry) // Default constructor NBTropModel::NBTropModel(void) { validWeather = false; validRxLatitude = false; validDOY = false; validRxHeight = false; } // end NBTropModel::NBTropModel() // Create a trop model using the minimum information: latitude and doy. // Interpolate the weather unless setWeather (optional) is called. // @param lat Latitude of the receiver in degrees. // @param day Day of year. NBTropModel::NBTropModel(const double& lat, const int& day) { validRxHeight = false; setReceiverLatitude(lat); setDayOfYear(day); setWeather(); } // end NBTropModel::NBTropModel(lat, day); // Create a trop model with weather. // @param lat Latitude of the receiver in degrees. // @param day Day of year. // @param wx the weather to use for this correction. NBTropModel::NBTropModel(const double& lat, const int& day, const WxObservation& wx) throw(InvalidParameter) { validRxHeight = false; setReceiverLatitude(lat); setDayOfYear(day); setWeather(wx); } // end NBTropModel::NBTropModel(weather) // Create a tropospheric model from explicit weather data // @param lat Latitude of the receiver in degrees. // @param day Day of year. // @param T temperature in degrees Celsius // @param P atmospheric pressure in millibars // @param H relative humidity in percent NBTropModel::NBTropModel(const double& lat, const int& day, const double& T, const double& P, const double& H) throw(InvalidParameter) { validRxHeight = false; setReceiverLatitude(lat); setDayOfYear(day); setWeather(T,P,H); } // end NBTropModel::NBTropModel() // Create a valid model from explicit input (weather will be estimated // internally by this model). // @param ht Height of the receiver in meters. // @param lat Latitude of the receiver in degrees. // @param d Day of year. NBTropModel::NBTropModel(const double& ht, const double& lat, const int& day) { setReceiverHeight(ht); setReceiverLatitude(lat); setDayOfYear(day); setWeather(); } // re-define this to get the throws double NBTropModel::correction(double elevation) const throw(TropModel::InvalidTropModel) { if(!valid) { if(!validWeather) GPSTK_THROW(InvalidTropModel("Invalid NB trop model: weather")); if(!validRxLatitude) GPSTK_THROW(InvalidTropModel("Invalid NB trop model: Rx Latitude")); if(!validRxHeight) GPSTK_THROW(InvalidTropModel("Invalid NB trop model: Rx Height")); if(!validDOY) GPSTK_THROW(InvalidTropModel("Invalid NB trop model: day of year")); } if(elevation < 0.0) return 0.0; return (dry_zenith_delay() * dry_mapping_function(elevation) + wet_zenith_delay() * wet_mapping_function(elevation)); } // end NBTropModel::correction(elevation) // Compute and return the full tropospheric delay, given the positions of // receiver and satellite and the time tag. This version is most useful // within positioning algorithms, where the receiver position and timetag // may vary; it computes the elevation (and other receiver location // information) and passes them to appropriate set...() routines // and the correction(elevation) routine. // @param RX Receiver position // @param SV Satellite position // @param tt Time tag of the signal double NBTropModel::correction(const Position& RX,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -