• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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:

Pommie

Well-Known Member
Most Helpful 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
Most Helpful 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
    addwf    0x20
    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
Most Helpful Member
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 :D

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.

You might also like to give your variables more helpful names?, which would make your code much more readable.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
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
Most Helpful 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 :D
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
    addwf    0x20
    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:

Latest threads

EE World Online Articles

Loading

 
Top