Welcome to the Excel Forum

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed.

Please Register to Remove these Ads

Please Register to Remove these Ads



Reply
  #1  
Old 05-27-2008, 04:43 PM
DocM DocM is offline
Registered User
 
Join Date: 27 May 2008
Posts: 3
DocM is becoming part of the community
Linear interpolation/extrapolation module - input?

Please Register to Remove these Ads

I recently got my hands on a very nice module for inputting 4 dimensional data (across multiple tables), and outputting a single interpolation. I am not very familiar with the code in which this is written, so it is very difficult for me to walk through this and determine what it wants me to input.

Written below is everything that I have. I wonder if some of you Excel Gurus can step through this and perhaps post an example of how one would implement it.

If anyone should find this function useful, feel free to use it. It is free source code (however I am unsure of the author).


Code:
'---------------------------------------------------------------------------------------
'
' P U R P O S E
'
' The function lin_xyzt uses linear interpolation (or extrapolation) to find the value
' z(x=x_value,y=y_value,t=t_value) from multiple tables (x, y, z) of different t values.
' Each table is arranged so that the 1st column and the 1st row contain x and y values,
' respectively.  The z values are at the intersection of its x and y values.
' The program assumes x and y in each table are in ascending order.
'
' I N P U T
'
' Table     = a range of cells in the worksheet that defines the multiple tables.
' row_col   = a range of cells in the following format (one line for each table in Table):
'             row_1, row_2, col_1, col_2, t
'             where
'             row_1  = starting row number of table, relative to the first cell in Table.
'             row_2  = ending row number of table.
'             col_1  = starting column number of table, relatve to the first cell in Table.
'             col_2  = ending column number of table
'             t      = table values, arranged in ascending order.
' x_value   = the x value where the z value is to be determined.
' y_value   = the y value where the z value is to be determined.
' t_value   = the t value where the z value is to be determined.
' extrapolate (optional)
'           = if omitted, will return #N/A if x_value, y_value or t_value is out-of-bound.
'           = "bd", will return table bounded value if x_value, y_value or t_value is out-of-bound.
'           = "et", will linearly extrapolate if x_value, y_value or t_value is out-of-bound.
'
' O U T P U T
'
' lin_xyzt  = the z value at (x=x_value, y=y_value, t=t_value).
'             For multiple x_values or y_values, the first pair will be returned.
'             If x_value, y_value or t_value is out-of-bounds, the argument extrapolate
'             will determine the returned value.
'
'---------------------------------------------------------------------------------------
Function lin_xyzt(Table As Object, row_col As Object, x_value, y_value, t_value, Optional extrapolate)

Dim i, j As Integer              ' counter.
Dim i1, i2 As Integer
Dim z1, z2 As Single
Dim active_all(1) As Boolean
Dim extr

Dim row_1, row_2, col_1, col_2 As Integer

Dim T As Object
Dim Table_1 As Range
Dim Table_2 As Range

If IsMissing(extrapolate) Then
   extr = ""
Else
   extr = LCase(extrapolate)
End If

Select Case row_col.Rows.count
Case 1                           ' single table.  t_value is ignored.
   row_1 = row_col(1, 1)
   row_2 = row_col(1, 2)
   col_1 = row_col(1, 3)
   col_2 = row_col(1, 4)
      
   Set Table_1 = Range(Table.Cells(row_1, col_1), Table.Cells(row_2, col_2))
   
   lin_xyzt = lin_xyz(Table_1, x_value, y_value, extrapolate)
