def getSatelliteVisable(satelliteName): #stations_url = 'http://celestrak.com/NORAD/elements/amateur.txt' stations_url = 'https://www.amsat.org/tle/current/nasabare.txt' satellites = load.tle_file(stations_url) #print('Loaded', len(satellites), 'satellites') ts = load.timescale() # San Diego home = Topos('32.48 N', '117.22 W') today = datetime.today() # timeframe to search for passes plus_time = 2 t0 = ts.utc(today.year, today.month, today.day, today.hour) t1 = ts.utc(today.year, today.month, today.day + plus_time) # get visible time for requested satellite by_name = {sat.name: sat for sat in satellites} satellite = by_name[satelliteName] t, events = satellite.find_events(home, t0, t1, altitude_degrees=10.0) for ti, event in zip(t, events): name = ('rise above 10°', 'culminate', 'set below 10°')[event] print(ti.utc_strftime('%Y %b %d %H:%M:%S'), name)
def loadSatellites(val): satellites = load.tle_file(constellationToLink[val]["link"], filename="%s.txt" % val) redisServer = constellationRedis[val] for satellite in satellites: data = {} tle = tlefile.read(satellite.name, "%s.txt" % val) data['platform'] = tle.platform data['line1'] = tle.line1 data['line2'] = tle.line2 json_data = json.dumps(data) redisServer.set(tle.platform, json_data) os.remove("%s.txt" % val) message = "Loaded " + str( len(satellites)) + " satellites to " + str(val) + " database" print(message) connection = pika.BlockingConnection( pika.ConnectionParameters(host=rabbitMQHost)) logChannel = connection.channel() logChannel.exchange_declare(exchange='logs', exchange_type='topic') logChannel.basic_publish(exchange='logs', routing_key='databaseUpdater.info', body=message)
def loadSatellites(self): ''' :return: ''' self.satellites = load.tle_file(self.url) return
def get_satellites(): """ Gets a list of satellites from celestrak and returns a dictionary of skyfield EarthSatellites """ STATIONS_URL = "http://celestrak.com/NORAD/elements/stations.txt" satellites = load.tle_file(STATIONS_URL) return {sat.name: sat for sat in satellites}
def load_tles(self): """Get all the amateur satellite TLEs from celestrak and save the TLEs in text file `satellites.tle`. """ # Get the satelliteBodyObjects from the TLEs file stations_url = 'http://celestrak.com/NORAD/elements/amateur.txt' self.satellite_body_objects = load.tle_file(stations_url) QMessageBox.information(self, "Ephemera", 'TLEs Downloaded!', QMessageBox.Ok)
def __init__(self): self.gps = load.tle_file("https://celestrak.com/NORAD/elements/gps-ops.txt") self.galileo = load.tle_file("https://celestrak.com/NORAD/elements/galileo.txt") self.glonass = load.tle_file("https://celestrak.com/NORAD/elements/glo-ops.txt") self.beidou = load.tle_file("https://celestrak.com/NORAD/elements/beidou.txt") self.allsat = self.gps+self.galileo+self.glonass+self.beidou print('Loaded', len(self.allsat), 'satellites') # create dict where we can fetch a satellite using its name as key self.sats_by_name = {sat.name: sat for sat in self.allsat} # Define observatory for az,el calculation self.obs = Topos('57.393109 N', '11.917798 E') # OSO25m # Define timerange, https://rhodesmill.org/skyfield/time.html self.ts = load.timescale() self.tgps = False self.tgalileo = False self.tglonass = False self.tbeidou = False #self.sat2plot = self.gps+self.galileo self.sat2plot = [] # Plot the data, awaiting key-press events self.plot()
def processTLE( tlefilename ): #removes duplicates from a 3le file. The satellites need to be ordered by norad id number list_of_satellites = load.tle_file(tlefilename) print('Loaded', len(list_of_satellites), 'satellites') processed_list = [] for i in range(len(list_of_satellites)): if i + 1 < len(list_of_satellites) and list_of_satellites[ i + 1].model.satnum == list_of_satellites[i].model.satnum: continue else: processed_list.append(list_of_satellites[i]) print('Removed duplicates,', len(processed_list), 'satellites remaining') return processed_list
def getData(sat_url): #removeFile.remCall() satellites = load.tle_file(sat_url) print('Loaded', len(satellites), 'satellites') t = ts.now() for sat in satellites: geocentric = sat.at(t) subpoint = geocentric.subpoint() satList.append({ 'name': str(sat.name), 'number': str(sat.model.satnum), 'Latitude': str(subpoint.latitude.degrees), 'Longitude': str(subpoint.longitude.degrees), 'altitude': str(round(subpoint.elevation.m)), 'Inclination-rad': str(sat.model.inclo), 'position-GCRS': str(geocentric.position.km) })
def getTLEs(self): """Get TLEs of a given satellite from Internet and save into a file""" url = 'https://celestrak.com/satcat/tle.php?CATNR={}'.format( self.catnr) self.filename = 'tle-CATNR-{}.txt'.format(self.catnr) try: # TODO: Use logger for logging print("Fetching TLEs for satellite with catalog number {}.".format( self.catnr)) tle = load.tle_file(url, filename=self.filename, reload=True) except OSError: print("An error occurred while fetching the TLEs") print("Are you connected to Internet?") else: print("TLEs are saved in {}".format(self.filename))
def get_data(): """ Downloads satellite data and creates a list of satellite objects Parameters: Returns: satellites: array of skyfield satellite objects """ # download satellite data with open("urls.txt", "r") as f: satellites = list() for line in f.readlines(): # you could switch this appendage around if you wanted # to have your sources ranked in a reverse priority satellites = satellites + load.tle_file(line.replace('\n', '')) os.remove(line.replace('\n', '').split('/')[-1]) return satellites
def set_up_satellite_data(self): """Set up the satellite data.""" # Get the satelliteBodyObjects from the TLEs file stations_url = 'http://celestrak.com/NORAD/elements/amateur.txt' self.satellite_body_objects = load.tle_file(stations_url) self.by_number = { sat.model.satnum: sat for sat in self.satellite_body_objects } # Get the satellite data from the json file with open('satslist.json', 'r') as f: self.satellite_data = json.load(f) # Merge the two # list of NORAD numbers in self.satelliteBodyObjects numbers = { sat.model.satnum: sat for sat in self.satellite_body_objects } # Create a dict of satellite_data dicts where the NORAD numbers are also # in satellite_body_objects, i.e. where we have both TLEs and satellite_name info self.satellites = { s: self.satellite_data[s] for s in self.satellite_data if (self.satellite_data[s]['Number'] in str(numbers.keys()) and self.satellite_data[s]['Status'] in ['active', 'operational']) } # Fill the modes and Select Satellite combo boxes self.fill_combo_box_with_list_of_modes() self.fill_select_satellite_combo() # Start the Auto-updater self.auto_update_timer = QTimer() self.auto_update_timer.timeout.connect(self.on_auto_update_timer) self.auto_update_timer.start(1 * 1000) # Start the clock-updater self.clock_update_timer = QTimer() self.clock_update_timer.timeout.connect(self.on_clock_update) self.clock_update_timer.start(1000)
def __init__(self): global load, utc, Topos global TEME_to_ITRF, SatrecArray, angle_between, length_of, tau, DAY_S global np from skyfield.api import load, utc, Topos from skyfield.sgp4lib import TEME_to_ITRF from sgp4.api import SatrecArray from skyfield.functions import angle_between, length_of from skyfield.constants import tau, DAY_S import numpy as np filename="tracking/iridium-NEXT.txt" self.satlist = load.tle_file(filename) if config.verbose: print(("%i satellites loaded into list"%len(self.satlist))) self.epoc = self.satlist[0].epoch self.ts=load.timescale(builtin=True) if config.verbose: tnow = self.ts.utc(datetime.datetime.now(datetime.timezone.utc)) days = tnow - self.epoc print('TLE file is %.2f days old'%days)
def finding_satellite_ele(): # Finding and loading satellite elements: stations_url = 'http://celestrak.com/NORAD/elements/stations.txt' # last_30_days = 'http://celestrak.com/NORAD/elements/tle-new.txt' # satellites = load.tle_file(last_30_days) satellites = load.tle_file(stations_url) # # print('Loaded', len(satellites), 'satellites') by_name = {sat.name: sat for sat in satellites} # satellite = by_name['ISS (ZARYA)'] # # print(satellite) planets = load('de421.bsp') #finding sunligth in earth from mars earth, venus = planets['earth'], planets['moon'] satellite = by_name['ISS (ZARYA)'] ts = load.timescale() two_hours = ts.utc(2019, 8, 14, 0, range(0, 120, 20)) p = (earth + satellite).at(two_hours).observe(venus).apparent() # print(p) sunlit = p.is_behind_earth() sunlight = [] for t_h, sunlit_i in zip(two_hours, sunlit): data = '{} {} is in {}'.format( t_h.utc_strftime('%Y-%m-%d %H:%M'), satellite.name, 'sunlight' if sunlit_i else 'shadow') sunlight.append(data) bluffton = Topos('20.5937 N', '78.9629 E', elevation_m=43) t0 = ts.utc(2020, 8, 13) t1 = ts.utc(2020, 8, 14) tn, events = satellite.find_events(bluffton, t0, t1, altitude_degrees=30.0) sunlight_time = [] for ti, event in zip(tn, events): name = ('rise above 30°', 'culminate', 'set below 30°')[event] time = ti.utc_strftime('%Y %b %d %H:%M:%S'), name sunlight_time.append(time) return jsonify({"earth_light":sunlight,"sunlight_time":sunlight_time})
2020 ''' from skyfield.api import EarthSatellite, load, Topos import datetime, pytz import numpy as np # The resolution of the calculated path of the satellite RES = 20000 # The host of the tle dataset TLE_HOST = 'https://www.celestrak.com/NORAD/elements/active.txt' # A specific satellite chosen from the tle dataset SAT_CHOSEN = 'KEPLER-1 (CASE)' # Get the tle data of the satellite chosen tle_sats = load.tle_file(TLE_HOST) print("loaded {} satellites from {}".format(len(tle_sats), TLE_HOST)) sats_by_name = {sat.name: sat for sat in tle_sats} sat_chosen = sats_by_name[SAT_CHOSEN] print(sat_chosen) # Get current time, end time, and time difference (delta) between each sample based on RES ts = load.timescale() ti = datetime.datetime.now(pytz.utc) # pytz.utc ensures utc encodding tf = ti + datetime.timedelta(days=1) delta = (tf - ti) / RES latitude = [] longitude = [] # Using the delta calculated earlier, we find the longitude and latitude at a time
from skyfield.api import load from skyfield.framelib import ICRS_to_J2000 import numpy as np z_vector = np.array([0, 0, 1]) ts = load.timescale() junk = load.tle_file("spacejunk.tle") sats = load.tle_file("sats.tle") killed = [] for i in range(60, 3600 * 24, 60): if len(killed) == 59: #>= 51: break t = ts.utc(2021, 6, 26, i // 3600, (i // 60) % 60, i % 60) jks_xyz = [] sats_xyz = [] for ii, jk in enumerate(junk): if ii in killed: jks_xyz.append(np.array([0., 0., 0.])) else: pos = np.dot(ICRS_to_J2000, jk.at(t).position.km) jks_xyz.append(pos) for sat in sats: pos = np.dot(ICRS_to_J2000, sat.at(t).position.km) sats_xyz.append(pos) for sidx, sat_xyz in enumerate(sats_xyz):
def loadTLE(filename): satlist = load.tle_file(filename) if verbose: print("%i satellites loaded into list" % len(satlist)) return satlist
epoch='>now-30', format='3le') with open('data.txt', 'w') as f: for line in data_generator: f.write(line + '\n') df = load_dataframe('data.txt') df['a'] = df['n'].apply(lambda n: (8681663.653 / n)**(2 / 3)) df['ah'] = df['a'] * (1 - df['ecc']) - 6371 df['ph'] = df['a'] * (1 + df['ecc']) - 6371 satellites_tle = [] satellites = load.tle_file('data.txt') print(len(satellites)) ts = load.timescale() t = ts.now() # Высокоэллиптические орбиты HEO = df[(df['ah'] <= 2000) & (df['ph'] >= 35786)] # «Молния» molniya = HEO[(HEO['inc'].between(60.8, 64.8)) & (HEO['n'].between(2.004, 2.01))] # «Тундра» tundra = df[(df['argp'].between(240, 300))
import matplotlib.pyplot as plt import numpy as np # The list of links with TLE data #GPS https://celestrak.com/NORAD/elements/gps-ops.txt #GALILEO https://celestrak.com/NORAD/elements/galileo.txt #GLONASS https://celestrak.com/NORAD/elements/glo-ops.txt #BEIDOU https://celestrak.com/NORAD/elements/beidou.txt #stations 'http://celestrak.com/NORAD/elements/stations.txt' import time from skyfield.api import Topos, load #https://rhodesmill.org/skyfield/earth-satellites.html gps = load.tle_file("https://celestrak.com/NORAD/elements/gps-ops.txt") galileo = load.tle_file("https://celestrak.com/NORAD/elements/galileo.txt") glonass = load.tle_file("https://celestrak.com/NORAD/elements/glo-ops.txt") beidou = load.tle_file("https://celestrak.com/NORAD/elements/beidou.txt") #satellites = gps + galileo + glonass + beidou #satellites = galileo + glonass #satellites = gps + galileo satellites = gps + beidou #print('Loaded', len(satellites), 'satellites') # create dict where we can fetch a satellite using its name as key sats_by_name = {sat.name: sat for sat in satellites} # Define observatory for az,el calculation obs = Topos('57.393109 N', '11.917798 E') # OSO25m # Define timerange. First time will be used for azelplot,
from skyfield.api import Topos, load import numpy as np ts = load.timescale() satellites = load.tle_file( 'https://www.celestrak.com/NORAD/elements/stations.txt') sat = satellites[0] def getLocationData(): print('Loaded', sat) t = ts.now() geocentric = sat.at(t) subpoint = geocentric.subpoint() return ({ 'name': str(sat.name), 'number': str(sat.model.satnum), 'Latitude': str(subpoint.latitude.degrees), 'Longitude': str(subpoint.longitude.degrees), 'altitude': str(round(subpoint.elevation.m)), 'Inclination-rad': str(sat.model.inclo), 'position-GCRS': str(geocentric.position.km) }) def getOrbits(): t_utc = ts.now().utc_datetime() minutes = np.arange(0, 200, 0.1) # about two orbits year = int(t_utc.strftime("%Y")) month = int(t_utc.strftime("%m"))
from skyfield.api import Topos, load from spack_track import getTLESatellites station_url2 = getTLESatellites("2019-09-25--2019-09-26") f = open("demofile4.txt", "w") f.write(station_url2) f.close() ts = load.timescale() t = ts.now() bluffton = Topos('37.67 N', '122.08 W') satellites = load.tle_file("demofile4.txt", reload=True) print('Loaded', len(satellites), 'satellites') print(bluffton) for satellite in satellites: geometry = satellite.at(t) subpoint = geometry.subpoint() latitude = subpoint.latitude longitude = subpoint.longitude elevation = subpoint.elevation difference = satellite - bluffton print(satellite) topocentric = difference.at(t) print(topocentric.position.km[2]) # print("Latitude, Lng, Ele", latitude, longitude, elevation)
#!/usr/bin/env python from skyfield.api import EarthSatellite from skyfield.api import load from skyfield.positionlib import Geocentric from skyfield.units import Angle ts = load.timescale() # Time used to find correct satellite t = ts.utc(2020, 3, 18, 6, 17, 23.0) # Coordinates used to find correct satellite loc = Geocentric([-393.9579313710918, -4609.1758828158, -4905.812181143784]) stations = load.tle_file('wheres_the_sat.tle') print('Loaded', len(stations), 'stations') # Zero degrees separation nada = Angle(degrees=0) # Iterate over stations looking for a collision (zero degrees separation) for station in stations: geocentric = station.at(t) if geocentric.separation_from(loc).degrees == nada.degrees: # Found a collision print(station.name) tgt = station # Time used to find next waypoint t2 = ts.utc(2020, 3, 18, 22, 44, 49.0) # Coordinates of next waypoint geocentric = tgt.at(t2)
def fetch(sat_name): stations_url = 'http://www.celestrak.com/NORAD/elements/amateur.txt' #URL for pulling TLE data satellites = load.tle_file(stations_url,reload=True) #Object for storing TLE data for all satellites by_name = {sat.name: sat for sat in satellites} #Dictionary of satellite data sat = by_name[sat_name] #create sat object with ISS data return sat
def run(challenge): ''' CHALLENGE:\n [challenge0, challenge1, challenge2, challenge3, challenge4, live] ''' if challenge not in CHALLENGES: print('invalid challenge') return challenge = CHALLENGES[challenge] found_sat = None try: sats = load.tle_file('examples/active.txt') for sat in sats: if sat.name == challenge['satellite_name']: found_sat = sat break assert found_sat print(sat) print() except: print('no sat') sys.exit(-1) ts = load.timescale(builtin=True) trackasat = Topos(challenge['trackasat_lat'], challenge['trackasat_long']) difference = sat - trackasat current_time = datetime.fromtimestamp(challenge['start_time_gmt'], timezone.utc) final_time = current_time + timedelta(0, DURATION_SECONDS) t_current = ts.utc(current_time) topocentric = difference.at(t_current) start_elevation, start_azimuth, distance = topocentric.altaz() print('start_azimuth:', start_azimuth.degrees) print('start_elevation:', start_elevation.degrees) t_final = ts.utc(final_time) topocentric = difference.at(t_final) final_elevation, final_azimuth, distance = topocentric.altaz() print('final_azimuth:', final_azimuth.degrees) print('final_elevation:', final_elevation.degrees) azimuth_range = start_azimuth.degrees - final_azimuth.degrees azimuth_range = abs((azimuth_range + 180) % 360 - 180) print('azimuth range:', azimuth_range) with open(OUTPUT_FILE, 'w') as f: for _ in range(DURATION_SECONDS): t_current = ts.utc(current_time) topocentric = difference.at(t_current) elevation, current_azimuth, distance = topocentric.altaz() if (current_azimuth.degrees >= 180 and current_azimuth.degrees < 360): orientation = 180 elevation_inverted = True else: orientation = 0 elevation_inverted = False trackasat_azimuth = abs( (current_azimuth.degrees - orientation + 180) % 360 - 180) trackasat_azimuth_pwm = (trackasat_azimuth * 4915 / 180) + 2457 if elevation_inverted: trackasat_elevation_pwm = \ (4915 * (180 - elevation.degrees) / 180) + 2457 else: trackasat_elevation_pwm = \ (4915 * elevation.degrees / 180) + 2457 f.write( str(current_time.timestamp()) + ', ' + str(int(trackasat_azimuth_pwm)) + ', ' + str(int(trackasat_elevation_pwm)) + '\n') current_time = current_time + timedelta(0, 1) f.write('\n\n') print('\nwrote', OUTPUT_FILE) f.close() diff = challenge['diff'] if diff: print() diff_string = EXAMPLES_FOLDER + '/' + diff + ' ' + OUTPUT_FILE print('diff', diff_string) print('vimdiff', diff_string)
def run(verbose, challenge, signal): 'CHALLENGE: [examples, live], SIGNAL: [signal_0, signal_1, signal_2]' if challenge not in CHALLENGES: print('invalid challenge') return if signal not in ['signal_0', 'signal_1', 'signal_2']: print('invalid signal') return challenge = CHALLENGES[challenge] positions = [] with open(challenge['directory'] + '/' + signal + '.csv', 'r') as input_file: if not input_file: 'file not found. did you run signal_to_pwm.py?' return for line in input_file: positions.append(eval(line)) assert positions print('loaded', len(positions), 'positions\n') if verbose: print('positions[0].azimuth:', positions[0]['azimuth']) print('positions[0].elevation:', positions[0]['elevation']) print('positions[len(positions) - 1][\'azimuth\']', positions[len(positions) - 1]['azimuth']) print('positions[len(positions) - 1][\'elevation\']', positions[len(positions) - 1]['elevation']) positions_azimuth_range = \ positions[0]['azimuth'] - positions[len(positions) - 1]['azimuth'] positions_azimuth_range = \ abs((positions_azimuth_range + 180) % 360 - 180) print('azimuth range:', positions_azimuth_range) print( 'elevation range:', abs(positions[0]['elevation'] - \ positions[len(positions) - 1]['elevation']) ) print() sats = load.tle_file('examples/active.txt') print('loaded', len(sats), 'sats') ts = load.timescale(builtin=True) matches = [] for sat in sats: print(sat) trackasat = Topos(challenge['trackasat_lat'], challenge['trackasat_long']) difference = sat - trackasat starting_time = datetime.fromtimestamp(challenge['start_time_gmt'], timezone.utc) final_time = starting_time + timedelta(0, 120) if verbose: t_starting = ts.utc(starting_time) topocentric = difference.at(t_starting) start_elevation, start_azimuth, distance = topocentric.altaz() print('start_azimuth:', start_azimuth.degrees) print('start_elevation:', start_elevation.degrees) t_final = ts.utc(final_time) topocentric = difference.at(t_final) final_elevation, final_azimuth, distance = topocentric.altaz() print('final_azimuth:', final_azimuth.degrees) print('final_elevation:', final_elevation.degrees) azimuth_range = start_azimuth.degrees - final_azimuth.degrees azimuth_range = abs((azimuth_range + 180) % 360 - 180) print('azimuth range:', azimuth_range) elevation_range = abs(start_elevation.degrees - final_elevation.degrees) print('elevation range:', elevation_range) success = True fail_count = 0 for position in positions: working_time = starting_time + timedelta(0, position['time']) t_working = ts.utc(working_time) topocentric = difference.at(t_working) elevation, azimuth, distance = topocentric.altaz() if elevation.degrees < 0: success = False break if verbose: print(azimuth.degrees, elevation.degrees, position['azimuth'], position['elevation']) if ( abs(azimuth.degrees - position['azimuth']) > \ AZ_ACCURACY_THRESHOLD or abs(elevation.degrees - position['elevation']) > \ EL_ACCURACY_THRESHOLD ): if verbose: print('mismatch:', azimuth.degrees - position['azimuth'], elevation.degrees - position['elevation']) fail_count += 1 if fail_count > FAIL_THRESHOLD: if verbose: print('sat failed with fail_count:', fail_count) success = False break if success: matches.append({'name': sat.name, 'fail_count': fail_count}) print() print('expected: ' + challenge[signal]) print('matches:') for match in matches: print(match) stop = timeit.default_timer() print('\nruntime:', stop - start)
import time import csv from skyfield.api import load, wgs84 # create time scale ts = load.timescale() # load satellite data from NORAD url = 'https://www.celestrak.com/NORAD/elements/active.txt' filename = 'active.txt' satellites = load.tle_file(url, filename=filename) saveFile = '../data/{take}/data_{frame:03d}.csv' take = 'take-001' numFrames = 60 # start an fixed loop for frame in range(numFrames): outPutFile = saveFile.format(frame=frame, take=take) # get current time. t = ts.now() # create our labels. header = ['name', 'x', 'y', 'z'] # create empty data struct data = [] # add header to data structure data.append(header)
def create_random_challenge(self, seed, num_sats=3) -> RandomChallenge: # create rng with the given seed random.seed(seed) sys.stderr.write("Seed: %d\n" % seed) # load LEO satellites satellites = load.tle_file(self.tle_filepath) leo_satellites = [ sat for sat in satellites if sat.model.no_kozai >= self.TWO_HOUR_ORBIT_RADIANS_PER_MIN ] # choose a time ts = load.timescale(builtin=True) time_mid = leo_satellites[0].epoch.astimezone(utc) time_min = time_mid - self.ONE_WEEK_TIME time_max = time_mid + self.ONE_WEEK_TIME time_range_s = (time_max - time_min).total_seconds() challenge_time_offset = datetime.timedelta(seconds=time_range_s * random.random()) challenge_t_start = time_min + challenge_time_offset challenge_t_end = challenge_t_start + self.CHALLENGE_INTERVAL challenge_t_utc = (datetime.datetime.utcfromtimestamp( challenge_t_start.timestamp()), datetime.datetime.utcfromtimestamp( challenge_t_end.timestamp())) challenge_t_ts = (ts.utc( challenge_t_utc[0].year, challenge_t_utc[0].month, challenge_t_utc[0].day, challenge_t_utc[0].hour, challenge_t_utc[0].minute, challenge_t_utc[0].second + challenge_t_utc[0].microsecond / 1000000.0), ts.utc( challenge_t_utc[1].year, challenge_t_utc[1].month, challenge_t_utc[1].day, challenge_t_utc[1].hour, challenge_t_utc[1].minute, challenge_t_utc[1].second + challenge_t_utc[0].microsecond / 1000000.0)) # retry up to 10 times (very unlikely) for i in range(10): # choose a groundstation groundstations = self.load_groundstations( self.groundstations_filepath) challenge_groundstation: Groundstation = random.choice( groundstations) loc = Topos(challenge_groundstation.latitude, challenge_groundstation.longitude) # find visible satellites candidate_satellites = [] for sat in leo_satellites: _d = sat - loc alt_at_t_start, az_at_t_start, distance_at_t_start = _d.at( challenge_t_ts[0]).altaz() alt_at_t_end, az_at_t_end, distance_at_t_end = _d.at( challenge_t_ts[1]).altaz() if alt_at_t_start.degrees > 0 and alt_at_t_end.degrees > 0 and \ abs(alt_at_t_end.degrees - alt_at_t_start.degrees) >= 2*MIN_CANDIDATE_DISTANCE_DEGREES and \ abs(az_at_t_end.degrees - az_at_t_start.degrees) >= 2*MIN_CANDIDATE_DISTANCE_DEGREES: candidate_satellites.append( (sat, alt_at_t_start.degrees, az_at_t_start.degrees, alt_at_t_end.degrees, az_at_t_end.degrees)) if len(candidate_satellites) == 0: print( "Unable to find valid sats for this groundstation and this time! " "Retrying...", file=sys.stderr) # otherwise, try again with next groundstation (in random sequence) # but this is not a problem in this version continue def satellites_not_too_close(sat1, sat2): _, sat1_alt_start, sat1_az_start, sat1_alt_end, sat1_az_end = sat1 _, sat2_alt_start, sat2_az_start, sat2_alt_end, sat2_az_end = sat2 return abs(sat1_alt_start - sat2_alt_start) > MIN_CANDIDATE_DISTANCE_DEGREES \ and abs(sat1_alt_end - sat2_alt_end) > MIN_CANDIDATE_DISTANCE_DEGREES \ and abs(sat1_az_start - sat2_az_start) > MIN_CANDIDATE_DISTANCE_DEGREES \ and abs(sat1_az_end - sat2_az_end) > MIN_CANDIDATE_DISTANCE_DEGREES def satellites_too_close(sat1, sat2): _, sat1_alt_start, sat1_az_start, sat1_alt_end, sat1_az_end = sat1 _, sat2_alt_start, sat2_az_start, sat2_alt_end, sat2_az_end = sat2 return abs(sat1_alt_start - sat2_alt_start) < MIN_CANDIDATE_DISTANCE_DEGREES \ and abs(sat1_alt_end - sat2_alt_end) < MIN_CANDIDATE_DISTANCE_DEGREES \ and abs(sat1_az_start - sat2_az_start) < MIN_CANDIDATE_DISTANCE_DEGREES \ and abs(sat1_az_end - sat2_az_end) < MIN_CANDIDATE_DISTANCE_DEGREES ambiguous_sats = set() for sat1 in candidate_satellites: for sat2 in candidate_satellites: if sat1[0] != sat2[0] and satellites_too_close(sat1, sat2): ambiguous_sats.add(sat1) ambiguous_sats.add(sat2) def key(sat): return sat[0].name print("excluding {} ambiguous satellites from candidates".format( len(ambiguous_sats)), file=sys.stderr) candidate_satellites = set(candidate_satellites).difference( ambiguous_sats) candidate_satellites = list(candidate_satellites) candidate_satellites.sort(key=key) # choose random satellite from candidates challenge_satellites = [] retry = False for i in range(3): if len(candidate_satellites) < 3: print( "Unable to find valid sats for this groundstation and this time! " "Retrying...", file=sys.stderr) # otherwise, try again with next groundstation (in random sequence) # but this is not a problem in this version retry = True break challenge_sat = random.choice(candidate_satellites) candidate_satellites.remove(challenge_sat) challenge_satellites.append(challenge_sat[0]) if retry: continue start = challenge_t_utc[0].replace(tzinfo=datetime.timezone.utc) end = challenge_t_utc[1].replace(tzinfo=datetime.timezone.utc) seconds = int(end.timestamp() - start.timestamp()) print("{} from {}, {} at {}".format( ','.join([sat.name for sat in challenge_satellites]), challenge_groundstation.latitude, challenge_groundstation.longitude, start), file=sys.stderr) return RandomChallenge(challenge_satellites, challenge_groundstation, start.timestamp(), seconds) raise RuntimeError()
radians(float(arg_pericenter)), # argpo: argument of perigee (radians) radians(float(inclination)), # inclo: inclination (radians) radians(float(mean_anomaly)), # mo: mean anomaly (radians) mean_motion_radians_per_minute, # no_kozai: mean motion (radians/minute) radians(float(ra_asc_node) ), # nodeo: right ascension of ascending node (radians) ) return satrec MINUTES_PER_DAY = 24 * 60 ONE_METER = 1.0 / AU_M ONE_KM_PER_HOUR = 1.0 * 24.0 / AU_KM ts = load.timescale(builtin=True) # TLE stations_tle = load.tle_file("stations-tle.txt", reload=False) # XML tree = ET.parse("stations.xml") root = tree.getroot() t0 = ts.utc(2020, 6, 27) for sat_tle in stations_tle: name = sat_tle.name.strip() print(name, sat_tle.model.satnum) # Find and parse XML twin satrec = satrec_from_XML(root, sat_tle.model.satnum) sat_xml = EarthSatellite.from_satrec(satrec, ts) p_xml = sat_xml.at(t0) p_tle = sat_tle.at(t0) #print("XML Location", p_xml.position.au) #print("TLE location", p_tle.position.au)
import os import math from dotenv import load_dotenv load_dotenv() from skyfield.api import Topos, load from datetime import timedelta from pytz import timezone from twilio.rest import Client # load the satellite dataset from Celestrak starlink_url = 'https://celestrak.com/NORAD/elements/starlink.txt' starlinks = load.tle_file(starlink_url) print('Loaded', len(starlinks), 'satellites') # update city location's latitude and longitude and timezone location = Topos('37.7749 N', '122.4194 W') tz = timezone('US/Pacific') # establish time window of opportunity ts = load.timescale() t0 = ts.now() t1 = ts.from_datetime(t0.utc_datetime() + timedelta(hours=2)) # loop through satellites to find next sighting first_sighting = {} for satellite in starlinks: # filter out farthest satellites and NaN elevation elevation = satellite.at(t0).subpoint().elevation.km isNan = math.isnan(elevation) if elevation > 400 or isNan: continue
def NaticalMilesToStatueMiles(tNaticalMiles): return (float(tNaticalMiles) * 1.15) def StatuteMilesToNaticalMiles(tStatueMiles): return (float(tStatueMiles) / 1.15) def StatuteMilesToKilometers(tStatueMiles): return (float(tStatueMiles) * 1.609344) #stations_url = 'http://celestrak.com/NORAD/elements/stations.txt' #satellite = by_name['ISS (ZARYA)'] stations_url = "https://www.amsat.org/tle/current/nasabare.txt" #satellite = by_name['AO-07'] satellites = load.tle_file(stations_url) print('Loaded', len(satellites), 'satellites') ts = load.timescale(builtin=True) def gridCase(input): A='' B='' C='' D='' E='' F='' if (len(input)>= 4): chars = [char for char in input]
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!')