scipy.spatial.transform.Rotation.

align_vectors#

classmethod Rotation.align_vectors(cls, a, b, weights=None, return_sensitivity=False)#

Schätzt eine Rotation zur optimalen Ausrichtung zweier Vektorsätze.

Findet eine Rotation zwischen den Bezugssystemen A und B, die einen Satz von Vektoren a und b, die in diesen Bezugssystemen beobachtet wurden, am besten ausrichtet. Die folgende Verlustfunktion wird minimiert, um die Rotationsmatrix \(C\) zu ermitteln:

\[L(C) = \frac{1}{2} \sum_{i = 1}^{n} w_i \lVert \mathbf{a}_i - C \mathbf{b}_i \rVert^2 ,\]

wobei \(w_i\) die weights für jeden Vektor sind.

Die Rotation wird mit dem Kabsch-Algorithmus geschätzt [1] und löst das Problem, das als „Pointing Problem“ oder „Wahba’s Problem“ bekannt ist [2].

Es gibt zwei Sonderfälle. Der erste Fall ist, wenn ein einzelner Vektor für a und b gegeben ist. In diesem Fall wird die Rotation mit dem kürzesten Abstand zurückgegeben, die b an a ausrichtet.

Der zweite Fall ist, wenn eines der Gewichte unendlich ist. In diesem Fall wird die Rotation mit dem kürzesten Abstand zwischen den primären Vektoren mit unendlichem Gewicht wie oben berechnet. Anschließend wird die Rotation um die ausgerichteten primären Vektoren berechnet, sodass die sekundären Vektoren gemäß der obigen Verlustfunktion optimal ausgerichtet sind. Das Ergebnis ist die Zusammensetzung dieser beiden Rotationen. Das Ergebnis dieses Verfahrens ist dasselbe wie beim Kabsch-Algorithmus, wenn das entsprechende Gewicht im Grenzwert gegen unendlich geht. Für einen einzelnen sekundären Vektor ist dies als „align-constrain“-Algorithmus bekannt [3].

Für beide Sonderfälle (einzelne Vektoren oder ein unendliches Gewicht) hat die Sensitivitätsmatrix keine physikalische Bedeutung und es wird ein Fehler ausgelöst, wenn sie angefordert wird. Bei einem unendlichen Gewicht fungieren die primären Vektoren als Zwangsbedingung mit perfekter Ausrichtung, sodass ihr Beitrag zu rssd auf 0 gesetzt wird, auch wenn sie unterschiedliche Längen haben.

Parameter:
aarray_like, shape (3,) oder (N, 3)

Vektorkomponenten, beobachtet im Ausgangsbezugssystem A. Jede Zeile von a bezeichnet einen Vektor.

barray_like, shape (3,) oder (N, 3)

Vektorkomponenten, beobachtet in einem anderen Bezugssystem B. Jede Zeile von b bezeichnet einen Vektor.

weightsarray_like shape (N,), optional

Gewichte, die die relative Bedeutung der Vektorbeobachtungen beschreiben. Wenn None (Standard), dann werden alle Werte in weights als 1 angenommen. Es kann genau ein Gewicht unendlich sein, und die Gewichte müssen positiv sein.

return_sensitivitybool, optional

Ob die Sensitivitätsmatrix zurückgegeben werden soll. Siehe Hinweise für Details. Standard ist False.

Rückgabe:
rotationRotation Instanz

Beste Schätzung der Rotation, die b nach a transformiert.

rssdfloat

Steht für „root sum squared distance“ (Wurzel aus der Summe der quadrierten Abstände). Quadratwurzel der gewichteten Summe der quadrierten Abstände zwischen den gegebenen Vektorsätzen nach der Ausrichtung. Sie ist gleich sqrt(2 * minimum_loss), wobei minimum_loss die Verlustfunktion ist, ausgewertet für die gefundene optimale Rotation. Beachten Sie, dass das Ergebnis auch mit den Magnituden der Vektoren gewichtet wird, sodass perfekt ausgerichtete Vektorpaare einen von Null verschiedenen rssd haben, wenn sie nicht die gleiche Länge haben. Je nach Anwendungsfall kann es daher wünschenswert sein, die Eingangsvektoren vor dem Aufruf dieser Methode auf Einheitslänge zu normalisieren.

sensitivity_matrixndarray, shape (3, 3)

Sensitivitätsmatrix der geschätzten Rotationsschätzung, wie in den Hinweisen erläutert. Wird nur zurückgegeben, wenn return_sensitivity True ist. Nicht gültig, wenn ein einzelnes Vektorpaar ausgerichtet wird oder wenn ein unendliches Gewicht vorhanden ist, in welchen Fällen ein Fehler ausgelöst wird.

Hinweise

