Ankündigung

Einklappen
Keine Ankündigung bisher.

Frage zu Datenbank-Abfrage

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Frage zu Datenbank-Abfrage

    Hallo,

    ich berechne die aktuell verbrauchte Leistung aus dem Zählerstand.

    Ich habe dazu drei verschiedene Varianten im Einsatz:
    1. ([Zählerstand]-[Zählerstand vor 10 min])*3600/60/10
    2. ([Zählerstand]-[Zählerstand vor 1 min]) *3600/60
    3. (3600/800*1000Ws)/[Zeit seit dem letzten Impuls]
      (1Impuls =3600*1000/800 Ws, da 800 Impulse pro kWh)


    Code:
    	[[[Zaehlerstand]]]
    	    name = Zaehlerstand
    	    type = num
    	    sqlite = yes
    	    knx_dpt = 14
    	    eval = sh.Allgemein.Stromzaehler.Counter()/800.0+65535*sh.Allgemein.Stromzaehler.Faktor()+97597.7-14.64
    	    eval_trigger = Allgemein.Stromzaehler.Counter
        [[[Momentanleistung_1min]]]
    	    type = num
    	    sqlite = yes
    	    eval = (sh.Allgemein.Stromzaehler.Zaehlerstand()- sh.Allgemein.Stromzaehler.Zaehlerstand.db('min', '1i'))*60.0*1000.0
    	    eval_trigger=Allgemein.Stromzaehler.Counter
        [[[Momentanleistung_10min]]]
    	    type = num
    	    sqlite = yes
    	    eval = (sh.Allgemein.Stromzaehler.Zaehlerstand()- sh.Allgemein.Stromzaehler.Zaehlerstand.db('min', '10i'))*60.0*1000.0/10.0
    	    eval_trigger=Allgemein.Stromzaehler.Counter
        [[[Momentanleistung_freq]]]
    	    type = num
    	    sqlite = yes
    #Frequenzzaehler: Jeder Counter=1/800kWh=3600/800kws=3600/800*1000Ws; Zeit zwischen zwei Impulsen messen und dadurch teilen --> W
    	    eval = 4500/sh.Allgemein.Stromzaehler.Counter.prev_age()
    	    eval_trigger=Allgemein.Stromzaehler.Counter
    	    enforce_updates=yes
    Jetzt ist aber komisch, dass die drei Varianten zu unterschiedlichen Ergebnissen kommen:
    Code:
    >>> sh.Allgemein.Stromzaehler.Momentanleistung_1min.db('avg', '15h', '14h')
    689.08
    >>> sh.Allgemein.Stromzaehler.Momentanleistung_freq.db('avg', '15h', '14h')
    437.61
    >>> sh.Allgemein.Stromzaehler.Momentanleistung_10min.db('avg', '15h', '14h')
    454.55
    Beim der 1min Variante stimmt also etwas nicht....
    Code:
    (sh.Allgemein.Stromzaehler.Zaehlerstand()- sh.Allgemein.Stromzaehler.Zaehlerstand.db('min', '1i'))
    sh.Allgemein.Stromzaehler.Zaehlerstand() gibt ja den aktuellen Zählerstand.
    sh.Allgemein.Stromzaehler.Zaehlerstand.db('min', '1i') sollte doch den niedrigsten Wert zwischen jetzt und vor einer Minute geben, oder?
    Somit sollte die Differenz den Verbrauch der letzten Minute ergeben, oder?

    Das scheint aber nicht ganz hin zu kommen. Der Fehler ist aber auch nicht ein Faktor zwei (so dass ich zwei Minuten erwischt hätte).

    Was mich auch wundert:
    Code:
    sh.Allgemein.Stromzaehler.Zaehlerstand.db('max', '1i')-  sh.Allgemein.Stromzaehler.Zaehlerstand()
    -0.0012500000302679837
    Sollte das nicht 0 ergeben?

    Gruß,
    Hendrik

    #2
    Hallo Hendrik,

    Du fragst wieso drei unterschiedliche Rechenvarianten und Zeiträume drei unterschiedliche Werte liefern?

    Generell, das rechnen mit kleinen (=<1) und großen Zahlen insbesondere Divisionen können zu Rundungsfehlern führen.

    Bei
    Code:
    sh.Allgemein.Stromzaehler.Zaehlerstand.db('max', '1i')-  sh.Allgemein.Stromzaehler.Zaehlerstand()
    nimmst Du den Wert von SH.py und ziehst davon einen Wert aus der DB ab.
    Bei Floats kann es zu Rundungsfehlern kommen, wie z.B. auch bei DPT9.

    Welche Werte stecken denn so dahinter? Also für:
    sh.Allgemein.Stromzaehler.Counter()
    sh.Allgemein.Stromzaehler.Zaehlerstand()

    Weiterhin solltest Du den trigger für Momentanleistung_10min und Momentanleistung_1min auf Allgemein.Stromzaehler.Zaehlerstand ändern, da Du in eval ja damit rechnest. Sonst kann es zu komischen Überschneidungen kommen. Die könnten evtl. noch vor dem eval von Zaehlerstand ausgeführt werden.

    Bis bald

    Marcus

    Kommentar


      #3
      Hallo Hendrik,

      wie Marcus schon schrieb ist das vollkommen normal:
      Code:
      >>> (sh.zaehler.haushalt.stand.sql() - sh.zaehler.haushalt.stand.sql.db('min','1i')) * 60
      1.40625
      >>> (sh.zaehler.haushalt.stand.sql() - sh.zaehler.haushalt.stand.sql.db('min','2i')) * 30
      0.703125
      >>> (sh.zaehler.haushalt.stand.sql() - sh.zaehler.haushalt.stand.sql.db('min','5i')) * 12
      0.83203125
      >>> (sh.zaehler.haushalt.stand.sql() - sh.zaehler.haushalt.stand.sql.db('min','10i')) * 6
      0.943359375
      Hier kommen allerdings schon 3 Stellen nach dem Komma mit DPT14 alle 2 Minuten auf den Bus.
      Umgezogen? Ja! ... Fertig? Nein!
      Baustelle 2.0 !

      Kommentar


        #4
        Moin Marcus,

        Zitat von mknx Beitrag anzeigen
        Du fragst wieso drei unterschiedliche Rechenvarianten und Zeiträume drei unterschiedliche Werte liefern?
        Genau.

        Generell, das rechnen mit kleinen (=<1) und großen Zahlen insbesondere Divisionen können zu Rundungsfehlern führen.
        Ich sehe jetzt nicht, wo ich den Code dahingehend verbessern könnte (ich glaube, es ist günstiger erst die Subtraktion, dann die Division durchzuführen, oder)
        Allerdings würde ich mich wundern, wenn es daran liegt, denn dafür ist mir der Offset zu systematisch. Würden wir nicht ein stochastisches Verhalten beobachten, wenn es am Runden liegt?

        Bei
        Code:
        sh.Allgemein.Stromzaehler.Zaehlerstand.db('max', '1i')-  sh.Allgemein.Stromzaehler.Zaehlerstand()
        nimmst Du den Wert von SH.py und ziehst davon einen Wert aus der DB ab.
        Bei Floats kann es zu Rundungsfehlern kommen, wie z.B. auch bei DPT9.
        Soweit klar. Der Zähler kommt allerdings nicht als DPT9, sondern als 800 Impulse pro kwh --> Ganzzahlen (das wäre natürlich ein Ansatz: Ich könnte die Differenz der Ganzzahlen nehmen).


        Welche Werte stecken denn so dahinter? Also für:
        sh.Allgemein.Stromzaehler.Counter()
        sh.Allgemein.Stromzaehler.Zaehlerstand()
        Code:
            [[[Counter]]]
                name = Counter
                type = num
                cache=yes
                sqlite = yes
                knx_dpt = 7
                enforce_updates=yes
                knx_listen = 6/7/1
            [[[Ueberlauf]]]
                name = Counter
                type = bool
                sqlite = yes
                knx_dpt = 1
                enforce_updates=yes
                knx_cache = 6/7/0
             [[[Faktor]]]  
                type=num
                eval = sh.Allgemein.Stromzaehler.Faktor() + 1 
                eval_trigger = Allgemein.Stromzaehler.Ueberlauf    
                sqlite=yes
            [[[Zaehlerstand]]]
                name = Zaehlerstand
                type = num
                sqlite = yes
                knx_dpt = 14
                eval = sh.Allgemein.Stromzaehler.Counter()/800.0+65535*sh.Allgemein.Stromzaehler.Faktor()+97597.7-14.64
                eval_trigger = Allgemein.Stromzaehler.Counter

        Erklärung: Counter kommt vom Binäreingang.
        Überlauf zählt die Überläufe (max ist ca 65535)
        Zählerstand dividiert durch 800 und addiert den Überlauf (wobei ich da glaube ich gerade noch einen Fehler entdeckt habe, der sollte aber nicht relevant sein (hinter dem + muss auch durch 800 geteilt werden)


        Weiterhin solltest Du den trigger für Momentanleistung_10min und Momentanleistung_1min auf Allgemein.Stromzaehler.Zaehlerstand ändern, da Du in eval ja damit rechnest. Sonst kann es zu komischen Überschneidungen kommen. Die könnten evtl. noch vor dem eval von Zaehlerstand ausgeführt werden.
        Ja, das sehe ich ein. Nach so einem systematischen Fehler suche ich.

        Aber nochmal auf
        Code:
        sh.Allgemein.Stromzaehler.Zaehlerstand.db('max', '1i')-  sh.Allgemein.Stromzaehler.Zaehlerstand() -0.0012500000302679837
        zurück kommend:
        Ist der Fehler nicht etwas groß? Ich hätte den auf weiter hinten liegenden Stellen erwartet.

        @Jumi:
        Danke für dein Beispiel. Hier ist der Fehler sogar auf der zweiten Nachkommastelle. Das wundert mich schon.

        Gruß,
        Hendrik



        Bis bald

        Marcus[/QUOTE]

        Kommentar


          #5
          Nunja, so eine Verbrauchsanzeige aus Impulsen ist eher ein Schätzwert. Ich würde die Momentanleistung an Deiner Stelle nur aus der Frequenz holen dabei die (hundertstel-)Sekunden zählen. Das wird aber ordentlich Arbeit für sh.py.
          Aus der Datenbank wird das nix solides - ich behaupte sogar das wird nie was solides auf der Basis von Impulsen.

          Als Beispiel mal eine Grafik wie so eine Momentanleistung bei uns gestern aussah. Da sieht man sehr gut was es da für Peaks gibt. Wie gesagt hier kommt das über den Bus mit 3 Stellen nach dem Komma.
          Angehängte Dateien
          Umgezogen? Ja! ... Fertig? Nein!
          Baustelle 2.0 !

          Kommentar


            #6
            Hallo Jumi,

            Wenn ich die Impulse pro Minute/pro 10 min zähle, komme ich auf einen Fehler wie unten dargestellt. Annahme ist, dass statt 10 Impulse (angekommen) in Wahrheit 10.99999 Impulse richtig gewesen wären. Mit ganz viel Pech könnte der Fehler tatsächlich zweimal so groß sein (Fehler am Anfang und Ende des Intervall).

            Bei 500W ist der Fehler bei 1min Betrachtung 13% und bei 10 min ca 1%. Der von mir gezeigte Fehler ist jedoch >50%. Und: Wenn ich in einem Intervall einen zu niedrigen Wert habe, dann habe ich im nächsten Intervall einen zu hohen. Das Integral sollte korrekt sein.
            Ich habe aber einen konstanten Offset.

            Übersehe ich etwas?

            Ich kann damit leben, wenn Peaks (wie die von dir gezeigten) geglättet werden.

            Gruß,
            Hendrik
            Angehängte Dateien

            Kommentar


              #7
              Gehen wir mal davon aus dass folgender Zeitlicher Verlauf in 10 Minuten besteht, ich übertreibe mal ein wenig und wähle den Zeitraum so groß damit man sieht was ich meine:

              Grundlast 200W
              1.-3. Minute läuft der Wasserkocher mit 2000W
              2.-4. Minute läuft im Geschirrspüler die Heizung mit 2000W
              5.-7. Minute passiert nichts
              8.-10. Minute geht man durch Haus Beleuchtung 200W

              Was soll denn da für ein Mittel rauskommen ? Was sagt uns das über die aktuelle Leistung? Für mich kommt da nur Murks raus.

              Minute - Leistung:
              1 - 2200
              2 - 4200
              3 - 4200
              4 - 2200
              5 - 200
              6 - 200
              7 - 200
              8 - 400
              9 - 400
              10 - 400

              Sofern ich mich nicht vertippt habe:
              Mittelwert 1-10: 1420W
              Mittelwert 1-5: 2272W
              Mittelwert 5-6: 200W
              Mittelwert 4-5: 1200W

              Also das ist nunmal so - besorg Dir nen eHZ den man auslesen kann und der die Leistung ausgibt. Für Zählerstände funktioniert das mit den Impulsen hinreichend genau, für eine Leistungsmessung wird das (so einfach) nix aussagekräftiges. Selbst ich lese ja nur die Leistung zu exakt einer Sekunde ab, in der nächsten kann schon der Geschirrspüler laufen ...
              Umgezogen? Ja! ... Fertig? Nein!
              Baustelle 2.0 !

              Kommentar


                #8
                Hallo JuMi,

                Zitat von JuMi2006 Beitrag anzeigen
                Sofern ich mich nicht vertippt habe:
                Mittelwert 1-10: 1420W
                Mittelwert 1-5: 2272W
                Mittelwert 5-6: 200W
                Mittelwert 4-5: 1200W

                Also das ist nunmal so - besorg Dir nen eHZ den man auslesen kann und der die Leistung ausgibt.
                Da haben wir wohl unterschiedliche Ansprüche. Für mich wäre o.g. Ergebnis ok.

                Momentan habe ich aber trotz konstantem Verbrauch (Nacht) zwei unterschiedliche Durchschnittswerte über 1 bzw. 10 min. Siehe Anhang.
                Da ist irgendwo der Wurm drin in der Implementierung -nicht in den vorhandenen Daten.

                Ich habe jetzt mal dies implementiert:
                Code:
                     [[[Counter_U]]]
                        type=num
                        eval= sh.Allgemein.Stromzaehler.Counter()+65535*sh.Allgemein.Stromzaehler.Faktor()
                        eval_trigger= Allgemein.Stromzaehler.Counter | Allgemein.Stromzaehler.Faktor
                        sqlite=yes
                    [[[Momentanleistung_1min_c]]]
                        type = num
                        sqlite = yes
                        eval = (sh.Allgemein.Stromzaehler.Counter_U()- sh.Allgemein.Stromzaehler.Counter_U.db('min', '1i'))*60.0*1000.0/800
                        eval_trigger=Allgemein.Stromzaehler.Counter_U
                    [[[Momentanleistung_10min_c]]]
                        type = num
                        sqlite = yes
                        eval = (sh.Allgemein.Stromzaehler.Counter_U()- sh.Allgemein.Stromzaehler.Counter_U.db('min', '10i'))*60.0*1000.0/800/10
                        eval_trigger=Allgemein.Stromzaehler.Counter_U
                Das sollte numerisch unproblematischer sein.

                Gruß,
                Hendrik
                Angehängte Dateien

                Kommentar


                  #9
                  Hallo,

                  ich denke, ich habe jetzt einen Hinweis auf das Problem:
                  Code:
                  sh.Allgemein.Stromzaehler.Counter_U()- sh.Allgemein.Stromzaehler.Counter_U.db('max', '1i')
                  13.0
                  Sollte dies nicht immer 0 ergeben?
                  Die DB scheint nicht bei jedem Update des Item geschrieben zu werden, oder?

                  Code:
                  >>> sh.Allgemein.Stromzaehler.Counter_U.db('max', '1i')
                  476650.0
                  >>> sh.Allgemein.Stromzaehler.Counter_U()
                  476655.0
                  Gruß,
                  Hendrik

                  Kommentar


                    #10
                    Hi Hendrik,

                    welche Version setzt Du denn ein?
                    Ist die aktuell? Hast Du das mit drinnen: https://knx-user-forum.de/451312-post15.html

                    Bis bald

                    Marcus

                    Kommentar


                      #11
                      Hallo,

                      ich habe jetzt aktualisiert. Ist deutlich besser.
                      Bei meinem Test
                      Code:
                      sh.Allgemein.Stromzaehler.Counter_U()- [URL="http://redaktion.knx-user-forum.de/lexikon/sh/"]sh[/URL].Allgemein.Stromzaehler.Counter_U.db('max', '1i')
                      Bekomme ich viel seltener etwas ungleich null.

                      Ich werde jetzt mal beobachten, welchen Einfluss das auf die Werte hat.

                      Gruß und danke,
                      Hendrik

                      Kommentar


                        #12
                        Hallo,

                        ich denke, es gibt da noch ein Problem und ich denke, ich habe es ein Stück weiter eingrenzen können.
                        Was mit der neuen Version des SQlite-Plugin besser geworden ist, ist
                        Code:
                        sh.Allgemein.Stromzaehler.Counter_U.db('max', '1i')-sh.Allgemein.Stromzaehler.Counter_U()
                        ergibt (fast) immer 0.

                        Aber:
                        Wenn ich den Wert von
                        Code:
                         sh.Allgemein.Stromzaehler.Counter_U.db('min', '1i')
                        mit dem smarthome.log vergleiche, so gibt es einen zeitlichen Versatz. Das liegt daran, dass der min Wert der DB nur jede Minute gespeichert wird.

                        Im Anhang finden sich zwei Dateien. Ein Bild und die zugehörige Excel-Datei.
                        counter_log: Wert aus smarthome.log
                        db min 1i: Counter_U.db('min', '1i')
                        counter: Counter_U()
                        db max 1i: Counter_U.db('max', '1i')


                        Man sieht, dass counter immer gleich db max 1i ist.

                        db min 1i habe ich auch über eine x-achse die um 1 min versetzt ist geplottet. Somit sollte die Linie auch auf der anderen (counter) liegen. Tut sie aber nicht, da sie nur minütlich aktualisiert wird.

                        Ist das so gewollt?

                        Gruß,
                        Hendrik
                        Angehängte Dateien

                        Kommentar


                          #13
                          Hallo Hendrik,

                          ja, ist doch auch richtig. Du fragst nach dem kleinsten Wert der letzten Minute.

                          Bis bald

                          Marcus

                          Kommentar


                            #14
                            Hallo Marcus,

                            das ist eine Frage der Definition, denke ich.
                            Gemeint hatte ich den kleinsten Wert der letzten 60s. Ich bekomme um 14:00:59 zwar den kleinsten Wert zwischen 14:00:00 und jetzt -wie gewünscht. Aber um 14:00:01 und jetzt bekomme ich auch den kleinsten Wert zwischen 14:00:00 und 14:00:01, nicht aber den kleinsten Wert zwischen 13:59:01 und 14:00:01.

                            Das muss man eben wissen. Meinst du nicht, das wäre etwas für die Dokumentation?

                            Für meinen Anwendungsfall heißt das, dass ich die Datenbankabfrage so nicht nutzen kann, da bei

                            Code:
                            sh.Allgemein.Stromzaehler.Counter_U.db('min', '1i')- sh.Allgemein.Stromzaehler.Counter_U()
                            durchaus auch nur die Differenz der letzten Sekunde (obiges Beispiel) herauskommen kann, ich aber durch 60 teile.

                            Somit ist das Problem klar.

                            Ich frage mich aber, wie man das umschiffen kann Ich müsste ja die zeitliche Differenz der Einträge ermitteln. Das geht aber m.W. bei einem Datenbankeintrag nicht, oder?

                            Eine Alternative wäre
                            Code:
                            sh.Allgemein.Stromzaehler.Counter_U.db('min', '2i', '1i')-sh.Allgemein.Stromzaehler.Counter_U.db('max',  '2i', '1i')
                            Darüber hätte ich immer 60 s, allerdings immer 60s verspätet. Das wäre zu verkraften. Es gibt ja auch noch den Frequenzzähler.

                            Gruß,
                            Hendrik

                            Kommentar


                              #15
                              Hallo Hendrik,

                              an welcher Stelle in Deinem Excel-Sheet steht denn was falsches drin?
                              Was man hier auch noch beachten sollte, ist die zeitliche Auflösung. Du betrachtest in dem Sheet und hier nur Sekunden. Die DB ist aber feiner.
                              Das steht dann im Debug-Log.
                              Evtl. hilft es Dir auch statt 1i 1.1i, dann betrachtest Du einen etwas größeren Zeitraum.

                              Bis bald

                              Marcus

                              Kommentar

                              Lädt...
                              X