Anwenden der Quaternionsrotation auf eine Vektorzeitreihe
Ich habe eine Zeitreihe von 3D-Vektoren in einem Python-Numpy-Array, die der folgenden ähnelt:
array([[-0.062, -0.024, 1. ],
[-0.071, -0.03 , 0.98 ],
[-0.08 , -0.035, 0.991],
[-0.083, -0.035, 0.98 ],
[-0.083, -0.035, 0.977],
[-0.082, -0.035, 0.993],
[-0.08 , -0.034, 1.006],
[-0.081, -0.032, 1.008],
.......
Ich möchte jeden Vektor um einen bestimmten Winkel um eine bestimmte Achse drehen theta
. Ich habe Quaternionen verwendet, um dies für einen Vektor zu erreichen, wie hier in Hennerays Antwort zu finden ist.
v1 = np.array ([1, -2, 0])
axis = np.array([-4, -2, 3])
theta = 1.5
rot_axis = np.insert(axis, 0, 0, axis=0)
axis_angle = (theta*0.5) * rot_axis/np.linalg.norm(rot_axis)
vec = quat.quaternion(*v1)
qlog = quat.quaternion(*axis_angle)
q = np.exp(qlog)
v_prime = q * vec * np.conjugate(q)
v_prime_vec = v_prime.imag
Meine Frage ist, was ist der schnellste Weg, um die gleiche Drehung auf jeden Vektor in v1 anzuwenden?
Sie können keine Quaternion erstellen, v1
wenn sie v1
ein 2D-Array von Vektoren enthält. Daher könnte ich eine Schleife verwenden, um jedes Array-Element nacheinander zu drehen. In der Antwort von Henneray im obigen Link wird jedoch erwähnt, dass die Quaternionen auf "entsprechend vektorisierte Numpy-Arrays" angewendet werden könnten. Hat jemand Vorschläge, wie dies umgesetzt werden könnte?
(Eine Nebenfrage: Wenn my theta
und axis
variables Arrays mit der gleichen Länge wie v1 wären , könnte dieselbe Methode auch verwendet werden, um jeden Vektor in v1 durch eine entsprechende Drehung zu drehen?)
Antworten
Es ist notwendig, zuerst die kartesischen [x, y, z] -Vektoren in 4-Vektoren umzuwandeln, wobei die erste Komponente gleich Null ist [0, x, y, z]. Anschließend können Sie dies in ein Quaternion-Array umwandeln, um vektorisierte Berechnungen durchzuführen.
Diese Funktion unten nimmt ein Array von kartesischen Vektoren und dreht sie um eine einzelne Rotationsachse. Sie müssen sicherstellen, dass die Norm dieser Achse Ihrem Drehwinkel Theta entspricht.
def rotate_vectors(vecs, axis):
"""
Rotate a list of 3D [x,y,z] vectors about corresponding 3D axis
[x,y,z] with norm equal to the rotation angle in radians
Parameters
----------
vectors : numpy.ndarray with shape [n,3]
list of [x,y,z] cartesian vector coordinates
axis : numpy.ndarray with shape [3]
[x,y,z] axis to rotate corresponding vectors about
"""
# Make an 4 x n array of zeros
vecs4 = np.zeros([vecs.shape[0],vecs.shape[1]+1])
# Fill the imaginary i, j, k components with x, y, z values, leaving the real part w=0
vecs4[:,1:] = vecs
# Convert to quaternion array
vecsq = quat.as_quat_array(vecs4)
# Make a rotation quaternion
qrot = quat.from_rotation_vector(axis)
# Rotate vectors
vecsq_rotated = qrot * vecsq * qrot.conjugate()
# Cast quaternion array to float and return only imaginary components (ignore real part)
return quat.as_float_array(vecsq_rotated)[:,1:]
Als Bonus benötigt diese Funktion eine Reihe von Rotationsachsen, um jeden Vektor um die entsprechenden Achsen zu drehen.
def rotate_vectors_each(vecs, axes):
"""
Rotate a list of 3D [x,y,z] vectors about corresponding 3D axes
[x,y,z] with norm equal to the rotation angle in radians
Parameters
----------
vectors : numpy.ndarray with shape [n,3]
list of [x,y,z] cartesian vector coordinates
axes : numpy.ndarray with shape [n,3]
axes to rotate corresponding vectors about
n = pulse shape time domain
3 = [x,y,z]
"""
# Make an 4 x n array of zeros
vecs4 = np.zeros([vecs.shape[0],vecs.shape[1]+1])
# Fill the imaginary i, j, k components with x, y, z values, leaving the real part w=0
vecs4[:,1:] = vecs
# Convert to quaternion array
vecsq = quat.as_quat_array(vecs4)
# Make an 4 x n array of zeros
rots4 = np.zeros([rots.shape[0],rots.shape[1]+1])
# Fill the imaginary i, j, k components with x, y, z values, leaving the real part w=0
rots4[:,1:] = rots
# Convert to quaternion array and take exponential
qrots = np.exp(quat.as_quat_array(0.5 * rots4))
# Rotate vectors
vecsq_rotated = qrots * vecsq * qrots.conjugate()
return quat.as_float_array(vecsq_rotated)[:,1:]
Beachten Sie, dass Sie bei so vielen Konvertierungen zwischen Achsenwinkel und Quaternionendarstellung nur eine geringe Leistungsverbesserung gegenüber der Rotationsmatrixalgebra erzielen. Quaternionen profitieren wirklich nur, wenn Sie einen Vektor durch viele aufeinanderfolgende Rotationen drehen, wobei Sie die Quaternionsmultiplikation stapeln können.
Eine "schnelle" Möglichkeit, die Rotationsberechnung selbst durchzuführen, besteht darin, Ihre Quaternion in eine Kosinusmatrix in 3x3-Richtung umzuwandeln, Ihre Vektoren in einer einzigen zusammenhängenden 3xN-Matrix zu haben und dann eine BLAS-Bibliotheksroutine (z. B. dgemm) aufzurufen, um einen Standard zu erstellen Matrix multiplizieren. Eine gute BLAS-Bibliothek mit großem N würde diese Berechnung mit mehreren Threads durchführen.