Lookup table example

kallileo
2018-10-18
2018-10-19
  • kallileo - 2018-10-18

    I use a level sensor to measure liquid level in a non linear tank and I need to convert the measured level in mm to volume in liters.
    The look up table of the tank looks like below:

    mm : lt
    0 : 53
    10 : 78
    20 : 99
    .
    .
    1990:13423
    2000: 13478

    The values in between 0-9, 10-19 etc will be calculated using linear interpolation.
    Any suggestions or programing examples on how to implement the aforementioned algorithm are welcomed.

    I think the values in the table should be entered into a two dimentional array and then I need to make a search for an appropriate value.

     
  • Ciprian - 2018-10-19

    I prefer to have a struct like this:

    TYPE udtSoundingTable :
    STRUCT
       Level : ARRAY [0..10] OF REAL;
       Volume : ARRAY [0..10] OF REAL;
    END_STRUCT
    END_TYPE
    

    As for the code, I use a modified binary search.
    As parameters, I pass my level array and the actual level of the tank and the function will return the upper and lower indexes between which my value is.

    FUNCTION FindClosest1D
    VAR_INPUT
       key : REAL;
    END_VAR
    VAR_IN_OUT
       arr : ARRAY [*] OF REAL;
    END_VAR
    VAR_OUTPUT
       out1 : INT;
       out2 : INT;
    END_VAR
    VAR
       size : DINT;
       i: INT;
       j: INT;
       middle: INT;
    END_VAR
    
    //Binary search
    size := UPPER_BOUND(arr,1);
    IF key <= arr[0] THEN
       out1 := 0;
       out2 := 0;
       RETURN;
    END_IF
    IF key >= arr[size] THEN
       out1 := TO_INT(size);
       out2 := TO_INT(size);
       RETURN;
    END_IF
    i := 0;
    j := TO_INT(size);
    middle := 0;
    WHILE (i < j) DO
       
       middle := (i+j)/2;
       IF key = arr[middle] THEN
           out1 := middle;
           out2 := middle;
           RETURN;
       END_IF
       
       IF key < arr[middle] THEN
          
          IF (middle > 0) AND (key > arr[middle - 1]) THEN
             
             IF key < 0 THEN
                 out1 := middle - 1;
                 out2 := middle;
             ELSE
                 out1 := middle;
                 out2 := middle - 1;
             END_IF
             RETURN;
          END_IF
          
          j := middle;
             
       ELSE
          
          IF (middle < size ) AND (key < arr[middle + 1]) THEN
              out1 := middle;
              out2 := middle + 1;
              RETURN;
          END_IF
     
          i := middle + 1;
          
       END_IF
    END_WHILE
    

    And after, I do a Linear Interpolation.

    FUNCTION LinearInterpolation : REAL
    VAR_INPUT
       X : REAL;
       X1 : REAL;
       Y1 : REAL;
       x2 : REAL;
       Y2 : REAL;
    END_VAR
    VAR
    END_VAR
    
    IF Y1 <> Y2 THEN
       LinearInterpolation := Y1 + (X - X1) * ((Y2 - Y1)/(X2 - X1));
    ELSE
       LinearInterpolation := Y1;
    END_IF
    

    Bellow is an example on how I use them:

    PROGRAM Prog
    VAR
       Tank1: udtSoundingTable := (Level := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], Volume := [12.3, 15.8, 19, 21.3, 25.9, 29, 32.3, 34, 36, 38, 40]);
       ActualLevel: REAL; //Modify this
       Volume: REAL;
       x1: INT;
       x2: INT;
    END_VAR
    
    FindClosest1D(arr := Tank1.Level, key := ActualLevel, out1 => x1, out2 => x2);
    Volume := LinearInterpolation(X1 := Tank1.Level[x1], X := ActualLevel, x2 := Tank1.Level[x2], Y1 := Tank1.Volume[x1], Y2 := Tank1.Volume[x2]); 
    
     

Log in to post a comment.