Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 11:17 01 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Basic Averaging Routine

Author Message
OA47

Guru

Joined: 11/04/2012
Location: Australia
Posts: 986
Posted: 09:26pm 12 Mar 2021
Copy link to clipboard 
Print this post

Does anyone have an example of a Basic averaging routine where a series of samples are sorted and the highest and lowest removed so the rest can be averaged?

OA47
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 09:55pm 12 Mar 2021
Copy link to clipboard 
Print this post

Is it a running average or a stand-alone block of values?
How many in the set and are you using a version of Basic with a SORT command?

Jim
VK7JH
MMedit
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 10:17pm 12 Mar 2021
Copy link to clipboard 
Print this post

Here is  a quicky that doesn't use SORT

 OPTION EXPLICIT
 OPTION DEFAULT NONE
 DIM FLOAT rdgs(10)
 
 DIM INTEGER n
 DIM FLOAT x
 FOR n = 1 TO 10
   rdgs(n) = RND()*30
   PRINT rdgs(n)
 NEXT n
 PRINT
 PRINT filtered()
 
FUNCTION filtered() AS FLOAT
 LOCAL FLOAT n, largest=0, least=50, av
 FOR n = 1 TO 10
   av = av + rdgs(n)
   IF rdgs(n) > largest THEN largest = rdgs(n)
   IF rdgs(n) < least THEN least = rdgs(n)
 NEXT n
 PRINT "Ignoring ";largest;" and ";least
 PRINT
 av = (av - largest-least)/8
 filtered = av
END FUNCTION


Jim
VK7JH
MMedit
 
OA47

Guru

Joined: 11/04/2012
Location: Australia
Posts: 986
Posted: 04:51am 13 Mar 2021
Copy link to clipboard 
Print this post

  Quote  Is it a running average or a stand-alone block of values?
How many in the set and are you using a version of Basic with a SORT command?


Here is some of the code I am currently running but I am not removing the highest and lowest values.

Dim Integer Rt
Dim Float CoreTemp(5),AvTemp

' This Sub Called every second

Rt=Rt+1
If Rt=6 Then Rt=1
CoreTemp(Rt)=Pin(TEMP)
AvTemp=(CoreTemp(1)+CoreTemp(2)+CoreTemp(3)+CoreTemp(4)+CoreTemp(5))/5
Text 240,30,Str$(AvTemp,2,1) + Chr$(96),LB,4,1,C.Blue


OA47
 
OA47

Guru

Joined: 11/04/2012
Location: Australia
Posts: 986
Posted: 04:53am 13 Mar 2021
Copy link to clipboard 
Print this post

  Quote  Here is  a quicky that doesn't use SORT


Thanks Jim I will investigate more.

OA47
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 05:46am 13 Mar 2021
Copy link to clipboard 
Print this post

Here's a different one showing it running a rolling average (temp & %RH data as ASCII strings, coming in), flagging and logging outsiders (noise - see the DEBUG statements in the 'noisecheck routine) and displaying/plotting data as it comes in. The full caboodle is on the forum somewhere - search for Digoo and member 'paceman'.

Greg

