Эффективный способ распространения спутникового каталога во времени

Постановка задачи

Мне нужно распространить весь каталог недавних TLE (для просмотра нужна бесплатная учетная запись) с сайта space-track.org с использованием skyfield или аналогичного. Обычно в списке есть 15-16 тыс. TLE. У меня он работает, но очень медленно. Порядка часов с использованием 46 ядер на сервере.

Не замужем за skyfield. Если astropy или pyephem или что-то еще быстрее, я бы с радостью принял ответ, который показывает, что я пытаюсь сделать, используя это.

Минимальный пример

Для моего приложения я загружаю 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

2,1 с ± 20 мс на цикл (среднее значение ± стандартное отклонение для 7 запусков, по 1 циклу в каждом)

Создайте массив объектов даты и времени с учетом часового пояса, по которым будут распространяться все спутники. Здесь я выбрал каждые 10 минут с 4 часов до полуночи в тот день, когда я пишу это, до 4 часов после.

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)

189 мс ± 36,9 мс на цикл (среднее значение ± стандартное отклонение для 7 запусков, по 10 циклов в каждом)

Наконец, рассчитайте астрометрические позиции для каждого временного шага для каждого спутника. Это то, что занимает вечность. Слишком долго для меня, чтобы запустить снова, просто чтобы получить время, но это порядка нескольких часов с использованием 46 ядер на сервере.

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

Дополнительные детали

Я нашел это обсуждение массивов дат в документации, в котором предлагается передать весь массив сразу: x.at(ts.utc(times)). Пока что это требует меньше ядер и работает немного быстрее, но все равно занимает непомерно много времени.

Я немного преодолел это замедление, создав генераторы для астрометрии (первоначально поэтому я отказался от передачи всего массива times сразу), но в конечном итоге мне действительно нужно оценивать вещи, поэтому я не могу вечно избегать тяжелой работы.

В случае, если окончательный вариант использования поддается некоторому конкретному ускорению, мне в конечном итоге нужно получить углы наблюдения с места за этими объектами, так что [x.altaz() for x in row.astrometrics] тип вещей.

Мысли о решении

Сейчас я думаю, что рассчитываю положение места наблюдения на каждом временном шаге в течение ночи для каждого спутника в каталоге. Я могу ошибаться, но если я прав, то я думаю, что увижу довольно приличное ускорение (может быть, недостаточное), вычислив это один раз, а затем просматривая его для каждого нового спутника. Кто-нибудь знает, как это сделать?

Кроме того, если есть более быстрая реализация пропагатора орбиты или способ ускорить реализацию небесного поля, я бы с радостью принял ответ, который показывает, как делать то, что я пытаюсь сделать, используя это (таким образом, включая теги astropy и pyephem ).

Спасибо.


person Engineero    schedule 04.04.2018    source источник
comment
Это старый вопрос, и я давно не смотрел на внутренности Skyfield, но это обсуждение может быть полезным для вас: github.com/skyfielders/python-skyfield/issues/188   -  person dsholes    schedule 14.03.2019
comment
@dsholes, спасибо! Это действительно полезно. Мне не нужно было возвращаться к этому в последнее время, но если я это сделаю, я реализую некоторые из этих ускорений в своем коде.   -  person Engineero    schedule 14.03.2019


Ответы (1)


Мой лучший совет — использовать Инструментарий NASA SPICE Toolkit для такого типа работы. Это позволяет вам загружать двухстрочные элементы, а затем использовать ядра NASA NAIF/SPICE для выполнения остальной работы (вы также можете найти некоторые спутники в других форматах, но TLE подойдет).

Если бы вы работали на C, вы бы использовали getelm_c. для их чтения и spkpos_c чтобы получить позицию. К счастью, существует оболочка для Python, которая называется spiceypy!

Метод getelm_c заключен в spiceypy.spiceypy.getelm(frstyr, lineln, lines) для load в вашем TLE. Вы хотите, чтобы они использовали spiceypy.spiceypy.spkpos(targ, et, ref, abcorr, obs), чтобы получить ваш позиция относительно тела ссылки.

Я предлагаю использовать документы из spiceypy, в частности, позицию примера Cassini, чтобы убедиться, что у вас есть все правильные файлы, если вы решите использовать ядра SPICE от NASA: https://spiceypy.readthedocs.io/en/master/exampleone.html

person Community    schedule 03.08.2019