Integralfunktion bei UserReadings

Begonnen von simonberry, 19 August 2014, 16:29:39

Vorheriges Thema - Nächstes Thema

simonberry

Hallo zusammen,

ich habe mich gestern länger mal mit den userReadings beschäftigt, und mir ist aufgefallen, dass es zwar die Differentalfunktion (Ableitung) gibt aber nicht die Umkehrfunktion dazu, also die Integralfunktion.
Anwendungsbeispiel Differentialfunktion:
* Aus einem Energiezähler (kWh) die aktuelle Leistung berechnen (kW)
Anwendungsbeispiel Integralfunktion:
* Aus einer aktuellen Leistung (kW) die Energie berechnen.  (kWh)

Meine Vorstellung der Funktion:
Es wird die Zeitdifferenz zwischen den beiden letzten Messungen multipliziert mit dem Mittelwert der letzen beiden Messsungen  und zum alten "Reading" addiert.
Reading = Reading + difftime * (oldvalue + value) / 2

Da ich so Neugierig bin habe ich mal in den Sourcen nach "differential" gegreped und bin in fhem.pl fündig geworden. (Oh Gott das Herzstück  :o)
Mit den bereits vorhandenen Berechnungsmethoden war es mir ein leichtes mein Vorhaben umzusetzen.  ;)

Ich habe das mal bei mir mit ein paar Handgriffen in der fhem.pl eingebaut und es funktioniert ganz prima:  :D
in der Funktion CommandAttr hinter "differential" "integral" eingetragen

        if(grep { /$modifier/ } qw(none difference differential integral offset monotonic)) {

in der Funktion readingsEndUpdate
einen weiteren elsif für integral ergänzt

      } elsif($modifier eq "differential") {
        my $deltav= $value - $oldvalue if(defined($oldvalue));
        my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
        if(defined($deltav) && defined($deltat) && ($deltat>= 1.0)) {
          $result= $deltav/$deltat;
        }
      } elsif($modifier eq "integral") {
        if (defined($oldt) && defined($oldvalue))
        {
          my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
          my $avgval= ($value + $oldvalue) / 2;
          $result = ReadingsVal($name,$userReading,$value);
          if($deltat>= 1.0) {
            $result+= $avgval*$deltat;
          }
        }


So und nun steht das bei mir in der fhem.pl und beim nächsten Update is es wieder weg.
Besteht Interesse das Aufzunehmen? Wie kann das geschehen.

Viele Grüße

Simonberry
NUC5i3RYK#DBLOG; MYSQL; LIRC; MPD; HM-CFG-HM-USB-2: HM-divers; MQTT2; Signalduino; Shelly; Sonoff; dash_dhcp; FS20; IT; FroniusWR; Somfy RTS; NFS-Server
Rpi B#: nfsmount; ser2net CUL868; CUL433; GPIO4:DS18B20; WEMOS-D1-MINI#JVC-via-IR;

rudolfkoenig

Ich habe zwar nicht wirklich Interesse, aber ich wuerde es aufnehmen, falls ich auch noch Patches fuer commandref_frame.html und commandref_frame_DE.html bekomme.

Das naechste mal bitte nicht in der Wunschliste sondern nach Sonstiges schreiben (fhem.pl Aenderungen gehoeren dahin, siehe MAINTAINER.txt) , Wunschliste lese ich eigentlich aus Prinzip nicht :)

simonberry

Hallo Rudolf,

Danke das Du es aufnimmst
Anbei die beiden patches, ich hoffe das passt so, aber es ist ja nicht viel.

Viele Dank und Grüße

Simonberry
NUC5i3RYK#DBLOG; MYSQL; LIRC; MPD; HM-CFG-HM-USB-2: HM-divers; MQTT2; Signalduino; Shelly; Sonoff; dash_dhcp; FS20; IT; FroniusWR; Somfy RTS; NFS-Server
Rpi B#: nfsmount; ser2net CUL868; CUL433; GPIO4:DS18B20; WEMOS-D1-MINI#JVC-via-IR;

micomat

Hallo Simonberry,

das klingt sehr interessant. Koenntest Du Deine Umsetzung mal kurz fuer doofe erklaeren? =)

