转自:.html
对于一般线性插值来说:r=P0+(P1−P0)tr=P0+(P1−P0)t,其中t∈[0, 1],代表了插值矢量r末端在弦P0-P1上的位置。假如t取值为1/4、2/4、3/4即将P0P1弦长均分为4等份,可以看出其对应的弧长并不相等。靠近中间位置的弧长较长,而靠近两段处的弧长较短,这就意味着当t匀速变化时,代表姿态矢量的角速度变化并不均匀: To better solve the nonconstant rotation speed and normalization issues, we need an interpolation method known as spherical linear interpolation (usually abbreviated as slerp). Slerp is similar to linear interpolation except that instead of interpolating along a line, we’re interpolating along an arc on the surface of a sphere. Figure 10.21 shows the desired result. When using spherical interpolation at quarter intervals of t, we travel one-quarter of the arc length to get from orientation to orientation. We can also think of slerp as interpolating along the angle, or in this case, dividing the angle between the orientations into quarter intervals.
球面线性插值(Spherical linear interpolation,通常简称Slerp),是四元数的一种线性插值运算,主要用于在两个表示旋转的四元数之间平滑差值。下面来简单推导一下Slerp的公式。插值的一般公式可以写为:r=a(t)p+b(t)qr=a(t)p+b(t)q,现在要找到合适的a(t)和b(t)。注意单位向量p和q之间的夹角为θ,p和r之间的夹角为tθ,q和r之间的夹角为(1-t)θ:
注意这个公式有2个问题,必须在实现过程中加以考虑:
具体实现可以参考下面的代码:
#include <iostream>
#include <math.h>void slerp(float starting[4], float ending[4], float result[4], float t )
{float cosa = starting[0]*ending[0] + starting[1]*ending[1] + starting[2]*ending[2] + starting[3]*ending[3];// If the dot product is negative, the quaternions have opposite handed-ness and slerp won't take// the shorter path. Fix by reversing one quaternion.if ( cosa < 0.0f ) {ending[0] = -ending[0];ending[1] = -ending[1];ending[2] = -ending[2];ending[3] = -ending[3];cosa = -cosa;}float k0, k1;// If the inputs are too close for comfort, linearly interpolateif ( cosa > 0.9995f ) {k0 = 1.0f - t;k1 = t;}else {float sina = sqrt( 1.0f - cosa*cosa );float a = atan2( sina, cosa );k0 = sin((1.0f - t)*a) / sina;k1 = sin(t*a) / sina;}result[0] = starting[0]*k0 + ending[0]*k1;result[1] = starting[1]*k0 + ending[1]*k1;result[2] = starting[2]*k0 + ending[2]*k1;result[3] = starting[3]*k0 + ending[3]*k1;
}int main()
{float p[4] = {1,0,0,0};float q[4] = {0.707,0,0,0.707};float r[4] = {0};slerp(p,q,r,0.333);std::cout<<r[0]<<","<<r[1]<<","<<r[2]<<","<<r[3]<<std::endl;slerp(p,q,r,0.667);std::cout<<r[0]<<","<<r[1]<<","<<r[2]<<","<<r[3]<<std::endl;return 0;
}
根据论文,求四元数加权平均值的MATLAB程序如下:
% Q is an Nx4 matrix of quaternions. weights is an Nx1 vector, a weight for each quaternion.
% Qavg is the weightedaverage quaternion% Markley, F. Landis, Yang Cheng, John Lucas Crassidis, and Yaakov Oshman.
% "Averaging quaternions." Journal of Guidance, Control, and Dynamics 30,
% no. 4 (2007): 1193-1197.function [Qavg] = quatWAvgMarkley(Q, weights)% Form the symmetric accumulator matrix
M = zeros(4, 4);
n = size(Q, 1); % amount of quaternions
wSum = 0;for i = 1:nq = Q(i,:)';w_i = weights(i);M = M + w_i.*(q*q');wSum = wSum + w_i;
end% scale
M = (1.0/wSum)*M;% The average quaternion is the eigenvector of M corresponding to the maximum eigenvalue.
% Get the eigenvector corresponding to largest eigen value
[Qavg, ~] = eigs(M, 1);end
下面测试一组数据,6个姿态分别表示绕Z轴旋转一定角度,求其平均姿态:
>> Q = [1,0,0,0; 0.999,0,0,0.044; 0.999,0,0,0.035; 1,0,0,0.026; 1,0,0,0.017; 1,0,0,0.009] % 0°,5°,4°,3°,2°,1° rotation about Z-axis
>> w = ones(6,1) / 6
>> quatWAvgMarkley(Q, w)
输出结果为(-0.9998, 0, 0, -0.0218),代表的平均姿态为绕Z轴旋转2.498°
参考:
Rotations
Averaging Quaternions and Vectors
Maths - Quaternion Interpolation (SLERP)
Joint Orientation Smoothing [Unity C#]
“Average” of multiple quaternions?
Exchanging data between MATLAB and VREP
How would I apply an Exponential Moving Average to Quaternions?
本文发布于:2024-02-05 01:24:30,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170720871061772.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |