Пример #1
0
def plot_radar_earth(ax, radar):
    for tx in radar._tx:
        ecef = coord.geodetic2ecef(tx.lat, tx.lon, tx.alt)
        ax.plot([ecef[0]], [ecef[1]], [ecef[2]], "x", color='r', label=tx.name)
    for rx in radar._rx:
        ecef = coord.geodetic2ecef(rx.lat, rx.lon, rx.alt)
        ax.plot([ecef[0]], [ecef[1]], [ecef[2]], "x", color='b', label=rx.name)
Пример #2
0
    def test_ecef_geo_inverse(self):
        dec = 3
        y = n.array((90.0, 0.0, 0.0))
        x = coord.geodetic2ecef(y[0], y[1], y[2])
        y_ref = coord.ecef2geodetic(x[0], x[1], x[2])
        nt.assert_array_almost_equal(y, y_ref, decimal=dec)

        y = n.array((-90.0, 0.0, 0.0))
        x = coord.geodetic2ecef(y[0], y[1], y[2])
        y_ref = coord.ecef2geodetic(x[0], x[1], x[2])
        nt.assert_array_almost_equal(y, y_ref, decimal=dec)

        y = n.array((0.0, 0.0, 0.0))
        x = coord.geodetic2ecef(y[0], y[1], y[2])
        y_ref = coord.ecef2geodetic(x[0], x[1], x[2])
        nt.assert_array_almost_equal(y, y_ref, decimal=dec)

        y = n.array((0.0, 90.0, 0.0))
        x = coord.geodetic2ecef(y[0], y[1], y[2])
        y_ref = coord.ecef2geodetic(x[0], x[1], x[2])
        nt.assert_array_almost_equal(y, y_ref, decimal=dec)

        y = n.array((90.0, 0.0, 100.0))
        x = coord.geodetic2ecef(y[0], y[1], y[2])
        y_ref = coord.ecef2geodetic(x[0], x[1], x[2])
        nt.assert_array_almost_equal(y, y_ref, decimal=dec)
Пример #3
0
    def test_geodetic2ecef(self):
        dec = 3
        x = coord.geodetic2ecef(90.0, 0.0, 0.0)
        nt.assert_almost_equal(x[2], coord.b, decimal=dec)

        x = coord.geodetic2ecef(-90.0, 0.0, 0.0)
        nt.assert_almost_equal(x[2], -coord.b, decimal=dec)

        x = coord.geodetic2ecef(0.0, 0.0, 0.0)
        nt.assert_almost_equal(x[0], coord.a, decimal=dec)

        x = coord.geodetic2ecef(0.0, 90.0, 0.0)
        nt.assert_almost_equal(x[1], coord.a, decimal=dec)

        x = coord.geodetic2ecef(90.0, 0.0, 100.)
        nt.assert_almost_equal(x[2], coord.b + 100., decimal=dec)
Пример #4
0
    def __init__(self,
                 name,
                 lat,
                 lon,
                 alt,
                 el_thresh,
                 freq,
                 rx_noise,
                 beam,
                 scan=None,
                 phased=True):
        self.name = name
        self.lat = lat
        self.lon = lon
        self.alt = alt
        self.el_thresh = el_thresh
        self.rx_noise = rx_noise
        self.beam = beam
        self.freq = freq
        self.phased = phased
        self.wavelength = c.c / freq
        self.ecef = coord.geodetic2ecef(lat, lon, alt)

        self.scan = scan
        self.extra_scans = None
        self.scan_controler = None
Пример #5
0
    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
