f2m package¶
Subpackages¶
Submodules¶
f2m.ampl_interface module¶
- class f2m.ampl_interface.AMPLModel(ampl_mod_path: str, auto_reset: bool = True)¶
Bases:
objectCode from https://gitlab.com/EuropeanSpaceAgency/trajectory-to-events
- checkSolved()¶
- coerceSpecialVariable(var_name)¶
- display(*args)¶
- getAMPL()¶
- getConstraint(name)¶
- getConstraints()¶
- getObjective(name)¶
- getObjectiveShape(obj_name)¶
- getObjectiveValue(obj_name)¶
- getObjectiveValues(name_list=None)¶
- getObjectives()¶
- getParamShape(param_name)¶
- getParameter(name)¶
- getParameterValue(param_name)¶
- getParameterValues(name_list=None)¶
- getParameters()¶
- getSetSize(set_name)¶
- getSolutionValues(name_list=None)¶
- getSpecialVariable(name_list=None)¶
- getVarShape(var_name)¶
- getVariable(name)¶
- getVariableValue(var_name)¶
- getVariableValues(name_list=None)¶
- getVariables()¶
- items()¶
- keys()¶
- reset()¶
- setParameterValue(param_name, param_value)¶
- setParameterValues(param_dict={}, **kwargs)¶
- showAMPLOutput()¶
- solve(hide_solver_output=True)¶
- solveAsync(callback, hide_solver_output=True)¶
- f2m.ampl_interface.extract_ocp_params(p)¶
[DEPRECATED] Extract user-defined parameters for the OCP
- f2m.ampl_interface.sample_ocp_params(traj_config, parameter)¶
[DEPRECATED] Sample specified trajectory parameter range to generate new OCP
- Parameters:
traj_config (dict) – Trajectory configuration
parameter (str) – Parameter to sample
Returns:
f2m.camera_noise module¶
- f2m.camera_noise.add_gaussian_noise(image: ndarray, std: float = 6, cosmic_rays_outliers: bool = True, framerate: int = 4) ndarray¶
f2m.motion_field module¶
- f2m.motion_field.least_squares_estimation(vars: dict[str, float], pars: dict[str, float], points: ndarray, flow: ndarray, focal_length: float, framerate: int, image_width: int, target_radius: int | None = None, stable_depth: bool = False, least_squares_kwargs: dict = {}) OptimizeResult¶
Estimate the spacecraft state using least squares optimization over motion field equations. If the system is linear, linear least squares will be used, otheriwse a non-linear version will be used.
- Parameters:
vars (dict[str, float]) – variables to optimize. The keys are the variable names and the values are the initial guesses.
pars (dict[str, float]) – parameters with known values
points (np.ndarray) – points in the image plane, shape (n, 2)
flow (np.ndarray) – optical flow vectors corresponding to points, shape (n, 2)
focal_length (float) – camera focal length related to the image width
framerate (int) – camera framerate
image_width (int) – image width, in pixels
target_radius (int, optional) – radius of the target in meters. Defaults to None (planar case)
stable_depth (bool, optional) – If True, replaces NaN depth values with the maximum depth
least_squares_kwargs (dict, optional) – additional arguments to pass to scipy.optimize.least_squares. Defaults to {}.
- Returns:
optimization result. The x attribute contains the optimized variables
- Return type:
OptimizeResult
- f2m.motion_field.motion_field(sx: float | ndarray, sy: float | ndarray, state: ndarray, fx: float = 1, fy: float = 1, target_radius: float | None = None, alpha: float | None = None, beta: float | None = None, stable_depth: bool = False) tuple[ndarray, ndarray]¶
Computes the motion field assuming a planar or spherical target surface. If target_radius is None, a planar surface is assumed; otherwise, the surface is treated as spherical.
A necessary step to compute the depth map is estimating the surface inclination relative to the camera, which is represented by the components of the unit vector orthogonal to the surface at the center of the image: (alpha, beta, gamma). By default, these values are inferred from the spacecraft state. Specifically, the orientation angles (phi, theta, psi) are used in the planar case, and in the spherical case, the rangefinder measurement (rho) and target_radius are also required.
Alternatively, users can explicitly provide alpha and beta (gamma is inferred from them to complete the unit vector). This is useful when surface geometry is known or constant.
If stable_depth is True, any NaN values in the computed depth map will be replaced by the maximum depth value found in the map.
- Parameters:
sx (float or np.ndarray) – Horizontal image coordinate(s) on the sensor.
sy (float or np.ndarray) – Vertical image coordinate(s) on the sensor.
state (np.ndarray) – Spacecraft state vector [x, y, z, vx, vy, vz, phi, theta, psi, p, q, r, rho]. - x and y are ignored and can be set to any value. - Planar case (target_radius is None): use either theta or z (rho overrides z if present). - Spherical case (target_radius is not None): requires rho; z is ignored.
fx (float, optional) – Horizontal focal length. Defaults to 1.
fy (float, optional) – Vertical focal length. Defaults to 1.
target_radius (float, optional) – Radius of the target in meters. If None, a planar target is assumed.
alpha (float, optional) – X-component of the surface normal vector.
beta (float, optional) – Y-component of the surface normal vector.
stable_depth (bool, optional) – If True, replaces NaN depth values with the maximum depth. Defaults to False.
- Returns:
The horizontal (u) and vertical (v) components of the motion field.
- Return type:
tuple
- f2m.motion_field.ransac_estimation(vars: dict[str, float], pars: dict[str, float], points: ndarray, flow: ndarray, focal_length: float, framerate: int, image_width: int, target_radius: int | None = None, least_squares_kwargs: dict = {}, min_samples: int = 3, residual_threshold: float = 0.1, consensus_threshold: float = 0.75, max_trials: int = 100) dict[str, Any]¶
Estimate the spacecraft state using least squares optimization over motion field equations with RANSAC to handle outliers
- Parameters:
vars (dict[str, float]) – variables to optimize. The keys are the variable names and the values are the initial guesses.
pars (dict[str, float]) – parameters with known values
points (np.ndarray) – points in the image plane, shape (n, 2)
flow (np.ndarray) – optical flow vectors corresponding to points, shape (n, 2)
focal_length (float) – camera focal length related to the image width
framerate (int) – camera framerate
image_width (int) – image width, in pixels
target_radius (int, optional) – radius of the target in meters. Defaults to None (planar case).
least_squares_kwargs (dict, optional) – additional arguments to pass to scipy.optimize.least_squares. Defaults to {}.
min_samples (int, optional) – number of samples to fit the model. Defaults to 3.
residual_threshold (float, optional) – maximum residual to consider an inlier. Defaults to 0.1.
consensus_threshold (float, optional) – minimum ratio of inliers to consider the model valid. Defaults to 0.75.
max_trials (int, optional) – maximum number of iterations. Defaults to 100.
- Returns:
- dictionary with the following keys:
result: optimized variables
mask: boolean mask indicating inliers
iterations: number of iterations
converged: whether the algorithm converged
consensus: ratio of inliers
- Return type:
dict[str, Any]
f2m.optical_flow module¶
- class f2m.optical_flow.LKOpticalFlowEstimator(feature_params: dict = None, lk_params: dict = None, do_histogram_equalization: bool = False, mask: ndarray = None)¶
Bases:
object- forward(img0: ndarray, img1: ndarray, features: ndarray = None, verbose: bool = False) tuple[ndarray, ndarray]¶
Compute the optical flow between two frames
- Parameters:
img0 (np.ndarray) – [3]xHxW cv2 image representing the first frame
img1 (np.ndarray) – [3]xHxW cv2 image representing the second frame
features (np.ndarray) – Nx2 array representing already tracked feature coordinates (Optional)
verbose (bool) – Debugging mode flag
- Returns:
Nx2 array representing features coordinates and Nx2 array representing their flow
- Return type:
tuple[np.ndarray, np.ndarray]
- update_tracked_points(tracked_points: ndarray, image: ndarray, verbose: bool = False) ndarray¶
Detects, filters then adds additional points to the list of tracked points
- Parameters:
tracked_points (np.ndarray) – Nx2 array of position of tracked points in next frame
image (np.ndarray) – [1]xHxW cv2 image representing the grayscale frame of the image
verbose (bool) – Debugging mode flag
- Returns:
Nx2 array of position of tracked points for the next frame of OF
- Return type:
np.ndarray
- f2m.optical_flow.draw_optical_flow(img: ndarray, points: ndarray, flow: ndarray, arrow_scale: float = 3.0, arrow_thickness: int = 2, color: tuple[int, int, int] = (0, 255, 0)) ndarray¶
Draw representation of optical flow
- Parameters:
img (np.ndarray) – cv2 image
points (np.ndarray) – Nx2 array representing features coordinates
flow (np.ndarray) – Nx2 array representing their flow
arrow_scale (float, optional) – scale optical flow arrows for better visualization. Defaults to 3.
arrow_thickness (int, optional) – thickness of the arrows. Defaults to 2.
(tuple[int (color) – color of arrows)
int – color of arrows)
int] – color of arrows)
- Returns:
[2]xHxW representation of the flow
- Return type:
np.ndarray
- f2m.optical_flow.generate_optical_flow_video(frames: ndarray, of_estimator: LKOpticalFlowEstimator, output_path: Path, arrow_scale: float = 3.0, arrow_thickness: int = 2, frame_interval: int = 1, fps: int = 4, verbose: bool = False, save_frames: bool = False) None¶
Generate the optical flow video between all frames
- Parameters:
frames (np.ndarray) – cv2 arrays representing video frames in BGR
of_estimator (LKOpticalFlowEstimator) – optical flow estimator
output_dir (Path) – where to save output frames
arrow_scale (float, optional) – scale optical flow arrows for better visualization. Defaults to 3.
arrow_thickness (int, optional) – thickness of the arrows. Defaults to 2.
frame_interval (int, optional) – Detect new points to track every frame_interval frames. Defaults to 1.
fps (int) – framerate in the output video. Defaults to 4
verbose (bool) – Debugging mode flag
save_frames (bool) – Save frames to disk
f2m.symbolic module¶
- f2m.symbolic.H_numerical(phi, theta, rho, R)¶
Created with lambdify. Signature:
func(phi, theta, rho, R)
Expression:
-R + R*sin(acos(cos(phi)*cos(theta)) +…
Source code:
- def _lambdifygenerated(phi, theta, rho, R):
return -R + R*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))/sqrt(-cos(phi)**2*cos(theta)**2 + 1)
Imported modules:
- f2m.symbolic.alpha_numerical(phi, theta, rho, R)¶
Created with lambdify. Signature:
func(phi, theta, rho, R)
Expression:
-R*sin(theta)*sin(acos(cos(phi)*cos(theta)) +…
Source code:
- def _lambdifygenerated(phi, theta, rho, R):
return -R*sin(theta)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))/(sqrt(-cos(phi)**2*cos(theta)**2 + 1)*sqrt(abs(R*sin(theta)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R)))**2/abs(sqrt(-cos(phi)**2*cos(theta)**2 + 1))**2 + abs(R*sin(phi)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(theta))**2/abs(sqrt(-cos(phi)**2*cos(theta)**2 + 1))**2 + abs(R*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(phi)*cos(theta)/sqrt(-cos(phi)**2*cos(theta)**2 + 1) - rho)**2))
Imported modules:
- f2m.symbolic.beta_numerical(phi, theta, rho, R)¶
Created with lambdify. Signature:
func(phi, theta, rho, R)
Expression:
R*sin(phi)*sin(acos(cos(phi)*cos(theta)) +…
Source code:
- def _lambdifygenerated(phi, theta, rho, R):
return R*sin(phi)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(theta)/(sqrt(-cos(phi)**2*cos(theta)**2 + 1)*sqrt(abs(R*sin(theta)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R)))**2/abs(sqrt(-cos(phi)**2*cos(theta)**2 + 1))**2 + abs(R*sin(phi)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(theta))**2/abs(sqrt(-cos(phi)**2*cos(theta)**2 + 1))**2 + abs(R*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(phi)*cos(theta)/sqrt(-cos(phi)**2*cos(theta)**2 + 1) - rho)**2))
Imported modules:
- f2m.symbolic.gamma_numerical(phi, theta, rho, R)¶
Created with lambdify. Signature:
func(phi, theta, rho, R)
Expression:
(-R*sin(acos(cos(phi)*cos(theta)) +…
Source code:
- def _lambdifygenerated(phi, theta, rho, R):
return (-R*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(phi)*cos(theta)/sqrt(-cos(phi)**2*cos(theta)**2 + 1) + rho)/sqrt(abs(R*sin(theta)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R)))**2/abs(sqrt(-cos(phi)**2*cos(theta)**2 + 1))**2 + abs(R*sin(phi)*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(theta))**2/abs(sqrt(-cos(phi)**2*cos(theta)**2 + 1))**2 + abs(R*sin(arccos(cos(phi)*cos(theta)) + arcsin(rho*sqrt(-cos(phi)**2*cos(theta)**2 + 1)/R))*cos(phi)*cos(theta)/sqrt(-cos(phi)**2*cos(theta)**2 + 1) - rho)**2)
Imported modules:
- f2m.symbolic.get_alpha(phi_value: float, theta_value: float, rho_value: float, R_value: float) float¶
Calculate alpha based on the given parameters.
- Parameters:
phi_value (float) – The value of phi.
theta_value (float) – The value of theta.
rho_value (float) – The value of rho.
R_value (float) – The value of R.
- Returns:
The calculated alpha.
- Return type:
float
- f2m.symbolic.get_beta(phi_value: float, theta_value: float, rho_value: float, R_value: float) float¶
Calculate beta based on the given parameters.
- Parameters:
phi_value (float) – The value of phi.
theta_value (float) – The value of theta.
rho_value (float) – The value of rho.
R_value (float) – The value of R.
- Returns:
The calculated beta.
- Return type:
float
- f2m.symbolic.get_gamma(phi_value: float, theta_value: float, rho_value: float, R_value: float) float¶
Calculate gamma based on the given parameters.
- Parameters:
phi_value (float) – The value of phi.
theta_value (float) – The value of theta.
rho_value (float) – The value of rho.
R_value (float) – The value of R.
- Returns:
The calculated gamma.
- Return type:
float
- f2m.symbolic.get_h(phi_value: float, theta_value: float, rho_value: float, R_value: float) float¶
Calculate h based on the given parameters.
- Parameters:
phi_value (float) – The value of phi.
theta_value (float) – The value of theta.
rho_value (float) – The value of rho.
R_value (float) – The value of R.
- Returns:
The calculated h.
- Return type:
float
- f2m.symbolic.is_singularity(phi_value: float, theta_value: float, epsilon: float = 1e-07) bool¶
Return True if abs value of phi and theta are lower than epsilon.
- Parameters:
phi_value (float) – the value of phi.
theta_value (float) – the value of theta.
epsilon (float, optional) – threshold value to decide if we are in a singluarity. Defaults to 1e-7.
- Returns:
True if we are in a singularity, False otherwise.
- Return type:
bool
f2m.trajectory module¶
- f2m.trajectory.AMPL_to_PANGU_conversion(trajectory: ndarray) ndarray¶
Convert an AMPL trajectory to the PANGU coordinate convention.
The AMPL body and PANGU camera frames are assumed to be physically aligned. Angular velocity therefore remains expressed in this common body/camera frame. Zero AMPL attitude becomes PANGU’s nadir-pointing attitude.
- Parameters:
trajectory – Trajectory with shape (N, 13), containing [x, y, z, vx, vy, vz, phi, theta, psi, p, q, r, m]. Angles and angular velocities are given in radians and radians per second, respectively.
- Returns:
- Converted trajectory with shape (N, 14), containing
[x, y, z, vx, vy, vz, qw, qx, qy, qz, p, q, r, m]. Position and velocity are expressed in the PANGU frame, attitude is a scalar-first camera-to-PANGU quaternion, and angular velocity is expressed in the aligned body/camera frame.
- f2m.trajectory.PANGU_to_AMPL_conversion(trajectory: ndarray) ndarray¶
Convert a PANGU trajectory to the AMPL coordinate convention.
The PANGU camera and AMPL body frames are assumed to be physically aligned. Angular velocity therefore remains expressed in this common camera/body frame.
- Parameters:
trajectory – Trajectory with shape (N, 14), containing [x, y, z, vx, vy, vz, qw, qx, qy, qz, p, q, r, m]. Attitude is a scalar-first camera-to-PANGU quaternion.
- Returns:
- Converted trajectory with shape (N, 13), containing
[x, y, z, vx, vy, vz, phi, theta, psi, p, q, r, m]. Position and velocity are expressed in the AMPL frame, attitude is represented by ZYX Euler angles in radians, and angular velocity is expressed in the aligned camera/body frame.
- f2m.trajectory.apply_camera_tilt(trajectory: ndarray, camera_tilt: Rotation, convention: str) ndarray¶
Apply a fixed local camera tilt to a trajectory.
The camera tilt maps vectors from the tilted camera frame to the original body/camera frame. It is post-multiplied with each attitude. Angular velocity is re-expressed in the tilted camera frame, while position, linear velocity, and mass remain unchanged.
- Parameters:
trajectory – Trajectory in AMPL shape (N, 13) or PANGU shape (N, 14).
camera_tilt – Rotation from the tilted camera frame to the original body/camera frame.
convention – Trajectory convention, either “AMPL” or “PANGU”.
- Returns:
A copy of the trajectory with the camera tilt applied. AMPL attitudes remain ZYX Euler angles in [phi, theta, psi] order, while PANGU attitudes remain scalar-first quaternions in [qw, qx, qy, qz] order.
- f2m.trajectory.convert_state_history_inertial_to_body_frame(traj_dir: str, return_ranges=False)¶
Converts an inertial state history to a body frame one. The body frame is defined in get_axes_from_state().
- Parameters:
traj_dir (str) – The directory from which to load the trajectory.
- Returns:
The time and state history in the body frame.
- Return type:
tuple(np.ndarray, np.ndarray)
- f2m.trajectory.generate_hohmann_trajectory(output_dir: Path, init_position, alt_p=None, alt_a=None, r_moon=1737400.0, mu_moon: float = 4902800118000.0, n_points=200, save_traj=True, as_array=False, fps: int = 4, field_of_view: int = 60, camera_tilt: tuple[float, float, float] | None = None, indices=None) dict | ndarray¶
Generates a Hohmann transfer trajectory.
Warning! User discretion is advised. This function isn’t validated and therefore is not guaranteed to work for all init_position values (and camera_tilts)
- Parameters:
output_dir (Path) – Path to the directory where trajectory files should be saved.
init_position (array-like) – Initial position vector for the transfer.
alt_p (float, optional) – Pericenter altitude in meters.
alt_p – Apocenter altitude in meters.
period_frac (float, optional) – Fraction of the orbital period to simulate. Defaults to 0.5.
r_moon (float, optional) – Radius of the Moon in meters. Defaults to 1737.4e3 m.
mu_moon (float, optional) – The gravitational parameter. Defaults to the Moon 4.902800118e12 m**3/s**2.
save_traj (bool, optional) – If True, saves the trajectory to a file. Defaults to True.
as_array (bool, optional) – If True, returns the trajectory as a NumPy array. Defaults to False.
fps (int, optional) – Frames per second for trajectory interpolation. Defaults to 4.
field_of_view (int, optional) – Camera field of view in degrees. Defaults to 60.
camera_tilt (Optional[tuple[float, float, float]], optional) – Camera tilt angles (X, Y, Z) in radians. Defaults to None.
indices (list) – List of indices that represents the indices of the state history that you want to save. Defaults to None.
- Returns:
If as_array is True, returns the trajectory as a NumPy array. Otherwise, returns a dictionary of state history.
- Return type:
np.ndarray
- f2m.trajectory.generate_multiple_trajectories(landing_model_path: Path, parameters_path: Path, output_dir: Path, number_of_trajectories: int, save_continuation: bool = False, save_traj: bool = True, verbose: bool = True, fps: int = 4, camera_tilt: tuple[float, float, float] | None = [0, 0, 0], offset: tuple[float, float, float] = [0, 0, 0], landing_site: tuple[float, float, float] = [-25010, -40149, -3530.85])¶
[DEPRECATED] Generate a trajectory with.
- Parameters:
landing_model_path (Path) – Path to the landing model.
parameters_path (Path) – Path to the parameters file.
output_dir (Path) – Path to the output directory.
number_of_trajectories (int) – Number of trajectories to generate.
save_continuation (bool, optional) – Save trajectory for each updated parameters. Defaults to False.
save_traj (bool, optional) – Save the trajectory for each full set of updated parameters. Defaults to True.
verbose (bool, optional) – Verbose flag. Defaults to True.
fps (int, optional) – States per second. Defaults to 4.
(Optional (camera_tilt) – (float, float, float)): camera tilt angles on X, Y, and Z axes
offset (tuple[float, float, float]) – position offset applied to the trajectory
- f2m.trajectory.generate_trajectory(landing_model_path: ~pathlib.Path, parameters_path: ~pathlib.Path, output_dir: ~pathlib.Path, verbose: bool = True, fps: int = 4, camera_tilt: ~scipy.spatial.transform._rotation.Rotation = <scipy.spatial.transform._rotation.Rotation object>, landing_site: tuple[float, float, float] = (-25010, -40149, -3530.85), save: bool = True) ndarray¶
Generate a trajectory with the given parameters, using AMPL and save it in the output directory.
- Parameters:
landing_model_path (Path) – Path to the landing model.
parameters_path (Path) – Path to the parameters file.
output_dir (Path) – Path to the output directory.
verbose (bool, optional) – Verbose flag. Defaults to True.
fps (int, optional) – States per second. Defaults to 4.
camera_tilt (Rotation) – camera tilt rotation. Defaults to ventral camera.
landing_site (tuple[float, float, float]) – The coordinates to translate the origin to the landing site position. Defaults to (-25010, -40149, -3530.850).
- Returns:
The optimized trajectory state history.
- Return type:
np.ndarray
- f2m.trajectory.get_angular_state_history(orbit: dict, as_array=False, sequence='XYZ')¶
Computes the angular state history of a spacecraft, assuming the camera points toward the Moon’s center.
- Parameters:
orbit (dict) – Dictionary of time-mapped position and velocity states.
as_array (bool, optional) – If True, returns results as a NumPy array. Defaults to False.
sequence (str) – If XYZ (used for ispace traj), then XYZ rotation order is maintained, else if “ZYX” (for hohmann transfer) then ZYX rotation order
- Returns:
A dictionary mapping time values to angular states [phi, theta, psi, phi_dot, theta_dot, psi_dot]. or np.ndarray: An array of the angular states [phi, theta, psi, phi_dot, theta_dot, psi_dot].
- Return type:
dict
- f2m.trajectory.get_hohmann_state_history(alt_p, alt_a, r_body, mu, n_points=100, as_array=False, direction='inbound')¶
Generate position and velocity history along a Hohmann transfer orbit.
- Parameters:
alt_p – float Perigee altitude above the central body [m].
alt_a – float Apogee altitude above the central body [m].
r_body – float Radius of the central body [m].
mu – float Gravitational parameter of the central body [m^3/s^2].
n_points – int, optional Number of points along the transfer orbit (default is 100).
as_array – bool, optional If True, return a NumPy array of shape (n_points, 6) where each row is [x, y, z, vx, vy, vz]. If False, return a dict keyed by time with each value being a 6-element state vector.
- Returns:
- np.ndarray or dict
The trajectory states along the transfer orbit, either as an array or a dictionary indexed by time.
Notes
The orbit is assumed to be planar and elliptical (Hohmann transfer).
The z and vz components are always zero due to the planar assumption.
The trajectory is computed for half the orbital period, corresponding
to the Hohmann transfer time.
- f2m.trajectory.get_landing_site(landing_site: str) tuple[float, float, float]¶
Get the landing site coordinates from the given string
- Parameters:
landing_site (str) – The landing site name
- Returns:
The landing site coordinates
- Return type:
tuple[float, float, float]
- f2m.trajectory.get_period(mu, radius)¶
Orbital period using Kepler’s third law
- f2m.trajectory.get_state_history_from_csv(path)¶
Read a CSV file containing trajectory state history.
- Parameters:
path (str) – Path to the CSV file.
- Returns:
Time and state history arrays.
- Return type:
tuple
- f2m.trajectory.get_velocity_from_position_diff(t, x)¶
Interpolates velocity from position data using finite differences.
- Parameters:
t (np.ndarray) – Time data.
x (np.ndarray) – Position data.
- Returns:
Interpolated velocity data.
- Return type:
np.ndarray
- f2m.trajectory.interpolate_vector(t, x, dt=1)¶
Interpolates position data using cubic splines.
- Parameters:
t (np.ndarray) – Time data.
x (np.ndarray) – Position data.
dt (int, float) – Time step for interpolation.
- Returns:
Interpolated position data.
- Return type:
np.ndarray
- f2m.trajectory.position_trajectory_above_landing_site(trajectory: ndarray, landing_site: ndarray | tuple[float, float, float]) ndarray¶
Position a local PANGU trajectory above a selected landing site.
The local trajectory is rigidly rotated so that its +z axis aligns with radial up at the landing site. It is then translated so that its final position lies above the landing site, with the final local z-coordinate interpreted as altitude above the spherical lunar surface.
The reference Moon centre is assumed to be at [0, 0, -1_737_400] in the PANGU south-polar model frame. The camera and trajectory origins are assumed to be collocated.
- Parameters:
trajectory – PANGU trajectory with shape (N, 14), containing [x, y, z, vx, vy, vz, qw, qx, qy, qz, p, q, r, m]. Position and velocity are expressed in the local PANGU frame, attitude is a scalar-first camera-to-local quaternion, and angular velocity is expressed in the camera frame.
landing_site – Landing-site surface coordinates [x, y, z] in the global PANGU south-polar model frame, in meters.
- Returns:
A copy of the trajectory expressed in the global PANGU model frame. Positions, velocities, and attitudes are transformed. Camera-expressed angular velocities and mass remain unchanged.
- f2m.trajectory.rotate_vector_rodrigues(v, k, theta)¶
Rotate vector v around axis k by angle theta (Rodrigues’ rotation formula).
- f2m.trajectory.rotated_hohmann_state_history(r_init, alt_p=None, alt_a=None, r_body=1737400.0, mu=4902800118000.0, n_points=100, as_array=False)¶
Generate a rotated Hohmann transfer trajectory to align with an arbitrary initial position vector.
- Parameters:
r_init – array-like Desired initial position vector in inertial frame [m].
alt_p – Passed through to get_hohmann_state_history.
alt_a – Passed through to get_hohmann_state_history.
r_body – Passed through to get_hohmann_state_history.
mu – Passed through to get_hohmann_state_history.
n_points – Passed through to get_hohmann_state_history.
as_array – Passed through to get_hohmann_state_history.
- Returns:
State history as array or dict, rotated to start at r_init.
Note
If alt_p is None and alt_a is not None -> outbound traj where r_init is periapsis position. If alt_p is not None and alt_a is None -> inbound traj where r_init is apoapsis position. Make sure that r_init corresponds properly to apoapsis or periapsis, making sure it’s smaller than alt_a if alt_a is passed, and idem for alt_p.
- f2m.trajectory.save_ampl_trajectory(ampl_model: ~f2m.ampl_interface.AMPLModel, output_dir: ~pathlib.Path, fps: int, camera_tilt: ~scipy.spatial.transform._rotation.Rotation = <scipy.spatial.transform._rotation.Rotation object>, landing_site: tuple[float, float, float] = [-25010, -40149, -3530.85]) None¶
Saves the computed trajectory and generates a flight file for visualization.
- Parameters:
ampl_model (AMPLModel) – The AMPL optimization model containing trajectory results.
output_dir (Path) – Directory to save trajectory data.
fps (int) – Frames per second for trajectory interpolation.
camera_tilt (Rotation) – Camera tilt rotation.
- f2m.trajectory.save_trajectory_hohmann(full_state_history: dict, output_dir: Path, fps: int, field_of_view=60, camera_tilt: tuple[float, float, float] | None = None, indices=None) None¶
Saves the computed Hohmann trajectory and generates a PANGU flight file.
- Parameters:
full_state_history (dict) – Dictionary of trajectory state history.
output_dir (Path) – Directory to save trajectory data.
fps (int) – Frames per second for trajectory interpolation.
field_of_view (int, optional) – Camera field of view in degrees. Defaults to 60.
camera_tilt (Optional[tuple[float, float, float]]) – Camera tilt angles (X, Y, Z).
- f2m.trajectory.solve_kepler(M, e, tol=1e-10, max_iter=100)¶
Solves Kepler’s equation E - e*sin(E) = M for E using Newton-Raphson.
- Parameters:
M (float) – Mean anomaly in radians
e (float) – Eccentricity (0 <= e < 1)
tol (float) – Convergence tolerance
max_iter (int) – Maximum number of iterations
- Returns:
Eccentric anomaly E in radians
- Return type:
float
- f2m.trajectory.trajectory_to_flight(trajectory: ndarray, field_of_view: int = 60, output_dir: Path | None = None) list[str]¶
Generate PANGU flight file starting from array representing trajectory’s states and saves it to output_dir/flight.fli.
- Parameters:
trajectory (np.ndarray) – trajectory’s state with shape Nx13 Note: trajectory shape can vary so long as position is in the 0 - 2, and attitude is in the 6 - 9 column. The convention we used is [x, y, z, vx, vy, vz, qw, qx, qy, qz, p, q, r].
field_of_view (int) – the field of view of the camera in degrees. Defaults to 60
output_dir (Optional[Path]) – Directory to save the flight file. If None, the flight file will not be saved.
- Returns:
Each element represents a line of Pangu’s flight file
- Return type:
list[str]
- f2m.trajectory.trajectory_to_flight_hohmann(trajectory: ndarray, field_of_view: int = 60, camera_tilt: tuple[float, float, float] | None = None) list[str]¶
Generate PANGU flight file with positions in quaternions, starting from array representing Hohmann trajectory’s states
- Parameters:
trajectory (np.ndarray) – tracjectory’s state with shape Nx12. Each state is [x, y, z, vx, vy, vz, phi, theta, psi, p, q, r]
field_of_view (int) – the field of view of the camera in degrees. Defaults to 60
(Optional (camera_tilt) – (float, float, float)): camera tilt angles on X, Y, and Z axes. Defaults to None.
- Returns:
Each element represents a line of Pangu’s flight file
- Return type:
list[str]
f2m.utils module¶
- f2m.utils.dict2array(d: dict)¶
- f2m.utils.get_axes_from_state(state: ndarray)¶
Computes a right-handed coordinate frame from a state vector.
- Parameters:
state (np.ndarray) – The state vector [x, y, z, vx, vy, vz].
- Returns:
A tuple (e_x, e_y, e_z) representing the unit vectors of the frame.
- Return type:
tuple
- Raises:
RuntimeError – If e_z and e_v are not linearly independent.
- f2m.utils.get_camera_tilt(roll: float = 0, pitch: float = 0, yaw: float = 0, degrees: bool = False) Rotation¶
Return the camera tilt expressed in the body frame.
The input uses the intrinsic camera-centric yaw-pitch-roll convention:
yaw: rotation around body +y pitch: rotation around the rotated +x roll: rotation around the resulting optical +z
The rotation is constructed using intrinsic YXZ Euler angles.
- Parameters:
roll – Camera roll around the resulting optical z-axis.
pitch – Camera pitch around the rotated x-axis.
yaw – Camera yaw around the body y-axis.
degrees – Whether the input angles are in degrees.
- Returns:
Camera tilt expressed in the body frame as a Rotation object.
- f2m.utils.get_dcm_from_euler_angles(angles, sequence='XYZ')¶
Computes the direction cosine matrix (DCM) from given Euler angles.
- Parameters:
angles (np.ndarray 3x1) – The Euler angles [phi, theta, psi] in radians.
sequence (str, optional) – The rotation sequence, either ‘XYZ’ or ‘ZYX’. Default is ‘XYZ’.
- Returns:
The 3x3 DCM corresponding to the given Euler angles.
- Return type:
np.ndarray
- f2m.utils.get_euler_angles_from_dcm(e_x, e_y, e_z, sequence)¶
Computes the Euler angles from a given direction cosine matrix (DCM).
- Parameters:
e_x (np.ndarray 3x1) – The first column of the DCM.
e_y (np.ndarray 3x1) – The second column of the DCM.
e_z (np.ndarray 3x1) – The third column of the DCM.
sequence (str, optional) – The rotation sequence, either ‘XYZ’ or ‘ZYX’. Default is ‘XYZ’.
- Returns:
The computed Euler angles [phi, theta, psi] in radians.
- Return type:
np.ndarray
- f2m.utils.get_quaternion_from_dcm(e_x, e_y, e_z)¶
Computes a quaternion from a given direction cosine matrix (DCM).
- Parameters:
e_x (np.ndarray 3x1) – The first column of the DCM.
e_y (np.ndarray 3x1) – The second column of the DCM.
e_z (np.ndarray 3x1) – The third column of the DCM.
- Returns:
The computed quaternion [q0, q1, q2, q3].
- Return type:
np.ndarray
- f2m.utils.get_quaternion_from_euler_angles(angles, sequence='XYZ')¶
Computes a quaternion from given Euler angles.
- Parameters:
angles (np.ndarray 3x1) – The Euler angles [phi, theta, psi] in radians.
sequence (str, optional) – The rotation sequence, either ‘XYZ’ or ‘ZYX’. Default is ‘XYZ’.
- Returns:
The computed quaternion [q0, q1, q2, q3].
- Return type:
np.ndarray
- f2m.utils.get_quaternion_state_history(state_history: ndarray)¶
Computes the quaternion state history from a given state history.
This function assumes that the camera is oriented such that it points toward the position vector from the origin (e.g., the Moon).
- Parameters:
state_history (np.ndarray) – An array of state vectors, where each row is [x, y, z, vx, vy, vz].
- Returns:
An array of quaternions representing the orientation history.
- Return type:
np.ndarray
- f2m.utils.lat_lon_to_pangu_xyz(latitude_deg: float, longitude_deg: float, elevation: float = 0.0, moon_radius: float = 1737400.0) tuple[float, float, float]¶
Computes PANGU south-polar model coordinates from lunar latitude, longitude, and radial elevation.
Lunar latitude is measured from the lunar equator, with positive values toward the north pole and negative values toward the south pole. Lunar longitude is measured from the lunar prime meridian, with positive values eastward. The point (0 deg latitude, 0 deg longitude) lies on the lunar equator at the prime meridian, approximately at the center of the Moon’s near side.
- Parameters:
latitude_deg (float) – The lunar latitude in degrees.
longitude_deg (float) – The lunar east longitude in degrees.
elevation (float) – The radial elevation above the reference spherical Moon in meters.
moon_radius (float) – The reference Moon radius in meters.
- Returns:
A tuple (x, y, z) representing the PANGU model coordinates in meters.
- Return type:
tuple
- f2m.utils.load_trajectory(traj_dir: Path | str | None = None, verbose: bool = False, use_interp: bool = False, return_throttle: bool = False, return_mass: bool = True, return_ranges: bool = True, custom_traj_file: Path | str | None = None) tuple[ndarray, ndarray, ndarray]¶
Takes either a trajectory directory or custom file as input to load the trajectory. This function is flexible regarding whether mass is given and whether there are range measurements available.
- Parameters:
traj_dir (Path|str|None) – The directory from which to load the trajectory. Defaults to None.
verbose (bool) – Flag to enable verbose output. Defaults to False.
use_interp (bool) – Flag to enable loading the interpolated state. Defaults to False.
return_throttle (bool) – Flag to specify whether the thrust exists and should be returned as a separate array. Defaults to False.
return_mass (bool) – Flag that keeps the mass (if it exists) in the state history, otherwise discard the last column (being mass). Defaults to True.
return_ranges (bool) – An option to determine whether or not the ranges are added to the state history
custom_traj_file (Path|str|None) – The path to the file containing the custom specified state history. Defaults to None.
- Returns:
time, state history, thrusts.
- Return type:
tuple(np.ndarray, np.ndarray, np.ndarray)
- f2m.utils.pangu_craft_to_quaternion(yaw_deg: float, pitch_deg: float, roll_deg: float) ndarray¶
Converts PANGU craft-view yaw, pitch, and roll angles to a scalar-first quaternion.
- Parameters:
yaw_deg (float) – The craft-view yaw angle in degrees. This rotates the boresight direction about the PANGU world z-axis.
pitch_deg (float) – The craft-view pitch angle in degrees. This sets the boresight elevation relative to the PANGU world horizontal plane.
roll_deg (float) – The craft-view roll angle in degrees. This twists the image about the resulting boresight direction.
- Returns:
- The scalar-first quaternion (q0, q1, q2, q3) representing the
camera-to-world rotation.
- Return type:
np.ndarray
- f2m.utils.pangu_craft_to_rotation(yaw_deg: float, pitch_deg: float, roll_deg: float) Rotation¶
Converts PANGU craft-view yaw, pitch, and roll angles to a scipy rotation object.
- Parameters:
yaw_deg (float) – The craft-view yaw angle in degrees. This rotates the boresight direction about the PANGU world z-axis.
pitch_deg (float) – The craft-view pitch angle in degrees. This sets the boresight elevation relative to the PANGU world horizontal plane.
roll_deg (float) – The craft-view roll angle in degrees. This twists the image about the resulting boresight direction.
- Returns:
The scipy rotation object representing the camera-to-world rotation.
- Return type:
Rotation
- f2m.utils.scale_pixel_coordinates(coord: ndarray, image_width: int) ndarray¶
Scale pixels coordinates in [-0.5, 0.5]
- Parameters:
x (np.ndarray) – pixel coordinates
image_width (int) – image resolution
- Returns:
rescaled coordinates
- Return type:
np.ndarray
f2m.visualization module¶
- f2m.visualization.generate_video_comparison(frames: ndarray, traj: ndarray, of_estimator: LKOpticalFlowEstimator, output_path: Path, rangefinder: bool = True, slope_estimation: bool = False, known_velocity: bool = False, alpha: float = None, beta: float = None, rotation_vector: ndarray = array([0, 0, 0]), focal_length: float = 0.866025, arrow_scale: float = 3.0, frame_interval: int = 1, fps: int = 4, verbose: bool = False, rotation: list[float] = [0, 0, 0]) None¶
Generate the video comparing ground truth optical flow to predicted optical flow for visual comparison
- Parameters:
frames (np.ndarray) – cv2 arrays representing video frames in BGR.
traj (np.ndarray) – trajectory data.
of_estimator (LKOpticalFlowEstimator) – optical flow estimator.
output_path (Path) – Where to save output frames.
rotation_vector (np.ndarray, optional) – Rotation vector for camera perspective in radians [roll, -pitch, yaw]. Defaults to np.array([0, 0, 0]).
focal_length (float, optional) – Focal length of video source.
arrow_scale (float, optional) – scale optical flow arrows for better visualization. Defaults to 3.
frame_interval (int, optional) – Detect new points to track every frame_interval frames. Defaults to 1.
fps (int, optional) – framerate in the output video. Defaults to 4
verbose (bool, optional) – defaults to False
- f2m.visualization.plot_angles(traj_dir: Path, save: bool = False) None¶
- f2m.visualization.plot_angular_velocities(traj_dir: Path, plot_magnitude: bool = False, save: bool = False, as_svg: bool = False) None¶
- f2m.visualization.plot_hohmann_transfer(traj_dir: Path, init_position, alt_a=None, alt_p=None, mu_body=4902800118000.0, planet_radius=1737400.0, save: bool = False)¶
- f2m.visualization.plot_main_thruster(traj_dir: Path, save: bool = False) None¶
- f2m.visualization.plot_mass(traj_dir: Path, save: bool = False) None¶
- f2m.visualization.plot_orbit(orbit_arr: ndarray, planet_radius=1737400.0, translate_planet: ndarray = [0, 0, 0], save: bool = False, title='Generic Orbit', traj_dir=None, elev: float = None, azim: float = None)¶
- f2m.visualization.plot_orbit_textured(orbit_arr: ndarray, texture_file: str, planet_radius: float = 1737400.0, translate_planet: ndarray = [0, 0, 0], downsample_scale: int = 1, sun_pos: tuple = (1000000000.0, 45, 45), save: bool = False, title='Textured Orbit', traj_dir=None, elev: float = None, azim: float = None, show_axes: bool = True)¶
- f2m.visualization.plot_positions(traj_dir: Path, save: bool = False) None¶
- f2m.visualization.plot_rho_vs_z(traj_dir: Path, estimate_z: bool = False, save: bool = False) None¶
- f2m.visualization.plot_thrusters(traj_dir: Path, save: bool = False) None¶
- f2m.visualization.plot_trajectory(traj_dir: Path, save: bool = False, as_svg: bool = False) None¶
- f2m.visualization.plot_velocities(traj_dir: Path, save: bool = False) None¶
- f2m.visualization.plot_velocity_boxplots(results, compare_param='landing_site', filter_params=None, components=['$v_x$', '$v_y$', '$v_z$'], title='Velocity Error Comparison', ylims=None, figsize=(8, 5), legend_label=None, legend_loc='upper right', logscale=False, error_metric='absolute', save=False, svg=False, output_path=None)¶
Creates a grouped box plot showing velocity component errors.
Parameters: - gt_by_group: list of arrays (n_components x time) for each group (e.g., landing site) - pred_by_group: list of arrays, same shape as gt_by_group - group_labels: list of labels (e.g., landing site names), same length as gt_by_group - components: list of component names to label plots - title: plot title - max_error: y-axis limit for error - figsize: figure size - save: whether to save the plot - output_path: path to save to (if save=True)
- f2m.visualization.plot_velocity_comparison(gt, pred, components_to_plot=['vx (m/s)', 'vy (m/s)', 'vz (m/s)'], error_tol=1, title=None, max_error=3, output_path=None, save=False, figsize=(20, 7))¶
- f2m.visualization.plot_velocity_comparison_paper(gt, pred, components_to_plot=['$v_x$ $(m/s)$', '$v_y$ $(m/s)$', '$v_z$ $(m/s)$'], title=None, ylims=None, output_path=None, save=False, svg=False, figsize=(8, 6))¶
- f2m.visualization.set_axes_equal(ax)¶
Make axes of 3D plot have equal scale so that spheres appear as spheres, cubes as cubes, etc.
- Input
ax: a matplotlib axis, e.g., as output from plt.gca().