Searching \ for '[PIC]: math calibration algorithm ?' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/math/index.htm?key=math
Search entire site for: 'math calibration algorithm ?'.

Exact match. Not showing close matches.
PICList Thread
'[PIC]: math calibration algorithm ?'
2001\03\12@020237 by Vasile Surducan

flavicon
face
Dear piclist guru's,

I have to do an automatic calibration procedure for a transducer.
This will be read by pic internal 10bit AD converter.
Assuming the whole AD range is 1024 and the transducer characteristic
is linear one, I need to read 2 points to determine the correct slope.
Zero will be between 300...400 and full scale between 950 and 1023 and
depends by transducer characteristics and biasing. No external scaling
device like operational amplifiers will be used.
I need interchangeability between various transducers which will match
condition above.
I'm new in pic maths so I was thinking to the following procedure
exemplified with one transducer values, all numbers are in decimal
representation:

1. measuring zero calibration value
  cal_zero = 376
  at cal_zero, displayed value must be tmin=0
2. measuring full scale calibration value
  full_scale = 978
  at full_scale, displayed value must be tmax=98.9
3. determine real scale
  real_scale = full_scale - cal_zero
  real_scale = 602
4. compute slope
  slope = real_scale/tmax
  slope = 602/98.9 = 6.08
  I want to use only fixed point unsigned math routine so I need some
trick
for this division:
  integer_slope = 10*602/989 = 6, remainder_lo=86
I will use 16bit division routine and check:
if remainder_hi = 0 then
 100*remainder_lo/tmax = fraction_slope_lo
 fraction_slope_hi = 0
 100*86/989 = 8; new_remainder is not important
elsif remainder_hi > 0 then
 10*remainder_hi:lo/tmax = fraction_slope_hi:lo
end if
At this moment I know 100*slope = 608
5. determine real displayed value
  real_value = 100*(measured_value-376)/100*slope
  real_value_t_max = 100*602/608 = 99.1  (full scale display)
  real_value_t_min = 100*1/608 = 0.16 ( first display greater than 0 )
 This division will be computed in same way like above one.
  I will have an error of about 0.2% at full scale which is enough.

Now the question: could be done this computation into an easy way ?
Here I must use 16b substraction, 16b multiply, 16b division and some
conversion from hex to decimal.

Thank's for your existence,
Vasile

--
http://www.piclist.com hint: To leave the PICList
spam_OUTpiclist-unsubscribe-requestTakeThisOuTspammitvma.mit.edu


2001\03\13@015917 by Vasile Surducan

flavicon
face
Well, I said "  Thank's for your existence, "
but it seems you're not at home... or my english stink's...


On Mon, 12 Mar 2001, Vasile Surducan wrote:

{Quote hidden}

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads


2001\03\13@081535 by Drew Vassallo

picon face
> >    real_value_t_max = 100*602/608 = 99.1  (full scale display)

The only potential problem I see with this (the logic looks good by the way)
is that 100*656 > 16 bits.  Your max value can't be larger than 655 for this
to work.  Since you're already at 602 for this example, I guess there's the
potential for you to overflow your dividend past 65535.

Just a quick observation.

--Andrew
_________________________________________________________________
Get your FREE download of MSN Explorer at http://explorer.msn.com

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads


2001\03\13@083251 by Vasile Surducan

flavicon
face
Good observation !
I wasn't think at...

On Tue, 13 Mar 2001, Drew Vassallo wrote:

{Quote hidden}

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads


2001\03\13@120916 by Nikolai Golovchenko

flavicon
face
I think it can be done a bit easier.

1. Calculating slope. slope=(full_scale-cal_zero)/100. Here a fixed
point division would be useful that takes at least 10 bits for
dividend, 7 bits for divisor and the result as fixed point, say 3Q8
(11 bits is 0.05% accuracy at the full scale).

