def test_planar2(): el_phase = 30.0 az_phase = 40.0 B = n.zeros([500, 500]) els = n.linspace(0, 90, num=500) azs = n.linspace(0, 360, num=500) bp = alib.planar_beam(az_phase, el_phase, 60, 19, az1=0.0, el1=90.0, a0=16.0, I_0=10**4.3, f=230e6) for ei, e in enumerate(els): for ai, a in enumerate(azs): k = coord.azel_ecef(60.0, 19.0, 0.0, a, e) B[ei, ai] = bp.gain(k) dB = 10.0 * n.log10(B) m = n.max(dB) plt.pcolormesh(azs, els, 10.0 * n.log10(B), vmin=m - 20.0, vmax=m) plt.axhline(el_phase) plt.axvline(az_phase) plt.colorbar() plt.show()
def plot_gain(beam, res=1000, min_el=0.0): '''Plot the gain of a beam patterns as a function of elevation at :math:`0^\circ` degrees azimuth. :param BeamPattern beam: Beam pattern to plot. :param int res: Number of points to devide the set elevation range into. :param float min_el: Minimum elevation in degrees, elevation range is from this number to :math:`90^\circ`. ''' #turn on TeX interperter plt.rc('text', usetex=True) fig = plt.figure(figsize=(15, 7)) ax = fig.add_subplot(111) theta = n.linspace(min_el, 90.0, num=res) S = n.zeros((res, )) for i, th in enumerate(theta): k = coord.azel_ecef(beam.lat, beam.lon, 0.0, 0, th) S[i] = beam.gain(k) ax.plot(theta, n.log10(S) * 10.0) bottom, top = plt.ylim() plt.ylim((0, top)) ax.set_xlabel('Elevation [deg]', fontsize=24) ax.set_ylabel('Gain $G$ [dB]', fontsize=24) plt.xticks(fontsize=17) plt.yticks(fontsize=17) ax.set_title('Gain pattern ' + beam.beam_name,\ fontsize=28) plt.show()
def test_planar4(): bp = alib.planar_beam(0.0, 45.0, 60, 10, az1=0.0, el1=90.0, a0=40.0, I_0=10**4.3, f=230e6) for phased_el in n.linspace(3, 90, num=10): bp.point(0.0, phased_el) gains = [] els = n.linspace(0.0, 90.0, num=1000) for ei, e in enumerate(els): k = coord.azel_ecef(60.0, 10.0, 0.0, 0.0, e) g = bp.gain(k) gains.append(g) gains = n.array(gains) plt.plot(els, 10.0 * n.log10(gains), label="el=%1.2f" % (phased_el)) plt.ylim([0, 50]) plt.axvline(phased_el, color="black") plt.legend() plt.xlabel("Elevation angle (deg)") plt.ylabel("Gain (dB)") plt.title("Planar array gain as a function of pointing direction") plt.show()
def plot_beams(): min_el = 80.0 bp = alib.airy_beam(90.0, 90, 60, 19, f=930e6, I_0=10**4.3, a=16.0) gains = [] els = n.linspace(min_el, 90.0, num=1000) for a in els: k = coord.azel_ecef(60.0, 19.0, 0.0, 90, a) gains.append(bp.gain(k)) gains = n.array(gains) plt.plot(els, 10.0 * n.log10(gains), label="airy") bp = alib.cassegrain_beam(90.0, 90, 60, 19, f=930e6, I_0=10**4.3, a0=16.0, a1=4.58) gains = [] for a in els: k = coord.azel_ecef(60.0, 19.0, 0.0, 90, a) gains.append(bp.gain(k)) gains = n.array(gains) plt.plot(els, 10.0 * n.log10(gains), label="cassegrain") bp = alib.planar_beam(0, 90.0, 60, 19, I_0=10**4.3, f=233e6, a0=40.0, az1=0, el1=90.0) gains = [] for a in els: k = coord.azel_ecef(60.0, 19.0, 0.0, 90, a) gains.append(bp.gain(k)) gains = n.array(gains) plt.plot(els, 10.0 * n.log10(gains), label="planar") plt.ylim([0, 50]) plt.legend() plt.show()
def antenna_pointing(self, t): '''Returns the instantaneous WGS84 ECEF pointing direction and the radar geographical location in WGS84 ECEF coordinates. :param float t: Seconds past a reference epoch to retrieve the pointing at. ''' p0 = coord.geodetic2ecef(self._lat, self._lon, self._alt) point = self._pointing(t) if self._pointing_coord == 'ned': k0 = coord.ned2ecef(self._lat, self._lon, self._alt, point[0], point[1], point[2]) elif self._pointing_coord == 'enu': k0 = coord.enu2ecef(self._lat, self._lon, self._alt, point[0], point[1], point[2]) elif self._pointing_coord == 'azel': k0 = coord.azel_ecef(self._lat, self._lon, self._alt, point[0], point[1]) return p0, k0
def get_angles(passes, o, radar, dt=0.1): '''Takes the passes structure that is output from :func:`simulate_tracking.get_passes`, the space object and the radar system and calculates the zenith angle for all passes. :param dict passes: Output from :func:`simulate_tracking.get_passes` that contains information about passes of an space object. :param SpaceObject o: Space object that made the passes. :param RadarSystem radar: Radar system that defines the FOV. :param float dt: Time step for angle evaluation. :return: Tuple of list of lists of times and list of lists of angles corresponding to each pass. ''' zenith_v = [] tx_ecef = [] rx_ecef = [] for tx in radar._tx: tx_ecef.append(tx.ecef) zenith_v.append(coord.azel_ecef(tx.lat, tx.lon, 0.0, 0.0, 90.0)) angs = [] ts = [] for txi, txp in enumerate(passes['t']): angs.append([]) ts.append([]) zenith = zenith_v[txi] txp0 = tx_ecef[txi] for ps in txp: t = n.arange(ps[0], ps[1], dt) ecef = o.get_orbit(t) pos_vecs = (ecef.T - txp0).T pos_vecs0 = pos_vecs / n.sqrt(pos_vecs[0, :]**2.0 + pos_vecs[1, :]**2.0 + pos_vecs[2, :]**2.0) z_angles = 180.0 * n.arccos(pos_vecs0[0, :] * zenith[0] + pos_vecs0[1, :] * zenith[1] + pos_vecs0[2, :] * zenith[2]) / n.pi angs[-1].append(z_angles) ts[-1].append(t) return ts, angs
def test_planar3(): S = n.zeros([100, 200]) el_phase = 90.0 bp = alib.planar_beam(0, el_phase, 60, 19.0, az1=0.0, el1=el_phase, a0=16.0, I_0=10**4.3, f=230e6) els = n.linspace(0, 90, num=100) azs = n.linspace(0, 360, num=200) for ei, e in enumerate(n.linspace(0, 90, num=100)): for ai, a in enumerate(n.linspace(0, 360, num=200)): k = coord.azel_ecef(60.0, 19.0, 0.0, a, e) S[ei, ai] = bp.gain(k) plt.pcolormesh(azs, els, 10.0 * n.log10(S), vmin=0, vmax=100) plt.axvline(el_phase) plt.colorbar() plt.show()
def ray_trace(dn=datetime(2016, 6, 21, 12, 00), f=233e6, lat=e3d._tx[0].lat, lon=e3d._tx[0].lon, elevation=30.0, az=180.0, fpref="", plot=False): np = 1000 alts = n.linspace(0, 4000, num=np) distance = n.linspace(0, 4000, num=np) ne = n.zeros(np) ne2 = n.zeros(np) dnex = n.zeros(np) dtheta = n.zeros(np) dalt = n.zeros(np) dney = n.zeros(np) dnez = n.zeros(np) xyz_prev = 0.0 px = n.zeros(np) dk = n.zeros(np) py = n.zeros(np) pz = n.zeros(np) p0x = n.zeros(np) p0y = n.zeros(np) p0z = n.zeros(np) # initial direction and position k = coord.azel_ecef(lat, lon, 10e3, az, elevation) k0 = k p = coord.geodetic2ecef(lat, lon, 10e3) pe = coord.geodetic2ecef(lat, lon, 10e3) p0 = coord.geodetic2ecef(lat, lon, 10e3) dh = 4e3 vg = 1.0 p_orig = p ray_time = 0.0 for ai, a in enumerate(alts): p = p + k * dh * vg p0 = p0 + k0 * dh ray_time += dh / c.c dpx = p + n.array([1.0, 0.0, 0.0]) * dh dpy = p + n.array([0.0, 1.0, 0.0]) * dh dpz = p + n.array([0.0, 0.0, 1.0]) * dh llh = coord.ecef2geodetic(p[0], p[1], p[2]) llh_1 = coord.ecef2geodetic(p0[0], p0[1], p0[2]) dalt[ai] = llh_1[2] - llh[2] if llh[2] / 1e3 > 1900: break alts[ai] = llh[2] / 1e3 pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * 1e6 f_p = 8.98 * n.sqrt(ne[ai]) v_g = n.sqrt(1.0 - (f_p / f)**2.0) else: ne[ai] = 0.0 llh = coord.ecef2geodetic(dpx[0], dpx[1], dpx[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnex[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dnex[ai] = 0.0 llh = coord.ecef2geodetic(dpy[0], dpy[1], dpy[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dney[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dney[ai] = 0.0 llh = coord.ecef2geodetic(dpz[0], dpz[1], dpz[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnez[ai] = (ne[ai] - pt.ne * 1e6) / dh else: dnez[ai] = 0.0 grad = n.array([dnex[ai], dney[ai], dnez[ai]]) px[ai] = p[0] py[ai] = p[1] pz[ai] = p[2] p0x[ai] = p0[0] p0y[ai] = p0[1] p0z[ai] = p0[2] # print(ai) dk[ai] = n.arccos( n.dot(k0, k) / (n.sqrt(n.dot(k0, k0)) * n.sqrt(n.dot(k, k)))) # no bending if gradient too small if n.dot(grad, grad) > 100.0: grad1 = grad / n.sqrt(n.dot(grad, grad)) p2 = p + k * dh llh = coord.ecef2geodetic(p2[0], p2[1], p2[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne2 = pt.ne * 1e6 else: ne2 = 0.0 f0 = 8.98 * n.sqrt(ne[ai]) n0 = n.sqrt(1.0 - (f0 / f)**2.0) f1 = 8.98 * n.sqrt(ne2) n1 = n.sqrt(1.0 - (f1 / f)**2.0) theta0 = n.arccos( n.dot(grad, k) / (n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k)))) # angle cannot be over 90 if theta0 > n.pi / 2.0: theta0 = n.pi - theta0 sin_theta_1 = (n0 / n1) * n.sin(theta0) dtheta[ai] = 180.0 * n.arcsin( sin_theta_1) / n.pi - 180.0 * theta0 / n.pi # print("n0/n1 %1.10f theta0 %1.2f theta1-theta0 %1.10f"%(n0/n1,180.0*theta0/n.pi,dtheta[ai])) cos_theta_1 = n.sqrt(1.0 - sin_theta_1**2.0) k_ref = (n0 / n1) * k + ( (n0 / n1) * n.cos(theta0) - cos_theta_1) * grad1 # normalize k_ref / n.sqrt(n.dot(k_ref, k_ref)) k = k_ref angle = n.arccos( n.dot(grad, k) / n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k))) los_time = n.sqrt(n.dot(p_orig - p, p_orig - p)) / c.c excess_ionospheric_delay = ray_time - los_time print("Excess propagation time %1.20f mus" % ((1e6 * (ray_time - los_time)))) theta = n.arccos( n.dot(k0, k) / (n.sqrt(n.dot(k0, k0)) * n.sqrt(n.dot(k, k)))) theta_p = n.arccos( n.dot(p0, p) / (n.sqrt(n.dot(p0, p0)) * n.sqrt(n.dot(p, p)))) llh0 = coord.ecef2geodetic(px[ai - 2], py[ai - 2], pz[ai - 2]) llh1 = coord.ecef2geodetic(p0x[ai - 2], p0y[ai - 2], p0z[ai - 2]) print("d_coord") print(llh0 - llh1) if plot: print(p0 - p) print(180.0 * theta_p / n.pi) fig = plt.figure(figsize=(14, 8)) plt.clf() plt.subplot(131) plt.title("Elevation=%1.0f" % (elevation)) plt.plot(n.sqrt((p0x - px)**2.0 + (p0y - py)**2.0 + (p0z - pz)**2.0), alts, label="Total error") plt.plot(dalt, alts, label="Altitude error") plt.ylim([0, 1900]) # plt.xlim([-50,800.0]) plt.grid() plt.legend() plt.xlabel("Position error (m)") plt.ylabel("Altitude km") plt.subplot(132) plt.plot(dtheta * 1e6, alts) # plt.plot(1e6*180.0*dk/n.pi,alts) plt.xlabel("Ray-bending ($\mu$deg/km)") plt.ylabel("Altitude km") plt.title("Total error=%1.2g (deg)" % (180.0 * theta_p / n.pi)) plt.ylim([0, 1900]) plt.subplot(133) plt.plot(ne, alts) plt.xlabel("$N_{\mathrm{e}}$ ($\mathrm{m}^{-3}$)") plt.ylabel("Altitude km") plt.ylim([0, 1900]) # ax.plot(px,py,pz) plt.tight_layout() plt.savefig("ref-%s-%d-%d.png" % (fpref, f / 1e6, elevation)) plt.close() return (p0, p, 180.0 * theta_p / n.pi, excess_ionospheric_delay)
def ray_trace_error(dn=datetime(2016, 6, 21, 12, 00), f=233e6, lat=e3d._tx[0].lat, lon=e3d._tx[0].lon, elevation=30.0, az=180.0, fpref="", ionosphere=False, error_std=0.05, plot=False): np = 2000 alts = n.repeat(1e99, np) distance = n.linspace(0, 4000, num=np) ne = n.zeros(np) ne2 = n.zeros(np) dtheta = n.zeros(np) dalt = n.zeros(np) dnex = n.zeros(np) dney = n.zeros(np) dnez = n.zeros(np) xyz_prev = 0.0 dk = n.zeros(np) px = n.zeros(np) py = n.zeros(np) pz = n.zeros(np) t_vec = n.zeros(np) t_i_vec = n.zeros(np) k_vecs = [] # initial direction and position k = coord.azel_ecef(lat, lon, 10e3, az, elevation) k0 = k p = coord.geodetic2ecef(lat, lon, 10e3) dh = 4e3 dt = 20e-6 # correlated errors std=1, 100 km correlation length scale_length = 40.0 ne_errors_x = n.convolve( n.repeat(1.0 / n.sqrt(scale_length), scale_length), n.random.randn(10000)) ne_errors_y = n.convolve( n.repeat(1.0 / n.sqrt(scale_length), scale_length), n.random.randn(10000)) ne_errors_z = n.convolve( n.repeat(1.0 / n.sqrt(scale_length), scale_length), n.random.randn(10000)) p_orig = p ray_time = 0.0 v_c = c.c for ai, a in enumerate(alts): # go forward in time dhp = v_c * dt p = p + k * dhp ray_time += dt print(ray_time * 1e6) t_vec[ai + 1] = dt k_vecs.append(k) dpx = p + n.array([1.0, 0.0, 0.0]) * dh dpy = p + n.array([0.0, 1.0, 0.0]) * dh dpz = p + n.array([0.0, 0.0, 1.0]) * dh llh = coord.ecef2geodetic(p[0], p[1], p[2]) if llh[2] / 1e3 > 2100: break alts[ai] = llh[2] / 1e3 pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne[ai] = pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6 if ionosphere: f0 = 8.98 * n.sqrt(ne[ai]) f_p = 8.98 * n.sqrt(ne[ai]) # update group velocity v_c = c.c * n.sqrt(1.0 - (f0 / f)**2.0) else: ne[ai] = 0.0 llh = coord.ecef2geodetic(dpx[0], dpx[1], dpx[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnex[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dnex[ai] = 0.0 llh = coord.ecef2geodetic(dpy[0], dpy[1], dpy[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dney[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dney[ai] = 0.0 llh = coord.ecef2geodetic(dpz[0], dpz[1], dpz[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: dnez[ai] = (ne[ai] - pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6) / dh else: dnez[ai] = 0.0 grad = n.array([dnex[ai], dney[ai], dnez[ai]]) px[ai] = p[0] py[ai] = p[1] pz[ai] = p[2] dk[ai] = n.arccos( n.dot(k0, k) / (n.sqrt(n.dot(k0, k0)) * n.sqrt(n.dot(k, k)))) # no bending if gradient too small if n.dot(grad, grad) > 100.0 and ionosphere: grad1 = grad / n.sqrt(n.dot(grad, grad)) p2 = p + k * dh llh = coord.ecef2geodetic(p2[0], p2[1], p2[2]) pt = Point(dn, llh[0], llh[1], llh[2] / 1e3) pt.run_iri() if pt.ne > 0.0: ne2 = pt.ne * (1.0 + error_std * ne_errors_x[ai]) * 1e6 else: ne2 = 0.0 f0 = 8.98 * n.sqrt(ne[ai]) n0 = n.sqrt(1.0 - (f0 / f)**2.0) f1 = 8.98 * n.sqrt(ne2) n1 = n.sqrt(1.0 - (f1 / f)**2.0) theta0 = n.arccos( n.dot(grad, k) / (n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k)))) # angle cannot be over 90 if theta0 > n.pi / 2.0: theta0 = n.pi - theta0 sin_theta_1 = (n0 / n1) * n.sin(theta0) dtheta[ai] = 180.0 * n.arcsin( sin_theta_1) / n.pi - 180.0 * theta0 / n.pi # print("n0/n1 %1.10f theta0 %1.2f theta1-theta0 %1.10f"%(n0/n1,180.0*theta0/n.pi,dtheta[ai])) cos_theta_1 = n.sqrt(1.0 - sin_theta_1**2.0) k_ref = (n0 / n1) * k + ( (n0 / n1) * n.cos(theta0) - cos_theta_1) * grad1 # normalize k_ref / n.sqrt(n.dot(k_ref, k_ref)) k = k_ref angle = n.arccos( n.dot(grad, k) / n.sqrt(n.dot(grad, grad)) * n.sqrt(n.dot(k, k))) return (t_vec, px, py, pz, alts, ne, k_vecs)
def rcs_psf(radar, txi, rxi, az, el, SNR, R, samp=1000, min_el=30.0, RCS_lim=10.0, hist_res=25): tx = radar._tx[txi] rx = radar._rx[rxi] G = tx.beam G.point(az, el) num = 0 it = 0 k_set = n.empty((3, ), dtype=n.float) k_all = n.empty((3, samp), dtype=n.float) sig = n.empty((samp, ), dtype=n.float) while num < samp: it += 1 k_set = draw_sph(1, min_el) k_set.shape = (k_set.size, ) k_ecef = coord.azel_ecef(G.lat, G.lon, 0.0, n.degrees(n.arctan2(k_set[1], k_set[0])), n.degrees(n.arcsin(k_set[2]))) Gc = G.gain(k_ecef) rcs = SNR * ( 4.0 * n.pi )**3 * R**4 * scipy.constants.k * rx.rx_noise * tx.coh_int_bandwidth / ( tx.tx_power * Gc**2 * tx.wavelength) if rcs < RCS_lim: print('iter {}, samp {}, rcs {} m^2 dB'.format( it, num, 10.0 * n.log10(rcs))) sig[num] = rcs k_all[0, num] = k_set[0] k_all[1, num] = k_set[1] k_all[2, num] = k_set[2] num += 1 fig = plt.figure() ax = fig.add_subplot(111) ax.hist(n.log10(sig), hist_res, density=True) n.savetxt('sig_data.txt', sig) ax.set_xlabel('$\log_{10}(RCS)$ [1]', fontsize=24) ax.set_ylabel('Probability', fontsize=24) ax.set_title( 'RCS distribution: SNR {} dB, R {} km, (az, el) = ({}, {}), samp include {} %' .format(10.0 * n.log10(SNR), R * 1e-3, az, el, float(it) / float(num) * 100.0), fontsize=20) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot(k_all[0, :], k_all[1, :], k_all[2, :], '.b') ax.set_xlabel('$k_x$ [1]', fontsize=24) ax.set_ylabel('$k_y$ [1]', fontsize=24) ax.set_aspect('equal') max_range = 1.5 ax.set_xlim(-max_range, max_range) ax.set_ylim(-max_range, max_range) ax.set_zlim(-max_range, max_range) plt.show() return sig, k_all
def get_passes_simple(o,radar,t0,t1,max_dpos=100e3,debug=False, sanity_check=False): '''Follow object and find peak SNR. Assume that this occurs for minimum zenith angle of each TX. :param SpaceObject o: The object in space to be followed. :param RadarSystem radar: The radar system used for tracking. :param float t0: Start time for tracking :param float t1: End time for tracking :param float max_dpos: Maximum separation in m between orbital evaluation points, used to calculate time-step size by approximating orbits as circles :param bool debug: Verbose output :param bool sanity_check: Even more verbose output :return: Tuple of (Peak SNR for tracking, Number of receivers that can observe, time of best detection) ''' # figure out the number of time points we need to evaluate to meet the max_dpos criteria num_t = simulate_tracking.find_linspace_num(t0, t1, o.a*1e3, o.e, max_dpos=max_dpos) # time vector t=n.linspace(t0,t1,num=num_t) dt = (t1-t0)/num_t # propagate object for all time points requested ecef=o.get_orbit(t) # zenith angles zenith = [] # tx and rx site locations in ecef tx_ecef = [] rx_ecef = [] # zenith directions for each tx and rx site zenith_tx = [] zenith_tx = [] for tx in radar._tx: tx_ecef.append( tx.ecef ) zenith_tx.append( coord.azel_ecef(tx.lat, tx.lon, 0.0, 0.0, 90.0) ) zenith_rx = [] for rx in radar._rx: rx_ecef.append( rx.ecef ) zenith_rx.append( coord.azel_ecef(rx.lat, rx.lon, 0.0, 0.0, 90.0) ) # position vectors between tx and rx pos_rx = [] for rxp0 in rx_ecef: pos_vec=(ecef.T-rxp0).T pos_rx.append(pos_vec) n_tx=len(radar._tx) n_rx=len(radar._rx) # peak snr for tx->rx combo peak_snr=n.zeros([n_tx,n_rx]) # number of receivers that can observe TX n_rx_detections=n.zeros(n_tx) # for each transmitter for txi,txp0 in enumerate(tx_ecef): # tx tx = radar._tx[txi] # zenith direction vector for this TX zenith = zenith_tx[txi] # position vector pos_tx=(ecef.T-txp0).T # unit vector for tx->target position vector pos_tx0=pos_tx/n.sqrt(pos_tx[0,:]**2.0+pos_tx[1,:]**2.0+pos_tx[2,:]**2.0) # zenith -> target angle z_angles_tx=180.0*n.arccos(pos_tx0[0,:]*zenith[0]+pos_tx0[1,:]*zenith[1]+pos_tx0[2,:]*zenith[2])/n.pi # peak elevation angle min_z=n.min(z_angles_tx) det_idx=n.argmin(z_angles_tx) if min_z < (90.0-radar._tx[txi].el_thresh): # object possibly detectable pos_vec=pos_rx[txi][:,det_idx] tx_dist=n.linalg.norm(pos_vec) # point tx antenna towards target k0 = tx.point_ecef(pos_vec) gain_tx = tx.beam.gain(k0) # for all receivers for rxi,rx in enumerate(radar._rx): # position vector pos_rx_now=pos_rx[rxi][:,det_idx] # distance rx_dist=n.linalg.norm(pos_rx_now) # unit vector pos_rx_now0=pos_rx_now/rx_dist if sanity_check: pos = radar._rx[rxi].ecef + pos_rx_now0*rx_dist print("diff %d"%(rxi)) print((ecef[:,det_idx] - pos)) zenith = zenith_rx[rxi] # rx zenith -> target angle z_angle_rx=180.0*n.arccos(pos_rx_now0[0]*zenith[0]+pos_rx_now0[1]*zenith[1]+pos_rx_now0[2]*zenith[2])/n.pi # point towards object k0 = rx.point_ecef(pos_rx_now) 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.diam, bandwidth=tx.coh_int_bandwidth, rx_noise_temp=rx.rx_noise) peak_snr[txi,rxi]=snr if snr >= tx.enr_thresh: n_rx_detections[txi]+=1.0 print("oid %d inc %1.2f diam %1.2f tx %d rx %d snr %1.2g min_range %1.2f (km) tx_dist %1.2f (km) rx_dist %1.2f (km) tx_zenith angle %1.2f rx zenith angle %1.2f"%(o.oid,o.i,o.diam,txi,rxi,snr,((1.0-o.e)*o.a)-6371.0,tx_dist/1e3,rx_dist/1e3,min_z,z_angle_rx)) else: print("oid {} not detected, SNR = {}".format(o.oid, snr)) return peak_snr, n_rx_detections, t[det_idx]
def time_compare_library_beams(): e3d = alib.e3d_array_beam(az0=0.0, el0=90.0, I_0=10**4.3) bp1 = alib.airy_beam(az0=0.0, el0=90.0, lat=60, lon=19, f=233e6, I_0=10**4.3, a=40.0) bp2 = alib.cassegrain_beam(az0=0.0, el0=90.0, lat=60, lon=19, f=233e6, I_0=10**4.3, a0=80.0, a1=80.0 / 16.0 * 2.29) bp3 = alib.planar_beam(az0=0.0, el0=90.0, lat=60, lon=19, f=233e6, I_0=10**4.3, a0=40.0, az1=0, el1=90.0) import time k = coord.azel_ecef(e3d.lat, e3d.lon, 0.0, 0, 87.0) test_n = 500 t = n.zeros((test_n, 4)) for i in range(test_n): t0 = time.clock() g = e3d.gain(k) t[i, 0] = time.clock() - t0 t0 = time.clock() g = bp1.gain(k) t[i, 1] = time.clock() - t0 t0 = time.clock() g = bp2.gain(k) t[i, 2] = time.clock() - t0 t0 = time.clock() g = bp3.gain(k) t[i, 3] = time.clock() - t0 print('Exec time %s: mean %.5f s, std %.5f s' % ( e3d.beam_name, n.mean(t[:, 0]), n.std(t[:, 0]), )) print('Exec time %s: mean %.5f s, std %.5f s' % ( bp1.beam_name, n.mean(t[:, 1]), n.std(t[:, 1]), )) print('Exec time %s: mean %.5f s, std %.5f s' % ( bp2.beam_name, n.mean(t[:, 2]), n.std(t[:, 2]), )) print('Exec time %s: mean %.5f s, std %.5f s' % ( bp3.beam_name, n.mean(t[:, 3]), n.std(t[:, 3]), )) print('Exec time %s vs %s: mean %.5f, std %.5f' % ( e3d.beam_name, bp3.beam_name, n.mean(t[:, 0]) / n.mean(t[:, 3]), n.std(t[:, 0]) / n.std(t[:, 3]), ))
def find_pass_interval(t, o, radar, logger=None): '''Find a pass inside the FOV of a radar given a series of times for a space object. :param numpy.ndarray t: Linear vector of times to use as a base to find pass in seconds relative space object epoch. :param SpaceObject o: Space object to find pass interval for. :param RadarSystem radar: Radar system that defines the FOV. :return: Tuple of (passes, passes_id, idx_v, postx_v, posrx_v), description below. **Return data:** * passes: 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. * passes_id: Same structure as the passes data but with the time indices's instead of the actual times. * idx_v: List of arrays of indices's of input time vector where the space object is inside the TX FOV, length of list is equal to the number of TX stations. * postx_v: list of arrays containing the position of the space object relative the TX stations, length of list is equal to number of TX stations and the array is the length of the input time vector. * posrx_v: list of arrays containing the position of the space object relative the RX stations, length of list is equal to number of RX stations and the array is the length of the input time vector. ''' ecef = o.get_orbit(t) dt = (n.max(t) - n.min(t)) / len(t) zenith_v = [] tx_ecef = [] rx_ecef = [] for tx in radar._tx: tx_ecef.append(tx.ecef) zenith_v.append(coord.azel_ecef(tx.lat, tx.lon, 0.0, 0.0, 90.0)) for rx in radar._rx: rx_ecef.append(rx.ecef) postx_v = [] posrx_v = [] idx_v = [] for rxp0 in rx_ecef: pos_vecs = (ecef.T - rxp0).T posrx_v.append(pos_vecs) # for each transmitter for txi, txp0 in enumerate(tx_ecef): zenith = zenith_v[txi] pos_vecs = (ecef.T - txp0).T pos_vecs0 = pos_vecs / n.sqrt(pos_vecs[0, :]**2.0 + pos_vecs[1, :]**2.0 + pos_vecs[2, :]**2.0) # elevation angle for transmitter z_angles = 180.0 * n.arccos(pos_vecs0[0, :] * zenith[0] + pos_vecs0[1, :] * zenith[1] + pos_vecs0[2, :] * zenith[2]) / n.pi # there the elevation angle is larger than elevation cutoff idx = n.where(z_angles < (90.0 - radar._tx[txi].el_thresh))[0] postx_v.append(pos_vecs) idx_v.append(idx) if logger is not None: logger.debug("txi{}: idx {} ".format(txi, len(idx))) #remove later #plt.plot(z_angles) #plt.show() #find passes #format # [tx num][pass num][0 = above, 1 = below] passes = [None] * len(radar._tx) passes_id = [None] * len(radar._tx) for txi, idx in enumerate(idx_v): if len(idx) > 0: Tv = t[idx] passes[txi] = [[Tv[0]]] passes_id[txi] = [[0]] for ti in range(len(Tv) - 1): if Tv[ti + 1] - Tv[ti] > 3 * dt: passes[txi][-1].append(Tv[ti]) passes[txi].append([Tv[ti + 1]]) passes_id[txi][-1].append(ti) passes_id[txi].append([ti + 1]) passes[txi][-1].append(Tv[-1]) passes_id[txi][-1].append(len(Tv) - 1) return passes, passes_id, idx_v, postx_v, posrx_v
def get_scan_snr(t, o, radar): '''Takes a series of times, a space object and a radar system and calculates the SNR for that space object given the scan pattern of the radar over the given times. :param numpy.ndarray t: Times in seconds relative space object epoch over witch SNR should be evaluated. :param SpaceObject o: Space object to be measured. :param RadarSystem radar: Radar system that performs the measurement. :return: List of lists of numpy.ndarray's corresponding to TX antenna index, RX antenna index and SNR-array in that order of list depth. ''' ecef = o.get_orbit(t) zenith_v = [] tx_ecef = [] rx_ecef = [] for tx in radar._tx: tx_ecef.append(tx.ecef) zenith_v.append(coord.azel_ecef(tx.lat, tx.lon, 0.0, 0.0, 90.0)) for rx in radar._rx: rx_ecef.append(rx.ecef) postx_v = [] posrx_v = [] idx_v = [] rx_dets = 0 for rxp0 in rx_ecef: pos_vecs = (ecef.T - rxp0).T posrx_v.append(pos_vecs) # for each transmitter for txi, txp0 in enumerate(tx_ecef): zenith = zenith_v[txi] pos_vecs = (ecef.T - txp0).T pos_vecs0 = pos_vecs / n.sqrt(pos_vecs[0, :]**2.0 + pos_vecs[1, :]**2.0 + pos_vecs[2, :]**2.0) postx_v.append(pos_vecs) snrs = [None] * len(radar._tx) for txi, tx in enumerate(radar._tx): snrs[txi] = [None] * len(radar._rx) for rxi, rx in enumerate(radar._rx): snr_curve = [] for I in range(len(t)): tx_dist = n.linalg.norm(postx_v[txi][:, I]) k_obj_tx = 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], ) k_obj_rx = 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], ) k0 = tx.get_scan(t[I]).local_pointing(t[I]) #get scan pointing tx.beam.point_k0(k0) gain_tx = tx.beam.gain(k_obj_tx) rx_dist = n.linalg.norm(posrx_v[rxi][:, I]) rx.beam.point_k0(k_obj_rx) gain_rx = rx.beam.gain(k_obj_rx) 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) snr_curve.append(snr) snr_curve = n.array(snr_curve) snrs[txi][rxi] = snr_curve return snrs