def sun_synchronous(cls, *, alt_km=None, ecc=None, inc_deg=None, ltan_h=12, date=None, ta_deg=0): """Creates Sun synchronous predictor instance. Parameters ---------- alt_km : float, optional Altitude, in km. ecc : float, optional Eccentricity. inc_deg : float, optional Inclination, in degrees. ltan_h : int, optional Local Time of the Ascending Node, in hours (default to noon). date : datetime.date, optional Reference date for the orbit, (default to today). ta_deg : float Increment or decrement of true anomaly, will adjust the epoch accordingly. Notes ----- See Vallado "Fundamentals of Astrodynamics and Applications", 4th ed (2013) section 11.4.1. """ if date is None: date = dt.datetime.today().date() try: with np.errstate(invalid="raise"): if alt_km is not None and ecc is not None: # Normal case, solve for inclination sma = R_E_KM + alt_km inc_deg = degrees( np.arccos( (-2 * sma**(7 / 2) * OMEGA * (1 - ecc**2)**2) / (3 * R_E_KM**2 * J2 * np.sqrt(MU_E)))) elif alt_km is not None and inc_deg is not None: # Not so normal case, solve for eccentricity sma = R_E_KM + alt_km ecc = np.sqrt( 1 - np.sqrt((-3 * R_E_KM**2 * J2 * np.sqrt(MU_E) * np.cos(radians(inc_deg))) / (2 * OMEGA * sma**(7 / 2)))) elif ecc is not None and inc_deg is not None: # Rare case, solve for altitude sma = (-np.cos(radians(inc_deg)) * (3 * R_E_KM**2 * J2 * np.sqrt(MU_E)) / (2 * OMEGA * (1 - ecc**2)**2))**(2 / 7) else: raise ValueError( "Exactly two of altitude, eccentricity and inclination must be given" ) except FloatingPointError as e: raise InvalidOrbitError( "Cannot find Sun-synchronous orbit with given parameters" ) from e # TODO: Allow change in time or location # Right the epoch is fixed given the LTAN, as well as the sub-satellite point epoch = dt.datetime(date.year, date.month, date.day, *float_to_hms(ltan_h)) raan = raan_from_ltan(epoch, ltan_h) return cls(sma, ecc, inc_deg, raan, 0, ta_deg, epoch)
def test_raan_from_ltan(when_utc, raan, ltan): assert pytest.approx(raan_from_ltan(when_utc, ltan), abs=1 / 3600) == raan
def sun_synchronous(cls, *, alt_km=None, ecc=None, inc_deg=None, ltan_h=12, date=None): """Creates Sun synchronous predictor instance. Parameters ---------- alt_km : float, optional Altitude, in km. ecc : float, optional Eccentricity. inc_deg : float, optional Inclination, in degrees. ltan_h : int, optional Local Time of the Ascending Node, in hours (default to noon). date : datetime.date, optional Reference date for the orbit, (default to today). """ if date is None: date = dt.datetime.today().date() # TODO: Allow change in time or location epoch = dt.datetime(date.year, date.month, date.day, *float_to_hms(ltan_h), tzinfo=dt.timezone.utc) raan = raan_from_ltan(epoch, ltan_h) try: with np.errstate(invalid="raise"): if alt_km is not None and ecc is not None: # Normal case, solve for inclination sma = R_E_KM + alt_km inc_deg = degrees( np.arccos( (-2 * sma**(7 / 2) * OMEGA * (1 - ecc**2)**2) / (3 * R_E_KM**2 * J2 * np.sqrt(MU_E)))) elif alt_km is not None and inc_deg is not None: # Not so normal case, solve for eccentricity sma = R_E_KM + alt_km ecc = np.sqrt( 1 - np.sqrt((-3 * R_E_KM**2 * J2 * np.sqrt(MU_E) * np.cos(radians(inc_deg))) / (2 * OMEGA * sma**(7 / 2)))) elif ecc is not None and inc_deg is not None: # Rare case, solve for altitude sma = (-np.cos(radians(inc_deg)) * (3 * R_E_KM**2 * J2 * np.sqrt(MU_E)) / (2 * OMEGA * (1 - ecc**2)**2))**(2 / 7) else: raise ValueError( "Exactly two of altitude, eccentricity and inclination must be given" ) except FloatingPointError: raise InvalidOrbitError( "Cannot find Sun-synchronous orbit with given parameters") return cls(sma, ecc, inc_deg, raan, 0, 0, epoch)