Anwenden der Quaternionsrotation auf eine Vektorzeitreihe

Nov 24 2020

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, v1wenn sie v1ein 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 thetaund axisvariables 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

1 henneray Nov 26 2020 at 11:52

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.

1 JamesTursa Nov 25 2020 at 01:21

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.