NPlateSRPCore#

class NPlateSRPCore(p_srp: float, areas: ndarray, diff_ref: ndarray, spec_ref: ndarray, double_sided: List[bool] | None = None)#

Bases: object

N-plate SRP kernels.

Computational core of nPlateSRP: the per-plate illumination sums for the acceleration and the position / velocity Jacobians, plus the spacecraft-fixed <-> inertial mapping. Attitude resolution (and its state derivatives), the Sun ephemeris and eta_srp lookup stay on the Python side, which passes the results in.

Let \(\mathbf{C}\) be the SC-fixed to inertial DCM (dcm_b2i), \(\mathbf{s} = -\mathbf{C}^T \mathbf{r}_{\odot \to sc}\) the SC-fixed spacecraft-to-Sun vector, \(r = |\mathbf{s}|\), \(\hat{\mathbf{s}} = \mathbf{s}/r\) and \(\cos\theta_i = \hat{\mathbf{n}}_i \cdot \hat{\mathbf{s}}\). Plate \(i\) has area \(A_i\), specular and diffuse reflectivities \(\rho_{s,i}\) and \(\rho_{d,i}\). Summed over the lit plates, the SC-fixed acceleration [1] is

\[\mathbf{T} = -\frac{\eta\, P_{SRP}}{m\, r^2} \sum_{\cos\theta_i > 0} A_i \cos\theta_i \left[ (1 - \rho_{s,i})\, \hat{\mathbf{s}} + \left(\tfrac{2}{3}\rho_{d,i} + 2\rho_{s,i}\cos\theta_i\right) \hat{\mathbf{n}}_i \right],\]

and the inertial one is \(\mathbf{a} = \mathbf{C}\,\mathbf{T}\). With \(p_i = \mathbf{n}_i \cdot \mathbf{s}\), \(c_i = \eta P_{SRP} A_i / m\), \(a_i = -c_i(1-\rho_{s,i})\), \(b_i = -\tfrac{2}{3}c_i\rho_{d,i}\) and \(d_i = -2c_i\rho_{s,i}\), the kernel writes it as \(\mathbf{T} = \sum a_i p_i\, \mathbf{s}/r^4 + \sum b_i p_i\, \mathbf{n}_i/r^3 + \sum d_i p_i^2\, \mathbf{n}_i/r^4\), whose gradient is

\[\begin{split}\frac{\partial \mathbf{T}}{\partial \mathbf{s}} &= \frac{\left(\sum a_i p_i\right) \mathbf{I} + \mathbf{s} \left(\sum a_i \mathbf{n}_i\right)^T}{r^4} - \frac{4 \left(\sum a_i p_i\right) \mathbf{s}\mathbf{s}^T}{r^6} + \frac{\sum b_i \mathbf{n}_i \mathbf{n}_i^T}{r^3} - \frac{3 \left(\sum b_i p_i \mathbf{n}_i\right) \mathbf{s}^T}{r^5} \\ &\quad + \frac{2 \sum d_i p_i \mathbf{n}_i \mathbf{n}_i^T}{r^4} - \frac{4 \left(\sum d_i p_i^2 \mathbf{n}_i\right) \mathbf{s}^T}{r^6}.\end{split}\]

The inertial Jacobians follow by the chain rule through \(\mathbf{s}\) and the attitude:

\[\begin{split}\frac{\partial \mathbf{a}}{\partial r_k} &= \frac{\partial \mathbf{C}}{\partial r_k} \mathbf{T} + \mathbf{C} \frac{\partial \mathbf{T}}{\partial \mathbf{s}} \left(-\mathbf{C}^T \mathbf{e}_k - \frac{\partial \mathbf{C}^T}{\partial r_k} \mathbf{r}_{\odot \to sc}\right), \\ \frac{\partial \mathbf{a}}{\partial v_k} &= \frac{\partial \mathbf{C}}{\partial v_k} \mathbf{T} - \mathbf{C} \frac{\partial \mathbf{T}}{\partial \mathbf{s}} \frac{\partial \mathbf{C}^T}{\partial v_k} \mathbf{r}_{\odot \to sc}.\end{split}\]

