GCAT (General Catalog of Artificial Space Objects) is Jonathan McDowell's comprehensive catalog of all known artificial objects in space. Brahe provides functions to download and query two GCAT catalogs: SATCAT (satellite catalog) and PSATCAT (payload satellite catalog), with automatic file-based caching.
What is GCAT?
GCAT is an independent catalog maintained by astrophysicist Jonathan McDowell at the Harvard-Smithsonian Center for Astrophysics. It provides detailed metadata for every cataloged space object, including physical dimensions, orbital parameters, ownership, and mission details. Unlike the US Space Command catalog (which focuses on tracking), GCAT emphasizes comprehensive metadata about each object's identity and purpose.
The SATCAT catalog contains physical, orbital, and administrative metadata for all cataloged artificial space objects. Each record includes 42 fields organized into several categories:
The PSATCAT catalog contains payload-specific metadata for missions, extending the SATCAT with operational and registry information. Each record includes 28 fields:
Category
Fields
Description
Mission
program, class (Python: class_), category, discipline, result
importbraheasbh# Download the SATCAT catalog (cached for 24 hours by default)satcat=bh.datasets.gcat.get_satcat()print(f"Loaded {len(satcat)} SATCAT records")# Look up the ISS by NORAD SATCAT numberiss=satcat.get_by_satcat("25544")ifiss:print("\nISS (by SATCAT number 25544):")print(f" JCAT: {iss.jcat}")print(f" Name: {iss.name}")print(f" Status: {iss.status}")print(f" Perigee: {iss.perigee} km")print(f" Apogee: {iss.apogee} km")print(f" Inc: {iss.inc}°")# Look up by JCAT identifierrecord=satcat.get_by_jcat("S049652")ifrecord:print(f"\nRecord by JCAT S049652: {record.name}")
#[allow(unused_imports)]usebraheasbh;usebh::datasets::gcat;fnmain(){// Download the SATCAT catalog (cached for 24 hours by default)letsatcat=gcat::get_satcat(None).unwrap();println!("Loaded {} SATCAT records",satcat.len());// Look up the ISS by NORAD SATCAT numberifletSome(iss)=satcat.get_by_satcat("25544"){println!("\nISS (by SATCAT number 25544):");println!(" JCAT: {}",iss.jcat);println!(" Name: {}",iss.name.as_deref().unwrap_or("Unknown"));println!(" Status: {}",iss.status.as_deref().unwrap_or("Unknown"));println!(" Perigee: {} km",iss.perigee.map_or("N/A".to_string(),|v|format!("{v}")));println!(" Apogee: {} km",iss.apogee.map_or("N/A".to_string(),|v|format!("{v}")));println!(" Inc: {}°",iss.inc.map_or("N/A".to_string(),|v|format!("{v}")));}// Look up by JCAT identifierifletSome(record)=satcat.get_by_jcat("S049652"){println!("\nRecord by JCAT S049652: {}",record.name.as_deref().unwrap_or("Unknown"));}}
importbraheasbh# Download the SATCAT catalogsatcat=bh.datasets.gcat.get_satcat()print(f"Total records: {len(satcat)}")# Search by name (case-insensitive, searches both name and pl_name)starlink=satcat.search_by_name("starlink")print(f"\nStarlink name search: {len(starlink)} results")# Filter chaining: payloads that are operational in LEOpayloads=satcat.filter_by_type("P")print(f"\nAll payloads: {len(payloads)}")operational=payloads.filter_by_status("O")print(f"Operational payloads: {len(operational)}")leo=operational.filter_by_perigee_range(160.0,2000.0)print(f"Operational LEO payloads: {len(leo)}")# Filter by inclination range (sun-synchronous orbits ~96-99 deg)sso=operational.filter_by_inc_range(96.0,99.0)print(f"Operational SSO payloads: {len(sso)}")
#[allow(unused_imports)]usebraheasbh;usebh::datasets::gcat;fnmain(){// Download the SATCAT catalogletsatcat=gcat::get_satcat(None).unwrap();println!("Total records: {}",satcat.len());// Search by name (case-insensitive, searches both name and pl_name)letstarlink=satcat.search_by_name("starlink");println!("\nStarlink name search: {} results",starlink.len());// Filter chaining: payloads that are operational in LEOletpayloads=satcat.filter_by_type("P");println!("\nAll payloads: {}",payloads.len());letoperational=payloads.filter_by_status("O");println!("Operational payloads: {}",operational.len());letleo=operational.filter_by_perigee_range(160.0,2000.0);println!("Operational LEO payloads: {}",leo.len());// Filter by inclination range (sun-synchronous orbits ~96-99 deg)letsso=operational.filter_by_inc_range(96.0,99.0);println!("Operational SSO payloads: {}",sso.len());}
Total records: 68349
Starlink name search: 11947 results
All payloads: 8777
Operational payloads: 4938
Operational LEO payloads: 3783
Operational SSO payloads: 1758
All filter methods return new catalog instances (immutable pattern), so the original catalog is never modified. This enables chaining multiple filters to progressively narrow results.
importbraheasbh# Download the PSATCAT catalogpsatcat=bh.datasets.gcat.get_psatcat()print(f"Loaded {len(psatcat)} PSATCAT records")# Filter for active payloads (result="S" and no end date)active=psatcat.filter_active()print(f"Active payloads: {len(active)}")# Filter by mission category (COM=communications, IMG=imaging, NAV=navigation, etc.)comms=psatcat.filter_by_category("COM")print(f"\nCommunications payloads: {len(comms)}")# Filter by mission class (A=amateur, B=business, C=civil, D=defense)civil=psatcat.filter_by_class("C")print(f"Civil payloads: {len(civil)}")# Look up a specific payload (ISS Zarya module)iss=psatcat.get_by_jcat("S25544")ifiss:print("\nISS Payload Details:")print(f" Name: {iss.name}")print(f" Program: {iss.program}")print(f" Category: {iss.category}")print(f" Class: {iss.class_}")print(f" Result: {iss.result}")
#[allow(unused_imports)]usebraheasbh;usebh::datasets::gcat;fnmain(){// Download the PSATCAT catalogletpsatcat=gcat::get_psatcat(None).unwrap();println!("Loaded {} PSATCAT records",psatcat.len());// Filter for active payloads (result="S" and no end date)letactive=psatcat.filter_active();println!("Active payloads: {}",active.len());// Filter by mission category (COM=communications, IMG=imaging, NAV=navigation, etc.)letcomms=psatcat.filter_by_category("COM");println!("\nCommunications payloads: {}",comms.len());// Filter by mission class (A=amateur, B=business, C=civil, D=defense)letcivil=psatcat.filter_by_class("C");println!("Civil payloads: {}",civil.len());// Look up a specific payload (ISS Zarya module)ifletSome(iss)=psatcat.get_by_jcat("S25544"){println!("\nISS Payload Details:");println!(" Name: {}",iss.name.as_deref().unwrap_or("Unknown"));println!(" Program: {}",iss.program.as_deref().unwrap_or("Unknown"));println!(" Category: {}",iss.category.as_deref().unwrap_or("Unknown"));println!(" Class: {}",iss.class.as_deref().unwrap_or("Unknown"));println!(" Result: {}",iss.result.as_deref().unwrap_or("Unknown"));}}
Loaded 26362 PSATCAT records
Active payloads: 15060
Communications payloads: 16184
Civil payloads: 3249
ISS Payload Details:
Name: Zarya Cargo Block
Program: TsM
Category: SS
Class: C
Result: S
Loaded 26362 PSATCAT records
Active payloads: 15060
Communications payloads: 16184
Civil payloads: 3249
ISS Payload Details:
Name: Zarya Cargo Block
Program: TsM
Category: SS
Class: C
Result: S
Both catalogs support conversion to Polars DataFrames for analysis. In Python, to_dataframe() returns a polars.DataFrame; in Rust, it returns a polars::DataFrame: