Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
helgee committed Dec 13, 2024
1 parent 3b39c3d commit 1f12032
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 93 deletions.
2 changes: 1 addition & 1 deletion crates/lox-earth/src/cio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@

//! Module cio exposes functions for calculating the Celestial Intermediate Origin (CIO) locator, s.
mod s06;
pub mod s06;
1 change: 1 addition & 0 deletions crates/lox-earth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ pub mod cip;
pub mod coordinate_transformations;
pub mod nutation;
pub mod rotation_angle;
#[allow(dead_code)]
pub mod tides;
pub mod tio;
74 changes: 68 additions & 6 deletions crates/lox-orbits/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::f64::consts::PI;
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*/
use lox_bodies::{Origin, RotationalElements, Spheroid};
use lox_bodies::{MaybeSpheroid, Origin, RotationalElements, Spheroid};
use lox_math::roots::Brent;
use lox_math::series::{Series, SeriesError};
use lox_math::types::units::Radians;
Expand All @@ -19,9 +19,12 @@ use lox_time::TimeLike;
use thiserror::Error;

use crate::events::{find_windows, Window};
use crate::frames::{BodyFixed, FrameTransformationProvider, Icrf, TryToFrame};
use crate::ground::GroundLocation;
use crate::trajectories::Trajectory;
use crate::frames::{
BodyFixed, DynFrame, FrameTransformationProvider, Icrf, ReferenceFrame, TryRotateTo, TryToFrame,
};
use crate::ground::{DynGroundLocation, GroundLocation};
use crate::states::State;
use crate::trajectories::{DynTrajectory, Trajectory};

#[derive(Debug, Clone, Error, PartialEq)]
pub enum ElevationMaskError {
Expand Down Expand Up @@ -61,9 +64,59 @@ impl ElevationMask {
}
}

pub fn elevation_dyn<T: TimeLike + TryToScale<Tdb, P> + Clone, P: FrameTransformationProvider>(

Check warning on line 67 in crates/lox-orbits/src/analysis.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/analysis.rs#L67

Added line #L67 was not covered by tests
time: T,
gs: &DynGroundLocation,
mask: &ElevationMask,
sc: &DynTrajectory<T>,

Check warning on line 71 in crates/lox-orbits/src/analysis.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/analysis.rs#L69-L71

Added lines #L69 - L71 were not covered by tests
provider: &P,
) -> Radians {
let body_fixed = DynFrame::BodyFixed(gs.origin());
let sc = sc.interpolate_at(time.clone());
let rot = DynFrame::Icrf.try_rotation(&body_fixed, time, provider);
let (r1, v1) = rot.unwrap().rotate_state(sc.position(), sc.velocity());
let sc = State::new(sc.time(), r1, v1, sc.origin(), body_fixed);
let obs = gs.observables_dyn(sc);
obs.elevation() - mask.min_elevation(obs.azimuth())

Check warning on line 80 in crates/lox-orbits/src/analysis.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/analysis.rs#L74-L80

Added lines #L74 - L80 were not covered by tests
}

pub fn visibility_dyn<T: TimeLike + TryToScale<Tdb, P> + Clone, P: FrameTransformationProvider>(
times: &[T],
gs: &DynGroundLocation,
mask: &ElevationMask,
sc: &DynTrajectory<T>,
provider: &P,
) -> Vec<Window<T>> {
if times.len() < 2 {
return vec![];
}
let start = times.first().unwrap().clone();
let end = times.last().unwrap().clone();
let times: Vec<f64> = times
.iter()
.map(|t| (t.clone() - start.clone()).to_decimal_seconds())
.collect();
let root_finder = Brent::default();
find_windows(
|t| {
elevation_dyn(
start.clone() + TimeDelta::from_decimal_seconds(t).unwrap(),
gs,
mask,
sc,
provider,
)
},
start.clone(),
end.clone(),
&times,
root_finder,
)
}

Check warning on line 115 in crates/lox-orbits/src/analysis.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/analysis.rs#L83-L115

Added lines #L83 - L115 were not covered by tests

