![]() |
WarpTwin
Documentation for WarpTwin models and classes.
|
###############################################################################
# Copyright (c) ATTX LLC 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.
###############################################################################
"""
Simple Comms Study
-----------------------
This script demonstrates how to set up a simple data transfer simulation. It
initializes a spacecraft, two ground stations, and simulates data transfer
between the spacecraft and the ground stations over a specified time period.
Author: Daniel Krobath
"""
import sys
from warptwin.WarpTwinPy import SimulationExecutive, CsvLogger, Time, connectSignals, DEGREES_TO_RADIANS
from warptwin.Spacecraft import Spacecraft
from warptwin.SpicePlanet import SpicePlanet
from warptwin.GroundStationModel import GroundStationModel
from warptwin.OrbitalElementsStateInit import OrbitalElementsStateInit
from warptwin.CommunicationsDataModel import CommunicationsDataModel
from warptwin.VisualsModel import VisualsModel
exc = SimulationExecutive() # Create our executive -- by convention named exc
exc.args().addDefaultArgument("end", 86400*15) # Set end time in seconds
exc.parseArgs(sys.argv) # this interperets command-line inputs
exc.setRateSec(10) # We can setRateHz or setRateSec
# Create the Earth from SPICE kernels
earth = SpicePlanet(exc, "earth")
# Initialize orbital elements state
oe = OrbitalElementsStateInit(exc)
oe.params.a(6978140.0) # Semi-major axis in meters
oe.params.e(0.01) # Eccentricity
oe.params.i(DEGREES_TO_RADIANS*75.0) # Inclination in radians
oe.params.RAAN(DEGREES_TO_RADIANS*0.0) # Right Ascension of Ascending Node in radians
oe.params.w(DEGREES_TO_RADIANS*0.0) # Argument of Periapsis in radians
oe.params.f(DEGREES_TO_RADIANS*0.0) # Mean Anomaly in radians
# Create the spacecraft and connect its initial state to the orbital elements
sc = Spacecraft(exc, "sc")
connectSignals(oe.outputs.pos__inertial, sc.params.initial_position)
connectSignals(oe.outputs.vel__inertial, sc.params.initial_velocity)
connectSignals(earth.outputs.self_id, sc.params.planet_ptr)
# Create ground stations
attx = GroundStationModel(exc, "ATTX") # Create the ATTX ground station and establish the ENU frame
attx.params.spacecraft_frame.mapTo(sc.outputs.body) # Assign the spacecraft that we will be tracking
attx.params.planet_rotating_frame.mapTo(earth.outputs.rotating_frame) # Set the planet fixed frame
attx.params.R_planet(6378140.0) # Set the ground station radius from the center of the Earth
attx.params.latitude_detic_rad(DEGREES_TO_RADIANS*40.0) # Set the geometric latitude in radians
attx.params.longitude_rad(DEGREES_TO_RADIANS*-105.0) # Set the longitude in radians
attx.params.elevation_mask_rad(DEGREES_TO_RADIANS*10.0) # Set the elevation mask in radians
rolla = GroundStationModel(exc, "Rolla") # Create the rolla ground station and establish the ENU frame
rolla.params.spacecraft_frame.mapTo(sc.outputs.body) # Assign the spacecraft that we will be tracking
rolla.params.planet_rotating_frame.mapTo(earth.outputs.rotating_frame) # Set the planet fixed frame
rolla.params.R_planet(6378140.0) # Set the ground station radius from the center of the Earth
rolla.params.latitude_detic_rad(DEGREES_TO_RADIANS*37.95) # Set the geometric latitude in radians
rolla.params.longitude_rad(DEGREES_TO_RADIANS*-91.78) # Set the longitude in radians
rolla.params.elevation_mask_rad(DEGREES_TO_RADIANS*10.0) # Set the elevation mask in radians
# Create two communications data models for the spacecraft and ground stations
attx_comm = CommunicationsDataModel(exc, "attx_comm") # Create the communications data model for the ATTX ground station
connectSignals(attx.outputs.range, attx_comm.inputs.range)
connectSignals(attx.outputs.masked, attx_comm.inputs.masked)
attx_comm.params.frequency(2.23e9) # Frequency in Hz
attx_comm.params.bit_rate(1e6) # Bit rate in bits per second
attx_comm.params.power_TX(30) # Transmit power in decibel-milliwatts (dBm)
attx_comm.params.gain_TX(6.5) # Transmit antenna gain in (dBi)
attx_comm.params.loss_TX(4.0) # Transmit system losses in dB
attx_comm.params.antenna_diameter(0.5) # receive antenna diameter in meters
attx_comm.params.antenna_efficiency(60) # receive antenna efficiency as a percentage (0 to 100)
attx_comm.params.noise_temperature(250) # Noise temperature in Kelvin
attx_comm.params.loss_RX(4.0) # receive system losses in dB
attx_comm.params.energy_per_bit_to_noise_ratio_required(3) # Required energy per bit to noise ratio in dB for link budget closure
rolla_comm = CommunicationsDataModel(exc, "Rolla_comm") # Create the communications data model for the Kaena Point ground station
connectSignals(rolla.outputs.range, rolla_comm.inputs.range)
connectSignals(rolla.outputs.masked, rolla_comm.inputs.masked)
rolla_comm.params.frequency(2.23e9) # Frequency in Hz
rolla_comm.params.bit_rate(1e6) # Bit rate in bits per second
rolla_comm.params.power_TX(30) # Transmit power in decibel-milliwatts (dBm)
rolla_comm.params.gain_TX(6.5) # Transmit antenna gain in (dBi)
rolla_comm.params.loss_TX(4.0) # Transmit system losses in dB
rolla_comm.params.antenna_diameter(0.5) # receive antenna diameter in meters
rolla_comm.params.antenna_efficiency(60) # receive antenna efficiency as a percentage (0 to 100)
rolla_comm.params.noise_temperature(250) # Noise temperature in Kelvin
rolla_comm.params.loss_RX(4.0) # receive system losses in dB
rolla_comm.params.energy_per_bit_to_noise_ratio_required(3) # Required energy per bit to noise ratio in dB for link budget closure
# Set parameters for logging
# Be sure to name output parameters in similar fashion to what follows:
# Anything relating to a ground station will have to have the ground station name postpended
# to the output parameter name like below for the analysis script to work properly
# Additionally, both time and tdb_time must be logged with the exact names below
# for the analysis script to work properly
states = CsvLogger(exc, "states.csv")
states.addParameter(exc.time().base_time, "time")
states.addParameter(exc.time().tdb_time, "tdb_time")
states.addParameter(attx.outputs.masked, "masked_attx")
states.addParameter(rolla.outputs.masked, "masked_rolla")
states.addParameter(attx.outputs.range, "range_attx")
states.addParameter(attx.outputs.range_rate, "range_rate_attx")
states.addParameter(rolla.outputs.range, "range_rolla")
states.addParameter(rolla.outputs.range_rate, "range_rate_rolla")
states.addParameter(attx_comm.outputs.free_space_path_loss, "FSPL_attx")
states.addParameter(attx_comm.outputs.eff_isotropic_radiated_pwr, "EISP_attx")
states.addParameter(attx_comm.outputs.carrier_to_noise_density_ratio, "C/N0_attx")
states.addParameter(attx_comm.outputs.energy_per_bit_to_noise_ratio, "Eb/N0_attx")
states.addParameter(attx_comm.outputs.link_margin, "link_margin_attx")
states.addParameter(rolla_comm.outputs.free_space_path_loss, "FSPL_rolla")
states.addParameter(rolla_comm.outputs.eff_isotropic_radiated_pwr, "EISP_rolla")
states.addParameter(rolla_comm.outputs.carrier_to_noise_density_ratio, "C/N0_rolla")
states.addParameter(rolla_comm.outputs.energy_per_bit_to_noise_ratio, "Eb/N0_rolla")
states.addParameter(rolla_comm.outputs.link_margin, "link_margin_rolla")
exc.logManager().addLog(states, 1)
# Enable visuals
exc.enableVisuals() # Enable visuals for the simulation
exc.visualsModel().addFrame(sc.outputs.body()) # Add the spacecraft body frame to the visuals
exc.visualsModel().addGroundStation(attx) # Add the ATTX ground station to the visuals
exc.visualsModel().addGroundStation(rolla) # Add the rolla ground station to the visuals
# Run the simulation
exc.startup()
exc.run()