Skip to content

Trajectory

Trajectory is a dynamically sized trajectory container that stores time-series state data with runtime-determined dimensions. Unlike static trajectory types, Trajectory allows you to specify the state vector dimension at creation time, making it ideal for applications where the dimension varies or is not known at compile time.

Use Trajectory when:

  • State dimension is determined at runtime
  • You need flexibility to work with different dimensions in the same codebase
  • State vectors are non-standard (not 3D or 6D)
  • Flexibility is prioritized over maximum performance

Initialization

Empty Trajectory

Create an empty trajectory by specifying the state dimension. The default dimension is 6 (suitable for position + velocity states):

import brahe as bh

bh.initialize_eop()

# Create 6D trajectory (default)
traj = bh.Trajectory()
print(f"Dimension: {traj.dimension()}")

# Create 3D trajectory (position only)
traj_3d = bh.Trajectory(3)
print(f"Dimension: {traj_3d.dimension()}")

# Create 12D trajectory (custom)
traj_12d = bh.Trajectory(12)
print(f"Dimension: {traj_12d.dimension()}")
use brahe as bh;
use bh::trajectories::DTrajectory;

fn main() {
    bh::initialize_eop().unwrap();

    // Create 6D trajectory (default)
    let traj = DTrajectory::default();
    println!("Dimension: {}", traj.dimension());

    // Create 3D trajectory
    let traj_3d = DTrajectory::new(3);
    println!("Dimension: {}", traj_3d.dimension());

    // Create 12D trajectory
    let traj_12d = DTrajectory::new(12);
    println!("Dimension: {}", traj_12d.dimension());
}
Output
1
2
3
Dimension: 6
Dimension: 3
Dimension: 12
1
2
3
Dimension: 6
Dimension: 3
Dimension: 12

From Existing Data

Create a trajectory from existing epochs and states:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create epochs
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)
epoch1 = epoch0 + 60.0  # 1 minute later
epoch2 = epoch0 + 120.0  # 2 minutes later

# Create states (6D: position + velocity)
state0 = np.array([bh.R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0])
state1 = np.array([bh.R_EARTH + 500e3, 456000.0, 0.0, -7600.0, 0.0, 0.0])
state2 = np.array([bh.R_EARTH + 500e3, 0.0, 0.0, 0.0, -7600.0, 0.0])

# Create trajectory from data
epochs = [epoch0, epoch1, epoch2]
states = np.array([state0, state1, state2])
traj = bh.Trajectory.from_data(epochs, states)

print(f"Trajectory length: {len(traj)}")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create epochs
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);
    let epoch1 = epoch0 + 60.0;  // 1 minute later
    let epoch2 = epoch0 + 120.0;  // 2 minutes later

    // Create states
    let state0 = na::DVector::from_vec(vec![
        R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0
    ]);
    let state1 = na::DVector::from_vec(vec![
        R_EARTH + 500e3, 456000.0, 0.0, -7600.0, 0.0, 0.0
    ]);
    let state2 = na::DVector::from_vec(vec![
        R_EARTH + 500e3, 0.0, 0.0, 0.0, -7600.0, 0.0
    ]);

    // Create trajectory from data
    let epochs = vec![epoch0, epoch1, epoch2];
    let states = vec![state0, state1, state2];
    let traj = DTrajectory::from_data(epochs, states).unwrap();

    println!("Trajectory length: {}", traj.len());
}
Output
Trajectory length: 3
Trajectory length: 3

Adding and Accessing States

Adding States

Add states to a trajectory one at a time:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create empty trajectory
traj = bh.Trajectory(6)

# Add states
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)
state0 = np.array([bh.R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0])
traj.add(epoch0, state0)

print(f"Trajectory length: {len(traj)}")

epoch1 = epoch0 + 60.0
state1 = np.array([bh.R_EARTH + 500e3, 456000.0, 0.0, -7600.0, 0.0, 0.0])
traj.add(epoch1, state1)

