diff --git a/CHANGELOG.md b/CHANGELOG.md index 7071866..b6e8377 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Added sunshield rotation calculation for NEO Surveyor. + + ## [0.3.0] - 2024 - 8 - 28 diff --git a/docs/code_structure.rst b/docs/code_structure.rst index 2086987..7b41f87 100644 --- a/docs/code_structure.rst +++ b/docs/code_structure.rst @@ -1,13 +1,12 @@ Code Organization ================= -Goals of kete ---------------- -kete is a collection of tools for calculating the orbits and expected fluxes for minor -planets specifically for the purpose of estimating which objects are visible in current, -past, or future sky surveys. Specifically the goal is that these calculations may be -performed on the full set of all known asteroids in a reasonable amount of time on a -laptop. +Goals of Kete +------------- +Kete is a collection of tools for calculating the orbits and expected fluxes for minor +planets for the purpose of estimating which objects are visible in current, past, or +future sky surveys. Specifically the goal is that these calculations may be performed +on the full set of all known asteroids in a reasonable amount of time on a laptop. Propagation ~~~~~~~~~~~ @@ -37,7 +36,7 @@ decades at this point, and is often used to keep track of the ephemeris of plane satellites (both natural and artificial), asteroids, and comets. Essentially the motion of anything in the Solar System can be encoded in some flavor of SPICE kernel. The primary downside of using cSPICE is that there is no native support for multi-core cpu -queries (an artifact of the age of the code). kete has native multi-core support for +queries (an artifact of the age of the code). Kete has native multi-core support for the majority of all commonly used SPICE kernels. @@ -59,8 +58,8 @@ the most common type of errors to do with memory allocation and management. In a to this, Rust has excellent native multi-core support, especially for embarrassingly parallel problems such as the orbit propagation required for kete. -kete Core -~~~~~~~~~~~ +Kete Core +~~~~~~~~~ The Rust core of the library, which does the underlying orbit and flux calculations is written entirely without any reference to Python. This core part is available as `kete_core`, and programming can be done entirely within Rust for tools which do not @@ -80,8 +79,8 @@ the `kete_core`. Ideally there should be no 'business' logic contained within th wrappers, and they should largely exist to provide convenient mappings from the Python concepts to the Rust internal organization. -kete Python -~~~~~~~~~~~~~ +Kete Python +~~~~~~~~~~~ The remaining part of the code which is strictly Python is mostly quality of life functions, plotting, and web query code. There is little to no mathematics or physics contained within the Python. \ No newline at end of file diff --git a/src/kete/neos.py b/src/kete/neos.py index eb3c5bc..193b57d 100644 --- a/src/kete/neos.py +++ b/src/kete/neos.py @@ -1,3 +1,5 @@ +import numpy as np + BANDS: list[float] = [4700.0, 8000.0] """Effective wavelength of the NC1 and NC2 bands in nm.""" @@ -22,3 +24,74 @@ [500.0, 1.01897, 0.96149], ] """Expected color correction required for black body sources at 300k""" + + +def sunshield_rotation(sun2obs, pointing): + """ + Calculate the angle the field of view must be rotated around the pointing + vector by in order to place the sun shield directly between the telescope + and sun. + + The rotation is defined as the angle needed to move the sun shield from + the Z-axis down to the angle required to place it between the + sun and telescope. The angle is defined by the right hand rule applied + along the pointing vector. + + Pointing vector must be at least about a half an arcsecond from the poles + in order to be computable. + + Note that no coordinate frames are specified here, this provides the + rotation in the current frame from the frame's Z-axis. Provided inputs + are assumed to be from the matching frame. + + Parameters + ---------- + sun2obs : + The vector from the spacecraft to the observer, units are arbitrary, + must be 1 dimensional. + pointing : + The vector along which the telescope is pointing, the spacecraft's + Z-axis. + + Returns + ------- + float + Angle in degrees around the pointing vector the spacecraft must be + rotated to place the sun shield between the telescope and the sun. + """ + obs2sun = -np.array(sun2obs) + + # normalize for safety + pointing = np.array(pointing) / np.linalg.norm(pointing) + + # The normal vector for the plane defined by the sun and pointing vectors. + sun_plane_normal = np.cross(obs2sun, pointing) + sun_plane_normal /= np.linalg.norm(sun_plane_normal) + + # Assuming that the spacecraft body z is along the pointing vector and + # body y-axis (sun shield) is facing directly up in the current frame. + # This means the body x-axis is defined by: + # sc_x = cross((0, 0, 1), pointing) = (-pointing.y, pointing.x, 0) + # This vector is the normal through the plane defined by the pointing and + # the Z-axis of the plane. + obs_body_x = np.array([-pointing[1], pointing[0], 0]) + + r = np.linalg.norm(obs_body_x) + if r < 1e-6: + # Safety check, this definition is bad near poles. + raise ValueError( + ( + "Nearly pointing at the pole, cannot compute within about half " + "an arcsecond of the pole. It is strongly recommended to not " + "use this angular definition so close to poles, quaternions are " + "the better choice." + ) + ) + obs_body_x /= r + + # The great circle distance from the body_x to the sun_plane_normal is + # an absolute rotation, so if the sun is on the "left" vs "right" + # is not captured, and an additional calculation is needed to find + # the sign of the rotation. + sign = np.sign(np.dot(obs_body_x, obs2sun)) + return sign * np.degrees(np.arccos(np.dot(sun_plane_normal, obs_body_x)))