Markisensteuerung: Hysterese 2.0, gewichteter Mittelwert, Standardabweichung von Sensordaten

Homematic-, TCL- und Shell-Script, Toolchain, C, etc.

Moderator: Co-Administratoren

Antworten
Stefan0815
Beiträge: 169
Registriert: 16.04.2019, 15:15
Hat sich bedankt: 9 Mal
Danksagung erhalten: 10 Mal

Markisensteuerung: Hysterese 2.0, gewichteter Mittelwert, Standardabweichung von Sensordaten

Beitrag von Stefan0815 » 05.05.2020, 01:15

Hintergrund für dieses Script war eine ausgefeilte Sonnenschutz-Steuerung von 2 großen Markisen und div. Rollladen nach Innentemperatur, Außentemperatur, Helligkeit, Uhrzeit, Wind, Regen und Blendwirkung einer untergehenden Sonne. Bei Temperaturwerten kann man leicht über eine einfache Hysterese steuern. Bei den Helligkeitswerten sieht dies schon anders aus, da Wolken kurzfristig die Sonne verdecken können. Man möchte dann natürlich nicht, dass Markisen und Rollladen ständig hin- und herfahren. Eine Lösung wäre ein Mittelwert über eine möglichst definierte Zeiteinheit. Noch besser ein gewichteter Mittelwert, der die letzten Daten mit einer höheren Wichtung versieht. Noch spezieller benötigt man es allerdings beim Thema Wind und einer einteiligen Markise der Dimension 7,50 x 4 m. Das ist ein Segel, welches bei Wind enorme Kräfte entwickeln kann. Insbesondere bei böigem Wind möchte man abschätzen, in welchen Dimension diese Böen erwartbar sind. Also Statistik.

Grundlage ist eine gezielte Sammlung von Umweltdaten über einen definierten Zeitraum. Das kann man so übrigens für sämtliche Sensordaten adaptieren.
5.PNG
LOG der gemessene Windgeschwindigkeit zum Zeitpunkt x in km/h

Code: Alles auswählen

!- liefert Wind-Werte der letzten 6h, bytelander - 05.05.2020

string DeviceChannelName = "Wetterstation:1";
string LogVariable = "UmweltWindLog";
string LogValue = "WIND_SPEED";
integer SecondsLog = 21600;
real Faktor = 2.0;

!- aktuelle Uhrzeit über Datum und 24-Stunden Zeit als Integer in Sekunden
integer now = system.Date("%F %X").ToTime().ToInteger();
!- aktuelle LogVariable auslesen
string list = dom.GetObject(LogVariable).Value();
string index;
integer count = 1; !- da es bei Eventauslösung immer ein (neues) Element gibt
!- neues Element an den Anfang der neuen Liste stellen
string newlist = dom.GetObject(DeviceChannelName).DPByHssDP(LogValue).Timestamp().ToTime().ToInteger().ToString()+"#"+dom.GetObject(DeviceChannelName).DPByHssDP(LogValue).Value().Round(1).ToString().RTrim("0").RTrim(".");

!- durch alle Listenelemente, um bereits gespeicherte Elemente, die noch nicht zu alt sind, in die neue Liste aufzunehmen, Liste wird HINTEN um zu alte Elemente abgeschnitten
foreach (index, list){
  !- Zeitauswertung für alle ALTEN Listenelemente
  if ((now-index.StrValueByIndex("#", 0).ToInteger())<=SecondsLog){
    newlist=newlist+"\t"+index;
    count=count+1;
  }
}

dom.GetObject(LogVariable).State(newlist); !- neue LOG-Liste schreiben
!- WriteLine(newlist.Replace("\t","@"));  
Der obige Scriptteil "missbraucht" hiefür eine String-Systemvariable als universellen Datenspeicher. Die Daten werden mit einem genauen Zeitstempel versehen und können somit gezielt abgeschnitten werden. Neue Daten werden vorn angefügt, alte Daten fliegen hinten raus. Weiterhin ist eine Auswertung nach genau definierten Zeitabschnitten möglich, was gerade bei Wind-Daten sehr sinnvoll ist. Ich verwende diese Datensammlung für alle Umweltdaten in unterschiedlichen Intervallen. Beispiel: Min/Max-Werte der Außentemperatur der letzten genau 12 und 24 Stunden.
4.PNG
praktische Nutzung zur Ermittlung von MIN/MAX-Werten
4.PNG (6.7 KiB) 2080 mal betrachtet

Code: Alles auswählen

!------------------- Mittelwert, gewichteter Mittelwert, Varianz und Standardabweichung für Long --------------------

string GMWLogVariable = "GMWWindLong"; !- Variable für gewichteten Mittelwert
string WindLong95Variable = "WindLong95"; !- Variable für WindLong95
integer GMWSecondsLog = 5400; !- Zeitspanne für gewichteten Mittelwert in Sekunden: 5400 (90 Minuten)
real sumMW;