print(f"Trajectory length: {len(traj)}")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create empty trajectory
    let mut traj = DTrajectory::new(6);

    // Add states
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);
    let state0 = na::DVector::from_vec(vec![
        R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0
    ]);
    traj.add(epoch0, state0);

    println!("Trajectory length: {}", traj.len());

    let epoch1 = epoch0 + 60.0;
    let state1 = na::DVector::from_vec(vec![
        R_EARTH + 500e3, 456000.0, 0.0, -7600.0, 0.0, 0.0
    ]);
    traj.add(epoch1, state1);

    println!("Trajectory length: {}", traj.len());
}
Output
Trajectory length: 1
Trajectory length: 2
Trajectory length: 1
Trajectory length: 2

Accessing by Index

Retrieve states and epochs by their index:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create and populate trajectory
traj = bh.Trajectory(6)
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)
state0 = np.array([bh.R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0])
traj.add(epoch0, state0)

epoch1 = epoch0 + 60.0
state1 = np.array([bh.R_EARTH + 600e3, 456000.0, 0.0, -7600.0, 0.0, 0.0])
traj.add(epoch1, state1)

epoch2 = epoch0 + 120.0
state2 = np.array([bh.R_EARTH + 700e3, 0.0, 0.0, 0.0, -7600.0, 0.0])
traj.add(epoch2, state2)

# Access by index
retrieved_epoch = traj.epoch_at_idx(1)
retrieved_state = traj.state_at_idx(1)

print(f"Epoch: {retrieved_epoch}")
print(f"Altitude: {retrieved_state[0] - bh.R_EARTH:.2f} m")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create and populate trajectory
    let mut traj = DTrajectory::new(6);
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);
    let state0 = na::DVector::from_vec(vec![
        R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0
    ]);
    traj.add(epoch0, state0);

    let epoch1 = epoch0 + 60.0;
    let state1 = na::DVector::from_vec(vec![
        R_EARTH + 600e3, 456000.0, 0.0, -7600.0, 0.0, 0.0
    ]);
    traj.add(epoch1, state1);

    let epoch2 = epoch0 + 120.0;
    let state2 = na::DVector::from_vec(vec![
        R_EARTH + 700e3, 0.0, 0.0, 0.0, -7600.0, 0.0
    ]);
    traj.add(epoch2, state2);

    // Access by index
    let retrieved_epoch = traj.epoch_at_idx(1).unwrap();
    let retrieved_state = traj.state_at_idx(1).unwrap();

    println!("Epoch: {}", retrieved_epoch);
    println!("Altitude: {:.2} m", retrieved_state[0] - R_EARTH);
}
Output
Epoch: 2024-01-01 00:01:00.000 UTC
Altitude: 600000.00 m
Epoch: 2024-01-01 00:01:00.000 UTC
Altitude: 600000.00 m

Accessing by Epoch

Get states at or near specific epochs:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create trajectory with multiple states
traj = bh.Trajectory(6)
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)

for i in range(5):
    epoch = epoch0 + i * 60.0
    state = np.array([bh.R_EARTH + 500e3 + i * 1000, 0.0, 0.0, 0.0, 7600.0, 0.0])
    traj.add(epoch, state)

# Get nearest state to a specific epoch
query_epoch = epoch0 + 120.0  # 2 minutes after start
nearest_epoch, nearest_state = traj.nearest_state(query_epoch)
print(
    f"Nearest state at t+120s altitude: {(nearest_state[0] - bh.R_EARTH) / 1e3:.2f} km"
)

