The first problem that emerges in the design of the mount is the conversion between the equatorial coordinate system (Right Ascension – declination system) and the horizontal coordinate system (altitude – azimuth).

The reason why this is important is essentially the following:

The circular path of stars is a result of the rotation of the earth. But due to the inclination angle of the rotational axis of the earth, there is a small angle between the earth’s north pole and the celestial sphere’s north pole. In the equatorial coordinate system (same as the horizontal coordinate system, but for the celestial sphere instead of the earth), keeping track of the stars would be easy: we only need to rotate one axis (the Right Ascension), because the positions of the stars on the celestial sphere is fixed, and we only need to rotate around the axis of the celestial sphere at the same speed (namely 24 hour/rotation, the rate of the earth’s rotation) to catch up with the celestial sphere and hence the stars on it.

This is how most traditional equatorial mounts work — to have the two axels inclined such that one of them is aligned with the celestial polar axis. This is also why in the previous design I had, I tilted the frame on which the telescope was set up.

However, in this design, I would like to simplify the mount structurally as much as possible. Plus I am going to motorize both axels anyways, it’s possible to calculate the equivalent motions in altitude and azimuth in the horizontal coordinate system, and keep track of the stars this way. To do this, we first need to be able to convert between the two systems (maybe only in one way: from equatorial to horizontal, but just in case).

There are two major methods to do this. The first one is to do some trigonometrical operations on what is called the Astronomical Triangle (the indices of which being the zenith, the celestial north pole, and the star being observed) (see here for more details), and the second one is to perform some transformations using matrices (see here for more details). After reading both articles, I decided to use the first one. The specific algorithm is pretty clearly explained in that article so… Here goes the code (If you don’t see the code below, click here):

# Created July 4, 2016 | |

# Last Major Modification July 15, 2016 | |

# Author Sibo W | |

import datetime | |

import pytz | |

import math | |

def get_lst(long, time): | |

'''Takes in: long observer's longitude in degrees, east as positive | |

time the time to be calculated in datetime type | |

use 'NOW' if current time is wanted | |

Returns Local (Mean) Sidereal Time. | |

The observer's east longitude has been neglected.''' | |

# Define subclsss UTC of tzinfo | |

UTC = pytz.timezone('UTC') | |

# Initialize current time if necessary | |

if time == 'NOW': | |

time = datetime.datetime.utcnow().replace(tzinfo = UTC) | |

# Calculate number of days since J2000 | |

J2000 = datetime.datetime(2000, 1, 1, 11, 58, 55, 816000, UTC) | |

# Note that J2000.0 = January 1, 2000, 12:00:00.000 Terrestrial Time | |

# = January 1, 2000, 11:58:55.816 UTC | |

days = (time – J2000).total_seconds() / 86400 | |

gst = days * 360.98562628 + 280.46061837 | |

# Note that the earth rotates 366.25 * 360 / 365.25 = 360.98562628 | |

# degrees each solar day | |

# Add the sidereal angle at J2000.0 at Prime Meridian 280.46061837 | |

lst = (gst + long) % 360 | |

return lst | |

def equatorial2horizontal(ra, dec, lst, lat): | |

'''Given Right Ascension ra in degrees | |

Declinition dec in degrees | |

Local Sidereal Time lst in degrees | |

Observer's latitude lat0 in degrees | |

Returns tuple (altitude, azimuth), both in degrees | |

''' | |

ra = math.radians(ra) | |

dec = math.radians(dec) | |

lst = math.radians(lst) | |

lat = math.radians(lat) | |

hour_angle = (lst – ra) | |

# calculates hour angle (lst – ra) | |

temp = math.sin(dec) * math.sin(lat) + \ | |

math.cos(dec) * math.cos(lat) * math.cos(hour_angle) | |

# where temp = sin(altitude) | |

altitude = math.asin(temp) | |

# gets altitude and converts it into degrees | |

temp = –math.sin(hour_angle) * math.cos(dec) / math.cos(altitude) | |

# where temp = sin(azimuth) | |

altitude = math.degrees(altitude) | |

azimuth = math.degrees(math.asin(temp)) | |

# gets altitude and converts it into degrees | |

azimuth %= 360 | |

return altitude, azimuth | |

def horizontal2equatorial(alt, azi, lst, lat): | |

'''Given Azimuth azi in degrees | |

Altitude alt in degrees | |

Local Sidereal Time lst in hours | |

Observer's latitude lat0 in degrees | |

Returns tuple (Right Ascension, declination), both in degrees | |

''' | |

azi = math.radians(azi) | |

alt = math.radians(alt) | |

lst = math.radians(lst) | |

lat = math.radians(lat) | |

temp = math.sin(alt) * math.sin(lat) + \ | |

math.cos(alt) * math.cos(lat) * math.cos(azi) | |

# where temp = sin(declination) | |

declination = math.asin(temp) | |

# gets declination and converts it into degrees | |

temp = –math.sin(azi) * math.cos(alt) / math.cos(declination) | |

# where temp = sin(hour angle) | |

declination = math.degrees(declination) | |

hour_angle = math.degrees(math.asin(temp)) | |

# gets hour angle and converts it into degrees | |

ra = math.degrees(lst) – hour_angle | |

# gets Right Ascension from hour angle and lst | |

return (ra, declination) | |

# TEST CASES | |

# UTC = pytz.timezone('UTC') | |

# test = datetime.datetime(2016, 7, 15, 7, 0, 0, 0, UTC) | |

# lst = get_lst(172, test) | |

# print(lst) | |

# | |

# print(equatorial2horizontal(120, 20, lst, 33)) | |

# | |

# print(horizontal2equatorial(10.17, 287.33, lst, 33)) |