def write_oem(self, t0, t1, n_items, fname): '''Writes OEM format file of orbital state for specific time interval. The states are linearly spaced in the specified time interval. :param float t0: Start time. :param float t1: End time. :param int n_items: State points between start and end times. ''' tv = n.linspace(t0, t1, num=n_items, dtype=n.float) state = self.get_state(tv) ut0 = dpt.jd_to_unix(dpt.mjd_to_jd(self.mjd0)) ccsds_write.write_oem(tv + ut0, state, oid=self.oid, fname=fname)
def _get_MicrosatR_state(mjd): tle_raw = '''1 43947U 19006A 19085.80962006 .00050945 29637-5 93510-4 0 9994 2 43947 96.6379 359.2115 0016283 220.5574 212.4511 16.01198803 9765''' tle_raw = [line.strip() for line in tle_raw.split('\n')] if len(tle_raw) % 2 != 0: raise Exception('Not even number of lines [not TLE compatible]') line1, line2 = tle_raw[0], tle_raw[1] jd0 = tle.tle_jd(line1) mjd0 = dpt.jd_to_mjd(jd0) sat_id = tle.tle_id(line1) state_TEME = tle.TLE_propagation_TEME(line1, line2, dpt.mjd_to_jd(mjd)) return state_TEME, sat_id
def propagate(self, dt, frame_transformation, frame_options={}): '''Propagate and change the epoch of this space object Frame transformations available: * TEME: From ITRF to TEME * ITRF: From TEME to ITRF * None: Do not perform transformation * function pointer: use custom transformation function that takes state as first argument (in SI units) and keyword arguments ''' state = self.get_state(np.array([dt], dtype=n.float64)) self.mjd0 = self.mjd0 + dt / (3600.0 * 24.0) if isinstance(frame_transformation, str): jd_ut1 = dpt.mjd_to_jd(self.mjd0) frame_options.setdefault('xp', 0.0) frame_options.setdefault('yp', 0.0) if frame_transformation == 'ITRF': state_frame = tle.TEME_to_ITRF(state[:, 0], jd_ut1, **frame_options) elif frame_transformation == 'TEME': state_frame = tle.ITRF_to_TEME(state[:, 0], jd_ut1, **frame_options) else: raise ValueError('Tranformation {} not recognized'.format( frame_transformation)) elif isinstance(frame_transformation, None): pass else: state_frame = frame_transformation(state, jd_ut1, **frame_options) x, y, z, vx, vy, vz = (state_frame * 1e-3).flatten() self.update( x=x, y=y, z=z, vx=vx, vy=vy, vz=vz, )
def __init__(self, population, known=False): self.size = len(population) assert self.size > 0, 'Population must contain at least one object.' self.population = population self._type = self.population._default_dtype self._data_format = [ 'oid', #0 'known', #1 't0_unix', #2 'tracks', #3 'tracklets', #4 'discovered', #5 'discovery_time', #6 ] mjd0s = population['mjd0'] self._t0_unix = np.empty((self.size, ), dtype=self._type) for ind, mjd0 in enumerate(mjd0s): self._t0_unix[ind] = dpt.jd_to_unix(dpt.mjd_to_jd(mjd0)) self._discovered = np.full((self.size, ), False, dtype=np.bool) self._discovery_track = np.empty((self.size, ), dtype=np.int64) self._discovery_time = np.empty((self.size, ), dtype=self._type) self._known = np.empty((self.size, ), dtype=np.bool) if isinstance(known, bool): for ind in range(self.size): self._known[ind] = known else: for ind in range(self.size): self._known[ind] = known[ind] self._oids = population['oid'] self._maintinence = [None] * self.size self._detections = [None] * self.size self._det_fields = [ "t0", "t1", "snr", 'tm', "range", "range_rate", "tx_gain", "rx_gain", "on_axis_angle" ] self._track_format = [ ('t0', self._type), ('dt', self._type), ('tracklet', np.bool), ('tracklet_index', np.int64), ('tracklet_len', np.int64), ('SNRdB', self._type), ('SNRdB-t', self._type), ('index', np.int64), ('baselines', np.int64), ('type', '|S8'), ] self.tracks = np.empty((0, ), dtype=self._track_format) self._tracking_summary_dtype = [ ('index', np.int64), ('peak-SNR-time', self._type), ('peak-SNRdB', self._type), ('tracking-time', self._type), ] self._scan_summary_dtype = [ ('index', np.int64), ('detection-time', self._type), ('SNRdB', self._type), ('tracking-time', self._type), ] self._tracklet_statistics_dtype = [ ('index', np.int64), ('track-id', np.int64), ('points-deviation-mean', self._type), ('points-deviation-std', self._type), ('points-deviation-skew', self._type), ('points', self._type), ('peak-SNRdB', self._type), ('span', self._type), ('points-deviation-normalized-mean', self._type), ('points-deviation-normalized-std', self._type), ('normalized-span', self._type), ] self._tracks_summary_dtype = [ ('index', np.int64), ('tracks', self._type), ('type', '|S8'), ('tracklets', self._type), ('tracklet-len-sum', self._type), ('tracklet-len-mean', self._type), ('tracklet-len-std', self._type), ('peak-SNRdB-mean', self._type), ('peak-SNRdB-std', self._type), ] self._prior_dtype = [ ('date', 'datetime64[us]'), ('index', np.int64), ('x', self._type), ('y', self._type), ('z', self._type), ('vx', self._type), ('vy', self._type), ('vz', self._type), ('cov', self._type, (6, 6)), ] self.priors = np.empty((0, ), dtype=self._prior_dtype) self._tracklet_statistics = np.empty( (0, ), dtype=self._tracklet_statistics_dtype) self._tracks_summary = np.empty((0, ), dtype=self._tracks_summary_dtype) self._tracking_summary = np.empty((0, ), dtype=self._tracking_summary_dtype) self._scan_summary = np.empty((0, ), dtype=self._scan_summary_dtype) self._tracklet_format = { 'track_id': None, 't': None, 'index': None, 'fnames': None, 'is_prior': None, } self.tracklets = []
tle_mjds = np.empty((len(TLEs), ), dtype=np.float64) for line_id, lines in enumerate(TLEs): line1, line2 = lines jd0 = tle.tle_jd(line1) mjd0 = dpt.jd_to_mjd(jd0) tle_mjds[line_id] = mjd0 best_tle = np.argmin(np.abs(tle_mjds - event_mjd)) line1, line2 = TLEs[best_tle] sat_id = tle.tle_id(line1) jd0 = tle.tle_jd(line1) mjd0 = dpt.jd_to_mjd(jd0) state_TEME = tle.TLE_propagation_TEME(line1, line2, dpt.mjd_to_jd(event_mjd)) kep = dpt.cart2kep(state_TEME, m=mass, M_cent=M_earth, radians=False) print('{}'.format(kep[0, 0])) print('{}'.format(kep[1, 0])) print('{}'.format(kep[2, 0])) print('{}'.format(kep[3, 0])) print('{}'.format(kep[4, 0])) print('{}'.format(kep[5, 0])) ''' os.environ['TZ'] = 'GMT' time.tzset() dt = np.datetime64('2019-04-02T12:01')
def tle_jd(line1): np_date = tle_npdt(line1) return dpt.mjd_to_jd(dpt.npdt2mjd(np_date))
def correlate(data, station, population, metric, n_closest = 1, out_file = None, verbose=False, MPI_on=False): '''Given a mono-static measurement of ranges and rage-rates, a radar model and a population: correlate measurements with population. :param dict data: Dictionary that contains measurement data. Contents are described below. :param AntennaRX station: Model of receiver station that performed the measurement. :param Population population: Population to correlate against. :param function metric: Metric used to correlate measurement and simulation of population. :param int n_closest: Number of closest matches to output. :param str out_file: If not :code:`None`, save the output data to this path. :param bool MPI_on: If True use internal parallelization with MPI to calculate correlation. Turn to False to externally parallelize with MPI. **Measurement data:** The file must be a dictionary that contains three data-sets: * 't': Times in unix-seconds * 'r': Ranges in meters * 'v': Range-rates in meters per second They should all be numpy vectors of equal length. ''' r = data['r'] t = data['t'] v = data['v'] t_sort = t.argsort() t = t[t_sort] r = r[t_sort] v = v[t_sort] #lt correction lt_correction = r/scipy.constants.c t += lt_correction _day = 3600.0*24.0 loc_ecef = station.ecef.copy() loc_ecef_norm = loc_ecef/n.linalg.norm(loc_ecef) jd_check = dpt.unix_to_jd(t) r_ref = n.empty(r.shape, dtype=r.dtype) v_ref = n.empty(v.shape, dtype=v.dtype) correlation_data = {} SO_generator = population.object_generator() if MPI_on: step = MPI.COMM_WORLD.size next_check = MPI.COMM_WORLD.rank else: step = 1 next_check = 0 for ind, obj in enumerate(SO_generator): if ind == next_check: if verbose: print('\n\nPID {} correlating {}/{} -------'.format(MPI.COMM_WORLD.rank, ind+1, len(population))) print(obj) jd_obj = dpt.mjd_to_jd(obj.mjd0) t_check = (jd_check - jd_obj)*_day states = obj.get_state(t_check) for jdi in range(jd_check.size): r_tmp = loc_ecef - states[:3,jdi] r_ref[jdi] = n.linalg.norm(r_tmp) v_ref[jdi] = n.dot( states[3:,jdi], r_tmp/r_ref[jdi], ) residual_r_mu = n.mean(r_ref - r) residual_r_std = n.std(r_ref - r) residual_v_mu = n.mean(v_ref - v) residual_v_std = n.std(v_ref - v) if len(v_ref) > 1: residual_a = ((v_ref[-1] - v_ref[0]) - v[-1] - v[0])/(t[-1] - t[0]) else: residual_a = 0 if verbose: print('Residuals:') print('residual_r_mu = {} m'.format(residual_r_mu)) print('residual_r_std = {} m'.format(residual_r_std)) print('residual_v_mu = {} m/s'.format(residual_v_mu)) print('residual_v_std = {} m/s'.format(residual_v_std)) print('residual_a = {} m/s^2'.format(residual_a)) cdat = { 'r_ref': r_ref.copy(), 'v_ref': v_ref.copy(), 'sat_id': obj.oid, 'stat': [residual_r_mu, residual_r_std, residual_v_mu, residual_v_std, residual_a] } if obj.oid in correlation_data: correlation_data[obj.oid].append(cdat) else: correlation_data[obj.oid] = [cdat] next_check += step oids = population['oid'] if step > 1: if MPI.COMM_WORLD.rank == 0: if verbose: print('---> PID %i: Receiving all results <barrier>'%(MPI.COMM_WORLD.rank)) for T in range(1,MPI.COMM_WORLD.size): for ID in range(T,len(population),MPI.COMM_WORLD.size): oid = oids[ID] correlation_data[oid] = MPI.COMM_WORLD.recv(source=T, tag=oid) if verbose: print('PID{} recived packet {} from PID{} '.format(MPI.COMM_WORLD.rank, oid, T)) else: if verbose: print('---> PID %i: Distributing all correlation results to process 0 <barrier>'%(MPI.COMM_WORLD.rank)) for ID in range(MPI.COMM_WORLD.rank,len(population),MPI.COMM_WORLD.size): oid = oids[ID] MPI.COMM_WORLD.send(correlation_data[oid], dest=0, tag=oid) if verbose: print('---> Distributing done </barrier>') matches_cdat = [] if MPI.COMM_WORLD.rank == 0 or not MPI_on: if verbose: print('Finding best matches.') match_metric = n.empty((len(correlation_data), 2), dtype = n.float64) key_list = [] key_cnt = 0 for key, cdats in correlation_data.items(): key_list.append(key) tmp_metrics = n.empty((len(cdats),), dtype=n.float64) for cind, cdat in enumerate(cdats): tmp_metrics[cind] = metric(t, r, v, cdat['r_ref'], cdat['v_ref']) tmp_match = n.argmin(tmp_metrics) match_metric[key_cnt, 0] = tmp_metrics[tmp_match] match_metric[key_cnt, 1] = tmp_match if verbose: print('{}: {} metric'.format(key, match_metric[key_cnt])) key_cnt += 1 match = n.argmin(match_metric[:,0]) if len(match_metric) > n_closest: all_match = n.argpartition(match_metric[:,0], n_closest) else: all_match = list(range(len(correlation_data))) if verbose: print('Best match {}:{} at {} match metric'.format( key_list[match], int(match_metric[match,1]), match_metric[match,0], )) cdat = correlation_data[key_list[match]][int(match_metric[match,1])] r_ref = cdat['r_ref'] v_ref = cdat['v_ref'] if out_file is not None: with h5py.File(out_file, 'w') as h_corr: for key, cdat in correlation_data.items(): for dat_key, dat in cdat.items(): h_corr[key+'/'+dat_key] = n.array(dat) h_corr.attrs['sat_match'] = key_list[match] h_corr['residuals'] = n.array(cdat['stat']) if len(match_metric) > n_closest: for may_match in all_match[:n_closest]: matches_cdat.append(correlation_data[key_list[may_match]][int(match_metric[may_match,1])]) else: for may_match in all_match: matches_cdat.append(correlation_data[key_list[may_match]][int(match_metric[may_match,1])]) if step > 1: matches_cdat = MPI.COMM_WORLD.bcast(matches_cdat, root=0) return matches_cdat
def simulate_Microsat_R_debris(num, max_dv, radii_range, mass_range, C_D_range, seed, propagator, propagator_options, mjd): tle_raw = '''1 43947U 19006A 19069.62495353 .00222140 22344-4 39735-3 0 9995 2 43947 96.6263 343.1609 0026772 226.5664 224.4731 16.01032328 7176 1 43947U 19006A 19069.68634861 .00217235 21442-4 38851-3 0 9995 2 43947 96.6282 343.2231 0026267 227.5469 217.1086 16.01062873 7183 1 43947U 19006A 19069.81093322 .00066734 37128-5 12017-3 0 9992 2 43947 96.6282 343.3467 0026246 227.0726 215.1493 16.01048534 7204 1 43947U 19006A 19070.54563657 .00111882 69857-5 20248-3 0 9991 2 43947 96.6271 344.0664 0025783 228.7058 125.4384 16.00925959 7318 1 43947U 19006A 19070.80923755 .00013653 19858-5 25403-4 0 9991 2 43947 96.6268 344.3320 0024927 225.1848 207.3499 16.01142181 7364 1 43947U 19006A 19071.12831853 .00154965 11740-4 27719-3 0 9998 2 43947 96.6279 344.6467 0025572 226.6832 243.5148 16.01113233 7412 1 43947U 19006A 19071.80921646 .00118874 76545-5 21379-3 0 9993 2 43947 96.6279 345.3224 0025491 224.0468 208.0149 16.01043615 7523 1 43947U 19006A 19072.44153689 .00037015 24665-5 66863-4 0 9999 2 43947 96.6279 345.9498 0025442 221.6016 252.7257 16.01159223 7620 1 43947U 19006A 19072.74405995 .00022228 21113-5 40609-4 0 9997 2 43947 96.6279 346.2500 0025432 220.3955 196.4626 16.01147542 7675 1 43947U 19006A 19073.12825718 .00008242 19370-5 15873-4 0 9996 2 43947 96.6304 346.6133 0023002 223.0617 246.6563 16.01114545 7738 1 43947U 19006A 19073.44154376 .00035052 24102-5 63784-4 0 9998 2 43947 96.6300 346.9244 0022588 225.2511 249.1037 16.01188227 7782 1 43947U 19006A 19073.80920446 -.00023017 21041-5 -40417-4 0 9994 2 43947 96.6337 347.2908 0022039 223.4278 208.5467 16.01076766 7841 1 43947U 19006A 19074.74408622 .00119327 76982-5 21614-3 0 9994 2 43947 96.6289 348.2321 0022856 222.6623 194.1149 16.01049775 7992 1 43947U 19006A 19075.01672454 .00167822 13470-4 30180-3 0 9994 2 43947 96.6290 348.5015 0022778 221.4659 325.7020 16.01154108 8039 1 43947U 19006A 19075.54702546 .00026769 22010-5 48973-4 0 9993 2 43947 96.6290 349.0278 0022754 219.3583 142.5100 16.01177853 8128 1 43947U 19006A 19075.74902949 .00160298 12418-4 29196-3 0 9995 2 43947 96.6301 349.2308 0021693 223.2409 221.9908 16.00986874 8150 1 43947U 19006A 19075.80608134 .00151204 11245-4 27527-3 0 9991 2 43947 96.6283 349.2862 0021642 222.7701 191.0541 16.01000711 8166 1 43947U 19006A 19075.80608134 .00152613 11422-4 27780-3 0 9994 2 43947 96.6283 349.2862 0021642 222.7701 191.0553 16.01002279 8160 1 43947U 19006A 19076.04950662 .00212767 20643-4 38419-3 0 9990 2 43947 96.6283 349.5277 0021615 221.8443 154.0766 16.01125308 8205 1 43947U 19006A 19076.38314227 .00228397 23614-4 40852-3 0 9999 2 43947 96.6283 349.8588 0021611 220.6464 277.1313 16.01285801 8254 1 43947U 19006A 19076.56965602 .00375665 62286-4 68387-3 0 9990 2 43947 96.6317 350.0396 0020897 222.9971 269.0493 16.01007118 8281 1 43947U 19006A 19076.62489356 .00301460 40170-4 54811-3 0 9991 2 43947 96.6317 350.0945 0020879 222.7479 227.4454 16.01029701 8290 1 43947U 19006A 19076.74888822 .00206456 19517-4 37455-3 0 9990 2 43947 96.6317 350.2206 0020779 222.3519 222.0257 16.01081824 8311 1 43947U 19006A 19076.80334391 .00189842 16753-4 34417-3 0 9997 2 43947 96.6317 350.2747 0020760 222.1378 175.8977 16.01098177 8326 1 43947U 19006A 19077.25548485 .00042586 26475-5 77957-4 0 9991 2 43947 96.6337 350.7139 0018680 228.2848 254.2224 16.01199217 8396 1 43947U 19006A 19077.49923692 .00048049 28483-5 87602-4 0 9993 2 43947 96.6337 350.9559 0018675 227.3154 219.3457 16.01241589 8433 1 43947U 19006A 19077.73867148 .00176479 14671-4 32436-3 0 9999 2 43947 96.6324 351.1992 0019599 225.2817 160.3011 16.00913438 8475 1 43947U 19006A 19078.62402633 .00193781 17362-4 35487-3 0 9996 2 43947 96.6337 352.0814 0019337 224.7610 220.1468 16.00981700 8611 1 43947U 19006A 19079.44446882 .00056887 32197-5 10424-3 0 9994 2 43947 96.6318 352.8859 0017932 222.6020 267.9762 16.01149860 8742 1 43947U 19006A 19079.56114259 .00331197 48376-4 60603-3 0 9996 2 43947 96.6357 353.0133 0018767 223.2624 219.3325 16.01004143 8769 1 43947U 19006A 19079.87121502 .00017670 20377-5 33169-4 0 9996 2 43947 96.6348 353.3097 0018626 221.5456 207.0221 16.01103300 8819 1 43947U 19006A 19080.12837572 .00018161 20446-5 34105-4 0 9991 2 43947 96.6342 353.5628 0017856 223.7454 246.0274 16.01109643 8852 1 43947U 19006A 19080.25184005 .00021666 21015-5 40443-4 0 9990 2 43947 96.6342 353.6854 0017855 223.2528 237.6932 16.01123784 8871 1 43947U 19006A 19080.56838169 .00007182 19289-5 14116-4 0 9996 2 43947 96.6323 353.9969 0018497 223.3308 260.9364 16.01125965 8927 1 43947U 19006A 19080.80934521 -.00010028 19397-5 -17132-4 0 9998 2 43947 96.6323 354.2362 0018496 222.3649 209.7823 16.01086764 8962 1 43947U 19006A 19081.01817130 -.00000602 19026-5 00000+0 0 9994 2 43947 96.6305 354.4520 0018602 217.7557 337.0831 16.00999357 8992 1 43947U 19006A 19081.19970958 .00192780 17239-4 35047-3 0 9995 2 43947 96.6332 354.6387 0017808 222.1497 298.3751 16.01166044 9020 1 43947U 19006A 19081.44288380 .00132357 90623-5 24030-3 0 9997 2 43947 96.6332 354.8802 0017799 221.2143 260.0465 16.01211967 9068 1 43947U 19006A 19081.68209472 .00185493 16056-4 34001-3 0 9993 2 43947 96.6354 355.1161 0017576 220.8387 198.1644 16.01033820 9107 1 43947U 19006A 19081.80977756 .00126608 84347-5 23219-3 0 9995 2 43947 96.6356 355.2444 0017575 222.5408 211.8678 16.01049036 9124 1 43947U 19006A 19082.19785193 .00009851 19489-5 19026-4 0 9997 2 43947 96.6356 355.6299 0017571 221.0666 288.6619 16.01097025 9186 1 43947U 19006A 19082.25710510 .00009887 19472-5 19026-4 0 9996 2 43947 96.6318 355.6880 0017118 220.4674 270.5748 16.01171238 9192 1 43947U 19006A 19082.38407701 .00138221 97199-5 25077-3 0 9994 2 43947 96.6325 355.8124 0017241 219.6702 282.7837 16.01240682 9219 1 43947U 19006A 19082.68646591 .00149753 11067-4 27555-3 0 9993 2 43947 96.6363 356.1139 0016876 222.4115 221.6813 16.01004284 9261 1 43947U 19006A 19082.81114447 .00088395 50732-5 16304-3 0 9995 2 43947 96.6363 356.2377 0016873 221.9425 220.2429 16.01009980 9289 1 43947U 19006A 19083.00642146 .00143972 10375-4 26369-3 0 9992 2 43947 96.6358 356.4314 0016878 221.0757 265.8708 16.01087252 9317 1 43947U 19006A 19083.49288397 -.03265362 32488-2 -61588-2 0 9990 2 43947 96.6406 356.9162 0017256 219.6745 189.3161 16.00630469 9392 1 43947U 19006A 19083.74911125 .00084825 48174-5 15749-3 0 9999 2 43947 96.6345 357.1709 0015989 224.4362 220.2191 16.00930159 9436 1 43947U 19006A 19083.81116759 .00103815 62739-5 19235-3 0 9995 2 43947 96.6324 357.2279 0015947 223.4735 218.5865 16.00945210 9446 1 43947U 19006A 19083.93495759 .00147725 10814-4 27243-3 0 9990 2 43947 96.6324 357.3507 0015945 222.9977 212.0347 16.00998010 9463 1 43947U 19006A 19084.04992207 .00154144 11623-4 28342-3 0 9996 2 43947 96.6354 357.4673 0016254 222.4775 154.7117 16.01036332 9486 1 43947U 19006A 19084.56994306 -.00389064 56746-4 -71643-3 0 9995 2 43947 96.6360 357.9786 0015819 222.1151 270.2904 16.00942425 9569 1 43947U 19006A 19084.68712708 .00107795 66250-5 19877-3 0 9992 2 43947 96.6366 358.0976 0015957 221.7662 225.5779 16.01024149 9583 1 43947U 19006A 19084.74556389 .00097765 57838-5 18034-3 0 9991 2 43947 96.6363 358.1566 0015910 221.6645 202.2537 16.01028963 9598 1 43947U 19006A 19084.98720666 .00152043 11367-4 27860-3 0 9992 2 43947 96.6362 358.3958 0015832 220.6056 155.1371 16.01110841 9636 1 43947U 19006A 19085.19976117 .00022830 21215-5 42802-4 0 9998 2 43947 96.6349 358.6073 0016094 221.4560 298.5857 16.01085713 9665 1 43947U 19006A 19085.49952644 .00052661 30351-5 96803-4 0 9996 2 43947 96.6377 358.9036 0016197 221.8414 224.9544 16.01169686 9718 1 43947U 19006A 19085.56842683 .00054526 31167-5 10000-3 0 9997 2 43947 96.6377 358.9720 0016198 221.5803 262.1287 16.01202917 9722 1 43947U 19006A 19085.80962006 .00050945 29637-5 93510-4 0 9994 2 43947 96.6379 359.2115 0016283 220.5574 212.4511 16.01198803 9765''' mass = 740 tle_raw = [line.strip() for line in tle_raw.split('\n')] if len(tle_raw) % 2 != 0: raise Exception('Not even number of lines [not TLE compatible]') TLEs = zip(tle_raw[0::2], tle_raw[1::2]) event_date = np.datetime64('2019-03-27T05:40') event_mjd = dpt.npdt2mjd(event_date) M_earth = propagator_sgp4.SGP4.GM*1e9/consts.G pop = Population( name='Simulated Microsat R debris', extra_columns = ['A', 'm', 'd', 'C_D', 'C_R'], space_object_uses = [True, True, True, True, True], propagator = propagator, propagator_options = propagator_options, ) pop.allocate(num) tle_mjds = np.empty((len(TLEs),), dtype=np.float64) for line_id, lines in enumerate(TLEs): line1, line2 = lines jd0 = tle.tle_jd(line1) mjd0 = dpt.jd_to_mjd(jd0) tle_mjds[line_id] = mjd0 best_tle = np.argmin(np.abs(tle_mjds - event_mjd)) line1, line2 = TLEs[best_tle] sat_id = tle.tle_id(line1) jd0 = tle.tle_jd(line1) mjd0 = dpt.jd_to_mjd(jd0) state_TEME = tle.TLE_propagation_TEME(line1, line2, dpt.mjd_to_jd(event_mjd)) #first has no pert states = np.repeat(state_TEME, num, axis=1) np.random.seed(seed) kep = dpt.cart2kep(state_TEME, m=mass, M_cent=M_earth, radians=False) pop.objs[0][1] = kep[0]*1e-3 pop.objs[0][2] = kep[1] pop.objs[0][3] = kep[2] pop.objs[0][4] = kep[4] pop.objs[0][5] = kep[3] pop.objs[0][6] = dpt.true2mean(kep[5], kep[1], radians=False) pop.objs[0][0] = float(sat_id) pop.objs[0][7] = mjd0 pop.objs[0][8] = np.pi*1.0**2 pop.objs[0][9] = mass pop.objs[0][10] = 2.0 pop.objs[0][11] = 2.3 pop.objs[0][12] = 1.0 ind = 1 while ind < num: C_D = np.random.rand(1)*(C_D_range[1] - C_D_range[0]) + C_D_range[0] rho = 11e3 while rho > 10e3: r = np.random.rand(1)*(radii_range[1] - radii_range[0]) + radii_range[0] A = np.pi*r**2 m = np.random.rand(1)*(mass_range[1] - mass_range[0]) + mass_range[0] vol = 4.0/3.0*np.pi*r**3 rho = m/vol pert_state = states[:,ind].copy() dv = np.random.rand(1)*max_dv ddir = _rand_sph(1).T pert_state[:3] += ddir[:,0]*dv kep = dpt.cart2kep(pert_state, m=mass, M_cent=M_earth, radians=False) if kep[0]*(1.0 - kep[1]) > 6353.0e3+100e3: pop.objs[ind][1] = kep[0]*1e-3 pop.objs[ind][2] = kep[1] pop.objs[ind][3] = kep[2] pop.objs[ind][4] = kep[4] pop.objs[ind][5] = kep[3] pop.objs[ind][6] = dpt.true2mean(kep[5], kep[1], radians=False) pop.objs[ind][0] = float(sat_id) + num pop.objs[ind][7] = mjd0 pop.objs[ind][8] = A pop.objs[ind][9] = m pop.objs[ind][10] = r*2.0 pop.objs[ind][11] = C_D pop.objs[ind][12] = 1.0 ind += 1 if 'out_frame' in pop.propagator_options: out_f = pop.propagator_options['out_frame'] else: out_f = 'ITRF' pop.propagator_options['out_frame'] = 'TEME' pop = propagate_population(pop, mjd) pop.propagator_options['out_frame'] = out_f return pop
def create_tracklet(o, radar, t_obs, hdf5_out=True, ccsds_out=True, dname="./tracklets", noise=False, dx=10.0, dv=10.0, dt=0.01, ignore_elevation_thresh=False): '''Simulate tracks of objects. ionospheric limit is a lower limit on precision after ionospheric corrections ''' if noise: noise = 1.0 else: noise = 0.0 # TDB, kludge, this should be allowed to change as a function of time bw = radar._tx[0].tx_bandwidth txlen = radar._tx[0].pulse_length * 1e6 # pulse length in microseconds ipp = radar._tx[0].ipp # pulse length in microseconds n_ipp = int(radar._tx[0].n_ipp) # pulse length in microseconds rfun, dopfun = debris.precalculate_dr(txlen, bw, ipp=ipp, n_ipp=n_ipp) t0_unix = dpt.jd_to_unix(dpt.mjd_to_jd(o.mjd0)) if debug_low: for tx in radar._tx: print("TX %s" % (tx.name)) for rx in radar._tx: print("RX %s" % (rx.name)) rx_p = [] tx_p = [] for tx in radar._tx: tx_p.append(coord.geodetic2ecef(tx.lat, tx.lon, tx.alt)) for rxi, rx in enumerate(radar._rx): rx_p.append(coord.geodetic2ecef(rx.lat, rx.lon, rx.alt)) ecefs = o.get_orbit(t_obs) state = o.get_state(t_obs) ecefs_p_dt = o.get_orbit(t_obs + dt) ecefs_m_dt = o.get_orbit(t_obs - dt) # velocity in ecef ecef_vel = (0.5 * ((ecefs_p_dt - ecefs) + (ecefs - ecefs_m_dt)) / dt) # linearized error estimates for ecef state vector error std_dev, when three or more # delays and doppl er shifts are measured ecef_stdevs = [] meas = [] for tx in radar._tx: ecef_stdevs.append({"time_idx": [], "m_time": [], "ecef_stdev": []}) for tx in radar._tx: m_rx = [] for rx in radar._rx: m_rx.append({ "time_idx": [], "m_time": [], "m_delay": [], "m_delay_std": [], "m_range": [], "m_range_std": [], "m_range_rate": [], "m_range_rate_std": [], "m_doppler": [], "m_doppler_std": [], "gain_tx": [], "gain_rx": [], "enr": [], "true_state": [], "true_time": [], "g_lat": [], "g_lon": [] }) meas.append(m_rx) # largest possible number of state vector measurements n_state_meas = len(radar._tx) * len(radar._rx) # jacobian for error covariance calc J = n.zeros([2 * n_state_meas, 6]) Sigma_Lin = n.zeros([2 * n_state_meas, 2 * n_state_meas]) # error standard deviation for state vector estimates at each position state_vector_errors = n.zeros([6, len(t_obs)]) # go through all times for ti, t in enumerate(t_obs): p = n.array([ecefs[0, ti], ecefs[1, ti], ecefs[2, ti]]) p_p = n.array( [ecefs_p_dt[0, ti], ecefs_p_dt[1, ti], ecefs_p_dt[2, ti]]) p_m = n.array( [ecefs_m_dt[0, ti], ecefs_m_dt[1, ti], ecefs_m_dt[2, ti]]) # for linearized state vector error determination p_dx0 = n.array([ecefs[0, ti] + dx, ecefs[1, ti], ecefs[2, ti]]) p_dx1 = n.array([ecefs[0, ti], ecefs[1, ti] + dx, ecefs[2, ti]]) p_dx2 = n.array([ecefs[0, ti], ecefs[1, ti], ecefs[2, ti] + dx]) # doppler error comes from linear least squares # initialize jacobian J[:, :] = 0.0 Sigma_Lin[:, :] = 0.0 state_meas_idx = 0 # go through all transmitters for txi, tx in enumerate(radar._tx): pos_vec_tx = -tx_p[txi] + p pos_vec_tx_p = -tx_p[txi] + p_p pos_vec_tx_m = -tx_p[txi] + p_m # for linearized errors pos_vec_tx_dx0 = -tx_p[txi] + p_dx0 pos_vec_tx_dx1 = -tx_p[txi] + p_dx1 pos_vec_tx_dx2 = -tx_p[txi] + p_dx2 # incident k-vector k_inc = -2.0 * n.pi * pos_vec_tx / n.linalg.norm( pos_vec_tx) / tx.wavelength elevation_tx = 90.0 - coord.angle_deg(tx_p[txi], pos_vec_tx) if elevation_tx > tx.el_thresh or ignore_elevation_thresh: k0 = tx.point_ecef( pos_vec_tx) # we are pointing at the object when tracking gain_tx = tx.beam.gain(k0) # get antenna gain range_tx = n.linalg.norm(pos_vec_tx) range_tx_p = n.linalg.norm(pos_vec_tx_p) range_tx_m = n.linalg.norm(pos_vec_tx_m) range_tx_dx0 = n.linalg.norm(pos_vec_tx_dx0) range_tx_dx1 = n.linalg.norm(pos_vec_tx_dx1) range_tx_dx2 = n.linalg.norm(pos_vec_tx_dx2) tx_to_target_time = range_tx / c.c # go through all receivers for rxi, rx in enumerate(radar._rx): pos_vec_rx = -rx_p[rxi] + p pos_vec_rx_p = -rx_p[rxi] + p_p pos_vec_rx_m = -rx_p[rxi] + p_m # rx k-vector k_rec = 2.0 * n.pi * pos_vec_rx / n.linalg.norm( pos_vec_rx) / tx.wavelength # scattered k-vector k_scat = k_rec - k_inc # for linearized pos error pos_vec_rx_dx0 = -rx_p[rxi] + p_dx0 pos_vec_rx_dx1 = -rx_p[rxi] + p_dx1 pos_vec_rx_dx2 = -rx_p[rxi] + p_dx2 elevation_rx = 90.0 - coord.angle_deg( rx_p[rxi], pos_vec_rx) if elevation_rx > rx.el_thresh or ignore_elevation_thresh: k0 = rx.point_ecef( pos_vec_rx ) # we are pointing at the object when tracking gain_rx = rx.beam.gain(k0) # get antenna gain range_rx = n.linalg.norm(pos_vec_rx) range_rx_p = n.linalg.norm(pos_vec_rx_p) range_rx_m = n.linalg.norm(pos_vec_rx_m) range_rx_dx0 = n.linalg.norm(pos_vec_rx_dx0) range_rx_dx1 = n.linalg.norm(pos_vec_rx_dx1) range_rx_dx2 = n.linalg.norm(pos_vec_rx_dx2) target_to_rx_time = range_rx / c.c # SNR of object at measured location enr_rx = debris.hard_target_enr( gain_tx, gain_rx, tx.wavelength, tx.tx_power, range_tx, range_rx, o.diam, bandwidth=tx. coh_int_bandwidth, # coherent integration bw rx_noise_temp=rx.rx_noise) if enr_rx > 1e8: enr_rx = 1e8 if enr_rx < 0.1: enr_rx = 0.1 #print("snr %1.2f"%(enr_rx)) dr = 10.0**(rfun(n.log10(enr_rx))) ddop = 10.0**(dopfun(n.log10(enr_rx))) # Unknown doppler shift due to ionosphere can be up to 0.1 Hz, # estimate based on typical GNU Ionospheric tomography receiver phase curves. if ddop < 0.1: ddop = 0.1 dr = n.sqrt(dr**2.0 + iono_errfun(range_tx / 1e3)** 2.0) # add ionospheric error if dr < o.diam: # if object diameter is larger than range error, make it at least as big as target dr = o.diam r0 = range_tx + range_rx rp = range_tx_p + range_rx_p rm = range_tx_m + range_rx_m range_rate_d = 0.5 * ( (rp - r0) + (r0 - rm)) / dt # symmetric numerical derivative # doppler (m/s) using scattering k-vector range_rate = n.dot( pos_vec_rx / range_rx, state[3:6, ti]) + n.dot( pos_vec_tx / range_tx, state[3:6, ti]) doppler = range_rate / tx.wavelength # print("rr1 %1.1f rr2 %1.1f"%(range_rate_d,range_rate)) doppler_k = n.dot(k_scat, ecef_vel[:, ti]) / 2.0 / n.pi range_rate_k = doppler_k * tx.wavelength # for linearized errors, range rate at small perturbations to state vector velocity parameters range_rate_k_dv0 = tx.wavelength * n.dot( k_scat, ecef_vel[:, ti] + n.array([dv, 0, 0])) / 2.0 / n.pi range_rate_k_dv1 = tx.wavelength * n.dot( k_scat, ecef_vel[:, ti] + n.array([0, dv, 0])) / 2.0 / n.pi range_rate_k_dv2 = tx.wavelength * n.dot( k_scat, ecef_vel[:, ti] + n.array([0, 0, dv])) / 2.0 / n.pi # full range for error calculation, with small perturbations to position state full_range_dx0 = range_rx_dx0 + range_tx_dx0 full_range_dx1 = range_rx_dx1 + range_tx_dx1 full_range_dx2 = range_rx_dx2 + range_tx_dx2 if enr_rx > tx.enr_thresh: # calculate jacobian row for state vector errors # range J[2 * state_meas_idx, 0:3] = n.array([(full_range_dx0 - r0) / dx, (full_range_dx1 - r0) / dx, (full_range_dx2 - r0) / dx]) # range inverse variance Sigma_Lin[2 * state_meas_idx, 2 * state_meas_idx] = 1.0 / dr**2.0 # range-rate J[2 * state_meas_idx + 1, 3:6] = n.array([ (range_rate_k_dv0 - range_rate_k) / dv, (range_rate_k_dv1 - range_rate_k) / dv, (range_rate_k_dv2 - range_rate_k) / dv ]) # range-rate inverse variance Sigma_Lin[2 * state_meas_idx + 1, 2 * state_meas_idx + 1] = 1.0 / (tx.wavelength * ddop)**2.0 state_meas_idx += 1 # detection! if debug_low: print( "rx %d tx el %1.2f rx el %1.2f gain_tx %1.2f gain_rx %1.2f enr %1.2f rr %1.2f prop time %1.6f dr %1.2f" % (rxi, elevation_tx, elevation_rx, gain_tx, gain_rx, enr_rx, range_rate, tx_to_target_time, dr)) # ground foot point in geodetic llh = coord.ecef2geodetic(p[0], p[1], p[2]) # time is time of transmit pulse meas[txi][rxi]["time_idx"].append(ti) meas[txi][rxi]["m_time"].append(t + t0_unix) meas[txi][rxi]["m_range"].append( (range_tx + range_rx) / 1e3 + noise * n.random.randn() * dr / 1e3) meas[txi][rxi]["m_range_std"].append(dr / 1e3) rr_std = c.c * ddop / radar._tx[ txi].freq / 2.0 / 1e3 meas[txi][rxi]["m_range_rate"].append( range_rate / 1e3 + noise * n.random.randn() * rr_std) # 0.1 m/s error due to ionosphere meas[txi][rxi]["m_range_rate_std"].append(rr_std) meas[txi][rxi]["m_doppler"].append( doppler + noise * n.random.randn() * ddop / 1e3) meas[txi][rxi]["m_doppler_std"].append(ddop) meas[txi][rxi]["m_delay"].append( tx_to_target_time + target_to_rx_time) meas[txi][rxi]["g_lat"].append(llh[0]) meas[txi][rxi]["g_lon"].append(llh[1]) meas[txi][rxi]["enr"].append(enr_rx) meas[txi][rxi]["gain_tx"].append(gain_tx) meas[txi][rxi]["gain_rx"].append(gain_rx) true_state = n.zeros(6) true_state[3:6] = (0.5 * ((p_p - p) + (p - p_m)) / dt) / 1e3 true_state[0:3] = p / 1e3 meas[txi][rxi]["true_state"].append(true_state) meas[txi][rxi]["true_time"].append(t_obs[ti] + t0_unix) else: if debug_high: print("not detected: enr_rx {}".format(enr_rx)) else: if debug_high: print("not detected: elevation_rx {}".format( elevation_rx)) else: if debug_high: print("not detected: elevation_tx {}".format(elevation_tx)) # if more than three measurements of range and range-rate, then we maybe able to # observe true state. if so, calculate the linearized covariance matrix if state_meas_idx > 2: # use only the number of measurements that were good JJ = J[0:(2 * state_meas_idx), :] try: Sigma_post = n.linalg.inv( n.dot(n.dot(n.transpose(JJ), Sigma_Lin), JJ)) ecef_stdevs[txi]["time_idx"].append(ti) ecef_stdevs[txi]["m_time"].append(t) ecef_stdevs[txi]["ecef_stdev"].append(Sigma_post) except: print("Singular posterior covariance...") if debug_low: print(meas) fnames = write_tracklets(o, meas, radar, dname, hdf5_out=hdf5_out, ccsds_out=ccsds_out) return (meas, fnames, ecef_stdevs)
def test_envisat_detection(): from mpi4py import MPI # SORTS imports CORE import population_library as plib from simulation import Simulation #SORTS Libraries import radar_library as rlib import radar_scan_library as rslib import scheduler_library as schlib import antenna_library as alib import rewardf_library as rflib #SORTS functions import ccsds_write import dpt_tools as dpt sim_root = './tests/tmp_test_data/envisat_sim_test' radar = rlib.eiscat_uhf() radar.set_FOV(max_on_axis=30.0, horizon_elevation=25.0) scan = rslib.beampark_model( lat=radar._tx[0].lat, lon=radar._tx[0].lon, alt=radar._tx[0].alt, az=90.0, el=75.0, ) radar.set_scan(scan) #tle files for envisat in 2016-09-05 to 2016-09-07 from space-track. TLEs = [ ('1 27386U 02009A 16249.14961597 .00000004 00000-0 15306-4 0 9994', '2 27386 98.2759 299.6736 0001263 83.7600 276.3746 14.37874511760117' ), ('1 27386U 02009A 16249.42796553 .00000002 00000-0 14411-4 0 9997', '2 27386 98.2759 299.9417 0001256 82.8173 277.3156 14.37874515760157' ), ('1 27386U 02009A 16249.77590267 .00000010 00000-0 17337-4 0 9998', '2 27386 98.2757 300.2769 0001253 82.2763 277.8558 14.37874611760201' ), ('1 27386U 02009A 16250.12384028 .00000006 00000-0 15974-4 0 9995', '2 27386 98.2755 300.6121 0001252 82.5872 277.5467 14.37874615760253' ), ('1 27386U 02009A 16250.75012691 .00000017 00000-0 19645-4 0 9999', '2 27386 98.2753 301.2152 0001254 82.1013 278.0311 14.37874790760345' ), ] pop = plib.tle_snapshot(TLEs, sgp4_propagation=True) pop['d'] = n.sqrt(4 * 2.3 * 4 / n.pi) pop['m'] = 2300. pop['C_R'] = 1.0 pop['C_D'] = 2.3 pop['A'] = 4 * 2.3 ccsds_file = './data/uhf_test_data/events/2002-009A-2016-09-06_08:27:08.tdm' obs_data = ccsds_write.read_ccsds(ccsds_file) jd_obs = dpt.mjd_to_jd(dpt.npdt2mjd(obs_data['date'])) jd_sort = jd_obs.argsort() jd_obs = jd_obs[jd_sort] jd_det = jd_obs[0] pop.delete([0, 1, 2, 4]) #now just best ID left jd_pop = dpt.mjd_to_jd(pop['mjd0'][0]) tt_obs = (jd_obs - jd_pop) * 3600.0 * 24.0 sim = Simulation( radar=radar, population=pop, root=sim_root, scheduler=schlib.dynamic_scheduler, ) sim.observation_parameters( duty_cycle=0.125, SST_fraction=1.0, tracking_fraction=0.0, SST_time_slice=0.2, ) sim.run_observation(jd_obs[-1] - jd_pop + 1.0) sim.print_maintenance() sim.print_detections() sim.set_scheduler_args(logger=sim.logger, ) sim.run_scheduler() sim.print_tracks() print(sim.catalogue.tracklets[0]['t']) print(jd_obs) shutil.rmtree(sim_root) assert False
#propagator_options = { # 'in_frame': 'TEME', # 'out_frame': 'ITRF', #}, ) #it seems to around 25m^2 area d = np.sqrt(25.0 * 4 / np.pi) pop['d'] = d measurement_file = './data/uhf_test_data/events/pass-1473150428660000.h5' #ccsds_file = './data/uhf_test_data/events/2002-009A-1473150428.tdm' ccsds_file = './data/uhf_test_data/events/2002-009A-2016-09-06_08:27:08.tdm' obs_data = ccsds_write.read_ccsds(ccsds_file) jd_obs = dpt.mjd_to_jd(dpt.npdt2mjd(obs_data['date'])) date_obs = obs_data['date'] sort_obs = np.argsort(date_obs) date_obs = date_obs[sort_obs] r_obs = obs_data['range'][sort_obs] * 0.5 v_obs = obs_data['doppler_instantaneous'][sort_obs] #print(v_obs) #exit() #TO DEBUG #jd_obs = jd_obs[:3] #date_obs = date_obs[:3] #r_obs = r_obs[:3]
def get_orbit_cart(self, t, x, y, z, vx, vy, vz, mjd0, **kwargs): ''' **Implementation:** All state-vector units are in meters. Keyword arguments contain only information needed for ballistic coefficient :code:`B` used by SGP4. Either :code:`B` or :code:`C_D`, :code:`A` and :code:`m` must be supplied. They also contain a option to give angles in radians or degrees. By default input is assumed to be degrees. **Frame:** The input frame is ECI (TEME) for orbital elements and Cartesian. The output frame is always ECEF. :param float B: Ballistic coefficient :param float C_D: Drag coefficient :param float A: Cross-sectional Area :param float m: Mass :param bool radians: If true, all angles are assumed to be in radians. ''' t = self._make_numpy(t) if 'B' in kwargs: B = kwargs['B'] else: B = 0.5*kwargs['C_D']*kwargs['A']/kwargs['m'] state_c = np.array([x,y,z,vx,vy,vz], dtype=np.float) state_c *= 1e-3 #to km mean_elements = tle.TEME_to_TLE(state_c, mjd0=mjd0, kepler=False) if np.any(np.isnan(mean_elements)): raise Exception('Could not compute SGP4 initial state: {}'.format(mean_elements)) # Create own SGP4 object obj = SGP4(mjd0, mean_elements, B) mjdates = mjd0 + t/86400.0 pos=np.zeros([3,t.size]) vel=np.zeros([3,t.size]) for mi,mjd in enumerate(mjdates): y = obj.state(mjd) pos[:,mi] = y[:3] vel[:,mi] = y[3:] if self.out_frame == 'TEME': states=np.empty((6,t.size), dtype=np.float) states[:3,:] = pos*1e3 states[3:,:] = vel*1e3 return states elif self.out_frame == 'ITRF': if self.polar_motion: PM_data = tle.get_Polar_Motion(dpt.mjd_to_jd(mjdates)) xp = PM_data[:,0] xp.shape = (1,xp.size) yp = PM_data[:,1] yp.shape = (1,yp.size) else: xp = 0.0 yp = 0.0 ecefs = teme2ecef(t, pos, vel, mjd0=mjd0, xp=xp, yp=yp ,model=self.polar_motion_model) ecefs *= 1e3 #to meter return ecefs else: raise Exception('Output frame {} not found'.format(self.out_frame))
def wls_state_est(mcmc=False, n_tracklets=1, track_length=600.0, n_points=3, oid=145128, N_samples=5000): """ Weighted linear least squares estimation of orbital elements Simulate measurements using create tracklet and estimate orbital parameters, which include six keplerian and area to mass ratio. Use fmin search. Optionally utilize MCMC to sample the distribution of parameters. number of tracklets, tracklet length, and number of tracklet points per tracklet are user definable, allowing one to try out different measurement strategies. """ # first we shall simulate some measurement # Envisat m = plib.master_catalog(sort=False) o = m.get_object(oid) dname="./test_tracklets_%d"%(oid) print(o) # figure out epoch in unix seconds t0_unix = dpt.jd_to_unix(dpt.mjd_to_jd(o.mjd0)) if rank == 0: os.system("rm -Rf %s"%(dname)) os.system("mkdir %s"%(dname)) e3d = rlib.eiscat_3d(beam='gauss') # time in seconds after mjd0 t_all = n.linspace(0, 24*3600, num=1000) passes, _, _, _, _ = simulate_tracking.find_pass_interval(t_all, o, e3d) print(passes) if n_tracklets == None: n_tracklets = len(passes[0]) n_tracklets = n.min([n_tracklets,len(passes[0])]) for pi in range(n_tracklets): p = passes[0][pi] mean_t=0.5*(p[1]+p[0]) print("duration %1.2f"%(p[1]-p[0])) if p[1]-p[0] > 50.0: if n_points == 1: t_obs=n.array([mean_t]) else: t_obs=n.linspace(n.max([p[0],mean_t-track_length/2]), n.min([p[1],mean_t+track_length/2]),num=n_points) print(t_obs) meas, fnames, ecef_stdevs = st.create_tracklet(o, e3d, t_obs, hdf5_out=True, ccsds_out=True, dname=dname) # then we read these measurements comm.Barrier() fl=glob.glob("%s/*"%(dname)) for f in fl: print(f) fl2=glob.glob("%s/*.h5"%(f)) print(fl2) fl2.sort() true_states=[] all_r_meas=[] all_rr_meas=[] all_t_meas=[] all_true_states=[] tx_locs=[] rx_locs=[] range_stds=[] range_rate_stds=[] for mf in fl2: h=h5py.File(mf,"r") all_r_meas.append(n.copy(h["m_range"].value)) all_rr_meas.append(n.copy(h["m_range_rate"].value)) all_t_meas.append(n.copy(h["m_time"].value-t0_unix)) all_true_states.append(n.copy(h["true_state"].value)) tx_locs.append(n.copy(h["tx_loc"].value)) rx_locs.append(n.copy(h["rx_loc"].value)) range_stds.append(n.copy(h["m_range_rate_std"].value)) range_rate_stds.append(h["m_range_std"].value) h.close() # determine orbital elements o_prior = m.get_object(oid) # get best fit space object o_fit=mcmc_od(all_t_meas, all_r_meas, all_rr_meas, range_stds, range_rate_stds, tx_locs, rx_locs, o_prior, mcmc=mcmc, odir=dname, N_samples=N_samples)
def test_OD(root, sub_path): import orbit_determination import TLE_tools as tle import dpt_tools as dpt import radar_library as rlib import propagator_sgp4 #import propagator_orekit #import propagator_neptune import ccsds_write radar = rlib.eiscat_3d(beam='interp', stage=1) radar.set_FOV(max_on_axis=90.0, horizon_elevation=10.0) radar.set_SNR_limits(min_total_SNRdb=10.0, min_pair_SNRdb=1.0) radar.set_TX_bandwith(bw = 1.0e6) #prop = propagator_neptune.PropagatorNeptune() prop = propagator_sgp4.PropagatorSGP4() mass=0.8111E+04 diam=0.8960E+01 m_to_A=128.651 params = dict( A = { 'dist': None, 'val': mass/m_to_A, }, d = { 'dist': None, 'val': diam, }, m = { 'dist': None, 'val': mass, }, C_D = { 'dist': None, 'val': 2.3, }, ) fname = glob.glob(root + sub_path + '*.oem')[0] prior_data, prior_meta = ccsds_write.read_oem(fname) prior_sort = np.argsort(prior_data['date']) prior_data = prior_data[prior_sort][0] prior_mjd = dpt.npdt2mjd(prior_data['date']) prior_jd = dpt.mjd_to_jd(prior_mjd) state0 = np.empty((6,), dtype=np.float64) state0[0] = prior_data['x'] state0[1] = prior_data['y'] state0[2] = prior_data['z'] state0[3] = prior_data['vx'] state0[4] = prior_data['vy'] state0[5] = prior_data['vz'] #state0_ITRF = state0.copy() state0 = tle.ITRF_to_TEME(state0, prior_jd, 0.0, 0.0) #state0_TEME = state0.copy() #state0_ITRF_ref = tle.TEME_to_ITRF(state0_TEME, prior_jd, 0.0, 0.0) #print(state0_ITRF_ref - state0_ITRF) #exit() data_folder = root + sub_path data_h5 = glob.glob(data_folder + '*.h5') data_h5_sort = np.argsort(np.array([int(_h.split('/')[-1].split('-')[1]) for _h in data_h5])).tolist() true_prior_h5 = data_h5[data_h5_sort[0]] true_obs_h5 = data_h5[data_h5_sort[1]] print(true_prior_h5) print(true_obs_h5) with h5py.File(true_prior_h5, 'r') as hf: true_prior = hf['true_state'].value.T*1e3 true_prior_jd = dpt.unix_to_jd(hf['true_time'].value) print('-- True time diff prior [s] --') prior_match_ind = np.argmin(np.abs(true_prior_jd-prior_jd)) jd_diff = prior_jd - true_prior_jd[prior_match_ind] state0_true = true_prior[:,prior_match_ind] state0_true = tle.ITRF_to_TEME(state0_true, true_prior_jd[prior_match_ind], 0.0, 0.0) print(prior_match_ind) print(jd_diff*3600.0*24.0) with h5py.File(true_obs_h5, 'r') as hf: true_obs = hf['true_state'].value.T*1e3 true_obs_jd = dpt.unix_to_jd(hf['true_time'].value) data_tdm = glob.glob(data_folder + '*.tdm') #this next line i wtf, maybe clean up data_tdm_sort = np.argsort(np.array([int(_h.split('/')[-1].split('-')[-1][2]) for _h in data_tdm])).tolist() ccsds_files = [data_tdm[_tdm] for _tdm in data_tdm_sort] print('prior true vs prior mean') print(state0_true - state0) for _fh in ccsds_files: print(_fh) r_obs_v = [] r_sig_v = [] v_obs_v = [] v_sig_v = [] t_obs_v = [] for ccsds_file in ccsds_files: obs_data = ccsds_write.read_ccsds(ccsds_file) sort_obs = np.argsort(obs_data['date']) obs_data = obs_data[sort_obs] jd_obs = dpt.mjd_to_jd(dpt.npdt2mjd(obs_data['date'])) date_obs = obs_data['date'] sort_obs = np.argsort(date_obs) date_obs = date_obs[sort_obs] r_obs = obs_data['range'][sort_obs]*1e3 #to m v_obs = -obs_data['doppler_instantaneous'][sort_obs]*1e3 #to m/s #v_obs = obs_data['doppler_instantaneous'][sort_obs]*1e3 #to m/s r_sig = 2.0*obs_data['range_err'][sort_obs]*1e3 #to m v_sig = 2.0*obs_data['doppler_instantaneous_err'][sort_obs]*1e3 #to m/s #TRUNCATE FOR DEBUG inds = np.linspace(0,len(jd_obs)-1,num=10,dtype=np.int64) jd_obs = jd_obs[inds] r_obs = r_obs[inds] v_obs = v_obs[inds] r_sig = r_sig[inds] v_sig = v_sig[inds] if ccsds_file.split('/')[-1].split('.')[0] == true_obs_h5.split('/')[-1].split('.')[0]: print('-- True time diff obs [s] --') jd_diff = jd_obs - true_obs_jd[inds] print(jd_diff*3600.0*24.0) #r_sig = np.full(r_obs.shape, 100.0, dtype=r_obs.dtype) #v_sig = np.full(v_obs.shape, 10.0, dtype=v_obs.dtype) r_obs_v.append(r_obs) r_sig_v.append(r_sig) v_obs_v.append(v_obs) v_sig_v.append(v_sig) t_obs = (jd_obs - prior_jd)*(3600.0*24.0) #correct for light time approximently lt_correction = r_obs*0.5/scipy.constants.c t_obs -= lt_correction t_obs_v.append(t_obs) print('='*10 + 'Dates' + '='*10) print('{:<8}: {} JD'.format('Prior', prior_jd)) for ind, _jd in enumerate(jd_obs): print('Obs {:<4}: {} JD'.format(ind, _jd)) print('='*10 + 'Observations' + '='*10) print(len(jd_obs)) prior = {} prior['cov'] = np.diag([1e3, 1e3, 1e3, 1e1, 1e1, 1e1])*1.0 prior['mu'] = state0 print('='*10 + 'Prior Mean' + '='*10) print(prior['mu']) print('='*10 + 'Prior Covariance' + '='*10) print(prior['cov']) rx_ecef = [] for rx in radar._rx: rx_ecef.append(rx.ecef) tx_ecef = radar._tx[0].ecef tune = 0 trace = orbit_determination.determine_orbit( num = 2000, r = r_obs_v, sd_r = r_sig_v, v = v_obs_v, sd_v = v_sig_v, grad_dx = [10.0]*3 + [1.0]*3, rx_ecef = rx_ecef, tx_ecef = tx_ecef, t = t_obs_v, mjd0 = prior_mjd, params = params, prior = prior, propagator = prop, step = 'Metropolis', step_opts = { 'scaling': 0.75, }, pymc_opts = { 'tune': tune, 'discard_tuned_samples': True, 'cores': 1, 'chains': 1, 'parallelize': True, }, ) #if comm.rank != 0: # exit() var = ['$X$ [km]', '$Y$ [km]', '$Z$ [km]', '$V_X$ [km/s]', '$V_Y$ [km/s]', '$V_Z$ [km/s]'] fig = plt.figure(figsize=(15,15)) for ind in range(6): ax = fig.add_subplot(231+ind) ax.plot(trace['state'][:,ind]*1e-3) ax.set( xlabel='Iteration', ylabel='{}'.format(var[ind]), ) state1 = np.mean(trace['state'], axis=0) print('='*10 + 'Trace summary' + '='*10) print(pm.summary(trace)) _form = '{:<10}: {}' print('='*10 + 'Prior Mean' + '='*10) for ind in range(6): print(_form.format(var[ind], state0[ind]*1e-3)) print('='*10 + 'Posterior state mean' + '='*10) for ind in range(6): print(_form.format(var[ind], state1[ind]*1e-3)) stated = state1 - state0 print('='*10 + 'State shift' + '='*10) for ind in range(6): print(_form.format(var[ind], stated[ind]*1e-3)) print('='*10 + 'True posterior' + '='*10) for ind in range(6): print(_form.format(var[ind], state0_true[ind]*1e-3)) print('='*10 + 'Posterior error' + '='*10) for ind in range(6): print(_form.format(var[ind],(state1[ind] - state0_true[ind])*1e-3)) print('='*10 + 'Parameter shift' + '='*10) theta0 = {} theta1 = {} for key, val in params.items(): if val['dist'] is not None: theta0[key] = val['mu'] theta1[key] = np.mean(trace[key], axis=0)[0] print('{}: {}'.format(key, theta1[key] - theta0[key])) else: theta0[key] = val['val'] theta1[key] = val['val'] range_v_prior = [] vel_v_prior = [] range_v = [] vel_v = [] range_v_true = [] vel_v_true = [] for rxi in range(len(rx_ecef)): t_obs = t_obs_v[rxi] print('Generating tracklet simulated data RX {}: {} points'.format(rxi, len(t_obs))) states0 = orbit_determination.propagate_state(state0, t_obs, dpt.jd_to_mjd(prior_jd), prop, theta0) states1 = orbit_determination.propagate_state(state1, t_obs, dpt.jd_to_mjd(prior_jd), prop, theta1) states0_true = orbit_determination.propagate_state(state0_true, t_obs, dpt.jd_to_mjd(prior_jd), prop, theta1) range_v_prior += [np.empty((len(t_obs), ), dtype=np.float64)] vel_v_prior += [np.empty((len(t_obs), ), dtype=np.float64)] range_v += [np.empty((len(t_obs), ), dtype=np.float64)] vel_v += [np.empty((len(t_obs), ), dtype=np.float64)] range_v_true += [np.empty((len(t_obs), ), dtype=np.float64)] vel_v_true += [np.empty((len(t_obs), ), dtype=np.float64)] for ind in range(len(t_obs)): range_v_prior[rxi][ind], vel_v_prior[rxi][ind] = orbit_determination.generate_measurements(states0[:,ind], rx_ecef[rxi], tx_ecef) range_v[rxi][ind], vel_v[rxi][ind] = orbit_determination.generate_measurements(states1[:,ind], rx_ecef[rxi], tx_ecef) range_v_true[rxi][ind], vel_v_true[rxi][ind] = orbit_determination.generate_measurements(states0_true[:, ind], rx_ecef[rxi], tx_ecef) prop_states = orbit_determination.propagate_state( state0, np.linspace(0, (np.max(jd_obs) - prior_jd)*(3600.0*24.0), num=1000), dpt.jd_to_mjd(prior_jd), prop, theta1, ) ''' pop = gen_pop() obj = pop.get_object(0) t_obs_pop = t_obs + (dpt.jd_to_mjd(prior_jd) - obj.mjd0)*3600.0*24.0 states0_true2 = obj.get_state(t_obs_pop) print(states0_true2) print(states0_true2 - states0_true) ''' fig = plt.figure(figsize=(15,15)) ax = fig.add_subplot(111, projection='3d') plothelp.draw_earth_grid(ax) for ind, ecef in enumerate(rx_ecef): if ind == 0: ax.plot([ecef[0]], [ecef[1]], [ecef[2]], 'or', label='EISCAT 3D RX') else: ax.plot([ecef[0]], [ecef[1]], [ecef[2]], 'or') ax.plot(states0[0,:], states0[1,:], states0[2,:], 'xb', label = 'Prior', alpha = 0.75) ax.plot(states1[0,:], states1[1,:], states1[2,:], 'xr', label = 'Posterior', alpha = 0.75) ax.plot(prop_states[0,:], prop_states[1,:], prop_states[2,:], '-k', label = 'Prior-propagation', alpha = 0.5) ax.plot(true_prior[0,:], true_prior[1,:], true_prior[2,:], '-b', label = 'Prior-True', alpha = 0.75) ax.plot(true_obs[0,:], true_obs[1,:], true_obs[2,:], '-r', label = 'Posterior-True', alpha = 0.75) ax.legend() for rxi in range(len(rx_ecef)): fig = plt.figure(figsize=(15,15)) t_obs_h = t_obs_v[rxi]/3600.0 ax = fig.add_subplot(221) lns = [] line1 = ax.plot(t_obs_h, (r_obs_v[rxi] - range_v[rxi])*1e-3, '-b', label='Maximum a posteriori: RX{}'.format(rxi)) line0 = ax.plot(t_obs_h, (r_obs_v[rxi] - range_v_true[rxi])*1e-3, '.b', label='True prior: RX{}'.format(rxi)) ax.set( xlabel='Time [h]', ylabel='2-way-Range residuals [km]', ) ax2 = ax.twinx() line2 = ax2.plot(t_obs_h, (r_obs_v[rxi] - range_v_prior[rxi])*1e-3, '-k', label='Maximum a priori: RX{}'.format(rxi)) ax.tick_params(axis='y', labelcolor='b') ax2.tick_params(axis='y', labelcolor='k') lns += line0+line1+line2 labs = [l.get_label() for l in lns] ax.legend(lns, labs, loc=0) ax = fig.add_subplot(222) lns = [] line1 = ax.plot(t_obs_h, (v_obs_v[rxi] - vel_v[rxi])*1e-3, '-b', label='Maximum a posteriori: RX{}'.format(rxi)) line0 = ax.plot(t_obs_h, (v_obs_v[rxi] - vel_v_true[rxi])*1e-3, '.b', label='True prior: RX{}'.format(rxi)) ax.set( xlabel='Time [h]', ylabel='2-way-Velocity residuals [km/s]', ) ax2 = ax.twinx() line2 = ax2.plot(t_obs_h, (v_obs_v[rxi] - vel_v_prior[rxi])*1e-3, '-k', label='Maximum a priori: RX{}'.format(rxi)) ax.tick_params(axis='y', labelcolor='b') ax2.tick_params(axis='y', labelcolor='k') lns += line0+line1+line2 labs = [l.get_label() for l in lns] ax.legend(lns, labs, loc=0) ax = fig.add_subplot(223) ax.errorbar(t_obs_h, r_obs_v[rxi]*1e-3, yerr=r_sig_v[rxi]*1e-3, label='Measurements: RX{}'.format(rxi)) ax.plot(t_obs_h, range_v[rxi]*1e-3, label='Maximum a posteriori: RX{}'.format(rxi)) ax.plot(t_obs_h, range_v_prior[rxi]*1e-3, label='Maximum a priori: RX{}'.format(rxi)) ax.set( xlabel='Time [h]', ylabel='2-way-Range [km]', ) ax.legend() ax = fig.add_subplot(224) ax.errorbar(t_obs_h, v_obs_v[rxi]*1e-3, yerr=v_sig_v[rxi]*1e-3, label='Measurements: RX{}'.format(rxi)) ax.plot(t_obs_h, vel_v[rxi]*1e-3, label='Maximum a posteriori: RX{}'.format(rxi)) ax.plot(t_obs_h, vel_v_prior[rxi]*1e-3, label='Maximum a priori: RX{}'.format(rxi)) ax.set( xlabel='Time [h]', ylabel='2-way-Velocity [km/s]', ) ax.legend() #dpt.posterior(trace['state']*1e-3, var, show=False) plt.show()
def test_create_tracklet(self): radar = rlib.eiscat_uhf() radar.set_FOV(30.0, 25.0) #tle files for envisat in 2016-09-05 to 2016-09-07 from space-track. TLEs = [ ('1 27386U 02009A 16249.14961597 .00000004 00000-0 15306-4 0 9994', '2 27386 98.2759 299.6736 0001263 83.7600 276.3746 14.37874511760117' ), ('1 27386U 02009A 16249.42796553 .00000002 00000-0 14411-4 0 9997', '2 27386 98.2759 299.9417 0001256 82.8173 277.3156 14.37874515760157' ), ('1 27386U 02009A 16249.77590267 .00000010 00000-0 17337-4 0 9998', '2 27386 98.2757 300.2769 0001253 82.2763 277.8558 14.37874611760201' ), ('1 27386U 02009A 16250.12384028 .00000006 00000-0 15974-4 0 9995', '2 27386 98.2755 300.6121 0001252 82.5872 277.5467 14.37874615760253' ), ('1 27386U 02009A 16250.75012691 .00000017 00000-0 19645-4 0 9999', '2 27386 98.2753 301.2152 0001254 82.1013 278.0311 14.37874790760345' ), ] pop = population_library.tle_snapshot(TLEs, sgp4_propagation=True) #it seems to around 25m^2 area d = n.sqrt(25.0 * 4 / n.pi) pop.add_column('d', space_object_uses=True) pop['d'] = d ccsds_file = './data/uhf_test_data/events/2002-009A-1473150428.tdm' obs_data = ccsds_write.read_ccsds(ccsds_file) jd_obs = dpt.mjd_to_jd(dpt.npdt2mjd(obs_data['date'])) date_obs = obs_data['date'] sort_obs = n.argsort(date_obs) date_obs = date_obs[sort_obs] r_obs = obs_data['range'][sort_obs] jd_sort = jd_obs.argsort() jd_obs = jd_obs[jd_sort] jd_det = jd_obs[0] jd_pop = dpt.mjd_to_jd(pop['mjd0']) pop_id = n.argmin(n.abs(jd_pop - jd_det)) obj = pop.get_object(pop_id) print(obj) jd_obj = dpt.mjd_to_jd(obj.mjd0) print('Day difference detection - TLE: {}'.format(jd_det - jd_obj)) t_obs = (jd_obs - jd_obj) * (3600.0 * 24.0) meas, fnames, ecef_stdevs = simulate_tracklet.create_tracklet( obj, radar, t_obs, hdf5_out=True, ccsds_out=True, dname="./tests/tmp_test_data", noise=False, ) out_h5 = fnames[0] + '.h5' out_ccsds = fnames[0] + '.tdm' print('FILES: ', fnames) with h5py.File(out_h5, 'r') as h_det: assert 'm_range' in h_det assert 'm_range_rate' in h_det assert 'm_time' in h_det sim_data = ccsds_write.read_ccsds(out_ccsds) date_sim = sim_data['date'] sort_sim = n.argsort(date_sim) date_sim = date_sim[sort_sim] r_sim = sim_data['range'][sort_sim] v_sim = sim_data['doppler_instantaneous'][sort_sim] lt_correction = n.round(r_sim / scipy.constants.c * 1e6).astype( n.int64).astype('timedelta64[us]') date_sim_cor = date_sim + lt_correction t_sim = dpt.jd_to_unix(dpt.mjd_to_jd(dpt.npdt2mjd(date_sim_cor))) for ind in range(len(date_sim)): time_df = (dpt.npdt2mjd(date_sim_cor[ind]) - dpt.npdt2mjd(date_obs[ind])) * 3600.0 * 24.0 assert time_df < 0.01 assert len(r_obs) == len(r_sim) dat = { 't': t_sim, 'r': r_sim * 1e3, 'v': v_sim * 1e3, } cdat = correlator.correlate( data=dat, station=radar._rx[0], population=pop, metric=correlator.residual_distribution_metric, n_closest=1, out_file=None, verbose=False, MPI_on=False, ) self.assertLess(n.abs(cdat[0]['stat'][0]), 5.0) self.assertLess(n.abs(cdat[0]['stat'][1]), 50.0) self.assertLess(n.abs(cdat[0]['stat'][2]), 5.0) self.assertLess(n.abs(cdat[0]['stat'][3]), 50.0) nt.assert_array_less(n.abs(r_sim - r_obs), 1.0) os.remove(out_h5) print('removed "{}"'.format(out_h5)) os.remove(out_ccsds) print('removed "{}"'.format(out_ccsds)) sat_folder = os.sep.join(fnames[0].split(os.sep)[:-1]) os.rmdir(sat_folder) print('removed "{}"'.format(sat_folder))
def Microsat_R_debris(mjd, num, radii_range, mass_range, propagator, propagator_options): tle_raw = Microsat_R_debris_raw_tle tle_raw = [line.strip() for line in tle_raw.split('\n')] if len(tle_raw) % 2 != 0: raise Exception('Not even number of lines [not TLE compatible]') TLEs = zip(tle_raw[0::2], tle_raw[1::2]) M_earth = propagator_sgp4.SGP4.GM*1e9/consts.G pop = Population( name='Microsat R debris', extra_columns = ['A', 'm', 'd', 'C_D', 'C_R'], space_object_uses = [True, True, True, True, True], propagator = propagator, propagator_options = propagator_options, ) pop.allocate(len(TLEs)*num) delete_inds = [] cnt = 0 for ind in range(num): for line_id, lines in enumerate(TLEs): line1, line2 = lines sat_id = tle.tle_id(line1) jd0 = tle.tle_jd(line1) mjd0 = dpt.jd_to_mjd(jd0) state_TEME = tle.TLE_propagation_TEME(line1, line2, dpt.mjd_to_jd(mjd)) kep = dpt.cart2kep(state_TEME, m=0.0, M_cent=M_earth, radians=False) if np.any(np.isnan(kep)): delete_inds.append(cnt) continue pop.objs[cnt][1] = kep[0]*1e-3 pop.objs[cnt][2] = kep[1] pop.objs[cnt][3] = kep[2] pop.objs[cnt][4] = kep[4] pop.objs[cnt][5] = kep[3] pop.objs[cnt][6] = dpt.true2mean(kep[5], kep[1], radians=False) pop.objs[cnt][0] = float(sat_id) pop.objs[cnt][7] = mjd rho = 1.1e4 while rho > 1e4 or rho < 1e2: r = np.random.rand(1)*(radii_range[1] - radii_range[0]) + radii_range[0] A = np.pi*r**2 m = np.random.rand(1)*(mass_range[1] - mass_range[0]) + mass_range[0] vol = 4.0/3.0*np.pi*r**3 rho = m/vol pop.objs[cnt][8] = A pop.objs[cnt][9] = m pop.objs[cnt][10] = r*2.0 pop.objs[cnt][11] = 2.3 pop.objs[cnt][12] = 1.0 cnt += 1 pop.delete(delete_inds) return pop
def get_passes(o, radar, t0, t1, max_dpos=1e3, logger=None, plot=False, t_samp=None): '''Follow object and determine possible maintenance track window. I.e. get all passes of the object inside the radar system FOV. :param SpaceObject o: Space object to find passes for. :param RadarSystem radar: Radar system that defines the FOV. :param float t0: Start time for passes search in seconds relative space object epoch. :param float t1: Stop time for passes search in seconds relative space object epoch. :param float max_dpos: Maximum separation in km between orbital evaluation points. :param Logger logger: Logger object for logging the execution of the function. :param float t_samp: If not None, overrides the "max_dpos" variable and fixes a time-sampling. :return: Dictionary containing information about all passes of the space object inside the radar system FOV. :rtype: dict **Output dictionary:** * t: Three layers of lists where first layer is a list corresponding to every RX antenna of the radar system. Second layer is the a entry in the list for every pass. Last layer of lists is a list of two elements where the first is the time in seconds when object enters the FOV and second is the time in seconds when the object leaves the FOV. I.e. :code:`pass_start_time = passes["t"][tx_index][pass_index][0]` and :code:`pass_end_time = passes["t"][tx_index][pass_index][1]`. * snr: This structure has the same format as the "t" item but with an extra layer of lists of receivers before the bottom. Then instead of the bottom layer of lists being start and stop times it records the peak SNR at the first item and the time of that peak SNR in the second item. I.e. :code:`pass_peak_snr = passes["snr"][tx_index][pass_index][rx_index][0]` and :code:`pass_peak_snr_time = passes["snr"][tx_index][pass_index][rx_index][1]`. ''' pass_struct = {"t": [], "snr": []} if t_samp is None: num_t = find_linspace_num(t0, t1, o.a * 1e3, o.e, max_dpos=max_dpos) t = n.linspace(t0, t1, num=num_t, dtype=n.float64) else: t = n.arange(t0, t1, t_samp, dtype=n.float64) num_t = len(t) if logger is not None: logger.debug("n_points %d %1.2f" % (num_t, max_dpos)) # time vector if logger is not None: date0_y, date0_m, date0_d = dpt.jd_to_date(dpt.mjd_to_jd(o.mjd0)) logger.debug( '--> Getting {} orbit location between: {:.5f} h and {:.5f} h relative {}-{}-{}' .format( num_t, t[0] / (3600), t[-1] / (3600), date0_y, date0_m, date0_d, )) passes, passes_id, idx_v, postx_v, posrx_v = find_pass_interval( t, o, radar, logger=logger) if logger is not None: logger.debug("passes:\n {}".format(passes)) tx_dets = 0 for idx in idx_v: if len(idx) > 0: tx_dets += 1 if tx_dets == 0: if logger is not None: logger.debug("no passes visible from any RX station") return pass_struct if logger is not None: logger.debug("--> List of passes constructed") logger.debug("{}".format(passes)) snrs = [None] * len(radar._tx) for txi, idx in enumerate(idx_v): if len(idx) > 0: snrs[txi] = [None] * len(passes[txi]) tx = radar._tx[txi] for pid, pass_ids in enumerate(passes_id[txi]): idx_p = idx[pass_ids[0]:pass_ids[1]] if logger is not None: logger.debug("{}".format(idx_p)) logger.debug("{}".format(pass_ids)) snrs[txi][pid] = [None] * len(radar._rx) rx_dets = 0 for rxi, rx in enumerate(radar._rx): snr_curve = [] for I in idx_p: tx_dist = n.linalg.norm(postx_v[txi][:, I]) k0 = coord.ecef2local( lat=tx.lat, lon=tx.lon, alt=tx.alt, x=postx_v[txi][0, I], y=postx_v[txi][1, I], z=postx_v[txi][2, I], ) tx.beam.point_k0(k0) gain_tx = tx.beam.gain(k0) rx_dist = n.linalg.norm(posrx_v[rxi][:, I]) # point towards object k0 = coord.ecef2local( lat=rx.lat, lon=rx.lon, alt=rx.alt, x=posrx_v[txi][0, I], y=posrx_v[txi][1, I], z=posrx_v[txi][2, I], ) rx.beam.point_k0(k0) gain_rx = rx.beam.gain(k0) snr = debris.hard_target_enr( gain_tx, gain_rx, rx.wavelength, tx.tx_power, tx_dist, rx_dist, diameter_m=o.d, bandwidth=tx.coh_int_bandwidth, rx_noise_temp=rx.rx_noise) if logger is not None: logger.debug( '\n--> TX-d: %.2f km | TX-g: %.2f dB' % (tx_dist * 1e-3, 10.0 * n.log10(gain_tx))) logger.debug( '--> RX-d: %.2f km | RX-g: %.2f dB' % (rx_dist * 1e-3, 10.0 * n.log10(gain_rx))) logger.debug('--> SNR: %.2f dB ' % (10.0 * n.log10(snr))) snr_curve.append(snr) snr_curve = n.array(snr_curve) if plot: snr_curve_dB = 10.0 * n.log10(snr_curve) snr_curve_dB[snr_curve_dB < 0] = 0 plt.plot(t[idx_p], snr_curve_dB) plt.plot(t[idx_p[n.argmax(snr_curve)]], n.max(snr_curve_dB), 'or') plt.title("tx %i, pass %i, rx %i" % (txi, pid, rxi)) plt.show() print('SNR max: %.2f @ %.2f h' % (n.max(snr_curve_dB), t[idx_p[n.argmax(snr_curve)]] / 3600.0)) if len(snr_curve) > 0: snr_max = n.max(snr_curve) else: snr_max = 0.0 if snr_max >= tx.enr_thresh: rx_dets += 1 snrs[txi][pid][rxi] = [ snr_max, t[idx_p[n.argmax(snr_curve)]] ] else: snrs[txi][pid][rxi] = [0, 0] if rx_dets == 0: snrs[txi][pid] = None if plot: fig = plt.figure(figsize=(15, 15)) ax = fig.add_subplot(111, projection='3d') plothelp.draw_earth_grid(ax) ax.plot(ecef[0, :], ecef[1, :], ecef[2, :], alpha=1, color="black") for I in idx_p: ax.plot([tx.ecef[0], tx.ecef[0] + postx_v[txi][0, I]], [tx.ecef[1], tx.ecef[1] + postx_v[txi][1, I]], [tx.ecef[2], tx.ecef[2] + postx_v[txi][2, I]], alpha=0.5, color="red") for rxi, rx in enumerate(radar._rx): ax.plot( [rx.ecef[0], rx.ecef[0] + posrx_v[rxi][0, I]], [rx.ecef[1], rx.ecef[1] + posrx_v[rxi][1, I]], [rx.ecef[2], rx.ecef[2] + posrx_v[rxi][2, I]], alpha=0.5, color="red") delta = 1000e3 ax.set_xlim([tx.ecef[0] - delta, tx.ecef[0] + delta]) ax.set_ylim([tx.ecef[1] - delta, tx.ecef[1] + delta]) ax.set_zlim([tx.ecef[2] - delta, tx.ecef[2] + delta]) plt.show() passes[txi] = [ x for ix, x in enumerate(passes[txi]) if snrs[txi][ix] is not None ] #remove tracks that were not above detection tresholds at any pair snrs[txi] = [ x for x in snrs[txi] if x is not None ] #remove tracks that were not above detection tresholds at any pair for txi, tx_snr in enumerate(snrs): if tx_snr is None: snrs[txi] = [] for txi, tx_pass in enumerate(passes): if tx_pass is None: passes[txi] = [] pass_struct['snr'] = snrs pass_struct['t'] = passes return pass_struct