def get_earth_rotation(dset): """Get corrections for satellite position and velocity by Earth rotation In a Earth-fixed reference system the Earth's rotation has to be applied, which accounts for time effect of Earth rotation during the signal propagates from the satellite to the receiver. Eq. 5.11 in :cite:`subirana2013` is used for correcting the satellite position and velocity in the Dataset field 'sat_posvel' about the Earth's rotation effect. Args: dset(Dataset): Model data Returns: tuple: with following entries =============== =============== ================================================================================== Elements Type Description =============== =============== ================================================================================== sat_pos numpy.ndarray Satellite position vector corrections in ITRS and [m] vel_pos numpy.ndarray Satellite velocity corrections in ITRS and [m/s] =============== =============== ================================================================================== """ sat_pos = np.zeros((dset.num_obs, 3)) sat_vel = np.zeros((dset.num_obs, 3)) flight_time = get_flight_time(dset) rotation_angle = flight_time * constant.omega sat_pos = ( rotation.R3(rotation_angle) @ dset.sat_posvel.trs.pos.val[:, :, None] - dset.sat_posvel.trs.pos.val[:, :, None]) sat_vel = ( rotation.R3(rotation_angle) @ dset.sat_posvel.trs.vel.val[:, :, None] - dset.sat_posvel.trs.vel.val[:, :, None]) return sat_pos[:, :, 0], sat_vel[:, :, 0]
def Q(time): """Transformation matrix for the celestial motion of the CIP The transformation matrix is described in the IERS Conventions [2], section 5.4.4. The implementation is based on section 5.6 "IAU 2006/2000A, CIO based, using X, Y series" in the SOFA Tools for Earth Attitude [1]. Args: time: A lib.time Time-object Returns: numpy.array: An array of 3x3 transformation matrices """ return rotation.R3(-E(time)) @ rotation.R2(-d(time)) @ rotation.R3(E(time)) @ rotation.R3(s(time))
def findsun(time): """Obtains the position vector of the Sun in relation to Earth (in ECEF). This routine is a reimplementation of routine findSun() in model.c of gLAB 3.0.0 software. Args: time(Time): Time object Returns: numpy.ndarray: Sun position vector given in ECEF [m] """ AU = 1.495_978_70e8 gstr, slong, sra, sdec = gsdtime_sun(time) sun_pos_x = np.cos(np.deg2rad(sdec)) * np.cos(np.deg2rad(sra)) * AU sun_pos_y = np.cos(np.deg2rad(sdec)) * np.sin(np.deg2rad(sra)) * AU sun_pos_z = np.sin(np.deg2rad(sdec)) * AU sun_pos_eci = np.vstack((sun_pos_x, sun_pos_y, sun_pos_z)).T # Rotate from inertial to non inertial system (ECI to ECEF) sun_pos_ecef = ( rotation.R3(np.deg2rad(gstr)) @ sun_pos_eci.T)[:, :, 0] # remove 1 dimension return sun_pos_ecef
def dW_dxp(time): """Derivative of transformation matrix for the polar motion with regards to the CIP (Celestial Intermediate Pole) in TRF along the Greenwich meridian x_p. This is done according to equations (2.31) in Teke :cite:`teke2011` which is the analytical partial derivative of equation (5.3) in :cite:'iers2010'. """ return rotation.R3(-s_prime(time)) @ rotation.dR2(xp(time)) @ rotation.R1(yp(time))
def dQ_dY(time): """Derivative of transformation matrix for nutation/presession with regards to the Y coordinate of CIP in GCRS """ # Rotation matrices R3_E = rotation.R3(E(time)) R3_s = rotation.R3(s(time)) R2_md = rotation.R2(-d(time)) R3_mE = rotation.R3(-E(time)) dR3_s = rotation.dR3(s(time)) dR3_E = rotation.dR3(E(time)) dR3_mE = rotation.dR3(-E(time)) dR2_md = rotation.dR2(-d(time)) return ( dR3_mE @ R2_md @ R3_E @ R3_s * (-dE_dY(time)) + R3_mE @ dR2_md @ R3_E @ R3_s * (-dd_dY(time)) + R3_mE @ R2_md @ dR3_E @ R3_s * (dE_dY(time)) + R3_mE @ R2_md @ R3_E @ dR3_s * (ds_dY(time)) )
def W(time): """Transformation matrix for the polar motion The transformation matrix is described in the IERS Conventions [2], section 5.4.1. The implementation is based on section 5.6 "IAU 2006/2000A, CIO based, using X, Y series" in the SOFA Tools for Earth Attitude [1]. Args: time: A lib.time Time-object Returns: numpy.array: An array of 3x3 transformation matrices """ return rotation.R3(-s_prime(time)) @ rotation.R2(xp(time)) @ rotation.R1(yp(time))
def _get_satellite_position_vector(self, bdict): """Determine satellite position vector in Earth centered Earth fixed (ECEF) coordinate system. Following equations are based on Table 20-IV. in :cite:`is-gps-200h`. Args: bdict (dict): Selected and prepared broadcast ephemeris dictionary with following entries =============== ====== ============================================================= Keys Unit Description =============== ====== ============================================================= a m Semimajor axis e Eccentricity of the orbit E rad Eccentric anomaly i rad Inclination lambda_ rad Instantaneous Greenwich longitude of the ascending node n rad/s Corrected mean motion r m Orbit radius tk s Eclapsed time referred to ephemeris reference epoch u rad Argument of latitude vega rad True anomaly =============== ====== ============================================================= Returns: dict: Following entries are added to broadcast ephemeris dictionary =============== ====== ================================================================================== Keys Unit Description =============== ====== ================================================================================== r_ecef m 3-dimensional numpy array with satellite position in Earth centered Earth fixed (ECEF) coordinate system r_orb m 3-dimensional numpy array with satellite position in orbital coordinate system =============== ====== ================================================================================== """ # TODO: What should be done for GEO satellites (e.g. see in gLAB function getPositionBRDC() in model.c)? # Transformation from spherical to cartesian orbital coordinate system r_orb = np.array([ bdict["r"] * np.cos(bdict["u"]), bdict["r"] * np.sin(bdict["u"]), 0.0 ]) # Transformation from cartesian orbital to Earth centered Earth fixed (ECEF) geocentric equatorial coordinate # system r_ecef = rotation.R3(-bdict["lambda_"]).dot( rotation.R1(-bdict["i"])).dot(r_orb.T) bdict.update({"r_ecef": r_ecef, "r_orb": r_orb})
def R(time): """Transformation matrix for the Earth rotation The transformation matrix is described in the IERS Conventions [2]_, section 5.4.2. The implementation is based on section 5.6 "IAU 2006/2000A, CIO based, using X, Y series" in the SOFA Tools for Earth Attitude [1]_. According to equation (5.5) in the IERS Conventions [2]_, `The CIO based transformation matrix arising from the rotation of the Earth around the axis of the CIP can be expressed as` .. math:: R(t) = R_3(-ERA) Args: time: A lib.time Time-object Returns: numpy.array: An array of 3x3 transformation matrices """ return rotation.R3(-ERA(time))
def dW_dyp(time): """Derivative of transformation matrix for the polar motion with regards to the CIP in ITRS. Analytical partial derivative of equation (5.3) in :cite:'iers2010'. """ return rotation.R3(-s_prime(time)) @ rotation.R2(xp(time)) @ rotation.dR1(yp(time))
def _keplerian_to_geocentric(self, a, e, i, Omega, omega, x_anomaly, anomaly="E"): r"""Compute orbit position and velocity vector in geocentric equatorial coordinate system based on Keplerian elements for elliptic orbits. The transformation is done either for float type or numpy array/list type input arguments. The implementation is based on Section 2.2.3 in :cite:`montenbruck2012`. Args: a (numpy.ndarray): Semimajor axis of orbit in [m] e (numpy.ndarray): Eccentricity of the orbit i (numpy.ndarray): Inclination of orbital plane in [rad] Omega (numpy.ndarray): Right ascension of ascending node in [rad] omega (numpy.ndarray): Argument of perigee in [rad] x_anomaly (numpy.ndarray): Anomaly in [rad], which can be either mean, eccentric or true anomaly in dependency of 'anomaly' argument anomaly (str): Anomaly, which can be 'M' (mean anomaly), 'E' (eccentric anomaly) or 'v' (true anomaly) Returns: tuple with numpy.ndarray types: with following elements ========== ===== ======================================================================= Element Unit Description ========== ===== ======================================================================= R m Orbit position vector in geocentric equatorial coordinate system V m Orbit velocity vector in geocentric equatorial coordinate system ========== ===== ======================================================================= """ # Determine eccentric anomaly E if anomaly == "M": # mean anomaly in [rad] E = get_eccentric_anomaly( x_anomaly, e) # TODO: get_eccentric_anomaly is not defined ... elif anomaly == "E": # eccentric anomaly in [rad] E = x_anomaly elif anomaly == "v": # true anomaly in [rad] (see Eq. 3.5 in [2]) E = 2 * np.atan( np.tan(v / 2) * np.sqrt(1 - e / (1 + e))) # TODO: v is not defined ... else: log.fatal( "Anomaly flag '{}' is wrong. It should be either 'M' (mean anomaly), 'E' (eccentric anomaly) " "or 'v' (true anomaly).", anomaly, ) num_obs = len(E) r_orb = np.zeros((num_obs, 3)) v_orb = np.zeros((num_obs, 3)) R = np.zeros((num_obs, 3)) V = np.zeros((num_obs, 3)) cosE = np.cos(E) sinE = np.sin(E) fac = np.sqrt((1 - e) * (1 + e)) r = a * (1 - e * cosE) # Distance v = np.sqrt(constant.GM * a) / r # Velocity for idx in range(0, num_obs): # Todo: Vectorize # Transformation from spherical to cartesian orbital coordinate system r_orb = np.array([[ a[idx] * (cosE[idx] - e[idx]), a[idx] * fac[idx] * sinE[idx], 0.0 ]]) v_orb = np.array( [[-v[idx] * sinE[idx], v[idx] * fac[idx] * cosE[idx], 0.0]]) # Transformation from cartesian orbital to geocentric equatorial coordinate system PQW = rotation.R3(-Omega[idx]).dot(rotation.R1(-i[idx])).dot( rotation.R3(-omega[idx])) R[idx] = (PQW.dot(r_orb.T)).T V[idx] = (PQW.dot(v_orb.T)).T return R, V