sub plotdata                          'another Digoo oC/%RH data set coming in.
 local float flT,flRH
 flT =val(temp$):  flRH =val(relhumid$)  'convert to integer for noisecheck & plot.
 
 if flRH > 99.0 then flRH = 99.0     'DEBUG stops any over-scale RH stuffing up display.
 if flRH = 99.0 then relhumid$ = "99" 'DEBUG stops any over-scale RH stuffing up display.
 
 'Noisecheck data then display & plot on grid. Scroll at grid end.
 xposn = plotstart + (timer/60000)   'start posn + elapsed mins since grid draw or scroll.
 if xposn => mm.hres-30 then scroll  'if reached end of grid, start scrolling.
 
 If cn1=6 Then cn1=5     'Reset rolling average noisecheck data array counters to 5
 If cn2=6 Then cn2=5     'after first 6 have been built up. After that, number 6 is
 If cnP=6 Then cnP=5     'then always the current result.
 
 if channel$ ="1" then                'this is Ch1 data.
   cn1 = cn1+1                        'array element counter for Ch1 noisecheck arrays.
   Tch1(cn1)= flT:  Rch1(cn1)= flRH   'build up Ch1 noisecheck array elements.
   if cn1 =6 then                     'when six Ch1 array elements have been filled.
     text 8,20,dattime$ +" Out  ",,2   'display date/time of current Ch1 data. Ch1=Outside
     noisecheck(Tch1(),5)             'check if Ch1 temp. is noise. Limits +/- 5oC.
     if noise then
       Ch1TN = Ch1TN +1                         'Update Ch1 temperature noise count.
       text 398,20,Str$(Ch1TN,2,0),,2,,yellow   'display it in textbox.
     else
       text 218,20,temp$,,2,,yellow   'display temperature in TCh1 textbox
       Pixel xposn,308-(5*(flT+5.0)),yellow   'and plot using base & slope of temp. scale.  
     endif
     noisecheck(Rch1(),15)            'check if Ch1 %RH is noise. Limits +/- 10%.
     if noise then
       Ch1RN = Ch1RN +1               'Update Ch1 %RH noise count.
       text 438,20,Str$(Ch1RN,2,0),,2,,GREEN     'display it in textbox
     else
       text 282,20,relhumid$,,2,,green   'display %RH in RCh1 textbox & then plot
       Pixel xposn,308-(2.5*flRH),green  'using base, slope and offset of %RH scale.
     endif
   endif
   
 else   ...... goes on to Channel 2 data.
--------------------------
sub noisecheck(param() As float,limit As float) As integer   'Simple rolling average.
 Local integer i,m
 Local float sum,rollave
 
 noise =0                       'reset flag.
 For i = 1 To 5
   sum = sum + param(i)
 Next i
 rollave = sum/5                'calc. rolling average of first 5 array elements.
 If param(6)> rollave+limit Or param(6)< rollave-limit Then noise =1  'test current result.
 if noise then                                   'DEBUG
   line xposn,134,xposn,142                      'DEBUG mark display when noise occurred.
   text xposn,150,Str$(param(6),2,2),ctv,,,red   'DEBUG display param(6)vertically.
   text xposn,65,Str$(rollave,2,2),ctv,,,cyan    'DEBUG display rollave vertically.
 endif                                           'DEBUG
 If noise Then Exit Sub         'if noise, exit with flag set.
 For m = 1 To 6                 'if not noise, shuffle array back one. This drops 1st array
   param(m) = param(m+1)        'element thus the current data, param(6), is now param(5).
 Next m
End Sub
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 07:58am 13 Mar 2021
Copy link to clipboard 
Print this post

This is a classic merge sort application. Attached is Geoff's code from the analog input routine on the Micromite - just convert the syntax and away you go

  Quote                              for(i = 0; i < ANA_AVERAGE; i++) {
                               b[i] = ExtInp(pin);                 // get the value
                               for(j = i; j > 0; j--) {            // and sort into position
                                   if(b[j - 1] < b[j]) {
                                       t = b[j - 1];
                                       b[j - 1] = b[j];
                                       b[j] = t;
                                   }
                                   else
                                       break;
                               }
                           }
                           // we then discard the top ANA_DISCARD samples and the bottom ANA_DISCARD samples and add up the remainder
                           for(j = 0, i = ANA_DISCARD; i < ANA_AVERAGE - ANA_DISCARD; i++) j += b[i];
 
OA47

Guru

Joined: 11/04/2012
Location: Australia
Posts: 986
Posted: 12:07am 14 Mar 2021
Copy link to clipboard 
Print this post

  Quote   just convert the syntax and away you go


Thank you for your contribution.

I could not fully understand the code enough to convert it to basic (must be your English accent Peter or maybe my lack of practice with C)

Could the code be simply converted to MMBasic retaining its simplicity or would I need to implement a C routine in my MMBasic program?

OA47
 
jirsoft

Guru

Joined: 18/09/2020
Location: Czech Republic
Posts: 533
Posted: 01:11am 14 Mar 2021
Copy link to clipboard 
Print this post

