from pprint import pprint import unittest from skyfield.api import Loader, Topos from skyfield.data import mpc from skyfield.constants import GM_SUN_Pitjeva_2005_km3_s2 as GM_SUN import pandas as pd import os import numpy as np from pytz import timezone import datetime import simple_cache import time import redis import pickle load = Loader('/var/data') eph = load('de421.bsp') ts = load.timescale(builtin=True) sun, earth = eph['sun'], eph['earth'] with load.open(mpc.COMET_URL) as f: comets = mpc.load_comets_dataframe(f) comets = comets.set_index('designation', drop=False) UTC = timezone('UTC') # LONGTTL=86400*30 # SHORTTTL=86400 LONGTTL = 86400 / 2 SHORTTTL = 86400 / 12 rconn = redis.StrictRedis(host='134.209.169.157', password="******")
def visible_pass(start_time, end_time, site, timezone=0, cutoff=10, twilight='nautical', visible_duration=120): ''' Generate the visible passes of space targets in a time period. Usage: visible_pass(start_time,end_time,site,timezone=8) Inputs: start_time -> [str] start time, such as '2020-06-01 00:00:00' end_time -> [str] end time, such as '2020-07-01 00:00:00' site -> [list of str] geodetic coordinates of a station, such as ['21.03 N','157.80 W','1987.05'] Parameters: timezone -> [int, optional, default=0] time zone, such as -10; if 0, then UTC is used. cutoff -> [float, optional, default=10] Satellite Cutoff Altitude Angle twilight -> [str, or float, optional, default='nautical'] Dark sign or solar cutoff angle; if 'dark', then the solar cutoff angle is less than -18 degrees; if 'astronomical', then less than -12 degrees; if 'nautical', then less than -6 degrees; if 'civil', then less than -0.8333 degrees; alternatively, it also can be set to a specific number, for example, 4.0 degrees. visible_duration -> [int, optional, default=120] Duration[seconds] of a visible pass Outputs: VisiblePasses_bysat.csv -> csv-format files that record visible passes in sort of target VisiblePasses_bydate.csv -> csv-format files that record visible passes in sort of date xxxx.txt -> one-day prediction files for targets ''' home = str(Path.home()) direc_eph = home + '/src/skyfield-data/ephemeris/' direc_time = home + '/src/skyfield-data/time_data/' de430 = direc_eph + 'de430.bsp' load_eph = Loader(direc_eph) load_time = Loader(direc_time) print('\nDownloading JPL ephemeris DE430 and timescale files', end=' ... \n') # URL of JPL DE430 url = 'http://www.shareresearch.me/wp-content/uploads/2020/05/de430.bsp' ''' url = 'http://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/de430.bsp' url = 'https://repos.cosmos.esa.int/socci/projects/SPICE_KERNELS/repos/juice/browse/kernels/spk/de430.bsp' ''' if not path.exists(de430): desc = 'Downloading {:s}'.format('de430.bsp') tqdm_request(url, direc_eph, 'de430.bsp', desc) print('Downloading timescale files', end=' ... \n') ts = load_time.timescale() planets = load_eph('de430.bsp') # Print information about the time system file and ephemeris file print(load_time.log) print(load_eph.log) print( '\nCalculating one-day predictions and multiple-day visible passes for targets', end=' ... \n') if twilight == 'dark': sun_alt_cutoff = -18 elif twilight == 'astronomical': sun_alt_cutoff = -12 elif twilight == 'nautical': sun_alt_cutoff = -6 elif twilight == 'civil': sun_alt_cutoff = -0.8333 elif type(twilight) is int or type(twilight) is float: sun_alt_cutoff = twilight else: raise Exception( "twilight must be one of 'dark','astronomical','nautical','civil', or a number." ) dir_TLE = 'TLE/' dir_prediction = 'prediction/' sun, earth = planets['sun'], planets['earth'] sats = load.tle_file(dir_TLE + 'satcat_3le.txt') lon, lat, ele = site observer = Topos(lon, lat, elevation_m=float(ele)) # local start time t_start = Time(start_time) - timezone * u.hour # local end time t_end = Time(end_time) - timezone * u.hour fileList_prediction = glob(dir_prediction + '*') if path.exists(dir_prediction): for file in fileList_prediction: remove(file) else: mkdir(dir_prediction) filename0 = 'VisiblePasses_bysat.csv' filename1 = 'VisiblePasses_bydate.csv' outfile0 = open(dir_prediction + filename0, 'w') header = [ 'Start Time[UTC+' + str(timezone) + ']', 'End Time[UTC+' + str(timezone) + ']', 'NORADID', 'During[seconds]' ] outfile0.write('{},{},{},{}\n'.format(header[0], header[1], header[2], header[3])) print('Generate one-day prediction for targets:') for sat in sats: visible_flag = False noradid = sat.model.satnum passes = next_pass(ts, t_start, t_end, sat, observer, cutoff) if not passes: continue else: outfile = open(dir_prediction + str(noradid) + '.txt', 'w') outfile.write( '# {:18s} {:8s} {:8s} {:8s} {:8s} {:10s} {:14s} {:7s} \n'. format('Date and Time(UTC)', 'Alt[deg]', 'Az[deg]', 'Ra[h]', 'Dec[deg]', 'Range[km]', 'Solar Alt[deg]', 'Visible')) for pass_start, pass_end in passes: t = t_list(ts, Time(pass_start), Time(pass_end), 1) sat_observer = (sat - observer).at(t) sat_alt, sat_az, sat_distance = sat_observer.altaz() sat_ra, sat_dec, sat_distance = sat_observer.radec() sun_observer = (earth + observer).at(t).observe(sun).apparent() sun_alt, sun_az, sun_distance = sun_observer.altaz() sun_beneath = sun_alt.degrees < sun_alt_cutoff #shadow = eclipsed(sat,sun,earth,t) sunlight = sat.at(t).is_sunlit(planets) # Under the premise of satellite transit, visibility requires at least two conditions to be met: dark and outside the earth shadow. #visible = sun_beneath & ~shadow visible = sun_beneath & sunlight if visible.any(): visible_flag = True t_visible = np.array(t.utc_iso())[visible] t_visible_0 = (Time(t_visible[0]) + timezone * u.hour).iso t_visible_1 = (Time(t_visible[-1]) + timezone * u.hour).iso during = round((Time(t_visible[-1]) - Time(t_visible[0])).sec) if during >= visible_duration: outfile0.write('{:s},{:s},{:d},{:d}\n'.format( t_visible_0, t_visible_1, noradid, int(during))) # Generate a one-day prediction file if Time(pass_end) < t_start + 1: for i in range(len(t)): outfile.write( '{:20s} {:>8.4f} {:>8.4f} {:>8.5f} {:>8.4f} {:>10.4f} {:>10.4f} {:>7d} \n' .format( t.utc_strftime('%Y-%m-%d %H:%M:%S')[i], sat_alt.degrees[i], sat_az.degrees[i], sat_ra.hours[i], sat_dec.degrees[i], sat_distance.km[i], sun_alt.degrees[i], visible[i])) outfile.write('\n') ''' # Generate a one-day prediction in visibility period if visible.any(): t_visible = np.array(t.utc_iso())[visible] for i in range(len(t_visible)): outfile.write('{:20s} {:>8.4f} {:>8.4f} {:>8.5f} {:>8.4f} {:>10.4f} \n'.format(t_visible[i],sat_alt.degrees[visible][i],sat_az.degrees[visible][i],sat_ra.hours[visible][i],sat_dec.degrees[visible][i],sat_distance.km[visible][i])) outfile.write('\n') ''' if not visible_flag: outfile0.write('{:s},{:s},{:d}\n\n'.format('', '', noradid)) else: outfile0.write('\n') outfile.close() print(noradid) outfile0.close() print('Generate multiple-day visible passes for all targets.') # Sort by the start time of the visible passes dates, temp = [], [] VisiblePasses = pd.read_csv(dir_prediction + filename0, dtype=object) for date in VisiblePasses[header[0]]: if str(date) != 'nan': dates.append(date[:10]) dates = np.sort(list(set(dates))) for date in dates: date_flag = VisiblePasses[header[0]].str.contains(date, na=False) temp.append(VisiblePasses[date_flag].sort_values( by=[header[0]]).append(pd.Series(dtype=object), ignore_index=True)) if not temp: print('No visible passes are found!') else: pd.concat(temp).to_csv(dir_prediction + 'VisiblePasses_bydate.csv', index=False, mode='w') print('Over!')
""" 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(basepath + '/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)
def test_load_using_cache_de421(download_patched): load = Loader(get_skyfield_data_path()) load('de421.bsp') assert download_patched.call_count == 0
def test_load_no_cache_de421(tmpdir): with mock.patch('jplephem.spk.SPK.open'): # avoid naughty side-effects with mock.patch('skyfield.iokit.download') as download_patched: load = Loader(tmpdir.dirname) load('de421.bsp') assert download_patched.call_count == 1
MY_LOGGER.debug('APP_PATH = %s', APP_PATH) MY_LOGGER.debug('CODE_PATH = %s', CODE_PATH) MY_LOGGER.debug('LOG_PATH = %s', LOG_PATH) MY_LOGGER.debug('OUTPUT_PATH = %s', OUTPUT_PATH) MY_LOGGER.debug('IMAGE_PATH = %s', IMAGE_PATH) MY_LOGGER.debug('WORKING_PATH = %s', WORKING_PATH) MY_LOGGER.debug('CONFIG_PATH = %s', CONFIG_PATH) try: # backup old tle files MY_LOGGER.debug('Backing up old files') backup_tle('de421.bsp') # update planets info MY_LOGGER.debug('Loading new files') LOAD = Loader(WORKING_PATH) TS = LOAD.timescale() PLANETS = LOAD('de421.bsp') # validate planets files MY_LOGGER.debug('Validating new files') validate_tle('de421.bsp') MY_LOGGER.debug('Finished') except: MY_LOGGER.critical('Global exception handler: %s %s %s', sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])
def solar_term(year, degrees, timezone='UTC'): """ Returns the date of the solar term for the given longitude and the given year. Solar terms are used for Chinese and Taiwanese holidays (e.g. Qingming Festival in Taiwan). More information: - https://en.wikipedia.org/wiki/Solar_term - https://en.wikipedia.org/wiki/Qingming This function is adapted from the following topic: https://answers.launchpad.net/pyephem/+question/110832 """ # Target angle as radians target_angle = radians(degrees) load = Loader(get_skyfield_data_path()) planets = load('de421.bsp') earth = planets['earth'] sun = planets['sun'] ts = load.timescale() tz = pytz.timezone(timezone) jan_first = ts.utc(date(year, 1, 1)) current_longitude = get_current_longitude(jan_first, earth, sun) # Find approximately the right time of year. difference = (target_angle - current_longitude) % tau # Here we have an approximation of the number of julian days to go date_delta = 365.25 * difference / tau # convert to "tt" and reconvert it back to a Time object t0 = ts.tt_jd(jan_first.tt + date_delta) def f(t): # We've got a float which is the `tt` sky_tt = ts.tt_jd(t) longitude = get_current_longitude(sky_tt, earth, sun) result = target_angle - longitude if result > pi: result = result - pi elif result < -pi: result = result + pi return result # Using datetimes to compute the next step date t0_plus_one_minute = t0.utc_datetime() + timedelta(minutes=1) # Back to Skyfield Time objects t0_plus_one_minute = ts.utc(t0_plus_one_minute) # Julian day for the starting date t0 = t0.tt # Adding one minute to have a second boundary t0_plus_one_minute = t0_plus_one_minute.tt # Newton method to converge towards the target angle t = newton(f, t0, t0_plus_one_minute) # Here we have a float to convert to julian days. t = ts.tt_jd(t) # To convert to datetime t = t.utc_datetime() # Convert in the timezone result = t.astimezone(tz) return result.date()
#! /usr/bin/env python3 import os from skyfield.api import PlanetaryConstants, Loader, Topos, pi, tau import matplotlib.pyplot as plt import numpy as np import datetime script_directory = os.path.dirname(__file__) load = Loader(os.path.join(script_directory, 'data')) def years_in_seconds(y): return int(y * 31556926) def hours_in_seconds(h): return int(h * 60 * 60) def wrap180(a): return (a + 180.0) % (2 * 180.0) - 180.0 def moon_subsolar_point(t): eph = load('de421.bsp') sun = eph['sun'] moon = eph['moon'] pc = PlanetaryConstants() pc.read_text(load('moon_080317.tf')) pc.read_text(load('pck00008.tpc'))
def get_loader(): return Loader(CACHE_FOLDER)
# This is a brand new function in Skyfield! # https://rhodesmill.org/skyfield/kepler-orbits.html from skyfield.api import Loader, Topos from skyfield.data import mpc from skyfield.constants import GM_SUN_Pitjeva_2005_km3_s2 as GM_SUN from skyfield import almanac import dateutil.parser from datetime import timedelta import argparse import sys, os load = Loader('~/.cache/skyfield') with load.open(mpc.COMET_URL) as f: comets = mpc.load_comets_dataframe(f) # Index by designation for fast lookup. comets = comets.set_index('designation', drop=False) ts = load.timescale(builtin=True) eph = load('de421.bsp') sun = eph['sun'] earth = eph['earth'] WHICH_TWILIGHT = "Nautical twilight" def comet_by_name(namepat):
from astropy.coordinates import Angle, EarthLocation, SkyCoord from astropy.time import Time import astropy.units as u from flask import abort from flask import Flask from flask import jsonify from flask import render_template from flask import request app = Flask(__name__) # Override download directory for data files if 'TLEPHEM_DATA_DIR' in os.environ: load = Loader(os.environ['TLEPHEM_DATA_DIR']) # TODO: Generalize this to support other sites SITE_LOCATION = EarthLocation( lat=28.7603135*u.deg, lon=-17.8796168*u.deg, height=2387*u.m) def generate_ephemeris(name, tle1, tle2, date_str): date = datetime.datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S') date = date.replace(tzinfo=utc) lst = Time(date, scale='utc', location=SITE_LOCATION).sidereal_time('apparent') print('name', name) print('tle1', tle1)
def __init__(self): self._loader = Loader(DATA_PATH) self.update()
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 if '://' in MSS_CONFIG_PATH: try: _fs = fs.open_fs(MSS_CONFIG_PATH) download_path = _fs.getsyspath("") except fs.errors.CreateFailed: logging.error( f'Make sure that the FS url "{MSS_CONFIG_PATH}" exists') except fs.opener.errors.UnsupportedProtocol: logging.error(f'FS url "{MSS_CONFIG_PATH}" not supported') else: download_path = MSS_CONFIG_PATH self.load = Loader(download_path, verbose=False) self.load_bsp = Loader(skyfield_data.get_skyfield_data_path(), verbose=False) self.timescale = self.load.timescale(builtin=True) self.planets = self.load_bsp('de421.bsp') 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()
import os import sys import pickle from skyfield.api import Topos, Loader from pytz import timezone pacific = timezone('US/Pacific') ROOT_DIR = os.environ['ROOT_DIR'] if ROOT_DIR is None: raise RuntimeError("ROOT_DIR not set") load = Loader(os.path.join(ROOT_DIR, './data/')) ts = load.timescale(builtin=True) planets = load('de421.bsp') def get_moon_pos(): earth = planets['earth'] moon = planets['moon'] # Jared's home loc = earth + Topos('47.647654 N', '-122.324748 E') apparent = loc.at(ts.now()).observe(moon).apparent() return apparent.altaz() def get_satellites(tle_file=None): if tle_file:
import json import pytest from skyfield.api import Loader from django.conf import settings from v0.accesses import Access, filter_range load = Loader(settings.EPHEM_DIR) timescale = load.timescale() def test_access_id_roundtrip(): sat_id = 5 gs_id = 6 time = timescale.utc(2018, 5, 23, 1, 2, 3) accid = Access.encode_access_id(sat_id, gs_id, time) assert (sat_id, gs_id, time) == Access.decode_access_id(accid) class Window(object): ts = load.timescale() def __init__(self, start_time, end_time): self.start_time = self.ts.utc(start_time) self.end_time = self.ts.utc(end_time) windows = [ Window(2018, 2019), Window(2019, 2020), Window(2020, 2021),
def main(): logging.basicConfig( level=logging.DEBUG, datefmt='%Y-%b-%d %H:%M:%S', format= '%(asctime)s %(levelname)s P%(process)d T%(thread)d %(filename)s L%(lineno)d %(funcName)s() - %(message)s %(relativeCreated)d ms' ) s = " Welcome to Telescope Planner! " line = len(s) * '=' print(f'\n{line}\n{s}\n{line}') # location, source = get_location() location, source = DEFAULT_LOCATION, "DEBUG method" load = Loader(DATA_FOLDER) ts = load.timescale() # now = ts.utc(2019, 3, 29, 1, 39) now = ts.now() tz = timezone('Europe/Lisbon') print(f'\nBased on the {source}, this is your current location:\n') print(f' {location.dms_latitude} {location.dms_longitude}') print(f' {location.city}, {location.country}') if location.altitude is None: print(f' Alt.: <undetermined>') altitude = '0' else: print(f' Alt.: {location.altitude:.0f}m\n') altitude = location.altitude # TODO: The sources variable can be initialized with a list of Messier IDs, for instance sources = SimpleNamespace(**{ 'planets': OUR_TOP_LIST_PLANETS, 'deepspace': OUR_TOP_LIST_DEEPSPACE }) session_params = { 'timescale': ts, 'start': now, 'end': now, 'latitude': location.latitude, 'longitude': location.longitude, 'altitude': altitude, 'min_alt': 0.0, 'max_alt': 90.0, 'min_az': 0.0, 'max_az': 360.0, 'constellation': 'Peg', # E.g. 'Virgo', 'Leo' 'only_kind': None, # E.g. 'Galaxy', 'Nebula'… # ~14.5 for the average 8-10inch telescope (DEFAULT_MIN_MAG) # ~6 for naked eye with little light pollution (NAKED_EYE_MAG): 'min_apparent_mag': DEFAULT_MIN_MAG, 'only_from_catalog': None, # NGC, IC, or Messier 'only_these_sources': None, # A dictionary of the top lists, from module constants # None for no limit, an integer to limit the number of results, for faster completion: 'limit': 100, } logging.debug(pformat(session_params)) logging.debug("New session") session = Session(**session_params) logging.debug( "Finalized Session initialization. Starting report generation.") print('Here are some interesting objects up in the sky right now:') print('\n Solar system:'.upper()) if session.objects_visible_now.planets: for obj in session.objects_visible_now.planets: obj.update_coords() # print(obj.name, obj.alt, obj.az, obj.distance) print( f' • {obj.name.ljust(17)} Alt: {obj.alt.degrees:8.4f} Az: {obj.az.degrees:8.4f}, D: {obj.distance.au:15.1f}au - {obj.kind}' ) else: print('[Nothing to show here]') print('\n Deep space objects:'.upper()) logging.debug("Starting deep space report generation.") if session.objects_visible_now.deepspace: for obj in session.objects_visible_now.deepspace: obj.update_coords() # print(obj.name, obj.alt, obj.az, obj.distance) print( f' • {obj.name.ljust(17)} Alt: {obj.alt.degrees:8.4f} Az: {obj.az.degrees:8.4f} - {obj.kind} in {CONSTELLATIONS_LATIN_FROM_ABBREV[obj.constellation]}' ) print('\n ', len(session.objects_visible_now.deepspace), "objects visible from a total of", len(session.deepspace_selection), "objects analyzed.") else: print(' • [Nothing to show here]') logging.debug("Finalized report presentation.") print('\n')
def load_sats() -> List: load = Loader('./tle_cache') sats = load.tle_file(url=TLE_URL) return sats
# 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=False) 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(
def draw_satellite_map(basemap_params, colored_attribute='orient'): ''' Input: basemap_params: <dict> 'basemap parameter': value colored_attribute: 'orient''elevation', which attributes to be used in colormap ''' llcrnrlon = basemap_params.get('llcrnrlon') llcrnrlat = basemap_params.get('llcrnrlat') urcrnrlon = basemap_params.get('urcrnrlon') urcrnrlat = basemap_params.get('urcrnrlat') projection = basemap_params.get('projection', 'cyl') lat_0 = basemap_params.get('lat_0') lon_0 = basemap_params.get('lon_0') if colored_attribute == 'orient': cmap = cm.get_cmap('hsv') # cyclic colormap for angles elif colored_attribute == 'elevation': cmap = cm.get_cmap('Oranges') else: raise ValueError('Unknown color encoding attributes.') # Dataset 1: 所有空间站 ## 从网络导入空间站数据 from skyfield.api import Topos, load stations_url = 'http://celestrak.com/NORAD/elements/stations.txt' satellites = load.tle(stations_url) satellite = satellites['ISS (ZARYA)'] all_satellites_names = list(satellites.keys()) all_satellites = list(satellites.values()) ## DataSET 2: 本地数据 # tle_path = "Full_Catalog-20190613T0000.tle" # satellites = load.tle(tle_path) # MAX_NUMBER = 100 # SAMPLE_IDX = np.random.choice(range(17000), MAX_NUMBER) # all_satellites_names = np.array(list(satellites.keys()))[SAMPLE_IDX] # all_satellites = np.array(list(satellites.values()))[SAMPLE_IDX] load = Loader(directory='.', expire=False) # expire=False: use local files ts = load.timescale() # 获取卫星的当前位置 t = ts.now() all_geocentric = [sate.at(t) for sate in all_satellites] # 避免不停地写list的向量运算np.vectorize一切, 我们 vecfun_subpoint = np.vectorize(lambda x: x.subpoint()) vecfun_lon = np.vectorize(lambda x: x.longitude.degrees) vecfun_lat = np.vectorize(lambda x: x.latitude.degrees) vecfun_ele = np.vectorize(lambda x: x.elevation.m) all_subpoint = vecfun_subpoint(all_geocentric) all_lon = vecfun_lon(all_subpoint) all_lat = vecfun_lat(all_subpoint) all_ele = vecfun_ele(all_subpoint) # 初始化画布 fig, ax = plt.subplots(figsize=(8,8)) m = Basemap(llcrnrlon=llcrnrlon, llcrnrlat=llcrnrlat, urcrnrlon=urcrnrlon, urcrnrlat=urcrnrlat, lat_0=lat_0, lon_0=lon_0, projection=projection) m.bluemarble() # 初始画图 # 全体位置 x, y = m(all_lon, all_lat) # 全体方位 all_velocity = [station.ITRF_position_velocity_error(t)[1] \ for station in all_satellites] all_orient = [np.mod(np.rad2deg(np.angle(v[0] + v[1]*1j)) - 90, 360) \ for v in all_velocity] if colored_attribute == 'orient': all_color_value = [sate.model.inclo for sate in all_satellites] elif colored_attribute == 'elevation': all_color_value = (all_ele - np.nanmin(all_ele)) / (np.nanmax(all_ele) - np.nanmin(all_ele)) scat = [] for i in range(len(x)): scat.append(m.scatter(x[i], y[i], marker=(3, 0, all_orient[i]), color=cmap(all_color_value[i]))) '''内嵌的函数init, update 用于动画''' def init(): # return scat, # return scat,sate_text return scat def update(frame): t = ts.now() all_geocentric = [sate.at(t) for sate in all_satellites] all_subpoint = vecfun_subpoint(all_geocentric) all_subpoint = vecfun_subpoint(all_geocentric) all_lon = vecfun_lon(all_subpoint) all_lat = vecfun_lat(all_subpoint) all_ele = vecfun_ele(all_subpoint) x, y = m(all_lon, all_lat) all_velocity = [station.ITRF_position_velocity_error(t)[1] \ for station in all_satellites] all_orient = [np.mod(np.rad2deg(np.angle(v[0] + v[1]*1j)) - 90, 360) \ for v in all_velocity] if colored_attribute == 'orient': all_color_value = [sate.model.inclo for sate in all_satellites] elif colored_attribute == 'elevation': all_color_value = (all_ele - np.nanmin(all_ele)) / (np.nanmax(all_ele) - np.nanmin(all_ele)) scat = [] for i in range(len(x)): scat.append(m.scatter(x[i], y[i], marker=(3, 0, all_orient[i]), color=cmap(all_color_value[i]))) # scat = m.scatter(x, y, marker=(3, 0, 40), zorder=10, color=[0.2,0.2,0.9]) # sate_text = plt.text(x+8, y-8, all_satellites_names, color=[0.9,0.2,0.2]) # return scat, # return scat,sate_text return scat ani = FuncAnimation(fig, update, frames=np.linspace(0, 50), init_func=init, blit=True, interval=200) plt.show()
def is_daylight(id_pass_start, id_pass_end): """check if it is daylight at the time""" def get_timestamp(tmp_dt): part = tmp_dt.strftime('%Y-%m-%d-%H-%M') bits = part.split('-') return time_scale.utc(int(bits[0]), int(bits[1]), int(bits[2]), int(bits[3]), int(bits[4])) # if unable to load files, assume daylight is true # avoids crash and at worst will capture a nighttime pass try: # update planets info MY_LOGGER.debug('Loading new files') load = Loader(WORKING_PATH) time_scale = load.timescale() e_e = load('de421.bsp') start_time_epoch = float(wxcutils.local_datetime_to_epoch \ (datetime.today().replace(hour=0).replace(minute=0) \ .replace(second=0))) end_time_epoch = start_time_epoch + (24 * 60 * 60) - 1 start_dt = wxcutils.epoch_to_datetime_utc(start_time_epoch) end_dt = wxcutils.epoch_to_datetime_utc(end_time_epoch) gps_location = api.Topos(CONFIG_INFO['GPS location NS'], CONFIG_INFO['GPS location EW']) a_t, a_y = almanac.find_discrete( get_timestamp(start_dt), get_timestamp(end_dt), almanac.sunrise_sunset(e_e, gps_location)) MY_LOGGER.debug(a_t) MY_LOGGER.debug(a_y) daylight_start = wxcutils.utc_to_epoch( a_t[0].utc_iso().replace('T', ' ').replace('Z', ''), '%Y-%m-%d %H:%M:%S') daylight_end = wxcutils.utc_to_epoch( a_t[1].utc_iso().replace('T', ' ').replace('Z', ''), '%Y-%m-%d %H:%M:%S') # capture if middle of the pass is in daylight id_pass_midpoint = id_pass_start + ((id_pass_end - id_pass_start) / 2) MY_LOGGER.debug( 'daylight_start = %s, %s', daylight_start, wxcutils.epoch_to_local(daylight_start, '%a %d %b %H:%M')) MY_LOGGER.debug( 'daylight_end = %s, %s', daylight_end, wxcutils.epoch_to_local(daylight_end, '%a %d %b %H:%M')) MY_LOGGER.debug( 'id_pass_start = %s, %s', id_pass_start, wxcutils.epoch_to_local(id_pass_start, '%a %d %b %H:%M')) MY_LOGGER.debug( 'id_pass_midpoint = %s, %s', id_pass_midpoint, wxcutils.epoch_to_local(id_pass_midpoint, '%a %d %b %H:%M')) MY_LOGGER.debug('id_pass_end = %s, %s', id_pass_end, wxcutils.epoch_to_local(id_pass_end, '%a %d %b %H:%M')) MY_LOGGER.debug('twighlight allowance in minutes = %s', CONFIG_INFO['twilight allowance']) id_twighlight = float(CONFIG_INFO['twilight allowance']) * 60 MY_LOGGER.debug('twighlight allowance in seconds = %f', id_twighlight) if (float(daylight_start) - id_twighlight) <= id_pass_midpoint <= (float(daylight_end) + id_twighlight) or \ (float(daylight_start) - id_twighlight) <= id_pass_midpoint <= (float(daylight_end) + id_twighlight): MY_LOGGER.debug('This is a daylight pass') return 'Y' else: MY_LOGGER.debug('This is NOT a daylight pass') except: MY_LOGGER.debug('Exception during is_daylight: %s %s %s', sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]) MY_LOGGER.debug( 'Assuming it is daylight so as to always capture a file in this case' ) return 'Y' return 'N'
def get_all_passes(tle: [str], lat_deg: float, long_deg: float, start_datetime_utc: datetime, end_datetime_utc: datetime, approved_passes: [OrbitalPass] = None, elev_m: float = 0.0, horizon_deg: float = 0.0, min_duration_s: int = 0) -> [OrbitalPass]: """ Get a list of all passes for a satellite and location for a time span. Wrapper for Skyfield TLE ground station pass functions that produces an OrbitalPass object list of possible passes. Parameters ---------- tle : [str] Can be [tle_line1, tle_line2] or [tle_header, tle_line1, tle_line2] lat_deg : float latitude of ground station in degrees long_deg : float longitude of ground station in degrees start_datetime_utc : datetime The start datetime wanted. end_datetime_utc : datetime The end datetime wanted. approved_passes : [OrbitalPass] A list of OrbitalPass objects for existing approved passes. elev_m : float elevation of ground station in meters horizon_deg : float Minimum horizon degrees min_duration_s : int Minimum duration wanted Raises ------ ValueError If the tle list is incorrect. Returns ------- [OrbitalPass] A list of OrbitalPass. """ pass_list = [] load = Loader('/tmp', verbose=False) ts = load.timescale() t0 = ts.utc(start_datetime_utc.replace(tzinfo=timezone.utc)) t1 = ts.utc(end_datetime_utc.replace(tzinfo=timezone.utc)) # make topocentric object loc = Topos(lat_deg, long_deg, elev_m) loc = Topos(latitude_degrees=lat_deg, longitude_degrees=long_deg, elevation_m=elev_m) # make satellite object from TLE if len(tle) == 2: satellite = EarthSatellite(tle[0], tle[1], "", ts) elif len(tle) == 3: satellite = EarthSatellite(tle[1], tle[2], tle[0], ts) else: raise ValueError("Invalid tle string list\n") # find all events t, events = satellite.find_events(loc, t0, t1, horizon_deg) # make a list of datetimes for passes for x in range(0, len(events)-3, 3): aos_utc = t[x].utc_datetime() los_utc = t[x+2].utc_datetime() duration_s = (los_utc - aos_utc).total_seconds() if duration_s > min_duration_s: new_pass = OrbitalPass(gs_latitude_deg=lat_deg, gs_longitude_deg=long_deg, aos_utc=aos_utc.replace(tzinfo=None), los_utc=los_utc.replace(tzinfo=None), gs_elevation_m=elev_m, horizon_deg=horizon_deg) if not pass_overlap(new_pass, approved_passes): pass_list.append(new_pass) # add pass to list return pass_list
plotstill = True plot = False plot_gif = False animate = False animated = False qdate = [] qxyz = [] dayskip = 1 #C3 math: solar escape velocity = 42.12 km/s # earth orbital velocity = 29.78 km/s # velocity needed to get free of Earth (11.2 km/s) = 12.7 km/s # velocity needed to get free of Sun (42.12-29.78-12.7) = 6.72 km/s # Total delta-v sunk into launch: 12.7+6.72 = 19.42 km/s load = Loader('./skyfield_data') ts = load.timescale() t = ts.utc(2028, 1, range(0, 18000, dayskip)) dates = t.utc_datetime() plist, pcol, plen, psym, rp, mp = get_planet_details(dayskip) #also need Quaoar: getting from #https://naif.jpl.nasa.gov/pub/naif/pds/data/nh-j_p_ss-spice-6-v1.0/nhsp_1000/data/spk/kbo_centaur_20170422.bsp #kbosdata = load('kbo_centaur_20170422.bsp') #print(kbosdata) #Approximate location of quaoar at intercept for trajectory1 with open('Data/quaoar.txt', 'r') as qfile: lines = qfile.readlines()[64:1202] dates = lines[::2] coord = lines[1::2]
def test_load_finals_builtins(tmpdir): load = Loader(get_skyfield_data_path()) with mock.patch('skyfield.iokit.download') as download_patched: load.timescale(builtin=True) assert download_patched.call_count == 0
def trajectory(context): """Calculate the path loss for a given trajectory. Args (context): tle_file: the file containing the TLE of all the satellites, must contains the following columns: tle1, tle2, norad_id. trajectory_file: the file containing the trajectory, must contains the following columns: altitude, longitude, latitude, time. frequency: the frequency, in hertz, of the carrier timestamp: the UTC Epoch timestamp (number of seconds since 01/01/1970). output_file: the file where the data are saved. confirm: whether or not we have to ask for confirmation. """ satellites_file = context.tle_file trajectory_file = context.trajectory_file frequency = context.frequency timestamp = context.time save_file = context.output_file write_trajectories = context.write_trajectories confirm = context.confirm print("Calculating the trajectory") # Set up skyfield load = Loader(".") data = load('de421.bsp') ts = load.timescale() planets = load('de421.bsp') # Load satellites orbits satellites = {} with open(satellites_file, 'r') as csvfile: reader = csv.reader(csvfile, delimiter=',') header = next(reader, None) tle1_index, tle2_index, id_index = header_indexes(header, ["tle1", "tle2", "norad_id"]) for row in reader: name, L1, L2 = row[id_index], row[tle1_index], row[tle2_index] satellites[name] = EarthSatellite(L1, L2) # Check if the output file already exists if confirm and os.path.isfile(save_file): if not confirmation("\"{}\" already exists. Overwrite it ?".format(save_file)): raise RuntimeError("Aborting trajectory calculation.") # Calculate attenuation at each point of the trajectory data = [] # List of list, [time, dist1, dist2, ..., dist N, minimum dist, minimum name, path_loss] with open(trajectory_file, 'r') as csvfile: reader = csv.reader(csvfile, delimiter=',', quotechar='\"') header = next(reader, None) altitude_index, longitude_index, latitude_index, time_index = header_indexes(header, ["altitude", "longitude", "latitude", "time"]) for row in reader: tofloat = lambda s : float(s.replace(',','.')) try: altitude, longitude, latitude, rela_time = tofloat(row[altitude_index]), tofloat(row[longitude_index]), tofloat(row[latitude_index]), tofloat(row[time_index]) except ValueError as e: raise RuntimeError("Ill-formed trajectory file ({}).".format(e)) epoch_time = timestamp + rela_time new_time = datetime.datetime.utcfromtimestamp(epoch_time) time = ts.utc(new_time.year, new_time.month, new_time.day, new_time.hour, new_time.minute, new_time.second) pos = Topos(longitude_degrees=longitude, latitude_degrees=latitude, elevation_m=altitude).at(time) data.append([epoch_time, longitude, latitude, altitude]) min_dist = math.inf min_name = "None" dists = [] for name, sat in satellites.items(): pos_relay = sat.at(time) dist = length_of((pos_relay-pos).distance().m) dists.append(dist) los = line_of_sight(pos, pos_relay) dists.append(path_loss(frequency, dist) if los else "") dists.append(line_of_sight(pos, pos_relay)) if los and dist < min_dist: min_dist = dist min_name = name if write_trajectories: sub = pos_relay.subpoint() # dists.extend(list(pos_relay.itrf_xyz().m)) dists.extend([sub.longitude.degrees, sub.latitude.degrees, sub.elevation.m]) data[-1].append(min_dist) data[-1].append(min_name) data[-1].append(path_loss(frequency, min_dist)) data[-1].extend(dists) # Save the file with open(save_file, 'w', newline='') as csvfile: spamwriter = csv.writer(csvfile, delimiter=',') sat_headers = [] for name in satellites: sat_headers.extend([name + ":dist (m)", name + ":path_loss (dB)", name + ":los"]) if write_trajectories: sat_headers.extend([name+":longitude (°)", name+":latitude (°)", name+":altitude (m)"]) spamwriter.writerow(["time (s)", "longitude (°)", "latitude (°)", "altitude (m)"] + ["minimum_dist (m)", "minimum_name (norad id)", "path_loss (dB)"] + sat_headers) for line in data: spamwriter.writerow(line)
return centers, hw TLE = """1 43205U 18017A 18038.05572532 +.00020608 -51169-6 +11058-3 0 9993 2 43205 029.0165 287.1006 3403068 180.4827 179.1544 08.75117793000017""" L1, L2 = TLE.splitlines() from skyfield.api import Loader, EarthSatellite from skyfield.timelib import Time import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D halfpi, pi, twopi = [f*np.pi for f in (0.5, 1, 2)] degs, rads = 180/pi, pi/180 load = Loader('~/Documents/fishing/SkyData') data = load('de421.bsp') ts = load.timescale() planets = load('de421.bsp') earth = planets['earth'] Roadster = EarthSatellite(L1, L2) print(Roadster.epoch.tt) hours = np.arange(0, 3, 0.01) time = ts.utc(2018, 2, 7, hours) Rpos = Roadster.at(time).position.km Rposecl = Roadster.at(time).ecliptic_position().km
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: obsgeoloc, obsgeovel = location.get_gcrs_posvel(t) frame = GCRS(obstime=t, obsgeoloc=obsgeoloc, obsgeovel=obsgeovel) else: frame = GCRS(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) moon_astropy = get_moon(t, location, ephemeris='de430') mercury_astropy = get_body('mercury', t, location, ephemeris='de430') jupiter_astropy = get_body('jupiter', t, location, ephemeris='de430') # convert to true equator and equinox jupiter_astropy = _apparent_position_in_true_coordinates(jupiter_astropy) mercury_astropy = _apparent_position_in_true_coordinates(mercury_astropy) moon_astropy = _apparent_position_in_true_coordinates(moon_astropy) 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)
## 从网络导入空间站数据 # stations_url = 'http://celestrak.com/NORAD/elements/stations.txt' # satellites = load.tle(stations_url) # satellite = satellites['ISS (ZARYA)'] # all_satellites_names = list(satellites.keys()) # all_satellites = list(satellites.values()) tle_path = "Full_Catalog-20190613T0000.tle" satellites = load.tle(tle_path) MAX_NUMBER = 100 all_satellites_names = np.array(list(satellites.keys()))[:MAX_NUMBER] all_satellites = np.array(list(satellites.values()))[:MAX_NUMBER] load = Loader(directory='.', expire=False) # expire=False: use local files ts = load.timescale() from skyfield.api import Loader, EarthSatellite from skyfield.timelib import Time import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D halfpi, pi, twopi = [f*np.pi for f in (0.5, 1, 2)] degs, rads = 180/pi, pi/180
ind = cwd.find('metis') metis_dir = Path(cwd[0:ind + 5]) from skyfield.api import Loader, utc from utilities.tle_functions import launchecef2tle, propagate_TLE, gcrf2tle from utilities.tle_functions import tledict2dataframe, kep2tle from utilities.constants import Re from sensors.visibility_functions import compute_visible_passes from sensors.visibility_functions import generate_visibility_file # Generate TLEs every 4 hours for first 24 hours, then every 12-24 hours after if __name__ == '__main__': load = Loader(os.path.join(metis_dir, 'skyfield_data')) ephemeris = load('de430t.bsp') ts = load.timescale() # RocketLab launch data from June 2018 # UTC = datetime(2018,6,23,4,10,21) # r_ITRF = 0.001*np.array([[-3651380.321], [1598487.431], [-5610448.359]]) # v_ITRF = 0.001*np.array([[5276.523548], [-3242.081015], [-4349.310553]]) # Rasit TLE (modified drag related terms) # line1 = '1 90001U 18999B 18178.09260417 +.00000000 +00000-0 +00000-0 0 9998' # line2 = '2 90001 084.9994 273.8351 0013325 288.2757 306.6473 15.21113008601617' # Compute TLE dictionary and dataframe at this time obj_id = 90001 # ecef_dict = {}