Señal de penetración en numpy

8

El problema consiste en modelar la propagación de una señal (por ejemplo, luz o sonido, etc.) a través de una serie de obstáculos, como en la figura a continuación. La señal no puede pasar a través de la superficie inferior (terreno), pero puede atravesar obstáculos. Quiero contar la cantidad de obstáculos atravesados.

ingrese la descripción de la imagen aquí

El terreno y los obstáculos están en matrices numpy 2D (x, y, z). Esto es lo que hago:

output = numpy.zeros(terrain.shape)

obstacles = terrain + obstacle_heights


for i in xrange (obstacles.shape[0]):
    for j in xrange (obstacles.shape[1]):

        mask = obstacles[i,j] > terrain[i,j:]
        output[i,j:][mask] +=1

El resultado sería algo así [0, 0, 0, 1, 1, 1, 2, 3, 4, 4, 4 ...]por fila.

Este método funciona bien (siempre que los valles del terreno se llenen usando numpy.maximum.accumulate). Ahora, ¿sería posible acelerar la cosa usando una solución vectorizada?

Zoran
fuente
1
Interesante pregunta. ¿Podría explicar más en detalle qué solución está buscando y cuáles son los datos de entrada? Creo que está buscando la creación de líneas (como capas de cadenas de líneas) que representen la señal pero, en este caso, debería ser necesario especificar también una dirección además del formato de origen.
mgri
Me interesan tanto la acústica como la atenuación de la luz (p. Ej. Neblina, humo). En aras de la simplicidad, la señal viaja paralela al terreno (verticalmente) y paralela a la cuadrícula del terreno (horizontalmente). Por "señal" me refiero solo a un iterador simple sobre la matriz numpy.
Zoran
1
¿Y qué hay de la altura de las señales?
dmh126
La altura de la señal es arbitraria: digamos 1,7 metros para la altura humana ... Luego puede elevar (temporalmente) el terreno para ese valor `máscara = obstáculos [i, j]> terreno [i, j:] + 1.7 '<en mi código estoy usando un tamaño angular que se obtiene dividiendo las alturas con distancias desde la fuente, pero eso no es relevante aquí, me parece (?)>
Zoran
Definitivamente será posible vectorizarlo, la FFT se puede vectorizar ( jakevdp.github.io/blog/2013/08/28/understanding-the-fft ). Sin embargo, estoy luchando por entender qué obstáculos.shape [0] y obstáculos.shape [1] representan.
John Powell

Respuestas:

1

Como dicen los comentarios anteriores, probablemente podría vectorizar la operación para eliminar los bucles for y hacerlo más eficiente.

Sin embargo, si considera el problema de una manera ligeramente diferente, la de los umbrales, puede aprovechar las herramientas de nipimage scipy para contar los obstáculos:

Primero, limite los datos del terreno por la altura de su señal para obtener una matriz booleana de dónde podría estar la señal, independientemente del origen.

signal_reach = terrain < signal_height

Luego puede usar el ndimage.labelmétodo para agrupar regiones discretas:

from scipy import ndimage
signal_regions, region_count = ndimage.label(signal_reach)

Una vez hecho esto, obtenga las ID de región que coinciden con las celdas de origen de su señal. En su caso, sería la primera columna.

import numpy as np
origin_labels = np.unique(signal_regions[:, 0]) # or whatever indexes meet the start of the signal
# ndimage lables are greater than 1, 0 is an unlabeled region
origin_labels = origin_lables[origin_lables > 0]

Ahora el umbral es donde la señal intercepta el terreno + obstáculos, y esta vez filtra las regiones externas o el área de interés utilizando numpy.isin.

area_of_interest = np.isin(signal_regions, origin_labels)
signal_intercepted = (obstacles >= signal_height) & area_of_interest

Y una ronda final de ndimage.labelle da una cuenta de los obstáculos interceptados, porque ya hemos filtrado las áreas bloqueadas por el terreno:

obstacles_hit, obstacle_count = ndimage.label(signal_intercepted)

Hay un poco más de código aquí, pero hay dos grandes ventajas:

  • No para bucles significa que el código debe ser razonablemente rápido,
  • Y para fines de cálculo, el origen de la señal puede estar en muchas celdas, en cualquier parte del ráster del terreno.
om_henners
fuente
1
¡Esto parece un enfoque prometedor! Lo probaré en enero y lo marcaré como la solución si funciona.
Zoran