Die Sensitivitätsmatrix gibt die Empfindlichkeit der geschätzten Rotation gegenüber kleinen Störungen der Vektormessungen an. Speziell betrachten wir den Fehler der Rotationsschätzung als einen kleinen Rotationsvektor des Bezugssystems A. Die Sensitivitätsmatrix ist proportional zur Kovarianz dieses Rotationsvektors, unter der Annahme, dass die Vektoren in a mit Fehlern gemessen wurden, die deutlich kleiner als ihre Längen sind. Um die tatsächliche Kovarianzmatrix zu erhalten, muss die zurückgegebene Sensitivitätsmatrix mit dem harmonischen Mittel [4] der Varianz bei jeder Beobachtung multipliziert werden. Beachten Sie, dass weights umgekehrt proportional zu den Beobachtungs-Varianzen sein sollen, um konsistente Ergebnisse zu erzielen. Wenn beispielsweise alle Vektoren mit der gleichen Genauigkeit von 0,01 gemessen werden (weights müssen alle gleich sein), dann sollten Sie die Sensitivitätsmatrix mit 0,01**2 multiplizieren, um die Kovarianz zu erhalten.

Siehe [5] für eine gründlichere Diskussion der Kovarianzschätzung. Siehe [6] für weitere Diskussionen über das „Pointing Problem“ und „minimal proper pointing“.

Referenzen

[3]

Magner, Robert, „Extending target tracking capabilities through trajectory and momentum setpoint optimization.“ Small Satellite Conference, 2018.

[5]

F. Landis Markley, „Attitude determination using vector observations: a fast optimal matrix algorithm“, Journal of Astronautical Sciences, Bd. 41, Nr. 2, 1993, S. 261-280.

[6]

Bar-Itzhack, Itzhack Y., Daniel Hershkowitz, und Leiba Rodman, „Pointing in Real Euclidean Space“, Journal of Guidance, Control, and Dynamics, Bd. 20, Nr. 5, 1997, S. 916-922.

Beispiele

>>> import numpy as np
>>> from scipy.spatial.transform import Rotation as R

Hier führen wir den grundlegenden Kabsch-Algorithmus aus, um zwei Vektorsätze bestmöglich auszurichten, wobei die letzten beiden Vektormessungen des b-Satzes verrauscht sind.

>>> a = [[0, 1, 0], [0, 1, 1], [0, 1, 1]]
>>> b = [[1, 0, 0], [1, 1.1, 0], [1, 0.9, 0]]
>>> rot, rssd, sens = R.align_vectors(a, b, return_sensitivity=True)
>>> rot.as_matrix()
array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.]])

Wenn wir die Rotation auf b anwenden, erhalten wir Vektoren, die nahe bei a liegen.

>>> rot.apply(b)
array([[0. , 1. , 0. ],
       [0. , 1. , 1.1],
       [0. , 1. , 0.9]])

Der Fehler für den ersten Vektor beträgt 0, und für die letzten beiden beträgt der Fehler die Magnitude 0,1. Der rssd ist die Quadratwurzel der Summe der gewichteten quadrierten Fehler, und die Standardgewichte sind alle 1. Daher wird in diesem Fall der rssd wie folgt berechnet: sqrt(1 * 0**2 + 1 * 0.1**2 + 1 * (-0.1)**2) = 0.141421356237308.

>>> a - rot.apply(b)
array([[ 0., 0.,  0. ],
       [ 0., 0., -0.1],
       [ 0., 0.,  0.1]])
>>> np.sqrt(np.sum(np.ones(3) @ (a - rot.apply(b))**2))
0.141421356237308
>>> rssd
0.141421356237308

Die Sensitivitätsmatrix für dieses Beispiel ist wie folgt:

>>> sens
array([[0.2, 0. , 0.],
       [0. , 1.5, 1.],
       [0. , 1. , 1.]])

Sonderfall 1: Rotation mit dem kürzesten Abstand zwischen einzelnen Vektoren finden

>>> a = [1, 0, 0]
>>> b = [0, 1, 0]
>>> rot, _ = R.align_vectors(a, b)
>>> rot.as_matrix()
array([[0., 1., 0.],
       [-1., 0., 0.],
       [0., 0., 1.]])
>>> rot.apply(b)
array([1., 0., 0.])

Sonderfall 2: Ein unendliches Gewicht. Hier finden wir eine Rotation zwischen primären und sekundären Vektoren, die exakt ausgerichtet werden kann.

>>> a = [[0, 1, 0], [0, 1, 1]]
>>> b = [[1, 0, 0], [1, 1, 0]]
>>> rot, _ = R.align_vectors(a, b, weights=[np.inf, 1])
>>> rot.as_matrix()
array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.]])
>>> rot.apply(b)
array([[0., 1., 0.],
       [0., 1., 1.]])

Hier müssen die sekundären Vektoren bestmöglich angepasst werden.

>>> a = [[0, 1, 0], [0, 1, 1]]
>>> b = [[1, 0, 0], [1, 2, 0]]
>>> rot, _ = R.align_vectors(a, b, weights=[np.inf, 1])
>>> rot.as_matrix()
array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.]])
>>> rot.apply(b)
array([[0., 1., 0.],
       [0., 1., 2.]])