图片缩略图

用于在DCM、Euler角度、四元数和Euler向量之间转换的函数

version 1.11.0.0 (5.71 KB) by 约翰·富勒
函数转换4种类型的旋转数据:DCM,欧拉角,四元数,欧拉参数。

29下载

更新2013年1月25日

视图版本历史

查看许可证

SpinCalc是一个整合的matlab函数,它将在包含的4种类型之间转换任何旋转数据。还将在两种不同的Euler角度集类型之间转换。

可以输入多个方向。N方向:
DCM==>3x3xN多维数组
EA ### ===> NX3矩阵
欧拉向量===> Nx4矩阵
四元数==>Nx4矩阵

输入包括错误检查标志,当欧拉角接近奇异点或适当的值偏离单位时发出警告。错误的DCM等致命错误。

* * * * *注意* * * * *用户
我遇到了很多关于平移到欧拉角集的问题。当将数据转换为欧拉角时,必须确保所转换的方向不在奇异点附近。奇异欧拉集是在特定的旋转顺序中不能唯一转换为3个变量的方向。奇异集如下:

第一类旋转:123-132-213-231-321-312
如果第二个旋转角度为-90或90度,则为单数。

类型2旋转:121-131-212-232-313-323
如果第二个旋转角度为0或180度,则为单数。

SpinCalc现在应该检测输入DCM、EV或Q何时对应一个奇异欧拉集输出。它将禁止在这样的事件中输出。

自然地,当从这些奇异的Euler角度集转换为其他数据类型时,您将得到正确的答案。不幸的是,您无法将该输出转换回正确的Euler角度集。这就是为什么禁止使用单欧拉输入。

一些用户可能需要SpinCalc,因为他们需要将奇异欧拉集转换为其他类型。在这些情况下,删除禁用的错误检查应该不会太难。如果需要帮助,请与我联系。

引用

约翰•富勒(2021)。用于在DCM、Euler角度、四元数和Euler向量之间转换的函数(//www.tatmou.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors), MATLAB中央文件交换。检索.

意见及评分(63)

史蒂夫Kiskamp

看起来像广告上说的那样有效!但是我对版本号感到困惑:上面的描述是1.11.0.0,文件是1.3。我假设它是文件没有更新的版本号。

alexey.

克里斯

太棒了,选择太多了。

金俊硕

马特J.

谢谢,这看起来很全面。然而,欧拉角计算中的奇异性误差是一个主要的不便。如果你能给用户一个选项,通过一些标志,告诉代码她是否关心计算出的欧拉角的唯一性,那就太好了。

斯特凡爷爷

Yun彭

亲爱的约翰,

谢谢你的光临。请问你能帮我如何使用你的函数从“zyx”欧拉角得到四元数吗?
非常感谢你提前:)

默罕默德

约翰·富勒

德文德拉,
听起来好像您的转换字符串命令与程序需要指示它做哪个操作的内容不匹配。转换字符串应该是这样的:

“EA321toDCM”

其中两种旋转格式类型之间始终有一个“to”。该文件的标题列出了所有可能的转换。

谢谢
约翰

Devendra Gangadayal.

你好,约翰,
希望您能帮助我。
不确定为什么我得到这个错误时,我运行你的下载文件:

???输入参数"CONVERSION"未定义。

错误在==> SpinCalc在62
i_type = strfind(低(转换)',');

提前非常感谢
德文德拉

杰弗里Vaquette

约翰·富勒

阿里,
如果您正在寻找预先乘以向量移动该向量的DCM,那么它将出现像DCM正在转换。此功能是有意产生输出的输出,旋转框架的框架,而不是帧内的向量。如果您只需要DCM旋转框架内的向量,则始终需要转换输出。

约翰

阿里Aghaeifar

从四元数到DCM的转换产生所需矩阵的转置。

托马斯Corie

非常有用的。我也在尝试类似的东西,但这就是我所想的,甚至更多。谢谢你!

汉族的太阳

菲利克斯•戈德堡

伟大的工作。

王shangcheng“山姆”

非常实用的工具集。如果能提供文献参考,那就太棒了。

约翰·富勒

Tim,很抱歉回复晚了,我丢失了我的登录邮箱很长一段时间,并且没有收到关于SpinCalc的更新。

这个值确实是2度,注释可能已经过时了。我很快会提交一个更新的版本来调整这个。您可以根据需要修改错误检查值(有些人完全删除它)。

蒂姆标志

感谢您提供了这个非常有用的工具。
我认为在.m文件顶部的注释中有一个小错误(如果您输入“help SpinCalc”会看到这个错误)。注释显示“如果中间角度在奇点值的0.1度范围内,则禁止输出”。但实际上,如果中间角度与奇异值的距离小于2°,则输出是禁止的。

丹尼尔·卢塞纳

我应该添加什么来代替tol和ichk?我分别替换为0.0001和0,但它不起作用。谢谢

这很有帮助

斯宾塞

欧拉角的定义是“身体固定”还是“世界固定”?

约翰·富勒

史蒂夫,
老实说,我只是在大多数情况下使用“eps”。十有八九它不会对问题产生太大的约束。当它确实失败时,你可以提高它的依从性。

谢谢
约翰

史蒂夫