2. Calculating real value. real_value=(measured_value-cal_zero)/slope.
Here you need a subtraction and division again. A nice trick is
possible to use just one divide routine! The only significant
difference is that you need the result as 7Q8 (0-100 range with a few
fraction bits).

So, the common divide routine should take:
       dividend = 10 bits or more in integer format
       divisor = 15 bits in 7Q8 format
and produce:
       quotient = 15 bits in 7Q8 format

3. Displaying the results. Depending on how much digits after the
point you display, multiply the 7Q8 result by 10 (to get 1 fraction
decimal digit) or 100 (2 fraction decimal digits) and leave only the
integer bits of the result. Multiplication by a constant is easy, if
you use the online constant multiplication code generator or a
regular multiplication routine.

Then convert the integer result to decimal, using a routine at
piclist.com (there is one for 0-999 range and another for 0-65535 -
one of them should fit).

That's it!

Try this for division:

;-----------------------------------------------------------------------------
; Input:
;  a1:a0 - 10 bit dividend
;  b1:b0 - 15 bit divisor in 7Q8 format (b1 is integer, b0 is
;          fractional)
; Output:
;  c1:c0 - 15 bit quotient in 7Q8 format
;
; Temporary:
;  temp - current remainder extension (used for intermidiate calculations
;                only)
;  count - counter
;
;-----------------------------------------------------------------------------
div_uint10_fxp7q8_fxp7q8

;left align the dividend
; (shift accumulator left 1 bit to get the first result bit weight
;  equal to 128)
       clrc
       rlf     a0, f
       rlf     a1, f
;initialize registers
       clrf temp                  ;clear remainder
       movlw 15                   ;15 iterations
       movwf count
       clrf c0                    ;clear result - it will be used
       clrf c1                    ;to shift zeroes to dividend
div_loop
       rlf c0, f                  ;shift in next result bit
       rlf c1, f
       rlf a0, f                  ;and shift out next bit of dividend
       rlf a1, f                  ;to remainder
       rlf temp, f

       movf b0, w                 ;load w with lower divisor byte
       btfsc temp, 7              ;if remainder positive - subtract,
        goto div_add              ;if negative - add
       ;subract
       subwf a0, f
       movf b1, w
       skpc
        incfsz b1, w
         subwf a1, f
       movlw 1
       skpc
        subwf temp, f
       goto div_next
div_add
       ;add
       addwf a0, f
       movf b1, w
       skpnc
        incfsz b1, w
         addwf a1, f
       movlw 1
       skpnc
        addwf temp, f
div_next
;here carry has a new result bit
       decfsz count, f
        goto div_loop
;shift in last result bit
       rlf c0, f
       rlf c1, f
       return
;-----------------------------------------------------------------------------

Good luck!
Nikolai

---- Original Message ----
From: Vasile Surducan <.....vasileKILLspamspam@spam@L30.ITIM-CJ.RO>
Sent: Monday, March 12, 2001 9:01:13
 To: PICLISTspamKILLspamMITVMA.MIT.EDU
Subj: [PIC]: math calibration algorithm ?

{Quote hidden}

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads


2001\03\13@130905 by Nikolai Golovchenko

flavicon
face
Just thought that once we have only 15 bits in divisor, the routine
can be optimized quite a bit:

;-----------------------------------------------------------------------------
; Input:
;  a1:a0 - 10 bit dividend   (a0 - lower byte)
;  b1:b0 - 15 bit divisor in 7Q8 format (b1 is integer, b0 is
;          fractional)
; Output:
;  c1:c0 - 15 bit quotient in 7Q8 format
;
; Temporary:
;  count - counter
;
;-----------------------------------------------------------------------------
div_uint10_fxp7q8_fxp7q8

;left align the dividend
; (shift accumulator left 1 bit to get the first result bit weight
;  equal to 128)
       clrc
       rlf     a0, f
       rlf     a1, f              ;carry is cleared here
