Einlesen von 3- 5 Leistungswerten mit anschließender Tendenzerkennung
Hallo Forum,
ich habe das Problem, dass meine PV-Anlage beim abendlichen Abschalten oft ein bisschen „Schluckauf“ hat, d.H. dass die Anlage nicht die Leistung linear reduziert, sondern das die Werte zum Schluß stark schwanken können. Das gleiche ist wenn eine Wolke über die Anlage zieht.
Anhand der Leistung erkenne ich den Start und Ende des Wechselrichters führe einen Übertrag der Tagesleistung aus. Um einen sicheres Ende erkennen zu können habe ich mir überlegt eine Tendenzauswertung über mehrere Minuten einzufügen.
Als Lösung habe ich mir überlegt, die Leistung 3-5 mal in einem Abstand von 5 Minuten einzulesen, jeweils in eine Variable abzulegen und anschließend die Tendenz auszuwerten. Also wie ein Array mit einem Pointer.
ich habe vor einiger Zeit mal ein ähnliches Problem mit der Außentemp gehabt.
Dort habe ich dann aber für einen vernünftigen Trend mehrere Temp-Werte gemittelt und daraus über zwei Mittelwerte einen Trend gebildet.
Hier mal ein Teil des Scripts:
$temp = GetValueFloat("vKS300_Temperatur"); // aktuelle Außentemperatur
// #### Temperaturen in Array speichern ####
$string_array = GetValueString("vKS300_array_recent");
$temp_count = 12; //Anzahl zu speichernder Temps
//Array auf vorhandensein prüfen / initialisieren
if ($string_array == "")
{
$temp_array = array_fill(0, $temp_count, $temp);
}
else
{
$temp_array = wddx_deserialize($string_array);
}
array_unshift($temp_array, $temp);
if (count($temp_array) > $temp_count)
unset($temp_array[$temp_count]);
//print_r($temp_array); //nur debug-Ausgabe
// Mittelwert
$mw = array_sum($temp_array) / count($temp_array);
// recent Temperatur mitteln um Kurve zu glätten
$tr = GetValueFloat("vKS300_Temperatur_recent"); // letzter gemittelter Wert
// SetValueFloat("vKS300_Temperatur_tr2",$tr1);
// Trend ermitteln
$tt = $mw-$tr;
// Zeit seit dem letzten Update ermitteln, in Minuten
$vUpdateTime = (date("U")-IPS_GetUpdateTime("vKS300_Temperatur_recent"))/3600;
/* Debug Ausgaben
echo ("Zeit des Updates: ".IPS_GetUpdateTime($DevName."_recent")."
");
echo date("U")."
";
echo ("UpdateTime:". $vUpdateTime."
");
echo ("Temp Trend: ".$tt. "
");
*/
// $ta auf $tr schreiben
if ($vUpdateTime)
SetValueFloat("vKS300_Temperatur_recent", $mw);
$tc = $tt/$vUpdateTime;
SetValueFloat("vKS300_Temperatur_trend", $tc);
// Temperatur-Array in String zurückschreiben
SetValueString("vKS300_array_recent", wddx_serialize_value($temp_array) );
Die Anzahl der Temps ist frei wählbar ($temp_count).
Ev. ist ja eine Anregung dabei…
Wenn was unklar ist, einfach fragen.
Das Script von Prof sind prinzipiell schon mal nicht schlecht aus, hat aber den nachteil das der Trend auch „flattert“, weil wenn der letzte Temp wert niedriger ist als der Schnitt zeigt der Trend nach unten (Wolke) und wenn der letzte Höher ist nach oben. Hängt also nur vom letzen ab, was dir ja imho nicht nützen würde.
Ich würde evtl in folgende Richtung gehen:
Durchschnittwert nehmen okay, dann vergleichen ob der Durchschnitt des ersten drittel der Werte drüber und der Durchschnitt des letzen drittels der werte drunter liegt. Wenn ja sinkende Tendenz erkannt.
Oder Durchschnitt der ersten Hälfte subtrahieren vom Durchschnitt der 2ten Hälfte.
Muss man mal bischen probieren was das Szenario am besten erfasst.
danke für eure Vorschläge. Ich denke wir sprechen alle vom gleichen. Jetzt geht es nur darum dies praktisch umzusetzen. Der Scriptteil mit dem Array gefällt mir schon gut. Schluendlich geht es jetzt darum die entsprechende Auswertung aus dem Array zu programmieren. Bin beim Programmieren nicht so Fit, aber werde mal was versuchen. Wird aber nächste Woche werden.
klar, hab ich verstanden. Mit dem Script hab ich noch a bisserl Probleme. Könnte mir einer von euch beiden das Script ein wenig auskommentieren?
Meine Vorstellung vom Script war einfacher, aber mit einem richtigen Arry gefällt mir das gleich besser, nur hab ich´s noch nicht ganz verstanden.
$temp = GetValueFloat("vKS300_Temperatur"); // aktuelle Außentemperatur
// #### Temperaturen in Array speichern ####
$string_array = GetValueString("vKS300_array_recent");
$temp_count = 12; //Anzahl zu speichernder Temps
//Array auf vorhandensein prüfen / initialisieren
if ($string_array == "")
{
$temp_array = array_fill(0, $temp_count, $temp); // Wenn nicht vorhanden mit 0 Initialisieren
}
else
{
$temp_array = wddx_deserialize($string_array); // Array aus String gewinnen
}
array_unshift($temp_array, $temp); // Vorn neuen Wert anfügen
if (count($temp_array) > $temp_count) // Wenn länger als soll
unset($temp_array[$temp_count]); // Letzen Wert entfernen
//print_r($temp_array); //nur debug-Ausgabe
// Mittelwert
$mw = array_sum($temp_array) / count($temp_array);
$half = floor($temp_count / 2);
// Array_sum addiert alle Werte des übergebenen Arrays
// array_slice splittet ein teilarray ab
// Hier wird Mittelwert zweite Hälfte des Array - Mittelwert erste Hälfte errechnet
$trend = (array_sum(array_slice ($temp_array,-$half))-array_sum(array_slice ($temp_array,0,$half)))/$half;
// Temperatur-Array in String zurückschreiben (Aus array wiueder String machen und in IPS speichern)
SetValueString("vKS300_array_recent", wddx_serialize_value($temp_array) );
Ein paar Sachen könnte man da noch optimieren, z.b. ist das array immer zu lang, so das die Abfrage an sich überflüssig wäre. Naja und die Initialisierung führt dazu, dass die ersten $temp_count Werte Müll ausspucken, könnte man z.B. mit der gerade gemessenen Temperatur, statt 0 füllen. Aber … hey lassen wir die Kirche mal im dorf, das sollte schon funktionieren so
wenn ich das Skript richtig interpretiere, dann soll aus einer Serie von Messwerten, aus den zuletzt eingetroffenen ein Mittelwert gebildet werden.
Es handelt sich dabei um einen sogenannten „Gleitenden Mittelwert“. Er wird mit jedem neu eintreffenden Wert aktualisiert und berücksichtigt dabei immer z.B. die letzten 10 Messungen.
Ich mache von dieser Art der Mittelwertbildung häufig Gebrauch und verwende dabei folgendes Prinzip:
die letzten Messwerte werden in einem Array gespeichert
das Array ist als „Ringpuffer“ organisiert
zur Realisierung der Ringstruktur wird ein Ringzeiger (Index) verwendet
der Ringzeiger lässt die Schreib-/Leseposition im Array rotieren
statt die Summe jedesmal neu zu berechnen, wird immer nur der älteste Wert subtrahiert und dann der neue Wert addiert
je größer das Array ist, um so träger reagiert der Mittelwert
Folgendes Skriptfragment soll das Prinzip verdeutlichen:
// hier Array ($buffer) aus einer Variablen einlesen
$index = GetValueInteger("Buffer_Index"); // alten Zeiger einlesen
$sum = GetValueInteger("Buffer_Sum"); // alte Summe einlesen
$index = $index++ % count($buffer); // Zeiger inkrementieren und Überlauf abfangen (Modulo-Funktion)
$sum -= $buffer[$index]; // zuerst alten Messwert subtrahieren
$buffer[$index] = $IPS_VALUE; // neuen Messwert speichern
$sum += $IPS_VALUE; // jetzt neuen Messwert aufaddieren
$average = $sum/count($buffer); // neuen Mittelwert berechnen
SetValueInteger("Buffer_Index", $index); // aktuellen Zeiger abspeichern
SetValueInteger("Buffer_Sum", $sum); // aktuelle Summe abspeichern
SetValueFloat("Buffer_Average", $average); // Mittelwert abspeichern
// hier Array ($buffer) wieder abspeichern
genauso mache ich z.B. 38 Tage Werte für meine Börsenkurse. Die lege ich dann in einer db ab und kann sie grafisch anzeigen.
Ich weiß, geht auch alles übers Internet…
Aber man experimentiert eben mit verschiedenen Techniken und sei es nur, um sie später einmal einsetzen zu können.
Auch ein nettes Konzept. Nur mit dem gleitenden Mittelwert wird es allerdings, wie ich schon vorher meinte, schwierig eine vernünftige Tendenzaussage ermitteln können. Um eben jene geht es ihm ja letzlich.
Im direkten Vergleich würde ich sagen deine Methode benötigt einen Hauch weniger Rechenoperationen dafür musste etwas mehr Werte speichern. Dürfte in unserem Fall aber beides ziemlich egal sein, geht ja nicht um highperformance Anwendungen
wie bereits gesagt, es geht mir darum erkennen zu können wann wirklich meine PV-Anlage abgeschaltet hat und nicht nur einen „sonnenscheinbedingten Schluckauf“ hatte, d.H. dass die Tendenzauswertung eigentlich mit den ersten Wert unterhalb meiner Schaltschwelle gestartet werden sollte. So ahb ich mir das wenigstens gedacht.
Ich werd die Scripte mal ausprobieren (mal schauen ob ich diese ohne Probleme zum laufen bekomme und werd dann Feedback geben.
Danke schon mal an alle Beteiligten, saubre Arbeit!!!
ich muss aus aktuellem Anlass mal diesen alten Beitrag hochholen. Ihr hatte ja hier zwei Wege zur Trendberechnung dargelegt. Ich habe prof seinen Weg mal umgesetzt und bin aber nun damit gar nicht so gluecklich, weil ich nicht weiss, wie ich das fuer mich verwenden kann.
Folgendes will ich erreichen:
Ein Objekt wird unter bestimmten Bedingungen eingeschaltet, z.B. anhand der Aussentemperatur. Nun moechte ich aber, dass es ausgeschaltet wird, wenn der Trend ueber eine laengere Zeit erkennen laesst, dass die Temperatur sinkt. Ich habe mal die Werte als Kurve mitgeschrieben, aber da kann ich nicht wirklich daraus einen Schaltzeitpunkt ableiten.
Vielleicht habt Ihr noch eine Idee, wie man das verwirklichen koennte.
Achso, die Messwerte fuer den Trend werden minuetlich erfasst und beinhalten 30 Messwerte.
hast Du die Änderung von Anti aus Post Nr. 5 eingefügt? Damit steigt die Aussagekraft erheblich.
Über welchen Zeitraum möchtest Du eine Betrachtung? Innerhalb welcher Zeit soll eine Aussage getroffen werden?
Tatsächlich sieht die Anzeig bei mir ähnlich aus. Wenn Du klarere Werte haben möchtest, muss man die Anzahl der Werte erhöhen.
Man könnte auch die Dauer zum letzten Minimum/Maximum ermitteln und dann bei dauerhafter Überschreitung eines bestimmten Delta über einen gewissen zeitlichen Abstand zum letzten Min/Max eine Entscheidung treffen.
Ich steuere z. B mit der Ermittlung der Tagesmitteltemp über mind. vier Tage meine Heizung automatisch in den „Sommer“-Modus.
Über welchen Zeitraum möchtest Du eine Betrachtung? Innerhalb welcher Zeit soll eine Aussage getroffen werden?
also im Moment nutze ich 30 Messwerte und damit einen zeitraum von 30 Minuten. Das sollte eigentlich ausreichen.
Tatsächlich sieht die Anzeig bei mir ähnlich aus. Wenn Du klarere Werte haben möchtest, muss man die Anzahl der Werte erhöhen.
hhm. Im Moment kann ich so damit nix anfangen. Ich will beispielsweise den Solarregler fuer den Pool abschalten, wenn von dort nicht mehr genuegend Waerme abgegeben werden kann. Auf der anderen Seite will ich aber auch keine staendigen Umschaltungen haben. Das gleiche gilt fuer meine Wintergarten Markise, da will ich das einfahren damit steuern.
Man könnte auch die Dauer zum letzten Minimum/Maximum ermitteln und dann bei dauerhafter Überschreitung eines bestimmten Delta über einen gewissen zeitlichen Abstand zum letzten Min/Max eine Entscheidung treffen.
das waere eine Moeglichkeit - mal schauen, ob HJH noch eine gute Idee hat.