Codeeffizienz: Koordinatentransformation einer Zeitreihe

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
SimonR
User
Beiträge: 4
Registriert: Montag 4. Juli 2011, 13:54

Hallo zusammen!

Erstmal möchte ich kurz mein Problem schildern:
Ich habe drei Arrays, mit Verläufen translatorischer Bewegungen (surge, sway und heave) und drei Arrays, die Winkelverläufe (roll, pitch und yaw) enthalten.
Die translatorischen Bewegungen eines bestimmten Punktes x, die aus den zeitlichen Winkeländerungen resultieren sollen auf die drei anderen Arrays addiert werden.

Die Drehmatrix berechne ich momentan für jeden Zeitpunkt neu (siehe Codeschnipsel unten)

Bild

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import numpy as np
import random

t = np.linspace(0,10,100)
tank_pos = np.array([25, 0, -5])

surge = np.cos(0.5 * t + random.uniform(0, 2*np.pi))
sway = np.cos(0.5 * t + random.uniform(0, 2*np.pi))
heave = np.cos(0.5 * t + random.uniform(0, 2*np.pi))
roll = np.cos(0.5 * t + random.uniform(0, 2*np.pi))
pitch = np.cos(0.5 * t + random.uniform(0, 2*np.pi))
yaw = np.cos(0.5 * t + random.uniform(0, 2*np.pi))

for n in range(0, len(surge)):
    R = np.array(
        [
            [
                np.cos(np.radians(pitch[n])) * np.cos(np.radians(yaw[n])),
                -np.cos(np.radians(roll[n])) * np.sin(np.radians(yaw[n])) + np.sin(np.radians(roll[n])) * np.sin(np.radians(pitch[n])) * np.cos(np.radians(yaw[n])),
                np.sin(np.radians(roll[n])) * np.sin(np.radians(yaw[n])) + np.cos(np.radians(roll[n])) * np.sin(np.radians(pitch[n])) * np.cos(np.radians(yaw[n]))
            ],
            [
                np.cos(np.radians(pitch[n])) * np.sin(np.radians(yaw[n])),
                np.cos(np.radians(roll[n])) * np.cos(np.radians(yaw[n])) + np.sin(np.radians(roll[n])) * np.sin(np.radians(pitch[n])) * np.sin(np.radians(yaw[n])),
                -np.sin(np.radians(roll[n])) * np.cos(np.radians(yaw[n])) + np.cos(np.radians(roll[n])) * np.sin(np.radians(pitch[n])) * np.sin(np.radians(yaw[n]))
            ],
            [
                -np.sin(np.radians(pitch[n])),
                np.sin(np.radians(roll[n])) * np.cos(np.radians(pitch[n])),
                np.cos(np.radians(roll[n])) * np.cos(np.radians(pitch[n]))
            ]
        ]
    )

    x = np.dot(R, tank_pos)
    surge[n] += x[0]
    sway[n] += x[1]
    heave[n] += x[2]

Meine Frage ist, wie ich das ganze effizienter gestalten kann, da das Berechnung recht lange dauert und die Arrays später durchaus 5 Mio. Datenpunkte enthalten können.

Kann ich irgendwie die das Produkt aus der Drehmatrix für die gesamte Zeitreihe und dem Ortsvektor in einem Schritt berechnen?

Besten Dank und viele Grüße
Simon
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hoi,

100%ig ist mir nicht klar, was Du da machst, aber:
- surge, sway, heave, etc. sind alle identisch generiert. Willst Du wirklich immer wieder gleich generierte Dinge an unterschiedliche Namen bilden? Oder tut es vielleicht ein dict?
- Iteration über eine Liste geht auch direkt, wenn Du *wirklich* Indices benötigst, verwendet 'enumerate'
- Wie Dein Arbeitscode aussehen soll, weiß ich nicht, aber vermeide besser die Konversion von Listen zu numpy.arrays und zurück. Numpy hat zum Beispiel ein random-Modul.
- Du berechnets viele Male "radians(x[n])". Warum nicht einen Zugriff und eine Transformation?, Also:

