Пример #1
0
    def test_find_linspace_num(self):

        a = 7000e3
        e = 0.0
        T = n.pi * 2.0 * n.sqrt(a**3 / MU_earth)
        circ = n.pi * 2.0 * a

        num = simulate_tracking.find_linspace_num(t0=0.0,
                                                  t1=T,
                                                  a=a,
                                                  e=e,
                                                  max_dpos=circ / 10.0)

        self.assertEqual(num, 10)
Пример #2
0
    def setUp(self):
        self.p = PropagatorKepler(in_frame='EME', out_frame='ITRF')
        self.radar = mock_radar()
        self.big_radar = mock_radar_mult()
        self.orbit = {
            'a': 7500,
            'e': 0,
            'i': 90.0,
            'raan': 0,
            'aop': 0,
            'mu0': 0.0,
            'mjd0': 57125.7729,
            'm': 0,
        }
        self.T = n.pi * 2.0 * n.sqrt(7500e3**3 / MU_earth)

        self.o = SpaceObject(C_D=2.3,
                             A=1.0,
                             C_R=1.0,
                             oid=42,
                             d=1.0,
                             propagator=PropagatorKepler,
                             propagator_options={
                                 'in_frame': 'EME',
                                 'out_frame': 'ITRF',
                             },
                             **self.orbit)

        #from pen and paper geometry we know that for a circular orbit and the radius of the earth at pole
        #that the place where object enters FOV is
        #true = mean = arccos(R_E / semi major)
        self.rise_ang = 90.0 - n.degrees(n.arccos(wgs84_a / 7500e3))
        self.fall_ang = 180.0 - self.rise_ang

        #then we can find the time as a fraction of the orbit traversal from the angle
        self.rise_T = self.rise_ang / 360.0 * self.T
        self.fall_T = self.fall_ang / 360.0 * self.T

        self.num = simulate_tracking.find_linspace_num(t0=0.0,
                                                       t1=self.T,
                                                       a=7500e3,
                                                       e=0.0,
                                                       max_dpos=1e3)
        self.full_t = n.linspace(0, self.T, num=self.num)