For a fixed attitude the position Jacobian reduces to \(-\mathbf{C}\, (\partial \mathbf{T}/\partial \mathbf{s})\, \mathbf{C}^T\) and the velocity Jacobian vanishes.

The kernel is generic over f64 and dual numbers, so compute_partials_ad differentiates the exact function that compute_acceleration evaluates.

Parameters:
p_srpfloat

Solar radiation pressure constant, \(P_{SRP}\): the pressure at 1 AU times 1 AU squared, in kg km s^-2.

areasnp.ndarray

(N,) plate areas in km^2.

diff_refnp.ndarray

(N,) diffuse reflectivity coefficients.

spec_refnp.ndarray

(N,) specular reflectivity coefficients.

double_sidedlist[bool], optional

(N,) flags; a double-sided plate lit from behind acts as a plate with the opposite normal. Defaults to all single-sided.

Methods

compute_acceleration(sun2body, dcm_b2i, ...)

Inertial SRP acceleration, in km/s^2.

compute_jacobian(sun2body, dcm_b2i, eta_srp, ...)

Analytical inertial position Jacobian, in 1/s^2, flattened row-major.

compute_jacobian_by_velocity(sun2body, ...)

Analytical inertial velocity Jacobian, in 1/s, flattened row-major.

compute_partials_ad(sun2body, dcm_b2i, ...)

Dual-number reference partials of compute_acceleration.

References

[1]

P. W. Kenneally, “High geometric fidelity solar radiation pressure modeling via graphics processing unit,” Master’s thesis, University of Colorado Boulder, 2016.

compute_acceleration(sun2body: list, dcm_b2i: ndarray, eta_srp: float, mass: float, normals: ndarray) → List[float]#

Inertial SRP acceleration, in km/s^2.

sun2body is the inertial Sun->spacecraft vector (km), dcm_b2i the (3, 3) SC-fixed -> inertial DCM, mass in kg and normals the (N, 3) SC-fixed plate outward normals.

compute_jacobian(sun2body: list, dcm_b2i: ndarray, eta_srp: float, mass: float, normals: ndarray, dcm_dr: TypeAliasForwardRef('numpy.ndarray') | None = None) → List[float]#

Analytical inertial position Jacobian, in 1/s^2, flattened row-major.

-DCM @ dT/ds @ DCM^T, with s the SC-fixed body->Sun vector and T the SC-fixed acceleration. When the attitude follows the position (nadir pointing), dcm_dr is the (3, 3, 3) derivative dcm_dr[j, i, k] = dDCM[i, j]/dr_k and the attitude terms are added. Normals and mass are held fixed.

compute_jacobian_by_velocity(sun2body: list, dcm_b2i: ndarray, eta_srp: float, mass: float, normals: ndarray, dcm_dv: ndarray) → List[float]#

Analytical inertial velocity Jacobian, in 1/s, flattened row-major.

Non-zero only through the attitude: dcm_dv is the (3, 3, 3) derivative dcm_dv[j, i, k] = dDCM[i, j]/dv_k (nadir pointing).

compute_partials_ad(sun2body: list, dcm_b2i: ndarray, eta_srp: float, mass: float, normals: ndarray, dcm_dr: TypeAliasForwardRef('numpy.ndarray') | None = None, dcm_dv: TypeAliasForwardRef('numpy.ndarray') | None = None) → tuple[List[float], List[float], List[float]]#

Dual-number reference partials of compute_acceleration.

Returns (da/dr, da/dv, da/d eta_srp), the Jacobians flattened row-major. The DCM is seeded through dcm_dr / dcm_dv when given (da/dv is zero without dcm_dv); normals, mass and the Sun position are held fixed, so d sun2body / dr = I. Used by check_force_model_partials.