# Get nearest state between stored epochs
query_epoch = epoch0 + 125.0  # Between stored epochs
nearest_epoch, nearest_state = traj.nearest_state(query_epoch)
print(
    f"Nearest state at t+125s altitude: {(nearest_state[0] - bh.R_EARTH) / 1e3:.2f} km"
)
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create trajectory with multiple states
    let mut traj = DTrajectory::new(6);
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);

    for i in 0..5 {
        let epoch = epoch0 + (i as f64) * 60.0;
        let state = na::DVector::from_vec(vec![
            R_EARTH + 500e3 + (i as f64) * 1000.0, 0.0, 0.0, 0.0, 7600.0, 0.0
        ]);
        traj.add(epoch, state);
    }

    // Get nearest state to a specific epoch
    let query_epoch1 = epoch0 + 120.0;  // 2 minutes after start
    let (_, nearest_state) = traj.nearest_state(&query_epoch1).unwrap();
    println!("Nearest state at t+120s altitude: {:.2} km",
        (nearest_state[0] - R_EARTH) / 1e3);

    // Get nearest state between stored epochs
    let query_epoch2 = epoch0 + 125.0;  // Between stored epochs
    let (_, nearest_state) = traj.nearest_state(&query_epoch2).unwrap();
    println!("Nearest state at t+125s altitude: {:.2} km",
        (nearest_state[0] - R_EARTH) / 1e3);
}
Output
Nearest state at t+120s altitude: 502.00 km
Nearest state at t+125s altitude: 502.00 km
Nearest state at t+120s altitude: 502.00 km
Nearest state at t+125s altitude: 502.00 km

Querying Trajectory Properties

Time Span and Bounds

Query the temporal extent of a trajectory:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create trajectory spanning 5 minutes
traj = bh.Trajectory(6)
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)

for i in range(6):
    epoch = epoch0 + i * 60.0
    state = np.array([bh.R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0])
    traj.add(epoch, state)

# Query properties
print(f"Number of states: {len(traj)}")
print(f"Start epoch: {traj.start_epoch()}")
print(f"End epoch: {traj.end_epoch()}")
print(f"Timespan: {traj.timespan():.1f} seconds")
print(f"Is empty: {traj.is_empty()}")

# Access first and last states
first_epoch, first_state = traj.first()
last_epoch, last_state = traj.last()
print(f"First epoch: {first_epoch}")
print(f"Last epoch: {last_epoch}")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create trajectory spanning 5 minutes
    let mut traj = DTrajectory::new(6);
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);

    for i in 0..6 {
        let epoch = epoch0 + (i as f64) * 60.0;
        let state = na::DVector::from_vec(vec![
            R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0
        ]);
        traj.add(epoch, state);
    }

    // Query properties
    println!("Number of states: {}", traj.len());
    println!("Start epoch: {}", traj.start_epoch().unwrap());
    println!("End epoch: {}", traj.end_epoch().unwrap());
    println!("Timespan: {:.1} seconds", traj.timespan().unwrap());
    println!("Is empty: {}", traj.is_empty());

    // Access first and last states
    let (first_epoch, _first_state) = traj.first().unwrap();
    let (last_epoch, _last_state) = traj.last().unwrap();
    println!("First epoch: {}", first_epoch);
    println!("Last epoch: {}", last_epoch);
}
Output
1
2
3
4
5
6
7
Number of states: 6
Start epoch: 2024-01-01 00:00:00.000 UTC
End epoch: 2024-01-01 00:05:00.000 UTC
Timespan: 300.0 seconds
Is empty: False
First epoch: 2024-01-01 00:00:00.000 UTC
Last epoch: 2024-01-01 00:05:00.000 UTC
1
2
3
4
5
6
7
Number of states: 6
Start epoch: 2024-01-01 00:00:00.000 UTC
End epoch: 2024-01-01 00:05:00.000 UTC
Timespan: 300.0 seconds
Is empty: false
First epoch: 2024-01-01 00:00:00.000 UTC
Last epoch: 2024-01-01 00:05:00.000 UTC

Interpolation

Trajectory supports linear interpolation to estimate states at arbitrary epochs between stored data points:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create trajectory with sparse data
traj = bh.Trajectory(6)
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)

# Add states every 60 seconds
for i in range(3):
    epoch = epoch0 + i * 60.0
    # Simplified motion: position changes linearly with time
    state = np.array([bh.R_EARTH + 500e3 + i * 10000, 0.0, 0.0, 0.0, 7600.0, 0.0])
    traj.add(epoch, state)

