Gleitende Durchschnitte mit userReadings

Begonnen von Prof. Dr. Peter Henning, 27 Juli 2015, 17:43:59

Vorheriges Thema - Nächstes Thema

Prof. Dr. Peter Henning

Hallo Liste,

ich war mit dem Vorschlag http://www.fhemwiki.de/wiki/Relative_Mittelwerte_berechnen_und_loggen
nicht so ganz zufrieden, weil die Routine immer erst die Logdateien liest.

(Edit: Ich meinte natürlich NICHT das Modul "average" - das hat eine ganz andere Funktionalität)

Also habe ich mal Folgendes probiert

1. gegeben ein (1-Wire) Device A.OWB mit einem Reading "pressure".
2. definiert das Attribute userReadings als
pressure.4:pressure {ReadingsVal("A.OWB","pressure.3",0)},pressure.3:pressure {ReadingsVal("A.OWB","pressure.2",0)},pressure.2:pressure {ReadingsVal("A.OWB","pressure.1",0)},pressure.1:pressure {ReadingsVal("A.OWB","pressure",0)}

Zentrale Idee dabei: Das reading "pressure" wird bei jedem Update durchgereicht: Zuerst in pressure.1, beim nächsten Schritt in pressure.2 etc. Dann hat man die letzten 4 Readings von pressure im System, und kann ihren Mittelwert problemlos als weiteres userReading anzeigen lassen.

War aber Pustekuchen, pressure.3 enthielt immer dasselbe wie pressure.2. Komisch, denk ich mir, machen wir mal einen weiteren Test:

pressure.4:pressure {ReadingsVal("A.OWB","pressure.3",0)},pressure.3:pressure {ReadingsVal("A.OWB","pressure.2a",0)},pressure.2a:pressure {ReadingsVal("A.OWB","pressure.1",0)},pressure.2:pressure {ReadingsVal("A.OWB","pressure.1",0)},pressure.1:pressure {ReadingsVal("A.OWB","pressure",0)}

Et voila, funktioniert prima: pressure.4, pressure.3, pressure.2 und pressure.1 enthalten die letzten 4 Readings von pressure. Aber, brat mir einer einen Storch, pressure.2a hat immer denselben Wert wie pressure.2.

Außer vagen Vermutungen habe ich bisher dafür keine Erklärung.

LG

pah

justme1968

die einzelnen user readings werden nach dem parsen des attributes in einem hash abgelegt. das hat zur folge das die reihenfolge der abarbeitung undefiniert ist.

gruss
  andre

ps: wo siehst du das average auf logfites zugreift? beim überfliegen des moduls habe ich nichts in der art gesehen.

pps: vielleicht hilft dir auch event-aggregator
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Prof. Dr. Peter Henning

Äh,  :-[, natürlich nicht das Modul "average" - das hat eine ganz andere Funktionalität. Sondern den Codeschnipsel hier http://www.fhemwiki.de/wiki/Relative_Mittelwerte_berechnen_und_loggen.

(Frag mich, warum ich das Modul genannt habe ? Beginnender Zerfall, allerhöchst urlaubsreif...)

Die Reihenfolge ist übrigens nicht undefiniert, sondern auch eine Hashtabelle folgt ihren klaren Gesetzmäßigkeiten. Und nach denen sollte das eigentlich anders laufen, nämlich tatsächlich von rechts weil das in der Folge eingetragen wird.

LG

pah

My-FHEM

#3
Ich berechne gleitende Durchschnitte in den Userreadings folgendermaßen:

wS_gld (Windgeschwindigkeit, n Abtastwerte)


wS_gld {ReadingsVal("$name","wS_gld",0) * (n-1) + ReadingsVal("$name","windSpeed",0)) / n}



Gruß

justme1968

naturlich gibt es gesetzmäßigkeiten. die sind aber implementierungsabhängig. ohne die jeweilige implementierung genau zu kennen ist die reihe folge  unbestimmt.

warum sollte die reihenfolge von der reihenfolge des eintragens abhängen?

eine gute hash funktion wird auch aufsteigend nummerierte werte nicht in das gleiche bucket einsortieren sonder möglichst gleichmäßig verteilen.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Prof. Dr. Peter Henning

Probiers aus - bei mir wird das wirklich prima durchgereicht.

LG

pah

herrmannj

Zitat von: My-FHEM am 27 Juli 2015, 18:43:54
Ich berechne gleitende Durchschnitte in den Userreadings folgendermaßen:

