随时间传播卫星目录的有效方法

Eng*_*ero 5 python pyephem astropy skyfield sgp4

问题陈述

我需要使用或类似方法从 space-track.org传播最近的 TLE整个目录(需要一个免费帐户才能查看)skyfield。列表中通常有 15k-16k TLE。我有它的工作,但它慢。在服务器上使用 46 个核心数小时。

没有结婚skyfield。如果astropypyephem或其他东西更快,我很乐意接受一个答案,该答案表明我正在尝试使用它来做什么。

最小的例子

对于我的应用程序,我将 TLE 加载到 Pandas 数据框中并在那里进行分析,因此我将在 Pandas 世界中保留我的示例。最小的例子如下。

假设卫星目录保存为catalog.txt,设置环境,然后读取 TLE,生成sf.sgp4lib.EarthSatellite对象,并将所有内容加载到 Pandas 数据帧中。我们还将位置偏移到了一些观察点。我将选择一个观察点留给读者(0, 0, 0 就可以了):

import skyfield as sf
import pandas as pd
from skyfield.api import load, Topos
from datetime import datetime, timezone, timedelta

with open('catalog.txt', 'r') as f:
    tle_list = [line.strip() for line in f.read().split('\n')
                if line is not '']
data = []
for i in range(0, len(tle), 2):  # every two lines
    temp = {}
    temp['tle1'] = tle_list[i]
    temp['tle2'] = tle_list[i+1]
    temp['earthsat'] = sf.sgp4lib.EarthSatellite(tle_list[i],
                                                 tle_list[i+1])
    data.append(temp)
df = pd.DataFrame(data=data)
site = Topos(latitude_degrees=site_lat,
             longitude_degrees=site_lon,
             elevation_m=site_alt)
df['earthsat'] = df.earthsat - site  # offset to site location
Run Code Online (Sandbox Code Playgroud)

每个循环 2.1 s ± 20 ms(7 次运行的平均值 ± 标准偏差,每次 1 次循环)

创建一个时区感知日期时间对象数组,在这些对象上传播所有卫星。在这里,我从我写这篇文章的那天午夜前 4 小时到 4 小时后每 10 分钟选择一次。

ts = load.timescale()
tz = timezone(timedelta(hours=-4))  # Eastern or whatever timezone
midnight = datetime(2018, 4, 4, 0, 0, 0, tzinfo=tz)  # midnight today
start = midnight - timedelta(hours=4)
end = midnight + timedelta(hours=4)
delta_time = timedelta(minutes=10)
# This is ugly, but I had issues using linspace or arange...
times = [start]
now = start
while now <= end:
    now += delta_time
    times.append(now)
Run Code Online (Sandbox Code Playgroud)

每个循环 189 ms ± 36.9 ms(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

最后,计算每颗卫星每个时间步长的天体测量位置。这是永远需要的。时间太长了,我无法再次运行以获取计时,但在服务器上使用 46 个内核大约需要几个小时。

df['astrometric'] = df.earthsat.apply(lambda x: [x.at(ts.utc(time)) for time in times])
Run Code Online (Sandbox Code Playgroud)

额外细节

我发现在日期排列讨论的文件中说,建议传递整个数组中的一次:x.at(ts.utc(times))。到目前为止,这需要更少的内核并且运行速度更快,但仍然需要非常长的时间。

我通过为天体测量创建生成器来暂时解决这个问题(最初是为什么我不立即传递整个times数组),但最终我实际上需要评估事物,所以我无法永远避免繁重的工作。

如果最终用例有助于某些特定的加速,我最终需要从这些对象中获取站点的观察角度,所以[x.altaz() for x in row.astrometrics]类型的事情。

关于解决方案的想法

我现在的想法是,我正在目录中的每颗卫星计算整个夜间每个时间步长的观测站点位置。我可能是错的,但如果我是对的,那么我想我会看到一个相当不错的加速(可能还不够),通过计算一次然后为每个新卫星查找它。有人知道怎么做这个吗?

此外,如果有更快的轨道传播器实现,或者有一种方法可以加快 Skyfield 的实现,我很乐意接受一个答案,该答案显示如何使用它(因此包括astropypyephem标签)来做我想做的事情。

谢谢你。

小智 1

我最好的建议是使用NASA SPICE 工具包来完成此类工作。这样您就可以加载两行元素,然后使用 NASA 的 NAIF/SPICE 内核来完成其余的工作(您可能还会发现一些其他格式的卫星,但 TLE 没问题)。

如果您使用 C 语言工作,您将使用getelm_c方法来读取它们,并使用spkpos_c来获取位置。幸运的是,有一个名为Spiceypy的Python 包装器!

getelm_c方法被包装spiceypy.spiceypy.getelm(frstyr, lineln, lines)您的 TLE 中加载。你想让他们用来获取你相对于参考体的位置。spiceypy.spiceypy.spkpos(targ, et, ref, abcorr, obs)

我建议使用 SPICEYPY 的文档,特别是卡西尼号示例的位置,以确保如果您决定使用 NASA 的 SPICE 内核,您拥有所有正确的文件: https://spiceypy.readthedocs.io/en/master/ exampleone.html