# Interpolate state at intermediate time
query_epoch = epoch0 + 30.0  # Halfway between first two states
interpolated_state = traj.interpolate(query_epoch)

print(f"Interpolated altitude: {(interpolated_state[0] - bh.R_EARTH) / 1e3:.2f} km")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::{Trajectory, InterpolatableTrajectory};
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create trajectory with sparse data
    let mut traj = DTrajectory::new(6);
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);

    // Add states every 60 seconds
    for i in 0..3 {
        let epoch = epoch0 + (i as f64) * 60.0;
        let state = na::DVector::from_vec(vec![
            R_EARTH + 500e3 + (i as f64) * 10000.0, 0.0, 0.0, 0.0, 7600.0, 0.0
        ]);
        traj.add(epoch, state);
    }

    // Interpolate state at intermediate time
    let query_epoch = epoch0 + 30.0;  // Halfway between first two states
    let interpolated_state = traj.interpolate(&query_epoch).unwrap();

    println!("Interpolated altitude: {:.2} km",
        (interpolated_state[0] - R_EARTH) / 1e3);
}
Output
Interpolated altitude: 505.00 km
Interpolated altitude: 505.00 km

Memory Management

Trajectory supports eviction policies to automatically manage memory in long-running applications:

Maximum Size Policy

Keep only the N most recent states:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create trajectory with max size limit
traj = bh.Trajectory(6).with_eviction_policy_max_size(3)

epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)

# Add 5 states
for i in range(5):
    epoch = epoch0 + i * 60.0
    state = np.array([bh.R_EARTH + 500e3 + i * 1000, 0.0, 0.0, 0.0, 7600.0, 0.0])
    traj.add(epoch, state)

# Only the 3 most recent states are kept
print(f"Trajectory length: {len(traj)}")
print(f"Start epoch: {traj.start_epoch()}")
print(f"Start altitude: {(traj.state_at_idx(0)[0] - bh.R_EARTH) / 1e3:.2f} km")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create trajectory with max size limit
    let mut traj = DTrajectory::new(6)
        .with_eviction_policy_max_size(3);

    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);

    // Add 5 states
    for i in 0..5 {
        let epoch = epoch0 + (i as f64) * 60.0;
        let state = na::DVector::from_vec(vec![
            R_EARTH + 500e3 + (i as f64) * 1000.0, 0.0, 0.0, 0.0, 7600.0, 0.0
        ]);
        traj.add(epoch, state);
    }

    // Only the 3 most recent states are kept
    println!("Trajectory length: {}", traj.len());
    println!("Start epoch: {}", traj.start_epoch().unwrap());
    println!("Start altitude: {:.2} km",
        (traj.state_at_idx(0).unwrap()[0] - R_EARTH) / 1e3);
}
Output
1
2
3
Trajectory length: 3
Start epoch: 2024-01-01 00:02:00.000 UTC
Start altitude: 502.00 km
1
2
3
Trajectory length: 3
Start epoch: 2024-01-01 00:02:00.000 UTC
Start altitude: 502.00 km

Maximum Age Policy

Keep only states within a time window:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Keep only states within last 2 minutes (120 seconds)
traj = bh.Trajectory(6).with_eviction_policy_max_age(120.0)

epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)

# Add states spanning 4 minutes
for i in range(5):
    epoch = epoch0 + i * 60.0
    state = np.array([bh.R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0])
    traj.add(epoch, state)

# Only states within 120 seconds of the most recent are kept
print(f"Trajectory length: {len(traj)}")
print(f"Timespan: {traj.timespan():.1f} seconds")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Keep only states within last 2 minutes (120 seconds)
    let mut traj = DTrajectory::new(6)
        .with_eviction_policy_max_age(120.0);

    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);

    // Add states spanning 4 minutes
    for i in 0..5 {
        let epoch = epoch0 + (i as f64) * 60.0;
        let state = na::DVector::from_vec(vec![
            R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0, 0.0
        ]);
        traj.add(epoch, state);
    }

    // Only states within 120 seconds of the most recent are kept
    println!("Trajectory length: {}", traj.len());
    println!("Timespan: {:.1} seconds", traj.timespan().unwrap());
}
Output
Trajectory length: 3
Timespan: 120.0 seconds
Trajectory length: 3
Timespan: 120.0 seconds