pub fn elevation<
T: TimeLike + TryToScale<Tdb, P> + Clone,
O: Origin + Spheroid + RotationalElements + Clone,
O: Origin + MaybeSpheroid + RotationalElements + Clone,
P: FrameTransformationProvider,
>(
time: T,
Expand Down Expand Up @@ -136,14 +189,23 @@ mod tests {
fn test_elevation() {
let gs = ground_station_trajectory();
let sc = spacecraft_trajectory();
let mask = ElevationMask::with_fixed_elevation(0.0);
let expected: Vec<Radians> = include_str!("../../../data/elevation.csv")
.lines()
.map(|line| line.parse::<f64>().unwrap().to_radians())
.collect();
let actual: Vec<Radians> = gs
.times()
.iter()
.map(|t| elevation(*t, &gs, &sc, &NoOpFrameTransformationProvider))
.map(|t| {
elevation(
*t,
&location(),
&mask,
&sc,
&NoOpFrameTransformationProvider,
)
})
.collect();
for (actual, expected) in actual.iter().zip(expected.iter()) {
assert_close!(actual, expected, 1e-1);
Expand Down
130 changes: 104 additions & 26 deletions crates/lox-orbits/src/frames.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@

use std::{convert::Infallible, str::FromStr};

use crate::frames::iau::icrf_to_bodyfixed;
use crate::frames::iers::{cirf_to_tirf, icrf_to_cirf, tirf_to_itrf};
use crate::rotations::Rotation;
use glam::{DMat3, DVec3};
use lox_bodies::{DynOrigin, MaybeRotationalElements, Origin, RotationalElements, Spheroid};
use lox_math::types::units::Seconds;
use lox_time::transformations::OffsetProvider;
use lox_time::prelude::Tdb;
use lox_time::transformations::{OffsetProvider, TryToScale};
use lox_time::TimeLike;
use thiserror::Error;

use crate::rotations::Rotation;

mod iau;
mod iers;

Expand Down Expand Up @@ -205,10 +208,12 @@ impl ReferenceFrame for DynFrame {

fn parse_iau_frame(s: &str) -> Option<DynFrame> {
let (prefix, origin) = s.split_once("_")?;
dbg!(prefix);
dbg!(origin);
if prefix.to_lowercase() != "iau" {
return None;
}
let origin: DynOrigin = origin.parse().ok()?;
let origin: DynOrigin = origin.to_lowercase().parse().ok()?;
let _ = origin.maybe_rotational_elements(0.0)?;
Some(DynFrame::BodyFixed(origin))
}
Expand Down Expand Up @@ -237,33 +242,106 @@ impl FromStr for DynFrame {
}

Check warning on line 242 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L242

Added line #L242 was not covered by tests
}

pub trait RotateTo<T: ReferenceFrame> {
type Time;

fn rotation(&self, frame: &T, time: Self::Time) -> Rotation;
}

pub trait TryRotateTo<T: ReferenceFrame> {
type Time;
pub trait TryRotateTo<R: ReferenceFrame, P: FrameTransformationProvider> {
type Error;

fn try_rotation(&self, frame: &T) -> Result<Rotation, Self::Error>;
fn try_rotation<T: TimeLike + Clone>(
&self,
frame: &R,
time: T,
provider: &P,
) -> Result<Rotation, Self::Error>;
}

impl<T: ReferenceFrame, U: RotateTo<T>> TryRotateTo<T> for U {
type Error = Infallible;

fn try_rotation(&self, frame: &T) -> Result<Rotation, Self::Error> {
Ok(self.rotation(frame))
}
}

impl TryRotateTo<DynFrame> for DynFrame {
type Error = ();

fn try_rotation(&self, frame: &DynFrame) -> Result<Rotation, Self::Error> {
impl<P: FrameTransformationProvider> TryRotateTo<DynFrame, P> for DynFrame {
// FIXME
type Error = String;

fn try_rotation<T: TimeLike + Clone>(
&self,
frame: &DynFrame,
time: T,
provider: &P,
) -> Result<Rotation, Self::Error> {
// FIXME
let seconds_j2000 = time.seconds_since_j2000();
let centuries_j2000 = time.centuries_since_j2000();
match self {
_ => todo!(),
DynFrame::Icrf => match frame {
DynFrame::Icrf => Ok(Rotation::IDENTITY),
DynFrame::Cirf => Ok(icrf_to_cirf(centuries_j2000)),

Check warning on line 272 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L260-L272

Added lines #L260 - L272 were not covered by tests
DynFrame::Tirf => {
Ok(icrf_to_cirf(centuries_j2000).compose(&cirf_to_tirf(seconds_j2000)))

Check warning on line 274 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L274

Added line #L274 was not covered by tests
}
DynFrame::Itrf => Ok(icrf_to_cirf(centuries_j2000)
.compose(&cirf_to_tirf(seconds_j2000))
.compose(&tirf_to_itrf(centuries_j2000))),
DynFrame::BodyFixed(target) => icrf_to_bodyfixed(target, seconds_j2000).ok_or(
format!("no rotational parameters available for {}", target.name()),
),

Check warning on line 281 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L276-L281

Added lines #L276 - L281 were not covered by tests
},
DynFrame::Cirf => match frame {
DynFrame::Icrf => Ok(icrf_to_cirf(centuries_j2000).transpose()),
DynFrame::Cirf => Ok(Rotation::IDENTITY),
DynFrame::Tirf => Ok(cirf_to_tirf(seconds_j2000)),

Check warning on line 286 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L283-L286

Added lines #L283 - L286 were not covered by tests
DynFrame::Itrf => {
Ok(cirf_to_tirf(seconds_j2000).compose(&tirf_to_itrf(centuries_j2000)))

Check warning on line 288 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L288

Added line #L288 was not covered by tests
}
DynFrame::BodyFixed(_) => Ok(self
.try_rotation(&DynFrame::Icrf, time.clone(), provider)?
.compose(&DynFrame::Icrf.try_rotation(frame, time, provider)?)),

Check warning on line 292 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L290-L292

Added lines #L290 - L292 were not covered by tests
},
DynFrame::Tirf => match frame {
DynFrame::Icrf => Ok(cirf_to_tirf(seconds_j2000)
.transpose()
.compose(&icrf_to_cirf(centuries_j2000).transpose())),
DynFrame::Cirf => Ok(cirf_to_tirf(seconds_j2000).transpose()),
DynFrame::Tirf => Ok(Rotation::IDENTITY),
DynFrame::Itrf => Ok(tirf_to_itrf(centuries_j2000)),
DynFrame::BodyFixed(_) => Ok(self
.try_rotation(&DynFrame::Icrf, time.clone(), provider)?
.compose(&DynFrame::Icrf.try_rotation(frame, time, provider)?)),

Check warning on line 303 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L294-L303

Added lines #L294 - L303 were not covered by tests
},
DynFrame::Itrf => match frame {
DynFrame::Icrf => Ok(tirf_to_itrf(centuries_j2000)
.transpose()
.compose(&cirf_to_tirf(seconds_j2000).transpose())
.compose(&icrf_to_cirf(centuries_j2000).transpose())),
DynFrame::Cirf => Ok(tirf_to_itrf(centuries_j2000)
.transpose()
.compose(&cirf_to_tirf(seconds_j2000).transpose())),
DynFrame::Tirf => Ok(tirf_to_itrf(centuries_j2000).transpose()),
DynFrame::Itrf => Ok(Rotation::IDENTITY),
DynFrame::BodyFixed(_) => Ok(self
.try_rotation(&DynFrame::Icrf, time.clone(), provider)?
.compose(&DynFrame::Icrf.try_rotation(frame, time, provider)?)),

Check warning on line 317 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L305-L317

Added lines #L305 - L317 were not covered by tests
},
DynFrame::BodyFixed(origin) => match frame {
DynFrame::Icrf => Ok(icrf_to_bodyfixed(origin, seconds_j2000)
.ok_or(format!(
"no rotational parameters available for {}",
origin.name()
))?
.transpose()),
DynFrame::Cirf => Ok(self
.try_rotation(&DynFrame::Icrf, time.clone(), provider)?
.compose(&DynFrame::Icrf.try_rotation(frame, time, provider)?)),
DynFrame::Tirf => Ok(self
.try_rotation(&DynFrame::Icrf, time.clone(), provider)?
.compose(&DynFrame::Icrf.try_rotation(frame, time, provider)?)),
DynFrame::Itrf => Ok(self
.try_rotation(&DynFrame::Icrf, time.clone(), provider)?
.compose(&DynFrame::Icrf.try_rotation(frame, time, provider)?)),
DynFrame::BodyFixed(target) => {
if origin == target {
Ok(Rotation::IDENTITY)

Check warning on line 337 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L319-L337

Added lines #L319 - L337 were not covered by tests
} else {
Ok(self
.try_rotation(&DynFrame::Icrf, time.clone(), provider)?
.compose(&DynFrame::Icrf.try_rotation(frame, time, provider)?))

Check warning on line 341 in crates/lox-orbits/src/frames.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames.rs#L339-L341

Added lines #L339 - L341 were not covered by tests
}
}
},
}
}
}
Expand Down
47 changes: 47 additions & 0 deletions crates/lox-orbits/src/frames/iau.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024. Helge Eichhorn and the LOX contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*/
use crate::frames::{BodyFixed, FrameTransformationProvider, Icrf, TryRotateTo};
use crate::rotations::Rotation;
use glam::{DMat3, DVec3};
use lox_bodies::{MaybeRotationalElements, RotationalElements};
use lox_math::types::units::Seconds;
use lox_time::prelude::Tdb;
use lox_time::TimeLike;

pub(crate) fn icrf_to_bodyfixed<T: MaybeRotationalElements>(
body: &T,
seconds: Seconds,
) -> Option<Rotation> {
let (Some((right_ascension, declination, prime_meridian)), Some(rates)) = (
body.maybe_rotational_elements(seconds),
body.maybe_rotational_element_rates(seconds),

Check warning on line 22 in crates/lox-orbits/src/frames/iau.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames/iau.rs#L16-L22

Added lines #L16 - L22 were not covered by tests
) else {
return None;

Check warning on line 24 in crates/lox-orbits/src/frames/iau.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames/iau.rs#L24

Added line #L24 was not covered by tests
};
let m1 = DMat3::from_rotation_z(-right_ascension);
let m2 = DMat3::from_rotation_x(-declination);
let m3 = DMat3::from_rotation_z(-prime_meridian);
let m = m3 * m2 * m1;
let v = DVec3::from(rates);
Some(Rotation::new(m).with_angular_velocity(v))
}

Check warning on line 32 in crates/lox-orbits/src/frames/iau.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames/iau.rs#L26-L32

Added lines #L26 - L32 were not covered by tests

impl<O: RotationalElements, P: FrameTransformationProvider> TryRotateTo<BodyFixed<O>, P> for Icrf {
type Error = ();

fn try_rotation<T: TimeLike>(
&self,
frame: &BodyFixed<O>,
time: T,
provider: &P,
) -> Result<Rotation, Self::Error> {
// FIXME
let seconds = time.seconds_since_j2000();
Ok(icrf_to_bodyfixed(&frame.0, seconds).unwrap())
}

Check warning on line 46 in crates/lox-orbits/src/frames/iau.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames/iau.rs#L37-L46

Added lines #L37 - L46 were not covered by tests
}
37 changes: 32 additions & 5 deletions crates/lox-orbits/src/frames/iers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,38 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*/
use crate::frames::{Cirf, Icrf, RotateTo};
use crate::rotations::Rotation;
use glam::{DMat3, DVec2, DVec3};
use lox_bodies::{Earth, RotationalElements};
use lox_earth::cio::s06::s;
use lox_earth::cip::xy06::xy;
use lox_earth::coordinate_transformations::{
celestial_to_intermediate_frame_of_date_matrix, polar_motion_matrix,
};
use lox_earth::rotation_angle::RotationAngle;
use lox_earth::tio::sp_00;
use lox_math::constants::f64::time::SECONDS_PER_DAY;

impl RotateTo<Cirf> for Icrf {
fn rotation(&self, _: &Cirf) -> Rotation {
todo!()
}
pub fn icrf_to_cirf(centuries: f64) -> Rotation {
// TODO: Add IERS corrections
let cip_coords = xy(centuries);
let cio_locator = s(centuries, cip_coords);
let m = celestial_to_intermediate_frame_of_date_matrix(cip_coords, cio_locator);
Rotation::new(m)
}

Check warning on line 26 in crates/lox-orbits/src/frames/iers.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames/iers.rs#L20-L26

Added lines #L20 - L26 were not covered by tests

pub fn cirf_to_tirf(seconds: f64) -> Rotation {
let era = Earth::rotation_angle_00(seconds / SECONDS_PER_DAY);
let rate = Earth.prime_meridian_dot(seconds);
let m = DMat3::from_rotation_z(-era);
let v = DVec3::new(0.0, 0.0, rate);
Rotation::new(m).with_angular_velocity(v)
}

Check warning on line 34 in crates/lox-orbits/src/frames/iers.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames/iers.rs#L28-L34

Added lines #L28 - L34 were not covered by tests

pub fn tirf_to_itrf(centuries: f64) -> Rotation {
// TODO: Add IERS corrections
let pole_coords: DVec2 = (0.0, 0.0).into();
let tio_locator = sp_00(centuries);
let m = polar_motion_matrix(pole_coords, tio_locator);
Rotation::new(m)
}

Check warning on line 42 in crates/lox-orbits/src/frames/iers.rs

View check run for this annotation

Codecov / codecov/patch

crates/lox-orbits/src/frames/iers.rs#L36-L42

Added lines #L36 - L42 were not covered by tests
Loading

0 comments on commit 1f12032

Please sign in to comment.