Beispiel #1
0
def test_sun(helper):

    with patch('beyond.dates.date.EopDb.get') as m:
        m.return_value = Eop(x=0,
                             y=0,
                             dx=0,
                             dy=0,
                             deps=0,
                             dpsi=0,
                             lod=0,
                             ut1_utc=0.2653703,
                             tai_utc=33.0)
        sun = get_body('Sun')
        sun_orb = sun.propagate(Date(2006, 4, 2))

    assert str(sun_orb.form) == 'cartesian'
    assert str(sun_orb.frame) == 'MOD'
    assert isinstance(sun_orb.propagator, SunPropagator)
    assert sun_orb.date.scale.name == "UT1"
    assert abs(32.734629699999999274950823746622 -
               sun_orb.date._offset) <= np.finfo(float).eps

    helper.assert_vector(
        sun_orb.base,
        np.array([
            146186235643.53641, 28789144480.499767, 12481136552.345926,
            -5757.901470756284, 26793.699110930935, 11616.03628136728
        ]))
Beispiel #2
0
def test_moon():
    with patch('beyond.dates.date.EopDb.get') as m:
        m.return_value = Eop(x=0,
                             y=0,
                             dx=0,
                             dy=0,
                             deps=0,
                             dpsi=0,
                             lod=0,
                             ut1_utc=-0.0889898,
                             tai_utc=28.0)
        moon = get_body('Moon')
        moon_orb = moon.propagate(Date(1994, 4, 28))

    assert str(moon_orb.form) == 'cartesian'
    assert str(moon_orb.frame) == 'EME2000'
    assert isinstance(moon_orb.propagator, MoonPropagator)
    assert moon_orb.date.scale.name == "TDB"
    assert abs(32.185528758994394138426287099719 +
               moon_orb.date._offset) <= np.finfo(float).eps
    np.testing.assert_array_equal(
        moon_orb.base,
        np.array([
            -134181155.8063418, -311598172.21627569, -126699062.57176001, 0.0,
            0.0, 0.0
        ]))
Beispiel #3
0
def loads(text):
    """Convert a string formatted along the CCSDS standard into an Orbit or
    Ephem instance.

    This function is a wrapper of :py:func:`beyond.io.ccsds.loads` and allows
    to integrate some space-command specific fields
    """

    orb = ccsds.loads(text)

    if isinstance(orb,
                  StateVector) and "ccsds_user_defined" in orb.complements:
        ud = orb.complements["ccsds_user_defined"]

        name = ud["PROPAGATOR"]
        if name == "KeplerNum":
            kwargs = {
                "step":
                timedelta(seconds=float(ud["PROPAGATOR_STEP_SECONDS"])),
                "bodies": [get_body(orb.frame.center.name)],
                "frame": orb.frame,
                "method": ud["PROPAGATOR_METHOD"],
            }
        else:
            kwargs = {}

        orb.as_orbit(get_propagator(name)(**kwargs))

    return orb
Beispiel #4
0
def test_moon(helper):
    with patch('beyond.dates.date.EopDb.get') as m:
        m.return_value = Eop(x=0,
                             y=0,
                             dx=0,
                             dy=0,
                             deps=0,
                             dpsi=0,
                             lod=0,
                             ut1_utc=-0.0889898,
                             tai_utc=28.0)
        moon = get_body('Moon')
        moon_orb = moon.propagate(Date(1994, 4, 28))

    assert str(moon_orb.form) == 'cartesian'
    assert str(moon_orb.frame) == 'EME2000'
    assert isinstance(moon_orb.propagator, MoonPropagator)
    assert moon_orb.date.scale.name == "TDB"
    assert abs(32.185528758994394138426287099719 +
               moon_orb.date._offset) <= np.finfo(float).eps
    helper.assert_vector(
        moon_orb,
        np.array([
            -134181155.8063418, -311598172.21627569, -126699062.57176001,
            976.8878152910264, -438.8323937765414, -87.42035305682552
        ]))
Beispiel #5
0
def orbit_kepler(iss_tle):

    orbit = iss_tle.orbit()

    orbit.propagator = KeplerNum(timedelta(seconds=60),
                                 bodies=get_body('Earth'))

    return orbit
Beispiel #6
0
def molniya_kepler(molniya_tle):

    molniya = molniya_tle.orbit()

    molniya.propagator = KeplerNum(timedelta(seconds=120),
                                   bodies=get_body('Earth'))

    return molniya
Beispiel #7
0
def orb():

    orb = Tle("""0 ISS (ZARYA)
1 25544U 98067A   08264.51782528 -.00002182  00000-0 -11606-4 0  2927
2 25544  51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537""").orbit()

    orb.propagator = Kepler(
        timedelta(seconds=60),
        bodies=get_body('Earth')
    )

    return orb
Beispiel #8
0
def orbit_man(orbit):
    orbit = orbit.copy()
    orbit.propagator = KeplerNum(get_body("Earth"), timedelta(seconds=60))
    orbit.maneuvers = [
        ImpulsiveMan(
            Date(2008, 9, 20, 12, 41, 9, 984493),
            [280, 0, 0],
            frame="TNW",
            comment="Maneuver 1",
        ),
        ImpulsiveMan(Date(2008, 9, 20, 13, 33, 11, 374985), [270, 0, 0],
                     frame="TNW"),
    ]
    return orbit
Beispiel #9
0
def orbit(request, iss_tle):

    orb = iss_tle.orbit()

    if request.param == "tle":
        return orb
    elif request.param == "ephem":
        start = Date(2018, 4, 5, 16, 50)
        stop = timedelta(hours=6)
        step = timedelta(seconds=15)

        return orb.ephem(start=start, stop=stop, step=step)
    elif request.param == "kepler":
        orb.propagator = KeplerNum(timedelta(seconds=60), get_body('Earth'))
        return orb