Hi OA47,
should be something like this:
CONST ANA_DISCARD = 1, pin = 1 'ANA_DISCARD is the amount of samples to be discarded top and bottom

DIM INTEGER i, j, ANA_AVERAGE = 100 'ANA_AVERAGE is amount of samples
DIM FLOAT b[ANA_AVERAGE-1], t, avg, sum

FOR i = 0 TO ANA_AVERAGE-1
 b[i] = ExtInp(pin) 'here is the sample read
 FOR j = i TO 1 STEP -1
   IF b[j-1] < b[j] THEN
     t = b[j-1]
     b[j-1] = b[j]
     b[j] = t
   ELSE
     EXIT FOR
   ENDIF
 NEXT j
NEXT i

sum = 0
FOR i = ANA_DISCARD TO ANA_AVERAGE-ANA_DISCARD-1
 INC sum, b[i]
NEXT i
avg = sum / (ANA_AVERAGE - 2*ANA_DISCARD)

Jiri
Napoleon Commander and SimplEd for CMM2 (GitHub),  CMM2.fun
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3378
Posted: 01:24am 14 Mar 2021
Copy link to clipboard 
Print this post

  jirsoft said  should be something like this:

Except with "(" instead of "[" and ")" instead of "]".
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 01:52am 14 Mar 2021
Copy link to clipboard 
Print this post

For a small array like you are using, we don't need to do a sort etc.

 ' This Sub Called every second
 
 Rt=Rt+1
 If Rt=6 Then Rt=1
 CoreTemp(Rt)=Pin(TEMP)
 AvTemp = AvT()
 Text 240,30,Str$(AvTemp,2,1) + Chr$(96),LB,4,1,C.Blue
 
 
 
FUNCTION AvT() AS FLOAT
 LOCAL FLOAT n, largest=-10, least=100 ' set largest and least to ridiculous extremes
 FOR n = 1 TO 5
   AvT = AvT + CoreTemp(n)
   IF CoreTemp(n) > largest THEN
     largest = CoreTemp(n)
   ELSEIF CoreTemp(n) < least THEN
     least = CoreTemp(n)
   ENDIF
 NEXT n
 'PRINT "Ignoring ";largest;" and ";least
 'PRINT
 AvT = (AvT - largest-least)/3
END FUNCTION


My original suggestion changed to fit your variables.

Jim
VK7JH
MMedit
 
OA47

Guru

Joined: 11/04/2012
Location: Australia
Posts: 986
Posted: 03:25am 14 Mar 2021
Copy link to clipboard 
Print this post

  Quote  My original suggestion changed to fit your variables.


Thanks Jim, but I was taking the average over 5 seconds where I think your code will take sequential samples, am I right?

OA47
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 04:33am 14 Mar 2021
Copy link to clipboard 
Print this post

My code is almost the same as yours.
You take an average of the last 5 readings.
I take the same last 5 readings and drop the highest and lowest before averaging.

Jim
VK7JH
MMedit
 
jirsoft

Guru

Joined: 18/09/2020
Location: Czech Republic
Posts: 533
Posted: 10:19am 14 Mar 2021
Copy link to clipboard 
Print this post

  lizby said  
  jirsoft said  should be something like this:

Except with "(" instead of "[" and ")" instead of "]".

Yes, of course. It was too late night... thanks lizby.
Jiri
Napoleon Commander and SimplEd for CMM2 (GitHub),  CMM2.fun
 
Ingotron
Newbie

Joined: 17/03/2021
Location: Germany
Posts: 1
Posted: 10:46am 17 Mar 2021
Copy link to clipboard 
Print this post

Hello,

a very simple and fast way of averaging data is the following (I use it for a data logger for noisy signals):

a ... current measured signal
b ... former stored signal
f ... filter constant

The new signal to store is calculated by:

b=(1-f)*b+f*a

For f=1 there is no filtering, for f=0 there is no signal information in b.
I use f=0.3 ... f=0.8 depending on the maximum frequency of information in the signal.

The advantage of this filter is, that it is very fast und does not need much memory space. The disadvantage is that the output signal is delayed.

Greetings

Ingo.
Edited 2021-03-17 20:48 by Ingotron
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025