2010-07-21 26 views
6

Estoy buscando una función en PHP para interpolar un conjunto de datos colocados irregulares (x, y, z) a un conjunto de datos de cuadrícula para usarlo en la función ContourPlot en JPGraph. Desarrollé una función basada en el simple Inverse distance weighting, pero es demasiado lenta. Necesito utilizar otro método como "Método de Shepard modificado" o cualquier otro método posible con más precisión para que sea más rápido y sencillo.Interpolación en PHP

Aquí está mi código actual:

for($i = 0, $ij = 0; $i < $gridX; $i ++) { 
    for($j = 0; $j < $gridY; $j ++, $ij ++) { 
     $x = $startP->x + ($deltaX * $i); 
     $y = $startP->y + ($deltaY * $j); 
     $g [$ij]->i = $i; 
     $g [$ij]->j = $j; 
     $g [$ij]->x = (int) $x; 
     $g [$ij]->y = (int) $y; 
     $g [$ij]->z = IDW_U ($x, $y, $sampleData, $sampleSize, $p); 
    } 
} 

function IDW_U($x, $y, $data, $size, $p) { 
    $idw_sum = IDWeightSum ($x, $y, $data, $size, $p); 
    $idw_u = 0.0; 
    for($k = 0; $k < $size; $k ++) { 
     if ($x == $data [$k]->x && $y == $data [$k]->y) 
      return $data [$k]->z; 
     $idw_u += IDWeight ($x, $y, $data [$k], $p) * $data [$k]->z/$idw_sum; 
    } 
    return $idw_u; 
} 

function IDWeightSum($x, $y, $data, $size, $p) { 
    $sum = 0.0; 
    for($k = 0; $k < $size; $k ++) 
     $sum += IDWeight ($x, $y, $data [$k], $p); 
    return $sum; 
} 

function IDWeight($x, $y, $d, $p) { 
    if ($x == $d->x && $y == $d->y) 
     return 1.0; 
    $dx = $x - $d->x; 
    $dy = $y - $d->y; 
    $ret = 1.0/pow (sqrt (pow ($dx, 2) + pow ($dy, 2)), $p); 
    return $ret; 
} 

¿Alguien sabe una función o una biblioteca disponible para este propósito?

+1

Publique su código que es demasiado lento. Puede haber algunas optimizaciones significativas posibles ... – ircmaxell

+0

Hmm, creo que 'gnuplot' puede interpolar y generar la misma calidad (o mejor) que JPGraph. Tal vez esa es una opción? Aunque una especie de curva de aprendizaje empinada, puedo decir con seguridad que no sé el 2% de lo que puede hacer el gnuplot. – Wrikken

+5

Esta recompensa podría ayudarte a obtener algunas respuestas. –

Respuesta

1

No estoy tan seguro de que PHP sea una buena opción para la funcionalidad intensiva de matemáticas como esa. Sin embargo, hay muchas bibliotecas gráficas disponibles donde el código ha sido optimizado, puesto en DLL's y cosas por el estilo.

Hemos utilizado Advanced Software Engineering ChartDirector PHP Charting para algunos gráficos bastante complejos y es rápido. No estoy seguro si incluye el algoritmo que le interesa, pero incluye algunos como LOWESS. El principal problema que veo es que se trata de X, Y y Z. El manejo de la tercera dimensión no es la característica más común. No estoy seguro de que esta biblioteca sea compatible con eso ...

+0

Gracias por su recomendación. Aunque tengo que tener mi propio código, lo eché un vistazo y lo probó como una solución alternativa. En realidad, funciona bien. Tiene una función para crear un gráfico de contorno para datos dispersos y es muy rápido. – Fred

0

Si no está vinculado a PHP, debe considerar cambiarlo para la mayor parte de este procesamiento intensivo que pueda. PHP es un lenguaje más lento (la última vez que lo busqué - hace aproximadamente un año, Python y Ruby lo superaron, así como C, C++ y Java.

Al cambiar a una herramienta gráfica fuera de línea (como gnuplot, como se menciona en los comentarios), volver a ejecutar sus pruebas de rendimiento y, si es necesario, cambiar el algoritmo a un script de Python o Ruby o una aplicación C o C++ compilada, obtendrá un aumento de rendimiento.

Sin embargo, no pude No encuentro datos de rendimiento más recientes en PHP en comparación con otros idiomas desde finales de 2008 o comienzos de 2009. Es posible que mis datos ya no sean verdaderos.

0

Puede ser útil que pase los datos por referencia:

function IDW_U($x, $y, &$data, $size, $p) ... 
function IDWeightSum($x, $y, &$data, $size, $p) ... 
3

Por lo que puedo ver, IDWeight se llama con bastante frecuencia. Usted podría mitad el número de llamadas a ese calculando IDW_U así:

function IDW_U($x, $y, $data, $size, $p) { 
$idw_sum = 0.0; 
$idw_u = 0.0; 
for($k = 0; $k < $size; $k ++) { 
    if ($x == $data [$k]->x && $y == $data [$k]->y) 
     return $data [$k]->z; 
    $iw = IDWeight ($x, $y, $data [$k], $p) 
    $idw_u += $iw * $data [$k]->z; 
    $idw_sum += $iw; 
} 
return $idw_u/$idw_sum; 
} 

Creo que el problema principal es, que para el cálculo de un píxel, se utilizan todos los conjuntos de datos, mientras que la mayoría de ellos tendrá poco impacto . Realmente podría aumentar el rendimiento al dividir los datos en áreas pequeñas y calcular todas las áreas por separado.

+0

Tienes razón, ayuda mucho. ¡Gracias! – Fred