Beispiel #10
0
def test_moon():
    with patch('beyond.dates.date.EopDb.get') as m:
        m.return_value = Eop(x=0, y=0, dx=0, dy=0, deps=0, dpsi=0, lod=0, ut1_utc=-0.0889898, tai_utc=28.0)
        moon = get_body('Moon')
        moon_orb = moon.propagate(Date(1994, 4, 28))

    assert str(moon_orb.form) == 'cartesian'
    assert str(moon_orb.frame) == 'EME2000'
    assert isinstance(moon_orb.propagator, MoonPropagator)
    assert moon_orb.date.scale.name == "TDB"
    assert abs(32.185528758994394138426287099719 + moon_orb.date._offset) <= np.finfo(float).eps
    np.testing.assert_array_equal(
        moon_orb.base,
        np.array([
            -134181155.8063418, -311598172.21627569, -126699062.57176001, 0.0, 0.0, 0.0
        ])
    )
Beispiel #11
0
def test_sun():

    with patch('beyond.dates.date.EopDb.get') as m:
        m.return_value = Eop(x=0, y=0, dx=0, dy=0, deps=0, dpsi=0, lod=0, ut1_utc=0.2653703, tai_utc=33.0)
        sun = get_body('Sun')
        sun_orb = sun.propagate(Date(2006, 4, 2))

    assert str(sun_orb.form) == 'cartesian'
    assert str(sun_orb.frame) == 'MOD'
    assert isinstance(sun_orb.propagator, SunPropagator)
    assert sun_orb.date.scale.name == "UT1"
    assert abs(32.734629699999999274950823746622 - sun_orb.date._offset) <= np.finfo(float).eps

    np.testing.assert_array_equal(
        sun_orb.base,
        np.array([
            146186235643.53641, 28789144480.499767, 12481136552.345926, 0.0, 0.0, 0.0
        ])
    )
Beispiel #12
0
def orbit_continuous_man(orbit):
    orbit = orbit.copy()
    orbit.propagator = KeplerNum(get_body("Earth"), timedelta(seconds=60))
    orbit.maneuvers = [
        ContinuousMan(
            Date(2008, 9, 20, 12, 41, 9, 984493),
            timedelta(minutes=3),
            dv=[280, 0, 0],
            frame="TNW",
            comment="Maneuver 1",
        ),
        ContinuousMan(
            Date(2008, 9, 20, 13, 33, 11, 374985),
            timedelta(minutes=3),
            dv=[270, 0, 0],
            frame="TNW",
        ),
    ]
    return orbit
Beispiel #13
0
def orbit(request, common_env):

    orb = Tle("""ISS (ZARYA)
1 25544U 98067A   18124.55610684  .00001524  00000-0  30197-4 0  9997
2 25544  51.6421 236.2139 0003381  47.8509  47.6767 15.54198229111731""").orbit()

    if request.param == "tle":
        return orb
    elif request.param == "ephem":
        start = Date(2018, 4, 5, 16, 50)
        stop = timedelta(hours=6)
        step = timedelta(seconds=15)

        return orb.ephem(start=start, stop=stop, step=step)
    elif request.param == "kepler":
        orb.propagator = Kepler(
            timedelta(seconds=60),
            get_body('Earth')
        )
        return orb
Beispiel #14
0
def space_phase(*argv):
    """Compute the phase of the moon or other solar system bodies

    Usage:
        space-phase <body> [<date>] [--graph] [--frame <frame>] [-a] [--file <file>]

    Options:
        <body>            Body
        <date>            Date to compute the moon phase at [default: now]
                          (format %Y-%m-%dT%H:%M:%S)
        -g, --graph       Display the moon phase
        -a, --analytical  Use analytical model instead of JPL files
        --file <file>     File
    """
    import sys
    from .clock import Date
    from .utils import docopt, parse_date
    from .station import StationDb

    args = docopt(space_phase.__doc__)

    if args["<date>"] is None:
        args["<date>"] = "now"

    try:
        date = parse_date(args["<date>"])
    except ValueError as e:
        print(e, file=sys.stderr)
        sys.exit(1)

    StationDb.list()

    body = args["<body>"]

    if body == "Moon":
        center = "EME2000"
        second = "Sun"
    else:
        center = body
        body = "Sun"
        second = "Earth"

    if args["--analytical"] and body.lower() == "moon":
        first = solar.get_body(body).propagate(date)
        second = solar.get_body(second).propagate(first.date)
        src = "analytical"
    else:
        src = "JPL"
        if args["--analytical"]:
            log.warning(
                "No analytical model available for '{}'. Switching to JPL source"
                .format(body))
        jpl.create_frames()
        first = jpl.get_orbit(body, date)
        second = jpl.get_orbit(second, first.date)

    if body == "Moon":
        phase = compute_phase(first, second, center)
    else:
        phase = np.pi - compute_phase(first, second, center)
        body = center

    illumin = illumination(phase)

    log.debug("Computing {} phase using source '{}'".format(body, src))
    log.info("{} at {:%Y-%m-%dT%H:%M:%S} : {:0.2f}%".format(
        body, date, illumin * 100))

    if args["--graph"] or args["--file"]:
        draw_phase(date, phase, body=args["<body>"], filepath=args["--file"])
