Ist sunset fehlerhaft?

Begonnen von andies, 25 August 2018, 15:43:42

Vorheriges Thema - Nächstes Thema

andies

Guten Tag, ich habe einen Widerspruch nicht auflösen können. Wenn ich das Modul Astro.pm von pah anschaue, sehe ich derzeit in Berlin
SunSet
20:11

und gleichzeitig liefert {sunset("HORIZON=0")}
20:07:09
Beide Angaben sind nicht identisch. Da pahs Modul sich an den umfangreichen Rechnungen diverser Astronomiewebseiten orientiert und diese Zeit auch mit Angaben aus dem Web übereinstimmt, vermute ich, dass sunset() nicht ganz korrekt ist.

Oder habe ich was falsch eingegeben?

Anmerkung: Unter "sunset" versteht man mW in der Astronomie üblicherweise die Zeit, in der die Oberkante der Sonne auf dem in Normalnull befindlichen Horizont verschwunden ist.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

rudolfkoenig

ZitatAnmerkung: Unter "sunset" versteht man mW in der Astronomie üblicherweise die Zeit, in der die Oberkante der Sonne auf dem in Normalnull befindlichen Horizont verschwunden ist.
Meines Wissens ist die Definition des "astronomischen Sonnenuntergangs" 18 Grad unter Horizont, damit man die Sterne beobachten kann. Es gibt aber diverse andere Definitionen, je nach Einsatzgebiet. Die Voreinstellung fuer sunrise/sunset in FHEM ist CIVIL (die Sonne ist 6 Grad unter dem Horizont, man kann nicht mehr ohne Hilfslicht lesen), man kann es aber verstellen, siehe https://fhem.de/commandref_modular.html#SUNRISE_EL

andies

Ja klar, die verschiedenen Definitionen sind ja in der commandref schön erklärt. Aber {sunset("HORIZON=0")} sollte doch nun gerade nicht 18 Grad unter Horizont liefern sondern exakt am Horizont (oder?). Und dann frage ich mich, wieso diese Zeit von der verschieden ist, die pah mit Astro ausrechnet?
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

rudolfkoenig

Die Quellen sind offen, und Mathe gabs in der Schule :)

andies

Na ich wollte erstmal sicher gehen, dass ich nichts übersehen habe. Ich vermute, du hast eine Näherungsformel genommen, während pah die ausführliche Rechnung macht. Letztere ist genauer.

In welcher Datei ist Sunset definiert?


Gesendet von iPhone mit Tapatalk Pro
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

rudolfkoenig

99_SUNRISE_EL.pm.

Ist urspruenglich aus dem Perl Modul DateTime::Event::Sunrise entstanden (vulgo kopiert), indem ich alle Abhaengigkeiten von den benutzten Date:: Modulen entfernt habe, da ich diese nicht auf dem Fritzbox installieren konnte.

andies

Hmm, jetzt bin ich mit meinem Perl-Latein am Ende. Also ich fasse mal zusammen, was ich kapiere. Meiner Vermutung nach wird sunrise hier berechnet (obwohl die eigentliche Funktion "sunset" gar nicht in der Datei sehe):

sub
_sunrise_sunset($$$$$)
{
  my ( $d, $lon, $lat, $altit, $h ) = @_;

  my $sidtime = _revolution( _GMST0($d) + 180.0 + $lon );

  # Compute Sun's RA + Decl + distance at this moment
  my ( $sRA, $sdec, $sr ) = _sun_RA_dec($d);

  # Compute time when Sun is at south - in hours UT
  my $tsouth  = 12.0 - _rev180( $sidtime - $sRA ) / $h;

  # Compute the diurnal arc that the Sun traverses to reach
  # the specified altitude altit:
  my $cost =
    ( sind($altit) - sind($lat) * sind($sdec) ) /
    ( cosd($lat) * cosd($sdec) );

  my $t;
  if ( $cost >= 1.0 ) {
      $t = 0.0;    # Sun always below altit
  }
  elsif ( $cost <= -1.0 ) {
      $t = 12.0;    # Sun always above altit
  }
  else {
      $t = acosd($cost) / 15.0;    # The diurnal arc, hours
  }

  # Store rise and set times - in hours UT

  my $hour_rise_ut = $tsouth - $t;
  my $hour_set_ut  = $tsouth + $t;
  return ( $hour_rise_ut, $hour_set_ut );

}

wobei die entscheidende mathematische Funktion noch diese hier ist