嘿,非常感谢分享这个代码!这对我帮助很大。
但我有一个问题:
您是否可以为公差值提供推荐,从RotationMatrix转换到Eulerangles?
谢谢

保罗·德莱瓦

这是不好的。我的第二篇文章被matlabcentral完全删除了,可能是因为它包含特殊字符……

我写过,在您最新的SpinCalc版本中,您在第238行引入了一个新错误。

在这一行(我不能在这里复制,因为它包含特殊字符),您应该使用一个元素一个元素的OR运算符(单个竖条),而不是短路OR运算符(双竖条),后者在N大于1时不起作用。

简而言之,您应该返回以前版本的第238行。

也请查看我昨天发布的4条建议。

保罗·德莱瓦

MATLAB Central一直在截断我在特殊字符之后写的所有内容。在我最近的帖子中,逻辑或运算符以及在它们之后写的任何东西都被删除了。无论如何,您可以检查第238行以前的版本。应该使用逐个元素的OR操作符(单竖条),而不是短路的OR操作符(双竖条)。

保罗·德莱瓦

我一直试图发布这篇文章,但MatlabCentral一直在截断它。以下是完整版本,删除了特殊字符:

1)请更新版本号。

2) 388行:

输出=mod([psi,θ,φ]*180/pi,360);

提出了改变:

输出= [psi,theta,phi] * 180 / pi;

THETA在代码中使用ACOS或ASIN进行计算。在MATLAB中,ACOS(X)和ASIN(X)都在一定范围内返回值。对于-1 =< X =< 1,

ACOS_X =这些“可信赖医疗组织”(X) *(180 /π)

总是返回从0到180度的值。这几乎与SpinCalc接受的范围(从0.1到179.9度)一致,作为THETA (EA type 2旋转)的输入。同理,当-1 =< X =< 1时,

ASIN_X =正如(X) *(180 /π)

始终返回从-90到90度的角度。同样,这几乎与SpinCalc接受作为θ输入的范围(从-89.9到89.9度)一致(EA类型1旋转)。如果X<-1或X>1,则结果ACOS_X或ASIN_X是复杂的,SpinCalc返回错误消息。
计算MOD(ACOS_X,360)是没有用的,因为

= mod (acos_x, 360) = acos_x

更重要的是,计算MOD(ASIN_X,360)与代码的其他部分不一致,因为对于ASIN_X的负值(即-90 =< ASIN_X < 0°)

= mod (asin_x, 360) == asin_x + 360

这意味着,对于ASIN_X的负值,THETA的范围将从270 =< ASIN_X < 360度,这被认为是超出了SpinCalc的输入范围(EA type 1旋转)。

3) 396行:

sing_chk =…
[find(abs(θ*180/pi)<0.1)。。。
找到(abs(θ* 180 / pi - 180) < 0.1);…
发现(abs(θ*180/pi-360))<0.1];

提出了改变:

sing_chk =…
[find(abs(θ*180/pi)<0.1)。。。
找到(abs(θ* 180 / pi - 180) < 0.1);…
发现(绝对稳定系数(θ*180/pi-360)<0.1)];

4)每次你把一个包含弧度角度的Nx1或Nx3数组转换成包含角度角度的数组,或者反过来(你在你的代码中做了很多次,包括上面提到的第388行和396行),你使用这个语法:

Y = X * 180 /π

y = x * pi / 180

这样,你重复分割(通过pi或180)n次。我建议您使用此Sintax,只要只计算该划分一次(参见函数DEG2RAD和RAD2DEG),这会更有效:

y = x *(180 / pi)

Y = X *(π/ 180)。

保罗·德莱瓦

我试图发布这篇文章,其中包含一些关于SpinCalc的注释,但网站一直在截断它。以下是完整的版本,去掉了一些特殊字符:

1)请更新版本号。

2) 388行:

输出=mod([psi,θ,φ]*180/pi,360);

提出了改变:

输出= [psi,theta,phi] * 180 / pi;

THETA在代码中使用ACOS或ASIN进行计算。在MATLAB中,ACOS(X)和ASIN(X)都在一定范围内返回值。对于-1 <= X <= 1,

ACOS_X =这些“可信赖医疗组织”(X) *(180 /π)

始终返回0到180度范围内的值。这几乎与SpinCalc接受的θ输入范围(从0.1度到179.9度)一致(带有“输入类型”EA####和“Euler类型”2)。类似地,对于-1<=X<=1,

ASIN_X =正如(X) *(180 /π)

始终返回范围为-90到90度的角度。同样,这几乎与SpinCalc接受为θ输入的范围(从-89.9到89.9度)一致(带有“输入类型”EA#####和“Euler类型”1)。如果X>1或X<-1,则结果ACOS#X或ASIN#X是复杂的,SpinCalc返回错误消息。
计算MOD(ACOS_X,360)是没有用的,因为

= mod (acos_x, 360) = acos_x

更重要的是,计算Mod(ASIN_X,360)与代码的其他部分不一致,因为对于ASIN_X的负值(即-90 <= ASIN_X <0度)

= mod (asin_x, 360) == asin_x + 360

这意味着,对于ASIN_X的负值,θ将从270 <= asin_x <360度的范围内,当用作Spincalc的输入(带有“输入类型”EA ###和“Euler类型”时被认为是OUT范围。1)。

3) 396行:

sing_chk =…
[find(abs(θ*180/pi)<0.1)。。。
找到(abs(θ* 180 / pi - 180) < 0.1);…
发现(abs(θ*180/pi-360))<0.1];

提出了改变:

sing_chk =…
[find(abs(θ*180/pi)<0.1)。。。
找到(abs(θ* 180 / pi - 180) < 0.1);…
发现(绝对稳定系数(θ*180/pi-360)<0.1)];

4)每次你把一个包含弧度角度的Nx1或Nx3数组转换成包含角度角度的数组,或者反过来(你在你的代码中做了很多次,包括上面提到的第388行和396行),你使用这个语法:

Y = X * 180 /π

y = x * pi / 180

这样,你重复分割(通过pi或180)n次。我建议您使用此Sintax,只要只计算该划分一次(参见函数DEG2RAD和RAD2DEG),这会更有效:

y = x *(180 / pi)

Y = X *(π/ 180)。

保罗·德莱瓦

我试图发布这篇文章,其中包含一些关于SpinCalc的注释,但网站一直在截断它。以下是完整的版本,去掉了一些特殊字符:

1)请更新版本号。