Beispiel #15
0
def space_planet(*args):
    """Compute position of a planet of the solar system and its major moons

    Usage:
        space-planet
        space-planet fetch
        space-planet <planet>... [options]

    Options:
        fetch                Retrieve .bsp file
        <planet>             Names of the planet to compute the ephemeris of. If
                             absent, list all bodies available
        -f, --frame <frame>  Frame in which to display the ephemeris to
                             [default: EME2000]
        -d, --date <date>    Start date of the ephem (%Y-%m-%d) [default: midnight]
        -r, --range <days>   Duration of extrapolation [default: 3d]
        -s, --step <step>    Step size of the ephemeris. [default: 60m]
        -a, --analytical     Force analytical model instead of .bsp files

    Example:
        space-planet Mars  # Position of Mars in EME2000
        space-planet Moon -f Phobos  # Position of the moon as seen from Phobos

    This command relies on .bsp files, parsed by the incredible jplephem lib.
    Bsp file can be retrieved at

        https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/

    Files examples:

        de432s.bsp     Moon, Sun, Mercury, Venus and main bodies barycentre
        mar097.bsp     Mars, Phobos and Deimos
        jup310.bsp     Jupiter and its major moons
        sat360xl.bsp   Saturn and its major moons

    The 'beyond.env.jpl' config variable must be set to a list of bsp files
    paths. See beyond documentation about JPL files:

        http://beyond.readthedocs.io/en/latest/api/env.html#module-beyond.env.jpl

    If no .bsp file is provided, the command falls back to analytical methods
    for Moon and Sun. Other bodies are not provided.
    """

    import requests

    from logging import getLogger

    log = getLogger(__name__)

    args = docopt(space_planet.__doc__)

    if args["fetch"]:

        folder = ws.folder / "jpl"

        if not folder.exists():
            folder.mkdir()

        naif = "https://naif.jpl.nasa.gov/pub/naif/generic_kernels/"
        baseurl = {
            "de403_2000-2020.bsp":
            naif + "spk/planets/a_old_versions/",  # Data until 2020-01-01
            "de430.bsp": naif + "spk/planets/",
            "de432s.bsp": naif + "spk/planets/",
            "de435.bsp": naif + "spk/planets/",
            "jup310.bsp": naif + "spk/satellites/",
            "sat360xl.bsp": naif + "spk/satellites/",
            "mar097.bsp": naif + "spk/satellites/",
            "pck00010.tpc": naif + "pck/",
            "gm_de431.tpc": naif + "pck/",
        }

        success = []

        filelist = ws.config.get("beyond",
                                 "env",
                                 "jpl",
                                 fallback="de403_2000-2020.bsp")
        if not isinstance(filelist, list):
            filelist = [filelist]

        for filepath in filelist:

            filepath = Path(filepath)
            if not filepath.is_absolute():
                filepath = folder / filepath

            if not filepath.exists():

                url = baseurl.get(filepath.name, "") + str(filepath.name)
                log.info("Fetching {}".format(filepath.name))
                log.debug(url)

                try:
                    r = requests.get(url, stream=True)
                except requests.exceptions.ConnectionError as e:
                    log.error(e)
                else:
                    try:
                        r.raise_for_status()
                    except requests.exceptions.HTTPError as e:
                        log.error("{} {}".format(filepath.name, e))
                    else:
                        total = int(r.headers.get("content-length", 0))
                        size = 0
                        with filepath.open("bw") as fp:
                            for chunk in r.iter_content(chunk_size=1024):
                                fp.write(chunk)
                                if total:
                                    size += len(chunk)
                                    print(
                                        "\r> {:6.2f} %   {} / {}".format(
                                            100 * size / total,
                                            humanize(size),
                                            humanize(total),
                                        ),
                                        end="",
                                    )
                        if total:
                            print("\r", " " * 40, end="\r")
                        success.append(str(filepath.absolute()))
                        log.debug("Adding {} to the list of jpl files".format(
                            filepath.name))
            else:
                success.append(str(filepath.absolute()))
                log.info("File {} already downloaded".format(filepath.name))

        # Adding the file to the list and saving the new state of configuration
        if success:
            ws.config.set("beyond", "env", "jpl", success)

        ws.config.save()

    elif args["<planet>"]:

        try:
            date = parse_date(args["--date"], fmt="date")
            stop = parse_timedelta(args["--range"])
            step = parse_timedelta(args["--step"])
        except ValueError as e:
            print(e, file=sys.stderr)
            sys.exit(1)

        if not args["--analytical"]:
            # Create all frames from .bsp files, if they are available
            try:
                jpl.create_frames()
            except jpl.JplError:
                jpl_error = True
            else:
                jpl_error = False

        # Create all frames from stations database
        StationDb.list()

        try:
            frame = get_frame(args["--frame"])
        except UnknownFrameError as e:
            print(e, file=sys.stderr)
            sys.exit(1)

        # Computation
        ephems = []

        for body_name in args["<planet>"]:
            try:
                if args["--analytical"] or jpl_error:
                    body = solar.get_body(body_name).propagate(date)
                else:
                    body = jpl.get_orbit(body_name, date)
            except UnknownBodyError as e:
                print(e, file=sys.stderr)
                sys.exit(1)

            ephem = body.ephem(start=date, stop=stop, step=step)
            ephem.frame = frame
            ephem.name = body_name
            ephems.append(ephem)
        else:
            print(ccsds.dumps(ephems))
    else:
        print("List of all available bodies")
        try:
            jpl.create_frames()
            txt = recurse(jpl.get_frame("Earth").center.node, set())
        except jpl.JplError as e:
            print(" Sun")
            print(" Moon")
        else:
            print(txt)
