Getting central value in a list

coparu67

Senior Member
Hi
In a list, how do I get the center value in a fast way?

I've got a sensor, but sometimes it sends incorrect values.
What I am thinking is to try 5 measures and take the central value. It's enough for me.
For example, if I get : 78, 84, 83, 0, 85, the central value is 83 (0-78-83-84-85)

Let say that values are in b0, b1, b2, b3 and b4.
How do I implement code to do this task?
Thanks
 

MartinM57

Moderator
Not sure that the "central" one is the one to take?

Here's some code that takes 12 readings from a potentiometer and averages them excluding the max and min (worked well for me) i.e it averages 10 readings

Code:
symbol POT_ADC = b0
symbol POT_ADC_1 = b1
symbol POT_ADC_2 = b2
symbol POT_ADC_3 = b3
symbol POT_ADC_4 = b4
symbol POT_ADC_5 = b5
symbol POT_ADC_6 = b6
symbol POT_ADC_7 = b7
symbol POT_ADC_8 = b8
symbol POT_ADC_9 = b9
symbol POT_ADC_10 = b10
symbol POT_ADC_11 = b11
symbol POT_ADC_12 = b12
symbol MAX_ADC = b18
symbol MIN_ADC = b19

symbol POT_WIPER_PIN = C.4

	readadc POT_WIPER_PIN, POT_ADC_1
	readadc POT_WIPER_PIN, POT_ADC_2
	readadc POT_WIPER_PIN, POT_ADC_3
	readadc POT_WIPER_PIN, POT_ADC_4
	readadc POT_WIPER_PIN, POT_ADC_5
	readadc POT_WIPER_PIN, POT_ADC_6
	readadc POT_WIPER_PIN, POT_ADC_7
	readadc POT_WIPER_PIN, POT_ADC_8
	readadc POT_WIPER_PIN, POT_ADC_9
	readadc POT_WIPER_PIN, POT_ADC_10
	readadc POT_WIPER_PIN, POT_ADC_11
	readadc POT_WIPER_PIN, POT_ADC_12

	'find highest and lowest
	MIN_ADC = POT_ADC_1 MAX POT_ADC_2 MAX POT_ADC_3 MAX POT_ADC_4 MAX POT_ADC_5 MAX POT_ADC_6 MAX POT_ADC_7 MAX POT_ADC_8 MAX POT_ADC_9 MAX POT_ADC_10 MAX POT_ADC_11 MAX POT_ADC_12
	MAX_ADC = POT_ADC_1 MIN POT_ADC_2 MIN POT_ADC_3 MIN POT_ADC_4 MIN POT_ADC_5 MIN POT_ADC_6 MIN POT_ADC_7 MIN POT_ADC_8 MIN POT_ADC_9 MIN POT_ADC_10 MIN POT_ADC_11 MIN POT_ADC_12
	
	'average pot reading excluding highest and lowest by adding them all together and then subtracting the max and the min, then dividing by 10
	POT_ADC = POT_ADC_1 + POT_ADC_2 + POT_ADC_3 + POT_ADC_4 + POT_ADC_5 + POT_ADC_6 + POT_ADC_7 + POT_ADC_8 + POT_ADC_9 + POT_ADC_10 + POT_ADC_11 + POT_ADC_12 - MIN_ADC - MAX_ADC / 10
...could be done in a 12x loop keeping track of max and min etc, but I like loop-free programs :)
 

AllyCat

Senior Member
Hi,

One solution is a classic "bubble sort" algorithm. There are several threads, for example this.

But here is a version to simulate (not rigorously tested) that I've literally just thrown together. No doubt hippy can/will come up with something much more elegant. ;)

