• AVR Freaks

C Array Averaging

Author
GUNN
New Member
  • Total Posts : 23
  • Reward points : 0
  • Joined: 2015/10/26 06:42:43
  • Location: 0
  • Status: offline
2017/07/31 02:05:34 (permalink)
0

C Array Averaging

hello!
 
I am having a brain block at the moment, hope somebody can help.
 
I have an array with an adjustable number of elements, every second each successive element gets updated with a dynamic value ("count") until it has reached its array limit and then starts back from the beginning.
 
Now, what I want to do is add all the elements together and divide by the array limit, but because its not a fixed length I don't know the syntax to add all the elements to "arraylimit" and then divide by "arraylimit".
 
char i;
  countarray[i] = count;
  if (i < arraylimit){
  i++;} else {i = 0;}
  countav = countarray[0] + ... /arraylimit; ????

#1

17 Replies Related Threads

    CinziaG
    die fucking humans
    • Total Posts : 3145
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: C Array Averaging 2017/07/31 02:21:51 (permalink)
    +1 (1)
    Mmmm, sum them all together up to arraylimit, and then divide by arraylimit...

    in 2018 you signed for your annihilation. in 2019 it will come ;) I promise
    my most wonderful creations here
    https://www.youtube.com/c...dPFRvtwsbSTXp6Sk6azGOQ
    #2
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 4014
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 02:22:36 (permalink)
    0
    Add the values as they are entered rather than wait until it is complete.

    #define MAX_LMT
    int idx=0,lmt=10,avg,cnt=0,x[MAX_LMT];
     
    x[idx++]=val;
    cnt+=val;
    if(idx==lmt){idx=0;avg=cnt/lmt;cnt=0;}

    lmt controls the array size

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #3
    GUNN
    New Member
    • Total Posts : 23
    • Reward points : 0
    • Joined: 2015/10/26 06:42:43
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 03:17:12 (permalink)
    +1 (1)
    CinziaG
    Mmmm, sum them all together up to arraylimit, and then divide by arraylimit...


    That would be easy if it was a fixed limit, but what is the syntax to say "sum to the array limit"?
     
    Gort2015
    Add the values as they are entered rather than wait until it is complete.

     
    #define MAX_LMT
     
    int idx=0,lmt=10,avg,cnt=0,x[MAX_LMT];
     
     
     
    x[idx++]=val;
     
    cnt+=val;
     
    if(idx==lmt){idx=0;avg=cnt/lmt;cnt=0;}

    lmt controls the array size




    The array is to be averaged every second when a new count has been added to it, the averaging part of the code is in an ISR that repeats every second.
     
    Could you comment your code and explain what is happening at each part please?
     
    All help is greatly appreciated, thank you.
    #4
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 4014
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 03:37:20 (permalink)
    +1 (1)
     
    #define MAX_LMT 50 // MAXIMUM SIZE FOR MEMORY, (MISSED OUT 50 ON 1ST POST)
    int idx=0,lmt=10,avg,sum=0,array[MAX_LMT]; // GLOBAL VARIABLES
    void __attribute__((interrupt, no_auto_psv)) _T5Interrupt(void){
    array[idx++]=count; // STORE NEW VALUE INTO ARRAY AND INCREMENT INDEX
     
    sum+=val; // SUM OF VALUES RECEIVED, RUNNING TOTAL
     
    if(idx==lmt){ // LIMIT REACHED OF HOW MANY ELEMENTS YOU NEED
    idx=0; // RESET INDEX
    avg=sum/lmt; // AVERAGE IS SUM / LIMIT
    sum=0; // RESET SUM
    }
    IFS1bits.T5IF=0; // CLEAR IRQ
    }

    Best I could do. If your limit changes make sure that it is smaller than MAX_LMT.
    Renamed cnt to sum, x to array and value to count that you had
    post edited by Gort2015 - 2017/07/31 03:39:18

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #5
    rodims
    Super Member
    • Total Posts : 1558
    • Reward points : 0
    • Joined: 2009/02/10 11:08:59
    • Location: 51.9627, 7.6262
    • Status: offline
    Re: C Array Averaging 2017/07/31 03:51:14 (permalink)
    +2 (2)
    If you understand Gort's proposal and what it does then -> use it.


    For me your problem description still is rather vague, so I have no idea what your problem is or what you need.
    In detail I did understand WHEN you actually need to average (which implies when you are allowed to reset your counter and sum). 
    Based on count ? Based on time ? Just forced by array size ? May be you need a 'moving average'  ?
    I think your application should tell you what is necessary.
     
    #6
    CinziaG
    die fucking humans
    • Total Posts : 3145
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: C Array Averaging 2017/07/31 03:58:36 (permalink)
    0
    Yeap, that's why I was skeptical...

    in 2018 you signed for your annihilation. in 2019 it will come ;) I promise
    my most wonderful creations here
    https://www.youtube.com/c...dPFRvtwsbSTXp6Sk6azGOQ
    #7
    GUNN
    New Member
    • Total Posts : 23
    • Reward points : 0
    • Joined: 2015/10/26 06:42:43
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 05:13:28 (permalink)
    0
    Gort2015
     
    #define MAX_LMT 50 // MAXIMUM SIZE FOR MEMORY, (MISSED OUT 50 ON 1ST POST)
    int idx=0,lmt=10,avg,sum=0,array[MAX_LMT]; // GLOBAL VARIABLES
    void __attribute__((interrupt, no_auto_psv)) _T5Interrupt(void){
    array[idx++]=count; // STORE NEW VALUE INTO ARRAY AND INCREMENT INDEX
     
    sum+=val; // SUM OF VALUES RECEIVED, RUNNING TOTAL
     
    if(idx==lmt){ // LIMIT REACHED OF HOW MANY ELEMENTS YOU NEED
    idx=0; // RESET INDEX
    avg=sum/lmt; // AVERAGE IS SUM / LIMIT
    sum=0; // RESET SUM
    }
    IFS1bits.T5IF=0; // CLEAR IRQ
    }

    Best I could do. If your limit changes make sure that it is smaller than MAX_LMT.
    Renamed cnt to sum, x to array and value to count that you had




    Thanks, I see what you did there.
     
    The problem with that is that you are summing to the limit and then resetting the sum after the limit is reached.
     
    What I am trying to do is a moving average, when a new value enters the array the oldest is discarded (re-written over), the average is taken and then displayed.
     
    Like I previously mentioned, if I had a fixed array length its quite easy...
     

    char i;
    countarray[i] = count;
    if (i < 10){
    i++;} else {i = 0;}
    countav = countarray[0] + countarray[1] + countarray[2] + countarray[3] + countarray[4] + countarray[5] + countarray[6] + countarray[7] + countarray[8] + countarray[9]/ 10;

     
    but I need the value of 10 (in the if statement and the division) to be a variable. This also means I need to sum the array to the value of the same variable. I need a function that sums the array regardless of how many elements it stores.
    #8
    rodims
    Super Member
    • Total Posts : 1558
    • Reward points : 0
    • Joined: 2009/02/10 11:08:59
    • Location: 51.9627, 7.6262
    • Status: offline
    Re: C Array Averaging 2017/07/31 05:35:59 (permalink)
    +2 (2)
    a) at any time you need the current valid number of counts in your array. You need a counter variable for that.
        This starts with 0 (your sum also starts with 0 ) and then increments +1 for each of your interrupts.
        Once the maximum is reached, the counter value will not change anymore. E.g. in your example, once the 10 is reached, it  will stay 10.  Do not mix up this counter value with your array index value , that's two different variables.
    b) build the sum in a loop, the maximum is your counter variable. Divide by the counter variable.
    c) Once the max (10) is reached, you will redundantly perform the summation for 9 of the elements, although this has already been done before. This is more a problem for larger arrays and/or if you are doing your calculations in the interrupt. 
    For this (performance) reason you might optimize that and just remove the oldest element from your sum (subtract) and thus replace it (add) with your new value. 
    My impression is, that you should not try that before b) works.
     
    As the 10 is only an example, replace this with the choosen size of your array.
    post edited by rodims - 2017/07/31 05:37:55
    #9
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 4014
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 05:51:12 (permalink)
    +1 (1)
    You can move the array values with memmove
     
    [1,2,3,4,5] 15/5
    [2,3,4,5,6] 20/5
    [3,4,5,6,7] 25/5
    [4,5,6,7,8] 30/5
     
    items=5
    memmove(array, array+1, items-1)
    array[items-1]=count
    sum-=array[0]
    sum+=count
    avg=sum/items

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #10
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 4014
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 05:59:41 (permalink)
    +1 (1)
    Since it only happens once per second, time shoudn't be a problem.
    I'd also move that code out of the interrupt.
     
    Set some flag in the isr or just wait for the irq flag to be set and ditch the interrupt.

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #11
    1and0
    Access is Denied
    • Total Posts : 11774
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: C Array Averaging 2017/07/31 06:04:32 (permalink)
    0
    GUNN
    but I need the value of 10 (in the if statement and the division) to be a variable. This also means I need to sum the array to the value of the same variable. I need a function that sums the array regardless of how many elements it stores.

    I'm still not understanding this clearly. Does this variable stays at 10 when it reaches 10, or this variable can change any time?
     
    #12
    GUNN
    New Member
    • Total Posts : 23
    • Reward points : 0
    • Joined: 2015/10/26 06:42:43
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 06:16:22 (permalink)
    0
    1and0
    GUNN
    but I need the value of 10 (in the if statement and the division) to be a variable. This also means I need to sum the array to the value of the same variable. I need a function that sums the array regardless of how many elements it stores.

    I'm still not understanding this clearly. Does this variable stays at 10 when it reaches 10, or this variable can change any time?
     




    the number 10 in this example is how many data points or elements in the array I need to average.
     
    The device I am making is a radiation detector. Pulses from a geiger-muller tube are counted over a one second period, recorded (in the array) and reset.
     
    The length of the array is how long (in seconds) the results are averaged. A 10 second (or 10 element array) period will provide a consistent result (radiation emission is non uniform). However, a long average time will reduce the instruments response and it sometimes may be useful to reduce the average period (and array length) to 3 seconds with the push of a button.
     
    It needs to be a moving average where the last element in the array is discarded, I believe Rodims and Gort2015 have solved the issue.
     
    Regards
     
    Gunn
    #13
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 4014
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 06:22:09 (permalink)
    +1 (1)
    Thumbs up then.

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #14
    moser
    Super Member
    • Total Posts : 608
    • Reward points : 0
    • Joined: 2015/06/16 02:53:47
    • Location: Germany
    • Status: offline
    Re: C Array Averaging 2017/07/31 06:31:06 (permalink)
    +1 (1)
    I believe you want the following: You have a fixed size array (let's say 10 elements) which you want to use for calculating a moving average. When the array is filled for the first time, and you have only a few values then the average should be computed only over those values. After the 10th value the average will be always computed about 10 elements, because starting with the 11th value you are overwriting the oldest value.
     
     
    Are you not familiar with using a loop? For example like this:

    char i;
    char number_of_elements;
     
    // insert new element (might overwrite old one)
    countarray[i] = count;
    // increase index
    if (i < arraylimit){i++;} else {i = 0;}
    // increase number of elements
    if (number_of_elements < arraylimit+1){number_of_elements++;}
    // calculate the average (sum up from countarray[0] to countarray[number_of_elements-1] and then divide)
    fill_in_type_which_suits_your_needs_here countsum = 0;
    char j;
    for (j=0;j<number_of_elements;++j) {
        countsum += countarray[j]
    }
    countav = countsum / number_of_elements;

    Initialize number_of_elements with 0. 
    Note, that arraylimit is the highest index in your array, and arraysize is used for the declaration of your countarray. Therefore arraylimit = arraysize - 1. It seems you are confusing those two numbers.
     
    I tried to stay near to your code, to help you understand it although this is not optimal. Furthermore, that is not really efficient for a moving average. What is efficient depends on your needs. Answer the following questions:
     
    1) When do you need the average updated? Do you need it updated every time directly after you have added a new value? Or only occasionally?
    2) Is the only thing what is dynamic about your array the start situation, when the array gets filled for the first time?
    3) What is your datatype used for the array? Integer or Float?
    4) How big is your array (roughly)? 10 or 100 or 1000 or ... ? Since you are using "char" as index type, it can not be much.
    5) Which accuracy do you need for the average?
    6) Is the starting condition really an issue for you? Would it be bad if you get a wrong average for the first 9 values (if your array is of size 10)?
    7) Is this code required to have a high performance and must be really, really, really fast?
     
     
    If you have an integer datatype then keeping the sum is typically the best solution. If you enter a value, then you add it to the sum and increase the number of elements by one. If you remove a value then subtract it from the sum and decrease the number of elements by one. If you overwrite a value, than that is the same as removing and then adding an element. To get the average you just divide the sum by the number of elements.
     
    If you have an float datatype, then you can not use the approach for integers, because the errors start adding up. There are quite a number of nice other algorithms to prevent it. But which fits for you, depends.
    #15
    GUNN
    New Member
    • Total Posts : 23
    • Reward points : 0
    • Joined: 2015/10/26 06:42:43
    • Location: 0
    • Status: offline
    Re: C Array Averaging 2017/07/31 06:56:19 (permalink)
    0
    hello Moser, thank you for your reply.
     
    1) Every second (when a new value has been added to the array)
    2) No, at a push of a button the array needs to be shortened. I didn't think about the starting condition, it would be an issue!
    3) The individual elements would be integers ( you can't get half a pulse from a GM tube) but the average will be a float.
    4) The array would be a maximum of 10 elements.
    5) To at least 1 decimal place.
    6) See point 2).
    7) No, as long as it can be keep up with 1Hz.
     
    Thank you for your help.
     
    #16
    NorthGuy
    Super Member
    • Total Posts : 6471
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: offline
    Re: C Array Averaging 2017/07/31 08:12:12 (permalink)
    +2 (2)
    It is easier to use smoothing than averaging:
     
    x = a*v + b*x, where (a + b) = 1, v is the new value.
     
    Smoothing is approximately equivalent to averaging when a = 2/N, so in your case a = 2/10 = 0.2. This lets you avoid using arrays and also produces better results for the user - for example, he doesn't see the 10s average suddently change when a big 10-second old value gets removed from the acarage.
     
    Here's the code:
     
    uint32_t rolling_sum;
     
    // to add a value (every 1s).
    // here's how the formula gets converted to the code:
    // rolling_sum is x*5. x = 0.2*v + 0.8*x  ===> rolling_sum = v + 4*x ===>
    // rolling_sum = v + 4*rolling_sum/5 ===> rolling_sum = rolling_sum + v - rolling_sum/5
    rolling_sum += new_value - ((rolling_sum + 2)/5);
     
    // to get the 10s average (any time)
    average = (rolling_sum + 2)/5;

     
    If you insist on averageing:
     
    uint32_t rolling_sum;
    uint32_t past_values[10];
    int index; // points to the next value to be updated
     
    // to add a value (every 1s).
    if (++index > 9) index = 0; // move the index to the next slot
    rolling_sum += new_value - past_values[index]; // replace the count from 10 seconds ago with the current count
    past_values[index] = new_value; // remember the value we used so that we could subtract it 10 cycles from now 
     
    // to get the 10s average (any time)
    average = (rolling_sum + 5)/10;

     
    #17
    1and0
    Access is Denied
    • Total Posts : 11774
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: C Array Averaging 2017/07/31 08:22:01 (permalink)
    +1 (1)
    Additional questions:
     
    2a, 6a) "Would it be bad if you get a wrong average for the first 9 values (if your array is of size 10)?" ... And would it be bad if you get the wrong average for the first 3 values (reduced length)? If not, the array elements can be zeroed or filled with the first value read at the start. This will make it simpler -- just average the most recent 10 or 3 values; instead of averaging over 1, 2, 3, ..., up to 10 at the start.
     
    3a, 5a) Avoid floating point math. Multiply your sum by 10 before dividing by 10 or 3. That will give one decimal place; i.e. the one's digit is the decimal digit. For displaying you just place the decimal point at the correct position.
     
    <edit> I like the smoothing suggested by NG.
     
    post edited by 1and0 - 2017/07/31 08:25:52
    #18
    Jump to:
    © 2021 APG vNext Commercial Version 4.5