Пример #3
0
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]
Пример #4
0
def get_detections(obj,
                   radar,
                   t0,
                   t1,
                   max_dpos=10.0e3,
                   logger=None,
                   pass_dt=None):
    '''Find all detections of a object by input radar between two times relative the object Epoch.

    :param SpaceObject obj: Space object to find detections of.
    :param RadarSystem radar: Radar system that scans for the object.
    :param float t0: Start time for scan relative space object epoch.
    :param float t1: End time for scan relative space object epoch.
    :param float max_dpos: Maximum separation between evaluation points in meters for finding the pass interval.
    :param Logger logger: Logger object for logging the execution of the function.
    :param float pass_dt: The time step used when evaluating pass. Default is the scan-minimum dwell time but can be forces to a setting by this variable.
    :return: Detections data structure in form of a list of dictionaries, see description below.
    :rtype: list
    
    **Return data:**
    
        List of same length as radar system TX antennas. Each entry in the list is a dictionary with the following items:

        * t0: List of pass start times. Length is equal the number of detection but unique times are equal to the number of passes..
        * t1: List of pass end times, i.e. when the space object passes below the FOV. Same list configuration as "t0"
        * snr: List of lists of SNR's for each TX-RX pair for each detection. I.e. the top list length is equal the number of detections and the elements are lists of length equal to the number of TX-RX pairs.
        * tm: List of times corresponding to each detection, same length as "snr" item.
        * range: Same structure as the "snr" item but with ranges between the TX and the RX antenna trough the object, i.e. two way range. Unit is meters.
        * range_rate: Same structure as the "range" item but with range-rates, i.e. rate of change of two way range. Unit is meters per second.
        * tx_gain: List of gains from the TX antenna for the detection, length of list is equal the number of detections.
        * rx_gain: List of lists in the same structure as the "snr" item but with receiver gains instead of signal to noise ratios.
        * on_axis_angle: List of angles between the space object and the pointing direction for each detection, length of list is equal to the number of detections.
    
    '''

    # list of transmitters
    txs = radar._tx
    # list of receivers
    rxs = radar._rx

    zenith = n.array([0, 0, 1], dtype=n.float)

    # list of detections for each transmitter-receiver pair
    # return detections, and also r, rr, tx gain, and rx gain
    detections = []
    for tx in txs:
        detections.append({
            "t0": [],
            "t1": [],
            "snr": [],
            'tm': [],
            "range": [],
            "range_rate": [],
            "tx_gain": [],
            "rx_gain": [],
            "on_axis_angle": []
        })

    num_t = simulate_tracking.find_linspace_num(t0,
                                                t1,
                                                obj.a * 1e3,
                                                obj.e,
                                                max_dpos=max_dpos)

    if logger is not None:
        logger.debug("n_points {} at {} m resolution".format(num_t, max_dpos))

    # time vector
    t = n.linspace(t0, t1, num=num_t, dtype=n.float)

    passes, passes_id, _, _, _ = simulate_tracking.find_pass_interval(
        t, obj, radar)
    for txi, pas in enumerate(passes):
        if pas is None:
            passes[txi] = []
    for txi, pas in enumerate(passes_id):
        if pas is None:
            passes_id[txi] = []

    #format: passes
    # [tx num][pass num][0 = above, 1 = below]

    if logger is not None:
        for txi in range(len(txs)):
            logger.debug('passes cnt: {}'.format(len(passes[txi])))

    for txi, tx in enumerate(txs):

        for pas in passes[txi]:

            if pass_dt is None:
                num_pass = int((pas[1] - pas[0]) / tx.scan.min_dwell_time)
            else:
                num_pass = int((pas[1] - pas[0]) / pass_dt)

            t_pass = n.linspace(pas[0], pas[1], num=num_pass, dtype=n.float)

            if logger is not None:
                logger.debug('tx{} - pass{} - num_pass: {}'.format(
                    txi, len(detections[txi]["t0"]), num_pass))

            states = obj.get_state(t_pass)

            ecef = states[:3, :]
            vels = states[3:, :]

            pos_rel_tx = (ecef.T - tx.ecef).T

            snrs = n.empty((num_pass, len(rxs)), dtype=n.float)
            angles = n.empty((num_pass, ), dtype=n.float)
            ks_obj = n.empty((3, num_pass), dtype=n.float)
            ksr_obj = n.empty((3, num_pass, len(rxs)), dtype=n.float)
            k0s = n.empty((3, num_pass), dtype=n.float)
            range_tx = n.empty((num_pass, ), dtype=n.float)
            vel_tx = n.empty((num_pass, ), dtype=n.float)
            gain_tx = n.empty((num_pass, ), dtype=n.float)
            gain_rx = n.empty((num_pass, len(rxs)), dtype=n.float)
            r_rad = n.empty((num_pass, len(rxs)), dtype=n.float)
            v_rad = n.empty((num_pass, len(rxs)), dtype=n.float)
            snrs_mask = n.full(snrs.shape, False, dtype=n.bool)
            zenith_mask = n.full(snrs.shape, False, dtype=n.bool)

            inds_mask = n.full((num_pass, ), True, dtype=n.bool)
            inds = n.arange(num_pass, dtype=n.int)

            for I in range(num_pass):
                k0 = tx.get_scan(t_pass[I]).local_pointing(t_pass[I])
                k0s[:, I] = k0

                ks_obj[:, I] = coord.ecef2local(
                    lat=tx.lat,
                    lon=tx.lon,
                    alt=tx.alt,
                    x=pos_rel_tx[0, I],
                    y=pos_rel_tx[1, I],
                    z=pos_rel_tx[2, I],
                )

                angles[I] = coord.angle_deg(k0s[:, I], ks_obj[:, I])
                if angles[I] > radar.max_on_axis:
                    inds_mask[I] = False

            inds_tmp = inds[inds_mask]

            if logger is not None:
                logger.debug('f1 inds left {}/{}'.format(
                    inds_mask.shape, inds.shape))

            for rxi, rx in enumerate(rxs):
                pos_rel_rx = (ecef.T - rx.ecef).T

                for I in inds_tmp:
                    k_obj_rx = coord.ecef2local(
                        lat=rx.lat,
                        lon=rx.lon,
                        alt=rx.alt,
                        x=pos_rel_rx[0, I],
                        y=pos_rel_rx[1, I],
                        z=pos_rel_rx[2, I],
                    )

                    ksr_obj[:, I, rxi] = k_obj_rx

                    elevation_angle_rx = 90.0 - coord.angle_deg(
                        zenith, k_obj_rx)
                    if elevation_angle_rx < rx.el_thresh:
                        continue

                    zenith_mask[I, rxi] = True

                    rx_dist = n.linalg.norm(pos_rel_rx[:, I])
                    rx_vel = n.dot(vels[:, I], pos_rel_rx[:, I] / rx_dist)

                    r_rad[I, rxi] = rx_dist
                    v_rad[I, rxi] = rx_vel

            for I in inds:
                if n.any(zenith_mask[I, :]):
                    tx.beam.point_k0(k0s[:, I])
                    range_tx[I] = n.linalg.norm(pos_rel_tx[:, I])
                    vel_tx[I] = n.dot(vels[:, I],
                                      pos_rel_tx[:, I] / range_tx[I])
                    gain_tx[I] = tx.beam.gain(ks_obj[:, I])

            for rxi, rx in enumerate(rxs):
                if logger is not None:
                    logger.debug('f2_rx{} inds left {}/{}'.format(
                        rxi, inds.shape, inds[zenith_mask[:, rxi]].shape))

                for I in inds[zenith_mask[:, rxi]]:

                    # TODO: We need to change this
                    # Probably we need to define additional parameters in the RadarSystem class that defines the constraints on each receiver transmitter, and defines if any of them are at the same location.
                    # what we need to do is give the RX a scan also that describes the pointing for detections when there is no after the fact beam-steering to do grid searches
                    #
                    if rx.phased:
                        # point receiver towards object (post event beam forming)
                        rx.beam.point_k0(ksr_obj[:, I, rxi])
                    else:
                        #point according to receive pointing
                        k0 = rx.get_scan(t_pass[I]).local_pointing(t_pass[I])
                        rx.beam.point_k0(k0)

                    gain_rx[I, rxi] = rx.beam.gain(ksr_obj[:, I, rxi])

                    snr = debris.hard_target_enr(
                        gain_tx[I],
                        gain_rx[I, rxi],
                        rx.wavelength,
                        tx.tx_power,
                        range_tx[I],
                        r_rad[I, rxi],
                        diameter_m=obj.d,
                        bandwidth=tx.coh_int_bandwidth,
                        rx_noise_temp=rx.rx_noise,
                    )

                    #if logger is not None:
                    #    logger.debug('angles[{}] {} deg, gain_tx[{}] = {}, gain_rx[{}, {}] = {}'.format(
                    #        I, angles[I],
                    #        I, gain_tx[I],
                    #        I, rxi, gain_rx[I, rxi],
                    #    ))

                    snrs[I, rxi] = snr

                    if snr < tx.enr_thresh:
                        continue

                    snrs_mask[I, rxi] = True

            for I in inds:
                if n.any(snrs_mask[I, :]):
                    inst_snrs = snrs[I, snrs_mask[I, :]]
                    if 10.0 * n.log10(n.max(inst_snrs)) > radar.min_SNRdb:
                        if logger is not None:
                            logger.debug(
                                'adding detection at {} sec with {} SNR'.
                                format(t_pass[I], snrs[I, :]))

                        detections[txi]["t0"].append(pas[0])
                        detections[txi]["t1"].append(pas[1])
                        detections[txi]["snr"].append(snrs[I, :])
                        detections[txi]["range"].append(r_rad[I, :] +
                                                        range_tx[I])
                        detections[txi]["range_rate"].append(v_rad[I, :] +
                                                             vel_tx[I])
                        detections[txi]["tx_gain"].append(gain_tx[I])
                        detections[txi]["rx_gain"].append(gain_rx[I, :])
                        detections[txi]["tm"].append(t_pass[I])
                        detections[txi]["on_axis_angle"].append(angles[I])

    return detections
