76_SolarForecast - Informationen/Ideen zu Weiterentwicklung und Support

Begonnen von DS_Starter, 11 Februar 2024, 14:11:00

Vorheriges Thema - Nächstes Thema

Hadl

Zitat von: DS_Starter am 01 November 2025, 21:45:50Das reicht aber eigentlich nur als Start wenn Ereq kleiner als ein einzelner (Stunden)-Slot ist, weil die Suche sonst nie genug Spielraum hat.

Besser ist es hier von $remainingSurp als initial $high auszugehen, wobei hier die aktuelle Stunde auch zeitgewichtet ist. Das gilt für den Fall der Zielerreichbarkeit.
Wenn das Ziel nicht erreichbar ist, erreicht die Iteration nicht das geforderte eps und bei Erreichen von max_iter abgebrochen. Der zurück gegebene Werte ist (nahe) dem maximalen Stundenslot. D.h. bei Nichterreichbarkeit ist eine Iteration nicht zielführend da kein Ergebnis vor Zwangsabbruch geliefert werden kann. Deswegen wird in diesem Fall der maximal verfügbare Stundeslot geliefert:
Ich glaube das ist nicht notwendig, denn wenn das Ziel nicht erreichbar ist, werden wir immer an der Abbruchbedingung mit max_iter scheitern, denn die Summe an Energie (charged) kann dann ja nichtmehr groß genug werden. Da hilft es auch nicht den oberen Werte der binären Suche höher zu setzen, da man ja eh in keiner Stunde mehr als den dortigen Max-Wert Laden kann. Die Konvergenz nach den max_iter Zyklen wird also immer knapp unter den startwert von "high" sein. Wenn man hier die Rest-Tagessumme (Energie) als Leistung nimmt, kommt halt eine utopisch hohe Leistung raus die es erlauben würden diese Summe in einer Stunde zu laden. Dann schlagen warscheinlich die Begrenzungen der Leistung zu.

Nochmal zum Algorithmus und der Unterscheidung zwischen Leistung und Energie (Energie = Leistung * Zeit) und der Zeitgewichtung.
Zitat von: DS_Starter am 31 Oktober 2025, 11:04:24Wenn $mid kleiner als $cap ist, passt das mit Zeitgewichtung weil sie auf $mid angewendet wird. Ist aber $cap kleiner wird der schon zeitgewichtete Wert der Stunde 00 nochmal behandelt.
Wenn man es tun will, dann die generelle Ersetzung in $hsurp->{$hod}{surplswh} nicht verwenden (wie Standard) und dann hier:
Zitat von: DS_Starter am 31 Oktober 2025, 14:18:23Die letzte Aussage bzgl. Doppelbegrenzung war mir ja bereits in #4387 aufgefallen weswegen ich zur aktuellen Stunde das vorab berechnete und mitgegebene zeitgewichtete Replacement verwende.

Ich bin der Überzeugung das wir nicht das "Replacement" mitnehmen sollten weil es sonst eine Doppel-zeitgewichtung ist, sonder das ist physikalisch richtig.

Nehmen wir mal an wir haben in der aktuellen Stunde
Energie Überschuss für ganze Stunde erwartet: 10kWh
Ladeleistung OTP: 1kW
90% der Stunde sind schon um (54 minuten vergangen, 6 minuten übrig)

Dann berechnen wir als Replacement der aktuellen Stunde für den Rest-Überschuss der letzen 6 Minuten eine Energie von 10kWh / 60min/h * 54min = 1kWh

In der Schleife der aktuellen Suche dürfen wir dann nicht annehmen das das 1kWh schon zeitgewichtet ist, und wenn wir mit 1kW Laden wir auch diesen 1kWh in den Akku bekommen (Energie != Leistung). Es sind ja nur noch 6 minuten Übrig. Ohne zeit-multiplikation Leistung in W und Energie in Wh zu wechseln stimmt nur, wenn es genau 1 Stunde in der Energie-Betrachtung ist.

Wir müssen also dort auch die Zeit mit reinnehmem. Laden wir weiter mit 1kW kommen in den 6 Minuten von der 1kWh im Akku an: 1kW / 60min/h * 6min = 0.1kWh