wS_gld (Windgeschwindigkeit, n Abtastwerte)


wS_gld {ReadingsVal("$name","wS_gld",0) * (n-1) + ReadingsVal("$name","windSpeed",0)) / n}



Gruß

Hi,

so in etwa mach ichs auch. Funktioniert Top.

(Ich habs in der 99er liegen und rechne noch die Zeit mit ein um auszugleichen das eine Sensornachricht verloren geht - annemometer ist an der Grenze des Empfangsbereiches ...)

vg
joerg

Prof. Dr. Peter Henning

Mag ja sein, dass irgendjemand das so rechnet - aber das ist kein gleitender Durchschnitt, sondern höchstens gleitender Unsinn.

In dieser Berechnung werden nämlich _alle_ vorhergehenden  Messwerte berücksichtigt, mit abnehmenden Gewichten für die früheren Werte bis auf den ersten. Dabei hängt es sehr stark vom ERSTEN Iterationswert ab, wie stark dieser eingeht - denn die m. Potenz von (n-1)/n fällt für große n nur sehr langsam ab.

Per se handelt es sich bei dieser Berechnung also nicht um eine Glättung mit definierten spektralen Eigenschaften.

LG

pah

justme1968

ZitatProbiers aus - bei mir wird das wirklich prima durchgereicht.
das ändert nichts daran das es mehr oder weniger zufall ist und sich abhängig von der perl version, den vorher oder danach stattfinden einfüge und lösch operationen auf dem gleichen hash und noch einigen anderen dingen ändern kann. unter umständen schon beim nächsten fhem start.

siehe z.b. jede vernünftige einführung in hash datenstrukturen und im perl fall besonders die perl doku: http://perldoc.perl.org/functions/keys.html:
ZitatHash entries are returned in an apparently random order. The actual random order is specific to a given hash; the exact same series of operations on two hashes may result in a different order for each hash. ...  Aside from the guarantees provided here the exact details of Perl's hash algorithm and the hash traversal order are subject to change in any release of Perl. ...

die einzig korrekte methode ist in *einem* notify oder user reading den neuen mittelwert zu berechnen und die historie selber zu verwalten. das könnte dann der einfachheit halber auch ein einziges reding sein das per split in ein array deserialisiert wird dann mit pop/unshift oder pop/shift manipuliert und zur ablage wieder in einen string serialisiert wird.

userReadings hierfür zu verwenden ist um es mit deinen worten zu sagen unsinn.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

herrmannj

ZitatMag ja sein, dass irgendjemand das so rechnet - aber das ist kein gleitender Durchschnitt, sondern höchstens gleitender Unsinn.
Charmant wie immer ;)

Grundsätzlich hast Du schon recht, praktisch ergibt diese Zahlenreihe: 60,50,70,20 gleitend 50 und gewichtet 50,47.

Bei stark abweichendem Startwert ist die Differenz beider Methoden initial größer, nähert sich allerdings abhängig von Laufzeit und Anzahl der Samples schnell sehr stark an.

Die Methode von my-fhem ist also pragmatisch und gut, ein (Dein) echter gleitender Durchschnitt ist in einigen Situationen genauer :)

vg
joerg

Prof. Dr. Peter Henning

@herrmannj:

Na, da widerspreche ich aber - es geht nicht darum, die Zahlenwerte irgendwie zu glätten. Sondern darum, Störsignale auf bestimmten Zeitskalen auszufiltern. Und das macht man nicht mit diskreten Laplacetransformationen. Beispielsweise kann man sehr einfach zeigen, dass eine "Annäherung" dieser Transformation an den gleitenden Mittelwert nur unter sehr speziellen Annahmen an den Signalverlauf stattfindet. Das Attribut "gut" kann ich dafür nicht vergeben.

@justme1968:

Prinzipiell richtig, dass es eines ordentlichen Moduls bedarf. Allerdings widerspreche ich auch hier - denn es geht gar nicht um die Speicherreihenfolge im Hash. Sondern um das, was bei Durchlaufen der keys aus dem Hash wieder herauskommt. Bei den wenigen Einträgen, die ich hier habe, gibt es mit hoher Wahrscheinlichkeit beim Anlegen keine Kollisionen, deshalb wird die ordinale Struktur mit eben dieser Wahrscheinlichkeit erhalten. Die "Zufälligkeit", die in der perldoc behauptet wird, kommt erst bei Kollisionen ins Spiel - denn dann hängt die ordinale Reihung von der Reihenfolge des Einspeicherns ab. Quelle: Skriptum zu meiner eigenen Vorlesung "Datenorganisation" aus dem Jahr 1999.

