def test_tle_export(): """Check `export_tle()` round-trip using all the TLEs in the test file. This iterates through the satellites in "SGP4-VER.TLE", generates `Satrec` objects and exports the TLEs. These exported TLEs are then compared to the original TLE, closing the loop (or the round-trip). """ data = get_data(__name__, 'SGP4-VER.TLE') tle_lines = iter(data.decode('ascii').splitlines()) # Skip these lines, known errors # Resulting TLEs are equivalent (same values in the Satrec object), but they are not the same # 25954: BSTAR = 0 results in a negative exp, not positive # 29141: BSTAR = 0.13519 results in a negative exp, not positive # 33333: Checksum error as expected on both lines # 33334: Checksum error as expected on line 1 # 33335: Checksum error as expected on line 1 expected_errs_line1 = set([25954, 29141, 33333, 33334, 33335]) expected_errs_line2 = set([33333, 33335]) if accelerated: # Non-standard: omits the ephemeris type integer. expected_errs_line1.add(11801) for line1 in tle_lines: if not line1.startswith('1'): continue line2 = next(tle_lines) # trim lines to normal TLE string size line1 = line1[:69] line2 = line2[:69] satrec = Satrec.twoline2rv(line1, line2) satrec_old = io.twoline2rv(line1, line2, wgs72) # Generate TLE from satrec out_line1, out_line2 = export_tle(satrec) out_line1_old, out_line2_old = export_tle(satrec_old) if satrec.satnum not in expected_errs_line1: assertEqual(out_line1, line1) assertEqual(out_line1_old, line1) if satrec.satnum not in expected_errs_line2: assertEqual(out_line2, line2) assertEqual(out_line2_old, line2)
def export_tle(self): """ Exports the TLE to line1 and line2. A sample output looks like this:: line1 = "1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927" line2 = "2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537" Returns ------- line1, line2 : (str, str) strings containing line 1, line 2 """ line1, line2 = export_tle(self._satrec) return line1, line2
def __str__(self): """ Exports the TLE as a Three-Line string, with name, line1 and line2. A sample output looks like this:: ISS (ZARYA) 1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927 2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537 Returns ------- str string containing line 1, line 2 and name of the satellite """ line1, line2 = export_tle(self._satrec) txt = "" if self._name is not None and self._name.strip(): txt += self._name + "\n" txt += line1 + "\n" + line2 + "\n" return txt
def generate_tles_from_scratch_with_sgp(filename_out, constellation_name, num_orbits, num_sats_per_orbit, phase_diff, inclination_degree, eccentricity, arg_of_perigee_degree, mean_motion_rev_per_day): with open(filename_out, "w+") as f_out: # First line: # # <number of orbits> <number of satellites per orbit> # f_out.write("%d %d\n" % (num_orbits, num_sats_per_orbit)) # Each of the subsequent (number of orbits * number of satellites per orbit) blocks # define a satellite as follows: # # <constellation_name> <global satellite id> # <TLE line 1> # <TLE line 2> satellite_counter = 0 for orbit in range(0, num_orbits): # Orbit-dependent raan_degree = orbit * 360.0 / num_orbits orbit_wise_shift = 0 if orbit % 2 == 1: if phase_diff: orbit_wise_shift = 360.0 / (num_sats_per_orbit * 2.0) # For each satellite in the orbit for n_sat in range(0, num_sats_per_orbit): mean_anomaly_degree = orbit_wise_shift + (n_sat * 360 / num_sats_per_orbit) # Epoch is set to the year 2000 # This conveniently in TLE format gives 00001.00000000 # for the epoch year and Julian day fraction entry jd, fr = jday(2000, 1, 1, 0, 0, 0) # Use SGP-4 to generate TLE sat_sgp4 = Satrec() # Based on: https://pypi.org/project/sgp4/ sat_sgp4.sgp4init( WGS72, # Gravity model [1] 'i', # Operating mode (a = old AFPSC mode, i = improved mode) satellite_counter + 1, # satnum: satellite number (jd + fr) - 2433281.5, # epoch: days since 1949 December 31 00:00 UT [2] 0.0, # bstar: drag coefficient (kg/m2er) 0.0, # ndot: ballistic coefficient (revs/day) 0.0, # nndot: second derivative of mean motion (revs/day^3) eccentricity, # ecco: eccentricity math.radians(arg_of_perigee_degree ), # argpo: argument or perigee (radians) math.radians( inclination_degree), # inclo: inclination(radians) math.radians(mean_anomaly_degree ), # mo: mean anomaly (radians) mean_motion_rev_per_day * 60 / 13750.9870831397, # no_kazai: mean motion (radians/minute) [3] math.radians(raan_degree) # nodeo: right ascension of # ascending node (radians) ) # Side notes: # [1] WGS72 is also used in the NS-3 model # [2] Due to a bug in sgp4init, the TLE below irrespective of the value here gives zeros. # [3] Conversion factor from: # https://www.translatorscafe.com/unit-converter/en-US/ (continue on next line) # velocity-angular/1-9/radian/second-revolution/day/ # # Export TLE from the SGP-4 object line1, line2 = export_tle(sat_sgp4) # Line 1 has some problems: there are unknown characters entered for the international # designator, and the Julian date is not respected # As such, we set our own bogus international designator 00000ABC # and we set our own epoch date as 1 January, 2000 # Why it's 00001.00000000: https://www.celestrak.com/columns/v04n03/#FAQ04 tle_line1 = line1[:7] + "U 00000ABC 00001.00000000 " + line1[ 33:] tle_line1 = tle_line1[:68] + str( calculate_tle_line_checksum(tle_line1[:68])) tle_line2 = line2 # Check that the checksum is correct if len(tle_line1) != 69 or calculate_tle_line_checksum( tle_line1[:68]) != int(tle_line1[68]): raise ValueError("TLE line 1 checksum failed") if len(tle_line2) != 69 or calculate_tle_line_checksum( tle_line2[:68]) != int(tle_line2[68]): raise ValueError("TLE line 2 checksum failed") # Write TLE to file f_out.write(constellation_name + " " + str(orbit * num_sats_per_orbit + n_sat) + "\n") f_out.write(tle_line1 + "\n") f_out.write(tle_line2 + "\n") # One more satellite there satellite_counter += 1
def find_orbit(nwalkers, ndim, pos, parameters, finding, loops, walks, counter, station, timestamp_min, timestamps, mode, measurements, orbit, meta=[[]], generated={}): # preparing the optimizer sampler = emcee.EnsembleSampler(nwalkers, ndim, log_probability, args=(parameters, finding, station, timestamp_min, timestamps, mode, measurements, orbit, meta)) # preparing the storage of the best result of all loops results_min = [] for i in range(ndim): results_min.append([]) residual_min = [] result_b4 = np.zeros(len(pos)) b4 = 0 b4_tle_line1 = "" b4_tle_line2 = "" b4_result = [] # now we can run the loops at each iteration we have the EMCEE results for i in range(loops): #start the optimization with emcee pos, prob, state = sampler.run_mcmc(pos, walks, progress=True) # extracting the orbit parameters back from the resulting POS. # in this case, we just use the best result, which is argmax of POS r_p, r_a, AoP, inc, raan, tp, bstar, td = get_kepler_parameters( pos[np.argmax(prob)], parameters, finding, orbit) eccentricity = (r_a - r_p) / (r_a + r_p) h_angularmomentuum = np.sqrt(r_p * (1.0 + eccentricity * np.cos(0)) * mu) T_orbitperiod = 2.0 * np.pi / mu**2.0 * ( h_angularmomentuum / np.sqrt(1.0 - eccentricity**2))**3 me = tp * (2.0 * np.pi) / T_orbitperiod * 180.0 / np.pi me = zeroTo360(me) AoP = zeroTo360(AoP) raan = zeroTo360(raan) n = 24.0 * 3600.0 / T_orbitperiod satnum = 0 epoch = timestamp_min ecco = eccentricity argpo = AoP inclo = inc mo = me no_kozai = n nodeo = raan ndot = 0.0 satrec = get_satrec(satnum, epoch, ecco, argpo, inclo, mo, no_kozai, nodeo, bstar, ndot, nddot=0.0) tle_line1, tle_line2 = exporter.export_tle(satrec) if i == 0: b4 = np.max(prob) b4_tle_line1 = tle_line1 b4_tle_line2 = tle_line2 b4_result = pos[np.argmax(prob)] else: if np.max(prob) > b4: b4 = np.max(prob) b4_tle_line1 = tle_line1 b4_tle_line2 = tle_line2 b4_result = pos[np.argmax(prob)] #print("prob", np.max(prob), np.argmax(prob), b4) #print(pos[np.argmax(prob)]) #save_progress(plotnames, counter, r_p, r_a, AoP, inc, raan, tp, bstar, td, np.max(prob), s1, t1, mode, filename_1) #save_progress_pos(plotnames, pos, prob, state) ''' for ii in range(ndim): results_min[ii].append(pos[np.argmax(prob)][ii]) residual_min.append(np.max(prob)) plt.plot(np.abs(residual_min)) plt.yscale("log") plt.grid() plt.savefig(plotnames+"_residual") plt.clf() plt.plot(results_min[0]) plt.plot(results_min[1]) plt.grid() plt.savefig(plotnames+"_radius") plt.clf() print(np.mean(results_min[0]), np.mean(results_min[1])) ''' #get_state_plot(r_a, r_p, inc, raan, AoP, tp, bstar, td, station, timestamp_min, timestamps, mode, measurements) samples = sampler.chain[:, 0:, :].reshape((-1, ndim)) result_percentile = np.percentile(samples, [16, 50, 84], axis=0) #import corner #import matplotlib.pyplot as plt #flat_samples = samples #fig = corner.corner(flat_samples) #plt.show() #print(samples.shape) #print(len(samples)) #print(samples[:, 0]) #print(samples[:, 1]) #print(samples[:, 2]) #print(samples[:, 3]) #print(samples[:, 4]) #print(samples[:, 5]) #plt.plot(samples[:, 0]) #plt.plot(samples[:, 1]) #plt.show() #print(np.mean(samples[:, 0])) #print(np.mean(samples[:, 1])) for r in range(len(result_percentile[1])): for key in finding.keys(): if finding[key] == r: parameters_name = key #if finding[key].keys() > 1: # for keykey in finding[key].keys(): # if finding[key][keykey] == r: # parameters_name = r result_b4[r] = result_percentile[1][r] print("tle_line1:", b4_tle_line1) print("tle_line2:", b4_tle_line2) if "tle" in generated: print( "compare", compare(b4_tle_line1, b4_tle_line2, generated["tle"]["line1"], generated["tle"]["line2"], timestamp_min, timestamps, td)) print("rp=", r_p, "ra=", r_a, "AoP=", AoP, "inc=", inc, "raan=", raan, "tp=", tp, "bstar=", bstar, "td=", td) print("overall", counter + 1, i + 1, "/", loops, "rms=", b4, "runtime=", time.time() - starttime) print("") # filtering the POS to change the values within their limits. # this shall help also with the percentiles and averages keys = list(finding.keys()) for k in range(len(pos)): for l in range(len(pos[k])): if keys[l] == "AoP": pos[k][l] = zeroTo360(pos[k][l]) if keys[l] == "raan": pos[k][l] = zeroTo360(pos[k][l]) if keys[l] == "inc": pos[k][l] = zeroTo180(pos[k][l]) counter += 1 sampler.reset() return b4_result, counter