-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfindPass.py
185 lines (137 loc) · 5.28 KB
/
findPass.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# findPass.py
#
# Find all the observable passes of a satellite for a given location and time range
#
# Harry Krantz
# Steward Observatory
# University of Arizona
# Copyright May 2020
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import datetime as dt
from satFunctions import *
from skyfield.api import utc
# Find all the valid flyover passes within the time frame for the provided TLE, location, and date range
# Args: tle = string, loc = skyfield topos, start = datetime, stop = datetime
# Returns: array of dict
def findPass(tle, loc, start, stop):
#Split the tle
name, line1, line2 = tle
noradID = parseTLEID(tle)
#Initialization
sat = skyfield.sgp4lib.EarthSatellite(line1, line2, name)
ts = skyfield.api.load.timescale()
#Convert datetimes to Skyfield time objects
try:
t0 = ts.utc(start)
t1 = ts.utc(stop)
except: #date lacks valid timezone, assuming utc
t0 = ts.utc(start.replace(tzinfo=utc))
t1 = ts.utc(stop.replace(tzinfo=utc))
#Find flyover passes within time frame
time, events = sat.find_events(loc, t0, t1, altitude_degrees = 0.0)
#Construct passes from each set of three event types
#Can definitley be done in a better more pythonic way
passes = [] #list of type [ [rise,climax,set]... ]
temp=[]
for t, e in zip(time,events):
temp.append(t)
if e == 2:
#Event type set, save the sublist and clear temp
passes.append(temp)
temp = []
#Iterate through passes and compute ephemerides for each
output = []
for p in passes:
try:
rise = computeEphemeris(tle,loc,p[0])
peak = computeEphemeris(tle,loc,p[1])
sett = computeEphemeris(tle,loc,p[2])
except IndexError as e:
print("... incomplete pass, skipping!")
continue
#Determine pass duration
try:
duration = sett["time"] - rise["time"]
except Exception as e:
print(e)
duration = "error"
#Organize parameters into dictionary for easy retrieval later
passs = {
"name" : rise["name"],
"id" : rise["id"],
"riseTime" : rise["time"],
"riseAz" : rise["azimuth"],
"maxTime" : peak["time"],
"maxAlt" : peak["altitude"],
"maxAz" : peak["azimuth"],
"maxRA" : peak["ra"],
"maxDec" : peak["dec"],
"maxVel" : peak["velocity"],
"range" : peak["range"],
"height" : peak["height"],
"sunElong" : peak["sunElong"],
"moonElong" : peak["moonElong"],
"setTime" : sett["time"],
"setAz" : sett["azimuth"],
"duration" : duration,
"eclipsed" : peak["eclipsed"],
"sunUp" : peak["sunUp"],
"moonUp" : peak["moonUp"]
}
#Save the parameters
output.append(passs)
return output
# Filter a list of passes for certain conditions
# None is a wildcard
# Args: passes = array of dict, sun = bool, moon = bool, eclipsed = bool, alt=num
# Returns: array of dict
def filterPasses(passes, sun=None, moon=None, eclipsed=None, alt=None):
output = []
for p in passes:
#Check for invalidations
if (sun != None and p["sunUp"] != sun):
continue
if (moon != None and p["moonUp"] != moon):
continue
if (eclipsed != None and p["eclipsed"] != eclipsed):
continue
if (alt != None and p["maxAlt"] < alt):
continue
#If valid, append pass to output list
output.append(p)
return output
# Prints the info from a single pass event in the format: [name, id, riseTime, riseAz, maxAltTime, maxAlt, maxAz, setTime, setAz, duration, eclipsed, sunUp, moonUp]
# Args: passs = dict
# Returns: nothing
def printPass(passs):
print("{: <24} {: <8} {: <21} {: <14.7s} {: <21} {: <10.7s} {: <14.7s} {: <21} {: <13.7s} {: <13.7s}".format(*map(str, [passs["name"], passs["id"], passs["riseTime"].strftime('%Y-%m-%d %H:%M:%S'), passs["riseAz"], passs["maxTime"].strftime('%Y-%m-%d %H:%M:%S'), passs["maxAlt"], passs["maxAz"], passs["setTime"].strftime('%Y-%m-%d %H:%M:%S'), passs["setAz"], passs["duration"]])))
# Prints a full list of pass events with informative header
# Args: passes = array of dict
# Returns: nothing
def printPassList(passes):
#Print the header and list of passes
headers = ["Name", "ID", "Rise Time", "Rise Azimuth", "Peak Time", "Peak Alt", "Peak Azimuth", "Set Time", "Set Azimuth", "Duration"]
print("{: <24} {: <8} {: <21} {: <14} {: <21} {: <10} {: <14} {: <21} {: <13} {: <13}".format(*headers))
print("----------------------------------------------------------------------------------------------------------------------------------------------------------------------")
for p in passes:
printPass(p)
# Reformat array of dicts into singular array with the requested values in headerNames
# Args: passes = array of dict, headerNames = array of string
# Returns: array
def makePassArray(passes, headerNames=None):
if headerNames == None:
headerNames = passes[0].keys()
output = []
for p in passes:
output.append( [ p[h] for h in headerNames ] )
return output