FourierAcceleration#

class FourierAcceleration(origin: Body, spacecraft: Spacecraft, base_frame: Frame, degree: int = 0, frame: str = 'inertial', angle: str = 'time', period: float | None = None, t0: EpochArray | float | None = None, body_fixed_frame=None, relative_body=None, coefficients: ndarray | None = None)#

Bases: DynamicModel

Models an empirical acceleration as a truncated Fourier series.

Each axis of a chosen frame carries its own series in a phase angle \(\theta\),

\[a_j(\theta) = A_{j,0} + \sum_{k=1}^{N} \left[ A_{j,k}\cos(k\theta) + B_{j,k}\sin(k\theta) \right], \qquad j \in \{1, 2, 3\}\]

and the resulting frame-local vector is rotated into the propagation frame,

\[\mathbf a_F = \mathbf T \, \mathbf a^{(f)} = \mathbf T \, \mathbf M(\theta) \, \mathbf p .\]

Degree \(N = 0\) leaves only the constant terms, so the model degenerates to a constant empirical acceleration in the chosen frame — the usual “constant along-track acceleration” is degree=0, frame="RTN".

Because the acceleration is linear in the coefficients, the partial that the filter needs is the design matrix itself,

\[\frac{\partial \mathbf a_F}{\partial \mathbf p} = \mathbf T \, \mathbf M(\theta),\]

which is exact rather than a difference approximation.

Parameters:
originBody

Propagation origin.

spacecraftSpacecraft

Spacecraft the empirical acceleration acts on.

base_frameFrame

Reference frame of the propagator.

degreeint, optional

Highest harmonic \(N\) retained. 0 (the default) gives a constant acceleration.

framestr, optional

"inertial", "body_fixed", or "RTN". Defaults to "inertial".

anglestr, optional

"time", "argument_of_latitude", or "solar_longitude". Defaults to "time". Ignored when degree == 0, which has no phase dependence.

periodfloat, optional

Repeat period of the series in seconds, for angle="time". Required when degree >= 1 and the phase is time-based.

t0EpochArray or float, optional

Epoch of zero phase for angle="time", in ephemeris seconds (TDB) or as an EpochArray. In a MissionSequence this must be the same epoch for every leg, since the legs share one coefficient state and a moving origin would give the phase a different meaning in each of them.

body_fixed_framestr or Frame, optional

Frame the coefficients are expressed in, for frame="body_fixed".

relative_bodystr or Body, optional

Body the orbit is described about, when that is not the propagation origin — a lunar RTN frame while propagating an Earth-centred arc, say. Governs the RTN triad and the orbital phase angles together: they describe the same orbit, so anchoring them to different bodies would give a frame and a phase that disagree. Defaults to the propagation origin.

coefficientsnp.ndarray, optional

Default coefficient vector, used when the propagated state carries no a_fourier entry. This is what makes the model usable as a plain force model — a known constant or periodic acceleration applied without estimating anything.

Attributes:
angle

Phase angle driving the series.

body_fixed_frame

Body-fixed frame the coefficients are expressed in, if any.

default_coefficients

Coefficients applied when the state carries no a_fourier entry.

degree

Highest harmonic retained; 0 is a constant acceleration.

depends_on_velocity

Whether the acceleration is a function of velocity.

frame

Frame the coefficients are expressed in.

n_coefficients

Length of the stacked a_fourier state, 3 * (2 * degree + 1).

n_terms

Number of terms per axis, 2 * degree + 1.

origin

Celestial body serving as origin of the state vector.

origin_name

Name of the origin body.

period

Repeat period of a time-based phase, in seconds.

ref_frame

Reference frame used by the model.

relative_body

Body the RTN triad and the orbital phase are referred to, if any.

t0

Epoch of zero phase for a time-based series, in ephemeris seconds.

Methods

coefficient_labels()

Names of the stacked coefficients, in state order.

compute_acceleration(position, ...)

Empirical Fourier acceleration applied to the body.

See also

scarabaeus.FirstOrderGaussMarkov

Stochastic empirical acceleration.