# Sun's Right Ascension (RA), Declination (dec) and distance (r)
sub
_sun_RA_dec($)
{
  my ($d) = @_;

  my ( $r, $lon ) = _sunpos($d);

  my $x = $r * cosd($lon);
  my $y = $r * sind($lon);

  my $obl_ecl = 23.4393 - 3.563E-7 * $d;

  my $z = $y * sind($obl_ecl);
  $y = $y * cosd($obl_ecl);

  my $RA  = atan2d( $y, $x );
  my $dec = atan2d( $z, sqrt( $x * $x + $y * $y ) );

  return ( $RA, $dec, $r );
}

Neben den radial-Koordinaten ist da eine Näherungsgleichung drin. Außerdem vermute ich, dass zwischen zwei Zeitpunkten der Horizont interpoliert wird. Diese Interpolation ergibt dann den genauen Zeitpunkt.

pah macht das nach den astronomischen Berechnungen und die sind iterativ. Er rechnet in Astro.pm so

sub Astro_SunPosition($$$){
...
  return ( \%sunCoor );
}

und dann
########################################################################################################
#
# Astro_SunRise - Find (local) time of sunrise and sunset, and twilights
#                 JD is the Julian Date of 0h local time (midnight)
#                 Accurate to about 1-2 minutes
#                 recursive: 1 - calculate rise/set in UTC in a second run
#                 recursive: 0 - find rise/set on the current local day.
#                                This is set when doing the first call to this function
#
########################################################################################################

sub Astro_SunRise($$$$$$){
  my ($JD, $deltaT, $lon, $lat, $zone, $recursive) = @_;
 
  my $jd0UT = floor($JD-0.5)+0.5;   # JD at 0 hours UT
 
  #-- calculations for noon
  my $sunCoor1 = Astro_SunPosition($jd0UT+   $deltaT/24./3600.,undef,undef);

  #-- calculations for next day's UTC midnight
  my $sunCoor2 = Astro_SunPosition($jd0UT+1.+$deltaT/24./3600.,undef,undef);
 
  #-- rise/set time in UTC
  my ($transit,$rise,$set) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
    $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1,undef);
  if( $transit eq "---" ){
    Log 1,"[Astro_SunRise] no solution possible - maybe the sun never sets ?";
   return( ($transit,$rise,$set) );
  }
 
  my ($transittemp,$risetemp,$settemp);
  #-- check and adjust to have rise/set time on local calendar day
  if ( $recursive==0 ) {
    if ($zone>0) {
      #rise time was yesterday local time -> calculate rise time for next UTC day
      if ($rise >=24-$zone || $transit>=24-$zone || $set>=24-$zone) {
        ($transittemp,$risetemp,$settemp) = Astro_SunRise($JD+1, $deltaT, $lon, $lat, $zone, 1);
        $transit = $transittemp
          if ($transit>=24-$zone);
        $rise = $risetemp
          if ($rise>=24-$zone);
        $set = $settemp
          if ($set>=24-$zone);
      }
    }elsif ($zone<0) {
      #rise time was yesterday local time -> calculate rise time for previous UTC day
      if ($rise<-$zone || $transit<-zone || $set<-zone) {
        ($transittemp,$risetemp,$settemp) = Astro_SunRise($JD-1, $deltaT, $lon, $lat, $zone, 1);
      $rise = $risetemp
        if ($rise<-$zone);
      $transit = $transittemp
        if ($transit<-$zone);
      $set  = $settemp
        if ($set <-$zone);
      }
    }

    $transit = Astro_mod($transit+$zone, 24.);
    $rise    = Astro_mod($rise   +$zone, 24.);
    $set     = Astro_mod($set    +$zone, 24.);

#-- Twilight calculation
#-- civil twilight time in UTC.
my $CivilTwilightMorning;
my $CivilTwilightEvening;
($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
   $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, -6.*$DEG);
if( $transittemp eq "---" ){
      Log 3,"[Astro_SunRise] no solution possible for civil twilight - maybe the sun never sets below -6 degrees?";
      $CivilTwilightMorning = "---";
      $CivilTwilightEvening = "---";
    }else{
  $CivilTwilightMorning = Astro_mod($risetemp +$zone, 24.);
  $CivilTwilightEvening = Astro_mod($settemp  +$zone, 24.);
    }
   
#-- nautical twilight time in UTC.
my $NauticTwilightMorning;
my $NauticTwilightEvening;
($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
  $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, -12.*$DEG);
if( $transittemp eq "---" ){
      Log 3,"[Astro_SunRise] no solution possible for nautical twilight - maybe the sun never sets below -12 degrees?";
      $NauticTwilightMorning = "---";
      $NauticTwilightEvening = "---";
    }else{
      $NauticTwilightMorning = Astro_mod($risetemp +$zone, 24.);
  $NauticTwilightEvening = Astro_mod($settemp  +$zone, 24.);
}

#-- astronomical twilight time in UTC.
my $AstroTwilightMorning;
my $AstroTwilightEvening;
($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
  $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, -18.*$DEG);
if( $transittemp eq "---" ){
      Log 3,"[Astro_SunRise] no solution possible for astronomical twilight - maybe the sun never sets below -18 degrees?";
      $AstroTwilightMorning = "---";
      $AstroTwilightEvening = "---";
    }else{
  $AstroTwilightMorning = Astro_mod($risetemp +$zone, 24.);
  $AstroTwilightEvening = Astro_mod($settemp  +$zone, 24.);
}

#-- custom twilight time in UTC
my $CustomTwilightMorning;
my $CustomTwilightEvening;
    ($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
  $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, $Astro{ObsHor}*$DEG);
  if( $transittemp eq "---" ){
      Log 3,"[Astro_SunRise] no solution possible for custom twilight - maybe the sun never sets below ".$Astro{ObsHor}." degrees?";
      $CustomTwilightMorning = "---";
      $CustomTwilightEvening = "---";
    }else{
  $CustomTwilightMorning = Astro_mod($risetemp +$zone, 24.);
  $CustomTwilightEvening = Astro_mod($settemp  +$zone, 24.);
}

return( ($transit,$rise,$set,$CivilTwilightMorning,$CivilTwilightEvening,
  $NauticTwilightMorning,$NauticTwilightEvening,$AstroTwilightMorning,$AstroTwilightEvening,$CustomTwilightMorning,$CustomTwilightEvening) ); 
  }else{
    return( ($transit,$rise,$set) ); 
  }
}