Beispiel #16
0
def space_passes(*argv):
    """Compute and plot passes geometry

    Usage:
      space-passes <station> (- | <satellite>...) [options]

    Option:
      -h --help          Show this help
      <station>          Location from which the satellite is tracked
      <satellite>        Satellite to track.
      -                  If used the orbit should be provided as stdin in TLE
                         or CCSDS format (see example)
      -d --date <date>   Starting date of the computation [default: now]
                         (format: "%Y-%m-%dT%H:%M:%S")
      -r --range <days>  Range of the computation [default: 1d]
      -n --no-events     Don't compute AOS, MAX and LOS
      -e --events-only   Only show AOS, MAX and LOS
      -l --light         Compute day/penumbra/umbra transitions
      -s --step <step>   Step-size [default: 30s]
      -p --passes <nb>   Number of passes to display [default: 1]
      -g --graphs        Display graphics with matplotlib
      -z --zenital       Reverse direction of azimut angle on the polar plot
                         to show as the passes as seen from the station
                         looking to the sky
      --radial           Compute radial velocity nullation point
      --csv              Print in CSV format
      --sep=<sep>        CSV separator [default: ,]

    Examples:
      Simple computation of the ISS, TLS is the name of my station

          $ space passes TLS ISS

      Hubble is not part of my satellite database, but I want to compute its
      visibility just once

          $ space tle norad 20580 | space passes TLS

    """

    args = docopt(space_passes.__doc__)

    try:
        start = parse_date(args["--date"])
        step = parse_timedelta(args["--step"])
        stop = parse_timedelta(args["--range"])
        pass_nb = int(args["--passes"])
        sats = Sat.from_command(*args["<satellite>"],
                                text=sys.stdin.read() if args["-"] else "")
    except ValueError as e:
        log.error(e)
        sys.exit(1)

    try:
        station = StationDb.get(args["<station>"])
    except UnknownFrameError:
        log.error("Unknwon station '{}'".format(args["<station>"]))
        sys.exit(1)

    events = not args["--no-events"]

    light = LightListener()

    if args["--light"] and events:
        events = [light, LightListener(LightListener.PENUMBRA)]
    if args["--radial"]:
        rad = RadialVelocityListener(station, sight=True)
        if isinstance(events, list):
            events.append(rad)
        else:
            events = rad

    # Computation of the passes
    for sat in sats:

        lats, lons = [], []
        lats_e, lons_e = [], []
        azims, elevs = [], []
        azims_e, elevs_e, text_e = [], [], []

        info_size = 0
        if args["--csv"]:
            print(args["--sep"].join([
                "date",
                "event",
                "name",
                "azimut",
                "elevation",
                "distance",
                "light",
            ]))
        else:
            info_size = len(station.name) + 10
            header = "Time                        Infos{} Sat{}     Azim    Elev  Dist (km)  Light    ".format(
                " " * (info_size - 5), " " * (len(sat.name) - 3))

            print(header)
            print("=" * len(header))

        count = 0
        dates = []
        for orb in station.visibility(sat.orb,
                                      start=start,
                                      stop=stop,
                                      step=step,
                                      events=events):

            if args["--events-only"] and orb.event is None:
                continue

            azim = -np.degrees(orb.theta) % 360
            elev = np.degrees(orb.phi)
            azims.append(azim)
            elevs.append(90 - elev)
            dates.append(orb.date)
            r = orb.r / 1000.0

            if orb.event:
                azims_e.append(azim)
                elevs_e.append(90 - elev)

            light_info = "Umbra" if light(orb) <= 0 else "Light"

            if args["--csv"]:
                fmt = [
                    "{orb.date:%Y-%m-%dT%H:%M:%S.%f}",
                    "{event}",
                    "{sat.name}",
                    "{azim:.2f}",
                    "{elev:.2f}",
                    "{r:.2f}",
                    "{light}",
                ]
                fmt = args["--sep"].join(fmt)
            else:
                fmt = "{orb.date:%Y-%m-%dT%H:%M:%S.%f}  {event:{info_size}} {sat.name}  {azim:7.2f} {elev:7.2f} {r:10.2f}  {light}"

            print(
                fmt.format(
                    orb=orb,
                    r=r,
                    azim=azim,
                    elev=elev,
                    light=light_info,
                    sat=sat,
                    event=orb.event if orb.event is not None else "",
                    info_size=info_size,
                ))

            orb_itrf = orb.copy(frame="ITRF")
            lon, lat = np.degrees(orb_itrf[1:3])
            lats.append(lat)
            lons.append(lon)

            if orb.event:
                lats_e.append(lat)
                lons_e.append(lon)
                text_e.append(orb.event.info)

            if (orb.event is not None and orb.event.info == "LOS"
                    and orb.event.elev == 0):
                print()
                count += 1
                if count == pass_nb:
                    break

        # Plotting
        if args["--graphs"] and azims:

            # Polar plot of the passes
            plt.figure(figsize=(15.2, 8.2))

            ax = plt.subplot(121, projection="polar")
            ax.set_theta_zero_location("N")

            plt.title("{} from {}".format(sat.name, station))
            if not args["--zenital"]:
                ax.set_theta_direction(-1)

            plt.plot(np.radians(azims), elevs, ".")

            for azim, elev, txt in zip(azims_e, elevs_e, text_e):
                plt.plot(np.radians(azim), elev, "ro")
                plt.text(np.radians(azim), elev, txt, color="r")

            if station.mask is not None:

                m_azims = np.arange(0, 2 * np.pi, np.pi / 180.0)
                m_elevs = [
                    90 - np.degrees(station.get_mask(azim)) for azim in m_azims
                ]

                plt.plot(-m_azims, m_elevs)

            # Add the Moon and Sun traces
            bodies = (('Sun', 'yo', None), ('Moon', 'wo', 'k'))
            bodies_ephem = {}

            for body, marker, edge in bodies:

                b_ephem = get_body(body).propagate(orb.date).ephem(dates=dates)
                bodies_ephem[body] = b_ephem
                mazim, melev = [], []
                for m in station.visibility(b_ephem):
                    mazim.append(-m.theta)
                    melev.append(90 - np.degrees(m.phi))

                plt.plot(mazim, melev, marker, mec=edge, mew=0.5)

            ax.set_yticks(range(0, 90, 20))
            ax.set_yticklabels(map(str, range(90, 0, -20)))
            ax.set_xticklabels(["N", "NE", "E", "SE", "S", "SW", "W", "NW"])
            ax.set_rmax(90)

            plt.tight_layout()

            plt.subplot(122)
            # Ground-track of the passes
            set_background()
            plt.plot(lons, lats, "b.")

            plt.plot(lons_e, lats_e, "r.")

            color = "#202020"

            # Ground Station
            sta_lat, sta_lon = np.degrees(station.latlonalt[:-1])

            # Visibility circle
            lon, lat = np.degrees(
                list(zip(*circle(orb_itrf.r, *station.latlonalt[-2::-1]))))
            lon = ((lon + 180) % 360) - 180
            plt.plot(lon, lat, ".", color=color, ms=2)

            # Mask
            if station.mask is not None:
                m_azims = np.arange(0, 2 * np.pi, np.pi / 180.0)
                m_elevs = [station.get_mask(azim) for azim in m_azims]
                mask = [m_azims, m_elevs]

                lon, lat = np.degrees(
                    list(
                        zip(*circle(
                            orb_itrf.r,
                            np.radians(sta_lon),
                            np.radians(sta_lat),
                            mask=mask,
                        ))))
                lon = ((lon + 180) % 360) - 180
                plt.plot(lon, lat, color="c", ms=2)

            # Add the moon and sun traces
            for body, marker, edge in bodies:
                b_itrf = np.asarray(bodies_ephem[body].copy(frame="ITRF",
                                                            form="spherical"))
                lon = ((np.degrees(b_itrf[:, 1]) + 180) % 360) - 180
                lat = np.degrees(b_itrf[:, 2])
                plt.plot(lon, lat, marker, mec=edge, mew=0.5)

            plt.xlim([-180, 180])
            plt.ylim([-90, 90])
            plt.grid(linestyle=":")
            plt.xticks(range(-180, 181, 30))
            plt.yticks(range(-90, 91, 30))
            plt.tight_layout()
            plt.subplots_adjust(left=0.02, right=0.98, top=0.98, bottom=0.02)

    if args["--graphs"]:
        plt.show()