Пример #6
0
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)
Пример #7
0
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)
Пример #8
0
    def __init__(self,N=1000,R_e=6378e3,h_e=100e3,plot=False):
        self.N=N
        self.R_e=R_e
        # get uniformly distributed points on a sphere
        # these will act ast grid points
        points=fibonacci_sphere(samples=N)*(R_e+h_e)

        # triangulate before shifting points onto a geoid
        tri = Delaunay(points)

        # shift points to fit geoid
        if True:
            points2=n.copy(points)
            llhs=[]
            for p in range(points.shape[0]):
                if p == 0:
                    llh=[0,0,0]
                    points[p,:]=n.array([0,0,0])
                else:
                    llh=coord.ecef2geodetic(points[p,0],points[p,1],points[p,2])
                    points2[p,:]=coord.geodetic2ecef(llh[0],llh[1],h_e)
                llhs.append(llh)
            llhs=n.array(llhs)
            points=points2
        
        # triangulate the grid, so that we know
        # the neighbouring points
        # the list "tri" contains the wire mesh

        # TBD: make sure that there are no duplicated wires!
        s=n.copy(tri.simplices)

        # these are the triangles
        tris = []
        
        # these are unique current carrying elements of the mesh
        wires={}
        wire_num=0
        # these are the connections between node points, in order to allow us to regularize current continuity.
        self.connections={}
        
        for i in range(s.shape[0]):
            pidx=s[i,:]
            
            if 0 in pidx:
                pidx=n.setdiff1d(pidx,[0])
                
                tri={}
                
                tri["edges"]=[[pidx[0],pidx[1]],[pidx[0],pidx[2]],[pidx[1],pidx[2]]]

                id_pairs=[[0,1],[0,2],[1,2]]

                wire_ids=[]
                for id_pair in id_pairs:
                    
                    e0=n.min([pidx[id_pair[0]],pidx[id_pair[1]]])
                    e1=n.max([pidx[id_pair[0]],pidx[id_pair[1]]])

                    self.add_connection(e0,e1)
                    
                    wire_id = "%d-%d"%(e0,e1)
                    wire_ids.append(wire_id)
                    if wire_id not in wires.keys():
                        del_l=points[e0,:]-points[e1,:]
                        r=points[e0,:]+0.5*del_l
                        llh=coord.ecef2geodetic(r[0],r[1],r[2])
                        
                        east=coord.enu2ecef(llh[0],llh[1],0.0,1.0,0,0)
                        north=coord.enu2ecef(llh[0],llh[1],0.0,0,1.0,0)
                        
                        wires[wire_id]={"del_l":del_l,
                                        "del_e":n.dot(del_l/n.linalg.norm(del_l),east),
                                        "del_n":n.dot(del_l/n.linalg.norm(del_l),north),                                        
                                        "r":r,
                                        "llh":llh,
                                        "wire_num":wire_num,
                                        "e0":e0,
                                        "e1":e1}
                        wire_num+=1
                    else:
                        pass

                tri["wire_ids"]=wire_ids
                tris.append(tri)
            else:
                print("middle point not in tri!")

        self.llhs=llhs
        self.tris=tris
        self.points=points
        self.wires=wires
Пример #9
0
def create_theory_matrix(wg,meas,h_e=100e3,R_e=6378e3,alpha=1e-11,tik=1e-13):
    """
    Given measurements, determine the current pattern at h_e km
    """
    n_stat=len(meas["glon"])
    n_meas=3*n_stat

    n_par=len(wg.wires)
    print("n_meas %d n_par %d"%(n_meas,n_par))    
    # how many points can we regularize using current continuity
    n_cur_reg=wg.points.shape[0]-1
    n_tik=n_par
    n_reg=n_cur_reg#+n_tik
    
    # theory matrix
    A=n.zeros([n_meas+n_reg,n_par])
    # measurements
    m=n.zeros(n_meas+n_reg)
    
    wire_ids=wg.wires.keys()
    
    const=sc.mu_0/4.0/n.pi
    
    for mi in range(n_stat):
        p=coord.geodetic2ecef(meas["glat"][mi],meas["glon"][mi],0)
        # convert the n,e,u meas to ecef in Tesla                             E                N           U
        B_meas=coord.enu2ecef(meas["glat"][mi],meas["glon"][mi],0,meas["neu"][mi,1],meas["neu"][mi,0],meas["neu"][mi,2])*1e-9

        up=coord.enu2ecef(meas["glat"][mi],meas["glon"][mi],0,0,0,1)

        for li in range(n_par):
            k=wire_ids[li]
            # for each wire, get the Biot-Savart law contribution
            # is ionosphere above the horizon?
            rp = wg.wires[k]["r"]-p
            rpn=n.linalg.norm(rp)
            rp0 = rp/rpn
            zen_angle=180.0*n.arccos(n.dot(rp0,up))/n.pi
            if zen_angle < 90.0:
#                print("station lat %1.2f lon %1.2f grid lat %1.2f lon %1.2f"%(meas["glat"][mi],
 #                                                                             meas["glon"][mi],
  #                                                                            wg.wires[k]["llh"][0],
   #                                                                           wg.wires[k]["llh"][1]))
                # biot-savart law
                cp=const*n.cross(wg.wires[k]["del_l"],rp)/rpn**3.0
                wire_idx=wg.wires[k]["wire_num"]
                # x
                A[mi*3+0,wire_idx]=cp[0]
                # y
                A[mi*3+1,wire_idx]=cp[1]                
                # z
                A[mi*3+2,wire_idx]=cp[2]
                # measurement
                m[mi*3+0]=B_meas[0]
                m[mi*3+1]=B_meas[1]
                m[mi*3+2]=B_meas[2]
                
        # current continuity
        nodes=wg.connections.keys()
        for ri in range(n_cur_reg):
            e0=nodes[ri]
            conns=wg.connections[e0]
            for e1 in conns:
                wire_idx=wg.get_wire_idx(e0,e1)
                # if index is reversed, current negative
                if e1 > e0:
                    A[ri+n_stat*3,wire_idx]=alpha
                else:
                    A[ri+n_stat*3,wire_idx]=-alpha
                    