Jetzt frage ich mich:  Besteht denn eine einfache Möglichkeit, dass die Berechnungen von pah einfach die Grundlage für sunset bilden? Oder kann man durch Änderung des Funktionsaufrufs die Astro-Funktion einfach verwenden? Also statt "sunset()" verwendet man "Astro_SunRise($$$$$$)" oder was auch immer?
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

#7
Lesen müste man:

Zitat von: Prof. Dr. Peter Henning am 07 Juli 2017, 09:13:53
... kann man in jedem eigenen Modul auch ein
require "95_Astro.pm";
an den Anfang setzen. Und sogar ohne Definition eines Astro-Devices auf die somit bekannten Routinen zugreifen. Etwa per
Astro_Get( IRGENDEINE HASH REFERENZ,"dummy","text", "SunRise","2019-12-24");
um den Sonnenaufgang an Heiligabend 2019 zu bekommen.
Man muss nur noch den aktuellen Tag einsetzen und hat alles für ein korrektes sunset().

Ich bin ja Programmierlaie: Ich hätte das gern als Ersatz für das ungenauere Sunset. Was muss ich da tun?Erstmal probieren, ob ich das hinkriege...
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

betateilchen

ich geh mal Popcorn holen...
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

andies

Also mir beim Programmieren zuzusehen gehört in Genre Horrorfilm.


Gesendet von iPad mit Tapatalk Pro
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

#10
Also ich gebe nach mehreren Stunden auf, betateilchen kann sein Popcorn wieder einpacken.

Mir fehlen einfach zu viele Perl-Kenntnisse, das geht doch weiter als meine Möglichkeiten. Ich muss für fast jeden Schritt etwas nachlesen und das dauert einfach zu lange. Ich finde Astro_Get und verstehe auch, dass man einen hash übergibt sowie durch das "text" dafür sorgt, dass eine Textausgabe erfolgt. Wird kein Datum eingegeben, dann holt sich Astro_Get das aktuelle Datum. Das ist schon mal super und damit hätte man die Klassiker wie sunset, sunrise sowie die typischen Angaben von REAL, CIVIL, NAUTIC, ASTRONOMIC, weil die auch in Astro berechnet wurden. Die könnte man sofort holen.