Beispiel #17
0
from beyond.propagators.keplernum import KeplerNum
from beyond.env.solarsystem import get_body
from beyond.orbits.man import ImpulsiveMan
from beyond.orbits.listeners import ApsideListener, find_event

orb = Tle("""ISS (ZARYA)
1 25544U 98067A   18124.55610684  .00001524  00000-0  30197-4 0  9997
2 25544  51.6421 236.2139 0003381  47.8509  47.6767 15.54198229111731"""
          ).orbit()

start = orb.date
stop = timedelta(minutes=300)
step = timedelta(seconds=60)

# Changing the propagator to Keplerian, as SGP4 is not able to perform maneuvers
orb.propagator = KeplerNum(step, bodies=get_body("Earth"))

# Research for the next perigee
perigee = find_event(orb.iter(stop=stop, listeners=ApsideListener()),
                     'Periapsis')

man1 = ImpulsiveMan(perigee.date, (280, 0, 0), frame="TNW")
orb.maneuvers = [man1]

dates1, alt1 = [], []

# Research for the next apogee after the first maneuver
apogee = find_event(
    orb.iter(start=perigee.date - step * 10,
             stop=stop,
             listeners=ApsideListener()), 'Apoapsis')
Beispiel #18
0
from beyond.propagators.kepler import Kepler
from beyond.env.solarsystem import get_body
from beyond.orbits.man import Maneuver
from beyond.orbits.listeners import ApsideListener


orb = Tle("""ISS (ZARYA)
1 25544U 98067A   18124.55610684  .00001524  00000-0  30197-4 0  9997
2 25544  51.6421 236.2139 0003381  47.8509  47.6767 15.54198229111731""").orbit()

start = orb.date
stop = timedelta(minutes=300)
step = timedelta(seconds=60)

# Changing the propagator to Keplerian, as SGP4 is not able to perform maneuvers
orb.propagator = Kepler(step, bodies=get_body("Earth"))

# Research for the next perigee
for p in orb.iter(start=start, stop=stop, step=step, listeners=ApsideListener()):
    if p.event and p.event.info == "Periapsis":
        perigee = p
        break

man1 = Maneuver(perigee.date, (280, 0, 0), frame="TNW")
orb.maneuvers = [man1]

dates1, alt1 = [], []
# Research for the next apogee after the first maneuver
for p in orb.iter(start=perigee.date, stop=stop, step=step, listeners=ApsideListener()):
    if p.event and p.event.info == "Apoapsis":
        apogee = p
