ベクトルを回転させたい場合は、クォータニオンを正規化する必要があることを知っています。
しかし、四元数を自動的に正規化しない理由はありますか?そして、もしあるなら、どのような四元数演算が非正規化された四元数をもたらすでしょうか?
この質問が少しあいまいな場合は申し訳ありません。私はまだ四元数に頭を巻きつけようとしています。
四元数を生成する演算はすべて、正規化する必要があります。これは、浮動小数点の歳差誤差により、演算が単位長にならないためです。
パフォーマンス上の理由から、標準化ルーチンが自動的に正規化を実行しないようにアドバイスします。有能なプログラマーは、精度の問題を認識し、必要に応じて数量を正規化できる必要があります。また、必ずしも単位長の四元数が必要なわけではありません。
同じことがベクトル演算にも当てはまります。
遅い対応;この回答は、質問者ではなく、将来この質問に出くわす人のためのものです。
時々四元数を正規化することに関してのみ、他の2つの答えには同意しません。クォータニオンを使用してベクトルを回転/変換したり、回転/変換行列を生成したりするための標準的な式は、暗黙的にクォータニオンが正規化されていると想定しています。正規化されていない四元数を使用した結果生じる誤差は、四元数の大きさの2乗に比例します。二次誤差の増加は、回避するのが最善です。
頻繁に正規化する場合、平方根は必要ありません。一次近似は非常にうまく機能します。これが、IEEEの倍精度浮動小数点数として使用され、やや様式化されたものです。
_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)
を推定するために、一次テイラー展開0.5*(3.0-qmagsq)
ではなく、一次パデ近似1.0/std::sqrt(qmagsq)
を使用していることに注意してください。この近似は、有効であれば、平方根の呼び出しを単純な除算で置き換えます。重要なのは、その近似値がいつ有効になるかを見つけることです。このとき、マジック番号2.107342e-08が役立ちます。
なぜパデ近似? 2つの理由。 1つは、qmagsq
の値が1に近い場合、_1+qmagsq
_は_3-qmagsq
_よりも精度が低くなることです。もう1つは、パデ近似がテイラー展開と比較して誤差を3倍に削減することです。 qmagsq
の値が0〜2の場合、この近似の誤差は_(1-qmagsq)^2 / 8
_未満です。マジック番号2.107342e-08は、このエラーがIEEEのULPダブルスの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回転部分を作成し、その二乗長を(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.
もちろん、少なくとも時折、クォータニオンを正規化することをお勧めします(他の操作でも必要になる場合があります)。
単位四元数がその一次導関数を数値積分することによって得られる場合、積分器は単純なエラーフィードバックを使用して自動的に正規化できます。
qを四元数の4 x 1列の行列とdqの時間微分で表すとしましょう。次に、dq + 0.5(1-qq)q/tauをdqの代わりに積分器に送信し、適切な時定数を使用します。 tauは継続的に正規化しますq。 q.qは内積を表します。
重力のないスペースに360万秒間浮遊する、保守的で明瞭なBricardメカニズムをシミュレーションしました。四元数は、フローティングベースボディの方向を表します。合計エネルギーは、0.5秒の時定数tauを使用して、100万分の1以内に一定のままでした。数値積分器DEでは、10 ^ -12の絶対誤差許容度とゼロの相対誤差許容度が使用されました。
http://www.Amazon.com/Computer-Solution-Ordinary-Differential-Equations/dp/0716704617/
四元数は、数値積分によって得られることがよくあります。積分器内で正規化されていない場合、振幅と位相の誤差が累積します。正規化されたクォータニオンは単位球に沿って移動し、その最初の微分はその球に正接します。四元数が単位球から離れると、積分器の外側で正規化することでは修正できない位相誤差が蓄積され始めます。したがって、位相誤差を最小限に抑えるには、数値積分器内でクォータニオンを継続的に正規化する必要があります。
あなたの質問は曖昧ですが、あなたが四元数を正規化する必要がある場合は簡単です
q_normalized = q/square(norm(q))
あり、q = q1 + q2i + q3 j + q4 kノルム(q)=(q1)^ 2 +(q2)^ 2 +(q3)^ 2)+(q4)^ 4
他にあなたの質問を説明してくれたら