Gruesse,
Markus
Synology DS218+ with fhem+iobroker in docker, 2x RasPi w. ser2net, CUL433+868, IT, EGPM2LAN, THZ/LWZ, FB_Callmonitor, HMS100TF, Homematic, 2x TX3-TH, Pushover, USB-IR-SML-Head, SONOS, GHoma, MBus, KLF200

simonberry

#4
Hallo Markus

Am Besten versuche ich es an meinem persönlichem Projekt (leider noch nicht ganz abgeschlossen) erkläre.

Ich will meinen Wärmeverbrauch der bezogenen Fernwärme loggen. In meiner Heizung ist zwar ein Wärmemengenzähler vom Energieversorger (Sharky 775 von Diehl) aber der ist verblomt und die Infrarotschnittstelle sendet nix... :'(

Mit Google und Wiki und Restwissen vom Studium habe ich herausgefunden:
Um die aktuelle Leistung der Fernwärmeübergabe zu berechnen benötigt man 3 Werte:

  • Temperatur Vorlauf
  • Temperatur Rücklauf
  • Volumenfluss vom Wasser
Die Aktuelle Leistung berechnet sich nach folgender Formel:
P = VolumenFluss * Spezifische Wärmekapazität Wasser * (TempVorlauf - TempRücklauf)

Die Bezogene Wärmemenge (das was ich bezahlen muss) ist dann das Integral bzw die Fläche unter dem Graphen.
Angenommen die Leistung ist 1 Stunde konstant:
E = P * 1h
Ändert sich die Leistung ist es die Summe von mehreren kleinen Zeitintervallen * Leistung
E = P1 * t1 + P2 * t2 + P3 *t3
Genau dieses tut meine Erweiterung nun.


Mittels 2 Temperatursensoren messe ich Vor  und Rücklauf, den Volumenfluss kann ich bis jetzt leider nur Raten, weshalb ich noch nicht ganz glücklich bin.
Der Volumenfluss wird durch die Heizung durch ein Stellglied eingestellt (mein Ansatz hier was ab zugreifen). Mein Wärmezähler misst den und zeigt den auch an, weshalb ich jetzt immer mit 135 Liter/h rechne.
Da das Stellglied aber nicht immer offen ist, muss ich außerdem noch raten, wann es offen ist. Das ist offensichtlich dann der Fall, wenn der Vorlauf plötzlich heiß wird (von ca. 28° auf 55°). Momentan frage ich einfach ab ob die Vorlauftemperatur größer als 45 ° ist.

Per notify ausgelöst durch die Vorlauftemperatur berechne ich nun die Leistung und speichere sie als reading einem dummy. Der Dummy berechnet dann per "userReading integral "die Wärmemenge.

Hier mein Code aus der fhem.cfg

define Fernwaerme dummy
attr Fernwaerme alias Fernwaerme
attr Fernwaerme icon sani_earth_source_heat_pump
attr Fernwaerme stateFormat {sprintf("%.1f kWh %.1f kW\n", ReadingsVal("Fernwaerme","Energie",0), ReadingsVal("Fernwaerme","Leistung",0));;}
attr Fernwaerme userReadings Energie integral {ReadingsVal("Fernwaerme","Leistung",0)/3600}
define notiVor notify Vorlauf {\
  fhem("setreading Fernwaerme Vorlauf ". $EVENT);;\
  fhem("setreading Fernwaerme Ruecklauf ". Value("Ruecklauf"));;\
  my $tempdiff = $EVENT - Value("Ruecklauf");;\
  if ($tempdiff < 0) \
  {\
    $tempdiff = 0;;\
  }\
  fhem("setreading Fernwaerme TempDiff ". $tempdiff);;\
  if ($EVENT > 45)\
  {\
    my $Leistung = 0.135 * 4.182 / 3.6 * $tempdiff;;\
    fhem("setreading Fernwaerme Leistung $Leistung");;\
  }\
  else\
  {\
    fhem("setreading Fernwaerme Leistung 0");;\
  }\
}
define FileLog_Fernwaerme FileLog log/Fernwaerme-%Y-%m.log Fernwaerme
define SVG_FileLog_Fernwaerme_1 SVG FileLog_Fernwaerme:SVG_FileLog_Fernwaerme_1:CURRENT


