def __init__(self, dirname: str = "data", ephemerides: str = "de441") -> None: self.load = Loader(dirname) self._ephName = ephemerides if not self._ephName.endswith(".bsp"): self._ephName += ".bsp"
def main(): # Set up and hide tkinter root window root = tk.Tk() root.withdraw() file_path = filedialog.askopenfilename() if not path.exists(file_path): print("Error - no such file") quit() root.destroy() # Load earth position from ephemeris data sfLoader = Loader('resources') ephemeris = sfLoader('de421.bsp') earth = ephemeris['earth'] # Setup timescale for calculating ground track ts = sfLoader.timescale() now = datetime.utcnow() steps = np.arange(0, 180, 1) time = ts.utc(now.year, now.month, now.day, now.hour, steps) # Load satellite data from tle file satellites = sfLoader.tle_file(file_path) # Set up plot plt.figure() img = plt.imread('resources/map.png') plt.imshow(img, extent=[-180, 180, -90, 90]) for sat in satellites: _calculateGroundTrack(earth, sat, time) plt.show()
def _convert_radec_to_altaz(ra, dec, lon, lat, height, time): """Convert a single position. This is done for easy code sharing with other tools. Skyfield does support arrays of positions. """ load = Loader('.') # Skyfield uses FTP URLs, but FTP doesn't work on Github Actions so # we use alternative HTTP URLs. load.urls['finals2000A.all'] = 'https://datacenter.iers.org/data/9/' load.urls['.bsp'] = [ ('*.bsp', 'https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/') ] radec = Star(ra=Angle(degrees=ra), dec=Angle(degrees=dec)) earth = load(EPHEMERIS)['earth'] location = earth + wgs84.latlon(longitude_degrees=lon, latitude_degrees=lat, elevation_m=height * 1000.0) ts = load.timescale(builtin=False) with load.open('finals2000A.all') as f: finals_data = iers.parse_x_y_dut1_from_finals_all(f) iers.install_polar_motion_table(ts, finals_data) obstime = ts.from_astropy(Time(time, scale='utc')) alt, az, _ = location.at(obstime).observe(radec).apparent().altaz( pressure_mbar=0) return dict(az=az.degrees, alt=alt.degrees)
def skyfield_ephem(load_path=None, parallax_correction=False, utc=None): '''Returns skyfield objects used for doing solar planning and conversion. Optional keywords: load_path: Directory location where the bsp files are stored. Defaults to current working directory if None. parallax_corection: Download the latest NuSTAR TLE file and apply the parallax correction based on NuSTAR's position in its orbit. Defaults to "False". If "True" then uses the nustar_pysolar.io TLE methods to parse the closest TLE entry in the NuSTAR database. If you set parallax_correction=True then Returns: observer, sun, ts The first two are Skyfield objects. "observer" is either geocentric or the NuSTAR location based on the TLE. "ts" is the Skyfield time object. ''' # Initialize Skyfield ephemeris tools. from skyfield.api import EarthSatellite, Loader from astropy.time import Time import sunpy.sun if load_path is None: load_path = './' load=Loader(load_path) else: load=Loader(load_path) ts = load.timescale() planets = load('de436.bsp') earth = planets['Earth'] sun = planets['Sun'] if parallax_correction is False: observer = earth else: assert (not utc is None),"Must set UTC when using parallax correction!" import nustar_pysolar.io as io tlefile = io.download_tle(outdir=load_path) mindt, line1, line2 = io.get_epoch_tle(utc, tlefile) nustar = EarthSatellite(line1, line2) observer = earth + nustar ts = load.timescale() return observer, sun, ts
def load_skyfield_data(): """Load data files used in Skyfield. This will download files from the internet if they haven't been downloaded before. Skyfield downloads files to the current directory by default, which is not ideal. Here we abuse astropy and use its cache directory to cache the data files per-user. If we start downloading files in other places in pwkit we should maybe make this system more generic. And the dep on astropy is not at all necessary. Skyfield will print out a progress bar as it downloads things. Returns ``(planets, ts)``, the standard Skyfield ephemeris and timescale data files. """ import os.path from astropy.config import paths from skyfield.api import Loader cache_dir = os.path.join(paths.get_cache_dir(), 'pwkit') loader = Loader(cache_dir) planets = loader('de421.bsp') ts = loader.timescale() return planets, ts
def loadAstronomyData(): if g.astroDataLoaded: return try: from skyfield.api import Loader load = Loader(getUserDataPath(), verbose=False) g.timescale = load.timescale(builtin=False) except OSError: print( 'Downloading the astronomy data failed. Some astronomical functions will not be available.', file=sys.stderr) g.astroDataLoaded = True g.astroDataAvailable = False return try: g.ephemeris = load('de421.bsp') except OSError: print( 'Downloading the astronomy data failed. Some astronomical functions will not be available.', file=sys.stderr) g.astroDataLoaded = True g.astroDataAvailable = False return g.astroDataLoaded = True g.astroDataAvailable = True return
def handle(self, *args, **options): load = Loader(settings.EPHEM_DIR) load('de405.bsp') load.timescale() self.stdout.write( self.style.SUCCESS( f'Successfully downloaded ephemeris files to {settings.EPHEM_DIR}!' ))
def __init__(self, intercept_df=None, sat_df=None): ''' Initialize ''' load = Loader('./data') data = load('de421.bsp') self.timescale = load.timescale() self.intercept_df = intercept_df self.sat_df = sat_df
def generatePlot(): print('Generating Plot') df = pandas.read_csv('../Data/tempCSV.csv') objectID = df.values[1][0][2:7] L1 = df.values[1][0] L2 = df.values[2][0] load = Loader( '~/Documents/fishing/SkyData') # avoids multiple copies of large files ts = load.timescale() data = load('de421.bsp') earth = data['earth'] ts = load.timescale() minutes = np.arange(60. * 24) # seven days time = ts.utc(today.year, today.month, today.day, 0, minutes) # start June 1, 2018 ISS = EarthSatellite(L1, L2) subpoint = ISS.at(time).subpoint() lon = subpoint.longitude.degrees lat = subpoint.latitude.degrees breaks = np.where(np.abs(lon[1:] - lon[:-1]) > 30) #don't plot wrap-around lon, lat = lon[:-1], lat[:-1] lon[breaks] = np.nan my_tweet = 'Ground Track of NORAD ID #' + str( objectID) + ' for the next 24 hours' fig1, ax1 = plt.subplots() earth = mpimg.imread('../Figures/earth.tif') earth = mpimg.imread(earthImg) ax1.imshow(earth) ax1.plot(10800 * (lon / 360 + .5), 5400 * (lat / 180 + 0.5)) plt.axis('off') imgFile = "../Figures/latestGroundTrack.png" plt.savefig(imgFile, dpi=300, bbox_inches='tight', pad_inches=0) fig2, ax2 = plt.subplots() ax2.plot(lon / 360 + .5, lat / 180 - .5) print(lat[0]) if (math.isnan(lat[0])): exitFlag = False else: exitFlag = True return exitFlag, my_tweet
def handle(self, *args, **options): load = Loader(settings.EPHEM_DIR) load("de405.bsp") load.timescale(builtin=True) self.stdout.write( self.style.SUCCESS( f"Successfully downloaded ephemeris files to {settings.EPHEM_DIR}!" ) )
def _load_sky_data(self, tmpdir): """ Load the primary input data for skyfield. This requires a download for the first one, or the inclusion of the data files. """ load = Loader(tmpdir) self._planets = load("de421.bsp") self._ts = load.timescale()
def __init__(self): self._tokenInEnglish = { '_tok_1': 'SWX ADVISORY line', 'test': 'STATUS: TEST', 'exercise': 'STATUS: EXER', 'dtg': 'Date/Time Group', 'centre': 'Issuing SWX Centre', 'advnum': 'YYYY/nnnn', 'prevadvsry': 'Previous Advisory YYYY/nnnn', 'phenomenon': 'SWX Hazard(s)', 'init': '(OBS|FCST) SWX', 'timestamp': 'DD/HHmmZ Group', 'noos': 'NO SWX EXP', 'notavail': 'NOT AVBL', 'daylight': 'DAY(LIGHT)? SIDE', 'lat_band': '(H|M)(N|S)H', 'equator': 'EQ(N|S)', 'longitudes': '(E|W)nnn[nn]-(E|W)nnn[nn]', 'box': 'lat/long bounding box', 'fltlvls': 'ABV FLnnn|FLnnn-nnn', 'fcsthr': 'FCST SWX +nn HR', 'rmk': 'RMK:', 'nextdtg': 'Next advisory issuance date/time', 'noadvisory': 'NO FURTHER ADVISORIES' } self.header = re.compile(r'.*(?=SWX ADVISORY)', re.DOTALL) setattr(self, 'lat_band', self.add_region) setattr(self, 'point', self.add_region) setattr(self, 'equator', self.add_region) self._Logger = logging.getLogger(__name__) # # Preparing Skyfield try: load = Loader(os.path.join(os.path.dirname(__file__), '../data'), verbose=False) self._ts = load.timescale() # # Open NAIF/JPL/NASA SPICE Kernel planets = load('de421.bsp') self._Gaia = planets['earth'] self._Helios = planets['sun'] except Exception: self._Logger.exception( 'Unable to load/initialize Skyfield Module.') raise return super(Decoder, self).__init__()
def __init__(self, parent=None, view=None): """ Arguments: parent -- Qt widget that is parent to this widget. view -- reference to mpl canvas class """ super(RemoteSensingControlWidget, self).__init__(parent) self.setupUi(self) self.view = view self.load_bsp = Loader(skyfield_data.get_skyfield_data_path(), verbose=False) self.planets = self.load_bsp('de421.bsp') self.timescale = self.load_bsp.timescale(builtin=True) button = self.btTangentsColour palette = QtGui.QPalette(button.palette()) colour = QtGui.QColor() colour.setRgbF(1, 0, 0, 1) palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) self.dsbTangentHeight.setValue(10.) self.dsbObsAngleAzimuth.setValue(90.) self.dsbObsAngleElevation.setValue(-1.0) # update plot on every value change self.cbDrawTangents.stateChanged.connect(self.update_settings) self.cbShowSolarAngle.stateChanged.connect(self.update_settings) self.btTangentsColour.clicked.connect(self.set_tangentpoint_colour) self.dsbTangentHeight.valueChanged.connect(self.update_settings) self.dsbObsAngleAzimuth.valueChanged.connect(self.update_settings) self.dsbObsAngleElevation.valueChanged.connect(self.update_settings) self.cbSolarBody.currentIndexChanged.connect(self.update_settings) self.cbSolarAngleType.currentIndexChanged.connect(self.update_settings) self.lbSolarCmap.setText( "Solar angle colours, dark to light: reds (0-15), violets (15-45), greens (45-180)" ) self.solar_cmap = ListedColormap([(1.00, 0.00, 0.00, 1.0), (1.00, 0.45, 0.00, 1.0), (1.00, 0.75, 0.00, 1.0), (0.47, 0.10, 1.00, 1.0), (0.72, 0.38, 1.00, 1.0), (1.00, 0.55, 1.00, 1.0), (0.00, 0.70, 0.00, 1.0), (0.33, 0.85, 0.33, 1.0), (0.65, 1.00, 0.65, 1.0)]) self.solar_norm = BoundaryNorm( [0, 5, 10, 15, 25, 35, 45, 90, 135, 180], self.solar_cmap.N) self.update_settings()
def params_newton_angle(): """ Session-scoped fixture to "cache" the newton angle func parameters """ load = Loader(get_skyfield_data_path()) ts = load.timescale() planets = load('de421.bsp') earth = planets['earth'] sun = planets['sun'] jan_first = ts.utc(date(2021, 1, 1)) t0 = ts.tt_jd(jan_first.tt).tt return t0, ts, earth, sun
def calculate_equinoxes(year, timezone='UTC'): """ calculate equinox with time zone """ tz = pytz.timezone(timezone) load = Loader(get_skyfield_data_path()) ts = load.timescale() planets = load('de421.bsp') t0 = ts.utc(year, 1, 1) t1 = ts.utc(year, 12, 31) datetimes, _ = almanac.find_discrete(t0, t1, almanac.seasons(planets)) vernal_equinox = datetimes[0].astimezone(tz).date() autumn_equinox = datetimes[2].astimezone(tz).date() return vernal_equinox, autumn_equinox
def init_ephem(orbits, load_path=None, show=False, parallax_correction=False): '''Initialize Skyfield ephemeris for Jupiter BSP file Takes output of io.parse_occ as input. Requires Astropy and SkyField Optional: load_path (where the bsp and SkyField data files are found. parllax_correction (apply the parallax correction from NuSTAR's orbit). Downloads the latest TLE archive from the NuSTAR SOC. Returns: observer, jupiter, ts The first two are Skyfield objects. The third is the Skyfield time series object. ''' from skyfield.api import Loader, EarthSatellite from astropy.time import Time if load_path is None: load_path = './' load = Loader(load_path) else: load = Loader(load_path) planets = load('jup310.bsp') jupiter, earth = planets['jupiter'], planets['earth'] ts = load.timescale() if parallax_correction is False: observer = earth else: import nustar_planning.io as io start_date = orbits.loc[0, 'visible'] utc = Time(start_date) tlefile = io.download_tle(outdir=load_path) mindt, line1, line2 = io.get_epoch_tle(utc, tlefile) nustar = EarthSatellite(line1, line2) observer = earth + nustar return observer, jupiter, ts
class StationList: def __init__(self): self._loader = Loader(DATA_PATH) self.update() def update(self): self._tles = {} for es in self._loader.tle_file(URL_TLE, True): self._tles[es.name] = es self._ts = self._loader.timescale() self._stations = self._tles.keys() LOGGER.info("Update StationList, found "+str(len(self._stations))+" items") def list(self): return self._stations def getStation(self, station, from_position): return Station(self._tles[station],self._ts, from_position)
def get_jupiter_radec(orbits, outfile=None): if outfile is not None: f = open(outfile, 'w') from skyfield.api import Loader load = Loader('../data') ts = load.timescale() planets = load('jup310.bsp') jupiter, earth = planets['jupiter'], planets['earth'] for ind in range(len(orbits)): tstart = orbits.loc[ind, 'visible'] tend = orbits.loc[ind, 'occulted'] print() on_time = (tend - tstart).total_seconds() point_time = tstart + 0.5 * (tend - tstart) astro_time = Time(point_time) t = ts.from_astropy(astro_time) astrometric = earth.at(t).observe(jupiter) ra, dec, distance = astrometric.radec() radeg = ra.to(u.deg) decdeg = dec.to(u.deg) dt += on_time print(tstart.isoformat() + ' {} {}'.format(radeg.value, decdeg.value)) if outfile is not None: f.write(tstart.isoformat() + ' {} {}'.format(radeg.value, decdeg.value) + '\n') if outfile is not None: f.close() print('Total accumualted time {}'.format(dt))
def load_ephemerides( cache_dir: str = None, ephemerides_file: str = EPHEMERIDES_FILE ) -> skyfield.jpllib.SpiceKernel: """Load the DE421 ephemeris. Note that the first time this function is called, it will need to download the DE421 epehemeris file from JPL. This file is 17 MB, but the server is a little slow, so it can take about 10 seconds. Subsequently, this data will be cached in `$HOME/.cache/radecbot` and loading will be fast. """ if cache_dir is None: cache_dir = os.path.join(os.getenv('HOME'), '.cache/radecbot') loader = Loader(cache_dir) filename = os.path.join(cache_dir, ephemerides_file) if not os.path.exists(filename): url = loader.build_url(ephemerides_file) loader.download(url, filename) if not os.path.exists(loader.path_to(ephemerides_file)): raise FileNotFoundError( f'Ephemerides file {loader.path_to(ephemerides_file)} not found! ' f'Did the download fail?') return loader(ephemerides_file)
def skyfield_ephem(load_path=None, parallax_correction=False, utc=None): '''Returns skyfield objects used for doing solar planning and conversion. Optional keywords: load_path: Directory location where the bsp files are stored. Defaults to current working directory if None. parallax_corection: Download the latest NuSTAR TLE file and apply the parallax correction based on NuSTAR's position in its orbit. Defaults to "False". If "True" then uses the nustar_pysolar.io TLE methods to parse the closest TLE entry in the NuSTAR database. If you set parallax_correction=True then Returns: observer, sun, ts The first two are Skyfield objects. "observer" is either geocentric or the NuSTAR location based on the TLE. "ts" is the Skyfield time object. ''' # Initialize Skyfield ephemeris tools. from skyfield.api import EarthSatellite, Loader from astropy.time import Time # Not actually used? So just comment out, and so no sunpy v1 issue # import sunpy.sun if load_path is None: load_path = './' load = Loader(load_path) else: load = Loader(load_path) ts = load.timescale() planets = load('de436.bsp') earth = planets['Earth'] sun = planets['Sun'] if parallax_correction is False: observer = earth else: assert ( not utc is None), "Must set UTC when using parallax correction!" import nustar_pysolar.io as io tlefile = io.download_tle(outdir=load_path) mindt, line1, line2 = io.get_epoch_tle(utc, tlefile) nustar = EarthSatellite(line1, line2) observer = earth + nustar ts = load.timescale() return observer, sun, ts
def is_light(): """is_light returns True if the sun is up and False otherwise""" # load in data directory to avoid redownloading loader = Loader('~/skyfield_data') ts = loader.timescale() e = loader('de421.bsp') # set current location (melbourne does not appear in the default list) melbourne = api.Topos('37.951910 S', '145.152080 E') # get current time in UTC format now = datetime.datetime.utcnow() now = now.replace(tzinfo=utc) # set the interval for now and 24 hours from now t0 = ts.utc(now) t1 = ts.utc(now + timedelta(hours=24)) # find the times and types of event (sunrise/sunset) t, y = almanac.find_discrete(t0, t1, almanac.sunrise_sunset(e, melbourne)) #y[0] = True for sunrise (which means it is currently dark) light = not y[0] return light
class RemoteSensingControlWidget(QtWidgets.QWidget, ui.Ui_RemoteSensingDockWidget): """This class implements the remote sensing functionality as dockable widget. """ def __init__(self, parent=None, view=None): """ Arguments: parent -- Qt widget that is parent to this widget. view -- reference to mpl canvas class """ super(RemoteSensingControlWidget, self).__init__(parent) self.setupUi(self) self.view = view self.load = Loader(MSS_CONFIG_PATH, verbose=False) self.planets = self.load('de421.bsp') self.timescale = self.load.timescale(builtin=True) # don't download files, use shipped files button = self.btTangentsColour palette = QtGui.QPalette(button.palette()) colour = QtGui.QColor() colour.setRgbF(1, 0, 0, 1) palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) self.dsbTangentHeight.setValue(10.) self.dsbObsAngleAzimuth.setValue(90.) self.dsbObsAngleElevation.setValue(-1.0) # update plot on every value change self.cbDrawTangents.stateChanged.connect(self.update_settings) self.cbShowSolarAngle.stateChanged.connect(self.update_settings) self.btTangentsColour.clicked.connect(self.set_tangentpoint_colour) self.dsbTangentHeight.valueChanged.connect(self.update_settings) self.dsbObsAngleAzimuth.valueChanged.connect(self.update_settings) self.dsbObsAngleElevation.valueChanged.connect(self.update_settings) self.cbSolarBody.currentIndexChanged.connect(self.update_settings) self.cbSolarAngleType.currentIndexChanged.connect(self.update_settings) self.lbSolarCmap.setText( "Solar angle colours, dark to light: reds (0-15), violets (15-45), greens (45-180)" ) self.solar_cmap = ListedColormap([(1.00, 0.00, 0.00, 1.0), (1.00, 0.45, 0.00, 1.0), (1.00, 0.75, 0.00, 1.0), (0.47, 0.10, 1.00, 1.0), (0.72, 0.38, 1.00, 1.0), (1.00, 0.55, 1.00, 1.0), (0.00, 0.70, 0.00, 1.0), (0.33, 0.85, 0.33, 1.0), (0.65, 1.00, 0.65, 1.0)]) self.solar_norm = BoundaryNorm( [0, 5, 10, 15, 25, 35, 45, 90, 135, 180], self.solar_cmap.N) self.update_settings() @staticmethod def compute_view_angles(lon0, lat0, h0, lon1, lat1, h1, obs_azi, obs_ele): mlat = ((lat0 + lat1) / 2.) lon0 *= np.cos(np.deg2rad(mlat)) lon1 *= np.cos(np.deg2rad(mlat)) dlon = lon1 - lon0 dlat = lat1 - lat0 obs_azi_p = fix_angle(obs_azi + np.rad2deg(np.arctan2(dlon, dlat))) return obs_azi_p, obs_ele def compute_body_angle(self, body, jsec, lon, lat): t = self.timescale.utc(jsec_to_datetime(jsec).replace(tzinfo=utc)) loc = self.planets["earth"] + Topos(lat, lon) astrometric = loc.at(t).observe(self.planets[body]) alt, az, d = astrometric.apparent().altaz() return az.degrees, alt.degrees def update_settings(self): """ Updates settings in TopView and triggers a redraw. """ settings = { "reference": self, "draw_tangents": self.cbDrawTangents.isChecked(), } if self.cbShowSolarAngle.isChecked(): settings["show_solar_angle"] = self.cbSolarAngleType.currentText( ), self.cbSolarBody.currentText() else: settings["show_solar_angle"] = None self.view.set_remote_sensing_appearance(settings) def set_tangentpoint_colour(self): """Slot for the colour buttons: Opens a QColorDialog and sets the new button face colour. """ button = self.btTangentsColour palette = QtGui.QPalette(button.palette()) colour = palette.color(QtGui.QPalette.Button) colour = QtWidgets.QColorDialog.getColor(colour) if colour.isValid(): palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) self.update_settings() def compute_tangent_lines(self, bmap, wp_vertices, wp_heights): """ Computes Tangent points of limb sounders aboard the aircraft Args: bmap: Projection of TopView wp_vertices: waypoints of the flight path wp_heights: altitude of the waypoints of flight path Returns: LineCollection of dotted lines at tangent point locations """ x, y = list(zip(*wp_vertices)) wp_lons, wp_lats = bmap(x, y, inverse=True) fine_lines = [ bmap.gcpoints2(wp_lons[i], wp_lats[i], wp_lons[i + 1], wp_lats[i + 1], del_s=10., map_coords=False) for i in range(len(wp_lons) - 1) ] line_heights = [ np.linspace(wp_heights[i], wp_heights[i + 1], num=len(fine_lines[i][0])) for i in range(len(fine_lines)) ] # fine_lines = list of tuples with x-list and y-list for each segment tplines = [ self.tangent_point_coordinates( fine_lines[i][0], fine_lines[i][1], line_heights[i], cut_height=self.dsbTangentHeight.value()) for i in range(len(fine_lines)) ] dirlines = self.direction_coordinates(wp_lons, wp_lats) lines = tplines + dirlines for i, line in enumerate(lines): for j, (lon, lat) in enumerate(line): line[j] = bmap(lon, lat) lines[i] = line return LineCollection( lines, colors=QtGui.QPalette(self.btTangentsColour.palette()).color( QtGui.QPalette.Button).getRgbF(), zorder=2, animated=True, linewidth=3, linestyles=[':'] * len(tplines) + ['-'] * len(dirlines)) def compute_solar_lines(self, bmap, wp_vertices, wp_heights, wp_times, solartype): """ Computes coloured overlay over the flight path that indicates the danger of looking into the sun with a limb sounder aboard the aircraft. Args: bmap: Projection of TopView wp_vertices: waypoints of the flight path wp_heights: altitude of the waypoints of flight path Returns: LineCollection of coloured lines according to the angular distance between viewing direction and solar angle """ # calculate distances and times body, difftype = solartype times = [datetime_to_jsec(_wp_time) for _wp_time in wp_times] x, y = list(zip(*wp_vertices)) wp_lons, wp_lats = bmap(x, y, inverse=True) fine_lines = [ bmap.gcpoints2(wp_lons[i], wp_lats[i], wp_lons[i + 1], wp_lats[i + 1], map_coords=False) for i in range(len(wp_lons) - 1) ] line_heights = [ np.linspace(wp_heights[i], wp_heights[i + 1], num=len(fine_lines[i][0])) for i in range(len(fine_lines)) ] line_times = [ np.linspace(times[i], times[i + 1], num=len(fine_lines[i][0])) for i in range(len(fine_lines)) ] # fine_lines = list of tuples with x-list and y-list for each segment # lines = list of tuples with lon-list and lat-list for each segment heights = [] times = [] for i in range(len(fine_lines) - 1): heights.extend(line_heights[i][:-1]) times.extend(line_times[i][:-1]) heights.extend(line_heights[-1]) times.extend(line_times[-1]) solar_x = [] solar_y = [] for i in range(len(fine_lines) - 1): solar_x.extend(fine_lines[i][0][:-1]) solar_y.extend(fine_lines[i][1][:-1]) solar_x.extend(fine_lines[-1][0]) solar_y.extend(fine_lines[-1][1]) points = [] old_wp = None total_distance = 0 for i, (lon, lat) in enumerate(zip(solar_x, solar_y)): points.append([[lon, lat] ]) # append double-list for later concatenation if old_wp is not None: wp_dist = get_distance((old_wp[0], old_wp[1]), (lat, lon)) * 1000. total_distance += wp_dist old_wp = (lat, lon) vals = [] for i in range(len(points) - 1): p0, p1 = points[i][0], points[i + 1][0] sol_azi, sol_ele = self.compute_body_angle(body, times[i], p0[0], p0[1]) obs_azi, obs_ele = self.compute_view_angles( p0[0], p0[1], heights[i], p1[0], p1[1], heights[i + 1], self.dsbObsAngleAzimuth.value(), self.dsbObsAngleElevation.value()) if sol_azi < 0: sol_azi += 360 if obs_azi < 0: obs_azi += 360 rating = self.calc_view_rating(obs_azi, obs_ele, sol_azi, sol_ele, heights[i], difftype) vals.append(rating) # convert lon, lat to map points for i in range(len(points)): points[i][0][0], points[i][0][1] = bmap(points[i][0][0], points[i][0][1]) points = np.concatenate([points[:-1], points[1:]], axis=1) # plot solar_lines = LineCollection(points, cmap=self.solar_cmap, norm=self.solar_norm, zorder=2, linewidths=3, animated=True) solar_lines.set_array(np.array(vals)) return solar_lines def tangent_point_coordinates(self, lon_lin, lat_lin, flight_alt=14, cut_height=12): """ Computes coordinates of tangent points given coordinates of flight path. Args: lon_lin: longitudes of flight path lat_lin: latitudes of flight path flight_alt: altitude of aircraft (scalar or numpy array) cut_height: altitude of tangent points Returns: List of tuples of longitude/latitude coordinates """ lins = list(zip(lon_lin[0:-1], lon_lin[1:], lat_lin[0:-1], lat_lin[1:])) lins = [(x0 * np.cos(np.deg2rad(np.mean([y0, y1]))), x1 * np.cos(np.deg2rad(np.mean([y0, y1]))), y0, y1) for x0, x1, y0, y1 in lins] direction = [(x1 - x0, y1 - y0) for x0, x1, y0, y1 in lins] direction = [(_x / np.hypot(_x, _y), _y / np.hypot(_x, _y)) for _x, _y in direction] los = [ rotate_point(point, -self.dsbObsAngleAzimuth.value()) for point in direction ] los.append(los[-1]) if isinstance(flight_alt, (collections.abc.Sequence, np.ndarray)): dist = [(np.sqrt( max((EARTH_RADIUS + a)**2 - (EARTH_RADIUS + cut_height)**2, 0)) / 110.) for a in flight_alt[:-1]] dist.append(dist[-1]) else: dist = (np.sqrt((EARTH_RADIUS + flight_alt)**2 - (EARTH_RADIUS + cut_height)**2) / 110.) tp_dir = (np.array(los).T * dist).T tps = [(x0 + tp_x, y0 + tp_y, y0) for ((x0, x1, y0, y1), (tp_x, tp_y)) in zip(lins, tp_dir)] tps = [(x0 / np.cos(np.deg2rad(yp)), y0) for (x0, y0, yp) in tps] return tps def direction_coordinates(self, lon_lin, lat_lin): """ Computes coordinates of tangent points given coordinates of flight path. Args: lon_lin: longitudes of flight path lat_lin: latitudes of flight path flight_alt: altitude of aircraft (scalar or numpy array) cut_height: altitude of tangent points Returns: List of tuples of longitude/latitude coordinates """ lins = list(zip(lon_lin[0:-1], lon_lin[1:], lat_lin[0:-1], lat_lin[1:])) lins = [(x0 * np.cos(np.deg2rad(np.mean([y0, y1]))), x1 * np.cos(np.deg2rad(np.mean([y0, y1]))), y0, y1) for x0, x1, y0, y1 in lins] lens = [np.hypot(x1 - x0, y1 - y0) * 110. for x0, x1, y0, y1 in lins] lins = [_x for _x, _l in zip(lins, lens) if _l > 10] direction = [(0.5 * (x0 + x1), 0.5 * (y0 + y1), x1 - x0, y1 - y0) for x0, x1, y0, y1 in lins] direction = [(_u, _v, _x / np.hypot(_x, _y), _y / np.hypot(_x, _y)) for _u, _v, _x, _y in direction] los = [ rotate_point(point[2:], -self.dsbObsAngleAzimuth.value()) for point in direction ] dist = 1. tp_dir = (np.array(los).T * dist).T tps = [(x0, y0, x0 + tp_x, y0 + tp_y) for ((x0, y0, _, _), (tp_x, tp_y)) in zip(direction, tp_dir)] tps = [[(x0 / np.cos(np.deg2rad(y0)), y0), (x1 / np.cos(np.deg2rad(y0)), y1)] for (x0, y0, x1, y1) in tps] return tps @staticmethod def calc_view_rating(obs_azi, obs_ele, sol_azi, sol_ele, height, difftype): """ Calculates the angular distance between given directions under the condition that the sun is above the horizon. Args: obs_azi: observator azimuth angle obs_ele: observator elevation angle sol_azi: solar azimuth angle sol_ele: solar elevation angle height: altitude of observer Returns: angular distance or 180 degrees if sun is below horizon """ delta_azi = obs_azi - sol_azi delta_ele = obs_ele - sol_ele if "horizon" in difftype: thresh = -np.rad2deg( np.arccos(EARTH_RADIUS / (height + EARTH_RADIUS))) - 3 if sol_ele < thresh: delta_ele = 180 if "azimuth" == difftype: return np.abs(obs_azi - sol_azi) elif "elevation" == difftype: return np.abs(obs_ele - sol_ele) else: return np.hypot(delta_azi, delta_ele)
import urllib.request import xml.etree.ElementTree as ET from datetime import datetime, timedelta, timezone import dbf import json from skyfield import api from skyfield import almanac from skyfield.api import Loader import math ziptable = dbf.Table(modules.config['storage']['zipdbf']) ziptable.open() # Yeah, so this is slow and I need to figure out how to persist it. zipidx = ziptable.create_index(lambda rec: rec.zcta5ce10) loader = Loader(modules.config['storage']['skyfield']) ts = loader.timescale() ephem = loader('de421.bsp') def actions(): return { '': get, 'get': get, 'details': details, 'astronomical': astronomical, 'srss': astronomical, } def with_zipcode(fcn):
def test_positions_skyfield(tmpdir): """ Test positions against those generated by skyfield. """ load = Loader(tmpdir) t = Time('1980-03-25 00:00') location = None # skyfield ephemeris try: planets = load('de421.bsp') ts = load.timescale() except OSError as e: if os.environ.get('CI', False) and 'timed out' in str(e): pytest.xfail('Timed out in CI') else: raise mercury, jupiter, moon = planets['mercury'], planets[ 'jupiter barycenter'], planets['moon'] earth = planets['earth'] skyfield_t = ts.from_astropy(t) if location is not None: earth = earth + Topos(latitude_degrees=location.lat.to_value(u.deg), longitude_degrees=location.lon.to_value(u.deg), elevation_m=location.height.to_value(u.m)) skyfield_mercury = earth.at(skyfield_t).observe(mercury).apparent() skyfield_jupiter = earth.at(skyfield_t).observe(jupiter).apparent() skyfield_moon = earth.at(skyfield_t).observe(moon).apparent() if location is not None: frame = TETE(obstime=t, location=location) else: frame = TETE(obstime=t) ra, dec, dist = skyfield_mercury.radec(epoch='date') skyfield_mercury = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_jupiter.radec(epoch='date') skyfield_jupiter = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_moon.radec(epoch='date') skyfield_moon = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) # planet positions w.r.t true equator and equinox moon_astropy = get_moon(t, location, ephemeris='de430').transform_to(frame) mercury_astropy = get_body('mercury', t, location, ephemeris='de430').transform_to(frame) jupiter_astropy = get_body('jupiter', t, location, ephemeris='de430').transform_to(frame) assert (moon_astropy.separation(skyfield_moon) < skyfield_angular_separation_tolerance) assert (moon_astropy.separation_3d(skyfield_moon) < skyfield_separation_tolerance) assert (jupiter_astropy.separation(skyfield_jupiter) < skyfield_angular_separation_tolerance) assert (jupiter_astropy.separation_3d(skyfield_jupiter) < skyfield_separation_tolerance) assert (mercury_astropy.separation(skyfield_mercury) < skyfield_angular_separation_tolerance) assert (mercury_astropy.separation_3d(skyfield_mercury) < skyfield_separation_tolerance) planets.close()
from skyfield.api import Topos, Loader load = Loader('./Skyfield-Data', expire=False, verbose=False) planets = load('de423.bsp') earth = planets['earth'] from astropy.constants import c c = c.to(u.au / u.year) GDEGENERATE = 0.2 SIGMA2_USE_ENERGY = 9 ts = load.timescale() self.theta_x, self.theya_y, self.dtheta_x, self.dtheta_y = equatorial_to_tangent() # Returns xyz position of ground-based observatory. # Need to implement obscode! Hard-coded for DECam def earth3d(self): t = ts.tt(jd=self.obsdate) earth += Topos('30.169 S', '70.804 W', elevation_m=2200) return earth.at(t).position.au * u.au def kbo2d_linear(self): x_earth, y_earth, z_earth = earth3d() t_emit = self.obsdate - z_earth / c X = self.a + self.adot * t_emit - self.g * x_earth - self.gdot * (self.adot * t_emit**2 - self.g * x_earth * t_emit) Y = self.b + self.bdot * t_emit - self.g * y_earth - self.gdot * (self.bdot * t_emit**2 - self.g * y_earth * t_emit) dX = np.array([np.ones(nobs), t_emit, np.zeros(nobs), np.zeros(nobs), -x_earth, self.g * x_earth * t_emit - self.adot * t_emit**2])
#!/usr/bin/env python import os import math import pytz import rospy from datetime import datetime from rosgraph_msgs.msg import Clock from geometry_msgs.msg import Vector3 from skyfield.api import PlanetaryConstants, Loader, load load = Loader(os.path.dirname(os.path.abspath(__file__)) + '/../include') sim_time = 0 msg_timeout = 0.5 last_msg_time = 0.0 def sim_time_callback(data): global last_msg_time global sim_time last_msg_time = rospy.get_time() sim_time = data.clock.to_sec() def run(): rospy.init_node('sun_seeker_node', anonymous=True) rospy.Subscriber('/clock', Clock, sim_time_callback) pub = rospy.Publisher('/sun_seeker/vector', Vector3, queue_size=1) rate = rospy.Rate(0.1)
def get_loader(): return Loader(CACHE_FOLDER)
from skyfield.api import Loader, Topos, Angle, EarthSatellite, Star from skyfield.timelib import Time from almanac2 import (meridian_transits, culminations, twilights, risings_settings, seasons, moon_phases, apsides, nodes, max_ecliptic_latitudes) from almanac2 import (_ecliptic_lon_diff, _moon_ul_alt, _lha, _alt, _satellite_alt, _ecliptic_lon, _linear_dist, _ecliptic_lat) from numpy import ndarray from functools import partial # Put your data directory here before running this file: load = Loader(r'') ts = load.timescale() ephem = load('de430t.bsp') earth = ephem['earth'] sun = ephem['sun'] moon = ephem['moon'] mars = ephem['mars barycenter'] venus = ephem['venus'] plain_greenwich = Topos(latitude='51.5 N', longitude='0 W') greenwich = earth + plain_greenwich iss_tle = """\ 1 25544U 98067A 18161.85073725 .00003008 00000-0 52601-4 0 9993 2 25544 51.6418 50.3007 0003338 171.6979 280.7366 15.54163173117534 """ ISS = EarthSatellite(*iss_tle.splitlines())
# v0.5.1: add attributes 'delta','r', 'phase_angle', 'elong' # 'delta': geocentric distance # 'r': barycentric distance # 'phase_angle': phase angle in radian # 'elong': solar elongation in radian # v0.5.2: correct elong calculations # v0.6: add propagate_lite, a faster, inaccurate version of propagate # v0.6.1: change time to tt ############################################################################## from __future__ import division import numpy as np from skyfield.api import Topos, Loader from scipy.optimize import newton load = Loader('./Skyfield-Data', expire=True) planets = load('de423.bsp') class propagate: """ input Keplerian elements in the format of numpy arrays Units: au, radian, JD """ def __init__(self, a, e, i, arg, node, M0, epoch, obs_date, helio=False): self.u_bary = 2.9630927492415936E-04 # standard gravitational parameter, GM, M is the mass of sun + all planets self.u_helio = 2.9591220828559093E-04 # GM, M is the mass of sun self.epsilon = 23.43929111 * np.pi / 180. # obliquity if helio: self.a, self.e, self.i, self.arg, self.node, self.M0 = self.helio_to_bary(
sun = ephemeris['sun'] topos_at = (ephemeris['earth'] + topos).at def is_sun_up_at(t): """Return `True` if the sun has risen by time `t`.""" t._nutation_angles = iau2000b(t.tt) return topos_at(t).observe( sun).apparent().altaz()[0].degrees > -degrees is_sun_up_at.rough_period = 0.5 # twice a day return is_sun_up_at from skyfield import api from skyfield.api import Loader load = Loader('~/sqm-in-a-box/skyfield/skyfield-data/') ts = load.timescale() planets = load('de421.bsp') from skyfield import almanac loc = api.Topos(latitude, longitude, elevation_m=elevation) t0 = ts.utc(datetime.now(tz)) t1 = ts.utc(tz.normalize(datetime.now(tz) + timedelta(1))) #center_time, center_up = almanac.find_discrete(t0, t1, daylength(planets, loc, DAYLENGTH_CENTER_HORIZON)) #print('Sunrise Sunset center of sun is even with horizon:') #print(center_time.utc_iso(), center_up)
# Total rotation of each observation from the beginning of the night rot_tot = [ f.integral(field_rot["delta_t"][0], i) for i in field_rot["delta_t"] ] field_rot["rot_tot"] = rot_tot for i, file in enumerate(f_names): rot_image(file=file, ini_angle=-70, angle=rot_tot[i], border=False) return field_rot if __name__ == "__main__": # Download Ephemerides & timescale files load = Loader("ephemerides") planets = load("de421.bsp") ts = load.timescale() # Solar System Ephemerides sun = planets["sun"] mercury = planets["mercury"] venus = planets["venus"] mars = planets["mars"] earth = planets["earth"] moon = planets["moon"] jupiter = planets["jupiter barycenter"] saturn = planets["saturn barycenter"] uranus = planets["uranus barycenter"] neptune = planets["neptune barycenter"] pluto = planets["pluto barycenter"]