ベクトルを回転させたい場合は、クォータニオンを正規化する必要があることを知っています。
しかし、クォータニオンを自動的に正規化しない理由はありますか?そして、ある場合、どのクォータニオン操作が正規化されていないクォータニオンになりますか?
- 2つのクォータニオンを乗算しますか?
- 内積?
申し訳ありませんが、この質問が少しあいまいな場合。私はまだ四元数に頭を包み込もうとしています。
ベクトルを回転させたい場合は、クォータニオンを正規化する必要があることを知っています。
しかし、クォータニオンを自動的に正規化しない理由はありますか?そして、ある場合、どのクォータニオン操作が正規化されていないクォータニオンになりますか?
申し訳ありませんが、この質問が少しあいまいな場合。私はまだ四元数に頭を包み込もうとしています。
遅い対応; この回答は、質問者ではなく、将来この質問に出くわす人々のためのものです。
たまにクォータニオンを正規化することだけに関して、他の2つの答えには同意しません。クォータニオンを使用してベクトルを回転/変換する、または回転/変換行列を生成するための標準式は、クォータニオンが正規化されていることを暗黙的に想定しています。正規化されていないクォータニオンを使用した結果として生じるエラーは、クォータニオンの大きさの2乗に比例します。二乗誤差の増加は避けるのが最善です。
頻繁に正規化する場合は、平方根は必要ありません。一次近似は非常にうまく機能します。IEEEが2倍になり、多少定型化されているため、クォータニオンに使用するものは次のとおりです。
double qmagsq = quat.square_magnitude();
if (std::abs(1.0 - qmagsq) < 2.107342e-08) {
quat.scale (2.0 / (1.0 + qmagsq));
}
else {
quat.scale (1.0 / std::sqrt(qmagsq));
}
推定に2.0/(1.0+qmagsq)
は、1次のテイラー展開ではなく1次のパデ近似を使用していることに注意してください。この近似は、有効な場合、平方根呼び出しを単純な除算に置き換えます。重要なのは、その近似がいつ有効になるかを見つけることです。ここで、マジックナンバー2.107342e-08が機能します。0.5*(3.0-qmagsq)
1.0/std::sqrt(qmagsq)
なぜパデ近似なのか?2つの理由。1つは、値がqmagsq
1に近い場合、1+qmagsq
精度の低下が。よりも低くなること3-qmagsq
です。もう1つは、パデ近似がテイラー展開と比較して誤差を3分の1に削減することです。qmagsq
0〜2の値の場合、この近似の誤差は。未満です(1-qmagsq)^2 / 8
。マジックナンバー2.107342e-08は、このエラーがIEEE2倍のULPの半分以上である場所を表しています。妥当な小さなステップを踏んでいる場合、クォータニオンの大きさの2乗は常にその制限内になります。に電話することはありませんsqrt
。
この「常に正規化する」パラダイムの1つの例外は、リー群積分手法を使用してクォータニオンを伝播する場合です。それが何を意味するのかわからない場合は、おそらくq(t+Δt) = q(t) + dq(t)/dt*Δt
クォータニオンを伝播するために同等のものを使用しています。リー群積分器ではない高階積分手法を使用している場合でも、どこかでそのオイラーステップを使用しています。
浮動小数点歳差運動エラーにより単位長ではなくなるため、クォータニオンを生成する操作は正規化する必要があります。
パフォーマンス上の理由から、正規化を自動的に実行する標準ルーチンには反対することをお勧めします。有能なプログラマーは、精度の問題を認識し、必要に応じて数量を正規化できる必要があります。また、単位長のクォータニオンが常に必要なわけではありません。
ベクトル演算についても同じことが言えます。
おかしなことに、回転行列の作成は、クォータニオンの正規化が不要な1つの操作であり、1つ節約できますsqrt
。
M = [w*w+x*x-y*y-z*z, 2*(-w*z+x*y), 2*(w*y+x*z);
2*(w*z+x*y), w*w-x*x+y*y-z*z, 2*(-w*x+y*z);
2*(-w*y+x*z), 2*(w*x+y*z), w*w-x*x-y*y+z*z] / (w*w+x*x+y*y+z*z)
(MATLAB風の表記法で)クォータニオンの場合w+x*i+y*j+z*k
。
さらに、同次座標と4x4変換行列を使用している場合は、除算操作を節約することもできます。クォータニオンが正規化されているかのように3x3回転部分を作成し、その2乗の長さを(4,4)要素に入れます。 :
M = [w*w+x*x-y*y-z*z, 2*(-w*z+x*y), 2*(w*y+x*z), 0;
2*(w*z+x*y), w*w-x*x+y*y-z*z, 2*(-w*x+y*z), 0;
2*(-w*y+x*z), 2*(w*x+y*z), w*w-x*x-y*y+z*z, 0;
0, 0, 0, w*w+x*x+y*y+z*z].
完全な変換を行うには、通常どおり、変換行列などを掛けます。このようにして、たとえば、
[xh yh zh wh]' = ... * OtherM * M * [xold yold zold 1]';
[xnew ynew znew] = [xh yh zh] / wh.
もちろん、少なくとも時々クォータニオンを正規化することをお勧めします(他の操作でも必要になる場合があります)。
単位クォータニオンがその1次導関数を数値積分することによって得られる場合、積分器は単純なエラーフィードバックを使用してそれを自動的に正規化できます。
qがクォータニオンの4行1列の行列を表し、dqがその時間微分を表すとします。次に、dqの代わりにdq + 0.5(1-qq)q / tauを積分器に送信し、適切な時定数tauを使用すると、 qが継続的に正規化されます。qqは内積を表します。
重力のない空間に360万秒間浮かんでいる、保守的で関節のあるブリカードメカニズムをシミュレートしました。これは約42日です。クォータニオンは、フローティングベースボディの方向を表しています。総エネルギーは、0.5秒の時定数タウを使用して100万分の1以内に一定のままでした。数値積分器DEでは、10^-12の絶対許容誤差とゼロの相対許容誤差が使用されました。
http://www.amazon.com/Computer-Solution-Ordinary-Differential-Equations/dp/0716704617/
クォータニオンは、多くの場合、数値積分によって取得されます。それらが積分器内で正規化されていない場合、振幅と位相の誤差が蓄積されます。正規化されたクォータニオンは単位球に沿って移動し、その1次導関数はその球に接します。クォータニオンが単位球から離れる方向にドリフトすると、積分器の外部で正規化しても修正できない位相エラーが蓄積され始めます。したがって、位相誤差を最小限に抑えるために、クォータニオンは数値積分器内で連続的に正規化する必要があります。
あなたの質問はあいまいですが、クォータニオンを正規化する必要がある場合は簡単です
q_normalized = q / square(norm(q))
で、q = q1 + q2i + q3 j + q4 kノルム(q)=(q1)^ 2 +(q2)^ 2 +(q3)^ 2)+(q4)^ 4
他にあなたの質問を私に説明するなら
NONunitクォータニオンの使用は効率的です。
補間など、単位長を必要とする操作はごくわずかです。
いくつかのヒント:
したがって、ユニットクォータニオンのみを使用する必要はなく、一般的な方法です。すべてのユースケースについて、正規化を使用するかどうかを決定できます。個人的には、非ユニットクォータニオンを使用することを好みます。
警告:ユニットクォータニオンを使用する場合、数値エラーを忘れることがよくあります。たとえば、行列のクォータニオンから/への変換で、それでも単位が大きな数値の不安定性をもたらすと考えると、行列はスケーリングされ、抽出されたクォータニオンは無効になります。あなたはそのような実験を簡単に行うことができます。