Apuntamos y nos comunicamos con satélites: primera parte: apuntar programáticamente



Descargo de responsabilidad : prácticamente no estoy familiarizado con la astronomía, solo entré en órbita en Kerbal y de alguna manera logré hacer un par de maniobras orbitales. Pero el tema es interesante, de modo que incluso si no me expreso correctamente en alguna parte, estoy sucio.



Todos los enlaces están al final del artículo.



Para estar seguro, la visibilidad no se trata solo de ver con los ojos.



, , . , . . — , .





.





. , - . , . , . LEMUR-2 JOEL, 640 --, .

O3B FM8 8,000, Tierra del Fuego. . ( ) , ( , ).





?





( , )



. 3- (LEO), (MEO), (GSO).



, ( 2,000), ( Kerbal, , , - ), . . 20-30 . . 90 .



, Medium Earth Orbit — , (GSO) (LEO). 10,000 30,000. 2000 8000 - Van Allen Belt ( ).

GPS . , ( ). 12 .





1 . 36,000. , . . . .



?





FPV , - . , , , .





, " ".



:





( , )



, :





— "" "feed antenna". -. .



:





( ), . , , . .





, Skyfield . , . , .



, , . 90 , . 8 . — 10 — 2- , - . , , .



, (altitude) elevation.

.





, , 45 . — . , . 0 , 180 .



Skyfield Python, Python (3). , , .



:



pip3 install skyfield


:



index.py



import datetime
import time
from skyfield.api import load, Topos, EarthSatellite


:



TLE_FILE = "https://celestrak.com/NORAD/elements/active.txt" # DB file to download
ISS_NAME = "ISS (ZARYA)"

# Coordinats
# 57°00'13.7"N 37°02'53.7"E
# Kimrsky District, Tver Oblast, Russia
LONGITUDE = 57.003810
LATITUDE = 37.048262


:



class SatelliteObserver:

    def __init__(self, where: Topos, what: EarthSatellite):
        self.where = where
        self.sat = what
        self.sat_name = what.name
        self.ts = load.timescale(builtin=True)
# ...


"" , (, ), EarthSatellite .





# ...
@classmethod
    def from_strings(cls, longitude: str or float, latitude: str or float, sat_name: str, tle_file: str) -> 'SatelliteObserver':
        place = Topos(latitude, longitude)
        satellites = load.tle(tle_file)
        print("loaded {} sats from {}".format(len(satellites), tle_file))
        _sats_by_name = {sat.name: sat for sat in satellites.values()}
        satellite = _sats_by_name[sat_name]
        return cls(place, satellite)
# ...


Topos ( ).



, _sats_by_name[sat_name].



def altAzDist_at(self, at: float) -> (float, float, float):
        """
        :param at: Unix time GMT (timestamp)
        :return: (altitude, azimuth, distance)
        """
        current_gmt = datetime.datetime.utcfromtimestamp(at)
        current_ts = self.ts.utc(current_gmt.year, current_gmt.month, current_gmt.day, current_gmt.hour,
                            current_gmt.minute, current_gmt.second + current_gmt.microsecond / 1000000.0)
        difference = self.sat - self.where
        observer_to_sat = difference.at(current_ts)
        altitude, azimuth, distance = observer_to_sat.altaz()
        return (altitude.degrees, azimuth.degrees, distance.km)


, at .



    def current_altAzDist(self) -> (float, float, float):
        return self.altAzDist_at(time.mktime(time.gmtime()))

    def above_horizon(self, at: float) -> bool:
        """
        :param at: Unix time GMT
        :return:
        """
        (alt, az, dist) = self.altAzDist_at(at)
        return alt > 0


current_altAzDist(self) — , .



main :



def main():
    iss = SatelliteObserver.from_strings(LONGITUDE, LATITUDE, ISS_NAME, TLE_FILE)
    elevation, azimuth, distance = iss.current_altAzDist()
    visible = "visible!" if elevation > 0 else "not visible =/"
    print("ISS from latitude {}, longitude {}: azimuth {}, elevation {} ({})".format(LATITUDE, LONGITUDE, azimuth, elevation, visible))

if __name__ == "__main__":
    main()


import datetime
import time
from skyfield.api import load, Topos, EarthSatellite

TLE_FILE = "https://celestrak.com/NORAD/elements/active.txt" # DB file to download
ISS_NAME = "ISS (ZARYA)"

