两个向量之间的夹角(Matlab)

7
我希望能够计算2个向量 V = [Vx Vy Vz]B = [Bx By Bz] 之间的夹角。这个公式正确吗?
VdotB = (Vx*Bx + Vy*By + Vz*Bz)

 Angle = acosd (VdotB / norm(V)*norm(B))

还有其他方法可以计算它吗?

我的问题不是为了规范化向量或使它更容易。我想知道如何获取这两个向量之间的角度。


1
似乎更像是数学问题而不是编程问题。 - Dennis Jaheruddin
2
根据您使用的编程语言,您应该添加括号以确保在除法之前计算乘积。如果按从左到右的顺序计算,这将是不正确的。 - Teepeemm
6个回答

18

根据这个链接,这似乎是最稳定的解决方案:

atan2(norm(cross(a,b)), dot(a,b))

1
这就是我感到困惑的原因,我不知道哪一个是正确的,也不知道为什么。 - Jack_111
2
只需通过我提供的链接阅读更多。理论上它们都是正确的,但在实践中,这个方法被认为提供了更稳定的结果(而使用acos的替代方法计算速度稍快)。 - Dennis Jaheruddin

2

有很多选择:

a1 = atan2(norm(cross(v1,v2)), dot(v1,v2))
a2 = acos(dot(v1, v2) / (norm(v1) * norm(v2)))
a3 = acos(dot(v1 / norm(v1), v2 / norm(v2)))
a4 = subspace(v1,v2)

以下是此mathworks线程中的所有公式。据说a3最稳定,但我不知道为什么。

对于存储在矩阵列上的多个向量,可以使用以下代码计算角度:

% Calculate the angle between V (d,N) and v1 (d,1)
% d = dimensions. N = number of vectors
% atan2(norm(cross(V,v2)), dot(V,v2))
c = bsxfun(@cross,V,v2);
d = sum(bsxfun(@times,V,v2),1);%dot
angles = atan2(sqrt(sum(c.^2,1)),d)*180/pi;

1
传统方法获取两个向量之间的夹角(即arccos(dot(u, v) / (norm(u) * norm(v))),如其他答案中所示)在几个边角情况下存在数字不稳定性。以下代码适用于n维和所有边角情况(它不检查长度为零的向量,但很容易添加)。请参见下面的注释。
% Get angle between two vectors
function a = angle_btw(v1, v2)

    % Returns true if the value of the sign of x is negative, otherwise false.
    signbit = @(x) x < 0;

    u1 = v1 / norm(v1);
    u2 = v2 / norm(v2);

    y = u1 - u2;
    x = u1 + u2;

    a0 = 2 * atan(norm(y) / norm(x));

    if not(signbit(a0) || signbit(pi - a0))
        a = a0;
    elseif signbit(a0)
        a = 0.0;
    else
        a = pi;
    end;

end

这段代码是根据Jeffrey Sarnoff(MIT许可证)的Julia实现修改而来,其本身基于W. Kahan教授(第15页)的这些笔记


0

该函数应返回以弧度为单位的角度。

function [ alpharad ] = anglevec( veca, vecb )
% Calculate angle between two vectors
alpharad = acos(dot(veca, vecb) / sqrt( dot(veca, veca) * dot(vecb, vecb)));
end

anglevec([1 1 0],[0 1 0])/(2 * pi/360) 
>> 45.00

0

您可以使用点运算符计算VdotB,并且可以更快地处理任意长度的向量,具体方法如下:

VdotB = sum(V(:).*B(:));

此外,正如评论中所提到的,Matlab有dot函数可以直接计算内积。
除此之外,公式本身就是这样的,你所做的是正确的。

4
如果您想要简洁,至少建议使用 V*B' - Dennis Jaheruddin
1
你是否有特别的原因避免使用内在的 dot 函数? - High Performance Mark
@HighPerformanceMark 除了忘记它的存在之外,没有其他的。 - Marc Claesen
没有任何原因,点函数很好用,只是我像这样写问题。 - Jack_111

0

Dennis Jaheruddin的解决方案 对于3D向量非常好用,对于更高维度的向量,我建议使用:

acos(min(max(dot(a,b)/sqrt(dot(a,a)*dot(b,b)),-1),1))

这个修复了数值问题,可以将acos的参数调整到接近1或-1。然而,当其中一个向量是零向量时,仍然存在问题。这种方法只需要3*N+1次乘法和1次平方根运算。但是,它还需要2次比较,而atan方法不需要。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接