2) 388行:

输出=mod([psi,θ,φ]*180/pi,360);

提出了改变:

输出= [psi,theta,phi] * 180 / pi;

THETA在代码中使用ACOS或ASIN进行计算。在MATLAB中,ACOS(X)和ASIN(X)都在一定范围内返回值。1 < = X < = 1,

ACOS_X =这些“可信赖医疗组织”(X) *(180 /π)

总是返回从0到180度的值。这几乎与SpinCalc接受的范围(从0.1到179.9度)一致,作为THETA的输入(“输入类型”EA###和“欧拉类型”2)。

ASIN_X =正如(X) *(180 /π)

始终返回范围为-90到90度的角度。同样,这几乎与SpinCalc接受为θ输入的范围(从-89.9到89.9度)一致(带有“输入类型”EA####和“Euler类型”1)。如果X>1或X<-1,则结果ACOS_X或ASIN_X是复杂的,SpinCalc返回一个错误消息。
计算MOD(ACOS_X,360)是没有用的,因为

= mod (acos_x, 360) = acos_x

更重要的是,计算MOD(ASIN_X,360)与代码的其他部分不一致,因为对于ASIN_X的负值(即-90<=ASIN_X<0°)

= mod (asin_x, 360) == asin_x + 360

这意味着,当ASIN_X为负值时,THETA的范围为270<=ASIN_X<360°,当作为SpinCalc的输入时(“输入类型”EA###和“Euler类型”1),则认为THETA超出了范围。

3) 396行:

sing_chk =…
(找到(abs(θ* 180 / pi) < 0.1);...
求(绝对值(θ*180/π-180)<0.1);。。。
找到(abs(θ* 180 /π- 360))< 0.1);

提出了改变:

sing_chk =…
(找到(abs(θ* 180 / pi) < 0.1);...
求(绝对值(θ*180/π-180)<0.1);。。。
找到(abs(θ* 180 / pi - 360) < 0.1)];

4)每次你把一个包含弧度角度的Nx1或Nx3数组转换成包含角度角度的数组,或者反过来(你在你的代码中做了很多次,包括上面提到的第388行和396行),你使用这个语法:

Y = X * 180 /π

y = x * pi / 180

这样,你重复分割(通过pi或180)n次。我建议您使用此Sintax,这更高效,只能计算该部门一次:

y = x *(180 / pi)

Y = X *(π/ 180)。

保罗·德莱瓦

2) 388行:

输出=mod([psi,θ,φ]*180/pi,360);

提出了改变:

输出= [psi,theta,phi] * 180 / pi;

THETA在代码中使用ACOS或ASIN进行计算。在MATLAB中,ACOS(X)和ASIN(X)都在一定范围内返回值。1 < = X < = 1,

ACOS_X =这些“可信赖医疗组织”(X) *(180 /π)

