Sonnenstand aus Kommandozeilenprogramm?
Hi, ich habe hier ein bestehendes System aus Skripten in dem ich ein Programm ersetzen muss, das den aktuellen Sonnenstand zurückgibt. Also man weiß die GPS-Koordinaten und Zeit und will wissen, wie hoch die Sonne (Winkel) und in welcher Richtung sie steht. Das Problem ist dass das bestehende Programm zu ungenau ist, weil es anscheinend nur für Jahre bis ca. 2000 gedacht war und die Abweichungen heute viel zu groß sind. Jetzt brauche ich einen Ersatz dafür.
Ich will kein Webservice oder so, sondern ein eigenständiges Programm das offline funktioniert, das man aus der Kommandozeile aufruft und wo man das Resultat als Text, Datei oder sowas rauskriegt. Keine Fenster zum Klicken oder so. Den Aufruf und das Format kann ich dann schon anpassen, aber viel mehr kann ich an dem ganzen System nicht ändern.
Ich finde einfach nichts passendes, vielleicht hat wer eine Idee?
Betriebssystem ist Windows und es sollte möglichst gratis sein. Linux wäre auch gut weil wir das vielleicht später umstellen wollen, aber das ist im Moment nicht so wichtig.
2 Antworten
Zwei schnell ergooglete Fundstücke - keine Ahnung wie gut die sind, aber die tun auf den ersten Blick genau das, was du suchst:
https://github.com/s-bear/sun-position
https://github.com/klausbrunner/solarpos
Das hier kann anscheinend nur Sonnenaufgang/Untergang, ist wohl nicht die Anforderung: https://github.com/risacher/sunwait
Also Online finden sich auf jeden Fall Excel-Sheets zur Berechnung. Da waren auch sehr exakte dabei.
Schau mal hier:
Als C++-Version (aber ich glaube irgendwo mit Fehler):
void sun::update(std::time_t time, double longitude, double latitude){
//See also https://astronomy.stackexchange.com/questions/24598/how-to-calculate-the-maximum-and-minimum-solar-azimuth-at-a-given-location
const double time_hours = double(time) / 3600.0;
const double time_days = time_hours / 24.0;
const double hours_past_local_midnight = time_hours - (std::floor(time_days) * 24.0);
const double julian_day = time_days+2440587.5;
const double julian_century = (julian_day - 2451545.0)/36525.0;
const double geom_mean_anom_sun = (357.52911 + julian_century * (35999.05029 - 0.0001537 * julian_century)) * (2.0 * M_PI/360.0);
const double earth_eccent_orbit = 0.016708634 - julian_century * (0.000042037 + 0.0000001267 * julian_century);
const double mean_obliq_eliptic = (23.0 + (26.0 + ((21.448 - julian_century * (46.815 + julian_century * (0.00059 - julian_century * 0.001813)))) / 60.0) / 60.0) * (2.0 * M_PI/360.0);
const double geom_mean_long_sun = std::fmod((280.46646 + julian_century * (36000.76983 + julian_century * 0.0003032)), 360.0) * (2.0 * M_PI/360.0);
const double sun_equ_of_ctr = (std::sin(geom_mean_anom_sun) * (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century)) + std::sin(2.0 * geom_mean_anom_sun) * (0.019993 - 0.000101 * julian_century) + std::sin(3.0 * geom_mean_anom_sun) * 0.000289) * (2.0 * M_PI/360.0);
const double obliq_corr = mean_obliq_eliptic + 0.00000355556 * M_PI * std::cos((0.1736667 - 2.686583333 * julian_century) * M_PI);
const double sun_true_long = geom_mean_long_sun + sun_equ_of_ctr;
const double vary = std::tan(obliq_corr / 2.0) * std::tan(obliq_corr / 2.0);
const double app_long = sun_true_long - 0.000007902777778 * M_PI - 0.000006638888889 * M_PI * std::sin((0.1736667 - 2.686583333 * julian_century) * M_PI);
const double equation_of_time = 60.0 * 4.0 * (vary * std::sin(2.0 * geom_mean_long_sun) - 2.0 * earth_eccent_orbit * std::sin(geom_mean_anom_sun) + 4.0 * earth_eccent_orbit * vary * std::sin(geom_mean_anom_sun) * std::cos(2.0 * geom_mean_long_sun) - 0.5 * vary * vary * std::sin(4.0 * geom_mean_long_sun) - 1.25 * earth_eccent_orbit * earth_eccent_orbit * std::sin(2.0 * geom_mean_anom_sun));
const double true_solar_time = std::fmod((hours_past_local_midnight/24.0) * 1440.0 + equation_of_time + 4.0 * (longitude * (360.0/(2 * M_PI))), 1440.0);
const double hour_angle = (true_solar_time / 4.0 < 0.0 ? true_solar_time / 4.0 + 180.0 : true_solar_time / 4.0 - 180.0) * ((2 * M_PI)/360.0);
const double declination = std::asin(std::sin(obliq_corr) * std::sin(app_long));
const double zenith_angle = std::acos(std::sin(latitude) * std::sin(declination) + std::cos(latitude) * std::cos(declination) * std::cos(hour_angle));
const double azimuth_angle = (hour_angle > 0.0 ? std::fmod(std::acos((std::sin(latitude) * std::cos(zenith_angle) - std::sin(declination)) / (std::cos(latitude) * std::sin(zenith_angle))) + M_PI, 2 * M_PI) : std::fmod((3 * M_PI) - std::acos((std::sin(latitude) * std::cos(zenith_angle) - std::sin(declination)) / (std::cos(latitude) * std::sin(zenith_angle))), 2 * M_PI));
dir = glm::normalize(glm::rotateX(glm::rotateY(glm::vec3(0.0, 0.0, -1.0), float(azimuth_angle)), float(-declination)));
this->zenith_angle = float(zenith_angle);
}
//Mostly from https://graphics.stanford.edu/~henrik/papers/nightsky/nightsky.pdf
void moon::update(std::time_t time, double longitude, double latitude){
const double time_hours = double(time) / 3600.0;
const double time_days = time_hours / 24.0;
const double hours_past_local_midnight = time_hours - (std::floor(time_days) * 24.0);
const double julian_day = time_days+2440587.5;
const double julian_century = (julian_day - 2451545.0)/36525.0;
const double l_tmp = 3.8104 + 8399.7091 * julian_century;
const double m_tmp = 2.3554 + 8328.6911 * julian_century;
const double m = 6.2300 + 628.3019 * julian_century;
const double d = 5.1985 + 7771.3772 * julian_century;
const double f = 1.6280 + 8433.4663 * julian_century;
const double eliptic_longitude = l_tmp + 0.1098 * std::sin(m_tmp) + 0.0222 * std::sin(2 * d - m_tmp) + 0.0115 * std::sin(2 * d) + 0.0037 * std::sin(2 * m_tmp) - 0.0032 * std::sin(m) - 0.0020 * std::sin(2 * f) + 0.0010 * std::sin(2 * d - 2 * m_tmp) + 0.0010 * std::sin(2 * d - m - m_tmp) + 0.0009 * std::sin(2 * d + m_tmp) + 0.0008 * std::sin(2 * d - m) + 0.0007 * std::sin(m_tmp - m) - 0.0006 * std::sin(d) - 0.0005 * std::sin(m + m_tmp);
const double eliptic_latitude = 0.0895 * std::sin(f) + 0.0049 * std::sin(m_tmp + f) + 0.0048 * std::sin(m_tmp - f) + 0.0030 * std::sin(2 * d - f) + 0.0010 * std::sin(2 * d + f - m_tmp) + 0.0008 * std::sin(2 * d - f - m_tmp) + 0.0006 * std::sin(2 * d+ f);
const double distance = 1.0 / (0.016593 + 0.000904 * std::cos(m_tmp) + 0.000166 * std::cos(2 * d - m_tmp) + 0.000137 * std::cos(2 * d) + 0.000049 * std::cos(2 * m_tmp) + 0.000015 * std::cos(2 * d + m_tmp) + 0.000009 * std::cos(2 * d - m));
const double mean_obliq_eliptic = (23.0 + (26.0 + ((21.448 - julian_century * (46.815 + julian_century * (0.00059 - julian_century * 0.001813)))) / 60.0) / 60.0) * (2.0 * M_PI/360.0);
const double obliq_corr = mean_obliq_eliptic + 0.00000355556 * M_PI * std::cos((0.1736667 - 2.686583333 * julian_century) * M_PI);
const double local_mean_sidereal_time = 4.894961 + 230121.675315 * julian_century + (longitude * (360.0/(2 * M_PI)));
const double hour_angle = local_mean_sidereal_time - std::atan((std::sin(eliptic_longitude) * std::cos(obliq_corr) + std::tan(eliptic_latitude) * std::sin(obliq_corr)) / std::cos(eliptic_longitude));
const double declination = std::asin(std::sin(eliptic_latitude) * std::cos(obliq_corr) + std::cos(eliptic_latitude) * std::sin(obliq_corr) * std::sin(eliptic_longitude));
const double zenith_angle = std::acos(std::sin(latitude) * std::sin(declination) + std::cos(latitude) * std::cos(declination) * std::cos(hour_angle));
const double azimuth_angle = -std::atan2(std::cos(declination) * std::sin(hour_angle), -std::sin(latitude) * std::cos(declination) * std::cos(hour_angle) + std::cos(latitude) * std::sin(declination));
dir = glm::normalize(glm::rotateX(glm::rotateY(glm::vec3(0.0, 0.0, -1.0), float(azimuth_angle)), float(-declination)));
this->distance = float(distance);
}
Am liebsten hätte ich wirklich ein Programm das ich aufrufe wie "sonnenstand.exe länge breite zeit" und das gibt mir einfach die zwei Werte als Text raus. So ist es nämlich derzeit gemacht. Und es soll möglichst weniger als 0.1 Grad abweichen und nicht wieder in ein paar Jahren ungenau werden...
Naja, Höhe gibt es nicht, nur Winkel. Höhe der Sonne wäre auch etwas komisch, ist ja ein paar Lichtminuten hoch.
Und wenn du das als Skript möchtest kannst du es dir umschreiben. Evtl. aber auch prüfen, dass kein Fehler drinnen ist.
Ansonsten: Das C++ hier ist tatsächlich sehr trivial, evtl. bekommst du es sogar hin das verwendbar zu machen.
So musst du nur noch das Parsing machen und dann compilieren (und evtl. Fegler finden falls vorhanden):
#include <iostream>
void print_sun_position(std::time_t time, double longitude, double latitude){
//See also https://astronomy.stackexchange.com/questions/24598/how-to-calculate-the-maximum-and-minimum-solar-azimuth-at-a-given-location
const double time_hours = double(time) / 3600.0;
const double time_days = time_hours / 24.0;
const double hours_past_local_midnight = time_hours - (std::floor(time_days) * 24.0);
const double julian_day = time_days+2440587.5;
const double julian_century = (julian_day - 2451545.0)/36525.0;
const double geom_mean_anom_sun = (357.52911 + julian_century * (35999.05029 - 0.0001537 * julian_century)) * (2.0 * M_PI/360.0);
const double earth_eccent_orbit = 0.016708634 - julian_century * (0.000042037 + 0.0000001267 * julian_century);
const double mean_obliq_eliptic = (23.0 + (26.0 + ((21.448 - julian_century * (46.815 + julian_century * (0.00059 - julian_century * 0.001813)))) / 60.0) / 60.0) * (2.0 * M_PI/360.0);
const double geom_mean_long_sun = std::fmod((280.46646 + julian_century * (36000.76983 + julian_century * 0.0003032)), 360.0) * (2.0 * M_PI/360.0);
const double sun_equ_of_ctr = (std::sin(geom_mean_anom_sun) * (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century)) + std::sin(2.0 * geom_mean_anom_sun) * (0.019993 - 0.000101 * julian_century) + std::sin(3.0 * geom_mean_anom_sun) * 0.000289) * (2.0 * M_PI/360.0);
const double obliq_corr = mean_obliq_eliptic + 0.00000355556 * M_PI * std::cos((0.1736667 - 2.686583333 * julian_century) * M_PI);
const double sun_true_long = geom_mean_long_sun + sun_equ_of_ctr;
const double vary = std::tan(obliq_corr / 2.0) * std::tan(obliq_corr / 2.0);
const double app_long = sun_true_long - 0.000007902777778 * M_PI - 0.000006638888889 * M_PI * std::sin((0.1736667 - 2.686583333 * julian_century) * M_PI);
const double equation_of_time = 60.0 * 4.0 * (vary * std::sin(2.0 * geom_mean_long_sun) - 2.0 * earth_eccent_orbit * std::sin(geom_mean_anom_sun) + 4.0 * earth_eccent_orbit * vary * std::sin(geom_mean_anom_sun) * std::cos(2.0 * geom_mean_long_sun) - 0.5 * vary * vary * std::sin(4.0 * geom_mean_long_sun) - 1.25 * earth_eccent_orbit * earth_eccent_orbit * std::sin(2.0 * geom_mean_anom_sun));
const double true_solar_time = std::fmod((hours_past_local_midnight/24.0) * 1440.0 + equation_of_time + 4.0 * (longitude * (360.0/(2 * M_PI))), 1440.0);
const double hour_angle = (true_solar_time / 4.0 < 0.0 ? true_solar_time / 4.0 + 180.0 : true_solar_time / 4.0 - 180.0) * ((2 * M_PI)/360.0);
const double declination = std::asin(std::sin(obliq_corr) * std::sin(app_long));
const double zenith_angle = std::acos(std::sin(latitude) * std::sin(declination) + std::cos(latitude) * std::cos(declination) * std::cos(hour_angle));
const double azimuth_angle = (hour_angle > 0.0 ? std::fmod(std::acos((std::sin(latitude) * std::cos(zenith_angle) - std::sin(declination)) / (std::cos(latitude) * std::sin(zenith_angle))) + M_PI, 2 * M_PI) : std::fmod((3 * M_PI) - std::acos((std::sin(latitude) * std::cos(zenith_angle) - std::sin(declination)) / (std::cos(latitude) * std::sin(zenith_angle))), 2 * M_PI));
std:.cout << "Azimuth: " << azimuth_angle << " Declination: " << declination << " Zenith: " << zenith_angle << std::endl;
}
int main(int argc, char argv[]){
//TODO: Parse arguments
print_sun_position(time, longitude, latitude);
return 0;
}
Kleine Korrektur:
int main(int argc, char* argv
[]){
//TODO: Parse arguments
print_sun_position(time, longitude, latitude);
return 0;
}
Danke erstmal, aber ein Excel-Sheet möchte ich vermeiden und dieser C++ code...ich kann nicht wirklich C++ aber glaube da wird nur Azimuth gerechnet, also fehlt schon mal die Höhe?