We aim and communicate with satellites: Part one - aiming programmatically



Disclaimer - I'm practically not familiar with astronomy, only I went into orbit in Kerbal and somehow I managed to make a couple of orbital maneuvers. But the topic is interesting, so that even if I do not express myself correctly somewhere, Iā€™m dirty.



All links are at the end of the article.



To be on the safe side, visibility is not just about seeing with the eye.



, , . , . . ā€” , .





.





. , - . , . , . 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