Расчет скользящего среднего

Скользящее среднее значение, рассчитанное по круговой матрице, дает постоянную величину < 0, когда среднее значение всегда должно быть между 0 и 1

Я пишу прошивку для устройства MSP430, которое использует светодиоды и фотодиоды для обнаружения определенных типов чернил. Устройство сканирует со скоростью около 155 мкс, а образцы под сканером находятся в диапазоне скоростей от 0,1 м / с до 3,3 м / с. Цель устройства - проверить наличие чернил и измерить соотношение чернил (прохождение) к тесту (не пройти) и включить зеленый светодиод, когда соотношение находится между соответствующим значением, и включить красный светодиод, если его нет. Я использую статические целочисленные массивы для хранения значений последовательных проходов и тестовых значений для одного и того же номера индекса каждого массива. После последнего индекса массива индекс возвращается к нулю, а старые значения перезаписываются.

GREEN_LED_ON; и подобные определения являются определениями портов для моего MCU и проверены на правильность.

Событие - это результат теста. Если чернила обнаружены, событие = ОБНАРУЖЕНО и наоборот

test будет средним значением, установленным графическим интерфейсом, но пока это ничего, потому что у меня не работает эта часть моей функции

Обычно у меня будет переменное среднее значение, устанавливаемое сопровождающим графическим интерфейсом, но для целей тестирования я установил среднее значение < 0, чтобы выяснить, почему светодиоды загорались не в то время, и обнаружил, что среднее значение <0. Среднее всегда должно быть 0=

Заметки:

  • Я попытался проверить, работают ли различные разделы кода, используя светодиодные выходы. Я закомментировал среднюю секцию, которая управляет светодиодами, и проверил, что часть события == работает, включив и выключив светодиоды. Затем я попытался поместить этот код в раздел flag==, и светодиоды также соответствовали этому разделу, как и ожидалось.
  • Я обнаружил проблему со значением массива. однажды n > size это только тестирует один раз вместо ожидания следующего изменения флага. Я не могу иметь n> размер, потому что дальше в моем коде, n++ будет равно 7, что за пределами

Я добавил раздел кода, чтобы убедиться, что опрокидывание не происходит. Значения 8000 и 30000 были выбраны, чтобы соответствовать самой низкой возможной скорости бега.

Я также изменил, где увеличивается индекс массива, и убедился, что он говорит в пределах границ массива.

Вот обновленная функция:

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) оператор AFTER для операторов flag, чтобы конечные значения моих массивов не равнялись 1. Вот изменение (оно есть в обоих операторах if(flag==):

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;

Вот оригинальный код:

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

2 ответа

Решение

В случае, если кто-то вернется к этому, это код, который я использую, и мое среднее значение работает отлично

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



  }
   }

У вас есть UB.

На вершине вы делаете if (n>=size) n = 0;, Это все еще позволяет n быть size-1

Но дальше вы делаете n++ до доступа к массивам. Это позволит вам получить доступ array[size], который является UB.

Я считаю, что вы хотите переместить n++ в нижней части вашего if разделы, после выполнения расчетов. И вы можете объединить оба if (++n >= size) n = 0;


ОБНОВИТЬ:

Я установил размер =5, и я все еще получаю отрицательные числа. Массивы в пределах границы теперь правильные?

Возможно. Но несколько вещей.

Только average нуждается [или должен быть] float,

У вас есть "параллельные" массивы. Я бы использовал структуру вместо

Я был над вашей логикой несколько раз, и я все еще не уверен, чего вы пытаетесь достичь.

Итак, я рефакторинг, чтобы попытаться удалить любые возможные тривиальные ошибки.

Я немного подозрительно отношусь к счетчикам вычитания, а затем добавления, особенно в точке переключения. Это единственное место, где вы можете получить отрицательные числа.

Может быть, поможет вставка функции в программу модульного тестирования, которая имитирует чернила различной длины / нет данных о потоке чернил. После этого вы можете использовать точки останова. Это может проверить / проверить вашу логику без необходимости использовать живую систему (т.е. программа модульного тестирования - это обычное приложение, которое вы можете запустить на своем ПК). Вы можете условно компилировать / выводить код светодиода в зависимости от "отмены при отрицательном значении", как указано ниже.

В любом случае, вот мое мнение об упрощении, которое может помочь прояснить [прошу прощения за бесполезную очистку стиля]:

// NOTE: in the long term, an int could wrap to a negative -- adjust this
// as needed
typedef long long ctr;

struct event {
    ctr testcount;
    ctr passcount;
};

// NOTE: moved this outside function to guarantee all values are zero at start
#define EVENTMAX    6
struct event events[EVENTMAX];

void
display(char event, char test)
{
    static int n = 0;
    static ctr sum = 0;             // total number of passes
    static double average;          // average pass rate over n
    static ctr consecpass = 0;      // consecutive passes
    static ctr consecfail = 0;      // consecutive fails
    static ctr testcount = 1;       // used to count the total number of tests
    static int flag = 0;
    struct event *cur;

    cur = &events[n];

    if (event == DETECTED) {
        if (flag == 0) {
            sum -= cur->passcount;
            testcount -= cur->testcount;

            cur->passcount = 0;
            cur->testcount = consecfail;

            sum += cur->passcount;
            testcount += cur->testcount;

            flag = 1;

            if (++n >= EVENTMAX)
                n = 0;
        }
        else {
            consecfail = 0;
        }

        consecpass++;
    }

    if (event == NOT_DETECTED) {
        if (flag == 1) {
            sum -= cur->passcount;
            testcount -= cur->testcount;

            cur->passcount = consecpass;
            cur->testcount = consecpass;

            sum += cur->passcount;
            testcount += cur->testcount;

            flag = 0;

            if (++n >= EVENTMAX)
                n = 0;
        }
        else {
            consecpass = 0;
        }

        consecfail++;
    }

    // add code to abort program if _either_ sum _or_ testcount is negative
    // here ...

    average = sum;
    average /= testcount;

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

ОБНОВЛЕНИЕ № 2:

Я обнаружил, что одна из проблем была перевернута. Я исправил это с помощью оператора if, в котором хранятся значения, если они превышают 8 000 или 30 000. Когда я нахожусь в режиме отладки, значения массивов выглядят так, как я ожидаю, но иногда я получаю отрицательные числа в сумме и счетчике. Как могут быть вычтены неправильные индексы?

Вы могли бы вычитать из "устаревшей" записи, даже если индекс действителен. Я понимаю, что вы пытаетесь RLE Impl.

Догадка...

Вы меняете "текущую" запись, но после ++n"другая" сторона может получить "следующую" запись, когда ей нужна предыдущая запись.

То есть вы вычитаете array[0], применить вещи, установить array[0] а затем увеличить n,

Другая сторона теперь вычитает array[1]когда нужно вычесть array[0] и установить array[1],

Таким образом, у вас может быть ошибка "выключено одним", логически говоря.

Не знаю.

С помощью приложения модульного тестирования вы можете добавить отладку printf За все. Когда происходит негативный, остановись. Затем проанализируйте журнал. модульный тест может / должен тестировать для всех крайних случаев.

Если вы введете в функцию последовательность (например) 1x10, 0x3, 1x5, 0x20, они должны появиться в массивах /struct. Сохраненные записи должны соответствовать входной последовательности.

Таким образом, сбросьте массив (ы), чтобы убедиться, что количество соответствует ожидаемому.

Какие значения бьют 8000/30000?

Другие вопросы по тегам