LG

pah

justme1968

der vorschlag mit dem array lässt sich problemlos in ein user reading stecken oder ein notify. das braucht kein eigenes modul.

sie speicherreihenfolge und die reihenfolge in der die keys durchlaufen werden sind für diese betrachtung identisch.

es kommt auch nicht auf die anzahl der ihm hash gespeicherten werte an. die zufälligkeit wird auch nicht nur behauptet sondern sie ist tatsächlich da, nicht nur bei kollisionen relevant und auch nicht von der reihenfolge der einfüge operationen abhängig.

sogar das folgende einfache beispiel liefert bei jedem start eine zufällige reihenfolge. das gilt auch für nur zwei elemente im hash.
use strict;
use warnings;

use Data::Dumper;

my %hash = ( 1 => 1, 2 => 2, 3 => 3 );

print Dumper keys %hash;

je nach genauer konstellation bei jedem aufruf, manchmal nur bei jedem 5ten oder 10ten.

d.h. selbst das argument das der userReadings hash nur ein mal gefüllt und danach nur noch ausgelesen wird greift nicht weil die initiale reihenfolge schon unbestimmt ist und das ganze hin und her schieben von der korrekten reihenfolge der keys abhängt. sonst überschreibst du dir zum falschen zeitpunkt einen später noch gebrauchten wert.

wann und wo es kollisionen gibt hängt nicht von der anzahl der werte ab sondern nur vom konkreten hash verfahren. ohne kenntnis der verfahrens lassen sich hier nur sehr beschränkt rückschlüsse ziehen.

es ist und bleibt unsinn das verhalten durch spielen mit den reading namen so hin zu drehen das es scheinbar stabil ist. die Anordnung der elemente im hash und die reihenfolge in der die keys durchlaufen werden ist für alle praktischen anwendungen als zufällig anzusehen und ein schlechtes beispiel ist es alle mal. der nächste der es probiert fällt auf die nase und wunder sich.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Prof. Dr. Peter Henning

Nun gut, ein schlechtes Beispiel ist es (also, Newbies, bitte nicht nachmachen).

Aber die von Dir behauptete Akausalität zwischen verschiedenen Aufrufen gibt es nicht - die kann höchstens durch Data::Dumper erzeugt werden.

LG

pah

justme1968

ich weiss es ist schwer zuzugeben unrecht zu haben...

use strict;
use warnings;

my %hash = ( 1 => 1, 2 => 2 );

foreach my $k (keys %hash) {
  printf "$k ";
}
printf "\n";


Zitat[rojo:/tmp] andre% perl x.pl
2 1
[rojo:/tmp] andre% perl x.pl
2 1
[rojo:/tmp] andre% perl x.pl
1 2
[rojo:/tmp] andre% perl x.pl
2 1
[rojo:/tmp] andre% perl x.pl
1 2
und jetzt sag nicht es  liegt am foreach oder sogar am print.

Data::Dumper hat seiteneffekte aber dazu gehört nicht das ein hash, der nicht in direktem zusammen hang steht, sich ändert (das wäre nur ein grund mehr sich nicht auf die hash reihenfolge zu verlassen) und erst recht nicht das sich die reihenfolge einer liste ändert (die ist im gegensatz zum hash wirklich fest).

also zum wiederholen: die anordnung der elemente in einem perl hash und die reihenfolge in der die keys durchlaufen werden ist für alle praktischen anwendungen als zufällig anzusehen.

unter dem link oben ist übrigens auch zu lesen warum das so ist. da wird nicht nur einfach etwas behauptet. und von mir schon gar nicht.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Prof. Dr. Peter Henning

Nö, das ist gar nicht schwer: Für perl-Implementationen hast Du offenbar Recht

Wenn man ein und dieselbe Hashfunktion verwendet, ist das System immer deterministisch. Perl benutzt aber einen Seed für die Erzeugung des Hashes - und damit hat man keine tatsächlich keine Kontrolle mehr. Oder anders ausgedrückt: Jeder Aufruf von perl verwendet eine andere Hashfunktion.

Interessant dazu das hier: http://stackoverflow.com/questions/6685019/hash-randomization-in-perl-5

LG

pah