SolarPosition.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk 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 GNSSTk 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 GNSSTk; 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-2022, 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 
40 
41 //------------------------------------------------------------------------------------
42 // includes
43 // system
44 // GNSSTk
45 #include "SolarPosition.hpp"
46 #include "CommonTime.hpp"
47 #include "GNSSconstants.hpp" // TWO_PI and DEG_TO_RAD
48 #include "JulianDate.hpp"
49 #include "Position.hpp"
50 #include "YDSTime.hpp"
51 
52 namespace gnsstk
53 {
54  using namespace std;
55 
56  //---------------------------------------------------------------------------------
57  // Compute Greenwich Mean Sidereal Time in degrees
58  static double GMST(const CommonTime& t)
59  {
60  static const long JulianEpoch = 2451545;
61  // days since epoch
62  double days = (static_cast<JulianDate>(t).jd - JulianEpoch); // days
63  if (days <= 0.0)
64  {
65  days -= 1.0;
66  }
67  double Tp = days / 36525.0; // dim-less
68 
69  // Compute GMST in radians
70  double G;
71  /* seconds (24060s = 6h 41min)
72  G = 24110.54841 + (8640184.812866 + (0.093104 - 6.2e-6*Tp)*Tp)*Tp; //
73  sec G /= 86400.0; // instead, divide the numbers above manually */
74  G = 0.279057273264 + 100.0021390378009 * Tp // seconds/86400 = days
75  + (0.093104 - 6.2e-6 * Tp) * Tp * Tp / 86400.0;
76  G += static_cast<YDSTime>(t).sod / 86400.0; // days
77 
78  // put answer between 0 and 360 deg
79  G = fmod(G, 1.0);
80  while (G < 0.0)
81  G += 1.0;
82  G *= 360.0; // degrees
83 
84  return G;
85  }
86 
87  //---------------------------------------------------------------------------------
88  /* accuracy is about 1 arcminute, when t is within 2 centuries of 2000.
89  Ref. Astronomical Almanac pg C24, as presented on USNO web site.
90  input
91  t epoch of interest
92  output
93  lat,lon,R latitude, longitude and distance (deg,deg,m in ECEF) of
94  sun at t. AR apparent angular radius of sun as seen at Earth
95  (deg) at t. */
96  Position solarPosition(const CommonTime& t, double& AR)
97  {
98  // const double mPerAU = 149598.0e6;
99  double D; // days since J2000
100  double g, q; // q is mean longitude of sun, corrected for aberration
101  double L; // sun's geocentric apparent ecliptic longitude (deg)
102  // double b=0; // sun's geocentric apparent ecliptic latitude (deg)
103  double e; // mean obliquity of the ecliptic (deg)
104  // double R; // sun's distance from Earth (m)
105  double RA; // sun's right ascension (deg)
106  double DEC; // sun's declination (deg)
107  // double AR; // sun's apparent angular radius as seen at Earth (deg)
108 
109  D = static_cast<JulianDate>(t).jd - 2451545.0;
110  g = (357.529 + 0.98560028 * D) * DEG_TO_RAD;
111  // AA 1990 has g = (357.528 + 0.9856003 * D) * DEG_TO_RAD;
112  q = 280.459 + 0.98564736 * D;
113  // AA 1990 has q = 280.460 + 0.9856474 * D;
114  L = (q + 1.915 * std::sin(g) + 0.020 * std::sin(2 * g)) * DEG_TO_RAD;
115 
116  e = (23.439 - 0.00000036 * D) * DEG_TO_RAD;
117  // AA 1990 has e = (23.439 - 0.0000004 * D) * DEG_TO_RAD;
118  RA = std::atan2(std::cos(e) * std::sin(L), std::cos(L)) * RAD_TO_DEG;
119  DEC = std::asin(std::sin(e) * std::sin(L)) * RAD_TO_DEG;
120 
121  /* equation of time = apparent solar time minus mean solar time
122  = [q-RA (deg)]/(15deg/hr) */
123 
124  /* compute the hour angle of the vernal equinox = GMST and convert RA to
125  lon */
126  double lon = fmod(RA - GMST(t), 360.0);
127  if (lon < -180.0)
128  {
129  lon += 360.0;
130  }
131  if (lon > 180.0)
132  {
133  lon -= 360.0;
134  }
135 
136  double lat = DEC;
137 
138  // ECEF unit vector in direction Earth to sun
139  double xhat = std::cos(lat * DEG_TO_RAD) * std::cos(lon * DEG_TO_RAD);
140  double yhat = std::cos(lat * DEG_TO_RAD) * std::sin(lon * DEG_TO_RAD);
141  double zhat = std::sin(lat * DEG_TO_RAD);
142 
143  // R in AU
144  double R = 1.00014 - 0.01671 * std::cos(g) - 0.00014 * std::cos(2 * g);
145  // apparent angular radius in degrees
146  AR = 0.2666 / R;
147  // convert to meters
148  R *= 149598.0e6;
149 
150  Position es;
151  es.setECEF(R * xhat, R * yhat, R * zhat);
152  return es;
153  }
154 
155  //---------------------------------------------------------------------------------
156  /* Compute the position (latitude and longitude, in degrees) of the sun
157  given the day of year and the hour of the day.
158  Adapted from sunpos by D. Coco 12/15/94 */
159  void crudeSolarPosition(const CommonTime& t, double& lat, double& lon)
160  {
161  int doy = static_cast<YDSTime>(t).doy;
162  int hod = int(static_cast<YDSTime>(t).sod / 3600.0 + 0.5);
163  lat = std::sin(23.5 * DEG_TO_RAD) *
164  std::sin(TWO_PI * double(doy - 83) / 365.25);
165  lat = lat / std::sqrt(1.0 - lat * lat);
166  lat = RAD_TO_DEG * std::atan(lat);
167  lon = 180.0 - hod * 15.0;
168  }
169 
170  //---------------------------------------------------------------------------------
171  /* Consider the sun and the earth as seen from the satellite. Let the sun be
172  a circle of angular radius r, center in direction s, and the earth be a
173  (larger) circle of angular radius R, center in direction e. The circles
174  overlap if |e-s| < R+r; complete overlap if |e-s| < R. Let L == |e-s|.
175  What is the area of overlap if R-r < L < R+r ?
176  Call the two points where the circles intersect p1 and p2. Draw a line
177  from e to s; call the points where this line intersects the two circles r1
178  and R1, respectively. Draw lines from e to s, e to p1, e to p2, s to p1
179  and s to p2. Call the angle between e-s and e-p1 alpha, and that between
180  s-e and s-p1, beta. Draw a rectangle with top and bottom parallel to e-s
181  passing through p1 and p2, and with sides passing through s and r1.
182  Similarly for e and R1. Note that the area of intersection lies within the
183  intersection of these two rectangles. Call the area of the rectangle
184  outside the circles A and B. The height H of the rectangles is H =
185  2Rsin(alpha) = 2rsin(beta) also L = rcos(beta)+Rcos(alpha) The area A will
186  be the area of the rectangle
187  minus the area of the wedge formed by the angle 2*alpha
188  minus the area of the two triangles which meet at s :
189  A = RH - (2alpha/2pi)*pi*R*R - 2*(1/2)*(H/2)Rcos(alpha)
190  Similarly
191  B = rH - (2beta/2pi)*pi*r*r - 2*(1/2)*(H/2)rcos(beta)
192  The area of intersection will be the area of the rectangular intersection
193  minus the area A
194  minus the area B
195  Intersection = H(R+r-L) - A - B
196  = HR+Hr-HL -HR+alpha*R*R+(H/2)Rcos(alpha)
197  -Hr+beta*r*r+(H/2)rcos(beta)
198  Cancel terms, and substitute for L using above equation L = ..
199  = -(H/2)rcos(beta)-(H/2)Rcos(alpha)+alpha*R*R+beta*r*r
200  substitute for H/2
201  = -R*R*sin(alpha)cos(alpha)-r*r*sin(beta)cos(beta)+alpha*R*R+beta*r*r
202  Intersection =
203  R*R*[alpha-sin(alpha)cos(alpha)]+r*r*[beta-sin(beta)cos(beta)] Solve for
204  alpha and beta in terms of R, r and L using the H and L relations above
205  (r/R)cos(beta)=(L/R)-cos(alpha)
206  (r/R)sin(beta)=sin(alpha)
207  so
208  (r/R)^2 = (L/R)^2 - (2L/R)cos(alpha) + 1
209  cos(alpha) = (R/2L)(1+(L/R)^2-(r/R)^2)
210  cos(beta) = (L/r) - (R/r)cos(alpha)
211  and 0 <= alpha or beta <= pi
212 
213  Rearth angular radius of the earth as seen at the satellite
214  Rsun angular radius of the sun as seen at the satellite
215  dES angular distance of the sun from the earth
216  return fraction (0 <= f <= 1) of area of sun covered by earth
217  units only need be consistent */
218  double solarPositionShadowFactor(double Rearth, double Rsun, double dES)
219  {
220  if (dES >= Rearth + Rsun)
221  {
222  return 0.0;
223  }
224  if (dES <= std::fabs(Rearth - Rsun))
225  {
226  return 1.0;
227  }
228  double r = Rsun, R = Rearth, L = dES;
229  if (Rsun > Rearth)
230  {
231  r = Rearth;
232  R = Rsun;
233  }
234  double cosalpha =
235  (R / L) * (1.0 + (L / R) * (L / R) - (r / R) * (r / R)) / 2.0;
236  double cosbeta = (L / r) - (R / r) * cosalpha;
237  double sinalpha = ::sqrt(1 - cosalpha * cosalpha);
238  double sinbeta = ::sqrt(1 - cosbeta * cosbeta);
239  double alpha = ::asin(sinalpha);
240  double beta = ::asin(sinbeta);
241  double shadow = r * r * (beta - sinbeta * cosbeta) +
242  R * R * (alpha - sinalpha * cosalpha);
243  shadow /= ::acos(-1.0) * Rsun * Rsun;
244  return shadow;
245  }
246 
247  //---------------------------------------------------------------------------------
248  // From AA 1990 D46
249  Position lunarPosition(const CommonTime& t, double& AR)
250  {
251  // days since J2000
252  double N = static_cast<JulianDate>(t).jd - 2451545.0;
253  // centuries since J2000
254  double T = N / 36525.0;
255  // ecliptic longitude
256  double lam =
257  DEG_TO_RAD * (218.32 + 481267.883 * T +
258  6.29 * ::sin(DEG_TO_RAD * (134.9 + 477198.85 * T)) -
259  1.27 * ::sin(DEG_TO_RAD * (259.2 - 413335.38 * T)) +
260  0.66 * ::sin(DEG_TO_RAD * (235.7 + 890534.23 * T)) +
261  0.21 * ::sin(DEG_TO_RAD * (269.9 + 954397.70 * T)) -
262  0.19 * ::sin(DEG_TO_RAD * (357.5 + 35999.05 * T)) -
263  0.11 * ::sin(DEG_TO_RAD * (259.2 + 966404.05 * T)));
264  // ecliptic latitude
265  double bet =
266  DEG_TO_RAD * (5.13 * ::sin(DEG_TO_RAD * (93.3 + 483202.03 * T)) +
267  0.28 * ::sin(DEG_TO_RAD * (228.2 + 960400.87 * T)) -
268  0.28 * ::sin(DEG_TO_RAD * (318.3 + 6003.18 * T)) -
269  0.17 * ::sin(DEG_TO_RAD * (217.6 - 407332.20 * T)));
270  // horizontal parallax
271  double par =
272  DEG_TO_RAD *
273  (0.9508 + 0.0518 * ::cos(DEG_TO_RAD * (134.9 + 477198.85 * T)) +
274  0.0095 * ::cos(DEG_TO_RAD * (259.2 - 413335.38 * T)) +
275  0.0078 * ::cos(DEG_TO_RAD * (235.7 + 890534.23 * T)) +
276  0.0028 * ::cos(DEG_TO_RAD * (269.9 + 954397.70 * T)));
277 
278  // obliquity of the ecliptic
279  double eps = (23.439 - 0.00000036 * N) * DEG_TO_RAD;
280 
281  // convert ecliptic lon,lat to geocentric lon,lat
282  double l = ::cos(bet) * ::cos(lam);
283  double m = ::cos(eps) * ::cos(bet) * ::sin(lam) - ::sin(eps) * ::sin(bet);
284  double n = ::sin(eps) * ::cos(bet) * ::sin(lam) + ::cos(eps) * ::sin(bet);
285 
286  /* convert to right ascension and declination,
287  (referred to mean equator and equinox of date) */
288  double RA = ::atan2(m, l) * RAD_TO_DEG;
289  double DEC = ::asin(n) * RAD_TO_DEG;
290 
291  /* compute the hour angle of the vernal equinox = GMST and convert RA to
292  lon */
293  double lon = ::fmod(RA - GMST(t), 360.0);
294  if (lon < -180.0)
295  {
296  lon += 360.0;
297  }
298  if (lon > 180.0)
299  {
300  lon -= 360.0;
301  }
302 
303  double lat = DEC;
304 
305  // apparent semidiameter of moon (in radians)
306  AR = 0.2725 * par;
307  // moon distance in meters
308  double R = 1.0 / ::sin(par);
309  R *= 6378137.0;
310 
311  // ECEF vector in direction Earth to moon
312  double x = R * std::cos(lat * DEG_TO_RAD) * std::cos(lon * DEG_TO_RAD);
313  double y = R * std::cos(lat * DEG_TO_RAD) * std::sin(lon * DEG_TO_RAD);
314  double z = R * std::sin(lat * DEG_TO_RAD);
315 
316  Position EM;
317  EM.setECEF(x, y, z);
318 
319  return EM;
320  }
321 
322  //---------------------------------------------------------------------------------
323 } // end namespace gnsstk
YDSTime.hpp
gnsstk::lunarPosition
Position lunarPosition(const CommonTime &t, double &AR)
Definition: SolarPosition.cpp:249
gnsstk::YDSTime
Definition: YDSTime.hpp:58
SolarPosition.hpp
Position.hpp
gnsstk::TWO_PI
const double TWO_PI
GPS value of PI*2.
Definition: GNSSconstants.hpp:68
gnsstk::JulianDate
Definition: JulianDate.hpp:89
GNSSconstants.hpp
gnsstk::GMST
static double GMST(const CommonTime &t)
Definition: SolarPosition.cpp:58
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
std::sin
double sin(gnsstk::Angle x)
Definition: Angle.hpp:144
gnsstk::Position::setECEF
Position & setECEF(const double X, const double Y, const double Z) noexcept
Definition: Position.cpp:601
gnsstk::RAD_TO_DEG
static const double RAD_TO_DEG
Conversion Factor from radians to degrees (units: degrees)
Definition: GNSSconstants.hpp:78
y
page HOWTO subpage DoxygenGuide Documenting Your Code page DoxygenGuide Documenting Your Code todo Flesh out this document section doctips Tips for Documenting When defining make sure that the prototype is identical between the cpp and hpp including both the namespaces and the parameter names for you have std::string as the return type in the hpp file and string as the return type in the cpp Doxygen may get confused and autolink to the cpp version with no documentation If you don t use the same parameter names between the cpp and hpp that will also confuse Doxygen Don t put type information in return or param documentation It doesn t really add anything and will often cause Doxygen to complain and not produce the documentation< br > use note Do not put a comma after a param name unless you mean to document multiple parameters< br/> the output stream</code >< br/> y
Definition: DOCUMENTING.dox:15
JulianDate.hpp
gnsstk::solarPositionShadowFactor
double solarPositionShadowFactor(double Rearth, double Rsun, double dES)
Definition: SolarPosition.cpp:218
gnsstk::CommonTime
Definition: CommonTime.hpp:84
gnsstk::solarPosition
Position solarPosition(const CommonTime &t, double &AR)
Definition: SolarPosition.cpp:96
std::cos
double cos(gnsstk::Angle x)
Definition: Angle.hpp:146
gnsstk::beta
double beta(double x, double y)
Definition: SpecialFuncs.cpp:204
example6.sod
sod
Definition: example6.py:103
CommonTime.hpp
std
Definition: Angle.hpp:142
gnsstk::Position
Definition: Position.hpp:136
gnsstk::crudeSolarPosition
void crudeSolarPosition(const CommonTime &t, double &lat, double &lon)
Definition: SolarPosition.cpp:159
gnsstk::DEG_TO_RAD
static const double DEG_TO_RAD
Conversion Factor from degrees to radians (units: degrees^-1)
Definition: GNSSconstants.hpp:76


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:41