Pénétration du signal dans numpy

8

Le problème consiste à modéliser la propagation d'un signal (par exemple lumière ou son, etc.) à travers une série d'obstacles, comme sur la figure ci-dessous. Le signal ne peut pas traverser la surface inférieure (terrain), mais il peut traverser des obstacles. Je veux compter le nombre d'obstacles traversés.

entrez la description de l'image ici

Le terrain et les obstacles sont dans des tableaux numpy 2D (x, y, z). C'est ce que je fais:

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

Le résultat serait quelque chose comme [0, 0, 0, 1, 1, 1, 2, 3, 4, 4, 4 ...]par ligne.

Cette méthode fonctionne bien (à condition que les vallées sur le terrain soient remplies en utilisant numpy.maximum.accumulate). Maintenant, serait-il possible d'accélérer la chose en utilisant une solution vectorisée?

Zoran
la source
1
Question interessante. Pourriez-vous expliquer plus en détail la solution que vous recherchez et quelles sont les données d'entrée? Je pense que vous cherchez la création de lignes (en tant que couches linestring) représentant le signal mais, dans ce cas, il devrait être nécessaire de spécifier également une direction en plus du format source.
mgri
Je m'intéresse à la fois à l'acoustique et à l'atténuation de la lumière (par exemple le voile, la fumée). Par souci de simplicité, le signal se déplace parallèlement au terrain (verticalement) et parallèlement à la grille du terrain (horizontalement). Par «signal», je veux dire seulement un simple itérateur sur la matrice numpy.
Zoran
1
Et qu'en est-il de la hauteur des signaux?
dmh126
La hauteur du signal est arbitraire: disons 1,7 mètre pour la taille humaine ... Ensuite, vous pouvez élever (temporairement) le terrain pour cette valeur `mask = obstacles [i, j]> terrain [i, j:] + 1,7` <in mon code j'utilise une taille angulaire qui s'obtient en divisant les hauteurs avec les distances de la source - mais cela n'est pas pertinent ici, il me semble (?)>
Zoran
Il sera certainement possible de le vectoriser, la FFT peut être vectorisée ( jakevdp.github.io/blog/2013/08/28/understanding-the-fft ). J'ai du mal à comprendre ce que représentent obstacles.shape [0] et obstacles.shape [1].
John Powell

Réponses:

1

Comme le disent les commentaires ci-dessus, vous pouvez probablement vectoriser l'opération pour supprimer les boucles for et la rendre plus efficace.

Cependant, si vous envisagez le problème d'une manière légèrement différente - celle du seuillage - vous pouvez profiter des outils de scipy ndimage pour compter les obstacles:

Tout d'abord, limitez vos données de terrain en fonction de la hauteur de votre signal pour obtenir un tableau booléen de l'endroit où le signal pourrait être, quelle que soit l'origine.

signal_reach = terrain < signal_height

Ensuite, vous pouvez utiliser la ndimage.labelméthode pour regrouper des régions discrètes:

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

Une fois cela fait, obtenez les identifiants de région qui correspondent aux cellules d'origine de votre signal. Dans votre cas, ce serait la première colonne.

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]

Maintenant, le seuil est là où le signal intercepte le terrain + les obstacles, et cette fois, filtre les régions à l'extérieur ou la zone d'intérêt à l'aide numpy.isin.

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

Et un dernier tour de ndimage.labelvous donne un compte des obstacles interceptés, car nous avons déjà filtré les zones bloquées par le terrain:

obstacles_hit, obstacle_count = ndimage.label(signal_intercepted)

Il y a un peu plus de code ici, mais il y a deux gros avantages:

  • Non pour les boucles signifie que le code doit être raisonnablement rapide,
  • Et à des fins de calcul, l'origine du signal peut être sur ou plusieurs cellules, n'importe où sur le raster de terrain.
om_henners
la source
1
Cela ressemble à une approche prometteuse! Je vais le tester en janvier et le signaler comme slution si ça marche.
Zoran