Beispiel #19
0
def _generic_cmd(ext, doc, *argv):  # pragma: no cover
    """Generic command handling
    """

    from .utils import docopt
    from .sat import Sat

    args = docopt(doc, argv=argv)

    if "compute" in args and args["compute"]:

        try:
            start = parse_date(args["--date"])
            if ext == "oem":
                stop = parse_timedelta(args["--range"])
                step = parse_timedelta(args["--step"])
            satlist = Sat.from_command(
                *args["<selector>"],
                text=sys.stdin.read() if args["-"] else "")
        except ValueError as e:
            log.error(e)
            sys.exit(1)

        orbs = []
        txt = ""
        for sat in satlist:
            if ext == "oem":
                ephem = sat.orb.ephem(start=start, stop=stop, step=step)
                ephem.name = sat.name
                ephem.cospar_id = sat.cospar_id
                ephem.method = args["--interp"]
                if args["--frame"] is not None:
                    ephem.frame = StationDb.get(args["--frame"])

                orbs.append(ephem)
            else:
                orb = sat.orb.propagate(start)
                orb.name = sat.name
                orb.cospar_id = sat.cospar_id
                if args["--frame"] is not None:
                    orb.frame = StationDb.get(args["--frame"])
                if args["--propagator"]:
                    propagator_cls = get_propagator(args["--propagator"])
                    if issubclass(propagator_cls, get_propagator("KeplerNum")):
                        orb.propagator = propagator_cls(
                            parse_timedelta(args["--step"]),
                            get_body(args["--body"]))
                    else:
                        orb.propagator = propagator_cls()

                txt = dumps(orb,
                            originator=config.get("center",
                                                  "name",
                                                  fallback="N/A"))

        if ext == "oem":
            txt = dumps(orbs,
                        originator=config.get("center", "name",
                                              fallback="N/A"))

        if not args["--insert"]:
            print(txt)

    if args["insert"] or ("compute" in args and args["compute"]
                          and args["--insert"]):

        if args["--insert"]:
            pass
        elif args["-"] and not sys.stdin.isatty():
            txt = sys.stdin.read()
        else:
            txt = open(args["<file>"]).read()

        try:
            sats = Sat.from_command(text=txt, create=True)
        except ValueError as e:
            log.error(e)
            sys.exit(1)

        for sat in sats:
            try:
                CcsdsDb.insert(sat, args["--force"])
            except FileExistsError as e:
                continue
    elif args["list"]:

        max_idx = int(args["--last"])

        try:
            for sat in Sat.from_selectors(*args["<selector>"],
                                          src=ext,
                                          orb=False):

                print(sat.name.center(65))

                rtags = CcsdsDb.rtags(sat, ext)
                if rtags:
                    tagw = len(max(rtags.values(), key=len))
                else:
                    tagw = 4

                if ext == "oem":
                    print(
                        "idx  Tag{}  Frame     Start                Stop                 Steps"
                        .format(" " * (tagw - 3)))
                    print("-" * (65 + tagw))
                else:
                    print(
                        "idx  Tag{}  Frame     Date                 Propagator  Man  Cov"
                        .format(" " * (tagw - 3)))
                    print("-" * (65 + tagw))

                for idx, orb in enumerate(CcsdsDb.list(sat, ext)):

                    if sat.req.limit == "any" and idx == sat.req.offset:
                        color = "* \033[32m"
                        endcolor = "\033[39m"
                    else:
                        color = "  "
                        endcolor = ""

                    if idx >= max_idx:
                        break

                    if ext == "oem":
                        steps = set()
                        for orb_i, orb_j in zip(orb[:-1], orb[1:]):
                            steps.add(orb_j.date - orb_i.date)

                        if len(steps) == 1:
                            (steps, ) = steps
                        elif (max(steps) - min(steps)).total_seconds() < 1e-5:
                            steps = max(steps)
                        else:
                            steps = "[{}, {}]".format(min(steps), max(steps))

                        print(
                            "{color}{idx:<2} {tag:{tagw}}  {orb.frame.name:8}  {orb.start:{fmt}}  {orb.stop:{fmt}}  {steps}{endcolor}"
                            .format(
                                idx=idx,
                                orb=orb,
                                tag=rtags[orb.filepath]
                                if orb.filepath in rtags else "",
                                fmt="%Y-%m-%dT%H:%M:%S",
                                steps=steps,
                                color=color,
                                endcolor=endcolor,
                                tagw=tagw,
                            ))
                    else:
                        print(
                            "{color}{idx:<2} {tag:{tagw}}  {orb.frame.name:8}  {orb.date:{fmt}}  {propagator:10}  {man}    {cov}{endcolor}"
                            .format(
                                idx=idx,
                                tag=rtags[orb.filepath]
                                if orb.filepath in rtags else "",
                                orb=orb,
                                fmt="%Y-%m-%dT%H:%M:%S",
                                propagator=orb.propagator.__class__.__name__
                                if orb.propagator else "None",
                                man=len(orb.maneuvers),
                                cov="Yes" if orb.cov.any() else "None",
                                color=color,
                                endcolor=endcolor,
                                tagw=tagw,
                            ))

                print()
        except ValueError as e:
            log.error(e)
            sys.exit(1)

    elif args["get"]:
        ephems = []

        try:
            for sat in Sat.from_selectors(*args["<selector>"],
                                          src=ext,
                                          orb=False):
                ephem = CcsdsDb.get(sat, raw=True)
                ephems.append(ephem)
            else:
                log.error("No {} file corresponding to {}".format(
                    sat.req.src.upper(), sat.req))
        except ValueError as e:
            log.error(e)
            sys.exit(1)

        # print(dumps(ephems))
        print(ephems[0])
    elif args["purge"]:

        log.info("Starting deletion of {} files".format(ext.upper()))

        try:
            until = parse_timedelta(args["--until"])
        except ValueError:
            until = parse_date(args["--until"])
        else:
            until = Date.now() - until

        for sat in Sat.from_selectors(*args["<selector>"], src=ext, orb=False):

            rtags = CcsdsDb.rtags(sat)

            sublist = []
            for file in CcsdsDb._list(sat, ext):
                mtime = Date.strptime(
                    file.stem.partition("_")[2], "%Y%m%d_%H%M%S")
                if mtime < until:
                    sublist.append(file)

            if not sublist:
                log.info("No file to delete")
                sys.exit(0)

            print("You are about to delete {} files".format(len(sublist)))
            for file in sublist:
                print("   {}".format(file.name))
            ans = input("Are you sure ? yes/[no] ")

            if ans.lower() != "yes":
                log.info("Deletion canceled")
                sys.exit(0)

            for filepath in sublist:
                if filepath in rtags:
                    log.warning(
                        "{} can't be destroyed due to the tag '{}'".format(
                            filepath.name, rtags[filepath]))
                    continue
                log.debug("{} {}".format(filepath.name, "destroyed"))
                filepath.unlink()
    elif args["list-tags"]:
        for sat in Sat.from_selectors(*args["<selector>"], src=ext, orb=False):
            tags = CcsdsDb.tags(sat, ext)
            if tags:
                tagw = len(max(tags.keys(), key=len))
                for tag, filepath in tags.items():
                    print("{:{}}  {}".format(tag, tagw, filepath.name))
    elif args["tag"]:
        sat = Sat.from_selector(*args["<selector>"], src=ext)
        try:
            CcsdsDb.tag(sat, args["<tag>"], force=args["--force"])
        except ValueError as e:
            log.error(e)
            sys.exit(1)