;initialize registers
       movlw 15                   ;15 iterations
       movwf count
       clrf c0                    ;clear result - it will be used
       clrf c1                    ;to shift zeroes to dividend
div_loop
       rlf c0, f                  ;shift in next result bit
       rlf c1, f
       rlf a0, f                  ;and shift out next bit of dividend
       rlf a1, f                  ;to remainder

       movf b0, w                 ;load w with lower divisor byte
       skpnc                      ;if remainder positive - subtract,
        goto div_add              ;if negative - add
       ;subract
       subwf a0, f
       movf b1, w
       skpc
        incfsz b1, w
         subwf a1, f
       goto div_next
div_add
       ;add
       addwf a0, f
       movf b1, w
       skpnc
        incfsz b1, w
         addwf a1, f
div_next
;here carry has a new result bit
       decfsz count, f
        goto div_loop
;shift in last result bit
       rlf c0, f
       rlf c1, f
       return
;-----------------------------------------------------------------------------


Nikolai

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads


2001\03\14@004707 by Scott Dattalo

face
flavicon
face
On Tue, 13 Mar 2001, Nikolai Golovchenko wrote:

> Just thought that once we have only 15 bits in divisor, the routine
> can be optimized quite a bit:

And there's another trick to optimize it further. But before going there,
I have a question. Why do you want to add the divisor (b) to the dividend
(a) when the msb of the dividend is set? In other words, when you shift the
dividend left and the carry get set, then yes, you unconditionally want to
perform the subtraction. However, if the carry doesn't get set then you need to
perform a comparison to see if dividend is less than the divisor. This
comparison can be a subtraction, but if it turns out that the dividend is not
greater than the subtraction has to be restored. Or am I'm missing something?

Let's assume that I don't undertand the algorithm and that what's below is
correct. Here's a cute trick to save a few cycles (I learned this one from Andy
Warren):

{Quote hidden}

Don't need a count register:

;>         movlw 15                   ;15 iterations
;>         movwf count

>         clrf c0                    ;clear result - it will be used
>         clrf c1                    ;to shift zeroes to dividend

         bsf  c1,2   ; use c0:c1 as the counter after 15 shifts, this
                     ; bit will go to the carry.

> div_loop

move the c0:c1<<1 down below
;>         rlf c0, f                  ;shift in next result bit
;>         rlf c1, f

{Quote hidden}

        rlf c0, f                  ;shift in next result bit
        rlf c1, f

Don't need this counter anymore:
>         decfsz count, f
>          goto div_loop

       skpc                      ;did the "count" bit pop out?
        goto  div_loop

       return

don't need this any more:
> ;shift in last result bit
>         rlf c0, f
>         rlf c1, f
>         return
> ;-----------------------------------------------------------------------------


Scott

--
http://www.piclist.com hint: The list server can filter out subtopics
(like ads or off topics) for you. See http://www.piclist.com/#topics


2001\03\14@022504 by Nikolai Golovchenko

flavicon
face
Good idea. Usually this trick is not useful for integer division,
because the dividend is usually used for storing the result (dividend
and quotient sharing the same location). But here we have a separate
memory for output, so it works! Using the trick, 3 words / 3 cycles /
1 register are saved. I just had to correct the bit you set, it should
have been c0.1.

;-----------------------------------------------------------------------------
; Input:
;  a1:a0 - 10 bit dividend
;  b1:b0 - 15 bit divisor in 7Q8 format (b1 is integer, b0 is
;          fractional)
; Output:
;  c1:c0 - 15 bit quotient in 7Q8 format
;
; Size: 27 words
; Time: 2+3+3+15*(2+3+7+5)-1+2=264 instruction cycles
;
;-----------------------------------------------------------------------------
div_uint10_fxp7q8_fxp7q8

;left align the dividend
; (shift accumulator left 1 bit to get the first result bit weight
;  equal to 128)
       clrc
       rlf     a0, f
       rlf     a1, f              ;carry is cleared here
