def MST(jdnumber): assert isinstance(jdnumber, JulianDayNumber), 'Invalid Julian Day Number' # Number of Julian centuries since J2000 T = (jdnumber.jdn - epoch_j2000.jdn) / julian_century ret_deg = 280.46061837 \ + 360.98564736629*(jdnumber.jdn - epoch_j2000.jdn) \ + (0.000387933 - T/38710000.0)*T*T return Longitude(radians(ret_deg))
def to_altazimuthal(self, lati_, hangle_): assert isinstance(lati_, Latitude), 'lati_ must be a Latitude' assert isinstance(hangle_, Longitude), 'hangle_ must be a Longitude' lati_rad, decl_rad, hangle_rad = lati_.rads, self.b.rads, hangle_.rads azimuth_rad = atan2(sin(hangle_rad), cos(hangle_rad)*sin(lati_rad) \ - tan(decl_rad)*cos(lati_rad)) altitude_rad = asin(sin(lati_rad)*sin(decl_rad) \ + cos(lati_rad)*cos(decl_rad)*cos(hangle_rad)) return AltAzimuthal(Longitude(azimuth_rad), Latitude(altitude_rad))
def to_ecliptical(self, epsilon_): assert isinstance(epsilon_, Angle), 'epsilon_ must be Angle' alpha_rad, delta_rad = self.a.rads, self.b.rads epsilon_rad = epsilon_.rads lambda_rad = atan2( sin(alpha_rad) * cos(epsilon_rad) + tan(delta_rad) * sin(epsilon_rad), cos(alpha_rad)) beta_rad = asin( sin(delta_rad) * cos(epsilon_rad) - cos(delta_rad) * sin(epsilon_rad) * sin(alpha_rad)) return Ecliptical(Longitude(lambda_rad), Latitude(beta_rad))
def to_equatorial(self, epsilon_): assert isinstance(epsilon_, Angle), 'epsilon_ must be Angle' lambda_rad, beta_rad = self.a.rads, self.b.rads epsilon_rad = epsilon_.rads alpha_rad = atan2( sin(lambda_rad) * cos(epsilon_rad) - tan(beta_rad) * sin(epsilon_rad), cos(lambda_rad)) delta_rad = asin( sin(beta_rad) * cos(epsilon_rad) + cos(beta_rad) * sin(epsilon_rad) * sin(lambda_rad)) return Equatorial(Longitude(alpha_rad), Latitude(delta_rad))
def deprecated_precession(coord, epoch_start, epoch_end): """Calculate the precession in the RA and Declination at the ending epoch of a body given the mean coordinates at a starting epoch. @param coord The mean coordinates referred to epoch_start as a Equatorial object @param epoch_start The epoch to which the coord is referred as a Julian Day Number in TD @param epoch_end The epoch for which the new coord is to be computed as a Julian Day Number in TD @return The RA and Declination for epoch_end as a SphCoord object @caution We assume that the coord is already corrected for the proper motion of the body over the epoch interval in question """ assert isinstance(coord, Equatorial), 'coord must be a Equatorial' assert isinstance(epoch_start, JulianDayNumber) \ and isinstance(epoch_end, JulianDayNumber), \ 'epochs much be JulianDayNumbers' T = (epoch_start.jdn - epoch_j2000.jdn) / julian_century t = (epoch_end.jdn - epoch_start.jdn) / julian_century K = (2306.2181 + (1.39656 - 0.000139 * T) * T) * t t_square = t**2 zeta = K + ( (0.30188 - 0.000344 * T) + 0.017998 * t) * t_square # arc-seconds zeta = radians(zeta / 3600.0) zappa = K + ( (1.09468 + 0.000066 * T) + 0.018203 * t) * t_square # arc-seconds zappa = radians(zappa / 3600.0) theta = (2004.3109 - (0.85330 + 0.000217 * T) * T) * t # arc-seconds theta -= ( (0.42665 + 0.000217 * T) + 0.041833 * t) * t_square # arc-seconds theta = radians(theta / 3600.0) alpha = coord.a.rads + zeta delta0 = coord.b.rads A = cos(delta0) * sin(alpha) B = cos(theta) * cos(delta0) * cos(alpha) - sin(theta) * sin(delta0) C = sin(theta) * cos(delta0) * cos(alpha) + cos(theta) * sin(delta0) alpha = zappa + atan2(A, B) # If the object is close to the celestial pole if fabs(delta0 - pi / 2) < radians(0.5): delta = acos(sqrt(A**2 + B**2)) else: delta = asin(C) return Equatorial(Longitude(alpha), Latitude(delta))
def equation_of_kepler_iterative(M_, e_, prec_): """Calculate the Eccentric anomaly from the Mean Anomaly using iteration. @param M_ The Mean anomaly as a Longitude object @param e_ The eccentricity of the orbit @param prec_ The precision at which to stop the iteration @return The Eccentric anomaly as a Longitude object """ assert isinstance(M_, Longitude), 'M_ should be a Longitude' assert isinstance(e_, Number), 'e_ should be a Number' assert 0 <= e_ < 1, 'e_ should lie between 0 and 1' assert isinstance(prec_, Number), 'prec_ should be a Number' E = M_.rads while True: dE = (M_.rads + e_ * sin(E) - E) / (1 - e_ * cos(E)) E += dE if fabs(dE) <= prec_: break return Longitude(E)
def apply_correction(self, coord): assert isinstance(coord, Equatorial), 'coord must be a Equatorial' alpha = coord.a.rads + self.zeta delta0 = coord.b.rads A = cos(delta0)*sin(alpha) B = cos(self.theta)*cos(delta0)*cos(alpha) - sin(self.theta)*sin(delta0) C = sin(self.theta)*cos(delta0)*cos(alpha) + cos(self.theta)*sin(delta0) alpha = self.zappa + atan2(A,B) # If the object is close to the celestial pole if fabs(delta0 - pi/2) < radians(0.5): delta = acos(sqrt(A**2+B**2)) else: delta = asin(C) return Equatorial(Longitude(alpha), Latitude(delta))
def proper_motion_classical(coord, annual_pm, epoch_yrs): """Compute the proper motion using the classical method of uniform changes in RA and declination. @param coord The coordinates of the star as a Equatorial object at the epoch. @param annual_pm The annual proper motion of the star as a tuple of Angles. @param epoch_yrs The number of years from the starting epoch. @return The updated coordinates for the star as an Equatorial object. """ assert isinstance(coord, Equatorial), 'coord should be a Equatorial' assert isinstance(annual_pm, tuple), 'annual_pm should be a tuple' assert len(annual_pm) == 2, 'annual_pm should be a 2-element tuple' assert isinstance(annual_pm[0], Angle) and isinstance(annual_pm[1],Angle), \ 'annual_pm elements should be Angles' alpha_0, delta_0 = coord.a.rads, coord.b.rads dalpha, ddelta = annual_pm[0].rads, annual_pm[1].rads alpha_new = alpha_0 + dalpha * epoch_yrs delta_new = delta_0 + ddelta * epoch_yrs return Equatorial(Longitude(alpha_new), Latitude(delta_new))
def proper_motion(coord, r_parsecs, v_parsecs_per_year, annual_pm, epoch_yrs): """Compute the proper motion of a star over the given number of years. @param coord The coordinates of the star as a Equatorial object at the epoch. @param r_parsecs The radial distance to the star in parsecs. @param v_parsecs_per_year The radial velocity of the star in parsecs/year. @param annual_pm The annual proper motion of the star as a tuple of Angles. @param epoch_yrs The number of years from the starting epoch. @return The updated coordinates for the star as an Equatorial object. """ assert isinstance(coord, Equatorial), 'coord should be a Equatorial' assert isinstance(annual_pm, tuple), 'annual_pm should be a tuple' assert len(annual_pm) == 2, 'annual_pm should be a 2-element tuple' assert isinstance(annual_pm[0], Angle) and isinstance(annual_pm[1],Angle), \ 'annual_pm elements should be Angles' alpha_0, delta_0 = coord.a.rads, coord.b.rads dalpha, ddelta = annual_pm[0].rads, annual_pm[1].rads x = r_parsecs * cos(delta_0) * cos(alpha_0) # parsecs y = r_parsecs * cos(delta_0) * sin(alpha_0) # parsecs z = r_parsecs * sin(delta_0) # parsecs dx = (x / r_parsecs ) * v_parsecs_per_year - z * ddelta * cos(alpha_0) - y * dalpha dy = (y / r_parsecs ) * v_parsecs_per_year - z * ddelta * sin(alpha_0) + x * dalpha dz = (z / r_parsecs) * v_parsecs_per_year + r_parsecs * ddelta * cos(delta_0) # dx,dy,dz are in parsecs/year x_new = x + epoch_yrs * dx # parsecs y_new = y + epoch_yrs * dy # parsecs z_new = z + epoch_yrs * dz # parsecs alpha_new = atan2(y_new, x_new) delta_new = atan2(z_new, sqrt(x_new**2 + y_new**2)) return Equatorial(Longitude(alpha_new), Latitude(delta_new))
def equation_of_kepler_binarysearch(M_, e_, loop_=33): """Calculate the Eccentric anomaly from the Mean Anomaly using binary search. @param M_ The Mean anomaly as a Longitude object @param e_ The eccentricity of the orbit @param loop_ The number of times to @return The Eccentric anomaly as a Longitude object """ assert isinstance(M_, Longitude), 'M_ should be a Longitude' assert isinstance(e_, Number), 'e_ should be a Number' assert 0 <= e_ < 1, 'e_ should lie between 0 and 1' assert type(loop_) is IntType, 'loop_ should be an integer' M_ = pfmod(M_.rads, 2 * pi) if M_ > pi: sign = -1 M_ = 2 * pi - M_ else: sign = 1 E0, D = pi / 2, pi / 4 for idx in range(loop_): M1 = E0 - e * sin(E0) E0 += copysign(D, M_ - M1) D /= 2 E0 *= sign return Longitude(E0)
def get_ecliptical_apparent(self): return Ecliptical(Longitude(self.lambda_apparent), Latitude(0))
def get_ecliptical(self): return Ecliptical(Longitude(self.L), Latitude(0))
def apply_correction(self, coord): assert isinstance(coord, Equatorial), 'coord must be a Equatorial' alpha = coord.a.rads + self.zeta delta0 = coord.b.rads A = cos(delta0)*sin(alpha) B = cos(self.theta)*cos(delta0)*cos(alpha) - sin(self.theta)*sin(delta0) C = sin(self.theta)*cos(delta0)*cos(alpha) + cos(self.theta)*sin(delta0) alpha = self.zappa + atan2(A,B) # If the object is close to the celestial pole if fabs(delta0 - pi/2) < radians(0.5): delta = acos(sqrt(A**2+B**2)) else: delta = asin(C) return Equatorial(Longitude(alpha), Latitude(delta)) if __name__ == "__main__": epoch_start = epoch_j2000 epoch_end = JulianDayNumber(Date(2028,11,13),Time(4,28,0)) prec = Precession(epoch_start, epoch_end) # theta Persei (proper motion corrected) theta_persei_epoch_start = Equatorial( Longitude(radians(41.054063)), Latitude(radians(49.227750)) ) print prec.apply_correction(theta_persei_epoch_start) # 2h46m11.331s, +49deg20'54.54"
star_coords = [copy.copy(star_) for date in dates] return conjunction(dates_, star_coords, coords_, prec_) if __name__ == "__main__": dates = [ JulianDayNumber(Date(1991, 8, 5), Time(0, 0, 0)), JulianDayNumber(Date(1991, 8, 6), Time(0, 0, 0)), JulianDayNumber(Date(1991, 8, 7), Time(0, 0, 0)), JulianDayNumber(Date(1991, 8, 8), Time(0, 0, 0)), JulianDayNumber(Date(1991, 8, 9), Time(0, 0, 0)), ] # Mercury coords1 = [ SphCoord( Longitude(radians((10.0 + 24.0 / 60.0 + 30.125 / 3600.0) * 15)), Latitude(radians(6 + 26.0 / 60.0 + 32.05 / 3600.0))), SphCoord( Longitude(radians((10.0 + 25.0 / 60.0 + 0.342 / 3600.0) * 15)), Latitude(radians(6 + 10.0 / 60.0 + 57.72 / 3600.0))), SphCoord( Longitude(radians((10.0 + 25.0 / 60.0 + 12.515 / 3600.0) * 15)), Latitude(radians(5 + 57.0 / 60.0 + 33.08 / 3600.0))), SphCoord( Longitude(radians((10.0 + 25.0 / 60.0 + 6.235 / 3600.0) * 15)), Latitude(radians(5 + 46.0 / 60.0 + 27.07 / 3600.0))), SphCoord( Longitude(radians((10.0 + 24.0 / 60.0 + 41.185 / 3600.0) * 15)), Latitude(radians(5 + 37.0 / 60.0 + 48.45 / 3600.0))) ] # Venus
D /= 2 E0 *= sign return Longitude(E0) if __name__ == "__main__": ## Refraction tests print refraction(Angle(0)) print refraction(Angle(pi / 4)) print refraction(Angle(pi / 2)) ## Angular Separation Tests # List of (alpha1, delta1, alpha2, delta2) tuples data = [ # sph1 a number (pi / 2, SphCoord(Longitude(pi / 6), Latitude(pi / 3))), # sph2 a tuple (SphCoord(Longitude(pi / 6), Latitude(pi / 3)), (0, pi / 2)), # (0,45), (30,60). Should be just over 23 degrees (SphCoord(Longitude(0), Latitude(pi / 4)), SphCoord(Longitude(pi / 6), Latitude(pi / 3))), # Example 17.a, Arcturus and Spica. (32.7930 degrees) (SphCoord(Longitude(radians(213.9154)), Latitude(radians(19.1825))), SphCoord(Longitude(radians(201.2983)), Latitude(radians(-11.1614)))), ] for item in data: try: sph1, sph2 = item print angular_separation(sph1, sph2) except Exception as e: print 'Error:', e
def get_equatorial(self): return Equatorial(Longitude(self.alpha), Latitude(self.delta))
def get_equatorial_apparent(self): return Equatorial(Longitude(self.alpha_apparent), Latitude(self.delta_apparent))
class AltAzimuthal(SphCoord): def __unicode__(self): return u'(A:' + self.a.dms() + u', h:' + self.b.dms() + u')' def __str__(self): return unicode(self).encode(sys.stdout.encoding or DEFAULT_ENCODING, 'replace') if __name__ == "__main__": ## Spherical Coordinate Tests data = [ (0, pi / 2), # Not Longitudes or Latitudes (Latitude(0), Latitude(pi / 2)), # alpha is not a Longitude (Longitude(0), Longitude(pi / 2)), # delta is not a Latitude (Longitude(0), Angle(pi / 2)) # delta is not a Latitude ] for tup in data: try: sph = SphCoord(tup[0], tup[1]) except AssertionError as e: print 'Error:', e print equa = Equatorial(Longitude(0), Latitude(0)) print equa ecli = equa.to_ecliptical(epsilon_j2000) print ecli print ecli.to_equatorial(epsilon_j2000) print