Dans l'attente de l'arrivée de mes pièces mécaniques pour terminer les horloges, j'ai repris le code d'origine en PB à la lumière de l'expérience accumulée et des résultats de contrôle avec Stellarium (V 25.4) et PB qui est passé en 6.30.
Des redondances de calculs ont été optimisées et le calcul de l'élongation vient affiner la détermination de la phase lunaire en cours. Je vous livre tout cela ici :
Code : Tout sélectionner
; ----------- Calcul des phases lunaires pour la date du jour (Version Double Précision) -------
; Programme de contrôle : Stellarium (v25.4)
; Version finale PhM - février 2026 - PB 6.30 (x64)
; -----------------------------------------------------------------------------------------------
EnableExplicit
; ------------------ Constantes
#DegToRad = #PI / 180
#RadToDeg = 180 / #PI
Global Lunaison.d = 29.530588853 ; Longueur moyenne du mois synodique
; ------------------ Structures des données (Passage en Double)
Structure CompleteLunarData
lambdaS.d ; Longitude du Soleil
lambdaL.d ; Longitude de la Lune
M.d ; Anomalie moyenne du Soleil
Mp.d ; Anomalie moyenne de la Lune
L.d ; Longitude moyenne de la Lune
D.d ; Élongation
beta.d ; Latitude lunaire
distance.d ; Distance Terre-Lune
anomaly.d ; Anomalie vraie de la Lune
age.d ; Âge lunaire
elongation.d ; Élongation
illumination.d ; Illumination (%)
EndStructure
; ------------------ Déclaration des procédures
Declare.d JourJulien(annee, mois, jour, heure, minute, seconde)
Declare.s PhaseLune(age.d, illumination.d, elongation.d)
Declare.d CalculUTCOffset(annee, mois, jour)
Declare.s SaisonHoraire(offset.d)
Declare.d PositifMod360(f.d)
Declare CalculateCompleteLunarData(JD.d, *data.CompleteLunarData, annee, mois, jour)
Declare CalculateSolarLunar(JD.d, *lambdaS.Double, *lambdaL.Double, *M.Double, *Mp.Double, *L.Double, *D.Double)
; ------------------ Date et heure locale
Global an = Year(Date())
Global mo = Month(Date())
Global jo = Day(Date())
;Global an = 2028
;Global mo = 2
;Global jo = 5
Global UTCOffset.d = CalculUTCOffset(an, mo, jo)
Global heure = Hour(Date()) - UTCOffset
Global minute = Minute(Date())
Global seconde = Second(Date())
;Global heure = 7 - UTCOffset
;Global minute = 0
;Global seconde = 0
; ------------------ Boucle principale
Define JD.d = JourJulien(an, mo, jo, heure, minute, seconde)
Define Lunar.CompleteLunarData
; 1. Calculer les données (Lunar\elongation contient maintenant la valeur brute 0-360°)
CalculateCompleteLunarData(JD, @Lunar, an, mo, jo)
; 2. Déterminer la phase AVANT de modifier l'élongation pour l'affichage
Define phase$ = PhaseLune(Lunar\age, Lunar\illumination, Lunar\elongation)
; 3. Préparer l'élongation pour l'affichage (Stellarium style : 0 à 180°)
Define elongAffiche.d = Lunar\elongation
If elongAffiche > 180 : elongAffiche = 360 - elongAffiche : EndIf
; ------------------ Affichage des résultats
MessageRequester("Observation lunaire du " + Str(jo) + "/" + Str(mo) + "/" + Str(an) + " (" + SaisonHoraire(UTCOffset) + ")",
"Heure locale : " + Str(heure + UTCOffset) + "h" + Str(minute) + "mn" + #LF$ +
"Âge lunaire : " + StrD(Lunar\age, 2) + " jours" + #LF$ +
"Élongation : " + StrD(elongAffiche, 4) + " °" + #LF$ + ;<-- On affiche la valeur "pliée"
"Illumination : " + StrD(Lunar\illumination, 2) + " %" + #LF$ +
"Phase : " + phase$)
End
; ------------------ Procédures de calculs ------------------
Procedure.d PositifMod360(f.d)
While f < 0 : f + 360 : Wend
While f >= 360 : f - 360 : Wend
ProcedureReturn f
EndProcedure
Procedure.d JourJulien(annee, mois, jour, heure, minute, seconde)
Protected a, b, y, m
y = annee
m = mois
If m <= 2
y = annee - 1
m = mois + 12
EndIf
a = y / 100
b = 2 - a + a / 4
Protected JD.d = Int(365.25 * (y + 4716)) + Int(30.6001 * (m + 1)) + jour + b - 1524.5
JD = JD + (heure + minute / 60.0 + seconde / 3600.0) / 24.0
ProcedureReturn JD
EndProcedure
Procedure CalculateSolarLunar(JD.d, *lambdaS.Double, *lambdaL.Double, *M.Double, *Mp.Double, *L.Double, *D.Double)
Protected T.d = (JD - 2451545.0) / 36525.0
; --- Soleil ---
Protected M_val.d = 357.5291092 + 35999.0502909 * T - 0.0001536 * T * T
M_val = PositifMod360(M_val)
*M\d = M_val
Protected Ls.d = 280.46646 + 36000.76983 * T + 0.0003032 * T * T
Ls = PositifMod360(Ls)
*lambdaS\d = Ls + 1.914602 * Sin(M_val * #DegToRad) - 0.004817 * Sin(2 * M_val * #DegToRad)
*lambdaS\d = PositifMod360(*lambdaS\d)
; --- Lune : éléments moyens ---
Protected L_val.d = 218.3164591 + 481267.88134236 * T - 0.0013268 * T * T
L_val = PositifMod360(L_val)
*L\d = L_val
Protected Mp_val.d = 134.9633964 + 477198.8675055 * T + 0.0087414 * T * T
Mp_val = PositifMod360(Mp_val)
*Mp\d = Mp_val
Protected D_val.d = 297.8501921 + 445267.1114034 * T - 0.0018819 * T * T
D_val = PositifMod360(D_val)
*D\d = D_val
Protected F_val.d = 93.2720950 + 483202.0175233 * T - 0.0036539 * T * T
F_val = PositifMod360(F_val)
; --- Série périodique de Meeus complète (Longitude Lunaire) ---
Protected Dg.d = D_val * #DegToRad
Protected Mg.d = M_val * #DegToRad
Protected Mpg.d = Mp_val * #DegToRad
Protected Fg.d = F_val * #DegToRad
Protected dL.d = 0.0
dL + 6.288774 * Sin(Mpg)
dL + 1.274027 * Sin(2*Dg - Mpg)
dL + 0.658309 * Sin(2*Dg)
dL + 0.213618 * Sin(2*Mpg)
dL - 0.185116 * Sin(Mg)
dL - 0.114332 * Sin(2*Fg)
dL + 0.058793 * Sin(2*Dg + Mpg)
dL + 0.057066 * Sin(2*Dg - Mg - Mpg)
dL + 0.053322 * Sin(2*Dg + 2*Mpg)
dL + 0.045758 * Sin(2*Dg - Mg)
dL - 0.040923 * Sin(Mg - Mpg)
dL - 0.034720 * Sin(Dg)
dL - 0.030461 * Sin(Mg + Mpg)
dL + 0.02131 * Sin(2*Dg - 2*Mpg)
*lambdaL\d = PositifMod360(L_val + dL)
EndProcedure
Procedure CalculateCompleteLunarData(JD.d, *data.CompleteLunarData, annee, mois, jour)
; 1. Positions de base (Calcul des longitudes Soleil/Lune)
CalculateSolarLunar(JD, @*data\lambdaS, @*data\lambdaL, @*data\M, @*data\Mp, @*data\L, @*data\D)
Protected T.d = (JD - 2451545.0) / 36525.0
; 2. Latitude lunaire (pour la précision de la position)
Protected F.d = 93.2720950 + 483202.0175233 * T - 0.0036539 * T * T
F = PositifMod360(F)
*data\beta = 5.128 * Sin(F * #DegToRad)
; 3. Distance Terre-Lune (en km)
Protected ecc.d = 0.0549006
*data\distance = 385001.0 / (1.0 + ecc * Cos(*data\Mp * #DegToRad))
; 4. Élongation brute (différence de longitude vraie sur 360°)
; C'est CETTE valeur qui est cruciale pour déterminer la phase exacte
Protected diff.d = *data\lambdaL - *data\lambdaS
If diff < 0 : diff + 360 : EndIf
*data\elongation = diff ; On stocke la valeur brute (0.0 à 359.99...)
; 5. Âge lunaire (en jours)
*data\age = (diff / 360.0) * Lunaison
; 6. Illumination (en %)
; Formule de la fraction éclairée : (1 - cos(D)) / 2
*data\illumination = (1 - Cos(diff * #DegToRad)) / 2 * 100
; Sécurité pour l'illumination
If *data\illumination < 0 : *data\illumination = 0 : EndIf
If *data\illumination > 100 : *data\illumination = 100 : EndIf
EndProcedure
Procedure.s PhaseLune(age.d, illumination.d, elongation.d)
; On garde 8.0 pour la Pleine Lune (confort visuel)
; On réduit à 5.0 pour la Nouvelle Lune (plus réaliste visuellement)
; On réduit à 6.0 pour les quartiers (plus précis)
; 1. NOUVELLE LUNE (étroite car la lune noire est brève)
If elongation < 5.0 Or elongation > 355.0
ProcedureReturn "Nouvelle lune"
EndIf
; 2. PLEINE LUNE (large pour absorber la parallaxe)
If Abs(elongation - 180.0) < 8.0
ProcedureReturn "Pleine lune"
EndIf
; 3. QUARTIERS (Resserrés pour coller à Stellarium)
If Abs(elongation - 90.0) < 2.0
ProcedureReturn "Premier quartier"
EndIf
If Abs(elongation - 270.0) < 2.0
ProcedureReturn "Dernier quartier"
EndIf
; 4. LES DURÉES (le reste du temps)
If elongation < 90.0
ProcedureReturn "Premier croissant"
ElseIf elongation < 180.0
ProcedureReturn "Gibbeuse croissante"
ElseIf elongation < 270.0
ProcedureReturn "Gibbeuse décroissante"
Else
ProcedureReturn "Dernier croissant"
EndIf
EndProcedure
Procedure.d CalculUTCOffset(annee, mois, jour)
Protected dimancheMars, dimancheOctobre, i
For i = 31 To 25 Step -1
If DayOfWeek(Date(annee, 3, i, 0, 0, 0)) = 0 : dimancheMars = i : Break : EndIf
Next
For i = 31 To 25 Step -1
If DayOfWeek(Date(annee, 10, i, 0, 0, 0)) = 0 : dimancheOctobre = i : Break : EndIf
Next
If (mois > 3 And mois < 10) Or (mois = 3 And jour >= dimancheMars) Or (mois = 10 And jour < dimancheOctobre)
ProcedureReturn 2.0
Else
ProcedureReturn 1.0
EndIf
EndProcedure
Procedure.s SaisonHoraire(offset.d)
If offset = 2.0 : ProcedureReturn "Heure d'été : UTC+2" : Else : ProcedureReturn "Heure d'hiver : UTC+1" : EndIf
EndProcedure