scarabaeus.PiecewiseFirstOrderGaussMarkov

Batch-segmented stochastic variant.

scarabaeus.StateArray

State vector used to initialize the model.

scarabaeus.DynamicModel

Abstract base class for all force model components.

Notes

The frame argument selects the triad the coefficients are expressed in:

"inertial"

Coefficients are expressed directly in the propagation frame, \(\mathbf T = \mathbf I\).

"body_fixed"

Coefficients are expressed in a rotating body-fixed frame and rotated out through SPICE, \(\mathbf T = \mathbf R_{bf\to rf}(t)\). Use this for an acceleration tied to the central body’s geography or illumination, such as an outgassing jet on a rotating comet.

"RTN"

Coefficients are expressed in the spacecraft’s local orbital triad (radial / along-track / cross-track, also called RSW or RIC),

\[\hat{\mathbf R} = \frac{\mathbf r}{r}, \quad \hat{\mathbf N} = \frac{\mathbf r \times \mathbf v} {\|\mathbf r \times \mathbf v\|}, \quad \hat{\mathbf T} = \hat{\mathbf N} \times \hat{\mathbf R},\]

with \(\mathbf T = [\hat{\mathbf R}\;\hat{\mathbf T}\; \hat{\mathbf N}]\). This triad depends on the state, so it contributes to \(\partial \mathbf a / \partial \mathbf r\) and \(\partial \mathbf a / \partial \mathbf v\).

The angle argument selects the phase \(\theta\):

"time"

\(\theta = 2\pi (t - t_0) / T\), with period the repeat time \(T\) in seconds. Independent of the state, so it adds nothing to the position and velocity partials. Required only when degree >= 1.

"argument_of_latitude"

\(\theta = u\), the angle from the ascending node to the spacecraft measured in the orbit plane. The natural variable for a per-revolution empirical acceleration. Undefined for an exactly equatorial orbit, where the node direction vanishes.

"solar_longitude"

\(\theta = \lambda_s\), the longitude of the Sun in the coefficient frame. This is the phase McMahon and Scheeres expand solar radiation pressure in [3]: in a body-fixed frame it is exactly their \(\lambda_s\), whose frequency is the body’s rotation relative to the Sun; in RTN it is the Sun-relative in-plane angle the CODE/Bern GPS model writes as \(u - u_0\). Nothing is supplied by the caller — the geometry sets the frequency. Undefined when the Sun lies along the frame’s third axis.

The difference between the last two is where the phase is measured from. A constant offset is absorbed by the coefficients, so over a short arc the two are equivalent; the Sun’s direction drifts by about a degree a day, though, so on a long arc only "solar_longitude" keeps a Sun-driven effect at a fixed phase.

A series in true anomaly \(\nu\) is deliberately not offered: since \(u = \nu + \omega\), a Fourier series in \(u\) spans exactly the same function space for a fixed argument of periapsis, and \(u\) stays well defined on the near-circular orbits where empirical accelerations are most often used, whereas \(\nu\) does not.

The estimated state is one stacked ("a_fourier", spice_id) entry of length \(3(2N+1)\), ordered axis-major and, within an axis, by harmonic:

[ A_1,0  A_1,1  B_1,1  ...  A_1,N  B_1,N |   <- first frame axis
  A_2,0  A_2,1  B_2,1  ...  A_2,N  B_2,N |   <- second frame axis
  A_3,0  A_3,1  B_3,1  ...  A_3,N  B_3,N ]   <- third frame axis

so degree=0 is simply [a_1, a_2, a_3]. coefficient_labels() returns the matching names.

The state vector must contain an entry of the form

  • ('a_fourier', 3*(2*degree+1), 'estimated', 'static', owner, value)

for the coefficients to be estimated. The coefficients are constants of the dynamics, so they are declared 'static': unlike the Gauss-Markov models, nothing about them is integrated.

References

[1]

Montenbruck, O., & Gill, E. (2000). Satellite Orbits, Sec. 3.7 (empirical accelerations in the radial / along-track / cross-track frame).

[2]

