Signalpenetration in Numpy

8

Das Problem besteht darin, die Ausbreitung eines Signals (z. B. Licht oder Ton usw.) durch eine Reihe von Hindernissen zu modellieren, wie in der folgenden Abbildung dargestellt. Das Signal kann nicht durch die Bodenfläche (Gelände) geleitet werden, es kann jedoch Hindernisse überwinden. Ich möchte die Anzahl der durchquerten Hindernisse zählen.

Geben Sie hier die Bildbeschreibung ein

Gelände und Hindernisse befinden sich in 2D-Numpy-Arrays (x, y, z). Das ist was ich mache:

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

Das Ergebnis wäre so etwas wie [0, 0, 0, 1, 1, 1, 2, 3, 4, 4, 4 ...]pro Zeile.

Diese Methode funktioniert einwandfrei (vorausgesetzt, die Täler im Gelände werden mit verwendet numpy.maximum.accumulate). Wäre es nun möglich, die Sache mit einer vektorisierten Lösung zu beschleunigen?

Zoran
quelle
1
Interessante Frage. Können Sie näher erläutern, nach welcher Lösung Sie suchen und welche Eingabedaten Sie haben? Ich denke, Sie suchen nach der Erstellung von Linien (als Linestring-Ebenen), die das Signal darstellen, aber in diesem Fall sollte es erforderlich sein, zusätzlich zum Quellformat auch eine Richtung anzugeben.
Mgri
Ich interessiere mich sowohl für Akustik als auch für Lichtdämpfung (z. B. Dunst, Rauch). Der Einfachheit halber bewegt sich das Signal parallel zum Gelände (vertikal) und parallel zum Geländegitter (horizontal). Mit "Signal" meine ich nur einen einfachen Iterator über die Numpy-Matrix.
Zoran
1
Und was ist mit der Signalhöhe?
dmh126
Die Signalhöhe ist beliebig: Sagen wir 1,7 Meter für die Körpergröße des Menschen ... Dann können Sie das Gelände (vorübergehend) für diesen Wert anheben: `mask = Hindernisse [i, j]> Gelände [i, j:] + 1,7` <in Mein Code Ich verwende eine Winkelgröße, die durch Teilen der Höhen durch Abstände von der Quelle erhalten wird - aber das ist hier nicht relevant, scheint mir (?)>
Zoran
Es wird definitiv möglich sein, es zu vektorisieren, die FFT kann vektorisiert werden ( jakevdp.github.io/blog/2013/08/28/understanding-the-fft ). Ich kämpfe darum zu verstehen, was Hindernisse.Form [0] und Hindernisse.Form [1] darstellen.
John Powell

Antworten:

1

Wie in den obigen Kommentaren angegeben, können Sie die Operation wahrscheinlich vektorisieren, um die for-Schleifen zu entfernen und effizienter zu gestalten.

Wenn Sie das Problem jedoch auf eine etwas andere Art und Weise betrachten - die des Schwellenwerts -, können Sie die Tools von scipy ndimage nutzen, um die Hindernisse zu zählen:

Schwellen Sie zunächst Ihre Geländedaten anhand Ihrer Signalhöhe, um unabhängig vom Ursprung ein boolesches Array zu erhalten, in dem sich das Signal befinden könnte.

signal_reach = terrain < signal_height

Dann können Sie die ndimage.labelMethode verwenden, um diskrete Regionen zu gruppieren:

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

Sobald dies erledigt ist, erhalten Sie die Regions-IDs, die mit den Ursprungszellen Ihres Signals übereinstimmen. In Ihrem Fall wäre es die erste Spalte.

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]

Jetzt liegt der Schwellenwert dort, wo das Signal das Gelände + Hindernisse abfängt, und dieses Mal werden Bereiche außerhalb oder außerhalb des interessierenden Bereichs mithilfe von herausgefiltert numpy.isin.

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

In einer letzten Runde von können ndimage.labelSie die abgefangenen Hindernisse zählen, da wir bereits vom Gelände blockierte Bereiche herausgefiltert haben:

obstacles_hit, obstacle_count = ndimage.label(signal_intercepted)

Hier gibt es etwas mehr Code, aber es gibt zwei große Vorteile:

  • Nein für Schleifen bedeutet, dass der Code relativ schnell sein sollte.
  • Und zu Berechnungszwecken kann der Signalursprung auf oder auf vielen Zellen irgendwo im Gelände-Raster liegen.
om_henners
quelle
1
Das sieht nach einem vielversprechenden Ansatz aus! Ich werde es im Januar testen und als Slution kennzeichnen, wenn es funktioniert.
Zoran