Daher dieser if/else
            if ($nhr eq '00') { $charged += min ($mid, $cap) / 60 * (60 - int $minute);}     # Restkapazität der aktuellen Stunde mit Restzeit gewichten
            else              { $charged += min ($mid, $cap);}                               # Zukünftige Stunden haben die Leistung über die ganze Stunde verfügbar


Viele Grüße

Hadl
FHEM: Rpi 5 + SSD / WR: Fronius Symo Gen24 10.0 Plus + BYD HVS 7.7, Fronius Symo Gen24 12.0 SC (60%) PV: (Ost=3.5 West=6.6 Nord=9.9 Ost=4.5) / Homematic BidCoS / Shelly / Viessmann

DS_Starter

#4411
ZitatIch glaube das ist nicht notwendig, denn wenn das Ziel nicht erreichbar ist, werden wir immer an der Abbruchbedingung mit max_iter scheitern, denn die Summe an Energie (charged) kann dann ja nichtmehr groß genug werden. Da hilft es auch nicht den oberen Werte der binären Suche höher zu setzen, da man ja eh in keiner Stunde mehr als den dortigen Max-Wert Laden kann. Die Konvergenz nach den max_iter Zyklen wird also immer knapp unter den startwert von "high" sein.
Ja genau. Deswegen ist eine Iteration nur bei einer Erreichbarkeit des Ziel sinnvoll, ansonsten kann der höchste verfügbare Stundenwert verwendet werden.

ZitatIch bin der Überzeugung das wir nicht das "Replacement" mitnehmen sollten weil es sonst eine Doppel-zeitgewichtung ist
Ja, entweder 

            if ($nhr eq '00') { $charged += min ($mid, $cap) / 60 * (60 - int $minute);}     # Restkapazität der aktuellen Stunde mit Restzeit gewichten
            else              { $charged += min ($mid, $cap);}                               # Zukünftige Stunden haben die Leistung über die ganze Stunde verfügbar

oder

          my $cap   = $nhr eq '00' ? int $replacement : $hsurp->{$hod}{surplswh};
          $charged += min ($mid, $cap);

mit  $replacement = $hsurp->{$hod}{surplswh} / 60 * (60 - int $minute)) zur Stunde 00 aus Vorberechnung (muß man ja nicht zweimal machen).
Beides vermischt führt zu einer Doppelbehandlung. $cap sind Wh.
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Hadl

Zitat von: DS_Starter am 01 November 2025, 22:48:31Ja genau. Deswegen ist eine Iteration nur bei einer Erreichbarkeit des Ziel sinnvoll, ansonsten kann der höchste verfügbare Stundenwert verwendet werden.
Ja, damit kann man sich Laufzeit sparen. Bei SmartPower wäre es eh egal, da wir dort pinmax setzen bei Nichterreichbarkeit.

Zitat von: DS_Starter am 01 November 2025, 22:48:31muß man ja nicht zweimal machen

Aah, jetzt verstehe ich was du meinst. Man muss es nicht zweimal machen für die gleiche Leistung. Aber für jeden der Leistungswerte muss man es machen. Dann sind aber beide unserer Codes falsch.
Ich versuchs mal zu zerlegen für die aktuelle Stunde.

$replacement ist die Energiemenge, die in der aktuellen Stunde noch zur Verfügung steht.
$hsurp->{$hod}{surplswh} ist die Energiemenge die in der ganzen aktuellen Stunde zur Verfügung stand (surplswh) => Nicht durch replacement ersetzt

Ziel ist es nun die Energiemenge der Rest-Stunde zu berechnen, wenn wir mit dem Minimum aus $mid Leistung und Leistung der aktuellen Stunde rechnen.

Energie aus Limitierter Leistung $mid: $EnergyMid = $mid / 60 * (60 - int $minute)
Energie aus verfügbarer Leistung surplswh: $EnergySurp = surplswh / 60 * (60 - int $minute)
Energiemenge zum Laden ist die kleinere aus Beiden: $charged += min ($EnergyMid, $EnergySurp);

oder vereinfacht
$charged += min ($mid, surplswh) / 60 * (60 - int $minute);

