# Calculate Median - Assembly

#### Suraj143

##### Active Member
Is there any example of calculation of median for Three (N=3), 16bit numbers in PIC assembly?

Last edited:

#### Nigel Goodwin

##### Super Moderator
Have you checked the PICList?

#### Diver300

##### Well-Known Member
Is it an 8 bit or a 16 bit PIC?

#### Pommie

##### Well-Known Member
Sort them and pick the middle one. A bubble sort will take a maximum of two passes. Why do you want the median?

Mike.

#### Suraj143

##### Active Member
Hi thanks all.I use pic12F675.

This is for Ultrasonic SR04 sensor.I want to take 3 readings and get the median.Its a small filter in this case.

Somehow If I get the 1st median correctly & to calculate next median do I need to shift the bytes in the array like LIFO buffer?

#### Pommie

##### Well-Known Member
Are you sure you want the median and not the mean? The median is simply the middle value so shifting values to add another doesn't make sense.

Mike.

#### Suraj143

##### Active Member
Hi, I wrote a code.Is there any errors? I hope its ok for me.

Code:
;==========================================================
;Copy 16bit results to Temp regs
;40-45h                 = Time values
;d1,d2,d3,d4,d5,d6         = Temp Regs
;Median                  = d3,d4
;==========================================================
Cal_Median        movf        40h,W
movwf        d1
movf        41h,W
movwf        d2
movf        42h,W
movwf        d3
movf        43h,W
movwf        d4
movf        44h,W
movwf        d5
movf        45h,W
movwf        d6
;
movlw        .2
movwf        Pass_Count

Next_1            call        Comp_1_2
btfss        STATUS,C
goto        Next_2
Swap_1_2        movf        d1,W
movwf        Temp
movf        d3,W
movwf        d1
movf        Temp,W
movwf        d3
;
movf        d2,W
movwf        Temp
movf        d4,W
movwf        d2
movf        Temp,W
movwf        d4

Next_2            call        Comp_2_3
btfss        STATUS,C
goto        Cal_Pass
Swap_2_3        movf        d3,W
movwf        Temp
movf        d5,W
movwf        d3
movf        Temp,W
movwf        d5
;
movf        d4,W
movwf        Temp
movf        d6,W
movwf        d4
movf        Temp,W
movwf        d6

Cal_Pass        decfsz        Pass_Count,F
goto        Next_1
return                ;d3,d4 = Median
;------------------------------------------
Comp_1_2        movf        d3,W
subwf        d1,W
btfss        STATUS,Z
return
movf        d4,W
subwf        d2,W
return

Comp_2_3        movf        d5,W
subwf        d3,W
btfss        STATUS,Z
return
movf        d6,W
subwf        d4,W
return

#### Diver300

##### Well-Known Member
The way that you swap two registers isn't the most efficient. You can save a couple of lines of code and a temporary register with either of these:-

Code:
this:-
movf    0x20, w
xorwf    0x21, w
xorwf    0x20
xorwf    0x21

or this:-
movf    0x20, w
subwf    0x21, w
subwf    0x21
However, you don't need to actually swap the registers at all. You can just work out which is the median value and collect it at the end.

This code compares V1 with V2, then V1 with V3 and then V2 with V3. From the three comparisons, there are 8 (2^3) results, but it turns out that 2 of those aren't possible, leaving 6 possible combinations. I found that using the result of the comparison of V2 and V3 to invert the other results gave the same outcome, and only three possible combinations, and those are used to select the final answer.

This code is shorter, takes less than half the time, and only uses one register other than the input and result registers, instead of six.

Code:
Cal_Median            clrf    Temp

movf    0x40, w
subwf    0x42, w
btfss   STATUS,Z
goto    comp_1_2_done
movf    0x41, w
subwf    0x43, w
comp_1_2_done    btfss   STATUS,C
bsf        Temp, 0

movf    0x40, w
subwf    0x44, w
btfss   STATUS,Z
goto    comp_1_3_done
movf    0x41, w
subwf    0x45, w
comp_1_3_done    btfss   STATUS,C
bsf        Temp, 1