Code:
#terminal 4800
b0 = 5 : b1 = 14 : b2 = 3 : b3 = 12 : b4 = 1

	for bptr = 0 to 4         ; Report initial list
		sertxd(#@bptr," ")
	next
	sertxd(cr,lf)
sort:
	bptr = 0
	do 
swp:
		if @bptrinc > @bptrdec then       ; swap @bptr and @bptr+1
			b5 = @bptrinc
			b6 = @bptr
			@bptrdec = b5
			@bptr = b6   
			if bptr > 0 then 
				dec bptr
				goto swp
			endif
		else
			inc bptr	
		endif
	loop while bptr < 4

for bptr = 0 to 4            ; Report final list
	sertxd(#@bptr," ")
next
sertxd(cr,lf,"Middle Value is ",#b2)
Cheers, Alan.
 

AllyCat

Senior Member
Hi,

In my program above, the bptr moves one step backwards or forwards through the list, dependent on whether a swap was made or not. However, I see that several other snippets on the forum simply go back to the start when a swap is made. I don't believe that is quite as efficient, but it's simpler and with only five numbers probably doesn't make much difference to the speed.

So here is an updated "fun" version which doesn't (need to) use any of the "normal" variables. I have set the byte pointer to overlay b0 - b4 , but any region in RAM (up to potentially 511 for most M2s) could be used. SWAP cannot be used with @bptrinc, but the alternative XOR method is actually more efficient anyway. ;)

Excluding the test harness, the core program code is about 33 bytes.

Code:
#terminal 4800
#no_data

symbol FIRST = 0       ; Pointer to byte variables
symbol MIDDLE = 2
symbol LAST = 4

do
	for bptr = FIRST to LAST         ; Create and Report random list
		random w3
		@bptr = w3 // 10		     ; Select the range for Random numbers
		sertxd(#@bptr," ")
	next
	sertxd(cr,lf)
sort:
	for bptr = FIRST to LAST
		if @bptrinc > @bptrdec then       ; Swap @bptr and @bptr+1
			@bptr = @bptrinc xor @bptr
			@bptr = @bptrdec xor @bptr			
			@bptr = @bptrinc xor @bptr	
			goto sort
		endif
	next

	for bptr = FIRST to LAST            ; Report final list
		sertxd(#@bptr," ")
	next

	bptr = MIDDLE
	sertxd(cr,lf,"Middle Value is ",#@bptr,cr,lf)
loop
Cheers, Alan.
 

coparu67

Senior Member
Thanks MartinM57
Your solution will be very useful to me with other sensors, and the code is very readable.
 

AllyCat

Senior Member
Hi,

They are also showing another example of the Simulator(s) not behaving the same as the real chips !

I'll try to work out a version that actually works correctly in both ! :confused:

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

I've started a new thread to discuss the discrepancy between the Simulator and real chips, but here is a bugfixed version to work around the issue for now.

The "Step back" method is about twice as fast as the "Reset pointer" version, so I've reinstated that. But the pointer must not start at variable/RAM location = zero, because it needs to detect bptr-1. However, I have removed the FOR .. NEXT structure as its behaviour is potentially rather "obscure". The program still seemed reasonably fast when tested with 17 numbers.

Code:
#terminal 4800
#no_data
;#define simulating			; Uncomment for PE5 simulation only 

symbol FIRST = 2     	  		; Pointer to byte variables Must be > 0
symbol MIDDLE = 4
symbol LAST = 6

	pause 2000					; Wait for terminal to open
	sertxd("Start",cr,lf)
do
	bptr = FIRST
	for bptr = FIRST to LAST     	    ; Create and Report random list
		random w0 : random w0 
		random w0 : random w0
		@bptr = w0 // 10		         ; Select the range for Random numbers
		sertxd(#@bptr," ")
	next
	sertxd(cr,lf)

sort:
	bptr = FIRST
do
sorti:
#ifdef simulating
	if @bptrinc > @bptr then         ; Swap @bptr with @bptr+1   
#else
	if @bptr < @bptrinc then         ; Required syntax for real PICaxe 
#endif
		@bptr = @bptrdec xor @bptr         ; bptr moves to 0
		@bptr = @bptrinc xor @bptr		; bptr = 1	
;;		@bptrdec = @bptrdec xor @bptr     ; bptr = -1  ; Doesn't work with PE5 download
		@bptr = @bptrdec xor @bptr     ; bptr = 0      ; Required for PE5
		dec bptr      		; bptr = -1     ; Required for PE5
		if bptr => FIRST then sorti       ; Step-Back version (Comment out for Reset version):
		goto sort                     ; Reset version
	endif
loop while bptr < LAST
 
	for bptr = FIRST to LAST            ; Report final list
		sertxd(#@bptr," ")
	next
 	bptr = MIDDLE
	sertxd(cr,lf,"Middle Value is ",#@bptr,cr,lf)
loop
Cheers, Alan,
 
Last edited:

AllyCat

Senior Member
Hi,

Back to the OP; It's amazing what a forum search can produce. ;)

This thread dates back to 2006 and does almost exactly what was requested, more than 5 years before I even joined the forum. But all the contributors to that thread (except the OP then) are some of our "big guns" still active on the forum now.

The program in #12 uses exactly the same algorithm as I (independently) used above, but with more conventional (and understandable) variables and PEEK/POKEs. The program needs to be adapted slightly from the 2006 listing, so here is my "translated" version:

Code:
Symbol Var1 = b1
Symbol Var2 = b2
Symbol Address = b0

b6 = 4 : b7 = 6: b8 = 2 : b9 = 5 : b10 = 3
sertxd (cr,lf,#b6," ",#b7," ",#b8," ",#b9," ",#b10)
For Address = 6 to 9  'Load the temp variables
 Peek Address,Var1
 Inc Address
 Peek Address,Var2  'Check and swap variables if necessary
 If Var1 > Var2 Then
  Poke Address,Var1
  Dec Address
  Poke Address,Var2
  if Address > 6 then
   Dec Address   ' bubble the comparison down
  Endif
 Endif
 Dec Address
Next
sertxd (cr,lf,#b6," ",#b7," ",#b8," ",#b9," ",#b10)
For interest, I've only just discovered that it's NOT actually a "Bubble Sort" but a (more efficient) "Insertion Sort" (because bubbles always rise), but the former proved to be a much more useful search term than the latter. BTW, two quite nice animations on those Wikipedia links, :)

Cheers, Alan.
 
Top