WarpTwin
Documentation for WarpTwin models and classes.
Loading...
Searching...
No Matches
script.py
###############################################################################
# Copyright (c) ATTX INC 2025. All Rights Reserved.
#
# This software and associated documentation (the "Software") are the 
# proprietary and confidential information of ATTX, INC. The Software is 
# furnished under a license agreement between ATTX and the user organization 
# and may be used or copied only in accordance with the terms of the agreement.
# Refer to 'license/attx_license.adoc' for standard license terms.
#
# EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
# INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION 
# REGULATIONS (EAR99). No part of the Software may be used, reproduced, or 
# transmitted in any form or by any means, for any purpose, without the express 
# written permission of ATTX, INC.
###############################################################################
"""
Spacecraft Constellation Tutorial
---------------------------------
This example shows how to create a constellation of spacecraft in WarpTwin
and visualize them using the visuals model.

Author: Alex Reynolds
"""
import sys
from warptwin.WarpTwinPy import (Time, SimulationExecutive, Frame, Node, 
                                     Body, CartesianVector3, Hdf5Logger, connectSignals,
                                     DEGREES_TO_RADIANS, HOURS_TO_SECONDS)
from warptwin.Spacecraft import Spacecraft
from warptwin.OrbitalElementsStateInit import OrbitalElementsStateInit
from warptwin.SpicePlanet import SpicePlanet
from warptwin.FrameStateSensorModel import FrameStateSensorModel
from warptwin.VisualsModel import VisualsModel
from warptwin.EarthObservationModel import EarthObservationModel

##########################################################################
# PARAMETERS FOR SPACECRAFT CONSTELLATION STUDY
##########################################################################
SIM_RUNTIME = 10                    # hours

# Orbit Parameters
# The following parameters are defined to configure a single constellation of 
# spacecraft in a single orbit with even spacing. Additional inclinations,
# altitudes, RAAN, etc. can easily be added by following this example.
TOTAL_NUM_SATELLITES = 10
ORBIT_SEMIMAJOR_AXIS = 6678.14e3                # km   
ORBIT_ECCENTRICITY = 0.0000001
ORBIT_INCLINATION = 97.0                        # degrees
ORBIT_RAAN = 10.0                               # degrees

# Create our base simulation infrastructure
exc = SimulationExecutive()                                                 # Create our executive -- by convention named exc
exc.setRateSec(5.0)                                                         # We can setRateHz or setRateSec -- default is 1 second
exc.args().addDefaultArgument("end",     SIM_RUNTIME*HOURS_TO_SECONDS)      # Default can be overridden by command line
exc.parseArgs(sys.argv)                                                     # This interperets command-line inputs

# Create instances of the Earth and Sun as SPICE planets
earth = SpicePlanet(exc, "earth")
sun = SpicePlanet(exc, "sun")

# Now loop and create our spacecraft constellation
spacecraft = []
for i in range(TOTAL_NUM_SATELLITES):
    spacecraft.append(Spacecraft(exc, "sc_" + str(i)))          # Create the spacecraft
    spacecraft[i].params.planet_ptr(earth)                      # Configure it from earth

# Add an Earth Observation Model to each spacecraft
eom = []
for i in range(TOTAL_NUM_SATELLITES):
    eom.append(EarthObservationModel(exc, "eom_" + str(i)))
    eom[i].params.planet_rotating_frame(earth.outputs.rotating_frame())    # Set the planet rotating frame to Earth
    eom[i].params.spacecraft_frame(spacecraft[i].outputs.body())           # Set the spacecraft frame to the body frame of the spacecraft
    eom[i].params.target_lat_rad(DEGREES_TO_RADIANS*40.0)                  # Set the ground station geocentric longitude in radians
    eom[i].params.target_lon_rad(DEGREES_TO_RADIANS*-105.0)                # Set the ground station longitude in radians
    eom[i].params.off_nadir_mask_rad(70.0*DEGREES_TO_RADIANS)              # Off-nadir mask in radians

# And set up logging for just a single spacecraft
log = Hdf5Logger(exc, "states.h5")
log.addParameter(exc.time().base_time,                  "time")
log.addParameter(spacecraft[0].outputs.pos_sc_pci,      "eci_pos")
log.addParameter(spacecraft[0].outputs.vel_sc_pci,      "eci_vel")
log.addParameter(eom[0].outputs.look_angle,             "look_angle_rad")
log.addParameter(eom[0].outputs.range,                  "range_m")
log.addParameter(eom[0].outputs.range_rate,             "range_rate_mps")
log.addParameter(eom[0].outputs.visible,                "visible")
log.addParameter(eom[0].outputs.total_visits,           "visits")
exc.logManager().addLog(log, 10)

exc.startup()

# Now loop and initialize our spacecraft states with equal spacing. Note this
# must occur after startup
for i in range(TOTAL_NUM_SATELLITES):
    spacecraft[i].initializeFromOrbitalElements(ORBIT_SEMIMAJOR_AXIS, 
                                                ORBIT_ECCENTRICITY, 
                                                DEGREES_TO_RADIANS*ORBIT_INCLINATION, 
                                                DEGREES_TO_RADIANS*ORBIT_RAAN, 
                                                0.0, 
                                                DEGREES_TO_RADIANS*i*(361.0/TOTAL_NUM_SATELLITES))

exc.run()