FHEM Forum

FHEM => Codeschnipsel => Thema gestartet von: Rampler am 28 August 2016, 15:45:07

Titel: Moving Average Probleme
Beitrag von: Rampler am 28 August 2016, 15:45:07
Hallo zusammen,
ich verwende die im Wiki
http://www.fhemwiki.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen (http://www.fhemwiki.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen)
beschriebene Moving Average Routine in meiner myutils.
Siehe hier:
###############################################################################
#
#  Moving average
#
#  Aufruf: movingAverage(devicename,readingname,zeitspanne in s)
#
###############################################################################

sub movingAverage($$$){
   my ($name,$reading,$avtime) = @_;
   my $hash = $defs{$name};
   my @new = my ($val,$time) = ($hash->{READINGS}{$reading}{VAL},$hash->{READINGS}{$reading}{TIME});
   my ($cyear, $cmonth, $cday, $chour, $cmin, $csec) = $time =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/;
   my $ctime = $csec+60*$cmin+3600*$chour;
   my $num;
   my $arr;
   #-- initialize if requested
   if( ($avtime eq "-1") ){
     $hash->{READINGS}{$reading}{"history"}=undef;
   }
   #-- test for existence
   if( !$hash->{READINGS}{$reading}{"history"}){
      #Log 1,"ARRAY CREATED";
      push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
      $num = 1;
      $arr=\@{$hash->{READINGS}{$reading}{"history"}};
   } else {
      $num = int(@{$hash->{READINGS}{$reading}{"history"}});
      $arr=\@{$hash->{READINGS}{$reading}{"history"}};
      my $starttime = $arr->[0][1];
      my ($syear, $smonth, $sday, $shour, $smin, $ssec) = $starttime =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/;
      my $stime = $ssec+60*$smin+3600*$shour;
      #-- correct for daybreak
      $stime-=86400
        if( $stime > $ctime);
      if( ($num < 100)&&( ($ctime-$stime)<$avtime) ){
        #Log 1,"ARRAY has $num elements, adding another one";
        push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
      }else{
        shift(@{$hash->{READINGS}{$reading}{"history"}});
        push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
      }
    }
    #-- output and average
    my $average = 0;
    for(my $i=0;$i<$num;$i++){
      $average+=$arr->[$i][0];
      Log 4,"[$name moving average] Value = ".$arr->[$i][0]." Time = ".$arr->[$i][1];
    }
    $average=sprintf( "%5.2f", $average/$num);
    #--average
    Log 4,"[$name moving average] calculated over $num values is $average"; 
    return $average;
}


Habe den Intervall für meinen Sonnensensor auf 1800 Sekunden gesetzt, das ergibt tagsüber 13 Intervalle. Am Folgetag, steht der Intervall dann allerdings auf 26, weil die Meldungen vom Sonnensensor zwischenzeitlich wahrscheinlich (logge leider nicht mit) erhöht waren.
Die Zeitspanne, entspricht jetzt nicht mehr 1800 Sekunden, sondern 1 Stunde.

Hier mal ein Auszug aus dem Log, bei dem der Intervall noch passt:

2016.08.27 07:35:17 3: [Sonnensensor moving average] calculated over 13 values is 2589.695
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2073.61 Time = 2016-08-27 07:07:37
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2185.48 Time = 2016-08-27 07:10:10
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2288.14 Time = 2016-08-27 07:12:29
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2378.76 Time = 2016-08-27 07:14:33
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2498.31 Time = 2016-08-27 07:17:27
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2606.73 Time = 2016-08-27 07:20:07
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2703.5 Time = 2016-08-27 07:22:32
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2788.87 Time = 2016-08-27 07:24:42
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2905.87 Time = 2016-08-27 07:27:43
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3006.85 Time = 2016-08-27 07:30:28
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3100.55 Time = 2016-08-27 07:33:00
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3185.54 Time = 2016-08-27 07:35:17
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3257.74 Time = 2016-08-27 07:37:19
2016.08.27 07:37:19 3: [Sonnensensor moving average] calculated over 13 values is 2690.765


Und jetzt (einen Tag später):