Iteration

Trajectories can be iterated to process all epoch-state pairs:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create and populate trajectory
traj = bh.Trajectory(6)
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)

for i in range(3):
    epoch = epoch0 + i * 60.0
    state = np.array([bh.R_EARTH + 500e3 + i * 1000, 0.0, 0.0, 0.0, 7600.0, 0.0])
    traj.add(epoch, state)

# Iterate over all states
for epoch, state in traj:
    altitude = (state[0] - bh.R_EARTH) / 1e3
    print(f"Epoch: {epoch}, Altitude: {altitude:.2f} km")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create and populate trajectory
    let mut traj = DTrajectory::new(6);
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);

    for i in 0..3 {
        let epoch = epoch0 + (i as f64) * 60.0;
        let state = na::DVector::from_vec(vec![
            R_EARTH + 500e3 + (i as f64) * 1000.0, 0.0, 0.0, 0.0, 7600.0, 0.0
        ]);
        traj.add(epoch, state);
    }

    // Iterate over all states
    for (epoch, state) in &traj {
        let altitude = (state[0] - R_EARTH) / 1e3;
        println!("Epoch: {}, Altitude: {:.2} km", epoch, altitude);
    }

}
Output
1
2
3
Epoch: 2024-01-01 00:00:00.000 UTC, Altitude: 500.00 km
Epoch: 2024-01-01 00:01:00.000 UTC, Altitude: 501.00 km
Epoch: 2024-01-01 00:02:00.000 UTC, Altitude: 502.00 km
1
2
3
Epoch: 2024-01-01 00:00:00.000 UTC, Altitude: 500.00 km
Epoch: 2024-01-01 00:01:00.000 UTC, Altitude: 501.00 km
Epoch: 2024-01-01 00:02:00.000 UTC, Altitude: 502.00 km

Matrix Export

Convert trajectory data to matrix format for analysis or export:

import brahe as bh
import numpy as np

bh.initialize_eop()

# Create trajectory
traj = bh.Trajectory(6)
epoch0 = bh.Epoch.from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)

for i in range(3):
    epoch = epoch0 + i * 60.0
    state = np.array([bh.R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0 + i * 10, 0.0])
    traj.add(epoch, state)

# Convert to matrix (rows are states, columns are dimensions)
matrix = traj.to_matrix()
print(f"Matrix type: {type(matrix)}")
print(f"Matrix shape: {matrix.shape}")
print(f"First state velocity: {matrix[0, 4]:.1f} m/s")
use brahe as bh;
use bh::time::Epoch;
use bh::trajectories::DTrajectory;
use bh::traits::Trajectory;
use bh::constants::R_EARTH;
use nalgebra as na;

fn main() {
    bh::initialize_eop().unwrap();

    // Create trajectory
    let mut traj = DTrajectory::new(6);
    let epoch0 = Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0,
        bh::time::TimeSystem::UTC);

    for i in 0..3 {
        let epoch = epoch0 + (i as f64) * 60.0;
        let state = na::DVector::from_vec(vec![
            R_EARTH + 500e3, 0.0, 0.0, 0.0, 7600.0 + (i as f64) * 10.0, 0.0
        ]);
        traj.add(epoch, state);
    }

    // Convert to matrix (rows are states, columns are dimensions)
    let matrix = traj.to_matrix().unwrap();
    println!("Matrix shape: ({}, {})", matrix.nrows(), matrix.ncols());
    println!("First state velocity: {:.1} m/s", matrix[(0, 4)]);
}
Output
1
2
3
Matrix type: <class 'numpy.ndarray'>
Matrix shape: (3, 6)
First state velocity: 7600.0 m/s
Matrix shape: (3, 6)
First state velocity: 7600.0 m/s

See Also