meteortools.utils.Math
1# Various maths functions scraped from WMPL 2 3import numpy as np 4import math 5from datetime import datetime, timedelta, MINYEAR 6# Copyright (C) 2018-2023 Mark McIntyre 7 8# Define Julian epoch 9JULIAN_EPOCH = datetime(2000, 1, 1, 12) # J2000.0 noon 10J2000_JD = timedelta(2451545) # J2000.0 epoch in julian days 11 12 13def jd2Date(jd, UT_corr=0, dt_obj=False): 14 """ Converts the given Julian date to (year, month, day, hour, minute, second, millisecond) tuple or a datetime. 15 16 Arguments: 17 jd: [float] Julian date 18 19 Keyword arguments: 20 UT_corr: [float] UT correction in hours (difference from local time to UT) 21 dt_obj: [bool] returns a datetime object if True. False by default. 22 23 Return: 24 (year, month, day, hour, minute, second, millisecond) or a datetime 25 26 """ 27 28 try: 29 30 dt = timedelta(days=jd) 31 32 date = dt + JULIAN_EPOCH - J2000_JD + timedelta(hours=UT_corr) 33 34 # If the date is out of range (i.e. before year 1) use year 1. This is the limitation in the datetime 35 # library. Time handling should be switched to astropy.time 36 except OverflowError: 37 date = datetime(MINYEAR, 1, 1, 0, 0, 0) 38 39 40 # Return a datetime object if dt_obj == True 41 if dt_obj: 42 return date 43 44 return date.year, date.month, date.day, date.hour, date.minute, date.second, date.microsecond/1000.0 45 46 47def datetime2JD(dt): 48 """ Convert a datetime to a julian date 49 """ 50 51 return date2JD(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond/1000.0) 52 53 54def date2JD(year, month, day, hour, minute, second, millisecond=0, UT_corr=0.0): 55 """ Convert date and time to Julian Date in J2000.0. 56 57 Arguments: 58 year: [int] year 59 month: [int] month 60 day: [int] day of the date 61 hour: [int] hours 62 minute: [int] minutes 63 second: [int] seconds 64 65 Kwargs: 66 millisecond: [int] milliseconds (optional) 67 UT_corr: [float] UT correction in hours (difference from local time to UT) 68 69 Return: 70 [float] julian date, J2000.0 epoch 71 """ 72 73 # Convert all input arguments to integer (except milliseconds) 74 year, month, day, hour, minute, second = map(int, (year, month, day, hour, minute, second)) 75 76 # Create datetime object of current time 77 dt = datetime(year, month, day, hour, minute, second, int(millisecond*1000)) 78 79 # Calculate Julian date 80 julian = dt - JULIAN_EPOCH + J2000_JD - timedelta(hours=UT_corr) 81 82 # Convert seconds to day fractions 83 return julian.days + (julian.seconds + julian.microseconds/1000000.0)/86400.0 84 85 86def jd2LST(julian_date, lon): 87 """ Convert Julian date to Local Sidereal Time and Greenwich Sidereal Time. The times used are apparent 88 times, not mean times. 89 90 Source: J. Meeus: Astronomical Algorithms 91 92 Arguments: 93 julian_date: [float] decimal julian date, epoch J2000.0 94 lon: [float] longitude of the observer in degrees 95 96 Return: 97 (LST, GST): [tuple of floats] a tuple of Local Sidereal Time and Greenwich Sidereal Time 98 """ 99 100 # t = (julian_date - J2000_JD.days)/36525.0 101 102 # Greenwich Sidereal Time 103 #GST = 280.46061837 + 360.98564736629*(julian_date - J2000_JD.days) + 0.000387933*t**2 - (t**3)/38710000 104 #GST = (GST + 360)%360 105 106 GST = np.degrees(calcApparentSiderealEarthRotation(julian_date)) 107 108 # Local Sidereal Time 109 LST = (GST + lon + 360) % 360 110 111 return LST, GST 112 113 114def jd2DynamicalTimeJD(jd): 115 """ Converts the given Julian date to dynamical time (i.e. Terrestrial Time, TT) Julian date. The 116 conversion takes care of leap seconds. 117 118 Arguments: 119 jd: [float] Julian date. 120 121 Return: 122 [float] Dynamical time Julian date. 123 """ 124 125 # Leap seconds as of 2017 (default) 126 leap_secs = 37.0 127 128 129 # Get the relevant number of leap seconds for the given JD 130 # COMMENTED OUT as tai-utc.dat is empty 131 #for jd_leap, ls in config.leap_seconds: 132 # 133 # if jd > jd_leap: 134 # leap_secs = ls 135 136 137 # Calculate the dynamical JD 138 jd_dyn = jd + (leap_secs + 32.184)/86400.0 139 140 141 return jd_dyn 142 143 144def greatCircleDistance(lat1, lon1, lat2, lon2): 145 """ Calculate the great circle distance in kilometers between two points on the Earth. 146 Source: https://gis.stackexchange.com/a/56589/15183 147 148 Arguments: 149 lat1: [float] Latitude 1 (radians). 150 lon1: [float] Longitude 1 (radians). 151 lat2: [float] Latitude 2 (radians). 152 lon2: [float] Longitude 2 (radians). 153 154 Return: 155 [float]: Distance in kilometers. 156 """ 157 158 # Haversine formula 159 dlon = lon2 - lon1 160 dlat = lat2 - lat1 161 162 a = np.sin(dlat/2)**2 + np.cos(lat1)*np.cos(lat2)*np.sin(dlon/2)**2 163 c = 2*np.arcsin(np.sqrt(a)) 164 165 # Distance in kilometers. 166 dist = 6371*c 167 168 return dist 169 170 171def angleBetweenSphericalCoords(phi1, lambda1, phi2, lambda2): 172 """ Calculates the angle between two points on a sphere. 173 174 Arguments: 175 phi1: [float] Latitude 1 (radians). 176 lambda1: [float] Longitude 1 (radians). 177 phi2: [float] Latitude 2 (radians). 178 lambda2: [float] Longitude 2 (radians). 179 180 Return: 181 [float] Angle between two coordinates (radians). 182 """ 183 184 return np.arccos(np.sin(phi1)*np.sin(phi2) + np.cos(phi1)*np.cos(phi2)*np.cos(lambda2 - lambda1)) 185 186 187def equatorialCoordPrecession(start_epoch, final_epoch, ra, dec): 188 """ Precess right Ascension and declination from one epoch to another, taking only precession into 189 account. 190 191 Implemented from: Jean Meeus - Astronomical Algorithms, 2nd edition, pages 134-135 192 193 Arguments: 194 start_epoch: [float] Julian date of the starting epoch 195 final_epoch: [float] Julian date of the final epoch 196 ra: [float] non-corrected right ascension in radians 197 dec: [float] non-corrected declination in radians 198 199 Return: 200 (ra, dec): [tuple of floats] precessed equatorial coordinates in radians 201 202 """ 203 204 205 T = (start_epoch - J2000_JD.days)/36525.0 206 t = (final_epoch - start_epoch)/36525.0 207 208 # Calculate correction parameters 209 zeta = ((2306.2181 + 1.39656*T - 0.000139*T**2)*t + (0.30188 - 0.000344*T)*t**2 + 0.017998*t**3)/3600 210 z = ((2306.2181 + 1.39656*T - 0.000139*T**2)*t + (1.09468 + 0.000066*T)*t**2 + 0.018203*t**3)/3600 211 theta = ((2004.3109 - 0.85330*T - 0.000217*T**2)*t - (0.42665 + 0.000217*T)*t**2 - 0.041833*t**3)/3600 212 213 # Convert parameters to radians 214 zeta, z, theta = map(math.radians, (zeta, z, theta)) 215 216 # Calculate the next set of parameters 217 A = np.cos(dec) * np.sin(ra + zeta) 218 B = np.cos(theta)* np.cos(dec) * np.cos(ra + zeta) - np.sin(theta) * np.sin(dec) 219 C = np.sin(theta)* np.cos(dec) * np.cos(ra + zeta) + np.cos(theta) * np.sin(dec) 220 221 # Calculate right ascension 222 ra_corr = np.arctan2(A, B) + z 223 224 # Calculate declination (apply a different equation if close to the pole, closer then 0.5 degrees) 225 if (np.pi/2 - np.abs(dec)) < np.radians(0.5): 226 dec_corr = np.sign(C)*np.arccos(np.sqrt(A**2 + B**2)) 227 else: 228 dec_corr = np.arcsin(C) 229 230 # Wrap right ascension to [0, 2*pi] range 231 ra_corr = ra_corr % (2*np.pi) 232 233 # Wrap declination to [-pi/2, pi/2] range 234 dec_corr = (dec_corr + np.pi/2) % np.pi - np.pi/2 235 236 return ra_corr, dec_corr 237 238 239equatorialCoordPrecession_vect = np.vectorize(equatorialCoordPrecession, excluded=['start_epoch']) 240"""Vectorize the equatorialCoordPrecession, so ra and dec can be passed as numpy arrays""" 241 242 243def raDec2AltAz(ra, dec, jd, lat, lon): 244 """ Convert right ascension and declination to azimuth (+east of sue north) and altitude. 245 246 Arguments: 247 ra: [float] right ascension in radians 248 dec: [float] declination in radians 249 jd: [float] Julian date 250 lat: [float] latitude in radians 251 lon: [float] longitude in radians 252 253 Return: 254 (azim, elev): [tuple] 255 azim: [float] azimuth (+east of due north) in radians 256 elev: [float] elevation above horizon in radians 257 258 """ 259 260 # Calculate Local Sidereal Time 261 lst = np.radians(jd2LST(jd, np.degrees(lon))[0]) 262 263 # Calculate the hour angle 264 ha = lst - ra 265 266 # Constrain the hour angle to [-pi, pi] range 267 ha = (ha + np.pi) % (2*np.pi) - np.pi 268 269 # Calculate the azimuth 270 azim = np.pi + np.arctan2(np.sin(ha), np.cos(ha)*np.sin(lat) - np.tan(dec)*np.cos(lat)) 271 272 # Calculate the sine of elevation 273 sin_elev = np.sin(lat)*np.sin(dec) + np.cos(lat)*np.cos(dec)*np.cos(ha) 274 275 # Wrap the sine of elevation in the [-1, +1] range 276 sin_elev = (sin_elev + 1) % 2 - 1 277 278 elev = np.arcsin(sin_elev) 279 280 return azim, elev 281 282 283raDec2AltAz_vect = np.vectorize(raDec2AltAz, excluded=['lat', 'lon']) 284"""Vectorize the raDec2AltAz function so it can take numpy arrays for: ra, dec, jd""" 285 286 287def altAz2RADec(azim, elev, jd, lat, lon): 288 """ Convert azimuth and altitude in a given time and position on Earth to right ascension and 289 declination. 290 291 Arguments: 292 azim: [float] azimuth (+east of due north) in radians 293 elev: [float] elevation above horizon in radians 294 jd: [float] Julian date 295 lat: [float] latitude of the observer in radians 296 lon: [float] longitde of the observer in radians 297 298 Return: 299 (RA, dec): [tuple] 300 RA: [float] right ascension (radians) 301 dec: [float] declination (radians) 302 """ 303 304 # Calculate hour angle 305 ha = np.arctan2(-np.sin(azim), np.tan(elev)*np.cos(lat) - np.cos(azim)*np.sin(lat)) 306 307 # Calculate Local Sidereal Time 308 lst = np.radians(jd2LST(jd, np.degrees(lon))[0]) 309 310 # Calculate right ascension 311 ra = (lst - ha) % (2*np.pi) 312 313 # Calculate declination 314 dec = np.arcsin(np.sin(lat)*np.sin(elev) + np.cos(lat)*np.cos(elev)*np.cos(azim)) 315 316 return ra, dec 317 318 319altAz2RADec_vect = np.vectorize(altAz2RADec, excluded=['lat', 'lon']) 320""" Vectorize the altAz2RADec function so it can take numpy arrays for: azim, elev, jd """ 321 322 323def calcApparentSiderealEarthRotation(julian_date): 324 """ Calculate apparent sidereal rotation GST of the Earth. 325 326 Calculated according to: 327 Clark, D. L. (2010). Searching for fireball pre-detections in sky surveys. The School of Graduate and 328 Postdoctoral Studies. University of Western Ontario, London, Ontario, Canada, MSc Thesis. 329 330 """ 331 332 t = (julian_date - J2000_JD.days)/36525.0 333 334 # Calculate the Mean sidereal rotation of the Earth in radians (Greenwich Sidereal Time) 335 GST = 280.46061837 + 360.98564736629*(julian_date - J2000_JD.days) + 0.000387933*t**2 - (t**3)/38710000 336 GST = (GST + 360) % 360 337 GST = math.radians(GST) 338 339 # print('GST:', np.degrees(GST), 'deg') 340 341 # Calculate the dynamical time JD 342 jd_dyn = jd2DynamicalTimeJD(julian_date) 343 344 345 # Calculate Earth's nutation components 346 delta_psi, delta_eps = calcNutationComponents(jd_dyn) 347 348 # print('Delta Psi:', np.degrees(delta_psi), 'deg') 349 # print('Delta Epsilon:', np.degrees(delta_eps), 'deg') 350 351 352 # Calculate the mean obliquity (in arcsec) 353 u = (jd_dyn - 2451545.0)/3652500.0 354 eps0 = 84381.448 - 4680.93*u - 1.55*u**2 + 1999.25*u**3 - 51.38*u**4 - 249.67*u**5 - 39.05*u**6 \ 355 + 7.12*u**7 + 27.87*u**8 + 5.79*u**9 + 2.45*u**10 356 357 # Convert to radians 358 eps0 /= 3600 359 eps0 = np.radians(eps0) 360 361 # print('Mean obliquity:', np.degrees(eps0), 'deg') 362 363 # Calculate apparent sidereal Earth's rotation 364 app_sid_rot = (GST + delta_psi*math.cos(eps0 + delta_eps)) % (2*math.pi) 365 366 return app_sid_rot 367 368 369def calcNutationComponents(jd_dyn): 370 """ Calculate Earth's nutation components from the given Julian date. 371 372 Source: Meeus (1998) Astronomical algorithms, 2nd edition, chapter 22. 373 374 The precision is limited to 0.5" in nutation in longitude and 0.1" in nutation in obliquity. The errata 375 for the 2nd edition was used to correct the equation for delta_psi. 376 377 Arguments: 378 jd_dyn: [float] Dynamical Julian date. See wmpl.Utils.TrajConversions.jd2DynamicalTimeJD function. 379 380 Return: 381 (delta_psi, delta_eps): [tuple of floats] Differences from mean nutation due to the influence of 382 the Moon and minor effects (radians). 383 """ 384 385 386 T = (jd_dyn - J2000_JD.days)/36525.0 387 388 # # Mean Elongation of the Moon from the Sun 389 # D = 297.85036 + 445267.11148*T - 0.0019142*T**2 + (T**3)/189474 390 391 # # Mean anomaly of the Earth with respect to the Sun 392 # M = 357.52772 + 35999.05034*T - 0.0001603*T**2 - (T**3)/300000 393 394 # # Mean anomaly of the Moon 395 # Mm = 134.96298 + 477198.867398*T + 0.0086972*T**2 + (T**3)/56250 396 397 # # Argument of latitude of the Moon 398 # F = 93.27191 + 483202.017538*T - 0.0036825*T**2 + (T**3)/327270 399 400 401 # Longitude of the ascending node of the Moon's mean orbit on the ecliptic, measured from the mean equinox 402 # of the date 403 omega = 125.04452 - 1934.136261*T 404 405 406 # Mean longitude of the Sun (deg) 407 L = 280.4665 + 36000.7698*T 408 409 # Mean longitude of the Moon (deg) 410 Ll = 218.3165 + 481267.8813*T 411 412 413 # Nutation in longitude 414 delta_psi = -17.2*math.sin(math.radians(omega)) - 1.32*math.sin(np.radians(2*L)) \ 415 - 0.23*math.sin(math.radians(2*Ll)) + 0.21*math.sin(math.radians(2*omega)) 416 417 # Nutation in obliquity 418 delta_eps = 9.2*math.cos(math.radians(omega)) + 0.57*math.cos(math.radians(2*L)) \ 419 + 0.1*math.cos(math.radians(2*Ll)) - 0.09*math.cos(math.radians(2*omega)) 420 421 422 # Convert to radians 423 delta_psi = np.radians(delta_psi/3600) 424 delta_eps = np.radians(delta_eps/3600) 425 426 return delta_psi, delta_eps
14def jd2Date(jd, UT_corr=0, dt_obj=False): 15 """ Converts the given Julian date to (year, month, day, hour, minute, second, millisecond) tuple or a datetime. 16 17 Arguments: 18 jd: [float] Julian date 19 20 Keyword arguments: 21 UT_corr: [float] UT correction in hours (difference from local time to UT) 22 dt_obj: [bool] returns a datetime object if True. False by default. 23 24 Return: 25 (year, month, day, hour, minute, second, millisecond) or a datetime 26 27 """ 28 29 try: 30 31 dt = timedelta(days=jd) 32 33 date = dt + JULIAN_EPOCH - J2000_JD + timedelta(hours=UT_corr) 34 35 # If the date is out of range (i.e. before year 1) use year 1. This is the limitation in the datetime 36 # library. Time handling should be switched to astropy.time 37 except OverflowError: 38 date = datetime(MINYEAR, 1, 1, 0, 0, 0) 39 40 41 # Return a datetime object if dt_obj == True 42 if dt_obj: 43 return date 44 45 return date.year, date.month, date.day, date.hour, date.minute, date.second, date.microsecond/1000.0
Converts the given Julian date to (year, month, day, hour, minute, second, millisecond) tuple or a datetime.
Arguments:
jd: [float] Julian date
Keyword arguments:
UT_corr: [float] UT correction in hours (difference from local time to UT)
dt_obj: [bool] returns a datetime object if True. False by default.
Return:
(year, month, day, hour, minute, second, millisecond) or a datetime
48def datetime2JD(dt): 49 """ Convert a datetime to a julian date 50 """ 51 52 return date2JD(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond/1000.0)
Convert a datetime to a julian date
55def date2JD(year, month, day, hour, minute, second, millisecond=0, UT_corr=0.0): 56 """ Convert date and time to Julian Date in J2000.0. 57 58 Arguments: 59 year: [int] year 60 month: [int] month 61 day: [int] day of the date 62 hour: [int] hours 63 minute: [int] minutes 64 second: [int] seconds 65 66 Kwargs: 67 millisecond: [int] milliseconds (optional) 68 UT_corr: [float] UT correction in hours (difference from local time to UT) 69 70 Return: 71 [float] julian date, J2000.0 epoch 72 """ 73 74 # Convert all input arguments to integer (except milliseconds) 75 year, month, day, hour, minute, second = map(int, (year, month, day, hour, minute, second)) 76 77 # Create datetime object of current time 78 dt = datetime(year, month, day, hour, minute, second, int(millisecond*1000)) 79 80 # Calculate Julian date 81 julian = dt - JULIAN_EPOCH + J2000_JD - timedelta(hours=UT_corr) 82 83 # Convert seconds to day fractions 84 return julian.days + (julian.seconds + julian.microseconds/1000000.0)/86400.0
Convert date and time to Julian Date in J2000.0.
Arguments:
year: [int] year
month: [int] month
day: [int] day of the date
hour: [int] hours
minute: [int] minutes
second: [int] seconds
Kwargs:
millisecond: [int] milliseconds (optional)
UT_corr: [float] UT correction in hours (difference from local time to UT)
Return:
[float] julian date, J2000.0 epoch
87def jd2LST(julian_date, lon): 88 """ Convert Julian date to Local Sidereal Time and Greenwich Sidereal Time. The times used are apparent 89 times, not mean times. 90 91 Source: J. Meeus: Astronomical Algorithms 92 93 Arguments: 94 julian_date: [float] decimal julian date, epoch J2000.0 95 lon: [float] longitude of the observer in degrees 96 97 Return: 98 (LST, GST): [tuple of floats] a tuple of Local Sidereal Time and Greenwich Sidereal Time 99 """ 100 101 # t = (julian_date - J2000_JD.days)/36525.0 102 103 # Greenwich Sidereal Time 104 #GST = 280.46061837 + 360.98564736629*(julian_date - J2000_JD.days) + 0.000387933*t**2 - (t**3)/38710000 105 #GST = (GST + 360)%360 106 107 GST = np.degrees(calcApparentSiderealEarthRotation(julian_date)) 108 109 # Local Sidereal Time 110 LST = (GST + lon + 360) % 360 111 112 return LST, GST
Convert Julian date to Local Sidereal Time and Greenwich Sidereal Time. The times used are apparent times, not mean times.
Source: J. Meeus: Astronomical Algorithms
Arguments:
julian_date: [float] decimal julian date, epoch J2000.0
lon: [float] longitude of the observer in degrees
Return:
(LST, GST): [tuple of floats] a tuple of Local Sidereal Time and Greenwich Sidereal Time
115def jd2DynamicalTimeJD(jd): 116 """ Converts the given Julian date to dynamical time (i.e. Terrestrial Time, TT) Julian date. The 117 conversion takes care of leap seconds. 118 119 Arguments: 120 jd: [float] Julian date. 121 122 Return: 123 [float] Dynamical time Julian date. 124 """ 125 126 # Leap seconds as of 2017 (default) 127 leap_secs = 37.0 128 129 130 # Get the relevant number of leap seconds for the given JD 131 # COMMENTED OUT as tai-utc.dat is empty 132 #for jd_leap, ls in config.leap_seconds: 133 # 134 # if jd > jd_leap: 135 # leap_secs = ls 136 137 138 # Calculate the dynamical JD 139 jd_dyn = jd + (leap_secs + 32.184)/86400.0 140 141 142 return jd_dyn
Converts the given Julian date to dynamical time (i.e. Terrestrial Time, TT) Julian date. The conversion takes care of leap seconds.
Arguments:
jd: [float] Julian date.
Return:
[float] Dynamical time Julian date.
145def greatCircleDistance(lat1, lon1, lat2, lon2): 146 """ Calculate the great circle distance in kilometers between two points on the Earth. 147 Source: https://gis.stackexchange.com/a/56589/15183 148 149 Arguments: 150 lat1: [float] Latitude 1 (radians). 151 lon1: [float] Longitude 1 (radians). 152 lat2: [float] Latitude 2 (radians). 153 lon2: [float] Longitude 2 (radians). 154 155 Return: 156 [float]: Distance in kilometers. 157 """ 158 159 # Haversine formula 160 dlon = lon2 - lon1 161 dlat = lat2 - lat1 162 163 a = np.sin(dlat/2)**2 + np.cos(lat1)*np.cos(lat2)*np.sin(dlon/2)**2 164 c = 2*np.arcsin(np.sqrt(a)) 165 166 # Distance in kilometers. 167 dist = 6371*c 168 169 return dist
Calculate the great circle distance in kilometers between two points on the Earth. Source: https://gis.stackexchange.com/a/56589/15183
Arguments:
lat1: [float] Latitude 1 (radians).
lon1: [float] Longitude 1 (radians).
lat2: [float] Latitude 2 (radians).
lon2: [float] Longitude 2 (radians).
Return:
[float]: Distance in kilometers.
172def angleBetweenSphericalCoords(phi1, lambda1, phi2, lambda2): 173 """ Calculates the angle between two points on a sphere. 174 175 Arguments: 176 phi1: [float] Latitude 1 (radians). 177 lambda1: [float] Longitude 1 (radians). 178 phi2: [float] Latitude 2 (radians). 179 lambda2: [float] Longitude 2 (radians). 180 181 Return: 182 [float] Angle between two coordinates (radians). 183 """ 184 185 return np.arccos(np.sin(phi1)*np.sin(phi2) + np.cos(phi1)*np.cos(phi2)*np.cos(lambda2 - lambda1))
Calculates the angle between two points on a sphere.
Arguments:
phi1: [float] Latitude 1 (radians).
lambda1: [float] Longitude 1 (radians).
phi2: [float] Latitude 2 (radians).
lambda2: [float] Longitude 2 (radians).
Return:
[float] Angle between two coordinates (radians).
188def equatorialCoordPrecession(start_epoch, final_epoch, ra, dec): 189 """ Precess right Ascension and declination from one epoch to another, taking only precession into 190 account. 191 192 Implemented from: Jean Meeus - Astronomical Algorithms, 2nd edition, pages 134-135 193 194 Arguments: 195 start_epoch: [float] Julian date of the starting epoch 196 final_epoch: [float] Julian date of the final epoch 197 ra: [float] non-corrected right ascension in radians 198 dec: [float] non-corrected declination in radians 199 200 Return: 201 (ra, dec): [tuple of floats] precessed equatorial coordinates in radians 202 203 """ 204 205 206 T = (start_epoch - J2000_JD.days)/36525.0 207 t = (final_epoch - start_epoch)/36525.0 208 209 # Calculate correction parameters 210 zeta = ((2306.2181 + 1.39656*T - 0.000139*T**2)*t + (0.30188 - 0.000344*T)*t**2 + 0.017998*t**3)/3600 211 z = ((2306.2181 + 1.39656*T - 0.000139*T**2)*t + (1.09468 + 0.000066*T)*t**2 + 0.018203*t**3)/3600 212 theta = ((2004.3109 - 0.85330*T - 0.000217*T**2)*t - (0.42665 + 0.000217*T)*t**2 - 0.041833*t**3)/3600 213 214 # Convert parameters to radians 215 zeta, z, theta = map(math.radians, (zeta, z, theta)) 216 217 # Calculate the next set of parameters 218 A = np.cos(dec) * np.sin(ra + zeta) 219 B = np.cos(theta)* np.cos(dec) * np.cos(ra + zeta) - np.sin(theta) * np.sin(dec) 220 C = np.sin(theta)* np.cos(dec) * np.cos(ra + zeta) + np.cos(theta) * np.sin(dec) 221 222 # Calculate right ascension 223 ra_corr = np.arctan2(A, B) + z 224 225 # Calculate declination (apply a different equation if close to the pole, closer then 0.5 degrees) 226 if (np.pi/2 - np.abs(dec)) < np.radians(0.5): 227 dec_corr = np.sign(C)*np.arccos(np.sqrt(A**2 + B**2)) 228 else: 229 dec_corr = np.arcsin(C) 230 231 # Wrap right ascension to [0, 2*pi] range 232 ra_corr = ra_corr % (2*np.pi) 233 234 # Wrap declination to [-pi/2, pi/2] range 235 dec_corr = (dec_corr + np.pi/2) % np.pi - np.pi/2 236 237 return ra_corr, dec_corr
Precess right Ascension and declination from one epoch to another, taking only precession into account.
Implemented from: Jean Meeus - Astronomical Algorithms, 2nd edition, pages 134-135
Arguments:
start_epoch: [float] Julian date of the starting epoch
final_epoch: [float] Julian date of the final epoch
ra: [float] non-corrected right ascension in radians
dec: [float] non-corrected declination in radians
Return:
(ra, dec): [tuple of floats] precessed equatorial coordinates in radians
Vectorize the equatorialCoordPrecession, so ra and dec can be passed as numpy arrays
244def raDec2AltAz(ra, dec, jd, lat, lon): 245 """ Convert right ascension and declination to azimuth (+east of sue north) and altitude. 246 247 Arguments: 248 ra: [float] right ascension in radians 249 dec: [float] declination in radians 250 jd: [float] Julian date 251 lat: [float] latitude in radians 252 lon: [float] longitude in radians 253 254 Return: 255 (azim, elev): [tuple] 256 azim: [float] azimuth (+east of due north) in radians 257 elev: [float] elevation above horizon in radians 258 259 """ 260 261 # Calculate Local Sidereal Time 262 lst = np.radians(jd2LST(jd, np.degrees(lon))[0]) 263 264 # Calculate the hour angle 265 ha = lst - ra 266 267 # Constrain the hour angle to [-pi, pi] range 268 ha = (ha + np.pi) % (2*np.pi) - np.pi 269 270 # Calculate the azimuth 271 azim = np.pi + np.arctan2(np.sin(ha), np.cos(ha)*np.sin(lat) - np.tan(dec)*np.cos(lat)) 272 273 # Calculate the sine of elevation 274 sin_elev = np.sin(lat)*np.sin(dec) + np.cos(lat)*np.cos(dec)*np.cos(ha) 275 276 # Wrap the sine of elevation in the [-1, +1] range 277 sin_elev = (sin_elev + 1) % 2 - 1 278 279 elev = np.arcsin(sin_elev) 280 281 return azim, elev
Convert right ascension and declination to azimuth (+east of sue north) and altitude.
Arguments:
ra: [float] right ascension in radians
dec: [float] declination in radians
jd: [float] Julian date
lat: [float] latitude in radians
lon: [float] longitude in radians
Return:
(azim, elev): [tuple]
azim: [float] azimuth (+east of due north) in radians
elev: [float] elevation above horizon in radians
Vectorize the raDec2AltAz function so it can take numpy arrays for: ra, dec, jd
288def altAz2RADec(azim, elev, jd, lat, lon): 289 """ Convert azimuth and altitude in a given time and position on Earth to right ascension and 290 declination. 291 292 Arguments: 293 azim: [float] azimuth (+east of due north) in radians 294 elev: [float] elevation above horizon in radians 295 jd: [float] Julian date 296 lat: [float] latitude of the observer in radians 297 lon: [float] longitde of the observer in radians 298 299 Return: 300 (RA, dec): [tuple] 301 RA: [float] right ascension (radians) 302 dec: [float] declination (radians) 303 """ 304 305 # Calculate hour angle 306 ha = np.arctan2(-np.sin(azim), np.tan(elev)*np.cos(lat) - np.cos(azim)*np.sin(lat)) 307 308 # Calculate Local Sidereal Time 309 lst = np.radians(jd2LST(jd, np.degrees(lon))[0]) 310 311 # Calculate right ascension 312 ra = (lst - ha) % (2*np.pi) 313 314 # Calculate declination 315 dec = np.arcsin(np.sin(lat)*np.sin(elev) + np.cos(lat)*np.cos(elev)*np.cos(azim)) 316 317 return ra, dec
Convert azimuth and altitude in a given time and position on Earth to right ascension and declination.
Arguments:
azim: [float] azimuth (+east of due north) in radians
elev: [float] elevation above horizon in radians
jd: [float] Julian date
lat: [float] latitude of the observer in radians
lon: [float] longitde of the observer in radians
Return:
(RA, dec): [tuple]
RA: [float] right ascension (radians)
dec: [float] declination (radians)
Vectorize the altAz2RADec function so it can take numpy arrays for: azim, elev, jd
324def calcApparentSiderealEarthRotation(julian_date): 325 """ Calculate apparent sidereal rotation GST of the Earth. 326 327 Calculated according to: 328 Clark, D. L. (2010). Searching for fireball pre-detections in sky surveys. The School of Graduate and 329 Postdoctoral Studies. University of Western Ontario, London, Ontario, Canada, MSc Thesis. 330 331 """ 332 333 t = (julian_date - J2000_JD.days)/36525.0 334 335 # Calculate the Mean sidereal rotation of the Earth in radians (Greenwich Sidereal Time) 336 GST = 280.46061837 + 360.98564736629*(julian_date - J2000_JD.days) + 0.000387933*t**2 - (t**3)/38710000 337 GST = (GST + 360) % 360 338 GST = math.radians(GST) 339 340 # print('GST:', np.degrees(GST), 'deg') 341 342 # Calculate the dynamical time JD 343 jd_dyn = jd2DynamicalTimeJD(julian_date) 344 345 346 # Calculate Earth's nutation components 347 delta_psi, delta_eps = calcNutationComponents(jd_dyn) 348 349 # print('Delta Psi:', np.degrees(delta_psi), 'deg') 350 # print('Delta Epsilon:', np.degrees(delta_eps), 'deg') 351 352 353 # Calculate the mean obliquity (in arcsec) 354 u = (jd_dyn - 2451545.0)/3652500.0 355 eps0 = 84381.448 - 4680.93*u - 1.55*u**2 + 1999.25*u**3 - 51.38*u**4 - 249.67*u**5 - 39.05*u**6 \ 356 + 7.12*u**7 + 27.87*u**8 + 5.79*u**9 + 2.45*u**10 357 358 # Convert to radians 359 eps0 /= 3600 360 eps0 = np.radians(eps0) 361 362 # print('Mean obliquity:', np.degrees(eps0), 'deg') 363 364 # Calculate apparent sidereal Earth's rotation 365 app_sid_rot = (GST + delta_psi*math.cos(eps0 + delta_eps)) % (2*math.pi) 366 367 return app_sid_rot
Calculate apparent sidereal rotation GST of the Earth.
Calculated according to:
Clark, D. L. (2010). Searching for fireball pre-detections in sky surveys. The School of Graduate and
Postdoctoral Studies. University of Western Ontario, London, Ontario, Canada, MSc Thesis.
370def calcNutationComponents(jd_dyn): 371 """ Calculate Earth's nutation components from the given Julian date. 372 373 Source: Meeus (1998) Astronomical algorithms, 2nd edition, chapter 22. 374 375 The precision is limited to 0.5" in nutation in longitude and 0.1" in nutation in obliquity. The errata 376 for the 2nd edition was used to correct the equation for delta_psi. 377 378 Arguments: 379 jd_dyn: [float] Dynamical Julian date. See wmpl.Utils.TrajConversions.jd2DynamicalTimeJD function. 380 381 Return: 382 (delta_psi, delta_eps): [tuple of floats] Differences from mean nutation due to the influence of 383 the Moon and minor effects (radians). 384 """ 385 386 387 T = (jd_dyn - J2000_JD.days)/36525.0 388 389 # # Mean Elongation of the Moon from the Sun 390 # D = 297.85036 + 445267.11148*T - 0.0019142*T**2 + (T**3)/189474 391 392 # # Mean anomaly of the Earth with respect to the Sun 393 # M = 357.52772 + 35999.05034*T - 0.0001603*T**2 - (T**3)/300000 394 395 # # Mean anomaly of the Moon 396 # Mm = 134.96298 + 477198.867398*T + 0.0086972*T**2 + (T**3)/56250 397 398 # # Argument of latitude of the Moon 399 # F = 93.27191 + 483202.017538*T - 0.0036825*T**2 + (T**3)/327270 400 401 402 # Longitude of the ascending node of the Moon's mean orbit on the ecliptic, measured from the mean equinox 403 # of the date 404 omega = 125.04452 - 1934.136261*T 405 406 407 # Mean longitude of the Sun (deg) 408 L = 280.4665 + 36000.7698*T 409 410 # Mean longitude of the Moon (deg) 411 Ll = 218.3165 + 481267.8813*T 412 413 414 # Nutation in longitude 415 delta_psi = -17.2*math.sin(math.radians(omega)) - 1.32*math.sin(np.radians(2*L)) \ 416 - 0.23*math.sin(math.radians(2*Ll)) + 0.21*math.sin(math.radians(2*omega)) 417 418 # Nutation in obliquity 419 delta_eps = 9.2*math.cos(math.radians(omega)) + 0.57*math.cos(math.radians(2*L)) \ 420 + 0.1*math.cos(math.radians(2*Ll)) - 0.09*math.cos(math.radians(2*omega)) 421 422 423 # Convert to radians 424 delta_psi = np.radians(delta_psi/3600) 425 delta_eps = np.radians(delta_eps/3600) 426 427 return delta_psi, delta_eps
Calculate Earth's nutation components from the given Julian date.
Source: Meeus (1998) Astronomical algorithms, 2nd edition, chapter 22.
The precision is limited to 0.5" in nutation in longitude and 0.1" in nutation in obliquity. The errata for the 2nd edition was used to correct the equation for delta_psi.
Arguments:
jd_dyn: [float] Dynamical Julian date. See wmpl.Utils.TrajConversions.jd2DynamicalTimeJD function.
Return:
(delta_psi, delta_eps): [tuple of floats] Differences from mean nutation due to the influence of
the Moon and minor effects (radians).