2010-07-14 2 views
4

Cette liste est une fonction simple qui associe un point 2D à un certain nombre, si vous considérez chaque {{x,y},z} comme f[x,y]=zMathematica Force pour interpoler sur la grille de tenseur non structuré

{ 
{{1,3},9}, {{1,4},16}, 
{{2,4},8}, {{2,5},10} 
} 

Je veux maintenant une fonction qui interpole/extrapole f[x,y] pour tout {x,y}.

Mathematica refuse de le faire:

Interpolation[{{{1,3},9}, {{1,4},16},{{2,4},8}, {{2,5},10}}, 
InterpolationOrder->1] 

de la Indim Interpolation: Les coordonnées ne se trouvent pas sur une grille de produit tenseur structuré.

Je comprends pourquoi (Mathematica veut un domaine « rectangulaire »), mais ce qui est la meilleure façon de forcer Mathematica pour créer une interpolation?

Cela ne fonctionne pas:

f[1,3]=9; f[1,4]=16; f[2,4]=8; f[2,5]=10; 
g=FunctionInterpolation[f[x,y],{x,1,2},{y,3,5}] 

FunctionInterpolation :: nreal:
16 Près de {x, y} = {1, -}, la fonction n'a pas évaluer un réel nombre. 5 FunctionInterpolation :: nreal:
17 Près de {x, y} = {1, -}, la fonction n'a pas évalué à un nombre réel. 5 FunctionInterpolation :: nreal:
18 Près de {x, y} = {1, -}, la fonction n'a pas validé en un nombre réel. 5 Général :: stop: La sortie supplémentaire de FunctionInterpolation :: nreal sera supprimée lors de ce calcul.

Même si vous ignorez les avertissements ci-dessus, l'évaluation g donne des erreurs

g[1.5,4] // FortranForm 


    f(1.5,4) + 0.*(-9.999999999999991*(f(1.4,4) - f(1.5,4)) + 
-  0.10000000000000009* 
-  (9.999999999999991* 
-   (9.999999999999991*(f(1.4,4) - f(1.5,4)) + 
-   4.999999999999996*(-f(1.4,4) + f(1.6,4))) + 
-   0.5000000000000006* 
-   (-10.000000000000014* 
-    (-3.333333333333333*(f(1.3,4) - f(1.6,4)) - 
-    4.999999999999996*(-f(1.4,4) + f(1.6,4))) - 
-   9.999999999999991* 
-    (9.999999999999991*(f(1.4,4) - f(1.5,4)) + 
-    4.999999999999996*(-f(1.4,4) + f(1.6,4)))))) 

L'autre idée « évidente » (interpoler fonctions eux-mêmes interpoler) ne fonctionne pas non plus.

Répondre

6

Si l'interpolation polynomiale est acceptable, InterpolatingPolynomial fait ce que vous voulez (où data est votre liste de points ci-dessus):

In[63]:= InterpolatingPolynomial[data, {x, y}] 

Out[63]= -24 + x (12 - 5 y) + 12 y 

In[64]:= f[2, 3] 

Out[64]= 6 

Vous pouvez également utiliser Fit pour faire des moindres carrés ajustés sur la combinaison linéaire des fonctions spécifié dans le deuxième argument:

In[65]:= Fit[Flatten /@ data, {1, x, y}, {x, y}] 

Out[65]= 4.75 - 8. x + 4.5 y 

Bien sûr, une fonction ajustée peut ne pas interpoler exactement vos points de données. Si un tel ajustement est acceptable si, FindFit pouvons répondre à toutes les fonctions de modèle (linéaire ou non linéaire) vous spécifiez:

In[72]:= FindFit[Flatten/@data, x y (a Sin[x] + b Cos[y]) + c, {a,b,c}, {x,y}] 

Out[72]= {a -> -0.683697, b -> 0.414257, c -> 15.3805} 

HTH!

1

Malheureusement, les polynômes sont trop ondulés, mais les fonctions linéaires ne sont pas assez .Je crois que le modèle correct est plusieurs segments de ligne, mais ils auront tous des pentes différentes.

Voici une solution de contournement hideuse qui fait ce que je veux.


(* data in format {{x,y},z} *) 
data = {{{1,3},9}, {{1,4},16}, {{2,4},8}, {{2,5},10}} 

(* find the ranges of x and y *) 
datax = DeleteDuplicates[Transpose[Transpose[data][[1]]][[1]]] 
datay = DeleteDuplicates[Transpose[Transpose[data][[1]]][[2]]] 

(* extract the values of y and z for each x *) 
datamap[t_]:=Map[{#[[1,2]], #[[2]]} &, Select[data, #[[1,1]] == t &]] 

(* interpolate for each value of x, create a rectangular array, and then 
    interpolate in y *) 
Map[(f[#]=Interpolation[datamap[#],InterpolationOrder->1])&, datax] 

(* and now apply f to the expanded grid I've created *) 

datatab = Flatten[Table[ 
{{datax[[i]], datay[[j]]}, f[datax[[i]]][datay[[j]]]}, 
{i,1,Length[datax]}, {j,1,Length[datay]}], 1] 

(* now mathematica will let me interpolate *) 
dataint = Interpolation[datatab, InterpolationOrder->1] 

(* The resulting function agrees with my original*) 

Flatten[Table[{{x,y},dataint[x,y]},{x,1,2},{y,3,5}],1] 

Out[29]= {{{1, 3}, 9}, {{1, 4}, 16}, {{1, 5}, 23}, {{2, 3}, 6}, {{2, 4}, 8}, 
{{2, 5}, 10}} 

(* above contains all my original points [plus a few extra] *) 

(* and does a reasonable job of interpolating *) 

dataint[1.5,3.5] 

9.75 

which is the average of the four corner values: 

{dataint[1,3], dataint[1,4], dataint[2,3], dataint[2,4]} 

{9, 16, 6, 8}