Beispiel #20
0
    def __call__(self, frame):

        plot_list = []

        date = self.date()

        if self.multiplier is None:
            text = "real time"
        else:
            if abs(self.multiplier) == 1:
                adj = ""
                value = abs(self.multiplier)
            elif abs(self.multiplier) > 1:
                adj = "faster"
                value = abs(self.multiplier)
            else:
                adj = "slower"
                value = 1 / abs(self.multiplier)
            sign = "" if self.multiplier > 0 else "-"
            text = "{}x{:0.0f} {}".format(sign, value, adj)

        self.date_text.set_text("{:%Y-%m-%d %H:%M:%S}\n{}".format(date, text))
        plot_list.append(self.date_text)

        for i, sat in enumerate(self.sats):
            color = self.COLORS[i % len(self.COLORS)]
            # Updating position of the satellite
            orb = sat.orb.propagate(date)
            orb_sph = orb.copy(form="spherical", frame="ITRF")
            lon, lat = self.lonlat(orb_sph)
            sat.point.set_data([lon], [lat])
            plot_list.append(sat.point)

            # Updating the label
            sat.text.set_position((lon + 0.75, lat + 0.75))
            plot_list.append(sat.text)

            # Updating the circle of visibility
            lonlat = np.degrees(circle(*orb_sph[:3]))
            lonlat[:, 0] = ((lonlat[:, 0] + 180) % 360) - 180
            sat.circle.set_data(lonlat[:, 0], lonlat[:, 1])
            plot_list.append(sat.circle)

            # Ground track
            if sat.win_ephem is None:
                try:
                    sat.win_ephem = WindowEphem(orb, sat.orb)
                except ValueError:
                    # In case of faulty windowed ephemeris, disable groundtrack
                    # altogether
                    sat.win_ephem = False

            if sat.win_ephem:
                sat.win_ephem.propagate(date)

                lons, lats = [], []
                segments = []
                prev_lon, prev_lat = None, None
                for win_orb in sat.win_ephem:
                    lon, lat = self.lonlat(
                        win_orb.copy(form="spherical", frame="ITRF"))

                    # Creation of multiple segments in order to not have a ground track
                    # doing impossible paths
                    if prev_lon is None:
                        lons = []
                        lats = []
                        segments.append((lons, lats))
                    elif orb.infos.kep.i < np.pi / 2 and (
                            np.sign(prev_lon) == 1 and np.sign(lon) == -1):
                        lons.append(lon + 360)
                        lats.append(lat)
                        lons = [prev_lon - 360]
                        lats = [prev_lat]
                        segments.append((lons, lats))
                    elif orb.infos.kep.i > np.pi / 2 and (
                            np.sign(prev_lon) == -1 and np.sign(lon) == 1):
                        lons.append(lon - 360)
                        lats.append(lat)
                        lons = [prev_lon + 360]
                        lats = [prev_lat]
                        segments.append((lons, lats))
                    elif abs(prev_lon) > 150 and (np.sign(prev_lon) !=
                                                  np.sign(lon)):
                        lons.append(lon - 360)
                        lats.append(lat)
                        lons = [prev_lon + 360]
                        lats = [prev_lat]
                        segments.append((lons, lats))

                    lons.append(lon)
                    lats.append(lat)
                    prev_lon = lon
                    prev_lat = lat

                sat.gt = []
                for lons, lats in segments:
                    sat.gt.append(
                        self.ax.plot(lons,
                                     lats,
                                     color=color,
                                     alpha=0.5,
                                     lw=2,
                                     animated=True)[0])
                    plot_list.append(sat.gt[-1])

        # Updating the sun
        sun = get_body("Sun").propagate(date).copy(form="spherical",
                                                   frame="ITRF")
        lon, lat = self.lonlat(sun)
        self.sun.set_data([lon], [lat])
        plot_list.append(self.sun)

        # Updating the night
        lonlat = np.degrees(circle(*sun[:3]))
        lonlat[:, 0] = ((lonlat[:, 0] + 180) % 360) - 180
        season = -95 if lat > 0 else 95
        lonlat = lonlat[
            lonlat[:, 0].argsort()]  # Sorting array by ascending longitude

        lonlat = np.concatenate([
            [[-185, season], [-185, lonlat[0, 1]]],
            lonlat,
            [[185, lonlat[-1, 1]], [185, season]],
        ])

        verts = [lonlat]

        # Eclipse (part of the orbit when the satellite is not illuminated by
        # the sun)
        if len(self.sats) == 1:
            virt_alt = Earth.r * orb_sph.r / np.sqrt(orb_sph.r**2 - Earth.r**2)
            theta = sun.theta + np.pi
            phi = -sun.phi
            lonlat = np.degrees(circle(virt_alt, theta, phi))
            lonlat[:, 0] = ((lonlat[:, 0] + 180) % 360) - 180

            if all(abs(lonlat[:, 0]) < 175):
                # This deals with the case when the umbra is between -180 and 180° of
                # longitude
                verts.append(lonlat)
            else:
                pos_lonlat = lonlat.copy()
                neg_lonlat = lonlat.copy()

                pos_lonlat[pos_lonlat[:, 0] < 0, 0] += 360
                neg_lonlat[neg_lonlat[:, 0] > 0, 0] -= 360

                min_lon = min(pos_lonlat[:, 0])
                max_lon = max(neg_lonlat[:, 0])

                lonlat = np.concatenate([neg_lonlat, pos_lonlat])

                if abs(min_lon - max_lon) > 30:
                    # This deals with the case when the umbra is spread between
                    # the east-west edges of the map, but not the north and south
                    # ones
                    verts.append(lonlat)
                else:
                    # This deals with the case when the umbra is spread between
                    # east west and also north or south

                    # sort by ascending longitude
                    lonlat = lonlat[lonlat[:, 0].argsort()]

                    west_lat = lonlat[0, 1]
                    east_lat = lonlat[-1, 1]

                    v = np.concatenate([
                        [[-360, season], [-360, west_lat]],
                        lonlat,
                        [[360, east_lat], [360, season]],
                    ])

                    verts.append(v)

        self.night.set_verts(verts)
        plot_list.insert(0, self.night)

        # Updating the moon
        moon = get_body("Moon").propagate(date).copy(frame="ITRF",
                                                     form="spherical")
        lon, lat = self.lonlat(moon)
        self.moon.set_data([lon], [lat])
        plot_list.append(self.moon)

        return plot_list
