|
| 1 | +# Analysis Engine |
| 2 | + |
| 3 | +ANISE includes a powerful **Analysis Engine** designed to answer complex astrodynamics questions declaratively. Instead of writing imperative loops to check conditions at every time step, you define *what* you want to compute, and ANISE figures out *how* to compute it efficiently. |
| 4 | + |
| 5 | +## Core Philosophy |
| 6 | + |
| 7 | +The analysis engine is built on three pillars: |
| 8 | + |
| 9 | +1. **Declarative Queries**: You describe the state of the system (e.g., "The distance between Earth and Mars") as an expression tree, rather than a sequence of math operations. |
| 10 | +2. **Continuous Resolution**: Unlike simple step-by-step propagation, the engine uses root-finding algorithms (specifically the **Brent solver**) to find exact times of events, such as when a satellite enters an eclipse or crosses a specific altitude. |
| 11 | +3. **Serialization**: All queries can be serialized to **S-expressions** (symbolic expressions). This allows you to define a query in Python, send it to a remote Rust/Python worker, and execute it safely without allowing arbitrary code execution. |
| 12 | + |
| 13 | +## Expression Trees |
| 14 | + |
| 15 | +Everything in the analysis engine is an **Expression**. These expressions can be nested to form complex queries. |
| 16 | + |
| 17 | +- **`StateSpec`**: Defines the "Context" of an orbital state. Who is the target? Who is the observer? What frame are we in? |
| 18 | + - *Example*: "LRO (Target) as seen from the Moon (Observer) in the Moon Body-Fixed frame." |
| 19 | +- **`VectorExpr`**: Computes a 3D vector. |
| 20 | + - *Examples*: `Radius`, `Velocity`, `SunVector`, `OrbitalMomentum`. |
| 21 | +- **`ScalarExpr`**: Computes a single floating-point number. |
| 22 | + - *Examples*: `Norm` (of a vector), `DotProduct`, `AngleBetween`, `OrbitalElement` (eccentricity, SMA), `ShadowFunction`. |
| 23 | +- **`DcmExpr`**: Defines how to compute a direct cosine matrix, used to correctly align instruments with respect to the orbit frame |
| 24 | + - *Examples*: `Triad` for an align/clock vector setup, `R1` for a rotation about X |
| 25 | + |
| 26 | +### Example |
| 27 | +To compute the **Beta Angle** (angle between the orbit plane and the vector to the Sun), you don't write a function. You build it: |
| 28 | + |
| 29 | +```rust |
| 30 | +// In pseudo-code representation of the internal tree |
| 31 | +Shape: AngleBetween( |
| 32 | + VectorA: SunVector(Observer), |
| 33 | + VectorB: OrbitalMomentum(Target, Observer) |
| 34 | +) |
| 35 | +``` |
| 36 | + |
| 37 | +## Event Finding (The Superlinear Solver) |
| 38 | + |
| 39 | +One of ANISE's most powerful features is its ability to find **Events**. An Event is defined by a `ScalarExpr` and a `Condition`. |
| 40 | + |
| 41 | +- **Scalar**: Any continuous values (e.g., "Elevation Angle"). |
| 42 | +- **Condition**: A threshold or extrema (e.g., `= 4.57 deg`, `> 5.0 deg`, `Maximum`, `Minimum`). |
| 43 | + |
| 44 | +### The Problem with Steps |
| 45 | +If you simply loop through time with a 1-minute step, you might miss short events (like a 30-second eclipse) or get inaccurate start/stop times. |
| 46 | + |
| 47 | +### The ANISE Solution: Brent's Method |
| 48 | +ANISE uses an adaptive checking method combined with **Brent's method** for root finding. |
| 49 | + |
| 50 | +1. **Search**: It scans the time domain using an adapative step scanner inspired from adaptive step Runge Kutta methods |
| 51 | +2. **Bracket**: When it detects that the condition changed (e.g., elevation went from negative to positive), it knows a root (0 crossings) exists in that interval. |
| 52 | +3. **Solve**: It deploys the Brent solver to find the *exact* event when determining the value crossed the threshold. |
| 53 | + |
| 54 | +This allows for **superlinear convergence**, meaning it finds high-precision times with very few function evaluations compared to brute-force searching. |
| 55 | + |
| 56 | +## Reporting |
| 57 | + |
| 58 | +The engine provides three main reporting modes: |
| 59 | + |
| 60 | +1. **`report_scalars`**: Evaluates a list of expressions at fixed time steps. This is parallelized using `rayon` for maximum speed. |
| 61 | +2. **`report_events`**: Finds discrete instants where a condition happens (e.g., "Apoapsis", "Max Elevation"). |
| 62 | +3. **`report_event_arcs`**: Finds durations where a condition holds true (e.g., "Eclipse Duration", "Comm Window"). |
| 63 | +4. **`report_visibility_arcs`**: Compute the Azimuth, Elevation, Range, and Range-rate ("AER") for each communication pass from a given location on _any_ celestial object. |
| 64 | + |
| 65 | +## Safety and S-Expressions |
| 66 | + |
| 67 | +Because analysis queries are just data structures (enums), they can be serialized into a lisp-like S-expression format. |
| 68 | + |
| 69 | +```lisp |
| 70 | +(Event |
| 71 | + (scalar (AngleBetween (Radius) (SunVector))) |
| 72 | + (condition (LessThan 90.0)) |
| 73 | +) |
| 74 | +``` |
| 75 | + |
| 76 | +This is critical for web services or distributed systems. A client can craft a complex query and send it to a server. The server parses the S-expression and executes it. Because the server *only* executes valid ANISE expressions, there is **no risk of arbitrary code injection**, unlike pickling Python objects or sending raw scripts. |
0 commit comments