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:
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 boundsI 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;
}
}
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;
}
}
}