Mir ist aber zum Beispiel nicht klar was ich tun soll, wenn jemand einen speziellen HORIZON eingibt. Das muss ja dann an Astro_Get übergeben werden, damit Astro_Compute alles richtig macht. Ich vermute mal, das müsste in den $hash - nur ist ja kein spezielles device angegeben?

Ich habe für mich jetzt einen workaround und nutze sunset via Astro (ReadingsVal("Astro","Sunset",""), das reicht mir nun.

- ENDE -
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Abspann "Übergangslösung"

Zitat von: Prof. Dr. Peter Henning am 26 August 2018, 17:31:13
Zeitberechnung in DOIF geht auch mit den Werten aus Astro. Lediglich
{sunset()}
ersetzen durch
{my $dummy;;Astro_Get($dummy,"dummy","text", "SunSet")}

Also z.B.
define di_light DOIF ([({my $dummy;;Astro_Get($dummy,"dummy","text", "SunSet")}-600)])(set lamp on)
HORIZON=irgendwas geht damit nicht.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

Prof. Dr. Peter Henning

Jetzt will ich mal einen schmutzigen Trick ins Spiel bringen - ohne dass ich ihn selber ausprobiert hätte. Die Funktion Astro_Get bekommt im ersten Argument eine hash-Referenz übergeben. Und holt sich die Attribute aus diesem hash - das muss also kein hash eines Astro-Devices sein.

Es müsste also folgendes gehen:

1.) Ein beliebiges Device (sagen wir mit Namen "Bla") bekommt ein User Attribute mit Namen "horizon", dessen Wert  der gewünschte Horizontwinkel ist.

2.) Der Funktionsaufruf müsste dann lauten

{Astro_Get($defs{"Bla"},"Bla","text", "CustomTwilightEvening")}

und den Sonnenuntergang für diesen Horizontwinkel liefern.

LG

pah

andies

Klappt
Internals:
   CFGFN     
   NAME       Bla
   NR         805
   STATE      ???
   TYPE       dummy
Attributes:
   horizon    -8.5
   userattr   horizon

und der Befehl liefert
20:19
im Einklang mit den jüdischen Speiseregeln ;-)

Dan würde es sich doch lohnen, das fehlerhafte und (nach meinem Verständnis auch unnötige) SUNRISE_EL.pm durch diesen Trick zu ersetzen? Oder gibt's dann wieder Popcorn?
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Zitat von: Prof. Dr. Peter Henning am 13 September 2018, 15:59:14
1.) Ein beliebiges Device (sagen wir mit Namen "Bla") bekommt ein User Attribute mit Namen "horizon", dessen Wert  der gewünschte Horizontwinkel ist
Warum nicht Bla=global?

Ich werde das mal rudolfkoenig vorschlagen, in dem anderen Thread.


Gesendet von iPhone mit Tapatalk Pro
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Zitat von: rudolfkoenig am 25 August 2018, 16:20:32
Meines Wissens ist die Definition des "astronomischen Sonnenuntergangs" 18 Grad unter Horizont, damit man die Sterne beobachten kann. Es gibt aber diverse andere Definitionen, je nach Einsatzgebiet. Die Voreinstellung fuer sunrise/sunset in FHEM ist CIVIL (die Sonne ist 6 Grad unter dem Horizont, man kann nicht mehr ohne Hilfslicht lesen), man kann es aber verstellen, siehe https://fhem.de/commandref_modular.html#SUNRISE_EL
Ist ja derselbe Thread, sitze am Handy und habe das nicht gesehen.

Also die Frage: kann man nicht das (ungenaue) SUNRISE_EL durch Astro und die Funktion
{Astro_Get($defs{"global"},"global","text", "Sunset")}
etc Ersetzen?



Gesendet von iPhone mit Tapatalk Pro
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

rudolfkoenig

ZitatAlso die Frage: kann man nicht das (ungenaue) SUNRISE_EL durch Astro und die Funktion [...] etc Ersetzen?
Vermutlich, weiss nur nicht, ob es funktioniert, das darf der Astro Autor/Maintainer beantworten.Weitere Probleme mit Astro:
- es wird nicht automatisch geladen
- Time::Local ist mW nicht "out of the Box" nach der Perl-Installation dabei.
=> Soweit ich sehe, ist Astro nicht ohne Weiteres ein Erstatz.

Ich habe keine Interesse daran, sunset durch Astro zu ersetzen.
Falls jemandem das wichtig ist, und alle Support-Aufgaben uebernimmt, stelle ich mich nicht in den Weg.