def predict(self, days=2.0): utc_now_seconds = float(datetime.now(tz=timezone('UTC')).timestamp()) self.logger.info( f"Time now in UTC is {datetime.now(tz=timezone('UTC')).isoformat()}" ) self.logger.info( f"Checking for {self.config.Lat}N {self.config.Lon}E {self.config.Lat}m " ) for sat in self.config.Sats: self.logger.debug(f"Checking for {sat}") sat, line1, line2 = self.tle_reader.find_sat(sat) if sat: self.logger.debug(f"We have TLE for {sat}") tle = f"{sat}\n{line1}\n{line2}\n" predict.observe(tle, self.config.Qth) try: p = predict.transits(tle, self.config.Qth, ending_after=utc_now_seconds - 900.0, ending_before=utc_now_seconds + days * 24.0 * 3600.0) passes = list(p) except Exception: passes = [] for orbit in passes: if orbit.peak()['elevation'] > self.config.MinAlt: when = datetime.fromtimestamp(orbit.start) #local_time = when.astimezone(timezone(self.config.TimeZone)) when_utc_str = when.strftime("%Y-%m-%d %H:%M:%S %Z%z") delay_str = self.secs_to_hms(orbit.start - utc_now_seconds) self.logger.info( f"{sat} Delay: {delay_str} Start: {when_utc_str} Duration: {int(orbit.duration()):4} Max Ele: {int(orbit.peak()['elevation']):3} " ) self.logger.debug(f"We have {len(passes)} Passes for {sat}")
def get_doppler(self, obs_time=None): if not obs_time: obs_time = time.time() prediction = predict.observe(self.tle, self.qth, obs_time) doppler = prediction['doppler'] correction = (self.freq/100E6) * doppler return correction
def getSatellitesAboveComplete(self): sats = {} ids = self.getIDs() for id in ids: data = self.mc.get("%s-data" % id) tle = "%s\n%s\n%s" % (data["satcat"]["SATNAME"], data["tle"][0], data["tle"][1]) # Get timezone offset based off of location # SUPER SLOW # Not using #tz = tzwhere.tzwhere() #timezone_str = tz.tzNameAt(self.qth[0], self.qth[1]) #print timezone_str utc_datetime = datetime.datetime.utcnow() local_datetime = utc_datetime - datetime.timedelta( minutes=self.offset) p = predict.observe(tle, self.qth, time.mktime(local_datetime.timetuple())) # This just gets me things above the horizon, not things actually visible if p["elevation"] > 0: #print "%s\nObject Type: %s\nNORAD ID: %s\nElevation: %s\nVisible: %s\n" % (p["name"],satData[ID]["catalogInfo"][0]["OBJECT_TYPE"], ID, p["elevation"], p["visibility"]) resultData = data resultData["prediction"] = p sats[id] = resultData self.sats = sats return sats
def test_transits_are_truncated_if_the_overlap_the_start_or_end_times(self): #predict.massage_tle(EXAMPLE_QTH) tle = predict.massage_tle(TLE) qth = predict.massage_qth(QTH) at = T1_IN_TRANSIT obs = predict.observe(tle, qth, at=at) self.assertTrue(obs['elevation'] > 0) at = T2_NOT_IN_TRANSIT obs = predict.observe(tle, qth, at=at) self.assertTrue(obs['elevation'] < 0) # should not raise a StopIteration next_transit = next(predict.transits(tle, qth, ending_after=at))
def main(args): TLE = pullTLE(name) qth = (47.654867,-122.306501,100) # lat (N), long (W), alt (meters) (get real altitude later + building) predict.observe(tle, qth) #get time, doppler and window check_TLE = False while(True):#main loop if(2000>nextObs-time.time() and not check_TLE) #check TLE 30 minutes before TLE = pullTLE(name) check_TLE = True if(nextObs-time.time()>100) #comms(tx_bytes,doppler,time_window,mode) #compute nextObs check_TLE = False end return 0
def __doppler_correction__(self, qth, tle): # the predict library expects long (W) # We expect long (E) sat_info = predict.observe(tle, qth) freq = self.center_freq + sat_info['doppler'] print "Doppler:", freq with self.bb_lock: self.bluebox.set_frequency(freq) t = threading.Timer(10, self.__doppler_correction__, [qth, tle]) t.daemon=True t.start()
def monitor(tle): while True: raw_data = predict.observe(tle, qth) data=json.dumps(raw_data) p = predict.transits(tle, qth) transit = p.next() #print("%f\t%f\t%f" % (transit.start, transit.duration(), transit.peak()['elevation'])) print "-------------------------------------------------------\n" print "Current sattelite: " + str(json.loads(data)['name']) + "\n" print "Latitude: " + str(json.loads(data)['latitude']) + " \n" print "Longitude: " + str(json.loads(data)['longitude']) + " \n" print "Next Transit: "+ str(datetime.datetime.fromtimestamp(int(transit.start)).strftime('%Y-%m-%d %H:%M:%S'))+"\n" print "Transit duration: " + str(transit.duration()) + "\n" print "Transit Peak: " + str(transit.peak()['elevation']) + "\n" print "-------------------------------------------------------\n" time.sleep(0.5) os.system("clear")
def getSatellitesAbove(qth): sats = {} for ID in satData.keys(): data = satData[ID] currentTLE = data["tle"] currentTLE = currentTLE.split("\n") currentTLE.pop() tle = "%s\n%s\n%s" % (data["catalogInfo"][0]["SATNAME"], currentTLE[0], currentTLE[1]) p = predict.observe(tle, qth) # This just gets me things above the horizon, not things actually visible if p["elevation"] > 0: #print "%s\nObject Type: %s\nNORAD ID: %s\nElevation: %s\nVisible: %s\n" % (p["name"],satData[ID]["catalogInfo"][0]["OBJECT_TYPE"], ID, p["elevation"], p["visibility"]) resultData = data resultData["prediction"] = p sats[ID] = resultData return sats
def azel_points(tlefile, qthfile, t): qth, locname = load_qth(qthfile) tle, satname = load_tle(tlefile) data = predict.observe(tle, qth, t) #find current state return data['azimuth'], data['elevation'], locname, satname
qth, locname = load_qth(qthfile) #load qth tle, satname = load_tle(tlefile) # load tle p = predict.transits(tle, qth) # predict future passes starttime, endtime, startaz, endaz, maxel = ([] for i in range(5) ) #initialize # Create Figure fig = plt.figure() ax = plt.subplot(111, projection='polar') # For each pass plot .... for i in range(3): # Predict 3 passes transit = next(p) #Find next pass starttime.append(time.ctime(transit.start)) endtime.append(time.ctime(transit.end)) startaz.append(predict.observe(tle, qth, transit.start)['azimuth']) endaz.append(predict.observe(tle, qth, transit.end)['azimuth']) maxel.append(transit.peak()['elevation']) azvec, elvec = [], [] t = transit.start if i == 0: while t < transit.end: az, el, locname, satname = azel_points(tlefile, qthfile, t) azvec.append(az * np.pi / 180) elvec.append(90 - el) t = t + 1 ax.plot(azvec, elvec, color='blue') print(maxel) # Fix ax.set_title("Azimuth and Elevation of " + satname + " over " + locname)
from pprint import pprint import predict tle = '0 OBJECT NY\n1 43550U 98067NY 19009.55938219 +.00013482 +00000-0 +17279-3 0 9995\n2 43550 051.6378 066.3469 0004106 279.6394 080.4135 15.59492665028120' x = predict.observe(tle, [0, 0, 0]) pprint(x)
def main(stdscr): recording = False levels = [] # parse program arguments parser = argparse.ArgumentParser() parser.add_argument("-d", "--doppler", help="automatic correction of Doppler shift", action="store_true") args = parser.parse_args() stdscr.nodelay(1) while True: satid, transit = nextsat() tle, freq = SATELLITES[satid] freqadjust = 0 aostime = time.strftime("%H:%M:%S", time.localtime(transit.start)) lostime = time.strftime("%H:%M:%S", time.localtime(transit.end)) logging.info("Scheduling %s at %s" % (tle[2:].split("\n")[0], aostime)) while transit.end > time.time(): # read key press and adjust freq c = stdscr.getch() if c == 258: # up arrow freqadjust -= FREQADJUST elif c == 259: # down arrow freqadjust += FREQADJUST elif c == 10: # enter key ra.tune(freq + freqadjust) now = time.time() observe = predict.observe(tle, GROUNDSTATION) name = observe['name'][2:] if transit.start > now: # waiting for upcoming satellite if recording: # stop recording logging.info("LOS. Levels: %.3f/%.3f/%.3f" % ( min(levels), sum(levels)/len(levels), max(levels) )) levels = [] ra.los() recording = False timeleft = transit.start - now minutes = int(timeleft / 60) seconds = int(timeleft - minutes * 60) writeline("Waiting for %s AOS: %s, %s %02.3f/%02.3f @ %d + %d" % ( name, aostime, "%03d:%02d" % (minutes, seconds), observe['elevation'], transit.peak()['elevation'], freq, freqadjust )) else: if args.doppler: f = freq + observe['doppler']/100000000 * freq ra.tune(f + freqadjust) else: f = freq if not recording: # start recording logging.info("AOS of %s at %d Hz for %.3f min (%.3f deg) " % ( name, freq, transit.duration()/60, transit.peak()['elevation'])) ra.aos() recording = True levels.append(float(ra.getlevel())) # gather statistics timeleft = transit.end - now minutes = int(timeleft / 60) seconds = int(timeleft - minutes * 60) writeline("Tracking %s LOS: %s, %s %02.3f/%02.3f @ %d + %d" % ( name, lostime, "%03d:%02d" % (minutes, seconds), observe['elevation'], transit.peak()['elevation'], f, freqadjust )) time.sleep(UPDATEINTERVAL)
def getDoppler(tle, gnd_lat, gnd_lng, gnd_alt, time=time.time()): prediction = predict.observe(tle, (gnd_lat, gnd_lng, gnd_alt), time) return prediction['doppler']
def observe(self, sat): """Get prediction of the satellite location, and relative azimuth and elevation given this groundstation""" return predict.observe(sat.tle, self.predict_qth)
def get_elevation(self, obs_time=None): if not obs_time: obs_time = time.time() prediction = predict.observe(self.tle, self.qth, obs_time) return prediction['elevation']
def get_azimuth(self, obs_time=None): if not obs_time: obs_time = time.time() prediction = predict.observe(self.tle, self.qth, obs_time) return prediction['azimuth']
async def on_message(message): if message.content.startswith("!predict"): command = message.content[9:] if "-u" in command: update_tle() command = command.replace("-u", "") await message.channel.send("TLE updated") if "-h" in command: command = command.replace("-h", "") await message.channel.send(embed=discord.Embed.from_dict(HELP_MSG)) #handle prediction commands if len(command.strip()) > 0: try: await message.delete() except: await message.channel.send( "Cannot Delete Message: Missing Permissions") try: #update the tle if it hasn't been updated in 12 hours if TLE_LAST_UPDATED == 0 or datetime.now().timestamp( ) - TLE_LAST_UPDATED > 43200: update_tle() await message.channel.send("TLE updated") #get command arguments sat_name, loc, pass_count = parse_args(command) loc = (round(loc[0] + randint(-10, 10) / 100, 4), round(loc[1] + randint(-10, 10) / 100, 4), round(loc[2] + randint(-10, 10), 4)) names = [ name.strip() for name in open(TLE_FILE).read().split("\n")[0::3] ] matches = difflib.get_close_matches(sat_name.upper(), names) if len(matches) == 0: await message.channel.send( "Error: Failed to find satellite") return sat_name = matches[0] #find the tle for the specifed sat in the tle file tle = find_sat_in_tle(sat_name, TLE_FILE) tf = TimezoneFinder() tz = tf.timezone_at(lat=loc[0], lng=loc[1]) utc_offset = datetime.now(pytz.timezone(tz)).strftime("%z") #predict the passes and add them to a list p = predict.transits(tle, (loc[0], loc[1] * -1, loc[2])) passes = [] for i in range(pass_count): transit = next(p) #while transit.peak()["elevation"] < 20: # transit = next(p) aos = round(transit.start + randint(-30, 30)) tca = round(transit.peak()["epoch"] + randint(-30, 30)) los = round(transit.end + randint(-30, 30)) #get map image url url = "" if pass_count == 1: start = predict.observe(tle, loc, at=aos) middle = predict.observe(tle, loc, at=tca) end = predict.observe(tle, loc, at=los) url = "https://www.mapquestapi.com/staticmap/v5/map?start={},{}&end={},{}&locations={},{}&size=600,400@2x&key={}&routeArc=true&format=jpg70&zoom=3".format( start["latitude"], start["longitude"] - 360, end["latitude"], end["longitude"] - 360, middle["latitude"], middle["longitude"] - 360, mapquest_key) data = requests.get(url).content with open("temp-map.jpg", "wb") as image: image.write(data) passes.append({ "satellite": sat_name, "start": aos, "middle": tca, "end": los, "url": url, "peak_elevation": round( transit.peak()['elevation'] + (randint(-20, 20) / 10), 1), "duration": round(transit.duration()), "azimuth": round( transit.at(transit.start)['azimuth'] + (randint(-20, 20) / 10), 1) }) #respond with an embeded message image_file = None response = discord.Embed( title=sat_name + " passes over {} [UTC{}]".format(str(loc), utc_offset)) for ps in passes: if ps["url"] != "": image_file = discord.File("temp-map.jpg", filename="map.jpg") response.set_image(url="attachment://map.jpg") delta = datetime.utcfromtimestamp( ps['start']) - datetime.utcnow() hours, minutes = divmod(delta.seconds / 60, 60) response.add_field( name=datetime.utcfromtimestamp(ps['start']).strftime( "%B %-d, %Y at %-H:%M:%S UTC") + " (in {} hours and {} minutes)".format( round(hours), round(minutes)), value= "Peak Elevation: {}\nDuration: {}\nAzimuth: {}\nEnd: {}" .format( ps['peak_elevation'], ps['duration'], ps['azimuth'], datetime.utcfromtimestamp(ps['end']).strftime( "%B %-d, %Y at %-H:%M:%S UTC")), inline=False) await message.channel.send(file=image_file, embed=response) if os.path.isfile("temp-map.jpg"): os.remove("temp-map.jpg") except Exception as e: await message.channel.send( "Oops! Something went wrong. Use `!predict -h` for help.") print(e)