"Fossies" - the Fresh Open Source Software Archive

Member "xearth-1.1/sunpos.c" (7 Nov 1999, 10101 Bytes) of package /linux/misc/old/xearth-1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * sunpos.c
    3  * kirk johnson
    4  * july 1993
    5  *
    6  * includes revisions from Frank T. Solensky, february 1999
    7  *
    8  * code for calculating the position on the earth's surface for which
    9  * the sun is directly overhead (adapted from _practical astronomy
   10  * with your calculator, third edition_, peter duffett-smith,
   11  * cambridge university press, 1988.)
   12  *
   13  * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson
   14  *
   15  * Parts of the source code (as marked) are:
   16  *   Copyright (C) 1989, 1990, 1991 by Jim Frost
   17  *   Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
   18  *
   19  * Permission to use, copy, modify and freely distribute xearth for
   20  * non-commercial and not-for-profit purposes is hereby granted
   21  * without fee, provided that both the above copyright notice and this
   22  * permission notice appear in all copies and in supporting
   23  * documentation.
   24  *
   25  * Unisys Corporation holds worldwide patent rights on the Lempel Zev
   26  * Welch (LZW) compression technique employed in the CompuServe GIF
   27  * image file format as well as in other formats. Unisys has made it
   28  * clear, however, that it does not require licensing or fees to be
   29  * paid for freely distributed, non-commercial applications (such as
   30  * xearth) that employ LZW/GIF technology. Those wishing further
   31  * information about licensing the LZW patent should contact Unisys
   32  * directly at (lzw_info@unisys.com) or by writing to
   33  *
   34  *   Unisys Corporation
   35  *   Welch Licensing Department
   36  *   M/S-C1SW19
   37  *   P.O. Box 500
   38  *   Blue Bell, PA 19424
   39  *
   40  * The author makes no representations about the suitability of this
   41  * software for any purpose. It is provided "as is" without express or
   42  * implied warranty.
   43  *
   44  * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   45  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
   46  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
   47  * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   48  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
   49  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   50  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   51  */
   52 
   53 #include "xearth.h"
   54 #include "kljcpyrt.h"
   55 
   56 #define TWOPI         (2*M_PI)
   57 #define DegsToRads(x) ((x)*(TWOPI/360))
   58 
   59 /*
   60  * the epoch upon which these astronomical calculations are based is
   61  * 1990 january 0.0, 631065600 seconds since the beginning of the
   62  * "unix epoch" (00:00:00 GMT, Jan. 1, 1970)
   63  *
   64  * given a number of seconds since the start of the unix epoch,
   65  * DaysSinceEpoch() computes the number of days since the start of the
   66  * astronomical epoch (1990 january 0.0)
   67  */
   68 
   69 #define EpochStart           (631065600)
   70 #define DaysSinceEpoch(secs) (((secs)-EpochStart)*(1.0/(24*3600)))
   71 
   72 /*
   73  * assuming the apparent orbit of the sun about the earth is circular,
   74  * the rate at which the orbit progresses is given by RadsPerDay --
   75  * TWOPI radians per orbit divided by 365.242191 days per year:
   76  */
   77 
   78 #define RadsPerDay (TWOPI/365.242191)
   79 
   80 /*
   81  * details of sun's apparent orbit at epoch 1990.0 (after
   82  * duffett-smith, table 6, section 46)
   83  *
   84  * Epsilon_g    (ecliptic longitude at epoch 1990.0) 279.403303 degrees
   85  * OmegaBar_g   (ecliptic longitude of perigee)      282.768422 degrees
   86  * Eccentricity (eccentricity of orbit)                0.016713
   87  */
   88 
   89 #define Epsilon_g    (DegsToRads(279.403303))
   90 #define OmegaBar_g   (DegsToRads(282.768422))
   91 #define Eccentricity (0.016713)
   92 
   93 /*
   94  * MeanObliquity gives the mean obliquity of the earth's axis at epoch
   95  * 1990.0 (computed as 23.440592 degrees according to the method given
   96  * in duffett-smith, section 27)
   97  */
   98 #define MeanObliquity (23.440592*(TWOPI/360))
   99 
  100 /*
  101  * Lunar parameters, epoch January 0, 1990.0
  102  */
  103 #define MoonMeanLongitude        DegsToRads(318.351648)
  104 #define MoonMeanLongitudePerigee DegsToRads( 36.340410)
  105 #define MoonMeanLongitudeNode    DegsToRads(318.510107)
  106 #define MoonInclination          DegsToRads(  5.145396)
  107 
  108 #define SideralMonth (27.3217)
  109 
  110 /*
  111  * Force an angular value into the range [-PI, +PI]
  112  */
  113 #define Normalize(x)                        \
  114   do {                                      \
  115     if ((x) < -M_PI)                        \
  116       do (x) += TWOPI; while ((x) < -M_PI); \
  117     else if ((x) > M_PI)                    \
  118       do (x) -= TWOPI; while ((x) > M_PI);  \
  119   } while (0)
  120 
  121 static double solve_keplers_equation _P((double));
  122 static double mean_sun _P((double));
  123 static double sun_ecliptic_longitude _P((time_t));
  124 static void   ecliptic_to_equatorial _P((double, double, double *, double *));
  125 static double julian_date _P((int, int, int));
  126 static double GST _P((time_t));
  127 
  128 /*
  129  * solve Kepler's equation via Newton's method
  130  * (after duffett-smith, section 47)
  131  */
  132 static double solve_keplers_equation(M)
  133      double M;
  134 {
  135   double E;
  136   double delta;
  137 
  138   E = M;
  139   while (1)
  140   {
  141     delta = E - Eccentricity*sin(E) - M;
  142     if (fabs(delta) <= 1e-10) break;
  143     E -= delta / (1 - Eccentricity*cos(E));
  144   }
  145 
  146   return E;
  147 }
  148 
  149 
  150 /*
  151  * Calculate the position of the mean sun: where the sun would
  152  * be if the earth's orbit were circular instead of ellipictal.
  153  */
  154 
  155 static double mean_sun (D)
  156      double D;                  /* days since ephemeris epoch */
  157 {
  158   double N, M;
  159 
  160   N = RadsPerDay * D;
  161   N = fmod(N, TWOPI);
  162   if (N < 0) N += TWOPI;
  163 
  164   M = N + Epsilon_g - OmegaBar_g;
  165   if (M < 0) M += TWOPI;
  166   return M;
  167 }
  168 
  169 /*
  170  * compute ecliptic longitude of sun (in radians)
  171  * (after duffett-smith, section 47)
  172  */
  173 static double sun_ecliptic_longitude(ssue)
  174      time_t ssue;               /* seconds since unix epoch */
  175 {
  176   double D;
  177   double M_sun, E;
  178   double v;
  179 
  180   D = DaysSinceEpoch(ssue);
  181   M_sun = mean_sun(D);
  182 
  183   E = solve_keplers_equation(M_sun);
  184   v = 2 * atan(sqrt((1+Eccentricity)/(1-Eccentricity)) * tan(E/2));
  185 
  186   return (v + OmegaBar_g);
  187 }
  188 
  189 
  190 /*
  191  * convert from ecliptic to equatorial coordinates
  192  * (after duffett-smith, section 27)
  193  */
  194 static void ecliptic_to_equatorial(lambda, beta, alpha, delta)
  195      double  lambda;            /* ecliptic longitude       */
  196      double  beta;              /* ecliptic latitude        */
  197      double *alpha;             /* (return) right ascension */
  198      double *delta;             /* (return) declination     */
  199 {
  200   double sin_e, cos_e;
  201 
  202   sin_e = sin(MeanObliquity);
  203   cos_e = cos(MeanObliquity);
  204 
  205   *alpha = atan2(sin(lambda)*cos_e - tan(beta)*sin_e, cos(lambda));
  206   *delta = asin(sin(beta)*cos_e + cos(beta)*sin_e*sin(lambda));
  207 }
  208 
  209 
  210 /*
  211  * computing julian dates (assuming gregorian calendar, thus this is
  212  * only valid for dates of 1582 oct 15 or later)
  213  * (after duffett-smith, section 4)
  214  */
  215 static double julian_date(y, m, d)
  216      int y;                     /* year (e.g. 19xx)          */
  217      int m;                     /* month (jan=1, feb=2, ...) */
  218      int d;                     /* day of month              */
  219 {
  220   int    A, B, C, D;
  221   double JD;
  222 
  223   /* lazy test to ensure gregorian calendar */
  224   assert(y >= 1583);
  225 
  226   if ((m == 1) || (m == 2))
  227   {
  228     y -= 1;
  229     m += 12;
  230   }
  231 
  232   A = y / 100;
  233   B = 2 - A + (A / 4);
  234   C = 365.25 * y;
  235   D = 30.6001 * (m + 1);
  236 
  237   JD = B + C + D + d + 1720994.5;
  238 
  239   return JD;
  240 }
  241 
  242 
  243 /*
  244  * compute greenwich mean sidereal time (GST) corresponding to a given
  245  * number of seconds since the unix epoch
  246  * (after duffett-smith, section 12)
  247  */
  248 static double GST(ssue)
  249      time_t ssue;               /* seconds since unix epoch */
  250 {
  251   double     JD;
  252   double     T, T0;
  253   double     UT;
  254   struct tm *tm;
  255 
  256   tm = gmtime(&ssue);
  257 
  258   JD = julian_date(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
  259   T  = (JD - 2451545) / 36525;
  260 
  261   T0 = ((T + 2.5862e-5) * T + 2400.051336) * T + 6.697374558;
  262 
  263   T0 = fmod(T0, 24.0);
  264   if (T0 < 0) T0 += 24;
  265 
  266   UT = tm->tm_hour + (tm->tm_min + tm->tm_sec / 60.0) / 60.0;
  267 
  268   T0 += UT * 1.002737909;
  269   T0 = fmod(T0, 24.0);
  270   if (T0 < 0) T0 += 24;
  271 
  272   return T0;
  273 }
  274 
  275 
  276 /*
  277  * given a particular time (expressed in seconds since the unix
  278  * epoch), compute position on the earth (lat, lon) such that sun is
  279  * directly overhead.
  280  */
  281 void sun_position(ssue, lat, lon)
  282      time_t  ssue;              /* seconds since unix epoch */
  283      double *lat;               /* (return) latitude        */
  284      double *lon;               /* (return) longitude       */
  285 {
  286   double lambda;
  287   double alpha, delta;
  288   double tmp;
  289 
  290   lambda = sun_ecliptic_longitude(ssue);
  291   ecliptic_to_equatorial(lambda, 0.0, &alpha, &delta);
  292 
  293   tmp = alpha - (TWOPI/24)*GST(ssue);
  294   Normalize(tmp);
  295   *lon = tmp * (360/TWOPI);
  296   *lat = delta * (360/TWOPI);
  297 }
  298 
  299 
  300 /*
  301  * given a particular time (expressed in seconds since the unix
  302  * epoch), compute position on the earth (lat, lon) such that the
  303  * moon is directly overhead.
  304  *
  305  * Based on duffett-smith **2nd ed** section 61; combines some steps
  306  * into single expressions to reduce the number of extra variables.
  307  */
  308 void moon_position(ssue, lat, lon)
  309      time_t  ssue;              /* seconds since unix epoch */
  310      double *lat;               /* (return) latitude        */
  311      double *lon;               /* (return) longitude       */
  312 {
  313   double lambda, beta;
  314   double D, L, Ms, Mm, N, Ev, Ae, Ec, alpha, delta;
  315 
  316   D      = DaysSinceEpoch(ssue);
  317   lambda = sun_ecliptic_longitude(ssue);
  318   Ms     = mean_sun(D);
  319 
  320   L = fmod(D/SideralMonth, 1.0)*TWOPI + MoonMeanLongitude;
  321   Normalize(L);
  322   Mm = L - DegsToRads(0.1114041*D) - MoonMeanLongitudePerigee;
  323   Normalize(Mm);
  324   N = MoonMeanLongitudeNode - DegsToRads(0.0529539*D);
  325   Normalize(N);
  326   Ev  = DegsToRads(1.2739) * sin(2.0*(L-lambda)-Mm);
  327   Ae  = DegsToRads(0.1858) * sin(Ms);
  328   Mm += Ev - Ae - DegsToRads(0.37)*sin(Ms);
  329   Ec  = DegsToRads(6.2886) * sin(Mm);
  330   L  += Ev + Ec - Ae + DegsToRads(0.214) * sin(2.0*Mm);
  331   L  += DegsToRads(0.6583) * sin(2.0*(L-lambda));
  332   N  -= DegsToRads(0.16) * sin(Ms);
  333 
  334   L -= N;
  335   lambda =(fabs(cos(L)) < 1e-12) ?
  336     (N + sin(L) * cos(MoonInclination) * M_PI/2) :
  337     (N + atan2(sin(L) * cos(MoonInclination), cos(L)));
  338   Normalize(lambda);
  339   beta = asin(sin(L) * sin(MoonInclination));
  340   ecliptic_to_equatorial(lambda, beta, &alpha, &delta);
  341   alpha -= (TWOPI/24)*GST(ssue);
  342   Normalize(alpha);
  343   *lon = alpha * (360/TWOPI);
  344   *lat = delta * (360/TWOPI);
  345 }