#        for ri in range(n_tik):
 #           A[ri+n_stat*3+n_cur_reg,ri]=tik

    return(A,m)
    print("n_meas %d n_reg %d n_par %d"%(n_meas,n_reg,n_par))
Пример #10
0
def create_theory_matrix(meas,
                         h_e=100e3,
                         R_e=6378e3,
                         min_lat=60,
                         max_lat=80,
                         min_lon=3,
                         max_lon=30,
                         n_lat_wires=40,
                         n_seg=50):
    """
    Given measurements, determine the current pattern at h_e km
    """
    lats = n.linspace(min_lat, max_lat, num=n_lat_wires + 1)
    lons_seg = n.linspace(min_lon, max_lon, num=n_seg + 1)

    wlens = n.zeros([n_lat_wires, n_seg])
    rl = []
    dls = []
    dAs = []
    for wi in range(n_lat_wires):
        r = []
        dl = []
        dA = []
        for si in range(n_seg):

            l0 = coord.geodetic2ecef(lats[wi], lons_seg[si], h_e)
            l0u = coord.geodetic2ecef(lats[wi + 1], lons_seg[si], h_e)

            l1 = coord.geodetic2ecef(lats[wi], lons_seg[si + 1], h_e)
            l1u = coord.geodetic2ecef(lats[wi + 1], lons_seg[si + 1], h_e)

            # area in this pixel
            A = n.linalg.norm(l0u - l0) * n.linalg.norm(l1u - l1)

            del_l = (l1 - l0)
            # unit vector
            del_l = del_l / n.linalg.norm(del_l)

            dl.append(del_l)
            r.append(0.5 * (l0 + l1))
            dA.append(A)

        rl.append(r)
        dls.append(dl)
        dAs.append(dA)
    lats = lats[0:(len(lats) - 1)]
    n_stat = len(meas["glon"])
    n_meas = 3 * n_stat

    n_par = n_lat_wires
    print("n_meas %d n_par %d" % (n_meas, n_par))

    # theory matrix
    #    A=n.zeros([n_meas,n_par])
    # measurements
    #   m=n.zeros(n_meas)

    const = sc.mu_0 / 4.0 / n.pi
    A = {}
    for mi in range(n_stat):
        p = coord.geodetic2ecef(meas["glat"][mi], meas["glon"][mi], 0)

        up = coord.enu2ecef(meas["glat"][mi], meas["glon"][mi], 0, 0, 0, 1)
        Ax = n.zeros(n_lat_wires)
        Ay = n.zeros(n_lat_wires)
        Az = n.zeros(n_lat_wires)
        for li in range(n_lat_wires):
            for si in range(n_seg):
                # for each wire segment, get the Biot-Savart law contribution
                # is ionosphere above the horizon?
                rp = rl[li][si] - p
                rpn = n.linalg.norm(rp)
                rp0 = rp / rpn
                zen_angle = 180.0 * n.arccos(n.dot(rp0, up)) / n.pi
                if zen_angle < 85.0:

                    print(
                        "station %s lat %1.2f lon %1.2f grid lat %1.2f lon %1.2f"
                        % (meas["stat"][mi], meas["glat"][mi],
                           meas["glon"][mi], lats[li], lons_seg[si]))
                    # biot-savart law (current density per unit surface area)
                    cp = dAs[li][si] * const * n.cross(dls[li][si],
                                                       rp) / rpn**3.0
                    # x
                    Ax[li] += cp[0]
                    # y
                    Ay[li] += cp[1]
                    # z
                    Az[li] += cp[2]
        if n.sum(Ax) != 0:
            stat = meas["stat"][mi]
            A[stat] = {"x": Ax, "y": Ay, "z": Az}
    n_stations = len(A.keys())
    print("n_stat %d" % (n_stations))
    return (A, lats, lons_seg)
Пример #11
0
def draw_radar(ax, lat, lon, name="radar", color="black"):
    n_earth = 1000
    earth = coord.geodetic2ecef(lat, lon, 0.0)
    #    print(earth)
    ax.plot([earth[0]], [earth[1]], [earth[2]], "x", color=color, label=name)
Пример #12
0
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)