Batch interpolation

EKB Every once in a while I get a data table with gaps, something like this:

102030405060
Item 13.24.73.7
Item 21.92.06.8
Item 30.00.57.82.21.3

What I want to do is to fill in the table using interpolation. For example, using linear interpolation, applying the routine to the table above should give

102030405060
Item 13.23.74.24.74.23.7
Item 21.92.03.24.45.66.8
Item 30.00.57.85.02.21.3

Here is my solution, with a demo at the end. A couple of notes:

  • As far as I can tell, this problem is not solved out of the box by the tcllib math::interpolate package, although it could be implemented using that package with a bit of work.
  • The routine assumes that there is an initial and final value for each of the rows.
## Worker procs

proc phi {x xl xu} {
    expr {(1.0 * $x - $xl)/(1.0 * $xu - $xl)}
}

proc linear {x xl yl xu yu} {
    set phi [phi $x $xl $xu]
    expr {$yl + $phi * ($yu - $yl)}
}

proc geometric {x xl yl xu yu} {
    set phi [phi $x $xl $xu]
    expr {$yl * pow(1.0 * $yu/$yl, $phi)}
}

proc interpolate {xs ys f} {
    set ysnew {}
    set yl [lindex $ys 0]
    set xl [lindex $xs 0]
    set yu {}
    set xu {}
    set i 0
    foreach yi $ys xi $xs {
        if [string is double -strict $yi] {
            set yl $yi
            set xl $xi
            set yu {}
            set xu {}
            lappend ysnew $yi
        } else {
            if {$yu == {}} {
                set i1 [expr {$i + 1}]
                foreach xj [lrange $xs $i1 end] yj [lrange $ys $i1 end] {
                    if [string is double -strict $yj] {
                        set yu $yj
                        set xu $xj
                        break
                    }
                }
            }
            lappend ysnew [$f $xi $xl $yl $xu $yu]
        }
        incr i
    }
    set ysnew
}

## Demo
console show

set xs {10 20 30 40 50 60}
puts "\t[join $xs \t]"
foreach n {"Item 1" "Item 2" "Item 3"} ys {
        {3.2 {} {} 4.7 5.2 3.7}
        {1.9 2.0 {} {} {} 6.8}
        {0.0 0.5 7.8 {} 2.2 1.3}
    } {
    puts "$n\t[join [interpolate $xs $ys linear] \t]"
}