!- Anzahl Elemente für Zeiteinheit ermitteln und "normalen" Mittelwert berechnen
integer count = 0;
foreach (index, newlist){
  if ((now-index.StrValueByIndex("#", 0).ToInteger())<=GMWSecondsLog){
    sumMW = sumMW + index.StrValueByIndex("#", 1).ToFloat();
    count=count+1;
  }
}
real MWLong = sumMW/count; !- Mittelwert für Long

real sumVQ;
foreach (index, newlist){
  if ((now-index.StrValueByIndex("#", 0).ToInteger())<=GMWSecondsLog){
    sumVQ = sumVQ + ((index.StrValueByIndex("#", 1).ToFloat() - MWLong) * (index.StrValueByIndex("#", 1).ToFloat() - MWLong));
  }
}

real VarianzLong = sumVQ/count;
real StandAbwLong = VarianzLong.Sqrt();
real WindLong95 =  MWLong+(StandAbwLong*Faktor);
dom.GetObject(WindLong95Variable).State(WindLong95.Round(2)); !- WindLong95 schreiben

real countGMW = ((count*(count+1))/2);
real sumGMW;
integer c = 0; !- Zähler für Gewichtung
foreach (index, newlist){
  if ((now-index.StrValueByIndex("#", 0).ToInteger())<=GMWSecondsLog){
    sumGMW=sumGMW+(index.StrValueByIndex("#", 1).ToFloat()*(count-c));
    c=c+1;
  }
}

real GMW = sumGMW/countGMW;
dom.GetObject(GMWLogVariable).State(GMW.Round(2)); !- neuen gewichteten Mittelwert für Long schreiben
!- WriteLine(GMW.Round(2));

!------------------- Mittelwert, gewichteter Mittelwert, Varianz und Standardabweichung für Short --------------------

string GMWLogVariable = "GMWWindShort"; !- Variable für gewichteten Mittelwert
string WindShort95Variable = "WindShort95"; !- Variable für WindLong95
integer GMWSecondsLog = 1800; !- Zeitspanne für gewichteten Mittelwert in Sekunden: 1800 (30 Minuten)
real sumMW;

!- Anzahl Elemente für Zeiteinheit ermitteln und "normalen" Mittelwert berechnen
integer count = 0;
foreach (index, newlist){
  if ((now-index.StrValueByIndex("#", 0).ToInteger())<=GMWSecondsLog){
    sumMW = sumMW + index.StrValueByIndex("#", 1).ToFloat();
    count=count+1;
  }
}
real MWShort = sumMW/count; !- Mittelwert für Short

real sumVQ;
foreach (index, newlist){
  if ((now-index.StrValueByIndex("#", 0).ToInteger())<=GMWSecondsLog){
    sumVQ = sumVQ + ((index.StrValueByIndex("#", 1).ToFloat() - MWShort) * (index.StrValueByIndex("#", 1).ToFloat() - MWShort));
  }
}
real VarianzShort = sumVQ/count;
real StandAbwShort = VarianzShort.Sqrt();
real WindShort95 =  MWShort+(StandAbwShort*Faktor);
dom.GetObject(WindShort95Variable).State(WindShort95.Round(2)); !- WindShort95 schreiben

real countGMW = ((count*(count+1))/2);
real sumGMW;
integer c = 0; !- Zähler für Gewichtung
foreach (index, newlist){
  if ((now-index.StrValueByIndex("#", 0).ToInteger())<=GMWSecondsLog){
    sumGMW=sumGMW+(index.StrValueByIndex("#", 1).ToFloat()*(count-c));
    c=c+1;
  }
}

real GMW = sumGMW/countGMW;
dom.GetObject(GMWLogVariable).State(GMW.Round(2)); !- neuen gewichteten Mittelwert für Short schreiben
!- WriteLine(GMW.Round(2));
Der zweite Scriptteil berechnet den Mittelwert, den umgekehrt gewichteten Mittelwert, die Varianz und die Standardabweichung für zwei genau definierte Intervalle. Im rund 95%-Bereich der Windwerte (also +-Standardabweichung *2) liegen nahezu alle Windböen. Die konkrete Steuerung der Markisen erfolgt dabei bei einer Windschwelle als oberen Hysteresepunkt und als unteren Hysteresepunkt müssen die 95%-Werte für Long und Short unter genau diesen Wert fallen. Der Shortwert steigt dabei sehr schnell an und der Longwert fällt nach starken Böen langsamer ab. Hört sich ggf. etwas kompliziert an, funktioniert aber extrem zuverlässig. Insbesondere auch dann, wenn man mal nicht vor Ort ist.
3.PNG
gewichtete Mittelwerte für die sekundengenau definierten Zeitabschnitte long und short, obere 95%-Schwelle für long und short
3.PNG (3.27 KiB) 2087 mal betrachtet
6.PNG
Mittelwert+2*Standardabeichung (95%) für long und short im Verlauf zu den gemessenen Windgeschwindigkeiten
Beispiel: Die obere Windschwelle wird mit 30 km/h festgelegt. Steigt der gemessene Windwert einmalig über diesen Wert, wird Wind=true. Sinken WindLong95 und WindShort95 einmalig zusammen unter 30 km/h wird Wind=false. Das funktioniert natürlich auch für Zwischenwerte, um eine Markise beispielsweise nur halb herauszufahren.