Tapley, B. D., Schutz, B. E., & Born, G. H. (2004). Statistical Orbit Determination, Ch. 4 (estimating dynamic model parameters).

[3]

McMahon, J. W., & Scheeres, D. J. (2010). New Solar Radiation Pressure Force Model for Navigation. Journal of Guidance, Control, and Dynamics, 33(5). See also McMahon (2011), PhD thesis, University of Colorado, Eq. (2.28), where the force is expanded as \(\sum_n [A_n(\delta_s)\cos n\lambda_s + B_n(\delta_s)\sin n\lambda_s]\).

Examples

A once-per-revolution along-track acceleration, estimated:

import scarabaeus as scb

state = [
    ("position", 3, "estimated", "dynamic", sc, [7000, 0, 0]),
    ("velocity", 3, "estimated", "dynamic", sc, [0, 7.5, 0]),
    ("a_fourier", 9, "estimated", "static", sc, [0.0] * 9),
]

force_model = scb.ForceModelTranslation(
    primary_body=sc,
    fourier_acceleration=True,
    fourier_degree=1,
    fourier_frame="RTN",
    fourier_angle="argument_of_latitude",
)
coefficient_labels() → list[str]#

Names of the stacked coefficients, in state order.

Returns:
list of str

3 * (2 * degree + 1) labels such as ['A0_R', 'A1_R', 'B1_R', 'A0_T', ...] for the RTN frame, matching the layout of the a_fourier state.

compute_acceleration(position: ndarray, current_state: dict, epoch: float, body: Body) → ndarray#

Empirical Fourier acceleration applied to the body.

\[\mathbf a_F = \mathbf T \, \mathbf M(\theta) \, \mathbf p\]
Parameters:
positionnp.ndarray

Spacecraft position 3-vector, km.

current_statedict

Dictionary containing the propagated state.

epochfloat

Current epoch in ephemeris seconds (TDB).

bodyBody

Body the acceleration is evaluated for.

Returns:
np.ndarray

Acceleration 3-vector in km/s^2. Zero when neither the state nor the model configuration supplies coefficients.

property angle: str#

Phase angle driving the series.

property body_fixed_frame: str | None#

Body-fixed frame the coefficients are expressed in, if any.

property default_coefficients#

Coefficients applied when the state carries no a_fourier entry.

property degree: int#

Highest harmonic retained; 0 is a constant acceleration.

property depends_on_velocity: bool#

Whether the acceleration is a function of velocity.

True for the RTN frame, whose triad is built from the velocity, and for the argument-of-latitude phase, which is measured in the orbit plane. The force model reads this to decide whether a \(\partial \mathbf a / \partial \mathbf v\) block is needed at all.

property frame: str#

Frame the coefficients are expressed in.

property n_coefficients: int#

Length of the stacked a_fourier state, 3 * (2 * degree + 1).

property n_terms: int#

Number of terms per axis, 2 * degree + 1.

property origin: Body#

Celestial body serving as origin of the state vector.

property origin_name: str#

Name of the origin body.

property period: float | None#

Repeat period of a time-based phase, in seconds.

property ref_frame#

Reference frame used by the model.

property relative_body: str | None#

Body the RTN triad and the orbital phase are referred to, if any.

property t0: float | None#

Epoch of zero phase for a time-based series, in ephemeris seconds.

exception CoefficientSizeError#

Bases: ValueError

Raised when the a_fourier state does not match the model degree.

exception DegenerateGeometryError#

Bases: ValueError

Raised when the orbit geometry leaves the phase angle undefined.

exception InvalidAngleError#

Bases: ValueError

Raised when angle is not one of the supported phase angles.

exception InvalidDegreeError#

Bases: ValueError

Raised when degree is negative or not an integer.

exception InvalidEpochError#

Bases: TypeError

Raised when t0 is neither an EpochArray nor a real number.

exception MissingEpochError#

Bases: ValueError

Raised when a time-based or solar phase has no t0 or epoch.

exception MissingPeriodError#

Bases: ValueError

Raised when a time-based phase is requested without a period.