Расчет скользящего среднего
Скользящее среднее значение, рассчитанное по круговой матрице, дает постоянную величину < 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?