总是返回从0到180度的值。这几乎与SpinCalc接受的范围(从0.1到179.9度)一致,作为THETA的输入(“输入类型”EA###和“欧拉类型”2)。

ASIN_X =正如(X) *(180 /π)

始终返回范围为-90到90度的角度。同样,这几乎与SpinCalc接受为θ输入的范围(从-89.9到89.9度)一致(带有“输入类型”EA####和“Euler类型”1)。
如果X>1或X<-1,则结果ACOS_X或ASIN_X是复杂的,SpinCalc返回一个错误消息。
计算MOD(ACOS_X,360)是没有用的,因为

= mod (acos_x, 360) = acos_x

更重要的是,计算MOD(ASIN_X,360)与代码的其他部分不一致,因为对于ASIN_X的负值(即-90<=ASIN_X<0°)

= mod (asin_x, 360) == asin_x + 360

这意味着,当ASIN_X为负值时,THETA的范围为270<=ASIN_X<360°,当作为SpinCalc的输入时(“输入类型”EA###和“Euler类型”1),则认为THETA超出了范围。

保罗·德莱瓦

关于代码的其他一些建议:
--------

请更新发布版本号。

--------

第388行:

输出=mod([psi,θ,φ]*180/pi,360);

提出了改变:

输出= [psi,theta,phi] * 180 / pi;

THETA在代码中使用ACOS或ASIN进行计算。在MATLAB中,ACOS(X)和ASIN(X)都在一定范围内返回值。1 < = X < = 1,

ACOS_X =这些“可信赖医疗组织”(X) *(180 /π)

总是返回从0到180度的值。这几乎与SpinCalc接受的范围(从0.1到179.9度)一致,作为THETA的输入(“输入类型”EA###和“欧拉类型”2)。

ASIN_X =正如(X) *(180 /π)

始终返回范围为-90到90度的角度。同样,这几乎与SpinCalc接受为θ输入的范围(从-89.9到89.9度)一致(带有“输入类型”EA####和“Euler类型”1)。
如果X>1或X<-1,则结果ACOS_X或ASIN_X是复杂的,SpinCalc返回一个错误消息。
计算MOD(ACOS_X,360)是没有用的,因为

= mod (acos_x, 360) = acos_x

更重要的是,计算MOD(ASIN_X,360)与代码的其他部分不一致,因为对于ASIN_X的负值(即-90<=ASIN_X<0°)

= mod (asin_x, 360) == asin_x + 360

这意味着,当ASIN_X为负值时,THETA的范围为270<=ASIN_X<360°,当作为SpinCalc的输入时(“输入类型”EA###和“Euler类型”1),则认为THETA超出了范围。

---------

第396行:

sing_chk =…
(找到(abs(θ* 180 / pi) < 0.1);...
求(绝对值(θ*180/π-180)<0.1);。。。
找到(abs(θ* 180 /π- 360))< 0.1);

提出了改变:

sing_chk =…
(找到(abs(θ* 180 / pi) < 0.1);...
求(绝对值(θ*180/π-180)<0.1);。。。
找到(abs(θ* 180 / pi - 360) < 0.1)];

--------------------------------

每次将包含弧度中的角度的nx1或nx3数组转换为以度数的角数组,反之亦然(并且在您的代码中执行大量的次数,包括上述行388和396),您使用此句法:

Y = X * 180 /π

y = x * pi / 180

这样,你重复分割(通过pi或180)n次。我建议您使用此Sintax,这更高效,只能计算该部门一次:

y = x *(180 / pi)

Y = X *(π/ 180)。

保罗·德莱瓦

第388行:

输出=mod([psi,θ,φ]*180/pi,360);

提出了改变:

输出= [psi,theta,phi] * 180 / pi;

THETA在代码中使用ACOS或ASIN进行计算。在MATLAB中,ACOS(X)和ASIN(X)都在一定范围内返回值。1 < = X < = 1,

ACOS_X =这些“可信赖医疗组织”(X) *(180 /π)

总是返回从0到180度的值。这几乎与SpinCalc接受的范围(从0.1到179.9度)一致,作为THETA的输入(“输入类型”EA###和“欧拉类型”2)。

ASIN_X =正如(X) *(180 /π)

始终返回范围为-90到90度的角度。同样,这几乎与SpinCalc接受为θ输入的范围(从-89.9到89.9度)一致(带有“输入类型”EA####和“Euler类型”1)。
如果X>1或X<-1,则结果ACOS_X或ASIN_X是复杂的,SpinCalc返回一个错误消息。
计算MOD(ACOS_X,360)是没有用的,因为

= mod (acos_x, 360) = acos_x

更重要的是,计算MOD(ASIN_X,360)与代码的其他部分不一致,因为对于ASIN_X的负值(即-90<=ASIN_X<0°)

= mod (asin_x, 360) == asin_x + 360

这意味着,当ASIN_X为负值时,THETA的范围为270<=ASIN_X<360°,当作为SpinCalc的输入时(“输入类型”EA###和“Euler类型”1),则认为THETA超出了范围。

保罗·德莱瓦

关于代码的其他一些建议:
------------------------------------
请更新发布版本号。
------------------------------------
第388行:

输出=mod([psi,θ,φ]*180/pi,360);

提出了改变:

输出= [psi,theta,phi] * 180 / pi;

THETA在代码中使用ACOS或ASIN进行计算。在MATLAB中,ACOS(X)和ASIN(X)都在一定范围内返回值。1 < = X < = 1,

ACOS_X =这些“可信赖医疗组织”(X) *(180 /π)

总是返回从0到180度的值。这几乎与SpinCalc接受的范围(从0.1到179.9度)一致,作为THETA的输入(“输入类型”EA###和“欧拉类型”2)。

ASIN_X =正如(X) *(180 /π)

始终返回范围为-90到90度的角度。同样,这几乎与SpinCalc接受为θ输入的范围(从-89.9到89.9度)一致(带有“输入类型”EA####和“Euler类型”1)。
如果X>1或X<-1,则结果ACOS_X或ASIN_X是复杂的,SpinCalc返回一个错误消息。
计算MOD(ACOS_X,360)是没有用的,因为

= mod (acos_x, 360) = acos_x

更重要的是,计算MOD(ASIN_X,360)与代码的其他部分不一致,因为对于ASIN_X的负值(即-90<=ASIN_X<0°)

= mod (asin_x, 360) == asin_x + 360

这意味着,当ASIN_X为负值时,THETA的范围为270<=ASIN_X<360°,当作为SpinCalc的输入时(“输入类型”EA###和“Euler类型”1),则认为THETA超出了范围。

--------------------------------

第396行:

sing_chk =…
(找到(abs(θ* 180 / pi) < 0.1);...
求(绝对值(θ*180/π-180)<0.1);。。。
找到(abs(θ* 180 /π- 360))< 0.1);

提出了改变:

sing_chk =…
(找到(abs(θ* 180 / pi) < 0.1);...
求(绝对值(θ*180/π-180)<0.1);。。。
找到(abs(θ* 180 / pi - 360) < 0.1)];

--------------------------------

每次将包含弧度中的角度的nx1或nx3数组转换为以度数的角数组,反之亦然(并且在您的代码中执行大量的次数,包括上述行388和396),您使用此句法:

Y = X * 180 /π

y = x * pi / 180

这样,你重复分割(通过pi或180)n次。我建议您使用此Sintax,这更高效,只能计算该部门一次:

y = x *(180 / pi)

Y = X *(π/ 180)。

约翰·富勒

保罗,
我已经加入了一个修复程序来解决这个bug,它与您的代码片段非常相似。谢谢收听!

保罗·德莱瓦

在用于检查欧拉角输入值奇点的IF语句中有一个错误。这些语句只有在INPUT大小为1x3时才能正常工作。当INPUT大小为Nx3 (N>1)时,它们不能正常工作。

第一个例子

假设欧拉角的旋转顺序类型为2(绕同一轴的第一次和第三次旋转)。让

INPUT = [10 -10 10] % (1x3)行向量

SpinCalc(源代码行107108109)中使用的以下IF语句正确地发现了奇异点(第二个欧拉角为-10,因此超出范围),并生成错误消息:

如果输入(:,2)<=零(大小(输入,1),1)|。。。
输入(:,2)> = 180 * = 180(尺寸(输入,1),1)
错误(“错误:第二次输入欧拉角(s)不在0到180度范围内”)
终止

第二个例子

让输入为行向量(N>1)的Nx3列表,例如

输入= [10 -10 10
10 00 10
10 10 10
10 180年10
10 190 10]%(5x3行矢量列表)

上面提到的IF语句没有发现第一行、第二行、第四行和第五行(其中第二欧拉角超出范围)中的奇点,也不会生成错误消息。

Spincalc包含一组类似的IF语句,其中包含相同的错误(源代码行从105到121)。

以下是我的解决方案:

input_size =大小(输入);
N=输入大小(1);

%识别奇异点(第二个欧拉角超出范围)
EA2 =输入(:,2);% (Nx1)第二欧拉角
0 = 0 (N, 1);%(资料片)
的=的(N - 1);%(资料片)
if rot_1_in==rot_3_in %
如果(ea2 <=零)||任何(ea2> = 180 *那些)
误差(“第二输入欧拉角不在0到180度范围内”)
elseif any(abs(EA2)<2*ONES) || any(abs(EA2)>178*ONES)
如果ichk==1
errordlg('警告:奇点(0或180度)附近的第二个输入欧拉角。')
终止
终止
else % Type 1旋转(围绕三个不同的轴旋转)
如果有(abs(EA2)>=90*个)
误差('第二输入欧拉角度,在-90到90度范围内')
elseif任何(abs (EA2) > 88 * 1)
如果ichk==1
errordlg('Warning: Second input Euler angle(s) near a singularity (-90 or 90°).')
终止
终止
终止

j·胡

对于某些旋转矩阵输入,某些转换将导致由于奇点引起的错误消息。它必须使用其他转换类型。如果代码可以自动选择任何输入的无差错转换,则会有用。

例如,旋转矩阵输入=
[0 0 1;
1 0 0;
0 1 0]
转换必须是“DCMTOEA2XX”,其中2需要是第一个,XX可以是13或31。

当调用代码以重复计算许多数据集时,需要自动选择转换类型。

谢谢

Georg Wiora

詹姆斯科伯恩

zhaopeng邱

保罗

谢谢你的代码,它很棒。

有趣的事实:在统计工具箱中,procrustes函数返回的旋转矩阵通常与eps不正交。

保罗·德莱瓦

这更棒:

DCM-3x3xN多维方向余弦矩阵,通过预乘列向量执行坐标系旋转(V_rot=DCM*V,其中V_rot在旋转的坐标系中被V解析)

保罗·德莱瓦

保罗·德莱瓦

我建议使用以下帮助文本:

“SpinCalc使用的所有旋转表示都表示坐标系的旋转。”

“DCM - 3x3xN多维矩阵,预乘以列向量旋转它们所示的参考系统。”

保罗·德莱瓦

保罗·德莱瓦

约翰·富勒

好吧,我没有时间在代码的帮助文本中复习语义。我同意下面的说法

% DCM - 3x3xN多维矩阵,预乘一个坐标
%帧列向量,将其旋转到所需的新帧。

可能会更好

% DCM - 3x3xN多维矩阵,预乘一个坐标
%帧列向量来计算其在所需坐标系中的坐标
%的新框架。

但事实仍然是,输入的DCM数据保持不变。我不会说这是高度误导,但它也不能期望教给每个用户旋转线性代数的细微差别,正如你所说明的。

代码按照公认的约定使用输入和输出,我的行业中“大多数”严肃的用户都遵循和理解这个约定,它就是这么简单。与所有Matlab FEX代码一样,用户在使用之前谨慎地检查代码,并通过外部测试知道什么进入和退出是非常重要的。

我将更新上面的评论,但我不会对SpinCalc进行进一步的修改,因为我相信它已经被广泛接受,经过了大量的测试,并且很简单。如果你不喜欢,那就给它打个差评,不要使用它。

谢谢
约翰

保罗·德莱瓦

好的,约翰,

我想这就是我们共同的背景:

我们同意,从参考坐标系a(原始坐标系)到另一参考坐标系B(旋转坐标系)的旋转会产生与向量v相反方向的明显旋转,向量v固定在a中。这导致了描述旋转的两种约定。我们叫他们:
1)“帧旋转”
2)“矢量旋转”(或“空间矢量旋转”)
最重要的一点是,当我们描述从a到B的旋转时,我们必须假设v在a中是固定的(见下文)。此外,我们同意SpinCalc使用“帧旋转”约定,当然我们也同意Rodriguez的旋转公式和所有其他在SpinCalc中正确实现的转换公式。

此外,正如前面的消息所讨论的,我们同意使用两种约定来表示DCM的旋转(乘法前或乘法后)。您最近更新的帮助文本清楚地表明,您使用的是列向量与DCM的预乘法。如果我们称R为DCM,称v为原始列向量,则R是这样一个矩阵:

v_rot = R * v。

下面是我们有分歧的地方:

我们不同意你的帮助短信。在你的最后一条消息中,你解释说你实现了“FRAME ROTATION”约定,但这并不是你在帮助文本中所写的,它将DCM定义为:

“一种多维矩阵,它预先乘以坐标系(列)向量,将其旋转到所需的新坐标系。”

让我们将A称为初始帧,B称为“所需的新帧”。
It unequivocally follows from your text that, in the equation v_rot = R*v, you describe v as one of the versors of A (i.e., a standard basis vector; i.e., either [1,0,0], [0,1,0], or [0,0,1], in 3D). Actually, in this singular case R*v is the same as selecting one of the columns of R, and this description of v is quite questionable, in my opinion, as a (pre- or post-) multiplication by R is typically used to rotate any vector, not only the versors of A. But this is not the most important fault in your definition.

因为你的帮助文本描述了“列向量”的旋转,所以你明确地将R定义为一个产生(即表示)“向量旋转”的矩阵,而不是“帧旋转”。此外,“帧旋转”约定假定v“固定在A中”(见上文)。相反,根据你的定义,v明确地出现在B中(而不是A中)。

最重要也是最不幸的是,R并不代表从a到B的“帧旋转”,而是从a到C的相反意义上同等大小的“帧旋转”。也就是说,C与B不一致,因为B与矢量一起旋转。例如,如果B围绕z旋转45°,则C围绕同一轴旋转-45°。因此,我们可以将方程改写如下:

vC=R*vA。
(vB=R*vA不正确)。

简而言之,您的帮助文本描述了从A到B的“帧旋转”,与通过R(从V到V_ROT或从VA到VC)产生的“矢量旋转”旋转的“帧旋转”与“矢量旋转”旋转相同若你宁可)。但遗憾的是,r既不产生,也不代表来自a到b的帧旋转。

然而,你的轴角表示描述了相反的旋转,即从A到C的“框架旋转”,其中v“固定在A中”,并从C中观察到。这是由R产生并表示的框架旋转,但C甚至没有在你的帮助文本中提到!换句话说,旋转的定义与实现是不一致的,这是非常容易引起误解的。

保罗·德莱瓦

保罗

约翰·富勒

另一个备注,如果您看看我的其他叫spincalcvis的其他提交,它将有一个好主意如何通过Spincalc处理输入/输出,因为它全部基于相同的父代码。

//www.tatmou.com/matlabcentral/fileexchange/27653-euler-angle-dcm-quaternion-and-euler-vector-conversionteaching-gui

谢谢
约翰

约翰·富勒

保罗,
SpinCalc使用的约定是标准约定,其中矩阵R预乘列向量,或R*v。帮助部分中的“by”可能有点含糊不清。当主文件回到我面前时,我可以更改它。

您看到的不一致的原因在于,SpinCalc中使用的R矩阵格式适用于DCM,它围绕矢量旋转坐标系,而不是围绕坐标系旋转矢量。因此,Euler矢量解决方案对应于围绕其旋转坐标系的矢量以及旋转多少。

围绕Z旋转[1;0;0]90度的矩阵相当于围绕Z旋转帧-90,或围绕-Z旋转+90。SpinCalc的所有数据输入和输出都对应于帧的旋转。

保罗·德莱瓦

SpinCalc的帮助文本定义了DCM(旋转矩阵)如下:

“3xn多维矩阵,它预先乘以坐标帧向量,将其旋转到所需的新帧。”

对我来说,“预乘”这个表达似乎有些模棱两可。在我看来,一个旋转矩阵R要么“预乘”一个列向量v1 (R*v1),要么“预乘”一个行向量v2 (v2*R)。

你什么意思?R*v还是v*R?
你介意在你的帮助文本中清除它吗?

给DCM一个清晰的定义是非常重要的。在线性代数中,执行旋转最常用的约定是通过列向量与DCM的预乘。以下是我遵循这个惯例得到的结果:

如果i, j, k是xyz坐标系的两个向量,则旋转矩阵R将i[1;0;0]绕z轴旋转90°,生成一个新的向量i_new,它与j[0;1;0]重合:

R = [0 -1 0
1 0 0
0 0 1);
i = [1;0;0);%列向量
i_new = r * i;
disp (i_new)
0
1.
0

因此,如果我使用SpinCalc来计算R对应的轴角向量,我希望它是[0 0 1 90],然而:

SpinCalc('DCMtoEV', R, 1e- 5,0)

ans =

0 0 -1 90

你如何解释这种明显的矛盾?这是因为您没有使用上述约定吗?你能在帮助文本中清楚地说明这一点吗?

约翰·富勒

盖塔诺,
我检查了这一行,不明白为什么它会产生一个错误,因为它是这样写的:

如果abs(det(INPUT(:,:,ii))+1)<0.05, %如果行列式接近-1,DCM是不合适的

您建议的这条线实际上会导致正确的DCM矩阵出现错误,因为它们的行列式应该等于+1。在您的行中,减法将导致正确的DCM被抛出,并且附加的abs功能是多余的。

谢谢
约翰

最近我下载了这个MatLab代码,我用它来得到旋转矩阵的欧拉角。

在我看来,在代码的165行有一个错误,准确地说,我会按照以下方式修改它:

“abs (abs(相同功能(输入(:,:ii))) 1) < 0.00005”

有人能告诉我这个观察是否正确吗?

非常感谢。
盖塔诺。

[电信工程中的学生,贝基 - 巴里(意大利)的多纯性]

chandrakala高达

非常有用的。谢谢。

布莱恩

我发现这段代码非常有用,它似乎完全按照描述的那样工作。谢谢你的杰出贡献。

詹姆斯Tursa

在与FEX中的其他人与他人进行比较后,我觉得需要碰到我的评级。

乔尔

约根

好的,谢谢你的反馈。

约翰·富勒

Jørgen,
指定的323旋转是单个Euler集,因为中间角度为0。任何中间角度为0或180的类型2旋转都无法通过尝试将Q、DCM或EV平移回Euler角度来唯一解析。如果您计划在表示为欧拉角的奇异方向之间平移,我建议您严格使用DCM、Q或EV,因为它们可以唯一地定义所有方向。

约根

当使用DCM到EA323时,我得到了一些意想不到的结果。

这是我的代码:

>> r = [0 -1 0;1 0 0;0 0 1]
R =

0 1 0
1 0 0
0 0 1

>> Spincalc2('dcmtoea323',r,eps,1)

ans =

0 0 0

------

矩阵R表示围绕Z轴的简单90度旋转,但欧拉角均为零。

约翰·富勒

我正在上传一个更新版本,修改了第一个和第三个欧拉角的边界。它们现在必须在-360和360之间。第二个欧拉角的边界将保持不变因为它们防止了模棱两可的欧拉集。

谢谢你的评论。

斯坦利

效果很好。与其他人一致认为,输入的某些限制,虽然可能会模糊内部代码,但会使其他代码的实现更加繁琐。
例如,在此代码片段中,ea(1)必须位于0->360。

Spincalc('ea321todcm',EA,EPS,0)

向下(1)= -10度比较容易。
也许是边界检查的开关?

约翰·富勒

谢谢你的评论。我正在编辑代码以适应注释2-5。我想把第二个欧拉角限制留在-90和90之间,因为达到这些界限的类型1的旋转会导致奇点。允许角度越过这些界限,虽然是正确的,但会使探测奇点变得更加模糊。

詹姆斯Tursa

我针对我碰巧拥有的独立代码对输入/输出类型的所有组合进行了点检,SpinCalc产生了相同的结果,因此我将根据点检得出结论,代码通常按照宣传的那样工作。因此我给了它一个相当高的评价。我确实有一些问题,但我认为这些问题可以很容易地得到改善:

------------------------------------------------------------------------------------
1) 有时结果是不可逆的。例如:

>> q = [1 2 3 4]
q=
1 2 3 4
>>q=q/标准(q)
q=
0.18257418583506 0.36514837167011 0.54772255750517 0.73029674334022
> > SpinCalc (QtoEA213, q, eps, 1)
ans =
1.0 e + 002 *
0.47726310993906 3.52337744339234 0.70346175941947
> > SpinCalc (EA213toQ, ans, eps, 1)
??? 使用==>SpinCalc时出错
错误:第二个输入欧拉角超出-90到90度范围

在这种情况下,以及在其他类似情况下,对有效欧拉角输入的检查过于严格。将第二个输入设置在-90到+90之外可能对某些物理应用程序没有意义,但它不是无效的输入,也不应该产生错误。

------------------------------------------------------------------------------------
2)小角度旋转四元数的欧拉旋转角计算不准确。问题代码是这样的:

MU=2*acos(Q(:,4));

例如:

>> q = [1 2 3 4e12]
q=
1.0 e + 012 *
0.00000000000100 0.00000000000200 0.00000000000300 4.00000000000000
>>q=q/标准(q)
q=
0.00000000000025 0.00000000000050 0.00000000000075 1.00000000000000
> > SpinCalc (QtoEV, q, eps, 1)
ans =
1 0 0 0
>>SpinCalc('EVtoQ',ans,每股收益,1)
ans =
0 0 0 1

你可以看到在这种情况下,小角度完全丢失在q(4)分量中,所以只使用那个分量来计算旋转角度对于小角度的情况不是一个好的方法。一个修复方法是使用atan2函数。例如,假设使用下面的代码而不是上面的代码:

QV=sqrt(和(Q(:,1:3)。*Q(:,1:3),2));
MU=2*atan2(QV,Q(:,4));

现在做同样的计算:

> > SpinCalc (QtoEV, q, eps, 1)
ans =
0.26726124191242 0.5345248382485 0.80178372573727 0.0000000000019
>>SpinCalc('EVtoQ',ans,每股收益,1)
ans =
0.00000000000025 0.00000000000050 0.00000000000075 1.00000000000000

你可以看到小角度的计算是正确的。注意:上面显示的atan2代码只是一个改进示例。这可能不是最好的整体方法。

------------------------------------------------------------------------------------
3)使用的一些算法对偏离统一的输入不健壮,等等。例如,假设我们从一个合适方向的余弦矩阵开始,对它进行一点扰动:

>> q = [1 2 3 4]
q=
1 2 3 4
>>q=q/标准(q)
q=
0.18257418583506 0.36514837167011 0.54772255750517 0.73029674334022
> > dcm = SpinCalc (QtoDCM, q, eps, 1)
dcm =
0.13333333333333 0.93333333333333 -0.33333333333333
-0.66666666666667 0.33333333333333 0.66666666666667
0.73333333333333 0.13333333333333 0.66666666666667
>>dcm=dcm+1e-7*(兰特(3,3)-0.5)
dcm =
0.13333337834626 0.9333333193158 -0.3333333768657
-0.66666669355282 0.33333337246323 0.66666661851703
0.73333334401759 0.13333335954302 0.66666669880738
> > SpinCalc (DCMtoQ, dcm、eps、1)
警告:输入的DCM(s)矩阵与精度公差不正交。
(等)
ans =
0.18257415540401 0.36514836686611 0.54772255130155 0.73029676324370
>>标准(ans)
ans =
1.00000000382748

用于转换的算法拾取dcm不是很合适(很好)的事实,但不纠正输出。在这种情况下,对返回的四元数进行归一化可能会更好。有效实现这一目标的一种方法是使用最近发表在J. Guidance第31卷第2期440-442页的Markley算法。该算法只使用一个平方根产生归一化四元数结果。

------------------------------------------------------------------------------------
4) 有些代码可以编写得更高效。例如,在本节中:

m1 =输入(:1);m2 =输入(:,2);m3 =输入(:,3);μ=输入(:,4)*π/ 180;
如果sqrt(m1.^2+m2.^2+m3.^2)-one(N,1)>tol*one(N,1),
误差(“输入欧拉矢量不构成单位矢量”)
终止
如果mu 2 * pi *那些(n,1),
误差('输入欧拉旋转角度(s)不在0和360度之间')
终止
Q=[m1.*sin(MU/2),m2.*sin(MU/2),m3.*sin(MU/2),cos(MU/2)];

为什么要分别拔出m1、m2和m3中的柱?为什么不在后续计算中使用输入(:,1:3)?为什么要多次计算sin(MU/2)?只能对其重新编码一次以计算sin(MU/2)。例如:

Q=[输入(:,1:3)。*sin(MU/2),cos(MU/2)];

------------------------------------------------------------------------------------
5)当一条警告信息就足够时,系统问题会出现多条警告信息。例如:

>> q = [1 2 3 4]
q=
1 2 3 4
>>q=q/标准(q)
q=
0.18257418583506 0.36514837167011 0.54772255750517 0.73029674334022
>> q = q + 1.e-7*(rand(1,4)- 0.5)
q=
0.18257418030539 0.36514838321335 0.54772258669887 0.73029678552152
>> qq = [q;q;q;q;]
qq =
0.18257418030539 0.36514838321335 0.54772258669887 0.73029678552152
0.18257418030539 0.36514838321335 0.54772258669887 0.73029678552152
(等)
> > SpinCalc (QtoDCM, qq, eps, 1)
ans (:: 1) =
0.13333335251383 0.93333342235746 -0.33333337639558
-0.66666675533740 0.33333337341210 0.66666670795756
0.73333338560076 0.13333335997254 0.66666675384566
ans (:: 2) =
0.13333335251383 0.93333342235746 -0.33333337639558
-0.66666675533740 0.33333337341210 0.66666670795756
0.73333338560076 0.13333335997254 0.66666675384566
(等)
> > SpinCalc (DCMtoQ, ans, eps, 1)
警告:输入DCM矩阵与精度公差不正交。警告:输入DCM矩阵与精度公差不正交。
(等)
ans =
0.18257418458450 0.36514839177157 0.54772259953620 0.73029676840507
0.18257418458450 0.36514839177157 0.54772259953620 0.73029676840507
(等)

现在我有10个错误消息框需要清除。如果数组是1000,那么我将有1000个错误消息框需要清除。对于这些类型的情况,每个函数调用只需要一条消息。

诚然,我的评论有点挑剔,但请记住,我认为可以很容易地解决这些问题来改进代码,我给了它相当高的评价。

詹姆斯Tursa

MATLAB版本兼容性
创建R2007b
与任何版本兼容
平台兼容性
窗户 macOS Linux

社区寻宝

在MATLAB Central中查找宝藏,了解社区如何帮助您!

开始狩猎!