/* convert ra to ha, in range 0..2*PI * need dec too if not already apparent. */ void radec2ha (Now *np, double ra, double dec, double *hap) { double ha, lst; if (epoch != EOD) as_ap (np, epoch, &ra, &dec); now_lst (np, &lst); ha = hrrad(lst) - ra; if (ha < 0) ha += 2*PI; *hap = ha; }
/* find Greenwich Hour Angle of the given object at the given time, 0..2*PI. */ void gha (Now *np, Obj *op, double *ghap) { Now n = *np; Obj o = *op; double tmp; n.n_epoch = EOD; n.n_lng = 0.0; n.n_lat = 0.0; obj_cir (&n, &o); now_lst (&n, &tmp); tmp = hrrad(tmp) - o.s_ra; if (tmp < 0) tmp += 2*PI; *ghap = tmp; }
/* find when the given object transits. start the search when LST matches the * object's RA at noon. * if ok, return 0 with np and op set to the transit conditions; if can't * converge return -1; if converges ok but not today return -2. * N.B. we assume np is passed set to local noon. */ static int find_transit (double dt, Now *np, Obj *op) { #define MAXLOOPS 10 #define MAXERR (0.25/60.) /* hours */ double mjdn = mjd; double lst; int i; /* insure initial guess is today -- if not, move by 24 hours */ if (dt < -12.0) dt += 24.0; if (dt > 12.0) dt -= 24.0; i = 0; do { mjd += dt/24.0; if (obj_cir (np, op) < 0) return (-1); now_lst (np, &lst); dt = (radhr(op->s_gaera) - lst); if (dt < -12.0) dt += 24.0; if (dt > 12.0) dt -= 24.0; } while (++i < MAXLOOPS && fabs(dt) > MAXERR); /* return codes */ if (i == MAXLOOPS) return (-1); return (fabs(mjd - mjdn) < 0.5 ? 0 : -2); #undef MAXLOOPS #undef MAXERR }
/* fill equatoreal and horizontal op-> fields; stern * * input: lam/bet/rho geocentric mean ecliptic and equinox of day * * algorithm at EOD: * ecl_eq --> ra/dec geocentric mean equatoreal EOD (via mean obliq) * deflect --> ra/dec relativistic deflection * nut_eq --> ra/dec geocentric true equatoreal EOD * ab_eq --> ra/dec geocentric apparent equatoreal EOD * if (PREF_GEO) --> output * ta_par --> ra/dec topocentric apparent equatoreal EOD * if (!PREF_GEO) --> output * hadec_aa --> alt/az topocentric horizontal * refract --> alt/az observed --> output * * algorithm at fixed equinox: * ecl_eq --> ra/dec geocentric mean equatoreal EOD (via mean obliq) * deflect --> ra/dec relativistic deflection [for alt/az only] * nut_eq --> ra/dec geocentric true equatoreal EOD [for aa only] * ab_eq --> ra/dec geocentric apparent equatoreal EOD [for aa only] * ta_par --> ra/dec topocentric apparent equatoreal EOD * precess --> ra/dec topocentric equatoreal fixed equinox [eq only] * --> output * hadec_aa --> alt/az topocentric horizontal * refract --> alt/az observed --> output */ static void cir_pos ( Now *np, double bet, /* geo lat (mean ecliptic of date) */ double lam, /* geo long (mean ecliptic of date) */ double *rho, /* in: geocentric dist in AU; out: geo- or topocentic dist */ Obj *op) /* object to set s_ra/dec as per equinox */ { double ra, dec; /* apparent ra/dec, corrected for nut/ab */ double tra, tdec; /* astrometric ra/dec, no nut/ab */ double lsn, rsn; /* solar geocentric (mean ecliptic of date) */ double ha_in, ha_out; /* local hour angle before/after parallax */ double dec_out; /* declination after parallax */ double dra, ddec; /* parallax correction */ double alt, az; /* current alt, az */ double lst; /* local sidereal time */ double rho_topo; /* topocentric distance in earth radii */ /* convert to equatoreal [mean equator, with mean obliquity] */ ecl_eq (mjed, bet, lam, &ra, &dec); tra = ra; /* keep mean coordinates */ tdec = dec; /* precess and save astrometric coordinates */ if (mjed != epoch) precess (mjed, epoch, &tra, &tdec); op->s_astrora = tra; op->s_astrodec = tdec; /* get sun position */ sunpos(mjed, &lsn, &rsn, NULL); /* allow for relativistic light bending near the sun. * (avoid calling deflect() for the sun itself). */ if (!is_planet(op,SUN) && !is_planet(op,MOON)) deflect (mjed, op->s_hlong, op->s_hlat, lsn, rsn, *rho, &ra, &dec); /* correct ra/dec to form geocentric apparent */ nut_eq (mjed, &ra, &dec); if (!is_planet(op,MOON)) ab_eq (mjed, lsn, &ra, &dec); op->s_gaera = ra; op->s_gaedec = dec; /* find parallax correction for equatoreal coords */ now_lst (np, &lst); ha_in = hrrad(lst) - ra; rho_topo = *rho * MAU/ERAD; /* convert to earth radii */ ta_par (ha_in, dec, lat, elev, &rho_topo, &ha_out, &dec_out); /* transform into alt/az and apply refraction */ hadec_aa (lat, ha_out, dec_out, &alt, &az); refract (pressure, temp, alt, &alt); op->s_alt = alt; op->s_az = az; /* Get parallax differences and apply to apparent or astrometric place * as needed. For the astrometric place, rotating the CORRECTIONS * back from the nutated equator to the mean equator will be * neglected. This is an effect of about 0.1" at moon distance. * We currently don't have an inverse nutation rotation. */ if (pref_get(PREF_EQUATORIAL) == PREF_GEO) { /* no topo corrections to eq. coords */ dra = ddec = 0.0; } else { dra = ha_in - ha_out; /* ra sign is opposite of ha */ ddec = dec_out - dec; *rho = rho_topo * ERAD/MAU; /* return topocentric distance in AU */ ra = ra + dra; dec = dec + ddec; } range(&ra, 2*PI); op->s_ra = ra; op->s_dec = dec; }
static int obj_fixed (Now *np, Obj *op) { double lsn, rsn; /* true geoc lng of sun, dist from sn to earth*/ double lam, bet; /* geocentric ecliptic long and lat */ double ha; /* local hour angle */ double el; /* elongation */ double alt, az; /* current alt, az */ double ra, dec; /* ra and dec at equinox of date */ double rpm, dpm; /* astrometric ra and dec with PM to now */ double lst; /* on the assumption that the user will stick with their chosen display * epoch for a while, we move the defining values to match and avoid * precession for every call until it is changed again. * N.B. only compare and store jd's to lowest precission (f_epoch). * N.B. maintaining J2k ref (which is arbitrary) helps avoid accum err */ if (0 /* disabled in PyEphem */ && epoch != EOD && epoch != op->f_epoch) { double pr = op->f_RA, pd = op->f_dec, fe = epoch; /* first bring back to 2k */ precess (op->f_epoch, J2000, &pr, &pd); pr += op->f_pmRA*(J2000-op->f_epoch); pd += op->f_pmdec*(J2000-op->f_epoch); /* then to epoch */ pr += op->f_pmRA*(fe-J2000); pd += op->f_pmdec*(fe-J2000); precess (J2000, fe, &pr, &pd); op->f_RA = pr; op->f_dec = pd; op->f_epoch = fe; } /* apply proper motion .. assume pm epoch reference equals equinox */ rpm = op->f_RA + op->f_pmRA*(mjd-op->f_epoch); dpm = op->f_dec + op->f_pmdec*(mjd-op->f_epoch); /* set ra/dec to astrometric @ equinox of date */ ra = rpm; dec = dpm; if (op->f_epoch != mjed) precess (op->f_epoch, mjed, &ra, &dec); /* compute astrometric @ requested equinox */ op->s_astrora = rpm; op->s_astrodec = dpm; if (op->f_epoch != epoch) precess (op->f_epoch, epoch, &op->s_astrora, &op->s_astrodec); /* convert equatoreal ra/dec to mean geocentric ecliptic lat/long */ eq_ecl (mjed, ra, dec, &bet, &lam); /* find solar ecliptical long.(mean equinox) and distance from earth */ sunpos (mjed, &lsn, &rsn, NULL); /* allow for relativistic light bending near the sun */ deflect (mjed, lam, bet, lsn, rsn, 1e10, &ra, &dec); /* TODO: correction for annual parallax would go here */ /* correct EOD equatoreal for nutation/aberation to form apparent * geocentric */ nut_eq(mjed, &ra, &dec); ab_eq(mjed, lsn, &ra, &dec); op->s_gaera = ra; op->s_gaedec = dec; /* set s_ra/dec -- apparent */ op->s_ra = ra; op->s_dec = dec; /* compute elongation from ecliptic long/lat and sun geocentric long */ elongation (lam, bet, lsn, &el); el = raddeg(el); op->s_elong = (float)el; /* these are really the same fields ... op->s_mag = op->f_mag; op->s_size = op->f_size; */ /* alt, az: correct for refraction; use eod ra/dec. */ now_lst (np, &lst); ha = hrrad(lst) - ra; hadec_aa (lat, ha, dec, &alt, &az); refract (pressure, temp, alt, &alt); op->s_alt = alt; op->s_az = az; return (0); }
/* find where and when an object, op, will rise and set and * it's transit circumstances. all times are utc mjd, angles rads e of n. * dis is the angle down from an ideal horizon, in rads (see riset()). * N.B. dis should NOT include refraction, we do that here. */ void riset_cir (Now *np, Obj *op, double dis, RiseSet *rp) { double mjdn; /* mjd of local noon */ double lstn; /* lst at local noon */ double lr, ls; /* lst rise/set times */ double ar, as; /* az of rise/set */ double ran; /* RA at noon */ Now n; /* copy to move time around */ Obj o; /* copy to get circumstances at n */ int rss; /* temp status */ /* work with local copies so we can move the time around */ (void) memcpy ((void *)&n, (void *)np, sizeof(n)); (void) memcpy ((void *)&o, (void *)op, sizeof(o)); /* fast Earth satellites need a different approach. * "fast" here is pretty arbitrary -- just too fast to work with the * iterative approach based on refining the times for a "fixed" object. */ if (op->o_type == EARTHSAT && op->es_n > FAST_SAT_RPD) { e_riset_cir (&n, &o, dis, rp); return; } /* assume no problems initially */ rp->rs_flags = 0; /* start the iteration at local noon */ mjdn = mjd_day(mjd - tz/24.0) + tz/24.0 + 0.5; n.n_mjd = mjdn; now_lst (&n, &lstn); /* first approximation is to find rise/set times of a fixed object * at the current epoch in its position at local noon. * N.B. add typical refraction if dis is above horizon for initial * go/no-go test. if it passes, real code does refraction rigorously. */ n.n_mjd = mjdn; if (obj_cir (&n, &o) < 0) { rp->rs_flags = RS_ERROR; return; } ran = o.s_gaera; riset (o.s_gaera, o.s_gaedec, lat, dis+(dis>.01 ? 0 : .01), &lr, &ls, &ar, &as, &rss); switch (rss) { case 0: break; case 1: rp->rs_flags = RS_NEVERUP; return; case -1: rp->rs_flags = RS_CIRCUMPOLAR; goto dotransit; default: rp->rs_flags = RS_ERROR; return; } /* iterate to find better rise time */ n.n_mjd = mjdn; switch (find_0alt ((lr - lstn)/SIDRATE, dis, &n, &o)) { case 0: /* ok */ rp->rs_risetm = n.n_mjd; rp->rs_riseaz = o.s_az; break; case -1: /* obj_cir error */ rp->rs_flags |= RS_RISERR; break; case -2: /* converged but not today, err but give times anyway */ rp->rs_risetm = n.n_mjd; rp->rs_riseaz = o.s_az; rp->rs_flags |= RS_NORISE; break; case -3: /* probably never up */ rp->rs_flags |= RS_NEVERUP; break; } /* iterate to find better set time */ n.n_mjd = mjdn; switch (find_0alt ((ls - lstn)/SIDRATE, dis, &n, &o)) { case 0: /* ok */ rp->rs_settm = n.n_mjd; rp->rs_setaz = o.s_az; break; case -1: /* obj_cir error */ rp->rs_flags |= RS_SETERR; break; case -2: /* converged but not today, err but give times anyway */ rp->rs_settm = n.n_mjd; rp->rs_setaz = o.s_az; rp->rs_flags |= RS_NOSET; break; case -3: /* probably circumpolar */ rp->rs_flags |= RS_CIRCUMPOLAR; break; } /* can try transit even if rise or set failed */ dotransit: n.n_mjd = mjdn; switch (find_transit ((radhr(ran) - lstn)/SIDRATE, &n, &o)) { case 0: /* ok */ rp->rs_trantm = n.n_mjd; rp->rs_tranalt = o.s_alt; break; case -1: /* did not converge */ rp->rs_flags |= RS_TRANSERR; break; case -2: /* converged but not today */ rp->rs_flags |= RS_NOTRANS; break; } }