C++ Module: facetDragDynamicEffector

Executive Summary

Drag dynamics class used to compute drag effects on spacecraft bodies

This class is used to implement drag dynamic effects on spacecraft using a variety of simple or complex models, which will include cannonball (attitude-independent) drag, single flat-plate drag, faceted drag models, and an interface to full-CAD GPU-accellerated drag models. For more information see the PDF Description.

Wind Velocity Input

When windVelInMsg is linked to a C++ Module: windBase-derived module (e.g. C++ Module: zeroWindModel), the drag model subtracts the air velocity v_air_N from the spacecraft inertial velocity before computing drag, yielding the atmosphere-relative velocity:

\[\mathbf{v}_{rel} = \mathbf{v}_{sc} - \mathbf{v}_{air}\]

If windVelInMsg is not linked, the inertial spacecraft velocity is used directly.

Example setup:

drag = facetDragDynamicEffector.FacetDragDynamicEffector()
drag.addFacet(10.0, 2.2, [1, 0, 0], [0, 0, 0])
drag.atmoDensInMsg.subscribeTo(atmo.envOutMsgs[0])

# Optional: link a wind model for atmosphere-relative velocity
drag.windVelInMsg.subscribeTo(windModel.envOutMsgs[0])

scObject.addDynamicEffector(drag)
scSim.AddModelToTask(simTaskName, drag)

Attaching to a State Effector

This effector supports the branching described in Advanced: Effector Module Branching, so a drag surface can be carried by an appendage instead of the hub. Attach it to the parent state effector rather than to the spacecraft:

stateEff.addDynamicEffector(drag, segment)

The parent’s inertial attitude and velocity then replace the hub’s in the drag calculation, so a panel that rotates or translates relative to the hub sees its own relative wind. Every facet normal and facet location passed to addFacet() is expressed in the parent segment’s frame in that configuration, not in the hub body frame, and the resulting force and torque are returned about the parent frame origin. The segment argument is omitted for a parent with a single degree of freedom.

Both the parent and the child are still added to the task in the usual way, the same as when the child is attached to the hub.

Input Message Timing

Both atmoDensInMsg and windVelInMsg are refreshed only during UpdateState(). Because Spacecraft::computeForceTorque() calls dynamic effectors before the atmosphere and wind models receive their next UpdateState(), the drag computation always uses the values from the previous time step (zero-initialized on the first step). Both inputs are therefore treated as piecewise-constant over each integration step.

Message Connection Descriptions

The following table lists all the module input and output messages. The module msg variable name is set by the user from python. The msg type contains a link to the message structure definition, while the description provides information on what this message is used for.

facetDragDynamicEffector module input and output messages

Module I/O Messages

Msg Variable Name

Msg Type

Description

atmoDensInMsg

AtmoPropsMsgPayload

input message for atmospheric density information.

windVelInMsg

WindMsgPayload

(optional) wind velocity input message; when linked, v_air_N is subtracted from the spacecraft inertial velocity to obtain the atmosphere-relative velocity.

Initialization and Reset

When this effector is attached to a spacecraft hub or a state-effector branch, initialization verifies that atmoDensInMsg is connected. The check is performed while linking either the hub states or the branch properties, so it does not depend on separately scheduling the effector.

Attachment-time validation does not replace task scheduling for this effector. Add it to a task so that UpdateState() refreshes the cached atmospheric density and optional wind data used during force evaluation.

When the effector is scheduled, its Reset() repeats the required-message check. Reset() does not clear the cached atmosphere, wind, geometry, force, or torque data.


struct SpacecraftGeometryData
#include <facetDragDynamicEffector.h>

spacecraft geometry data

Public Members

std::vector<double> facetAreas

vector of facet areas

std::vector<double> facetCoeffs

vector of facet coefficients

std::vector<Eigen::Vector3d> facetNormals_B

vector of facet normals

std::vector<Eigen::Vector3d> facetLocations_B

vector of facet locations

class FacetDragDynamicEffector : public SysModel, public DynamicEffector
#include <facetDragDynamicEffector.h>

faceted atmospheric drag dynamic effector

Public Functions

FacetDragDynamicEffector()
~FacetDragDynamicEffector()

The destructor.

void linkInStates(DynParamManager &states) override

This method is used to link the dragEffector to the hub attitude and velocity, which are required for calculating drag forces and torques.

Parameters:

states – dynamic parameter states

void linkInProperties(DynParamManager &properties) override

This method is used to link the dragEffector to its parent state effector’s properties

Parameters:

properties – The parameter manager to collect from

void computeForceTorque(double integTime, double timeStep) override

This method computes the body forces and torques for the dragEffector in a simulation loop, selecting the model type based on the settable attribute “modelType.”

Parameters:
  • integTime – [in] [s] Current integration time.

  • timeStep – [in] [s] Integration time step.

void Reset(uint64_t CurrentSimNanos) override

class method

Validate the module configuration when the scheduler resets the model.

Parameters:

CurrentSimNanos – [ns] Time at which the reset occurs

void UpdateState(uint64_t CurrentSimNanos) override

This method is called to update the local atmospheric conditions at each timestep. Naturally, this means that conditions are held piecewise-constant over an integration step.

Parameters:

CurrentSimNanos – The current simulation time in nanoseconds

void WriteOutputMessages(uint64_t CurrentClock)

The DragEffector does not write output messages to the rest of the sim.

Parameters:

CurrentClock – [in] [ns] Current simulation time.

bool ReadInputs()

This method is used to read the incoming density message and wind velocity message (if linked) and update the internal density/atmospheric data.

void addFacet(double area, double dragCoeff, Eigen::Vector3d B_normal_hat, Eigen::Vector3d B_location)

Add a facet to the drag model.

Parameters:
  • area – [in] [m^2] Facet area.

  • dragCoeff – [in] [-] Facet drag coefficient.

  • B_normal_hat – [in] [-] Facet normal expressed in the parent body frame.

  • B_location – [in] [m] Facet location relative to the parent body-frame origin.

Public Members

uint64_t numFacets

number of facets

ReadFunctor<AtmoPropsMsgPayload> atmoDensInMsg

atmospheric density input message

ReadFunctor<WindMsgPayload> windVelInMsg

wind velocity input message

StateData *hubSigma = nullptr

Hub/Inertial attitude represented by MRP.

StateData *hubVelocity = nullptr

m/s Hub inertial velocity vector

Eigen::Vector3d v_B

m/s spacecraft velocity expressed in body frame B (relative to air if windVelInMsg is linked, else relative to inertial frame N)

Eigen::Vector3d v_hat_B

Drag force direction in the body frame.

BSKLogger bskLogger

BSK Logging.

Private Functions

void validateConfiguration()

Validate that the required atmospheric density input is connected.

void plateDrag()

This method WILL implement a more complex flat-plate aerodynamics model with attitude dependence and lift forces.

void updateDragDir()

This method updates the internal drag direction based on the spacecraft velocity vector. It accounts for wind velocity if the wind message is linked.

double getDensity()

This method obtains the density from the input data

Private Members

AtmoPropsMsgPayload atmoInData
WindMsgPayload windInData
SpacecraftGeometryData scGeometry

Struct to hold spacecraft facet data.

Eigen::MatrixXd *inertialVelocityProperty = nullptr

m/s parent frame origin inertial velocity

Eigen::MatrixXd *inertialAttitudeProperty = nullptr

parent frame attitude relative to the inertial frame