(http://M:%5Cfernwaerme.png)



NUC5i3RYK#DBLOG; MYSQL; LIRC; MPD; HM-CFG-HM-USB-2: HM-divers; MQTT2; Signalduino; Shelly; Sonoff; dash_dhcp; FS20; IT; FroniusWR; Somfy RTS; NFS-Server
Rpi B#: nfsmount; ser2net CUL868; CUL433; GPIO4:DS18B20; WEMOS-D1-MINI#JVC-via-IR;

rudolfkoenig

Habs eingecheckt.

Bitte demnaechst "diff -u" zum Patch-Bauen verwenden, mit einem reinen diff kann man wenig anfangen.
Weitehin waere praktisch, wenn die deutsche Doku auch deutsch waere (habs jetzt selbst uebersetzt).
Ich habe eine weitere Pruefung beim Rechnen gesetzt, habe trotzdem das Gefuehl, dass eine noch fehlt (fuer value). Kannst Du das alles bitte pruefen?

Gruss,
  Rudi

simonberry

Hallo Rudi,

sorry für den zwei englischen Versionen, hab mir wohl beim kopieren die deutsche Version überbügelt.<br>  diff -u werde ich verwenden und zwar für folgendes:
Die Methode "integral" wird beim Start von FHEM noch abgelehnt...
Die Prüfungen hab ich mir angeschaut, ich hatte oldt und oldval auch geprüft im if oben drüber... jetzt wird's doppelt geprüft, schadet auch nicht.

Viele Grüße

Simonberry




NUC5i3RYK#DBLOG; MYSQL; LIRC; MPD; HM-CFG-HM-USB-2: HM-divers; MQTT2; Signalduino; Shelly; Sonoff; dash_dhcp; FS20; IT; FroniusWR; Somfy RTS; NFS-Server
Rpi B#: nfsmount; ser2net CUL868; CUL433; GPIO4:DS18B20; WEMOS-D1-MINI#JVC-via-IR;

UvG

Hallo zusammen,
ich bin neu in diesem Forum und wollte bei userreadings die Funktion integral ausprobieren.
Leider bekomme ich eine Fehlermeldung:

PCA301_01A196: unknown modifier integral for userReading Timediff, this userReading will be ignored

Definiert habe ich
Timediff:power integral {ReadingsVal($name,'power',0)/3600}
Fhem ist auf dem neuestem Stand

Was kann falsch sein

Gruß
Ulrich

simonberry

Hallo Ulrich
es kann sein, dass der letzt Patch noch nicht aktiviert wurde, such mal in fhem.pl nach der Zeile

if(grep { /$modifier/ } qw(none difference differential offset monotonic)) {

Und ergänze "integral", so dass es so aussieht:

if(grep { /$modifier/ } qw(none difference differential integral offset monotonic)) {


Viele Grüße

NUC5i3RYK#DBLOG; MYSQL; LIRC; MPD; HM-CFG-HM-USB-2: HM-divers; MQTT2; Signalduino; Shelly; Sonoff; dash_dhcp; FS20; IT; FroniusWR; Somfy RTS; NFS-Server
Rpi B#: nfsmount; ser2net CUL868; CUL433; GPIO4:DS18B20; WEMOS-D1-MINI#JVC-via-IR;

UvG

Hallo Simonberry,

danke für die Antwort.
Änderung habe ich gemacht und es funktioniert.
Lieder wird dies woll nach der nächsten Änderung von fhem.pl wieder geändert.

Danke

Ulrich

simonberry

Hallo Ulrich

Rudi hat die Änderung übernommen, ist also beim nächsten update erledigt.

siehe
http://forum.fhem.de/index.php/topic,33260.0/topicseen.html

Gruß

Simonberry
NUC5i3RYK#DBLOG; MYSQL; LIRC; MPD; HM-CFG-HM-USB-2: HM-divers; MQTT2; Signalduino; Shelly; Sonoff; dash_dhcp; FS20; IT; FroniusWR; Somfy RTS; NFS-Server
Rpi B#: nfsmount; ser2net CUL868; CUL433; GPIO4:DS18B20; WEMOS-D1-MINI#JVC-via-IR;

cwagner

Nach Rücksprache mit dem Autor: In Beitrag #4 gibt es eine falsche Einheitenbezeichnung: Das Ergebnis des Rechenweges ergibt MWh bzw. MW (im Code Beispiel ist das attr stateformat anzupassen)

Christian
PI 2B+/3B+ Raspbian 12, Perl 5.36.0, FHEM 6.3: 295 Module in ConfigDB: Steuerung Heizkessel, FBH, Solarthermie, kontr. Lüftung mit WRG. Smarthome u.a. HMCUL, 1-Wire (FT232RL ; DS2480B), EnOcean (TCM EPS3), MQTT2. DOIF, PID20, Threshold, OWX; Micropelt IRTV, Volkszähler, SolarForecast; MariaDB

buennerbernd

Ich habe userReadings mit integral-Funktion entdeckt.
Leider passt die Implementierung nicht auf jeden Use-Case. Es wird der Durchschnitt zwischen altem und neuem Wert zur Berechnung herangezogen.
Ich habe eine Datenquelle, die nur bei Änderungen Daten liefert. Die Durchschnittsberechnung verfälscht in diesem Fall sehr.
Wünschenswert wäre eine Alternative, die nur den alten Wert heranzieht. (z.B. ein Gerät war lange Zeit ausgeschaltet und hat in dieser Zeit nichts verbraucht. Der Zähler sollte sich im Moment des Anschaltens noch nicht erhöhen.)
Modulentwickler von KLF200 und KLF200Node

simonberry

Hallo buennerbernd,

so ganz verstehe ich Dein Problem leider nicht. Kannst Du das evtl etwas konkreter erläutern?

Evtl hilft es ja auch die Events mittels event-on-change-reading etwas besser zu dosieren.
Oder die Datenquelle muss künstlich so eingestellt werden, dass im Fall von "aus" 0 liefert.

Viele Grüße

Simonberry

NUC5i3RYK#DBLOG; MYSQL; LIRC; MPD; HM-CFG-HM-USB-2: HM-divers; MQTT2; Signalduino; Shelly; Sonoff; dash_dhcp; FS20; IT; FroniusWR; Somfy RTS; NFS-Server
Rpi B#: nfsmount; ser2net CUL868; CUL433; GPIO4:DS18B20; WEMOS-D1-MINI#JVC-via-IR;

buennerbernd

Die Daten kommen bei mir per MQTT.
Sie kommen nicht in regelmäßigen Intervallen, sondern sehr zeitnah, wenn es einen neuen Wert gibt.
Bei mir z.B. eine Klimaanlage, die liefert den aktuellen Strom per MQTT:

Die Klimaanlage ist tagelang aus -> wenige mal am Tag kommt CT = 0
Die Klimaanlage wird eingeschaltet -> sofort kommt CT = 4,39 einmalig bis zur nächsten Änderung
Die Klimaanlage schaltet etwas runter -> Änderung auf CT = 3,84 einmalig bis zur nächsten Änderung

Bei jedem Dateneingang kann ich den bisherigen Verbrauch abrechnen. Dabei ist es unerheblich, was der neue Wert ist. Der alte Wert hat bis dahin gegolten. Der Durchschnitt aus altem und neuem Wert würde den Verbrauch extrem verfälschen.

Die aktuelle Integtral-Implementierung Reading = Reading + difftime * (oldvalue + value) / 2 ist gut geeignet für Daten, die in regelmäßigen Intervallen kommen und unklar ist, wann in einem Intervall sich die Daten geändert haben.

Für den Fall, dass die Intervalle unterschiedlich lang sind, dafür aber klar ist, dass der Wert seit Anfang des Intervalls gilt, passt folgende Formel besser: Reading = Reading + difftime * oldvalue.
Es ist klar, dass der Verbrauch so immer einen Wert hinterher hinkt. Dafür ist er aber deutlich genauer.

Super wäre es, wenn es für solche Datenquellen eine alternative Integralberechnung gäbe.

Viele Grüße,
buennerbernd.
Modulentwickler von KLF200 und KLF200Node