1

I'm not entirely sure what to call what I need.

enter image description here

I have this data in a CSV file and in an SQL database. What I need to do is to be able to use the table to bilinear interpolate. So when say d = 2.5 and HVL = 1.6 what is the best way to solve this? The calculation I can perform just not sure how to select the appropriate numbers from the table, some form of LINQ statement?

Edit:

With the figures 1.6 and 2.5 I need to select the numbers surrounding it as a 2x2 matrix (Bilinear interpolation)

enter image description here

Thanks

James
  • 73
  • 1
  • 12
  • What are you trying to do? – Sean Lange May 31 '17 at 21:18
  • This is radiation backscatter factors (BSF), so for a depth of 2 cm and a HVL of 1.0 mm the BSF = 1.070. As above its when the depth and the HVL are not listed I wish to interpolate to find the BSF. – James May 31 '17 at 21:26
  • What does that mean? You are tossing around these equations like somebody should know what they mean. I see you have a column for d and columns for HVL. Given the examples of 2.5 and 1.6 what do you want returned? – Sean Lange May 31 '17 at 21:28
  • @SeanLange I suspect this is a simple matrix interpolation X/Y Just not digging the screenshot – John Cappelletti May 31 '17 at 21:29
  • 1
    Hopefully you aren't asking an under-specified question for programming a medical treatment application on StackOverflow. – NetMage May 31 '17 at 21:33
  • I suppose matrix interpolation would be correct. The terms I used were as an example from the table. – James May 31 '17 at 21:41
  • @James: In order to get the proper solution you have to provide all necessary details. – Bogdan Sahlean May 31 '17 at 21:44
  • One detail would be what type of fit you expect to use to interpolate. – NetMage May 31 '17 at 23:34
  • @James - You really need to provide us with the input data as value C# code so that we can best help you. – Enigmativity Jun 01 '17 at 00:25
  • Sorted, I can read the data from a database using LINQ [LINQ to find the closest number that is greater / less than an input](https://stackoverflow.com/questions/6436246/linq-to-find-the-closest-number-that-is-greater-less-than-an-input) I can use this to select the rows and columns and from that create a matrix with which I can perform the interpolation. Will post solution. – James Jun 01 '17 at 09:40

1 Answers1

4

1) I took a small portion of your matrix which looks like so:

enter image description here

2) We then take your matix and dynamically normalize it (see cte0), and that looks like this:

enter image description here

Now, for performance sake, if this is a static matrix, I would recommend that you actually store the data is this fashion.

3) Given your target values @X and @Y, we then need to determine the desired rows and columns (in cte1). The result looks like this:

enter image description here

  • The fields and values are the desired Row/Column numbers

4) In cte2, we want to grab the X/Y ranges and values, and that looks like this:

enter image description here

4) The final query is a small matter of interpolation of the X/Y ranges/values. I used a UDF just to facilitate the math.

I should note that the results were validated as illustrated below:

enter image description here

OK, How about the Code?

I should add, that I left these portions as cte's so you can see how the individual parts work together. Certainly this can be compressed further (See Edit Below).

Declare @YourTable Table ([y] int,[x1.5] float,[x2.0] float,[x3.0] float,[x4.0] float)
Insert Into @YourTable Values
 (1,1.050,1.055,1.057,1.057)
,(2,1.080,1.089,1.097,1.098)
,(3,1.091,1.103,1.114,1.446)

Declare @XML xml = (Select * from @YourTable for XML Raw) 
Declare @Y float = 2.5
Declare @X float = 1.6

;with cte0 as (
                Select RowNr = Dense_Rank() over (Order By r.value('@y','float'))
                      ,ColNr = Dense_Rank() over (Order By convert(float,replace(attr.value('local-name(.)','varchar(100)'),'x','')))
                      ,Y     = r.value('@y','float')
                      ,X     = convert(float,replace(attr.value('local-name(.)','varchar(100)'),'x',''))
                      ,V      = attr.value('.','float') 
                 From  @XML.nodes('/row') as A(r)
                 Cross Apply A.r.nodes('./@*') AS B(attr)
                 Where attr.value('local-name(.)','varchar(100)') not in ('y') )
     ,cte1 as ( 
                Select *
                 From (Select R1=max(RowNr),R2=max(RowNr)+1 From  cte0 A where Y<@Y) A
                 Join (Select C1=max(ColNr),C2=max(ColNr)+1 From  cte0 A where X<@X) B
                   on 1=1
              )
     ,cte2 as (
                Select X1  = max(case when C=1 then X end)
                      ,X2  = max(case when C=2 then X end)
                      ,Y1  = max(case when R=1 then Y end)
                      ,Y2  = max(case when R=2 then Y end)
                      ,Q11 = max(case when R=1 and C=1 then V end)
                      ,Q12 = max(case when R=1 and C=2 then V end)
                      ,Q21 = max(case when R=2 and C=1 then V end)
                      ,Q22 = max(case when R=2 and C=2 then V end)
                 From (
                        Select *
                              ,R=Dense_Rank() over (Order By RowNr)
                              ,C=Dense_Rank() over (Order By ColNr)
                         From  cte0 A
                         Cross Join cte1
                         Where RowNr between R1 and R2
                           and ColNr between C1 and C2
                      ) A
              )
Select Value = [dbo].[udf-Stat-Interpolate](@Y,Y1,Y2,[dbo].[udf-Stat-Interpolate](@X,X1,X2,Q11,Q12) ,[dbo].[udf-Stat-Interpolate](@X,X1,X2,Q21,Q22) )
 From  cte2

Returns

Value
1.0876

And Finally, the UDF if Interested

CREATE Function [dbo].[udf-Stat-Interpolate] (@PosNr float,@PosMin float,@PosMax float,@ValMin float,@ValMax float)  
Returns Float as  
Begin 
   Return (((@PosNr-@PosMin)/(@PosMax-@PosMin)*(@ValMax-@ValMin)))+@ValMin
End

Edit - If matrix is stored as illustrated above (#2)

Declare @Y float = 2.5
Declare @X float = 1.6

Select Value = [dbo].[udf-Stat-Interpolate](@Y,Y1,Y2,[dbo].[udf-Stat-Interpolate](@X,X1,X2,Q11,Q12),[dbo].[udf-Stat-Interpolate](@X,X1,X2,Q21,Q22) )
 From (
        Select X1  = max(case when C=1 then X end)
              ,X2  = max(case when C=2 then X end)
              ,Y1  = max(case when R=1 then Y end)
              ,Y2  = max(case when R=2 then Y end)
              ,Q11 = max(case when R=1 and C=1 then V end)
              ,Q12 = max(case when R=1 and C=2 then V end)
              ,Q21 = max(case when R=2 and C=1 then V end)
              ,Q22 = max(case when R=2 and C=2 then V end)
        From (
               Select *
                     ,R=Dense_Rank() over (Order By RowNr)
                     ,C=Dense_Rank() over (Order By ColNr)
                From  YourTable A
                Cross Join (
                            Select *
                             From (Select R1=max(RowNr),R2=max(RowNr)+1 From  YourTable A where Y<@Y) A
                             Join (Select C1=max(ColNr),C2=max(ColNr)+1 From  YourTable A where X<@X) B on 1=1
                           ) B
                Where RowNr between R1 and R2
                  and ColNr between C1 and C2
            ) A
      ) A
John Cappelletti
  • 79,615
  • 7
  • 44
  • 66