;initialize registers
       clrf c0                    ;clear result - it will be used
       clrf c1                    ;to shift zeroes to dividend
       bsf c0, 1                  ;15 iterations
div_loop
       rlf a0, f                  ;and shift out next bit of dividend
       rlf a1, f                  ;to remainder

       movf b0, w                 ;load w with lower divisor byte
       skpnc                      ;if remainder positive - subtract,
        goto div_add              ;if negative - add
       ;subract
       subwf a0, f
       movf b1, w
       skpc
        incfsz b1, w
         subwf a1, f
       goto div_next
div_add
       ;add
       addwf a0, f
       movf b1, w
       skpnc
        incfsz b1, w
         addwf a1, f
div_next
;here carry has a new result bit
       rlf c0, f                  ;shift in next result bit
       rlf c1, f
       skpc
        goto div_loop
       return
;-----------------------------------------------------------------------------

This routine uses a non-restoring algorithm. The nice thing about it
is that it doesn't require a comparison. Each iteration does either
addition or subtraction, but never both. Therefore, it is almost two
times faster comparing to the restoring algorithm.

First, divisor is subtracted from dividend (lets call it the
remainder). Depending on inputs/outputs types the divisor should be
aligned relative to the remainder, so that the first result bit has an
appropriate weight (128 in our case), but let's not go into that, this
is exactly how it is always done in a division.

If the remainder becomes negative after subtraction, the next result
bit should be zero. This is the value of carry after subtraction,
which is convenient. Next iteration we shift the remainder left and
add the divisor to it. This is equivalent to the restoring method,
where divisor is added to remainder to restore it, then remainder shifted
left, and divisor subtracted again. In both methods we add a divisor
in fact. The result of two iterations is:

1) Non-restoring: remainder = remainder - divisor + divisor/2 = remainder - divisor/2
2) Restoring:     remainder = remainder - divisor + divisor - divisor/2 = remainder - divisor/2

And carry flag is always set correct for addition and subtraction
(subtraction is performed as addition internally, I guess). Don't you
now love the way carry works in PICs!

The routine works, I checked :)

Thanks,
Nikolai

---- Original Message ----
From: Scott Dattalo <EraseMEscottspam_OUTspamTakeThisOuTDATTALO.COM>
Sent: Wednesday, March 14, 2001 7:33:01
 To: PICLISTspamspam_OUTMITVMA.MIT.EDU
Subj: [PIC]: math calibration algorithm ?

{Quote hidden}

;>>         movlw 15                   ;15 iterations
;>>         movwf count

>>         clrf c0                    ;clear result - it will be used
>>         clrf c1                    ;to shift zeroes to dividend

>           bsf  c1,2   ; use c0:c1 as the counter after 15 shifts, this
>                       ; bit will go to the carry.

>> div_loop

> move the c0:c1<<1 down below
;>>         rlf c0, f                  ;shift in next result bit
;>>         rlf c1, f

{Quote hidden}

--
http://www.piclist.com hint: The list server can filter out subtopics
(like ads or off topics) for you. See http://www.piclist.com/#topics


2001\03\14@030515 by Vasile Surducan

flavicon
face
Nikolai, it will take a little to understand everything you told
me here. However, you deserve 20 USD just for the fact you exist
( and don't talk here about the constant code multiplier generator )
I hope it will come soon that day when I would be happy to send you
something.
Thank's also for the divide routine. I've notice some of the AN617 divide
routine does not produce a correct result.
Vasil(i)e





On Tue, 13 Mar 2001, Nikolai Golovchenko wrote:

{Quote hidden}

--
http://www.piclist.com hint: The list server can filter out subtopics
(like ads or off topics) for you. See http://www.piclist.com/#topics


More... (looser matching)
- Last day of these posts
- In 2001 , 2002 only
- Today
- New search...