La libreria standard di Python è fornitissima di funzioni pronte all'uso, ma per il nostro modesto lavoro di programmatori di software astrologico è bene che ci dotiamo di strumenti fatti apposta per lo scopo.
Per prima cosa apriremo un file tools.py con un editor a nostra scelta, in cui raccoglieremo tutte le funzioni che andremo via via creando in modo da poterle richiamare facilmente.
Per prime definiremo delle funzioni goniometriche di supporto alle operazioni sulle coordinate.
La libreria standard ha già queste funzioni, pero' si applicano ai gradi misurati in radianti (in cui l'angolo piatto vale 2 pigreco, per intenderci), mentre molte delle formule disponibili usano la misura in gradi.
Per prime le funzioni seno, coseno, tangente e arctangente2 (è la funzione inversa della tangente, ma a differenza della funzione arctangente normale effettua alcuni controlli sul segno degli operandi, risolvendo il dubbio sul corretto posizionamento dell'angolo nei quadranti, come si vede nellla tabella seguente):
Python 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118] on linux2 Type "copyright", "credits" or "license()" for more information. >>> ======== RESTART: /home/ubuntu/Scrivania/proveStroBlog/provaatan2.py ======== arctan(x) for x varying from 0° to 360° step 30° x atan(sin(x)/cos(x)) atan2(sin(x),cos(x)) 30.000 30.000 30.000 60.000 60.000 60.000 90.000 90.000 90.000 120.000 -60.000 120.000 150.000 -30.000 150.000 180.000 -0.000 180.000 210.000 30.000 -150.000 240.000 60.000 -120.000 270.000 90.000 -90.000 300.000 -60.000 -60.000 330.000 -30.000 -30.000 360.000 -0.000 -0.000 >>>
Ecco le prime funzioni goniometriche in gradi e una funzione per riportare un angolo all'angolo giro fondamentale che toglie il segno meno se presente:
import math def sin(x): return math.sin(math.radians(x)) def cos(x): return math.cos(math.radians(x)) def tan(x): return sin(x)/cos(x) def atan(x): return math.degrees(math.atan(x)) def atan2(y , x): return math.degrees(math.atan2(y, x)) def reduce360(x): return x % 360.0
Ora ci servono due funzioni per convertire un angolo dalla notazione sessagesimale alla decimale e viceversa. Decido che il segno che compare davanti alle ore darà il segno a tutta la variable decimale, mentre, al contrario, nella conversione da decimale a sessagesimale solo le ore riceveranno un eventuale segno negativo. La funzione, oltre che alle ore, puo' applicarsi immodificata anche agli angoli, sempre in notazione sessagesimale.
def dms2ddd(hour, minute, second): """ from sexagesimal to decimal the sign of hour variable is automatically applied to minutes and seconds """ if hour < 0: sign = -1 hour *= sign else: sign = 1 return (hour+minute/60.0+second/3600.0)*sign def ddd2dms(dec_hour): """ from decimal to sexagesimal representation of hours and angles. the sign of dec_hour variable is applied only to hours variable see the dms2ddd function for comparison """ if dec_hour < 0: sign = -1 dec_hour *= sign else: sign = 1 total_seconds = int(dec_hour * 3600.0+.5) seconds = total_seconds % 60 total_minutes = int((total_seconds - seconds)/60.0) minutes = total_minutes % 60 hours = int((total_minutes - minutes)/60.0) return (hours * sign, minutes, seconds)
Ci serve inoltre una funzione che converta una data dal formato giorno, mese, anno, ora minuto e secondo, scomodissimo per il calcolo, in quella comoda notazione che corrisponde alla data juliana.
def cal2jul(year, month, day, hour=0, minute=0, second=0): """ converts calendar date to julian date this routine and the following are built following Duffet Smith /Zwart instructions as given in Peter Duffett-Smith-Zwart Practical Astronomy with your Calculator or Spreadsheet Fourth Edition, Cambridge University Press, Fourth Ed. 2011 For an easier use of the function, hours minutes and seconds are defaulted to 0, so it's not necessary to give them as parameters when the hour is 00:00:00 """ month2 = month year2 = year if month2 <= 2: year2 -= 1 month2 += 12 else: pass if (year*10000 + month*100 + day) >= 15821015: a = math.trunc(year2/100.0) b = 2 - a + math.trunc(a/4.0) else: a = 0 b = 0 if year < 0: c = math.trunc((365.25 * year2)-0.75) else: c = math.trunc(365.25 * year2) d = math.trunc(30.6001 *(month2 + 1)) return b + c + d + day + hour / 24.0 + minute / 1440.0 + second / 86400.0 + 1720994.5
Infine ecco due funzioni che servono per il calcolo del tempo siderale di Greenwich e del tempo siderale locale, necessari ad allineare il tempo locale con un riferimento alle cosiddette "stelle fisse" (che tanto fisse non sono, ma per noi astrologi il riferimento statico è l'eclittica e la sua divisione in segni zodiacali, che, per inciso, non c'entrano niente con le costellazioni).
def ut2gst(year, month, day, hour, minute, second): """ Sidereal time is a time-keeping system astronomers use to keep track of the direction to point their telescopes to view a given star in the night sky. Briefly, sidereal time is a "time scale that is based on the Earth's rate of rotation measured relative to the fixed stars." (source Wikipedia) This routine converts Universal Time to Sidereal Time for Greenwich (Greenwich Sidereal Time) """ jd = cal2jul(year, month, day) S = jd - 2451545.0 T = S/36525.0 T0 = (6.697374558 + 2400.051336 * T+ 0.000025862 *T*T) % 24 UT = dms2ddd(hour, minute, second)*1.002737909 GST = (UT + T0) % 24 return GST
e
def gst2lst( gst, long_degree, long_minute, long_second=0): """ Corrects GST for a different location on the Earth """ lg = dms2ddd(long_degree, long_minute, long_second)/15. lst = (gst + lg) % 24. return lst
Nel prossimo post vedremo qual è il significato di queste due ultime funzioni.