2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 61524.32 Time = 2016-08-28 09:34:46
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 63085.79 Time = 2016-08-28 09:37:39
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 64410.4 Time = 2016-08-28 09:40:18
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 65594.65 Time = 2016-08-28 09:42:42
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 66831.54 Time = 2016-08-28 09:44:51
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 67555.26 Time = 2016-08-28 09:47:51
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 69200.06 Time = 2016-08-28 09:50:35
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 70476.42 Time = 2016-08-28 09:53:06
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 71375.58 Time = 2016-08-28 09:55:22
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 72257.19 Time = 2016-08-28 09:57:23
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 73073.01 Time = 2016-08-28 10:00:14
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 74415.17 Time = 2016-08-28 10:02:51
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 74116.91 Time = 2016-08-28 10:05:13
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 75138.88 Time = 2016-08-28 10:07:21
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 75840.66 Time = 2016-08-28 10:10:18
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 77042.46 Time = 2016-08-28 10:13:01
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 78397.78 Time = 2016-08-28 10:15:30
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 79178.51 Time = 2016-08-28 10:17:44
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 80801.38 Time = 2016-08-28 10:20:48
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 81985.63 Time = 2016-08-28 10:23:37
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 82950.59 Time = 2016-08-28 10:26:12
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 83310.25 Time = 2016-08-28 10:28:32
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 84025.19 Time = 2016-08-28 10:30:38
2016.08.28 10:30:38 3: [Sonnensensor moving average] calculated over 23 values is 73590.77



Meines erachtens ist das Problem, dass die Variable $num nur hochgezählt wird, aber nie runter, was natürlich suboptimal bei Sensoren ist, deren Intervallfrequenz sich verändert.
Ist irgendwie täuschend, wenn man beim dazu gehörenden UserReading:
brightness.av:B.* {movingAverage("Sonnensensor","brightness",1800)}

eine halbe Stunde angibt..

Wäre toll, wenn das auch noch funktioniert...

Viele Grüße
   Klaus
Titel: Antw:Moving Average Probleme
Beitrag von: erwin am 01 September 2016, 17:15:25
hi Klaus,
das Problem hatte ich auch!
ich hab einiges geändert, sollte funktionieren, willst du versuchen, bevor ich das Wiki update?

###############################################################################
#
#  Moving average
#
#  Aufruf: movingAverage(devicename,readingname,zeitspanne in s)
#
# MH changes:
#    timestamp handling, delete old entries, delete entries if # >= 24, Log3, ....
###############################################################################

sub movingAverage($$$){
   my ($name,$reading,$avtime) = @_;
   my $hash = $defs{$name};
   my $val =  $hash->{READINGS}{$reading}{VAL};
   my $time = $hash->{READINGS}{$reading}{TIME};
   my $ctime = time_str2num($time);
   Log3 $name, 4,"[movingAverage $name] time= $time $ctime reading= $reading value= $val";
   my @new = ($val,$ctime);
   my $num;
   my $arr;
   #-- initialize if requested
   if( ($avtime eq "-1") ){
     $hash->{READINGS}{$reading}{"history"}=undef;
   }
   #-- test for existence
   if( !$hash->{READINGS}{$reading}{"history"}){
      Log3 $name, 3,"[movingAverage $name] ARRAY CREATED";
      push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
      $num = 1;
      $arr=\@{$hash->{READINGS}{$reading}{"history"}};
   } else {
      $num = int(@{$hash->{READINGS}{$reading}{"history"}});
      $arr=\@{$hash->{READINGS}{$reading}{"history"}};
      my $stime = $arr->[0][1];
      while( ($num >= 24) || ((($ctime-$stime) > $avtime) && $num > 1) ){ #delete "old" entries, or more then 24 entries
        Log3 $name, 5,"[movingaverage $name] ARRAY has $num elements, deleting one w. Timestamp=" .  movingAverageTS($stime);
        shift(@{$hash->{READINGS}{$reading}{"history"}});
        $num--; # correct # of entries
        $arr=\@{$hash->{READINGS}{$reading}{"history"}};
        $stime = $arr->[0][1];
      }
      push(@{$hash->{READINGS}{$reading}{"history"}},\@new); # always push the last one
      $num++; # correct # of entries
      Log3 $name, 4,"[movingaverage $name] ARRAY has $num elements, added one";
    }
    #-- output and average
    my $average = 0;
    for(my $i=0;$i<$num;$i++){
      $average+=$arr->[$i][0];
      Log3 $name, 5,"[movingaverage $name] Value= ".$arr->[$i][0]." Time= " . movingAverageTS($arr->[$i][1]);
    }
    $average=sprintf( "%5.3f", $average/$num);
    #--average
    Log3 $name, 4,"[movingaverage $name] calculated over $num values is $average";
    return $average;
}

#return timestring (HH:MM:SS format) from given unix timestamp
sub movingAverageTS($) {
    my ($utime) = @_;
    my @t = localtime($utime);
    my $mytimestr = sprintf("%02d:%02d:%02d", $t[2], $t[1], $t[0]);
    return $mytimestr;
}

1;