Пример #5
0
def plot_scan_for_object(obj, radar, t0, t1, plot_full_scan=False):

    # list of transmitters
    txs = radar._tx
    # list of receivers
    rxs = radar._rx

    num_t = simulate_tracking.find_linspace_num(t0,
                                                t1,
                                                obj.a * 1e3,
                                                obj.e,
                                                max_dpos=10e3)

    # time vector
    t = n.linspace(t0, t1, num=num_t, dtype=n.float)

    passes, _, _, _, _ = simulate_tracking.find_pass_interval(t, obj, radar)
    #format: passes
    # [tx num][pass num][0 = above, 1 = below]

    fig = plt.figure(figsize=(15, 15))
    ax = fig.add_subplot(111, projection='3d')
    ax.grid(False)
    ax.view_init(15, 5)
    plothelp.draw_earth_grid(ax)
    plot_radar_earth(ax, radar)

    scan_range = 1200e3

    lab_done = False
    lab_done_so = False
    cycle_complete = False

    for txi, tx in enumerate(txs):

        for pas in passes[txi]:
            num_pass = int((pas[1] - pas[0]) / tx.scan.min_dwell_time)
            t_pass = n.linspace(pas[0], pas[1], num=num_pass, dtype=n.float)

            ecefs = obj.get_orbit(t_pass)

            if lab_done_so:
                ax.plot(ecefs[0, :], ecefs[1, :], ecefs[2, :], '-k')
            else:
                lab_done_so = True
                ax.plot(ecefs[0, :],
                        ecefs[1, :],
                        ecefs[2, :],
                        '-k',
                        label='Space Object')

            for I in range(num_pass):
                scan = tx.get_scan(t_pass[I])
                if scan._scan_time is not None:
                    if t_pass[I] - pas[0] > scan._scan_time:
                        cycle_complete = True

                txp0, k0 = scan.antenna_pointing(t_pass[I])

                if not plot_full_scan:
                    if cycle_complete:
                        continue

                if lab_done:
                    ax.plot(
                        [txp0[0], txp0[0] + k0[0] * scan_range],
                        [txp0[1], txp0[1] + k0[1] * scan_range],
                        [txp0[2], txp0[2] + k0[2] * scan_range],
                        '-g',
                        alpha=0.2,
                    )
                else:
                    ax.plot(
                        [txp0[0], txp0[0] + k0[0] * scan_range],
                        [txp0[1], txp0[1] + k0[1] * scan_range],
                        [txp0[2], txp0[2] + k0[2] * scan_range],
                        '-g',
                        alpha=0.01,
                        label='Scan',
                    )
                    lab_done = True

    max_range = 1500e3

    ax.set_xlim(txs[0].ecef[0] - max_range, txs[0].ecef[0] + max_range)
    ax.set_ylim(txs[0].ecef[1] - max_range, txs[0].ecef[1] + max_range)
    ax.set_zlim(txs[0].ecef[2] - max_range, txs[0].ecef[2] + max_range)
    plt.legend()
    plt.show()