Mittelwert ohne Ausreißer

Hallo Gemeinde,

in meiner Zisterne herrscht wohl ein Wellenbad !

ich würde gerne meinen Füllstand der Zisterne etwas mitteln.

Ich dachte so an 5 Werte, wovon der niedrigste und der höchste ignoriert werden und aus den 3 mittleren Werten ein Durchschnitt errechnet wird.

Das ganze sollte endlos laufen, da alle 60 Sekunden ein neuer Wert vom Sensor kommt.

Ich steh gerade etwas auf dem Schlauch und weiß nicht genau, wie ich das Script anfangen soll ?
Könntet ihr mir einen Tritt verpassen, damit ich in die richtige Richtung laufe ? :slight_smile:

Liebe Grüße
Sascha

Zum einen aktiviere mal das Archiv. Hol dir dann vom Archiv die letzten fünf Werte (oder die, die du mitteln möchtest) heraus. Mit AC_GetLoggedValues und der richtigen Zeitspanne ( in deinem Fall die letzen 5-6 Minuten - time()-300 für fünf Minuten oder 360 für sechs Minuten) solltest die für dich richtige Anzahl herausbekommen. Retour bekommst du ein Array, dass du dann entsprechend deinen Wünschen zerlegen kannst. So oder so ähnlich wäre mein Ansatz.

ja das kenne ich auch, wenn ein Zulauf etwas tröpfelt, da reissen die Werte schon mal aus.
Bei mir ist es die Drainage. Ich habe schon mal manuell die Ausreisser im Archiv gelöscht :wink:

image

liegt dein Zulauf nicht unterhalb des Wasserspiegels ?

Danke für den Anstoß :slight_smile:
Das mit „AC_GetLoggedValues“ hört sich sehr gut an.
Mir ist zwar noch nicht ganz klar, wie ich dann den niedrigsten und den höchsten Wert löschen kann, aber ich fange erstmal mit dem einlesen der Daten an.

@Axel:
Es scheint die Sonne, die Zisternenpumpe ist Stromlos und der Wasserspiegel völlig glatt.
Das „Wellenbad“ ist nur auf der elektrischen Seite :slight_smile: Sorry, wenn ich mich da etwas umständlich ausgedrückt habe.

LG
Sascha

Servus

das hier wird dir helfen:
Gleitenden Mittelwert oder gleitenden Median berechnen - IP-Symcon 4.x/5.x/6.x / Skripte, PHP, SQL (Anleitungen) - IP-Symcon Community

schöne Grüße
Bernhard

sort the array (sort)
remove the first element (array_shift)
remove the last element (array_pop)
create the sum of the remaining array (array_sum)
divide the sum with the number of elements in the remaining array (count).
Code example:

sort($prices, SORT_NUMERIC);
array_shift($prices);
array_pop($prices);
$sum = array_sum($prices);
$average = $sum / count($prices);

Ich hab deine Antwort auf die Frage hier gefunden. Dort wird genau das gemacht, was du möchtest. Musst es eigentlich nur mehr abtippen :wink:
Wobei man sagen muss, dass diese Version NUR dann funktioniert wenn es GENAU einen Maximum- und EINEN Minimumwert gibt, der gelöscht werden soll. Wenn du da zwei Ausreisser in der Liste hast, dann funktioniert das natürlich nicht. Da musst du dann die Version von @bbernhard anwenden.
Wobei sich für mich da die Frage stellt, was definiert einen Ausreisser nach oben und nachunten. Nur weil etwas abweicht, heißt es noch nicht, dass es nicht richtig ist.

Danke für die ganzen Tips :slight_smile:
Ich werde mal beide Version ausprobieren.

@hfichtinger:
„Wobei sich für mich da die Frage stellt, was definiert einen Ausreisser nach oben und nachunten. Nur weil etwas abweicht, heißt es noch nicht, dass es nicht richtig ist.“

Definition Ausreißer:
Wenn bei strahlendem Sonnenschein plötzlich 1000Liter Wasser aus der Zisterne fehlen und in der nächsten Minute wieder da sind ^^

LG
Sascha

Soweit bin ich hier schonmal (das andere Script von bbernhard lief auf Anhieb)

<?php
$werte = AC_GetLoggedValues(35764,36743,time()-360,time(),0);