movf    0x42, w
subwf    0x44, w
btfss   STATUS,Z
goto    comp_2_3_done
movf    0x43, w
subwf    0x45, w
comp_2_3_done    movlw    0x3
btfss   STATUS,C
xorwf    Temp            ;Temp is now 0 for 42/43
;1 for 40/41
;3 for 44/45

btfsc    Temp, 1
goto    use_44_45

btfsc    Temp, 0
goto    use_40_41

movf    0x42, w
movwf    d3
movf    0x43, w
goto    sort_done

use_44_45        movf    0x44, w
movwf    d3
movf    0x45, w
goto    sort_done

use_40_41        movf    0x40, w
movwf    d3
movf    0x41, w
sort_done        movwf    d4
return

#### Nigel Goodwin

##### Super Moderator
I think you need to rethink what you're doing?.

Presumably you're essentially just adding the three results together, and then dividing by three.

This is much more awkward than it needs to be - so don't use three readings

If you change to either two readings, or four readings, division becomes a simple shift operation - far faster, far smaller and far easier to write.

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
I don't even divide.... I sum several ADC readings and just use that... Most calculations are done using multiply and divide.. If you have a larger number the result is more accurate.. I read a sensor 24 times ( to remove any fluctuations ) then just divide down.. Most pics will do 24 samples in less than 50mS so its very do-able.

#### Diver300

##### Well-Known Member
The technique that I use is to put in damping, much like an RC network but done in code. That can be done by adding each reading into a total, and subtracting a proportion of the total from the total each time. The total is larger than the average of the reading by the reciprocal of the proportion.

As an example, if the reading is added every millisecond, and 1/256 of the total is subtracted from the total every millisecond, then the total will end up 256 times larger than the average reading, and will be damped with a time constant of about 256 ms.

That sort of calculation is quite easy to perform in a PIC. Dividing by 256 in an 8 bit pic is just a matter of using the next register along. The register for the total always needs to be more bits than the reading, so a 16 bit reading would need a 24 bit total. In some cases that is more registers, but where there is a 10 bit ADC, the total can be 16 bits, so two bytes are needed anyhow.

That technique has the advantage of using very few registers, and the action each sample time is always the same.

#### Pommie

##### Well-Known Member
He asked for the median not the mean but I've no idea why.

Mike.

#### Nigel Goodwin

##### Super Moderator
He asked for the median not the mean but I've no idea why.

Mike.
From his user name it's a reasonable bet English isn't his first language, and the differences are pretty vague even if it is

#### Pommie

##### Well-Known Member
From his user name it's a reasonable bet English isn't his first language, and the differences are pretty vague even if it is
But the code he posted returns the median not the mean. I also thought it was a language thing but the code proves otherwise.

Mike.

#### Suraj143

##### Active Member
Hi all thanks for the replies.I'm doing a "median check" & not a mean check."Mean Value" is only good for analog readings, Takes multiple samples & divide by nos samples.

When it comes to ultrasonic which is measurung the time it needs to calculate the "median value". That is due to unexpected results happens in most cheap ultrasonic sensors output.

#### Suraj143

##### Active Member
The way that you swap two registers isn't the most efficient. You can save a couple of lines of code and a temporary register with either of these:-

Code:
this:-
movf    0x20, w
xorwf    0x21, w
xorwf    0x20
xorwf    0x21

or this:-
movf    0x20, w
subwf    0x21, w
subwf    0x21
However, you don't need to actually swap the registers at all. You can just work out which is the median value and collect it at the end.

This code compares V1 with V2, then V1 with V3 and then V2 with V3. From the three comparisons, there are 8 (2^3) results, but it turns out that 2 of those aren't possible, leaving 6 possible combinations. I found that using the result of the comparison of V2 and V3 to invert the other results gave the same outcome, and only three possible combinations, and those are used to select the final answer.

This code is shorter, takes less than half the time, and only uses one register other than the input and result registers, instead of six.
That is a nice piece of code. Many thanks.Surely I'm going to use this one.Double sorting is no need for 3 elements as you suggest.

To fill up my 40-45h buffer, I read 3 samples continuosely & place them one after the other & do the Median check.

Last edited: