Searching \ for 'linearization of table' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page:
Search entire site for: 'linearization of table'.

Truncated match.
PICList Thread
'linearization of table'
1998\10\08@161319 by Joao Batista

Would anybody have how to help me to solve a problem, although simple,
but not for a less experienced user?

I am using a sensor of pressure and an operational one that supplies me
the following values:

PSI      Volts

0          1,183
5          1,440
10        1,773
15        2,092
20        2,471
25        2,823
30        3,150
35        3,460
40        3,750

When using a test routine multiplying the value of ADRES (PIC16C74A) for
16 and the routine bin_bcd I get to obtain a reading in display of 40,80
when in full scale (255).

But as there is not linear of the circuit in subject, I don't get to
maintain a proportional value in the display to input of  PIC.

How make a table that maintains the proportion?

Does a formula exist for this problem?

If somebody possesses an answer, I would thank if  could send me.

Thank you

Joco Batista - /

1998\10\08@165344 by Larry Teague


Steve's Workbench, from Radio Shack, has an article discussing the use of a
thermistor with a Basic Stamp II.  The article has a clear explanation of
linearization and even has a simple Gauss fit program in basic.  You can
find the article at

Hope it helps,

{Quote hidden}


1998\10\08@174725 by Sean Breheny

face picon face
Hi Joco,

You can use the table that you just showed here, and then use linear
interpolation between the points.

(NOTE: I will use the english "." convention for the decimal point, instead
of the ",")

For example, between 10 and 15 psi, you get about 0,0638 volts per psi. So,
if the measured input voltage falls between 1.773 and 2.092, like, for
example, 2.000 volts, you do the following:

2.000 - 1.773 = 0.277

0.277 / 0.0638 = 3.56 psi

final reading: 13.56 psi,  which I think you will find to be very close to
the real value.

You do this for every point in your table (i.e. you calculate this "slope"
factor between 0 and 5, between 5 and 10, etc) and then put them in a
lookup table. You also put the base values in another table. So, in your case:

Vb                          S
1.183                        .0514
1.440                        .0666
1.773                        .0638
2.092                        .0758
2.471                     .0704
2.823                        .0654
3.150                     .0620
3.460                         .0580
3.750                         .0580 (Just make it the same as the last one)

So, your pic does the following:

1) Get value from ADC
2) Look up ADC value and see between which two Vb values it falls, and pick
the lower of the
3) Look up the corresponding S value and compute the PSI: psi = (Vadc - Vb)/S

Now, of course, this would require floating point division and floating
point comparison, and there are ways to make this better for the PIC:

1) Don't put floating point values of Vb into the table. Instead, store the
actual code that you will get from the ADC.

2) Instead of picking the values of the table to be evenly spaced as far as
PSI goes, pick them to be evenly spaced as far as Vb goes, and pick them so
that the number which you get from the ADC has zeros in as many of its
lower bits as possible (so if the interval between table ADC values is,
say, 4, and you start at a multiple of four, then the lowest two bits of
each table ADC value will be zero) This allows you to eliminate the
floating point compare from the table lookup process. You can just see if
the upper 6 bits of the value you read from the ADC are the same as the
upper 6 bits of a value in the table, and select that one.

3) If you use more points than you have given here, your answer will be
more accurate. Not only that, but the slope values will not matter as much,
and you can round them off to be powers of two, so that the floating point
division just becomes an integer binary right shift (pic instruction RRF)

I know that this is not very clear. Please feel free to email me privately
and I will explain it further.

Good luck,


At 05:04 PM 10/8/98 -0300, you wrote:
{Quote hidden}

| Sean Breheny                   |
| Amateur Radio Callsign: KA3YXM |
| Electrical Engineering Student |
Save lives, please look at
Personal page:  Phone(USA): (607) 253-0315 ICQ #: 3329174

1998\10\09@050149 by Dr. Imre Bartfai


I have checked the data using the regression analysis technique, and the
connection is LINEAR. The estimated formula is:

PSI = -17.20598 + Volts * 15.12302

Any better pocket calculator would do also this fit. However, to check
whether the connection is really linear, is a bit (not very) harder.

I hope this helps you.


On Thu, 8 Oct 1998, Joao Batista wrote:

{Quote hidden}

1998\10\09@114046 by Joao Batista

Dear Sean,

I received its solution proposal for my problem, only that I didn't understand
very well, as to use a routine of floating point.
It is probable that due to my lack of experience in division with floating point
is hindering my understanding.
I please request its help in this point, if it is possible..


Joco Batista

Sean Breheny wrote:

{Quote hidden}

1998\10\09@114437 by evd

> From: Joao Batista <KILLspamjq96KILLspamspamCLARET.COM.BR>
> Subject: linearization of table

Although not an exact solution to the PSI-to-Volts problem posed, the
following code is probably directly usable with little modification.

It's an example of piece-wise linearization.  Ie., a sensor that's
very non-linear over its full-range is often "linear enough" across
segments of its range.

This is 1st-pass, *but* functional code; a fragment of a 12c672 based
temperature sensor project.  Optimization is clearly possible, especially
for register use.  But, the simple "block" code is more straight-forward.

To build the piece-wise linearization tables, calculate the x_data
points (0-255 atod values) for convenient y_data points (deg_F with
perfect deg_C equivalents in this case).

                       +---[ thermistor ]---< Vdd
  12c672 GP0/AN0: o----+        10k
                       +-------\/\/\/-------> Vss


     cblock _ram_              ; registers
       x_dat                           ;copy of adc data
       idx                             ;coordinate look-up index, bit count
       x1,x2                           ;x1,x2 coordinates
       y1,y2                           ;y1,y2 coordinates
       rpt,xpt,ypt,zpt                 ;linearization multiply,division regs

; use example:

       movlw   89                  ;example adc value
       call    set_xy              ;set x1,x2 y1,y2 coordinates
       call    lin_xy              ;linearize

; entered with w=X, returns x1,x2 and y1,y2 coordinates from x_tbl,y_tbl
; such that X is between x1,x2 (x1<=X<x2)

set_xy: movwf   x_dat                   ;save X data
       movlw   (y_tbl-x_tbl)-1         ;length of x_tbl -1
       movwf   idx                     ;init index
s1_xy:  decf    idx,f                   ;next location's index
       movlw   x_tbl                   ;start of x_tbl
       call    nxtbl                   ;get data at tbl+idx
       subwf   x_dat,w                 ;w= x_dat-w
       btfss   status,c                ;skips next if carry_set
       goto    s1_xy                   ;c_clr -- x_dat < tbl_dat

       movlw   x_tbl                   ;else -- x_dat >= tbl_dat
       call    nxtbl                   ;get data at tbl+idx
       movwf   x1                      ;save
       movlw   x_tbl+1
       call    nxtbl                   ;get data at tbl+idx
       movwf   x2                      ;save
       movlw   y_tbl
       call    nxtbl                   ;get data at tbl+idx
       movwf   y1                      ;save
       movlw   y_tbl+1
       call    nxtbl                   ;get data at tbl+idx
       movwf   y2                      ;save

nxtbl:  addwf   idx,w                   ;index table location
       movwf   pcl                     ;returns data at pcl in w

; x,y coordinate pair lookup tables for -22F (-30C) to 122F (+50C)
; equal length, in ascending order, 1st & last xy_pairs for range guard

; x= (ysi44006 thermistor to vdd with 10k to vss), y= (deg_f)

x_tbl: dt   0, 18, 23,29,36,44,54,65,76,89,101,115,128,140,152,164,174,184,255
y_tbl: dt -40,-22,-13,-4, 5,14,23,32,41,50, 59, 68, 77, 86, 95,104,113,122,212

; coordinate linearization: x1,x2 -- y1,y2
; return w= ((y2-y1)/(x2-x1)) * (X-x1) + y1

lin_xy: movf    x1,w
       subwf   x_dat,w                 ;w= x_dat-x1
       movwf   xpt                     ;set x_part= x_dat-x1
       movf    y1,w
       subwf   y2,w                    ;w= y2-y1
       movwf   zpt                     ;set z_part= y2-y1
       movf    x1,w
       subwf   x2,w                    ;w= x2-x1
       movwf   ypt                     ;set y_part= x2-x1
       call    scale                   ;xpt= xpt*zpt/ypt
       movf    xpt,w
       addwf   y1,w                    ;w= xpt+y1

scale:  ;   x= x*z/y    y & z are unchanged
       ;               x,y,z are 8-bit, (x*z) <= 15-bits

#define bcnt    idx

mult:                               ; r:x <- x*z
       movlw   8
       movwf   bcnt                    ;set bit count
       clrf    rpt                     ;clear ms8 of product
       bcf     status,c                ;clear carry
       rrf     xpt,f                   ;lsb of multiplier into carry
mul1:   btfss   status,c
       goto    mul2                    ;carry was clear
       movf    zpt,w
       addwf   rpt,f                   ;prod_ms8 += multiplicand
mul2:   rrf     rpt,f                   ;align 16-bit product, r:x
       rrf     xpt,f                   ;(prod_ls8 replaces multiplier)
       decfsz  bcnt,f                  ;loop thru bits
       goto    mul1

divi:                               ; x <- r:x/y (remainder in r)
       movlw   8
       movwf   bcnt                    ;set bit count
div1:   bcf     status,c                ;dividend *2
       rlf     xpt,f
       rlf     rpt,f
       movf    ypt,w                   ;subtract divisor from dividend ms_8
       subwf   rpt,f
       btfss   rpt,7                   ;check if msb set
       goto    div2                    ;ok -- bit clear
       movf    ypt,w                   ;else set -- undo previous sutraction
       addwf   rpt,f
       goto    div3
div2:   incf    xpt,f                   ;count previous subtraction
div3:   decfsz  bcnt,f                  ;loop thru bits
       goto    div1

#define round_up

       ifdef   round_up            ; round-up result -- destroys remainder
       bcf     status,c                ;remainder *2 for rounding
       rlf     rpt,f
       movf    ypt,w                   ;subtract divisor from rmdr*2
       subwf   rpt,f
       btfss   status,c                ;skip next on carry set
       goto    divx                    ;else carry clear -- 2*r < divisor
       incf    xpt,f                   ;round x up


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