0
\$\begingroup\$

Calculate if the value exceeds percentage <> numeric deadbands of the previous value.

The first function is for percentage. It detects if $value is $deadband% greater or less than $previous.

The second is for numeric difference. It detects if the difference between $value and $previous is greater than $deadband.

function percentage_deadband($value,$previous,$deadband)
{
    if($previous==0 || $value==0 || $previous == $value)
    {
        return false; //if previous or value is 0, we can't work. assume false.
    }
    $percentage = $value / $previous * 100;
    if($percentage > 100){
        return $percentage - $deadband > 100;//if percentage - deadband > 100, we know the deadband is exceeded
    }
    if($percentage < 100){
        return 100 - $percentage > $deadband;//if 100 - percentage is greater than deadband, we know the deadband is exceeded
    }
    return false;
}


function numeric_deadband($value,$previous,$deadband)
{
    if($previous==0 || $value==0 || $previous == $value)
    {
        return false;
    }
    if($previous > $value){
        return $previous - $deadband >= $value;
    }else{
        return $value - $previous >= $deadband;
    }
    return false;
}

Testing the functions

$numeric_deadband = 3;
$numeric_set = [
    0=>['value'=>77,'previous'=>80],//true
    1=>['value'=>78,'previous'=>77],//false
    2=>['value'=>81,'previous'=>78],//true
    3=>['value'=>81,'previous'=>81]//false
];
echo '<strong>numeric set:</strong><br/>';
foreach($numeric_set as $row)
{

    var_dump(numeric_deadband($row['value'],$row['previous'],$numeric_deadband));
    echo '<br/>';
}

echo '<br/>';

$percentage_deadband = 10;
$percentage_set = [
    0=>['value'=>27,'previous'=>39],//true
    1=>['value'=>39,'previous'=>40],//false
    2=>['value'=>41,'previous'=>28],//true
    3=>['value'=>28,'previous'=>31]//false
];
echo '<strong>percentage set:</strong><br/>';
foreach($percentage_set as $row)
{

    var_dump(percentage_deadband($row['value'],$row['previous'],$percentage_deadband));
    echo '<br/>';
}

They seem to work correctly with my small set of test data, but I am not so great with math. I'd love a second opinion.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Some comments would be nice, for example, in the first function you could specify that $n represents $value as a percentage of $previous. You could also remove the last if statement from the first function - you're returning false either way. You also might want to be more descriptive with your variable named $n - maybe try $percentChange \$\endgroup\$ – Brian Hannay Jul 13 '15 at 4:22
  • 1
    \$\begingroup\$ not really related to your question but you might want to use PHPUnit for testing in the future \$\endgroup\$ – Marcel Burkhard Jul 14 '15 at 11:32
2
\$\begingroup\$

I'm unclear about what is TRUE and what is FALSE (and how you interpret it).

Is it FALSE = when value is greater than previous by more than deadband?
    (i.e. value > previous + deadband is NOT OK)
    (i.e. value <= previous + deadband is OK)
That's how I did it below, but if you want the opposite, change the "<" sign. 

I would change the two functions in one, and give an extra argument (true for numeric, false for percentage):

    function check_deadband($value,$previous,$deadband,$check_numeric) {
        if ($value <= 0) {
            return false;
        }
        if ($check_numeric) {
           // numeric testing
            $difference=abs($previous-$value);
            return $difference < $deadband;
            // ex. value: 74, previous: 70 => difference = 4
            // difference: 4 < deadband: 3 => false, not ok
        } else {
            // percentage testing
            $percentage=abs(($value - $previous) * 100/$previous);
            return $percentage < $deadband;
            // ex. v:111 p:100, (v-p)*100/p:11% < 10% => false, not ok
        }
    }

You eliminated the previous=0 or previous=value cases in your example, but I didn't understand why (you can put them back). I also not sure that your percentage formula is corect. If you want the difference in percentage, then (value-previous)*100/previous will give you the right answer. (ex. value = 10, previous=5 => percentage is 100 - correct!) You can check the function with the following testing code:

    $numeric_deadband = 3;
    $percentage_deadband = 10;

    /// GENERATE RADNOM DATA ex. 5.000 rows
    $rows_nr=5000;
    $min=40;
    $max=80;
    for ($i=0; $i<$rows_nr; $i++) {
        $numeric_set[]=array(
            "value"=>rand($min,$max), 
            "previous" => rand(40,80));
        $percentage_set[]=array(
            "value"=>rand($min,$max),
            "previous" => rand(40,80));
    }

    $time=microtime(true); // just for testing purposes
    foreach ($numeric_set as $row) {
        // check NUMERIC set
        // remove echos after testing
        echo "NUMERIC >> value: $row[value] vs previous :".
            "$row[previous] (deadband: $numeric_deadband) => ";
        echo check_deadband(
            $row["value"],
            $row["previous"],
            $numeric_deadband,
            true)
            ? "true" : "false";
        echo "<br/>";
    } unset($row);

    // CHECK time in miliseconds
    echo "<p>Checking deadband for NUMERIC ($rows_nr rows) took:".
        round((microtime(true)-$time)*1000)." miliseconds</p>";

    $time=microtime(true);
    foreach ($percentage_set as $row) {
        // check PERCENTAGE set
        // remove echo after testing
        echo "PERCENTAGE >> value: $row[value] vs previous:".
        "$row[previous]  (deadband: $percentage_deadband) => ";
        echo check_deadband(
            $row["value"],
            $row["previous"],
            $percentage_deadband,
            false)
            ? "true" : "false";
        echo "<br/>";
    } unset($row);

    echo "<p>Checking deadband for PERCENTAGE ($rows_nr rows) took:".
        round((microtime(true)-$time)*1000)." miliseconds</p>";

Hope this works. Feedback would be appreciated!

EDIT: Changed the script to detect both above and below deadband changes.

\$\endgroup\$
2
  • \$\begingroup\$ it needs to detect both greater than previous by deadband and less than previous by deadband. \$\endgroup\$ – r3wt Jul 17 '15 at 14:37
  • 1
    \$\begingroup\$ See modified script - it detects both cases. \$\endgroup\$ – verjas Jul 17 '15 at 14:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.