Search code examples
carraysmsp430circular-buffercode-composer

Calculating a running average


The running average calculated from circular array produced constant < 0 average when average should always be between 0 and 1.

I am writing firmware for an MSP430 device that uses LEDs and photodiodes to detect specific types on ink. The device scans at about 155us and the samples under the scanner range from velocities of .1m/s to 3.3m/s. The goal of the device is to test for ink and measure the ink (pass) to test (not pass) ratio and turn on a green LED when the ratio is between the corresponding value and turn on a red LED when it is not. I am using static integer arrays to store the values of consecutive passes and test values to the same index number of each array. After the last index of the array, the index is set back to zero and the old values are written over.

GREEN_LED_ON; and similar definitions are port definitions for my MCU and are verified to be correct.

event is the test result. If ink is detected, event=DETECTED and vice versa

test will be the average set by a GUI, but for now it is nothing because I don't have this part of my function working

Normally I will have the variable average set by an accompanying GUI, but for testing purposes I set average<0 just to figure out why the LEDs were coming on at the wrong time and I found that I am getting an average<0. Average should always be 0=

Notes:

  • I've tried checking if various sections of the code are working by using the LED outputs. I commented out the average section that controls the LEDs and verified that the event== part works by turning on and off the LEDs. Then I tried putting that code in the flag== section and the LEDs also corresponded with that section as expected.
  • I found a problem with the array value. Once n > size it only tests once instead of waiting for the next flag change. I can't have n>size because further down in my code, n++ will equal 7, which is out of bounds

I added a section of code to make sure rollover doesn't occur. The values 8,000 and 30,000 were chosen to match the slowest possible running speed.

I also changed where the array index increments and made sure it says within bound of the array.

Here is the updated function:

void display(char event, char test) {

static int size=5;
static int array[6]={0};  //array with number of passes for each n
static int n=0;
static float sum=0;//total number of passes
static float average=0;//average pass rate over n
static int consecpass=0; //consecutive passes
static int consecfail=0; //consecutive fails
static int totalnumberoftests[6]={0}; //total number of tests conducted.  Counts the number of passing or failing tests for the nth value
static float counter=1; //used to count the total number of tests
static int flag=0;


    if (event == DETECTED)
    {
        if (flag==0)
        {

            sum=sum-array[n];
            counter=counter-totalnumberoftests[n];
            array[n]=0;
            totalnumberoftests[n]=consecfail;
            sum=sum+array[n];
            counter=counter+totalnumberoftests[n];

            flag=1;
            consecpass++;

            n++;
            if(n>=size)n=0;
            //GREEN_LED_ON;
            //RED_LED_OFF;
        }else{

        consecfail=0;
        consecpass++;
        //GREEN_LED_ON;
        //RED_LED_OFF;

        }

    } if (event==NOT_DETECTED){

        if(flag==1)
        {

            sum=sum-array[n];
            counter=counter-totalnumberoftests[n];
            array[n]=consecpass;
            totalnumberoftests[n]=consecpass;
            sum=sum+array[n];
            counter=counter+totalnumberoftests[n];

            flag=0;
            consecfail++;

            n++;
            if(n>=size)n=0;
            //RED_LED_ON;
            //GREEN_LED_OFF;
        }else{


        consecpass=0;
        consecfail++;
        //RED_LED_ON;
        //GREEN_LED_OFF;


        }
    }

    if (consecpass>8000)
    {
        sum=sum-array[n];
        counter=counter-totalnumberoftests[n];
        array[n]=consecpass;
        totalnumberoftests[n]=consecpass;
        sum=sum+array[n];
        counter=counter+totalnumberoftests[n];
        consecpass=0;
        n++;
        if(n>=size)n=0;
    }

    if(consecfail>30000)
    {
        sum=sum-array[n];
        counter=counter-totalnumberoftests[n];
        array[n]=0;
        totalnumberoftests[n]=consecfail;
        sum=sum+array[n];
        counter=counter+totalnumberoftests[n];
        consecfail=0;
        n++;
        if(n>=size)n=0;
    }

    average=sum/counter;

    if(average<.6 && average > .1)
    {
        GREEN_LED_ON;
        RED_LED_OFF;
    }else{
        GREEN_LED_OFF;
        RED_LED_ON;
    }


}