call syntax ist gleichgeblieben,
Logging: im betreffenden device verbose=5 setzen
have fun
erwin

update: fixed a bug when deleting array entries, keep minimum 1 entry....
Titel: Antw:Moving Average Probleme
Beitrag von: Rampler am 23 September 2016, 19:06:22
Hallo Erwin,

sorry habe den Thread irgendwie verdrängt...
Bin grad am Testen...
Bis jetzt Daumen hoch, werde berichten ..

Viele Grüße
  Klaus

Edit1: Bis jetzt super, habe das Log3 angepasst:

#  Logging: Steuerung über Verbose vom Device
#           1 - calculated over xx values is xxx.xx
#               ARRAY CREATED
#           2 - ARRAY has 11 elements, deleting one w. Timestamp=hh:mm:ss
#               ARRAY has 11 elements, added one
#           3 - Value= xxx.xx Time= hh:mm:ss
#           4 - time= year-month-day hh:mm:ss unixtime reading= reading value= xxx.xx

Habe bei meinem Sonnensensor standartmäßig Verbose auf 0
Die Steuerung über Verbose ist eine coole Sache !
Titel: Antw:Moving Average Probleme
Beitrag von: Rampler am 23 September 2016, 20:01:42
... bin begeistert ...
2016.09.23 19:44:04 1: [movingaverage Sonnensensor] calculated over 11 values is 47.16
2016.09.23 19:46:50 1: [movingaverage Sonnensensor] calculated over 11 values is 30.64
2016.09.23 19:49:21 1: [movingaverage Sonnensensor] calculated over 12 values is 28.14
2016.09.23 19:51:38 1: [movingaverage Sonnensensor] calculated over 12 values is 18.98
2016.09.23 19:53:41 1: [movingaverage Sonnensensor] calculated over 13 values is 17.54
2016.09.23 19:56:33 1: [movingaverage Sonnensensor] calculated over 12 values is  7.90

Und es funktioniert ..
bin mal auf morgen früh gespannt ..

DANKE
Titel: Antw:Moving Average Probleme
Beitrag von: Rampler am 24 September 2016, 07:15:20
Hallo Erwin,

über Nacht sieht es so aus ..
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 4.94 Time= 19:38:54
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 3.36 Time= 19:41:04
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 1.95 Time= 19:44:04
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 1.17 Time= 19:46:50
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.63 Time= 19:49:21
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.38 Time= 19:51:38
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.26 Time= 19:53:41
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.14 Time= 19:56:33
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.07 Time= 19:59:11
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.04 Time= 20:01:34
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.01 Time= 20:03:43
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0 Time= 20:06:41
2016.09.23 20:06:41 1: [movingaverage Sonnensensor] calculated over 12 values is  1.08
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 12 elements, deleting one w. Timestamp=19:38:54
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 11 elements, deleting one w. Timestamp=19:41:04
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 10 elements, deleting one w. Timestamp=19:44:04
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 9 elements, deleting one w. Timestamp=19:46:50
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 8 elements, deleting one w. Timestamp=19:49:21
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 7 elements, deleting one w. Timestamp=19:51:38
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 6 elements, deleting one w. Timestamp=19:53:41
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 5 elements, deleting one w. Timestamp=19:56:33
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 4 elements, deleting one w. Timestamp=19:59:11
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 3 elements, deleting one w. Timestamp=20:01:34
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 2 elements, deleting one w. Timestamp=20:03:43
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 2 elements, added one
2016.09.24 06:20:22 3: [movingaverage Sonnensensor] Value= 0 Time= 20:06:41
2016.09.24 06:20:22 3: [movingaverage Sonnensensor] Value= 0.03 Time= 06:20:22
2016.09.24 06:20:22 1: [movingaverage Sonnensensor] calculated over 2 values is  0.01
2016.09.24 06:23:16 2: [movingaverage Sonnensensor] ARRAY has 2 elements, deleting one w. Timestamp=20:06:41
2016.09.24 06:23:16 2: [movingaverage Sonnensensor] ARRAY has 2 elements, added one
2016.09.24 06:23:16 3: [movingaverage Sonnensensor] Value= 0.03 Time= 06:20:22
2016.09.24 06:23:16 3: [movingaverage Sonnensensor] Value= 0.05 Time= 06:23:16


Würde sagen das passt, obwohl der Sensor in der Nacht immer wieder 0 meldet ...
Sieht so aus, als ob die 0 nicht berücksichtigt wird ...
Viele Grüße
  Klaus

EDIT: Problem war event-on-change state, habe mal auf event-on-update state geändert, so konnte er keine events melden.
Von mir ein dreimal JA !!