Code: Alles auswählen

transformed = radians(x[n])
#.... viele Berechnungen mit "transformed"
- Die Übung das auf np.cos/np.sin zu erweitern überlasse ich Dir. Im Allgemeinen gilt: Eine Berechnung, die immer dasselbe Ergebnis liefert, rechnet man schneller einmal aus als x-Mal. ;-)
- Für gewöhnlich bastelt man sich in solchen Fällen eine Transformationsmatrix und wendet diese auf die zu transformierende Matrix an. Schau mal hier oder hier. Du wirst im Netz noch x weitere, z. T. leichter verständliche Beispiele finden, ggf. sogar ein fertiges Model - für Deinen Fall keine ich aber leider keines*.
- Die Generierung und Applikation der Transformationsmatrix kannst Du in Funktionen verpacken. Dann steht Dir das multiprocessing-Modul offen, mit dem derartige Rechnungen sehr gut zu verteilen sind.
- Und wenn das Alles immer noch nicht hilft, sei Dir noch numexpr empfohlen, mit dem Du Speicherzugriffe bei array-Zuweisungen etwas performanter machen kannst.

HTH,
Christian

* Ich habe jetzt auch keine Zeit und muß mal echte Arbeit machen. Etwas Ähnliches wie Dein Problem habe ich zwar mal gemacht, habe aber keine Zeit mich jetzt einzufuchsen ;-)
SimonR
User
Beiträge: 4
Registriert: Montag 4. Juli 2011, 13:54

Vielen Dank für Deine Antwort.

Der von mir gepostete Code ist auf mein eigentliches Problem vereinfacht; die sechs Arrays sind sonst nicht identisch.
(Falls es interessiert: Ich habe Bewegungsspektren von Schiffen im Seegang generiert. Zeitreihen aus diesen Bewegungen (dt. Schnellen, Schwojen, Tauchen, Rollen, Stampfen, Gieren) sind in den Arrays enthalten)

Dein Hinweis mit der Radiant-Umrechnung hat die Rechendauer schon knapp halbiert. Das empfinde ich jetzt auch irgendwie als logisch... ;)
Danke!
- Wie Dein Arbeitscode aussehen soll, weiß ich nicht, aber vermeide besser die Konversion von Listen zu numpy.arrays und zurück. Numpy hat zum Beispiel ein random-Modul.
Kannst Du mir auf die Sprünge helfen? An welcher Stelle mache ich das? Wenn es np.linspace ist, was wäreb eine geeignete Alternative?

Deine Anderen Hinweise werde ich auch noch abarbeiten.

Dank Dir nochmal.

Grüße
Simon
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

SimonR hat geschrieben:
- Wie Dein Arbeitscode aussehen soll, weiß ich nicht, aber vermeide besser die Konversion von Listen zu numpy.arrays und zurück. Numpy hat zum Beispiel ein random-Modul.
Kannst Du mir auf die Sprünge helfen? An welcher Stelle mache ich das? Wenn es np.linspace ist, was wäreb eine geeignete Alternative?
Na ja, viel wird es nicht bringen, weil ich vermutet habe, daß die random.uniform-Aufrufe häufiger vorkommen. Dann wäre numpy.random.uniform() eine Alternative. -- Obwohl das ja eigentlich auch nichts mit Listen vs. Arrays zu tun hat :oops:

Ansonsten wird es noch sinnvoll sein wiederholte und identische np.cos und np.sin-Aufrufe zu bündeln - falls noch nicht geschehen.

Weitere Optimierung mag mit den Schritten gelingen, die ich oben beschrieb - aber von hier aus ist das schon etwas schwierig. Schreib' mal wie weit Du gekommen bist und wo es ggf. noch hängt, wenn Du noch nicht zufrieden bist.

Gruß,
Christian
Antworten