Case Else
   Set T = Range(row_col.Cells(1, 5), row_col.Cells(row_col.Rows.count, 5))
      
   active_all(1) = True
   Call bracket(T, t_value, i1, i2, active_all())
   
   row_1 = row_col(i1, 1)
   row_2 = row_col(i1, 2)
   col_1 = row_col(i1, 3)
   col_2 = row_col(i1, 4)
   Set Table_1 = Range(Table.Cells(row_1, col_1), Table.Cells(row_2, col_2))
         
   row_1 = row_col(i2, 1)
   row_2 = row_col(i2, 2)
   col_1 = row_col(i2, 3)
   col_2 = row_col(i2, 4)
   Set Table_2 = Range(Table.Cells(row_1, col_1), Table.Cells(row_2, col_2))
      
   z1 = lin_xyz(Table_1, x_value, y_value, extrapolate)
   z2 = lin_xyz(Table_2, x_value, y_value, extrapolate)
   
   If t_value >= T(i1) And t_value <= T(i2) Then
      lin_xyzt = lin_2xy(T(i1), z1, T(i2), z2, t_value)
   Else
      Select Case extr
      Case "bd"
         If t_value < T(i1) Then
            lin_xyzt = z1
         ElseIf t_value > T(i2) Then
            lin_xyzt = z2
         Else
            lin_xyzt = [#N/A]
         End If
      Case "et"
         lin_xyzt = lin_2xy(T(i1), z1, T(i2), z2, t_value)
      Case Else
         lin_xyzt = [#N/A]
      End Select
   End If
   
End Select

End Function
Reply With Quote
  #2  
Old 05-27-2008, 05:55 PM
mrice's Avatar
mrice mrice is offline
Forum Guru
 
Join Date: 22 Jun 2004
Location: Surrey, England
MS Office Version:Excel 2007
Posts: 1,842
mrice has been very helpful
You appear to be some code missing as there are no definitions for the functions..

lin_xyz()
lin_2xy()

and the subroutine....

bracket()
__________________
Martin

Eighty Twenty Spreadsheet Automation http://homepage.ntlworld.com/martin.rice1/ for all your Excel customisation and consulting needs.
Reply With Quote
  #3  
Old 05-27-2008, 06:03 PM
DocM DocM is offline
Registered User
 
Join Date: 27 May 2008
Posts: 3
DocM is becoming part of the community
Ah, yes, sorry about that. Here is the additional code.

Code:
'---------------------------------------------------------------------------------------
'
' P U R P O S E
'
' The function lin_2xy uses linear interpolation to find the value y(x=x_value) from
' a pair (x1,y1), (x2,y2).
'
' I N P U T
'
' x1        = 1st x value.
' y1        = 1st y value.
' x2        = 2nd x value.
' y2        = 2nd y value.
' x_value   = the x value where the y value is to be determined.
'
' O U T P U T
'
' lin_2xy   = the y value at x_value.
'
'---------------------------------------------------------------------------------------
Function lin_2xy(x1, y1, x2, y2, x_value)

If x1 = x2 Then
   lin_2xy = [#N/A]
Else
   lin_2xy = y1 + (y2 - y1) / (x2 - x1) * (x_value - x1)
End If

End Function
Code:
'---------------------------------------------------------------------------------------
'
' P U R P O S E
'
' The function lin_xyz uses linear interpolation to find the value
' z(x=x_value,y=y_value) from a table (x, y, z).
' The table is arranged so that the 1st column and the 1st row contain x and y values,
' respectively.  The z values are at the intersection of its x and y values.
' The function will extrapolate beyond the table limit if the optional argument extrapolate is defined.
' The program assumes x and y in Table are in ascending order.
'
' I N P U T
'
' Table     = a range of cells in the worksheet that defines the table.
' x_value   = the x value where the z value is to be determined.
' y_value   = the y value where the z value is to be determined.
' extrapolate
'           = if omitted, will return #N/A if x_value or y_value is out of range.
'           = "bd", will return table bounded value if x_value or y_value is out of range.
'           = "et", will linearly extrapolate even x_value or y_value is out of range.
'
' O U T P U T
'
' lin_xyz   = the z value at (x=x_value, y=y_value).
'             For multiple x_values or y_values, the first pair will be returned.
'             If x_value or y_value is out of bounds, and argument extrapolate is omitted,
'                #N/A will be returned.
'             Otherwise, lin_xyz will return values based on the argument extrapolate.
'
'---------------------------------------------------------------------------------------
Function lin_xyz(Table As Object, x_value, y_value, Optional extrapolate)

Dim i, j As Integer             ' counter.
Dim ii, jj As Integer           ' <>0, if (x_value, y_value) found in table.
Dim z1, z2 As Single            ' temparary storage for z.
Dim extr, x_v, y_v

If IsMissing(extrapolate) Then
   extr = ""
Else
   extr = extrapolate
End If

ii = 0
For i = 2 To Table.Rows.count - 1
    If ((Table(i, 1) - x_value) * _
        (Table(i + 1, 1) - x_value) <= 0!) Then
        ii = i
        Exit For
    End If
Next i

jj = 0
For j = 2 To Table.Columns.count - 1
    If ((Table(1, j) - y_value) * _
        (Table(1, j + 1) - y_value) <= 0!) Then
        jj = j
        Exit For
    End If
Next j

If ii = 0 Or jj = 0 Then
   Select Case extr
   Case "bd"
      x_v = x_value
      y_v = y_value
      If ii = 0 Then
         If x_value < Table(2, 1) Then
            ii = 2
            x_v = Table(2, 1)
         ElseIf x_value > Table(Table.Rows.count, 1) Then
            ii = Table.Rows.count
            x_v = Table(Table.Rows.count, 1)
         End If
      End If
      If jj = 0 Then
         If y_value < Table(1, 2) Then
            jj = 2
            y_v = Table(1, 2)
         ElseIf y_value > Table(1, Table.Columns.count) Then
            jj = Table.Columns.count
            y_v = Table(1, Table.Columns.count)
         End If
      End If
      
      z1 = lin_2xy(Table(ii, 1), Table(ii, jj), _
                   Table(ii + 1, 1), Table(ii + 1, jj), x_v)
      z2 = lin_2xy(Table(ii, 1), Table(ii, jj + 1), _
                   Table(ii + 1, 1), Table(ii + 1, jj + 1), x_v)
      lin_xyz = lin_2xy(Table(1, jj), z1, _
                        Table(1, jj + 1), z2, y_v)
      
   Case "et"
      If ii = 0 Then
         If x_value < Table(2, 1) Then
            ii = 2
         ElseIf x_value > Table(Table.Rows.count, 1) Then
            ii = Table.Rows.count - 1
         End If
      End If
      If jj = 0 Then
         If y_value < Table(1, 2) Then
            jj = 2
         ElseIf y_value > Table(1, Table.Columns.count) Then
            jj = Table.Columns.count - 1
         End If
      End If
      
      z1 = lin_2xy(Table(ii, 1), Table(ii, jj), _
                   Table(ii + 1, 1), Table(ii + 1, jj), x_value)
      z2 = lin_2xy(Table(ii, 1), Table(ii, jj + 1), _
                   Table(ii + 1, 1), Table(ii + 1, jj + 1), x_value)
      lin_xyz = lin_2xy(Table(1, jj), z1, _
                        Table(1, jj + 1), z2, y_value)

   Case Else
      lin_xyz = [#N/A]
   End Select
Else
   z1 = lin_2xy(Table(ii, 1), Table(ii, jj), _
               Table(ii + 1, 1), Table(ii + 1, jj), x_value)
   z2 = lin_2xy(Table(ii, 1), Table(ii, jj + 1), _
               Table(ii + 1, 1), Table(ii + 1, jj + 1), x_value)
   lin_xyz = lin_2xy(Table(1, jj), z1, _
                     Table(1, jj + 1), z2, y_value)
End If

End Function
I was unable to find a bracket() subroutine, however I attached the file that contains all of the functions. I will continue to look through it to see what I dig up. Thanks for the support!
Attached Files
File Type: txt line regression code.txt (36.8 KB, 16 views)
Reply With Quote
  #4  
Old 05-27-2008, 10:43 PM
DocM DocM is offline
Registered User
 
Join Date: 27 May 2008
Posts: 3
DocM is becoming part of the community
The code for the bracket function is below.

Code:
'---------------------------------------------------------------------------------------
'
' P U R P O S E
'
' The function bracket find x1=x(i1) and x2=x(i2) from a table x
' so that x1 <= x_value <= x2.
'
' I N P U T
'
' x         = a range of cells representing x.
' x_value   = the x value to be bracketed.
' active    = an array of x.count elements.
'           = 0 if the corresponding x is to be ignored.
'
' O U T P U T
'
' i1        = the x index which will enclose x_value.
' i2        = the x index which will enclose x_value.
'           x(i1) <= x_value <= x(i2)
'           If x_value is out-of-bound, the two closest x values to x_value
'           will be returned.
'           If there are identical values of x(i1) or x(i2) in x, the first one
'           encountered will be used.
'
'---------------------------------------------------------------------------------------
Sub bracket(x As Object, x_value, i1, i2, active() As Boolean)

Dim i As Integer           ' counter.
Dim x1, xi, x2 As Single   ' = x(i1), x(i), x(i2), respectively.
Dim nactive As Integer
Dim usable As Boolean

nactive = UBound(active)

' If dx of first pair of x times number of points matches the last x,
' the program assumes x is equally spaced.

If x.count >= 2 And nactive <= 1 Then
   If Abs((x(x.count) - x(1)) / (x.count - 1) - (x(2) - x(1))) <= 0.01 * Abs(x(2) - x(1)) Then
      If x(x.count) >= x(1) Then
         i1 = Int((x_value - x(1)) / (x(2) - x(1))) + 1
         If x_value < x(i1) Then          ' Minor adjustment in case of round-off error.
            i1 = i1 - 1
         End If
         If i1 < 1 Then
            i1 = 1
         ElseIf i1 > x.count - 1 Then
            i1 = x.count - 1
         End If
         i2 = i1 + 1
      Else
         i1 = x.count - Int((x_value - x(x.count)) / (x(1) - x(2)))
         If x_value < x(i1) Then          ' Minor adjustment in case of round-off error.
            i1 = i1 + 1
         End If
         If i1 < 2 Then
            i1 = 2
         ElseIf i1 > x.count Then
            i1 = x.count
         End If
         i2 = i1 - 1
      End If
      If x_value >= x(i1) And x_value <= x(i2) Then
         Exit Sub
      ElseIf x_value < x(i1) And (i1 = 1 Or i1 = x.count) Then
         Exit Sub
      ElseIf x_value > x(i2) And (i2 = 1 Or i2 = x.count) Then
         Exit Sub
      End If
   End If
End If

' If the above fails, a more thorough search is performed.

i1 = 0
i2 = 0
For i = 1 To x.count
   xi = x(i)
   If nactive <= 1 Then
      usable = True
   Else
      usable = active(i)
   End If
   
   If Not usable Or Not IsNumeric(xi) Or VarType(xi) = vbEmpty Then
      
      ' Do nothing.
      
   ElseIf i1 = i2 Then
      If i1 = 0 Then
         i1 = i
         i2 = i
         x1 = xi
         x2 = xi
      ElseIf xi > x2 Then
         i2 = i
         x2 = xi
      ElseIf xi < x1 Then
         i1 = i
         x1 = xi
      End If
   ElseIf x1 <= x_value And x2 >= x_value Then
      If xi <= x1 Or xi >= x2 Then
         ' Do nothing.
      ElseIf xi < x_value Then
         i1 = i
         x1 = xi
      Else
         i2 = i
         x2 = xi
      End If
   ElseIf x1 >= x_value Then
      If xi < x1 Then
         i2 = i1
         x2 = x1
         i1 = i
         x1 = xi
      ElseIf xi <> x1 And xi < x2 Then
         i2 = i
         x2 = xi
      End If
   ElseIf x2 <= x_value Then
      If xi > x2 Then
         i1 = i2
         x1 = x2
         i2 = i
         x2 = xi
      ElseIf xi <> x2 And xi > x1 Then
         i1 = i
         x1 = xi
      End If
   End If
Next i

End Sub
Reply With Quote


Reply

Bookmarks


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off

Forum Jump