astrotrack 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, Gabriella Mariam Zahra Rajpoot
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: astrotrack
3
+ Version: 0.1.0
4
+ Summary: A tool for analysing and investigating LEO satellite flyover occurrences with contamination in radio astronomy observational data.
5
+ Author-email: Gabriella Mariam Zahra Rajpoot <LetterToGabi@gmail.com>
6
+ License: BSD 3-Clause License
7
+ Keywords: astronomy,satellite,radio,signal,analysis,LEO,skyfield
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: numpy>=1.25
12
+ Requires-Dist: matplotlib>=3.5
13
+ Requires-Dist: pandas>=2.0
14
+ Requires-Dist: scipy>=1.10
15
+ Requires-Dist: astropy>=7.0
16
+ Requires-Dist: skyfield>=1.50
17
+ Requires-Dist: h5py>=3.10
18
+ Requires-Dist: tabulate>=0.9
19
+ Requires-Dist: tqdm>=4.60
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest; extra == "dev"
22
+ Requires-Dist: pytest-cov; extra == "dev"
23
+ Requires-Dist: build>=1.0; extra == "dev"
24
+ Requires-Dist: twine>=6.0; extra == "dev"
25
+ Requires-Dist: black; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # astrotrack: Characterising LEO Satellite RFI in Wide-Field Radio Astronomy
29
+
30
+ ![CI](https://github.com/Gabriella8080/astrotrack/actions/workflows/CI.yml/badge.svg) ![License](https://img.shields.io/badge/license-BSD--3-blue)
31
+
32
+ ## Overview
33
+
34
+ `astrotrack` is an open-source Python package for characterising potential Low Earth Orbit (LEO) satellite interference in wide-field radio astronomy observations. While interferometric arrays are able to spatially localise LEO satellite radiation, wide-beam radiometers like REACH (de Lera Acedo et al. 2022) integrate the total sky power into a frequency spectrum and therefore lack equivalent strategies for identifying satellite-generated contamination. To address this limitation, `astrotrack` provides tools for combining Two-Line Element (TLE) data with site-specific observational constraints to identify LEO satellite flyovers and investigate their potential association with radio frequency interference (RFI).
35
+
36
+ > **Accompanying Paper**: *'astrotrack: Characterising LEO Satellite Interference in Wide-Field Radio Astronomy'*, in preparation.
37
+
38
+ <br>
39
+ <div align="center">
40
+ <img src="docs/images/animated_satellites.gif" width="600">
41
+ <p><em>3-D trajectory animation generated by AstroTrack's <code>satcon_animate</code> module of Eutelsat OneWeb satellite flyovers at the REACH site in the Karoo radio reserve, South Africa on 15 June 2025.</em></p>
42
+ </div>
43
+ <br>
44
+
45
+ ## Repository Structure
46
+
47
+ | Paths | Description |
48
+ | ----- | ------------|
49
+ | [`data/`](data/) | CSV horizon profiles, including a [baseline](data/horizon-profiles/baseline-horizon.csv) and [REACH radiometer](data/horizon-profiles/REACH-horizon.csv) horizon profile. Alongside this, the [TLE catalogue](data/TLE-catalogues/TLEs.txt) used in exemplar and experimental analyses is provided. |
50
+ | [`docs/`](docs/) | [Example usage](docs/examples/) of functionalities across `astrotrack` modules. |
51
+ | [`astrotrack/`](astrotrack/) | `astrotrack` Python package source code. |
52
+ | [`notebooks/astrotrack_demo/`](/notebooks/astrotrack_demo/) | [Demonstration notebook](notebooks/astrotrack_demo/01_astrotrack_demo.ipynb) showing example `astrotrack` workflow. |
53
+ | [`notebooks/astrotrack_results/`](notebooks/astrotrack_results/) | Notebooks documenting experimental results and analyses. |
54
+ | [`tests`](tests/) | Unit tests validating `astrotrack` functionalities and edge case performance.|
55
+ | [`environment.yml`](environment.yml) | Conda environment for `astrotrack` specifying required dependencies.|
56
+
57
+
58
+ ## Data Availability
59
+
60
+ Raw HDF5 files containing PSD observations used for comparison are proprietary to the REACH collaboration and are therefore not made publicly available. The publicly available 12,270 TLEs used in this work are provided in a [CSV file](data/TLE-catalogues/TLEs.txt) downloaded from [Space-Track](https://www.space-track.org) on 17:10:37 UTC 14 June 2025.
61
+
62
+
63
+ ## `astrotrack` Installation
64
+
65
+ To install `astrotrack` from source, follow the instructions below:
66
+
67
+ ```bash
68
+ conda env create -f environment.yml
69
+ conda activate astrotrack
70
+ pip install -e .
71
+ ```
72
+
73
+ The package can then be imported using:
74
+
75
+ ```bash
76
+ import astrotrack
77
+ ```
78
+
79
+ `astrotrack` is recommended to be used with the provided Conda [environment](environment.yml).
80
+
81
+
82
+ ## Quick Start
83
+
84
+ The below example demonstrates how to initialise `astrotrack` using a provided TLE catalogue along with user-defined observational constraints, the satellite constellation of interest, and a target date:
85
+
86
+ ```python
87
+ from datetime import datetime
88
+ from astrotrack.preprocess import load_satellite_data
89
+
90
+ data = load_satellite_data(
91
+ tle_file="LEO_TLE_file.txt",
92
+ target_date=datetime(2025, 1, 18, 12, 25, 8),
93
+ obs_len=3600,
94
+ traj_res=60,
95
+ obs_lat=51.5,
96
+ obs_lon=-0.1,
97
+ R=2000,
98
+ horizon_data="Horizon-Profile.csv",
99
+ satcon="STARLINK"
100
+ )
101
+ ```
102
+
103
+ > **Generating Epoch Times with Skyfield**: The following code can be used to initialise a time array for satellite propagation.
104
+ >
105
+ >```python
106
+ >import numpy as np
107
+ >from skyfield.api import load
108
+ >
109
+ ># Create a timescale object:
110
+ >ts = load.timescale()
111
+ >
112
+ ># Define orbit duration:
113
+ >orbit_duration = np.arange(0, 3600, 1) # in seconds
114
+ >
115
+ ># Generate time array:
116
+ >epochs_of_orbit = ts.utc(2025, 1, 1, 10, 15, 0 + orbit_duration)
117
+ >```
118
+ >
119
+
120
+
121
+ ## Example Usage & Workflow
122
+
123
+ `astrotrack` is organised into five modules. A typical workflow begins with initialising and structuring satellite Two-Line Element (TLE) data for analysis, after which the subsequent modules derive orbital properties, Doppler behaviour with respect to a ground-based experiment, animations, and enable spectral associations.
124
+
125
+ <br>
126
+ <div align="center">
127
+ <img src="docs/images/package-modules.png" width="600">
128
+ </div>
129
+ <br>
130
+
131
+ - [`preprocess`](): Loads and filters satellite TLE data provided by the user.
132
+ - [`satcon_properties`](): Filters, analyses, and visualises satellite trajectories as well as their metrics.
133
+ - [`doppler_analysis`](): Evaluates Doppler shifts and detectability relative to a user-defined instrument's specifications.
134
+ - [`satcon_animate`](): Generates 3-D trajectory animations.
135
+ - [`psd_analysis`](): Visualises satellite flyover properties alongside measured PSD data coincidential with satellite flyovers.
136
+
137
+ A detailed overview of all five modules, their key functions, and example usage is provided in a supplementary [document](docs/examples/examples.md).
138
+
139
+
140
+ A [demonstration notebook](notebooks/astrotrack_demo/01_astrotrack_demo.ipynb) is also provided, and includes usage of an example [horizon profile](data/horizon-profiles/REACH-horizon.csv) from the REACH experiment as well as a [TLE catalogue](data/TLE-catalogues/TLEs.txt) compiled from [Space-Track](https://www.space-track.org). A [baseline horizon profile](data/horizon-profiles/baseline-horizon.csv) corresponding to an idealised flat horizon is additionally available to be used directly, or modified by the user to incorporate site-specific observational constraints.
141
+
142
+ ## Testing \& Validation
143
+
144
+ `astrotrack` is validated using unit tests covering the package's functionalities from [TLE preprocessing](tests/preprocess_test.py), deriving [satellite properties](tests/satcon_properties_test.py), performing [Doppler Analysis](tests/doppler_analysis_test.py), and analysis with [PSD observations](tests/psd_analysis_test.py).
145
+
146
+ The entire test suite can be run using:
147
+ ```bash
148
+ pytest
149
+ ```
150
+
151
+ ## License
152
+
153
+ The `astrotrack` Python package source code is released under BSD 3-Clause License, with citation details provided in the [`CITATION.cff`](CITATION.cff) file.
154
+
155
+ ## Bibliography
156
+
157
+ de Lera Acedo, E., de Villiers, D.I.L., Razavi-Ghods, N. et al. *The REACH radiometer for detecting the 21-cm hydrogen signal from redshift z ≈ 7.5–28*. Nat Astron 6, 984–998 (2022). https://doi.org/10.1038/s41550-022-01709-9
@@ -0,0 +1,130 @@
1
+ # astrotrack: Characterising LEO Satellite RFI in Wide-Field Radio Astronomy
2
+
3
+ ![CI](https://github.com/Gabriella8080/astrotrack/actions/workflows/CI.yml/badge.svg) ![License](https://img.shields.io/badge/license-BSD--3-blue)
4
+
5
+ ## Overview
6
+
7
+ `astrotrack` is an open-source Python package for characterising potential Low Earth Orbit (LEO) satellite interference in wide-field radio astronomy observations. While interferometric arrays are able to spatially localise LEO satellite radiation, wide-beam radiometers like REACH (de Lera Acedo et al. 2022) integrate the total sky power into a frequency spectrum and therefore lack equivalent strategies for identifying satellite-generated contamination. To address this limitation, `astrotrack` provides tools for combining Two-Line Element (TLE) data with site-specific observational constraints to identify LEO satellite flyovers and investigate their potential association with radio frequency interference (RFI).
8
+
9
+ > **Accompanying Paper**: *'astrotrack: Characterising LEO Satellite Interference in Wide-Field Radio Astronomy'*, in preparation.
10
+
11
+ <br>
12
+ <div align="center">
13
+ <img src="docs/images/animated_satellites.gif" width="600">
14
+ <p><em>3-D trajectory animation generated by AstroTrack's <code>satcon_animate</code> module of Eutelsat OneWeb satellite flyovers at the REACH site in the Karoo radio reserve, South Africa on 15 June 2025.</em></p>
15
+ </div>
16
+ <br>
17
+
18
+ ## Repository Structure
19
+
20
+ | Paths | Description |
21
+ | ----- | ------------|
22
+ | [`data/`](data/) | CSV horizon profiles, including a [baseline](data/horizon-profiles/baseline-horizon.csv) and [REACH radiometer](data/horizon-profiles/REACH-horizon.csv) horizon profile. Alongside this, the [TLE catalogue](data/TLE-catalogues/TLEs.txt) used in exemplar and experimental analyses is provided. |
23
+ | [`docs/`](docs/) | [Example usage](docs/examples/) of functionalities across `astrotrack` modules. |
24
+ | [`astrotrack/`](astrotrack/) | `astrotrack` Python package source code. |
25
+ | [`notebooks/astrotrack_demo/`](/notebooks/astrotrack_demo/) | [Demonstration notebook](notebooks/astrotrack_demo/01_astrotrack_demo.ipynb) showing example `astrotrack` workflow. |
26
+ | [`notebooks/astrotrack_results/`](notebooks/astrotrack_results/) | Notebooks documenting experimental results and analyses. |
27
+ | [`tests`](tests/) | Unit tests validating `astrotrack` functionalities and edge case performance.|
28
+ | [`environment.yml`](environment.yml) | Conda environment for `astrotrack` specifying required dependencies.|
29
+
30
+
31
+ ## Data Availability
32
+
33
+ Raw HDF5 files containing PSD observations used for comparison are proprietary to the REACH collaboration and are therefore not made publicly available. The publicly available 12,270 TLEs used in this work are provided in a [CSV file](data/TLE-catalogues/TLEs.txt) downloaded from [Space-Track](https://www.space-track.org) on 17:10:37 UTC 14 June 2025.
34
+
35
+
36
+ ## `astrotrack` Installation
37
+
38
+ To install `astrotrack` from source, follow the instructions below:
39
+
40
+ ```bash
41
+ conda env create -f environment.yml
42
+ conda activate astrotrack
43
+ pip install -e .
44
+ ```
45
+
46
+ The package can then be imported using:
47
+
48
+ ```bash
49
+ import astrotrack
50
+ ```
51
+
52
+ `astrotrack` is recommended to be used with the provided Conda [environment](environment.yml).
53
+
54
+
55
+ ## Quick Start
56
+
57
+ The below example demonstrates how to initialise `astrotrack` using a provided TLE catalogue along with user-defined observational constraints, the satellite constellation of interest, and a target date:
58
+
59
+ ```python
60
+ from datetime import datetime
61
+ from astrotrack.preprocess import load_satellite_data
62
+
63
+ data = load_satellite_data(
64
+ tle_file="LEO_TLE_file.txt",
65
+ target_date=datetime(2025, 1, 18, 12, 25, 8),
66
+ obs_len=3600,
67
+ traj_res=60,
68
+ obs_lat=51.5,
69
+ obs_lon=-0.1,
70
+ R=2000,
71
+ horizon_data="Horizon-Profile.csv",
72
+ satcon="STARLINK"
73
+ )
74
+ ```
75
+
76
+ > **Generating Epoch Times with Skyfield**: The following code can be used to initialise a time array for satellite propagation.
77
+ >
78
+ >```python
79
+ >import numpy as np
80
+ >from skyfield.api import load
81
+ >
82
+ ># Create a timescale object:
83
+ >ts = load.timescale()
84
+ >
85
+ ># Define orbit duration:
86
+ >orbit_duration = np.arange(0, 3600, 1) # in seconds
87
+ >
88
+ ># Generate time array:
89
+ >epochs_of_orbit = ts.utc(2025, 1, 1, 10, 15, 0 + orbit_duration)
90
+ >```
91
+ >
92
+
93
+
94
+ ## Example Usage & Workflow
95
+
96
+ `astrotrack` is organised into five modules. A typical workflow begins with initialising and structuring satellite Two-Line Element (TLE) data for analysis, after which the subsequent modules derive orbital properties, Doppler behaviour with respect to a ground-based experiment, animations, and enable spectral associations.
97
+
98
+ <br>
99
+ <div align="center">
100
+ <img src="docs/images/package-modules.png" width="600">
101
+ </div>
102
+ <br>
103
+
104
+ - [`preprocess`](): Loads and filters satellite TLE data provided by the user.
105
+ - [`satcon_properties`](): Filters, analyses, and visualises satellite trajectories as well as their metrics.
106
+ - [`doppler_analysis`](): Evaluates Doppler shifts and detectability relative to a user-defined instrument's specifications.
107
+ - [`satcon_animate`](): Generates 3-D trajectory animations.
108
+ - [`psd_analysis`](): Visualises satellite flyover properties alongside measured PSD data coincidential with satellite flyovers.
109
+
110
+ A detailed overview of all five modules, their key functions, and example usage is provided in a supplementary [document](docs/examples/examples.md).
111
+
112
+
113
+ A [demonstration notebook](notebooks/astrotrack_demo/01_astrotrack_demo.ipynb) is also provided, and includes usage of an example [horizon profile](data/horizon-profiles/REACH-horizon.csv) from the REACH experiment as well as a [TLE catalogue](data/TLE-catalogues/TLEs.txt) compiled from [Space-Track](https://www.space-track.org). A [baseline horizon profile](data/horizon-profiles/baseline-horizon.csv) corresponding to an idealised flat horizon is additionally available to be used directly, or modified by the user to incorporate site-specific observational constraints.
114
+
115
+ ## Testing \& Validation
116
+
117
+ `astrotrack` is validated using unit tests covering the package's functionalities from [TLE preprocessing](tests/preprocess_test.py), deriving [satellite properties](tests/satcon_properties_test.py), performing [Doppler Analysis](tests/doppler_analysis_test.py), and analysis with [PSD observations](tests/psd_analysis_test.py).
118
+
119
+ The entire test suite can be run using:
120
+ ```bash
121
+ pytest
122
+ ```
123
+
124
+ ## License
125
+
126
+ The `astrotrack` Python package source code is released under BSD 3-Clause License, with citation details provided in the [`CITATION.cff`](CITATION.cff) file.
127
+
128
+ ## Bibliography
129
+
130
+ de Lera Acedo, E., de Villiers, D.I.L., Razavi-Ghods, N. et al. *The REACH radiometer for detecting the 21-cm hydrogen signal from redshift z ≈ 7.5–28*. Nat Astron 6, 984–998 (2022). https://doi.org/10.1038/s41550-022-01709-9
@@ -0,0 +1,22 @@
1
+ from .doppler_analysis import ( # noqa: F401
2
+ check_doppler_resolution,
3
+ plot_doppler_shifts,
4
+ )
5
+ from .preprocess import load_satellite_data # noqa: F401
6
+ from .psd_analysis import ( # noqa: F401
7
+ load_hdf5,
8
+ plot_psd_satellite_time_series,
9
+ plot_psd_with_satellite_metric,
10
+ )
11
+ from .satcon_animate import animate_trajectories # noqa: F401
12
+ from .satcon_properties import ( # noqa: F401
13
+ filter_by_norads,
14
+ filter_by_time,
15
+ filter_custom,
16
+ filter_nth,
17
+ get_norads,
18
+ plot_flyover_histogram_by_norad,
19
+ plot_max_elevation_histogram,
20
+ plot_satellite_metric,
21
+ plot_satellite_trajectory,
22
+ )
@@ -0,0 +1,111 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ import pandas as pd
4
+ from tabulate import tabulate
5
+
6
+ default_font = "Times New Roman"
7
+
8
+
9
+ def plot_doppler_shifts(
10
+ all_satellite_data,
11
+ f0,
12
+ font_family=default_font,
13
+ figsize=(8, 5),
14
+ marker_color="deeppink",
15
+ time_window=10,
16
+ ):
17
+ """
18
+ Plot the Doppler shifts for each satellite in separate subplots,
19
+ centered around visibility midpoint.
20
+
21
+ Parameters:
22
+ ----------
23
+ all_satellite_data : list[dict]
24
+ Satellite data dictionaries.
25
+ f0 : float
26
+ Transmission frequency [Hz].
27
+ font_family : str
28
+ Font family for plot text.
29
+ figsize : tuple
30
+ Figure size for each subplot.
31
+ marker_color : str
32
+ Color of scatter plot markers.
33
+ time_window : float
34
+ Half-width of x-axis around visibility [min].
35
+ """
36
+ c = 3.0e5 # speed of light in km/s
37
+ for satellite_data in all_satellite_data:
38
+ plt.rcParams["font.family"] = font_family
39
+ plt.figure(figsize=figsize)
40
+
41
+ epochs = satellite_data["Epochs"]
42
+ velocity_r = np.array(satellite_data["Velocities"]) # km/s
43
+ elevations = satellite_data["Elevations"]
44
+ tle_line_2 = satellite_data["TLE"][1]
45
+ norad_id = tle_line_2.split()[1]
46
+ theta_max = max(elevations)
47
+ epochs_np = np.array([np.datetime64(e) for e in epochs])
48
+ center_time = epochs_np[len(epochs_np) // 2]
49
+ relative_time = (epochs_np - center_time) / np.timedelta64(1, "m") # mins
50
+ doppler_shift = (velocity_r / c) * f0
51
+
52
+ plt.scatter(
53
+ relative_time,
54
+ doppler_shift / 1e3,
55
+ s=3,
56
+ color=marker_color,
57
+ label=rf"$\theta_{{max}} \approx {theta_max:.0f}^\circ$",
58
+ )
59
+
60
+ print_time = (
61
+ center_time.astype("datetime64[s]").tolist().strftime("%Y-%m-%d %H:%M:%S")
62
+ )
63
+ plt.xlabel("Visibility Time (min)")
64
+ plt.ylabel("Doppler Shift (kHz)")
65
+ plt.title(f"NORAD {norad_id} Doppler Shift (Centered at {print_time}):")
66
+ plt.axhline(0, color="black", linestyle="--")
67
+ plt.xlim(-time_window, time_window)
68
+ plt.legend(loc="upper right", fontsize=10)
69
+ plt.grid(True)
70
+ plt.show()
71
+
72
+
73
+ def check_doppler_resolution(
74
+ all_satellite_data, f0_array, resolution=12_000, experiment="REACH", return_df=False
75
+ ):
76
+ """
77
+ Check if Doppler shift can be resolved,
78
+ given experiment's frequency resolution.
79
+
80
+ Parameters:
81
+ ----------
82
+ all_satellite_data : list[dict]
83
+ Satellite data dictionaries.
84
+ f0_array : array
85
+ Frequencies to test [Hz].
86
+ resolution : float
87
+ Frequency resolution of experiment [Hz].
88
+ experiment_name : str
89
+ Name of experiment.
90
+ """
91
+ c = 3.0e5 # speed of light in km/s
92
+ rows = []
93
+
94
+ for satellite_data in all_satellite_data:
95
+ norad_id = satellite_data["TLE"][1].split()[1]
96
+ velocity_r = np.array(satellite_data["Velocities"])
97
+ f_max_needed = (resolution * c) / (np.max(np.abs(velocity_r)) * 1e6)
98
+
99
+ row = {"Satellite NORAD ID": norad_id}
100
+ for f0 in f0_array:
101
+ max_doppler_khz = np.max(np.abs((velocity_r / c) * f0)) / 1e3
102
+ row[f"{f0/1e6:.1f} MHz"] = f"""{max_doppler_khz:.2f} kHz | {
103
+ 'YES' if max_doppler_khz > resolution/1e3 else 'NO'
104
+ }"""
105
+ row[f"Freq. to Resolve ({experiment})"] = f"{f_max_needed:.0f} MHz"
106
+ rows.append(row)
107
+
108
+ df = pd.DataFrame(rows)
109
+ print(tabulate(df, headers="keys", tablefmt="grid", showindex=False))
110
+ if return_df:
111
+ return df