def interpolate(self, step_size: float, num_points: int = 5) -> OrbitEphemerisMessage: """Interpolates the ephemeris data to the desired time step size. :param step_size: The interpolated step size in seconds. :param num_points: The number of states to use for interpolation. """ epochs, state_vects = [], [] for emph_line in self.ephemeris_lines: epochs.append(emph_line.epoch) # Convert components from m and m\s to km and km\s state_vect = [i * 1000.0 for i in emph_line.state_vector] state_vects.append(state_vect) offset_epochs = conv.get_J2000_epoch_offset(epochs) interpolation = interpolate_ephemeris(self.ref_frame, offset_epochs, state_vects, num_points, self.ref_frame, offset_epochs[0], offset_epochs[-1], step_size) interp_ephem_lines = [] for proto_buf in interpolation: epoch = conv.get_UTC_string(proto_buf.time) state_vector = [i / 1000.0 for i in list(proto_buf.true_state)] interp_ephem_line = EphemerisLine(epoch=epoch, state_vector=state_vector) interp_ephem_lines.append(interp_ephem_line) interp_oem_data = self.copy() interp_oem_data.ephemeris_lines = interp_ephem_lines return interp_oem_data
def predict(self): self.predict["state"] = "disabled" start = get_J2000_epoch_offset(self.start_time.get()) end = get_J2000_epoch_offset(self.end_time.get()) data, tle = {}, [ l for l in self.tle.get("0.0", "end-1c").splitlines() if l.startswith("1") or l.startswith("2") ] for f in [ "latitude", "longitude", "altitude", "fov_azimuth", "fov_elevation", "fov_aperture", "step_size" ]: data[f] = [ float(t.strip()) for t in getattr(self, f).get().split(",") ] if (f not in ["altitude", "step_size"]): data[f] = [d * Constant.DEGREE_TO_RAD for d in data[f]] cfg_list = [] sim_meas = len(data["latitude"]) <= 2 or len(data["latitude"]) != len( data["longitude"]) for i in range(0, len(tle), 2): cfg_list.append( configure(prop_start=start, prop_initial_TLE=tle[i:i + 2], prop_end=end, prop_step=data["step_size"][0], sim_measurements=sim_meas, gravity_degree=-1, gravity_order=-1, ocean_tides_degree=-1, ocean_tides_order=-1, third_body_sun=False, third_body_moon=False, solid_tides_sun=False, solid_tides_moon=False, drag_model=DragModel.UNDEFINED, rp_sun=False)) cfg_list[-1].output_flags |= OutputFlag.OUTPUT_ECLIPSE if (sim_meas): add_station(cfg_list[-1], "Sensor", data["latitude"][0], data["longitude"][0], data["altitude"][0], data["fov_azimuth"][0], data["fov_elevation"][0], data["fov_aperture"][0]) cfg_list[-1].measurements[MeasurementType.AZIMUTH].error[:] = [ 0.0 ] cfg_list[-1].measurements[ MeasurementType.ELEVATION].error[:] = [0.0] else: cfg_list[-1].geo_zone_lat_lon[:] = [ l for ll in zip(data["latitude"], data["longitude"]) for l in ll ] if (len(cfg_list)): i = 0 lookup = {0.0: "Sunlit", 0.5: "Penumbra", 1.0: "Umbra"} self.output.delete("0.0", tk.END) if (sim_meas): self.output_label[ "text"] = "UTC, Azimuth [deg], Elevation [deg]" else: self.output_label[ "text"] = "UTC, Latitude [deg], Longitude [deg], Altitude [m]" for o in propagate_orbits(cfg_list): self.output.insert(tk.END, f"\nObject {tle[i][2:7]}:\n") i += 2 for m in o.array: if (sim_meas): self.output.insert( tk.END, "{}: {:.5f}, {:.5f} ({})\n".format( get_UTC_string(m.time), (m.values[0] / Constant.DEGREE_TO_RAD + 360) % 360, m.values[1] / Constant.DEGREE_TO_RAD, lookup[m.true_state[-1]])) else: lla = pos_to_lla(Frame.GCRF, m.time, m.true_state) self.output.insert( tk.END, "{}: {:.5f}, {:.5f}, {:.2f} ({})\n".format( get_UTC_string(m.time), lla[0] / Constant.DEGREE_TO_RAD, lla[1] / Constant.DEGREE_TO_RAD, lla[2], lookup[m.true_state[-1]])) self.predict["state"] = "normal"
default=datetime(day1.year, day1.month, day1.day).strftime(timefmt)) parser.add_argument("--step-size", help="step size [sec]", type=float, default=900.0) parser.add_argument("--export-oem", help="Export output to CCSDS OEM files", action="store_true", default=False) if (len(sys.argv) == 1): parser.print_help() exit(1) args = parser.parse_args() start = get_J2000_epoch_offset(args.start_time) end = get_J2000_epoch_offset(args.end_time) config, elements = [], [ l for l in getattr(args, "tle-file").read().splitlines() if l.startswith("1") or l.startswith("2") ] for i in range(0, len(elements), 2): config.append( configure(prop_start=start, prop_initial_TLE=elements[i:i + 2], prop_end=end, prop_step=args.step_size, gravity_degree=-1, gravity_order=-1, ocean_tides_degree=-1, ocean_tides_order=-1,
["2020-07-24T03:22:03.679Z", 5.711479, 0.636510], ["2020-07-24T03:22:08.283Z", 5.706017, 0.608080], ["2020-07-24T03:22:12.904Z", 5.701007, 0.580095], ["2020-07-24T03:22:17.432Z", 5.696508, 0.553190], ["2020-07-24T03:22:22.073Z", 5.692283, 0.526236], ["2020-07-24T03:22:26.745Z", 5.688394, 0.499645], ["2020-07-24T03:22:31.417Z", 5.684841, 0.473698], ["2020-07-24T03:22:35.997Z", 5.681670, 0.448829], ["2020-07-24T03:22:40.696Z", 5.678703, 0.423978], ["2020-07-24T03:22:45.390Z", 5.675990, 0.399725], ["2020-07-24T03:22:49.930Z", 5.673622, 0.376921]] # Use Laplace IOD to estimate an initial state from 3 RA/dec times, ra, dec = [], [], [] for i in range(3): times.append(get_J2000_epoch_offset(real_obs[i][0])) ra.append(real_obs[i][1]) dec.append(real_obs[i][2]) initial_epoch = times[1] initial_state = iod_laplace(Frame.EME2000, lat, lon, alt, times, ra, dec) # Configure orbit determination config = configure(prop_start=initial_epoch, prop_initial_state=initial_state, prop_end=get_J2000_epoch_offset(real_obs[-1][0])) # Define ground station(s) add_station(config, "UTA-ASTRIA-NMSkies", lat, lon, alt) # Define measurement types; RA/dec used here config.measurements[MeasurementType.RIGHT_ASCENSION].error[:] = [
# along with this program. If not, see <http://www.gnu.org/licenses/>. from numpy import diag from numpy.random import multivariate_normal from orbdetpy import (configure, add_facet, add_maneuver, add_station, build_measurement, AttitudeType, Filter, ManeuverTrigger, ManeuverType, MeasurementType, Constant) from orbdetpy.ccsds import export_OEM, export_TDM from orbdetpy.conversion import get_J2000_epoch_offset, get_UTC_string from orbdetpy.estimation import determine_orbit from orbdetpy.propagation import propagate_orbits from orbdetpy.plotting.estimation import plot as estimation_plot from orbdetpy.plotting.simulation import plot as simulation_plot # Set up configuration for measurement generation cfg = configure(prop_start=get_J2000_epoch_offset("2019-05-01T00:00:00Z"), prop_initial_state=[ -23183898.259, 35170229.755, 43425.075, -2566.938, -1692.19, 138.948 ], prop_end=get_J2000_epoch_offset("2019-05-01T01:00:00Z"), prop_step=300.0, sim_measurements=True) # Uncomment to define box-wing model #add_facet(cfg, Constant.PLUS_I, 3.0) #add_facet(cfg, Constant.PLUS_J, 3.0) #add_facet(cfg, Constant.PLUS_K, 3.0) #add_facet(cfg, Constant.MINUS_I, 3.0) #add_facet(cfg, Constant.MINUS_J, 3.0) #add_facet(cfg, Constant.MINUS_K, 3.0)
now = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%fZ") print(f"J2000_EPOCH = {conv.get_UTC_string(0.0)}") print( f"""J2000_EPOCH => 2000-01-01T12:00:00Z = {conv.get_J2000_epoch_offset("2000-01-01T12:00:00Z")}s""" ) print(f"""J2000_EPOCH => {now} (now) = {conv.get_J2000_epoch_offset(now)}s""") # Time difference between pairs of epochs for key, val in vars(Epoch).items(): if (key.endswith("_EPOCH") and key != "J2000_EPOCH"): print( f"J2000_EPOCH => {key} = {conv.get_epoch_difference(Epoch.J2000_EPOCH, val)}s" ) print() time = conv.get_J2000_epoch_offset("1998-08-10T23:10:00Z") # Inertial GCRF state vector gcrf_pv = [-6045E3, -3490E3, 2500E3, -3.457E3, 6.618E3, 2.533E3] # Frame transformations itrf_pv = conv.transform_frame(Frame.GCRF, time, gcrf_pv, Frame.ITRF_CIO_CONV_2010_ACCURATE_EOP) print("GCRF=>ITRF: {:.2f}m, {:.2f}m, {:.2f}m, {:.2f}m/s, {:.2f}m/s, {:.2f}m/s". format(*itrf_pv)) print( "ITRF=>GCRF: {:.2f}m, {:.2f}m, {:.2f}m, {:.2f}m/s, {:.2f}m/s, {:.2f}m/s\n". format(*conv.transform_frame(Frame.ITRF_CIO_CONV_2010_ACCURATE_EOP, time, itrf_pv, Frame.GCRF))) # Position => Lat/Lon/Alt lla = conv.pos_to_lla(Frame.GCRF, time, gcrf_pv[:3])
def predict(self): self.predict["state"] = "disabled" start = get_J2000_epoch_offset(self.start_time.get()) end = get_J2000_epoch_offset(self.end_time.get()) data, tle = {}, [ l for l in self.tle.get("0.0", "end-1c").splitlines() if l.startswith("1") or l.startswith("2") ] for f in [ "latitude", "longitude", "altitude", "fov_azimuth", "fov_elevation", "fov_aperture", "step_size" ]: data[f] = [ float(t.strip()) for t in getattr(self, f).get().split(",") ] if (f not in ["altitude", "step_size"]): data[f] = [d * Constant.DEGREE_TO_RAD for d in data[f]] cfg_list = [] sim_meas = len(data["latitude"]) <= 2 or len(data["latitude"]) != len( data["longitude"]) for i in range(0, len(tle), 2): cfg_list.append( configure(prop_start=start, prop_initial_TLE=tle[i:i + 2], prop_end=end, prop_step=data["step_size"][0], sim_measurements=sim_meas)) if (not sim_meas): cfg_list[-1].geo_zone_lat_lon[:] = [ l for ll in zip(data["latitude"], data["longitude"]) for l in ll ] continue add_station(cfg_list[-1], "Sensor", data["latitude"][0], data["longitude"][0], data["altitude"][0], data["fov_azimuth"][0], data["fov_elevation"][0], data["fov_aperture"][0]) cfg_list[-1].measurements[MeasurementType.AZIMUTH].error[:] = [0.0] cfg_list[-1].measurements[MeasurementType.ELEVATION].error[:] = [ 0.0 ] if (len(cfg_list)): i = 0 self.output.delete("0.0", tk.END) if (sim_meas): self.output_label[ "text"] = "UTC, Azimuth [deg], Elevation [deg]" else: self.output_label[ "text"] = "UTC, Latitude [deg], Longitude [deg], Altitude [m]" for o in propagate_orbits(cfg_list): self.output.insert(tk.END, "\nObject {}:\n".format(tle[i][2:7])) i += 2 for m in o.array: if (sim_meas): self.output.insert( tk.END, "{}: {:.5f}, {:.5f}\n".format( get_UTC_string(m.time), (m.values[0] / Constant.DEGREE_TO_RAD + 360) % 360, m.values[1] / Constant.DEGREE_TO_RAD)) else: lla = pos_to_lla(Frame.GCRF, m.time, m.true_state) self.output.insert( tk.END, "{}: {:.5f}, {:.5f}, {:.2f}\n".format( get_UTC_string(m.time), lla[0] / Constant.DEGREE_TO_RAD, lla[1] / Constant.DEGREE_TO_RAD, lla[2])) self.predict["state"] = "normal"
# You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from numpy import diag from numpy.random import multivariate_normal from orbdetpy import (configure, add_facet, add_maneuver, add_station, build_measurement, AttitudeType, Filter, ManeuverTrigger, ManeuverType, MeasurementType, Constant) from orbdetpy.ccsds import export_OEM, export_TDM from orbdetpy.conversion import get_J2000_epoch_offset, get_UTC_string from orbdetpy.estimation import determine_orbit from orbdetpy.propagation import propagate_orbits from orbdetpy.plotting.estimation import plot as estimation_plot from orbdetpy.plotting.simulation import plot as simulation_plot # Set up configuration for measurement generation cfg = configure(prop_start=get_J2000_epoch_offset("2019-05-01T00:00:00Z"), prop_initial_state=[-23183898.259, 35170229.755, 43425.075, -2566.938, -1692.19, 138.948], prop_end=get_J2000_epoch_offset("2019-05-01T01:00:00Z"), prop_step=300.0, sim_measurements=True) # Uncomment to define box-wing model #add_facet(cfg, Constant.PLUS_I, 3.0) #add_facet(cfg, Constant.PLUS_J, 3.0) #add_facet(cfg, Constant.PLUS_K, 3.0) #add_facet(cfg, Constant.MINUS_I, 3.0) #add_facet(cfg, Constant.MINUS_J, 3.0) #add_facet(cfg, Constant.MINUS_K, 3.0) #cfg.rso_solar_array_area = 20.0 #cfg.rso_solar_array_axis[:] = Constant.PLUS_J # Uncomment to define initial attitude #cfg.rso_attitude_provider = AttitudeType.FIXED_RATE
# # 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 <http://www.gnu.org/licenses/>. from orbdetpy import configure, Frame from orbdetpy.conversion import get_J2000_epoch_offset, get_UTC_string from orbdetpy.propagation import propagate_orbits from orbdetpy.utilities import interpolate_ephemeris # Propagate for 1 hour at 5 minute intervals with default settings cfg = configure(prop_start=get_J2000_epoch_offset("2020-03-09T22:00:02.000Z"), prop_initial_state=[ -152408.166, -958234.785, 6908448.381, -7545.691, 285.553, -126.766 ], prop_end=get_J2000_epoch_offset("2020-03-09T23:00:02.000Z"), prop_step=300.0) times, states = [], [] for o in propagate_orbits([cfg])[0].array: times.append(o.time) states.append(o.true_state) # Interpolate over the same period at 1 minute intervals for i in interpolate_ephemeris(Frame.GCRF, times, states, 5, Frame.GCRF, cfg.prop_start, cfg.prop_end, 60.0):
from orbdetpy.conversion import get_J2000_epoch_offset from orbdetpy.propagation import propagate_orbits with open(path.join(path.dirname(path.realpath(__file__)), "tle_tests.txt"), "r") as fp: test_cases = [[]] for l in fp.read().splitlines(): if (l.strip()): test_cases[-1].append(l) else: test_cases.append([]) config = [configure(prop_step=60.0, prop_inertial_frame=Frame.TEME, gravity_degree=-1, gravity_order=-1, ocean_tides_degree=-1, ocean_tides_order=-1, third_body_sun=False, third_body_moon=False, solid_tides_sun=False, solid_tides_moon=False, drag_model=DragModel.UNDEFINED, rp_sun=False)] diff_norm = lambda x, y: math.sqrt((x[0]-y[0])**2 + (x[1]-y[1])**2 + (x[2]-y[2])**2) for test in test_cases: epstr = "19" + test[0][18:32] if (test[0][18:20] >= "57") else "20" + test[0][18:32] eputc = (datetime.strptime(epstr[:7], "%Y%j") + timedelta(days=float(epstr[7:]))).strftime("%Y-%m-%dT%H:%M:%S.%f") eptdt = get_J2000_epoch_offset(eputc) config[0].prop_initial_TLE[:] = test[:2] for line in test[2:]: truth = [float(t)*1000.0 for t in line.split()[:7]] truth[0] = truth[0]*60.0/1000.0 config[0].prop_start = eptdt + truth[0] config[0].prop_end = config[0].prop_start prop = propagate_orbits(config)[0].array[0] assert(diff_norm(truth[1:4], prop.true_state[:3]) < 2.0E-3) # 2.0 mm position error tolerance assert(diff_norm(truth[4:7], prop.true_state[3:6]) < 0.003E-3) # 0.003 mm/s velocity error tolerance