The orbits module provides functions to compute essential properties of satellite orbits, including orbital period, mean motion, periapsis/apoapsis characteristics, and specialized orbits like sun-synchronous configurations. These properties are fundamental for mission design, orbit determination, and trajectory analysis.
The orbital period \(T\) of a satellite is the time it takes to complete one full revolution around the central body. It is related to the semi-major axis \(a\) and gravitational parameter \(\mu\) by:
\[ T = 2\pi\sqrt{\frac{a^3}{\mu}} \]
The orbital_period function computes the period for Earth-orbiting objects, while orbital_period_general accepts an explicit gravitational parameter for any celestial body.
importbraheasbhbh.initialize_eop()# Define orbit parametersa=bh.R_EARTH+500.0e3# Semi-major axis (m) - LEO orbit at 500 km altitude# Compute orbital period for Earth orbit (uses GM_EARTH internally)period_earth=bh.orbital_period(a)print(f"Orbital period (Earth): {period_earth:.3f} s")print(f"Orbital period (Earth): {period_earth/60:.3f} min")# Compute orbital period for general body (explicit GM)period_general=bh.orbital_period_general(a,bh.GM_EARTH)print(f"Orbital period (general): {period_general:.3f} s")# Verify they matchprint(f"Difference: {abs(period_earth-period_general):.2e} s")# Example with approximate GEO altitudea_geo=bh.R_EARTH+35786e3period_geo=bh.orbital_period(a_geo)print(f"\nGEO orbital period: {period_geo/3600:.3f} hours")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Define orbit parametersleta=bh::constants::R_EARTH+500.0e3;// Semi-major axis (m) - LEO orbit at 500 km altitude// Compute orbital period for Earth orbit (uses GM_EARTH internally)letperiod_earth=bh::orbits::orbital_period(a);println!("Orbital period (Earth): {:.3} s",period_earth);println!("Orbital period (Earth): {:.3} min",period_earth/60.0);// Compute orbital period for general body (explicit GM)letperiod_general=bh::orbits::orbital_period_general(a,bh::constants::GM_EARTH);println!("Orbital period (general): {:.3} s",period_general);// Verify they matchprintln!("Difference: {:.2e} s",(period_earth-period_general).abs());// Example with approximate GEO altitudeleta_geo=bh::constants::R_EARTH+35786e3;letperiod_geo=bh::orbits::orbital_period(a_geo);println!("\nGEO orbital period: {:.3} hours",period_geo/3600.0);}
Orbital period (Earth): 5676.977 s
Orbital period (Earth): 94.616 min
Orbital period (general): 5676.977 s
Difference: 0.00e+00 s
GEO orbital period: 23.934 hours
Orbital period (Earth): 5676.977 s
Orbital period (Earth): 94.616 min
Orbital period (general): 5676.977 s
Difference: 0.00e0 s
GEO orbital period: 23.934 hours
The plot below shows how orbital period and velocity vary with altitude for circular Earth orbits:
importosimportpathlibimportsysimportnumpyasnpimportplotly.graph_objectsasgofromplotly.subplotsimportmake_subplotsimportbraheasbh# Add plots directory to path for importing brahe_themesys.path.insert(0,str(pathlib.Path(__file__).parent))frombrahe_themeimportget_theme_colors,save_themed_html# ConfigurationSCRIPT_NAME=pathlib.Path(__file__).stemOUTDIR=pathlib.Path(os.getenv("BRAHE_FIGURE_OUTPUT_DIR","./docs/figures/"))# Ensure output directory existsos.makedirs(OUTDIR,exist_ok=True)# Generate data# Generate range of altitudes from 0 to 40,000 km in 500 km incrementsalt=np.arange(0,41000*1e3,500*1e3)# Compute velocity over altitude (km/s)vp=[bh.perigee_velocity(bh.R_EARTH+a,0.0)/1e3forainalt]# Compute orbital period over altitude (hours)period=[bh.orbital_period(bh.R_EARTH+a)/3600forainalt]# Create figure with theme supportdefcreate_figure(theme):"""Create figure with theme-specific colors."""colors=get_theme_colors(theme)# Create subplot with secondary y-axisfig=make_subplots(specs=[[{"secondary_y":True}]])# Add velocity trace (primary y-axis)fig.add_trace(go.Scatter(x=alt/1e6,y=vp,mode="lines",line=dict(color=colors["primary"],width=2),name="Velocity",showlegend=True,),secondary_y=False,)# Add orbital period trace (secondary y-axis)fig.add_trace(go.Scatter(x=alt/1e6,y=period,mode="lines",line=dict(color=colors["secondary"],width=2),name="Orbital Period",showlegend=True,),secondary_y=True,)# Configure primary x-axisfig.update_xaxes(tickmode="linear",tick0=0,dtick=5,title_text="Satellite Altitude [1000 km]",range=[0,40],showgrid=False,)# Configure primary y-axis (velocity)fig.update_yaxes(tickmode="linear",tick0=0,dtick=1,title_text="Velocity [km/s]",range=[0,10],showgrid=False,secondary_y=False,)# Configure secondary y-axis (period)fig.update_yaxes(tickmode="linear",tick0=0,dtick=5,title_text="Orbital Period [hours]",range=[0,30],showgrid=False,secondary_y=True,)returnfig# Generate and save both themed versionslight_path,dark_path=save_themed_html(create_figure,OUTDIR/SCRIPT_NAME)print(f"✓ Generated {light_path}")print(f"✓ Generated {dark_path}")
When orbital elements are unknown but you have a Cartesian state vector, orbital_period_from_state computes the period directly from position and velocity:
importbraheasbhimportnumpyasnpbh.initialize_eop()# Define orbital elements for a LEO satellitea=bh.R_EARTH+500.0e3# Semi-major axis (m)e=0.01# Eccentricityi=97.8# Inclination (degrees)raan=15.0# Right ascension of ascending node (degrees)argp=30.0# Argument of periapsis (degrees)nu=45.0# True anomaly (degrees)# Convert to Cartesian stateoe=np.array([a,e,i,raan,argp,nu])state_eci=bh.state_koe_to_eci(oe,bh.AngleFormat.DEGREES)print("ECI State (position in km, velocity in km/s):")print(f" r = [{state_eci[0]/1e3:.3f}, {state_eci[1]/1e3:.3f}, {state_eci[2]/1e3:.3f}] km")print(f" v = [{state_eci[3]/1e3:.3f}, {state_eci[4]/1e3:.3f}, {state_eci[5]/1e3:.3f}] km/s")# Compute orbital period from state vectorperiod=bh.orbital_period_from_state(state_eci,bh.GM_EARTH)print(f"\nOrbital period from state: {period:.3f} s")print(f"Orbital period from state: {period/60:.3f} min")# Verify against period computed from semi-major axisperiod_from_sma=bh.orbital_period(a)print(f"\nOrbital period from SMA: {period_from_sma:.3f} s")print(f"Difference: {abs(period-period_from_sma):.2e} s")
usebraheasbh;usenalgebraasna;fnmain(){bh::initialize_eop().unwrap();// Define orbital elements for a LEO satelliteleta=bh::constants::R_EARTH+500.0e3;// Semi-major axis (m)lete=0.01;// Eccentricityleti=97.8;// Inclination (degrees)letraan=15.0;// Right ascension of ascending node (degrees)letargp=30.0;// Argument of periapsis (degrees)letnu=45.0;// True anomaly (degrees)// Convert to Cartesian stateletoe=na::SVector::<f64,6>::new(a,e,i,raan,argp,nu);letstate_eci=bh::state_koe_to_eci(oe,bh::constants::AngleFormat::Degrees);println!("ECI State (position in km, velocity in km/s):");println!(" r = [{:.3}, {:.3}, {:.3}] km",state_eci[0]/1e3,state_eci[1]/1e3,state_eci[2]/1e3);println!(" v = [{:.3}, {:.3}, {:.3}] km/s",state_eci[3]/1e3,state_eci[4]/1e3,state_eci[5]/1e3);// Compute orbital period from state vectorletperiod=bh::orbits::orbital_period_from_state(&state_eci,bh::constants::GM_EARTH);println!("\nOrbital period from state: {:.3} s",period);println!("Orbital period from state: {:.3} min",period/60.0);// Verify against period computed from semi-major axisletperiod_from_sma=bh::orbits::orbital_period(a);println!("\nOrbital period from SMA: {:.3} s",period_from_sma);println!("Difference: {:.2e} s",(period-period_from_sma).abs());}
ECI State (position in km, velocity in km/s):
r = [1848.964, -434.937, 6560.411] km
v = [-7.098, -2.173, 1.913] km/s
Orbital period from state: 5676.977 s
Orbital period from state: 94.616 min
Orbital period from SMA: 5676.977 s
Difference: 9.09e-13 s
ECI State (position in km, velocity in km/s):
r = [1848.964, -434.937, 6560.411] km
v = [-7.098, -2.173, 1.913] km/s
Orbital period from state: 5676.977 s
Orbital period from state: 94.616 min
Orbital period from SMA: 5676.977 s
Difference: 9.09e-13 s
importbraheasbhbh.initialize_eop()# Example 1: LEO satellite with 98-minute periodperiod_leo=98*60# 98 minutes in secondsa_leo=bh.semimajor_axis_from_orbital_period(period_leo)altitude_leo=a_leo-bh.R_EARTHprint("LEO Satellite (98 min period):")print(f" Semi-major axis: {a_leo:.3f} m")print(f" Altitude: {altitude_leo/1e3:.3f} km")# Example 2: Geosynchronous orbit (24-hour period)period_geo=24*3600# 24 hours in secondsa_geo=bh.semimajor_axis_from_orbital_period(period_geo)altitude_geo=a_geo-bh.R_EARTHprint("\nGeosynchronous Orbit (24 hour period):")print(f" Semi-major axis: {a_geo:.3f} m")print(f" Altitude: {altitude_geo/1e3:.3f} km")# Example 3: Using general function for Moon orbitperiod_moon=27.3*24*3600# 27.3 days in secondsa_moon=bh.semimajor_axis_from_orbital_period_general(period_moon,bh.GM_EARTH)print("\nMoon's orbit (27.3 day period):")print(f" Semi-major axis: {a_moon/1e3:.3f} km")# Verify round-trip conversionperiod_verify=bh.orbital_period(a_leo)print("\nRound-trip verification:")print(f" Original period: {period_leo:.3f} s")print(f" Computed period: {period_verify:.3f} s")print(f" Difference: {abs(period_leo-period_verify):.2e} s")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Example 1: LEO satellite with 98-minute periodletperiod_leo=98.0*60.0;// 98 minutes in secondsleta_leo=bh::orbits::semimajor_axis_from_orbital_period(period_leo);letaltitude_leo=a_leo-bh::constants::R_EARTH;println!("LEO Satellite (98 min period):");println!(" Semi-major axis: {:.3} m",a_leo);println!(" Altitude: {:.3} km",altitude_leo/1e3);// Example 2: Geosynchronous orbit (24-hour period)letperiod_geo=24.0*3600.0;// 24 hours in secondsleta_geo=bh::orbits::semimajor_axis_from_orbital_period(period_geo);letaltitude_geo=a_geo-bh::constants::R_EARTH;println!("\nGeosynchronous Orbit (24 hour period):");println!(" Semi-major axis: {:.3} m",a_geo);println!(" Altitude: {:.3} km",altitude_geo/1e3);// Example 3: Using general function for Moon orbitletperiod_moon=27.3*24.0*3600.0;// 27.3 days in secondsleta_moon=bh::orbits::semimajor_axis_from_orbital_period_general(period_moon,bh::constants::GM_EARTH);println!("\nMoon's orbit (27.3 day period):");println!(" Semi-major axis: {:.3} km",a_moon/1e3);// Verify round-trip conversionletperiod_verify=bh::orbits::orbital_period(a_leo);println!("\nRound-trip verification:");println!(" Original period: {:.3} s",period_leo);println!(" Computed period: {:.3} s",period_verify);println!(" Difference: {:.2e} s",(period_leo-period_verify).abs());}
LEO Satellite (98 min period):
Semi-major axis: 7041160.278 m
Altitude: 663.024 km
Geosynchronous Orbit (24 hour period):
Semi-major axis: 42241095.664 m
Altitude: 35862.959 km
Moon's orbit (27.3 day period):
Semi-major axis: 382980.745 km
Round-trip verification:
Original period: 5880.000 s
Computed period: 5880.000 s
Difference: 8.19e-12 s
LEO Satellite (98 min period):
Semi-major axis: 7041160.278 m
Altitude: 663.024 km
Geosynchronous Orbit (24 hour period):
Semi-major axis: 42241095.664 m
Altitude: 35862.959 km
Moon's orbit (27.3 day period):
Semi-major axis: 382980.745 km
Round-trip verification:
Original period: 5880.000 s
Computed period: 5880.000 s
Difference: 8.19e-12 s
A satellite's average angular rate over one orbit is its mean motion\(n\), calculated from the semi-major axis and gravitational parameter:
\[ n = \sqrt{\frac{\mu}{a^3}} \]
The mean_motion function computes this for Earth-orbiting objects, while mean_motion_general works for any celestial body. Both functions support output in radians or degrees per second via the angle_format parameter.
importbraheasbhbh.initialize_eop()# Define orbit parametersa_leo=bh.R_EARTH+500.0e3# LEO satellite at 500 km altitudea_geo=bh.R_EARTH+35786e3# GEO satellite# Compute mean motion in radians/s (Earth-specific)n_leo_rad=bh.mean_motion(a_leo,bh.AngleFormat.RADIANS)n_geo_rad=bh.mean_motion(a_geo,bh.AngleFormat.RADIANS)print("Mean Motion in radians/second:")print(f" LEO (500 km): {n_leo_rad:.6f} rad/s")print(f" GEO: {n_geo_rad:.6f} rad/s")# Compute mean motion in degrees/sn_leo_deg=bh.mean_motion(a_leo,bh.AngleFormat.DEGREES)n_geo_deg=bh.mean_motion(a_geo,bh.AngleFormat.DEGREES)print("\nMean Motion in degrees/second:")print(f" LEO (500 km): {n_leo_deg:.6f} deg/s")print(f" GEO: {n_geo_deg:.6f} deg/s")# Convert to degrees/day (common unit for TLEs)print("\nMean Motion in degrees/day:")print(f" LEO (500 km): {n_leo_deg*86400:.3f} deg/day")print(f" GEO: {n_geo_deg*86400:.3f} deg/day")# Verify using general functionn_leo_general=bh.mean_motion_general(a_leo,bh.GM_EARTH,bh.AngleFormat.RADIANS)print(f"\nVerification (general function): {n_leo_general:.6f} rad/s")print(f"Difference: {abs(n_leo_rad-n_leo_general):.2e} rad/s")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Define orbit parametersleta_leo=bh::constants::R_EARTH+500.0e3;// LEO satellite at 500 km altitudeleta_geo=bh::constants::R_EARTH+35786e3;// GEO satellite// Compute mean motion in radians/s (Earth-specific)letn_leo_rad=bh::orbits::mean_motion(a_leo,bh::constants::AngleFormat::Radians);letn_geo_rad=bh::orbits::mean_motion(a_geo,bh::constants::AngleFormat::Radians);println!("Mean Motion in radians/second:");println!(" LEO (500 km): {:.6} rad/s",n_leo_rad);println!(" GEO: {:.6} rad/s",n_geo_rad);// Compute mean motion in degrees/sletn_leo_deg=bh::orbits::mean_motion(a_leo,bh::constants::AngleFormat::Degrees);letn_geo_deg=bh::orbits::mean_motion(a_geo,bh::constants::AngleFormat::Degrees);println!("\nMean Motion in degrees/second:");println!(" LEO (500 km): {:.6} deg/s",n_leo_deg);println!(" GEO: {:.6} deg/s",n_geo_deg);// Convert to degrees/day (common unit for TLEs)println!("\nMean Motion in degrees/day:");println!(" LEO (500 km): {:.3} deg/day",n_leo_deg*86400.0);println!(" GEO: {:.3} deg/day",n_geo_deg*86400.0);// Verify using general functionletn_leo_general=bh::orbits::mean_motion_general(a_leo,bh::constants::GM_EARTH,bh::constants::AngleFormat::Radians);println!("\nVerification (general function): {:.6} rad/s",n_leo_general);println!("Difference: {:.2e} rad/s",(n_leo_rad-n_leo_general).abs());}
Mean Motion in radians/second:
LEO (500 km): 0.001107 rad/s
GEO: 0.000073 rad/s
Mean Motion in degrees/second:
LEO (500 km): 0.063414 deg/s
GEO: 0.004178 deg/s
Mean Motion in degrees/day:
LEO (500 km): 5478.972 deg/day
GEO: 360.986 deg/day
Verification (general function): 0.001107 rad/s
Difference: 0.00e+00 rad/s
Mean Motion in radians/second:
LEO (500 km): 0.001107 rad/s
GEO: 0.000073 rad/s
Mean Motion in degrees/second:
LEO (500 km): 0.063414 deg/s
GEO: 0.004178 deg/s
Mean Motion in degrees/day:
LEO (500 km): 5478.972 deg/day
GEO: 360.986 deg/day
Verification (general function): 0.001107 rad/s
Difference: 0.00e0 rad/s
ISS-like Orbit (15.5 revs/day):
Mean motion: 0.064583 deg/s
Semi-major axis: 6794863.068 m
Altitude: 416.727 km
Geosynchronous Orbit (1 rev/day):
Mean motion: 0.004167 deg/s
Semi-major axis: 42241095.664 m
Altitude: 35862.959 km
LEO from radians/s:
Mean motion: 0.001000 rad/s
Semi-major axis: 7359459.593 m
Altitude: 981.323 km
Round-trip verification:
Original mean motion: 0.064583 deg/s
Computed mean motion: 0.064583 deg/s
Difference: 9.71e-17 deg/s
ISS-like Orbit (15.5 revs/day):
Mean motion: 0.064583 deg/s
Semi-major axis: 6794863.068 m
Altitude: 416.727 km
Geosynchronous Orbit (1 rev/day):
Mean motion: 0.004167 deg/s
Semi-major axis: 42241095.664 m
Altitude: 35862.959 km
LEO from radians/s:
Mean motion: 0.001000 rad/s
Semi-major axis: 7359459.593 m
Altitude: 981.323 km
Round-trip verification:
Original mean motion: 0.064583 deg/s
Computed mean motion: 0.064583 deg/s
Difference: 9.71e-17 deg/s
The periapsis is the point of closest approach to the central body, where orbital velocity is greatest.
Info
The word periapsis is formed by combination of the Greek words "peri-" (meaning around, about) and "apsis" (meaning "arch or vault"). An apsis is the farthest or nearest point in the orbit of a planetary body about its primary body.
Therefore periapsis is the point of closest approach of the orbiting body with respect to its central body. The suffix can be modified to indicate the closest approach to a specific celestial body: perigee for Earth, perihelion for the Sun.
Brahe provides functions to compute periapsis velocity, distance, and altitude based on orbital elements.
The periapsis altitude is the height above the surface of the central body:
\[ h_p = r_p - R_{body} = a(1-e) - R_{body} \]
where \(R_{body}\) is the radius of the central body. For Earth orbits, the perigee_altitude function provides a convenient wrapper using \(R_{\oplus}\).
Periapsis velocity: 7689.119 m/s
Perigee velocity: 7689.119 m/s
Periapsis distance: 6809.355 km
Periapsis altitude: 431.219 km
Perigee altitude: 431.219 km
Periapsis velocity: 7689.119 m/s
Perigee velocity: 7689.119 m/s
Periapsis distance: 6809.355 km
Periapsis altitude: 431.219 km
Perigee altitude: 431.219 km
The apoapsis is the farthest point from the central body, where orbital velocity is lowest.
Info
The word apoapsis is formed by combination of the Greek words "apo-" (meaning away from, separate, or apart from) and "apsis".
Therefore apoapsis is the farthest point of an orbiting body with respect to its central body. The suffix can be modified to indicate the farthest point from a specific celestial body: apogee for Earth, aphelion for the Sun.
Brahe provides functions to compute apoapsis velocity, distance, and altitude based on orbital elements.
Warning
Apoapsis position, velocity, and altitude are only defined for elliptic and circular orbits. For parabolic and hyperbolic orbits, these quantities are undefined.
The apoapsis altitude is the height above the surface of the central body:
\[ h_a = r_a - R_{body} = a(1+e) - R_{body} \]
where \(R_{body}\) is the radius of the central body. For Earth orbits, the apogee_altitude function provides a convenient wrapper using \(R_{\oplus}\).
A sun-synchronous orbit maintains a constant angle relative to the Sun by matching its nodal precession rate to Earth's annual revolution. The right ascension of the ascending node (\(\Omega\)) advances at the same rate as the Sun's apparent motion: approximately 0.9856°/day. This configuration is highly valuable for Earth observation satellites requiring consistent illumination conditions—a sun-synchronous satellite crosses the equator at the same local time on each pass (e.g., always at 2 PM).
Earth's oblateness, characterized by the \(J_2\) zonal harmonic, causes secular drift in \(\Omega\):
#[allow(unused_imports)]usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Example 1: Typical sun-synchronous LEO at 800 km altitudeleta_leo=bh::constants::R_EARTH+800e3;// Semi-major axislete_leo=0.0;// Circular orbitletinc_leo_deg=bh::orbits::sun_synchronous_inclination(a_leo,e_leo,bh::constants::AngleFormat::Degrees);letinc_leo_rad=bh::orbits::sun_synchronous_inclination(a_leo,e_leo,bh::constants::AngleFormat::Radians);println!("Sun-synchronous LEO (800 km, circular):");println!(" Inclination: {:.3} degrees",inc_leo_deg);println!(" Inclination: {:.6} radians",inc_leo_rad);// Example 2: Different altitudesletaltitudes=[500.0,600.0,700.0,800.0,900.0,1000.0];// kmprintln!("\nSun-synchronous inclination vs altitude (circular orbits):");foralt_kminaltitudes.iter(){leta=bh::constants::R_EARTH+alt_km*1e3;letinc=bh::orbits::sun_synchronous_inclination(a,0.0,bh::constants::AngleFormat::Degrees);println!(" {:4} km: {:.3} deg",*alt_kmasi32,inc);}// Example 3: Effect of eccentricityleta_fixed=bh::constants::R_EARTH+700e3;leteccentricities=[0.0,0.001,0.005,0.01,0.02];println!("\nSun-synchronous inclination vs eccentricity (700 km orbit):");foreineccentricities.iter(){letinc=bh::orbits::sun_synchronous_inclination(a_fixed,*e,bh::constants::AngleFormat::Degrees);println!(" e = {:.3}: {:.3} deg",e,inc);}// Example 4: Practical mission example (Landsat-like)leta_landsat=bh::constants::R_EARTH+705e3;lete_landsat=0.0001;letinc_landsat=bh::orbits::sun_synchronous_inclination(a_landsat,e_landsat,bh::constants::AngleFormat::Degrees);println!("\nLandsat-like orbit (705 km, nearly circular):");println!(" Inclination: {:.3} deg",inc_landsat);println!(" Period: {:.3} min",bh::orbits::orbital_period(a_landsat)/60.0);}
importosimportpathlibimportsysimportnumpyasnpimportplotly.graph_objectsasgoimportbraheasbh# Add plots directory to path for importing brahe_themesys.path.insert(0,str(pathlib.Path(__file__).parent))frombrahe_themeimportget_theme_colors,save_themed_html# ConfigurationSCRIPT_NAME=pathlib.Path(__file__).stemOUTDIR=pathlib.Path(os.getenv("BRAHE_FIGURE_OUTPUT_DIR","./docs/figures/"))# Ensure output directory existsos.makedirs(OUTDIR,exist_ok=True)# Generate data# Generate range of altitudes from 300 to 1000 km in 1 km incrementsalt=np.arange(300e3,1000e3,1e3)# Compute sun-synchronous inclination for range of eccentricitieseccentricities=[0.0,0.1,0.3,0.5]ssi_data={}foreineccentricities:ssi_data[e]=[bh.sun_synchronous_inclination(bh.R_EARTH+a,e,angle_format=bh.AngleFormat.DEGREES)forainalt]# Create figure with theme supportdefcreate_figure(theme):"""Create figure with theme-specific colors."""colors=get_theme_colors(theme)fig=go.Figure()# Color palette for different eccentricitiescolor_palette=[colors["primary"],colors["secondary"],colors["accent"],colors["error"],]# Add traces for each eccentricityfori,einenumerate(eccentricities):fig.add_trace(go.Scatter(x=alt/1e3,y=ssi_data[e],mode="lines",line=dict(color=color_palette[i%len(color_palette)],width=2),name=f"e = {e:.1f}",showlegend=True,))# Configure axesfig.update_xaxes(tickmode="linear",tick0=300,dtick=100,title_text="Satellite Altitude [km]",range=[300,1000],showgrid=False,)fig.update_yaxes(tickmode="linear",title_text="Inclination [deg]",showgrid=False,)returnfig# Generate and save both themed versionslight_path,dark_path=save_themed_html(create_figure,OUTDIR/SCRIPT_NAME)print(f"✓ Generated {light_path}")print(f"✓ Generated {dark_path}")
Most sun-synchronous Earth observation missions operate at altitudes between 500-1000 km with near-zero eccentricity. The launch provider selects the precise inclination based on the above equation to achieve the desired sun-synchronous behavior.