if (n >= size) statement to AFTER the flag statements to avoid having the final values of my arrays be 1. Here is the change (it is on both if(flag==) statements:

if (flag == 1) {
    sum = sum - array[n];
    counter = counter - totalnumberoftests[n];
    array[n] = consecpass;
    totalnumberoftests[n] = consecpass;
    sum = sum + array[n];
    counter = counter + totalnumberoftests[n];

    flag = 0;
    consecfail++;

    n++;
    if (n >= size)
        n = 0;

Here is the original code:

void display(char event, char test) {

    static int size = 6;
    static int array[6] = { 0 };  //array with number of passes for each n
    static int n = 0;
    static float sum = 0;//total number of passes
    static float average = 0;//average pass rate over n
    static int consecpass = 0; //consecutive passes
    static int consecfail = 0; //consecutive fails
    static int totalnumberoftests[6] = { 0 }; //total number of tests conducted.  Counts the number of passing or failing tests for the nth value
    static float counter = 1; //used to count the total number of tests
    static int flag = 0;    

    if (n >= size) {    
        n = 0;    
    }

    if (event == DETECTED) {
        if (flag == 0) {
            n++;
            sum = sum - array[n];
            counter = counter - totalnumberoftests[n];
            array[n] = 0;
            totalnumberoftests[n] = consecfail;
            sum = sum + array[n];
            counter = counter + totalnumberoftests[n];

            flag = 1;
            consecpass++;               
        } else {    
            consecfail = 0;
            consecpass++;               
        }    
    } 

    if (event == NOT_DETECTED) {    
        if (flag == 1) {
            n++;
            sum = sum - array[n];
            counter = counter - totalnumberoftests[n];
            array[n] = consecpass;
            totalnumberoftests[n] = consecpass;
            sum = sum + array[n];
            counter = counter + totalnumberoftests[n];

            flag = 0;
            consecfail++;               
        } else {        
            consecpass = 0;
            consecfail++;               
        }
    }

    average = sum / counter;

    if (average < 0) {
        GREEN_LED_ON;
        RED_LED_OFF;
    } else {
        GREEN_LED_OFF;
        RED_LED_ON;
    }        
}

Solution

  • In case anyone come back to this, this is the code I am using and my running average is working perfectly

     void display(char event, char test) {
    
       static int size=9; //size of the array
       static int array[10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0};  //array with number of passes for each n
       static int n=0; //number for the index in both arrays
       static long int sum=0;//total of passes
       static double average=0;//rate of passes per tests.  The sum of the values in array[n] divided by total tests in totalnumberoftest[n] attay
       static int consecpass=0; //consecutive passes
       static int consecfail=0; //consecutive fails
       static int totalnumberoftests[10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //total number of tests conducted.  Counts the number of passing or failing tests for the nth value
       static long int counter=1; //used to count the total number of tests
       static int flag=0;//flag used to indicate when the input goes from event==DETECTED to event==NOT_DETECTED
       static int lowlimitb=0;// integer value from low limit b in desert for average setting.  Value entered should be the positive tests/total tests percentage
    
    
            sum=sum-(float)array[n]; //subtract the nth value of array from sum
            counter=(float)counter-totalnumberoftests[n];
            array[n]=0;//set the nth value to zero, because the previous state of event was NOT_DETECTED, meaning there were no positive tests
            totalnumberoftests[n]=consecfail; //add the number of negative tests to total tests
            sum=sum+(float)array[n]; //add array index n to sum (should be zero)
            counter=counter+(float)totalnumberoftests[n]; //counter is the total number of tests.  Add totalnumberoftests with the last index n adds the last consecfail to counter
    
            flag=1; //set flag==1 to indicate the last event was DETECTED
            consecpass++; //count a pass
            consecfail=0;
    
            n++; //set the next index for the arrays
            if(n>size)n=0;  //if array index is greater than the size of the array, set the index back to zero. This will overwrite the data in array index zero
            //GREEN_LED_ON;
            //RED_LED_OFF;
        }else{ //the last event=DETECT, no need to change array indices
    
    
        consecpass++;
        //GREEN_LED_ON;
        //RED_LED_OFF;
    
        }
    
    } if (event==NOT_DETECTED){
    
        if(flag==1) //flag gets set to 1 in event==DETECTED
        {
    
            sum=sum-(float)array[n];    //subtract the nth value of array from current sum of passes
            counter=counter-(float)totalnumberoftests[n];
            array[n]=consecpass; //set array[n] equal to the number of consecutive passes
            totalnumberoftests[n]=consecpass; //set the number of tests for index n = number of passes
            sum=sum+(float)array[n]; //add the last number of consecutive passes (stored in array[n]) to the current sum of passes
            counter=counter+(float)totalnumberoftests[n];
    
            flag=0; //set the flag==0 so the array indices do not change until event changes
            consecfail++;
    
            n++; //set the next index for the arrays
            if(n>size)n=0;//if array index is greater than the size of the array, set the index back to zero. This will overwrite the data in array index zero
            //RED_LED_ON;
            //GREEN_LED_OFF;
        }else{
    
        consecpass=0;
        consecfail++;
        //RED_LED_ON;
        //GREEN_LED_OFF;
    
    
        }
    }
    
    if (consecpass>8000) //used to prevent rollover and to indicate failure if device is standing still.  8000 was selected because the absolute minimum speed will be 10cm/s
    {
        sum=sum-(float)array[n];
        counter=counter-(float)totalnumberoftests[n];
        array[n]=consecpass;
        totalnumberoftests[n]=consecpass;
        sum=sum+(float)array[n];
        counter=counter+(float)totalnumberoftests[n];
        consecpass=0;
        n++;
        if(n>size)n=0;
    }
    
    if(consecfail>30000) //used to prevent rollover and to indicate failure if device is standing still.  30000 was selected because the absolute minimum speed will be 10cm/s
    {
        sum=sum-(float)array[n];
        counter=counter-(float)totalnumberoftests[n];
        array[n]=0;
        totalnumberoftests[n]=consecfail;
        sum=sum+(float)array[n];
        counter=counter+(float)totalnumberoftests[n];
        consecfail=0;
        n++;
        if(n>size)n=0;
    }
    
    average=(double)sum/(double)counter; //average is a float.  The total number of positive tests/total number of tests
    
    
    if(average<.35 && average > .25 //acceptable passing range
    {
        GREEN_LED_ON;
        RED_LED_OFF;
    
    
    } else {
    
        GREEN_LED_OFF;
        RED_LED_ON;
        }
    
    
    
      }
       }