contact#
Satellite pass prediction and contact window computation.
contact computes when a satellite is visible from a ground station:
acquisition of signal (AOS), loss of signal (LOS), maximum elevation,
and pass duration. Orbit propagation is delegated to
sgp4 (SGP4 from the NORAD General Perturbations models) and
coordinate transforms to coordinate.
Installation#
Install with opam:
$ opam install contact
If opam cannot find the package, it may not yet be released in the
public opam-repository. Add the overlay repository, then install
it:
$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install contact
Usage#
Parse a Two-Line Element set, define a ground station, and predict all visible passes over a time window. The TLE below is an idealised ISS element set with epoch 2026-01-01; passes are computed from that epoch:
# let tle_string =
"ISS (ZARYA)\n\
1 25544U 98067A 26001.00000000 .00001764 00000+0 39538-4 0 9991\n\
2 25544 51.6416 45.0000 0008003 90.0000 0.0000 15.49560000 15" in
let tle = Result.get_ok (Sgp4.parse_tle_string tle_string) in
let la = Contact.ground_station ~lat:34.05 ~lon:(-118.25) ~alt:0.071 in
let passes = Contact.predict tle la ~duration_days:3.0 in
List.length passes
- : int = 15
Each pass carries AOS/LOS Unix timestamps, ISO-8601 strings, the peak elevation in degrees, and duration in seconds:
# let tle_string =
"ISS (ZARYA)\n\
1 25544U 98067A 26001.00000000 .00001764 00000+0 39538-4 0 9991\n\
2 25544 51.6416 45.0000 0008003 90.0000 0.0000 15.49560000 15" in
let tle = Result.get_ok (Sgp4.parse_tle_string tle_string) in
let la = Contact.ground_station ~lat:34.05 ~lon:(-118.25) ~alt:0.071 in
match Contact.predict tle la ~duration_days:3.0 with
| { max_elevation; duration; _ } :: _ ->
Fmt.str "first pass: %.1f deg peak, %.0fs long"
max_elevation duration
| [] -> "no passes"
- : string = "first pass: 61.6 deg peak, 630s long"
Contact.elevation computes a point-in-time elevation angle instead
of scanning for full pass windows:
# let tle_string =
"ISS (ZARYA)\n\
1 25544U 98067A 26001.00000000 .00001764 00000+0 39538-4 0 9991\n\
2 25544 51.6416 45.0000 0008003 90.0000 0.0000 15.49560000 15" in
let tle = Result.get_ok (Sgp4.parse_tle_string tle_string) in
let la = Contact.ground_station ~lat:34.05 ~lon:(-118.25) ~alt:0.071 in
let epoch_unix = Sgp4.epoch_unix tle in
match Contact.elevation tle la epoch_unix with
| Some el -> Fmt.str "%.2f" el
| None -> "N/A"
- : string = "-43.84"
A negative elevation means the satellite is below the horizon; pass
prediction filters these out using min_elevation (default 5°).
Licence#
ISC