in reply to How to Determine Stable Y-Values... or Detect an Edge..?
I think a fairly straight-forward (modified) moving averages algorithm might suit your needs. The modification is to round the moving average to the nearest transition level. For example, if your transition levels are every 30 units as somewhat suggested by your description, (but not so much by the graphs), then you calculate the average for the last N values and then round that to the nearest transition level.
This code demonstrates the idea (using simulated data):
#! perl -slw use strict; use GD::Graph::lines; use GD::Graph::colour qw(:colours :lists :files :convert); use Data::Dump qw[ pp ]; use List::Util qw[ sum ]; our $MOVES ||= 4; our $SRAND ||= 1; srand $SRAND; ## Allow consistancy between runs for testing my $y = 30 * int rand 6; ## A base level for the random data my @data = map[], 1..4; my @moving; ## to hold the last $MOVING values for averaging ## Every 3 minutes throughout a day for my $x ( 0 .. (24 * 20 -1 ) ) { ## Generate Y values varies randomly around the current transition + level ## (which varies randomly see below) my $actualY = $y + -30 + int( rand 60 ); push @{ $data[ 0 ] }, $x / 20; ## X values in decimal hours push @{ $data[ 1 ] }, $y; ## display the random baseline in red push @{ $data[ 2 ] }, $actualY; ## The actual values in green ## Store the LAST $MOVES values push @moving, $actualY; shift @moving if $#moving >= $MOVES ; ## Calculate the moving average my $ave = sum( @moving ) / $MOVES; ## and round it to the nearest transition level $ave = 30 * ( int( ( $ave + 15 ) / 30 ) ); push @{ $data[ 3 ] }, $ave; ## display it in blue ## Make a random change to the base level 20% of the time next if rand > 0.2; $y = ( int( $y / 30 ) + ( -1 + int rand 3 ) ) * 30; $y = 30 if $y < 30; $y = 150 if $y > 150; } #pp \@data; <>; my $file = '789655.png'; my $graph = GD::Graph::lines->new(3000, 768); $graph->set( 'bgclr' => 'white', 'transparent' => 0, 'interlaced' => 1, title => 'Some simple graph', x_label => 'X Label', x_max_value => 24, x_min_value => 0, x_tick_number => 24, y_label => 'Y label', y_max_value => 180, y_min_value => 0, y_tick_number => 12, y_label_skip => 2, ) or die $graph->error; my $gd = $graph->plot(\@data) or die $graph->error; open IMG, '>', $file or die $!; binmode IMG; print IMG $gd->png; close IMG; system $file; ## Load the graph into the local default image viewer __END__ Usage: 789655.pl -MOVES=5 ##(less than 3 or > 10 not good )
When you run this, you'll see a different graph to me (different PRNG), but you should see a green line hopping wildly either side of a step-wise varying red line. These are the simulated data and actual random transition levels respectively.
The blue line--which should be tracking the red line fairly closely (though with lag)--is the rounded moving average calculated from the green data without reference to the red.
The higher you set -MOVES, the less likely you are to detect false edges, but the greater the lag before you detect them. 4 to 8 seems to work well depending upon your priorities. If you are doing this statically--ie. when you have all the data to hand, you can easily correct for the lag by a simple -X offset. If you are doing it in real time as the data is gathered, the lag could be a problem depending upon your responsiveness requirements.
There are some other interesting variations upon the above that might be applicable depending on the nature of the data and the use of the calculated values, but describing them all would be pointless. Maybe you can share that information with us?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: How to Determine Stable Y-Values... or Detect an Edge..?
by ozboomer (Friar) on Aug 21, 2009 at 06:07 UTC | |
by BrowserUk (Patriarch) on Aug 21, 2009 at 12:25 UTC | |
by ozboomer (Friar) on Aug 24, 2009 at 00:24 UTC |