Viel Spaß, bytelander
Viele Grüße
Stefan

alchy
Beiträge: 10744
Registriert: 24.02.2011, 01:34
System: CCU
Hat sich bedankt: 65 Mal
Danksagung erhalten: 671 Mal

Re: Markisensteuerung: Hysterese 2.0, gewichteter Mittelwert, Standardabweichung von Sensordaten

Beitrag von alchy » 10.05.2020, 12:13

Kleiner Tipp, bleib vorsichtig mit der Anzahl der Zeichen, welche du in einer Systemvariable (zwischen)speicherst.

Alchy

Blacklist................... almost full
Ignoranz ist die Summe aller Maßnahmen die man ergreift, um bestehende Tatsachen nicht sehen zu müssen.

© Sandra Pulsfort (*1974)

Lies bitte die Logik von WebUI Programmen und die Tipps und Tricks für Anfänger.

Wichtig auch CUxD ersetzt System.exec. Die HM Script Doku (Downloadart Skripte) hilft auch weiter.
Zum Testen von Scripten den >> HomeMatic Script Executor << von Anli benutzen.

Stefan0815
Beiträge: 169
Registriert: 16.04.2019, 15:15
Hat sich bedankt: 9 Mal
Danksagung erhalten: 10 Mal

Re: Markisensteuerung: Hysterese 2.0, gewichteter Mittelwert, Standardabweichung von Sensordaten

Beitrag von Stefan0815 » 10.05.2020, 12:19

alchy hat geschrieben:
10.05.2020, 12:13
Kleiner Tipp, bleib vorsichtig mit der Anzahl der Zeichen, welche du in einer Systemvariable (zwischen)speicherst.

Alchy
...ja klar danke. Daher auch nur gerundete und maximal abgeschnittene Werte. Das größte LOG hat derzeit unter 8.000 Zeichen. Das dürfte noch kein Problem sein.

Grüße bytelander
Viele Grüße
Stefan

Stefan0815
Beiträge: 169
Registriert: 16.04.2019, 15:15
Hat sich bedankt: 9 Mal
Danksagung erhalten: 10 Mal

Re: Markisensteuerung: Hysterese 2.0, gewichteter Mittelwert, Standardabweichung von Sensordaten

Beitrag von Stefan0815 » 10.05.2020, 12:24

alchy hat geschrieben:
10.05.2020, 12:13
Kleiner Tipp, bleib vorsichtig mit der Anzahl der Zeichen, welche du in einer Systemvariable (zwischen)speicherst.

Alchy
Wo liegt denn die Grenze für String? Ich finde da gerade nichts.
Viele Grüße
Stefan

alchy
Beiträge: 10744
Registriert: 24.02.2011, 01:34
System: CCU
Hat sich bedankt: 65 Mal
Danksagung erhalten: 671 Mal

Re: Markisensteuerung: Hysterese 2.0, gewichteter Mittelwert, Standardabweichung von Sensordaten

Beitrag von alchy » 10.05.2020, 13:15

Mit 8000 Zeichen bist du noch weit entfernt. Ein paar hunderttausend mehr können es schon sein.
Aber weil du die Grösse nicht ausnutzt, heißt das nicht das die User dies auch tun. :mrgreen:
Kann aber auch durchaus sein, das die Grenze jetzt niedriger oder höher oder gar nicht mehr vorhanden ist.
Ich wollte nur darauf hinweisen.

Alchy

Blacklist................... almost full
Ignoranz ist die Summe aller Maßnahmen die man ergreift, um bestehende Tatsachen nicht sehen zu müssen.

© Sandra Pulsfort (*1974)

Lies bitte die Logik von WebUI Programmen und die Tipps und Tricks für Anfänger.

Wichtig auch CUxD ersetzt System.exec. Die HM Script Doku (Downloadart Skripte) hilft auch weiter.
Zum Testen von Scripten den >> HomeMatic Script Executor << von Anli benutzen.

Stefan0815
Beiträge: 169
Registriert: 16.04.2019, 15:15
Hat sich bedankt: 9 Mal
Danksagung erhalten: 10 Mal

Re: Markisensteuerung: Hysterese 2.0, gewichteter Mittelwert, Standardabweichung von Sensordaten

Beitrag von Stefan0815 » 11.05.2020, 11:27

alchy hat geschrieben:
10.05.2020, 13:15
Mit 8000 Zeichen bist du noch weit entfernt. Ein paar hunderttausend mehr können es schon sein.
Aber weil du die Grösse nicht ausnutzt, heißt das nicht das die User dies auch tun. :mrgreen:
Kann aber auch durchaus sein, das die Grenze jetzt niedriger oder höher oder gar nicht mehr vorhanden ist.
Ich wollte nur darauf hinweisen.

Alchy
Guten Hinweis. Den sollte ich im Script aufnehmen.
Danke und viele Grüße
Stefan
Viele Grüße
Stefan

Antworten

Zurück zu „Softwareentwicklung für die HomeMatic CCU“