Beispiel #21
0
def test_unknown():

    with raises(UnknownBodyError):
        get_body("Mars")
Beispiel #22
0
def test_unknown():

    with raises(UnknownBodyError):
        get_body("Mars")
Beispiel #23
0
    def update_bodies(self):

        plot_list = []

        # Updating the sun
        sun = get_body("Sun").propagate(self.date).copy(form="spherical",
                                                        frame="ITRF")
        lon, lat = orb2lonlat(sun)
        self.sun.set_data([lon], [lat])
        plot_list.append(self.sun)

        # Updating the night
        lonlat = np.degrees(orb2circle(sun))
        lonlat[:, 0] = ((lonlat[:, 0] + 180) % 360) - 180
        season = -95 if lat > 0 else 95
        lonlat = lonlat[
            lonlat[:, 0].argsort()]  # Sorting array by ascending longitude

        lonlat = np.concatenate([
            [[-185, season], [-185, lonlat[0, 1]]],
            lonlat,
            [[185, lonlat[-1, 1]], [185, season]],
        ])

        verts = [lonlat]

        # Eclipse (part of the orbit when the satellite is not illuminated by
        # the sun)
        if len(self.sats) == 1:
            orb_sph = self.sats[0].propagated.copy(form="spherical",
                                                   frame="ITRF")
            virt_alt = Earth.r * orb_sph.r / np.sqrt(orb_sph.r**2 - Earth.r**2)
            theta = sun.theta + np.pi
            phi = -sun.phi
            lonlat = np.degrees(circle(virt_alt, theta, phi))
            lonlat[:, 0] = ((lonlat[:, 0] + 180) % 360) - 180

            if all(abs(lonlat[:, 0]) < 175):
                # This deals with the case when the umbra is between -180 and 180° of
                # longitude
                verts.append(lonlat)
            else:
                pos_lonlat = lonlat.copy()
                neg_lonlat = lonlat.copy()

                pos_lonlat[pos_lonlat[:, 0] < 0, 0] += 360
                neg_lonlat[neg_lonlat[:, 0] > 0, 0] -= 360

                min_lon = min(pos_lonlat[:, 0])
                max_lon = max(neg_lonlat[:, 0])

                lonlat = np.concatenate([neg_lonlat, pos_lonlat])

                if abs(min_lon - max_lon) > 30:
                    # This deals with the case when the umbra is spread between
                    # the east-west edges of the map, but not the north and south
                    # ones
                    verts.append(lonlat)
                else:
                    # This deals with the case when the umbra is spread between
                    # east west and also north or south

                    # sort by ascending longitude
                    lonlat = lonlat[lonlat[:, 0].argsort()]

                    west_lat = lonlat[0, 1]
                    east_lat = lonlat[-1, 1]

                    v = np.concatenate([
                        [[-360, season], [-360, west_lat]],
                        lonlat,
                        [[360, east_lat], [360, season]],
                    ])

                    verts.append(v)

        self.night.set_verts(verts)
        plot_list.append(self.night)

        # Updating the moon
        moon = (get_body("Moon").propagate(self.date).copy(frame="ITRF",
                                                           form="spherical"))
        lon, lat = orb2lonlat(moon)
        self.moon.set_data([lon], [lat])
        plot_list.append(self.moon)

        return plot_list