# Coordinats
# 57°00'13.7"N 37°02'53.7"E
# Kimrsky District, Tver Oblast, Russia
LONGITUDE = 57.003810
LATITUDE = 37.048262

class SatelliteObserver:

    def __init__(self, where: Topos, what: EarthSatellite):
        self.where = where
        self.sat = what
        self.sat_name = what.name
        self.ts = load.timescale(builtin=True)

    @classmethod
    def from_strings(cls, longitude: str or float, latitude: str or float, sat_name: str, tle_file: str) -> 'SatelliteObserver':
        place = Topos(latitude, longitude)
        satellites = load.tle(tle_file)
        print("loaded {} sats from {}".format(len(satellites), tle_file))
        _sats_by_name = {sat.name: sat for sat in satellites.values()}
        satellite = _sats_by_name[sat_name]
        return cls(place, satellite)

    def altAzDist_at(self, at: float) -> (float, float, float):
        """
        :param at: Unix time GMT (timestamp)
        :return: (altitude, azimuth, distance)
        """
        current_gmt = datetime.datetime.utcfromtimestamp(at)
        current_ts = self.ts.utc(current_gmt.year, current_gmt.month, current_gmt.day, current_gmt.hour,
                            current_gmt.minute, current_gmt.second + current_gmt.microsecond / 1000000.0)
        difference = self.sat - self.where
        observer_to_sat = difference.at(current_ts)
        altitude, azimuth, distance = observer_to_sat.altaz()
        return (altitude.degrees, azimuth.degrees, distance.km)

    def current_altAzDist(self) -> (float, float, float):
        return self.altAzDist_at(time.mktime(time.gmtime()))

    def above_horizon(self, at: float) -> bool:
        """
        :param at: Unix time GMT
        :return:
        """
        (alt, az, dist) = self.altAzDist_at(at)
        return alt > 0

def main():
    iss = SatelliteObserver.from_strings(LONGITUDE, LATITUDE, ISS_NAME, TLE_FILE)
    elevation, azimuth, distance = iss.current_altAzDist()
    visible = "visible!" if elevation > 0 else "not visible =/"
    print("ISS from latitude {}, longitude {}: azimuth {}, elevation {} ({})".format(LATITUDE, LONGITUDE, azimuth, elevation, visible))

if __name__ == "__main__":
    main()


python3:



python3 index.py




[#################################] 100% active.txt
loaded 6351 sats from https://celestrak.com/NORAD/elements/active.txt
ISS from latitude 37.048262, longitude 57.00381: azimuth 55.695482310974974, elevation 6.232187065056109 (visible!)


( ) (elevation), .



(visible!) — !.. 6 . , 45.



. .



(https://celestrak.com/NORAD/elements/active.txt) , , .



.



UPD

, :



import datetime
import time
from skyfield.api import load, Topos, EarthSatellite

#     
TLE_FILE = "https://celestrak.com/NORAD/elements/active.txt" # DB file to download

SAT_NAME = "ISS (ZARYA)"

#  
satellites = load.tle(TLE_FILE)

#       
print("loaded {} sats from {}".format(len(satellites), TLE_FILE))
_sats_by_name = {sat.name: sat for sat in satellites.values()}
satellite = _sats_by_name[SAT_NAME]

ts = load.timescale()
t = ts.now()

#     
location = Topos('52.173141 N', '44.108612 E')

#      
difference = satellite - location
topocentric = difference.at(t)

alt, az, distance = topocentric.altaz()

if alt.degrees > 0:
    print('The ISS is above the horizon')

print(alt)
print(az)
print(int(distance.km), 'km')


.



:



import datetime
import time
from skyfield.api import load, Topos, EarthSatellite

TLE_FILE = "https://celestrak.com/NORAD/elements/active.txt" # DB file to download

MIN_DEGREE = 45
MIN_AZ = 50
MAX_AZ = 140

satellites = load.tle(TLE_FILE)
ts = load.timescale()
t = ts.now()

location = Topos('52.173141 N', '44.108612 E')

for sat in satellites.values():
    difference = sat - location
    topocentric = difference.at(t)

    alt, az, distance = topocentric.altaz()

    azValue = int(str(az).replace('deg', '').split(" ")[0])

    if alt.degrees >= MIN_DEGREE and azValue >= MIN_AZ and azValue <= MAX_AZ:
        print(sat.name, alt, az)


upd: tvr

upd: Fenja

upd: sandroDan

upd: dpytaylo

upd: extempl





https://nyan-sat.com/chapter0.html








All Articles