foreach($werte as $wert) {
    echo date("d.m.Y H:i:s", $wert['TimeStamp']) . " -> " . $wert['Value'] . PHP_EOL;
}

sort($werte, SORT_NUMERIC);
array_shift($werte);
array_pop($werte);
$sum = array_sum($werte);
$average = $sum / count($werte);

echo $average;

Das ganze gibt mir dann diese Ausgabe:

05.07.2021 22:18:07 → 20956
05.07.2021 22:17:07 → 20963
05.07.2021 22:16:07 → 20966
05.07.2021 22:15:07 → 20965
05.07.2021 22:13:07 → 20966
0

wie man sieht, wird die Variable „$average“ leider nur mit „0“ ausgegeben.-
Hier hatte ich mir den Durchschnittswert erhofft.

Sieht jemand den Fehler, den ich hier gemacht habe ?

LG
Sascha

Das Beispiel geht davon aus, dass du eine Array NUR mit den Zahlen hast.
Also z.B. definiert als $werte = array(20956, 20963, 20966, [...]);

Du hast aber das spezial Array vom Archive Control

$werte = array(
    array ('TimeStamp' => 12548975646, 'Value' => 20956),
    array ('TimeStamp' => 12548975668, 'Value' => 20987)
);

Du kannst jetzt in der Foreachschleife ein neues Array befüllen, z.B. mit $neueWerte[] = $wert['Value'] Und dann in dem u.s. Teil sort, array_shift, array_pop, array_sum, cont verwenden.

@tobiasr:
Das funktioniert jetzt hervorragend :slight_smile:
Danke für deine Erklärung.
@all:
Ich hätte nicht gedacht, heute noch soweit zu kommen!
Na gut, dank euch :slight_smile:
Jetzt bleibt nur noch eine Sache übrig:

Ich kenne den Wert für „Zisterne leer“ = 10670
und für „Zisterne voll“ = 21000

Das würde ich nun gerne als 0-100% in eine neue Variable speichern, wobei auch wenn der Wert mal größer als das Max oder kleiner als das Minimum wird, niemals mehr als 100 oder weniger als 0 geschrieben wird.

Also keine Zisterne mit 103% oder eine leere mit -2%.

Wie könnte ich das denn anstellen ?

Ganz liebe Grüße
Sascha

Wenn es eine lineare Kurve ist, dann könntest du es so machen
voll=21000-10670
aktuell=aktuell-10670
prozent=aktuell/voll*100
Und dann noch eventuell auf 100% setzen, wenn mehr als 100 und 0% wenn weniger als 0 herauskommt.
Bsp.:
prozent=(15000-10670)/(21000-10670)*100=41,92%

Super :slight_smile:
Das funktioniert schonmal einwandfrei !

Hier mal das ganze Script, wie es jetzt bei mir läuft:

<?php
$werte = AC_GetLoggedValues(35764,36743,time()-300,time(),0);

$voll = 20800;
$leer = 10670;
$prozent = 0;

$output = 45249;

foreach($werte as $wert) {
    $neueWerte[] = $wert['Value'];
    //echo date("d.m.Y H:i:s", $wert['TimeStamp']) . " -> " . $wert['Value'] . PHP_EOL;
}

sort($neueWerte, SORT_NUMERIC); // Array Sortieren
array_shift($neueWerte); // Erstes Element löschen
array_pop($neueWerte); // Letztes Element löschen
$sum = array_sum($neueWerte); // Array summieren
$average = $sum / count($neueWerte); // Durchschnitt erechnen

$prozent=((int)$average-$leer)/($voll-$leer)*100; // Umrechnung auf Prozent (0-100%)

if ($prozent > 100){ // Werte über 100% auf 100% reduzieren
    $prozent = 100;
}

if ($prozent < 0){ // Werte unter 0% auf 0% aufblasen
    $prozent = 0;
}

SetValueInteger($output,$prozent);

//echo (int)$average;
//print PHP_EOL;
//echo (int)$prozent;
//print "%";

mein Drainage kann ich mit dem Skript ebenfalls glätten, lasse nur die %Rechnung weg

1 „Gefällt mir“

ist zwar alter Beitrag:
ich habe meine Elektronik ausgetauscht bei gleichem Sensor, jetzt ist Ruhe.
Es werden nur noch Werte geschrieben, wenn sich wirklich was tut