ベクトル時系列へのクォータニオン回転の適用
次のようなPythonnumpy配列に3Dベクトルの時系列があります。
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],
.......
各ベクトルを指定された軸を中心に指定された角度で回転させたいtheta
。ここhennerayの回答にあるように、私はクォータニオンを使用して1つのベクトルに対してこれを実現しています。
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
私の質問は、v1の各ベクトルに同じ回転を適用する最も速い方法は何ですか?
ベクトルの2D配列が含まれているv1
場合からクォータニオンを作成することはできないため、v1
ループを使用して各配列要素を順番に回転させることができます。ただし、上記のリンクのhennerayの回答では、クォータニオンは「適切にベクトル化されたnumpy配列」に適用できると述べられています。誰かがこれをどのように実装できるかについて何か提案がありますか?
(副次的な質問:私の変数theta
とaxis
変数がv1と同じ長さの配列である場合、同じ方法を使用して、v1の各ベクトルを対応する回転で回転させることもできますか?)
回答
最初に[x、y、z]デカルトベクトルを4ベクトルに変換し、最初の成分がゼロ[0、x、y、z]に等しいようにする必要があります。次に、これをクォータニオン配列にキャストして、ベクトル化された計算を実行できます。
以下のこの関数は、デカルトベクトルの配列を取得し、それらを単一の回転軸を中心に回転させます。この軸のノルムが回転角シータと等しいことを確認する必要があります。
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:]
ボーナスとして、この関数は回転軸の配列を取り、対応する軸によって各ベクトルを回転させます。
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:]
軸角度とクォータニオン表現の間の変換が非常に多いため、回転行列代数よりもパフォーマンスがほとんど向上しないことに注意してください。クォータニオンは、実際には、ベクトルを多数の連続した回転で回転させている場合にのみメリットがあります。これにより、クォータニオンの乗算を積み重ねることができます。
回転計算自体を行う「高速」な方法の1つは、クォータニオンを3x3方向余弦行列に変換し、ベクトルを単一の3xN連続行列に入れてから、BLASライブラリルーチン(dgemmなど)を呼び出して標準を実行することです。行列の乗算。Nが大きい優れたBLASライブラリは、この計算をマルチスレッドで実行します。