2012-03-11 19 views
8

Digamos que tengo n número de puntos que definen una superficie en el eje zspline de interpolación superficie

f(x1,y1) = 10 
f(x2,y2) = 12 
f(x3,y3) = 5 
f(x4,y4) = 2 
... 
f(xn,yn) = 21 

ahora quieren ser capaces de aproximar f (x, y). Estoy buscando un algoritmo para una aproximación lineal y especialmente una spline. Un ejemplo de algoritmo o al menos algunos punteros sería genial.

+0

El artículo de [wikipedia] [1] es un poco desalentador, pero al menos trate de ver la sección de ejemplos. [1]: http://en.wikipedia.org/wiki/Spline_interpolation –

+1

¿Tiene x, y puntos de control en una cuadrícula regular? –

+0

Para las funciones de la forma f (x, y), es más común de hacer una suposición acerca de la forma de los datos subyacentes (polinomio de grado K, suma de n gaussianas, etc.) y luego determinar los coeficientes de mínimos cuadrados. ¿Eso funcionaría aquí? ¿Sabes algo sobre lo que representan los datos? Si realmente quieres una spline, vale la pena echar un vistazo a NURBS http://en.wikipedia.org/wiki/NURBS. Tienen buenas propiedades para renderizar.Construya una triangulación de Delaunay de los puntos (x, y) para obtener la base a menos que estén en una cuadrícula regular. Para la adaptación del avión, querrás un ajuste estándar de mínimos cuadrados. – Gene

Respuesta

1

Puede usar sus puntos como puntos de control de una superficie Bezier (o Bspline), especialmente si (xi, yi) muestra un rectángulo en el plano XY. En este sentido, no hay ajuste apropiado.

La superficie que obtendrá estará en el casco convexo de sus puntos, e intersecará (interpolará) los puntos en el límite de {xi, yi}.

Si desea experimentar, This forums posting parece contener código simple en Matlab, y se puede utilizar GuIRIT a hacer lo mismo si usted no tiene Matlab (aunque requiere averiguar el formato de archivo del programa) .

+0

La implementación final tendrá que ser en ruby, por lo que Matlab no es realmente una opción. Pero el problema es realmente sobre un rectángulo en el plano XY. – tcurdt

+0

Nunca utilicé Ruby, pero estoy seguro de que hay un paquete de Bezier/Bspline para él. – user1071136

4

Esta es una vaga descripción de un enfoque para hacer una aproximación lineal.

  1. Determinar el Voronoi diagram de sus puntos (para cada punto en el plano, encontrar el más cercano (x_i,y_i))
  2. Tome el dual de esto para conseguir la Delaunay triangulation: conectar (x_i,y_i) y (x_j,y_j) si hay un segmento de la línea de puntos de modo que (x_i,y_i) y (x_j,y_j) son equidistantes (y más cercanos que cualquier otro par).
  3. En cada triángulo, busca el avión a través de los tres vértices. Esta es la interpolación lineal que necesita.

los siguientes implementos los dos primeros pasos en Python. La regularidad de su cuadrícula puede permitirle acelerar las cosas (también puede estropear la triangulación).

import itertools 

""" Based on http://stackoverflow.com/a/1165943/2336725 """ 
def is_ccw(tri): 
    return ((tri[1][0]-tri[0][0])*(tri[1][1]+tri[0][1]) 
      + (tri[2][0]-tri[1][0])*(tri[2][1]+tri[1][1]) 
      + (tri[0][0]-tri[2][0])*(tri[0][1]+tri[2][1])) < 0 

def circumcircle_contains_point(triangle,point): 
    import numpy as np 
    matrix = np.array([ [p[0],p[1],p[0]**2+p[1]**2,1] for p in triangle+point ]) 
    return is_ccw(triangle) == (np.linalg.det(matrix) > 0) 

triangulation = set() 
""" 
A triangle is in the Delaunay triangulation if and only if its circumscribing 
circle contains no other point. This implementation is O(n^4). Faster methods 
are at http://en.wikipedia.org/wiki/Delaunay_triangulation 
""" 
for triangle in itertools.combinations(points,3): 
    triangle_empty = True 
    for point in points: 
     if point in triangle: 
      next 
     if circumcircle_contains_point(triangle,point): 
      triangle_empty = False 
      break 
    if triangle_empty: 
     triangulation.add(triangle) 
2

La interpolación en datos 2D irregulares no es tan fácil. No conozco ninguna generalización spline verdadera a 2D irregular.

Además de los enfoques basados ​​en la triangulación, se puede echar un vistazo a Barnes (http://en.wikipedia.org/wiki/Barnes_interpolation) y el inverso de la distancia para medir peso (http://en.wikipedia.org/wiki/Inverse_distance_weighting), o más generalmente, RBF (http://en.wikipedia.org/wiki/Radial_basis_functions).

Si su punto está fuertemente disperso de forma no uniforme (clústeres densos), puede ser necesario adaptar el tamaño de las funciones, o recurrir a la aproximación en lugar de la interpolación.

+0

Siendo realistas, no se extienden tanto. En el peor de los casos, podría incluso vivir con una interpolación lineal, pero preferiría una superficie más lisa. – tcurdt

+0

La aproximación suena como un ángulo interesante, también. – tcurdt

+0

+1 para funciones de base radial. Hace algunos años escribí un artículo que trabajaba con estos objetos generalizados para funciones en múltiples. Funcionan muy bien siempre que no tenga los clústeres densos y la cantidad de puntos n no sea demasiado grande. (Si n se agranda, quiere que su RBF tenga soporte compacto para que la matriz involucrada sea escasa. Pero entonces necesitaría usar álgebra lineal dispersa para mantener su escalado aceptable). Interpolación agradable y sin problemas. –