Code ist im Anhang. Ich geh damit morgen mal ins Rennen und werde berichten!


Da ich mich gerade schon eingearbeitet habe, hab ich mir auch noch diese Funktion angeschaut:

sub ___batAdjustPowerByMargin {
  my ($name, $limpower, $pinmax, $whneed, $otpMargin, $remainingSurp) = @_;

  my $pow;
  my $ratio = 0;
  $ratio    = $remainingSurp * 100 / $whneed if($whneed);
 
  return ($pinmax, $ratio)                            if($limpower == $pinmax);
  return ($limpower * (1 + $otpMargin / 100), $ratio) if($limpower == 0 || !$otpMargin || $ratio >= 100 + $otpMargin);

  if ($ratio <= 100) {
      $pow = $ratio <= 50 ? $pinmax : $limpower * (1 + $otpMargin / 100);
  }
  else {
      $pow = $pinmax - ($pinmax - $limpower) * ($ratio - 100) / $otpMargin;
  }

return ($pow, $ratio);
}

Dort ist ein Problem drin.
return ($limpower * (1 + $otpMargin / 100), $ratio) if($limpower == 0 || !$otpMargin || $ratio >= 100 + $otpMargin); Wenn limpower == 0 ist dann bleibts 0
Wenn otpMargin nicht ungleich 0 ist, dann bleibts limpower (multiplikation mit 1)
Aber wenn ratio >= 120% ist, und eigentlich viel Leistung da ist, dann erhöhen wir nochmal. (zweiter return)
Ich hab mal nen Vorschlag im Anhang mit dem Fix


Ich hab noch in meinem Log das gefunden. Kann das von SF kommen?
2025.11.02 00:00:04 2: logdb - timestamp >2025-11-01 24:00:00< is invalid: Hour '24' out of range 0..23 . The dataset is ignored.
FHEM: Rpi 5 + SSD / WR: Fronius Symo Gen24 10.0 Plus + BYD HVS 7.7, Fronius Symo Gen24 12.0 SC (60%) PV: (Ost=3.5 West=6.6 Nord=9.9 Ost=4.5) / Homematic BidCoS / Shelly / Viessmann

DS_Starter

#4413
Moin,

ZitatIch hab noch in meinem Log das gefunden. Kann das von SF kommen?
Code Auswählen
2025.11.02 00:00:04 2: logdb - timestamp >2025-11-01 24:00:00< is invalid: Hour '24' out of range 0..23 . The dataset is ignored.
Ja. Das ist ein befürchteter Seiteneffekt der Änderung in #4361. Deswegen wurde diese Änderung in der eingecheckten Version wieder entfernt.

ZitatAber wenn ratio >= 120% ist, und eigentlich viel Leistung da ist, dann erhöhen wir nochmal. (zweiter return)
"Nochmal" nicht, aber es wird eine Anhebung über limpower hinaus vorgenommen was bei einem ratio von > 1 + optPower tatsächlich unerwünscht ist. Das passe ich an, danke für den Hinweis.  :)
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

DS_Starter

ZitatGibt es auch einen Wert wo ich meine 40% hinterlegen kann, also die Menge an Energie die ich beim Laden möglichst schnell ohne Leistungslimitierung und ohne optionale Lasten erreichen will, jedoch den Akku durchaus darunter entladen lasse, falls notwendig. Die 40% dürfen auch durchaus so wie OptimumTargetSoC steigen, damit nicht meine optionalen Lasten den Akku bei schlechten Tagen auf 40% halten.
Wenn ich es richtig interpretiere gibt es Interesse an einem SoC-Parameter (nennen wir ihn mal ctlBarrierSoC), ab dem die Ladeleistungs-Strategie optPower oder smartPower beginnen soll zu wirken.

Oder in eine Logik überführt:
SoC <= lowSoC                   -> pinreduced
lowSoC < SoC <= ctlBarrierSoC   -> pinmax
charPowLimSoC < SoC <= Ladeziel -> Leistung durch optPower oder smartPower gesteuert

Trifft es das und gibt es dafür weitere Interessenten?

LG
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter