quaternion.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. #include "quaternion.h"
  2. #include "matrix.h"
  3. #include "float.h"
  4. #include "math.h"
  5. #include "helpler_funtions.h"
  6. ///\ @brief 四元数的简单构造
  7. void Quaternion(float q[4])
  8. {
  9. q[0] = 1.0f;
  10. for (int i = 1; i < 4; ++i)
  11. {
  12. q[i] = 0.0f;
  13. }
  14. }
  15. ///\ @brief 四元数归一化为单位四元数
  16. void Quaternion_Normalize(float Q[4])
  17. {
  18. float q_norm = Vector_GetNorm(Q, 4);
  19. Vector_DotProductRealNum(Q, 1.0F / q_norm, 4);
  20. }
  21. /**
  22. * @brief 四元数规范化 保证实部不小于0
  23. *
  24. */
  25. void Quaternion_Canonicalize(float Q[4])
  26. {
  27. for (int i = 0; i < 4; ++i)
  28. {
  29. if (fabsf(Q[i]) > FLT_EPSILON)
  30. {
  31. Vector_DotProductRealNum(Q, sign(Q[i]), 4);
  32. return;
  33. }
  34. }
  35. }
  36. /**
  37. * @brief 使用旋转矩阵构造四元数
  38. *
  39. * @param Q 四元数
  40. * @param R 旋转矩阵
  41. */
  42. void Quaternion_ByDcm(const float R[3][3], float Q[4])
  43. {
  44. float t = Matrix_GetTrace(&R[0][0], 3);
  45. if (t > 0.0f)
  46. {
  47. t = sqrtf(1.0f + t);
  48. Q[0] = 0.5f * t;
  49. t = 0.5f / t;
  50. Q[1] = (R[2][1] - R[1][2]) * t;
  51. Q[2] = (R[0][2] - R[2][0]) * t;
  52. Q[3] = (R[1][0] - R[0][1]) * t;
  53. }
  54. else if (R[0][0] > R[0][1] && R[0][0] > R[2][2])
  55. {
  56. t = sqrtf(1.0f + R[0][0] - R[1][1] - R[2][2]);
  57. Q[1] = 0.5F * t;
  58. t = 0.5f / t;
  59. Q[0] = (R[2][1] - R[1][2]) * t;
  60. Q[2] = (R[1][0] + R[0][1]) * t;
  61. Q[3] = (R[0][2] + R[2][0]) * t;
  62. }
  63. else if (R[1][1] > R[2][2])
  64. {
  65. t = sqrtf(1.0f - R[0][0] + R[1][1] - R[2][2]);
  66. Q[2] = 0.5F * t;
  67. t = 0.5f / t;
  68. Q[0] = (R[0][2] - R[2][0]) * t;
  69. Q[1] = (R[1][0] + R[0][1]) * t;
  70. Q[3] = (R[2][1] + R[1][2]) * t;
  71. }
  72. else
  73. {
  74. t = sqrtf(1.0f - R[0][0] - R[1][1] + R[2][2]);
  75. Q[3] = 0.5F * t;
  76. t = 0.5f / t;
  77. Q[0] = (R[1][0] - R[0][1]) * t;
  78. Q[1] = (R[0][2] + R[2][0]) * t;
  79. Q[2] = (R[2][1] + R[1][2]) * t;
  80. }
  81. }
  82. /**
  83. * @brief 使用欧拉角构造四元数
  84. *
  85. * @param euler 欧拉角, 顺序必须为 航向—>俯仰->横滚, 单位 rad
  86. * @param Q 四元数
  87. */
  88. void Quaternion_ByEuler(float yaw, float pitch, float roll, float Q[4])
  89. {
  90. Q[0] = (cosf(yaw / 2) * cosf(pitch / 2) * cosf(roll / 2) -
  91. sinf(yaw / 2) * sinf(pitch / 2) * sinf(roll / 2));
  92. Q[1] = (cosf(yaw / 2) * sinf(pitch / 2) * cosf(roll / 2) -
  93. sinf(yaw / 2) * cosf(pitch / 2) * sinf(roll / 2));
  94. Q[2] = (cosf(yaw / 2) * cosf(pitch / 2) * sinf(roll / 2) +
  95. sinf(yaw / 2) * sinf(pitch / 2) * cosf(roll / 2));
  96. Q[3] = (cosf(yaw / 2) * sinf(pitch / 2) * sinf(roll / 2) +
  97. sinf(yaw / 2) * cosf(pitch / 2) * cosf(roll / 2));
  98. }
  99. /**
  100. * @brief 使用轴角构造四元数
  101. *
  102. * @param anxisAngle 旋转轴角向量, 模为转角 rad, 方向为转轴
  103. * @param Q 四元数
  104. */
  105. void Quaternion_ByAxisAngle(const float anxisAngle[3], float Q[4])
  106. {
  107. float angle = Vector_GetNorm(anxisAngle, 3);
  108. if (angle < 1e-10)
  109. {
  110. /* 如果 angle 太小, 相当于没转 */
  111. Quaternion(Q);
  112. }
  113. else
  114. {
  115. float axis[3] = { anxisAngle[0], anxisAngle[1], anxisAngle[2] };
  116. Vector_DotProductRealNum(axis, 1.0f / angle, 3);
  117. float magnitude = sinf(angle * 0.5f);
  118. Q[0] = cosf(angle * 0.5f);
  119. for (int i = 0; i < 3; i++)
  120. {
  121. Q[i + 1] = axis[i] * magnitude;
  122. }
  123. }
  124. }
  125. /**
  126. * @brief 使用向量, 构造由 V1->V2 的最短旋转四元数
  127. *
  128. * @param Vsrc 旋转前的向量
  129. * @param Vdst 旋转后的向量
  130. * @param Q V1->V2 的最速旋转四元数
  131. */
  132. void Quaternion_ByTwoVectors(const float Vsrc[3], const float Vdst[3], float Q[4])
  133. {
  134. float Vcr[3], dot;
  135. const float eps = 1e-5;
  136. Vector_CrossProduct_3D(Vsrc, Vdst, Vcr);
  137. dot = Vector_DotProduct(Vsrc, Vdst, 3);
  138. if (dot < 0.0f && Vector_GetNorm(Vcr, 3) < eps)
  139. {
  140. /* 判断 Vsrc Vdst 是接近 180 度 */
  141. float Vtmp[3] = { fabsf(Vcr[0]), fabsf(Vcr[1]), fabsf(Vcr[2]) };
  142. if (Vtmp[0] < Vtmp[1])
  143. {
  144. if (Vtmp[0] < Vtmp[2])
  145. {
  146. Vtmp[0] = 1;
  147. Vtmp[1] = 0;
  148. Vtmp[2] = 0;
  149. }
  150. else
  151. {
  152. Vtmp[0] = 0;
  153. Vtmp[1] = 0;
  154. Vtmp[2] = 1;
  155. }
  156. }
  157. else
  158. {
  159. if (Vtmp[1] < Vtmp[2])
  160. {
  161. Vtmp[0] = 0;
  162. Vtmp[1] = 1;
  163. Vtmp[2] = 0;
  164. }
  165. else
  166. {
  167. Vtmp[0] = 0;
  168. Vtmp[1] = 0;
  169. Vtmp[2] = 1;
  170. }
  171. }
  172. Q[0] = 0;
  173. Vector_CrossProduct_3D(Vsrc, Vtmp, Vcr);
  174. }
  175. else
  176. {
  177. Q[0] = dot +
  178. sqrt(Vector_DotProduct(Vsrc, Vsrc, 3) * Vector_DotProduct(Vdst, Vdst, 3));
  179. }
  180. Q[1] = Vcr[0];
  181. Q[2] = Vcr[1];
  182. Q[3] = Vcr[2];
  183. Quaternion_Normalize(Q);
  184. }
  185. /**
  186. * @brief 单位四元数乘法
  187. *
  188. * @param Q1
  189. * @param Q2
  190. * @param Q Q1 X Q2
  191. */
  192. void Quaternion_Multiplication(const float Q1[4], const float Q2[4], float Q[4])
  193. {
  194. Q[0] = Q1[0] * Q2[0] - Q1[1] * Q2[1] - Q1[2] * Q2[2] - Q1[3] * Q2[3];
  195. Q[1] = Q1[1] * Q2[0] + Q1[0] * Q2[1] - Q1[3] * Q2[2] + Q1[2] * Q2[3];
  196. Q[2] = Q1[2] * Q2[0] + Q1[3] * Q2[1] + Q1[0] * Q2[2] - Q1[1] * Q2[3];
  197. Q[3] = Q1[3] * Q2[0] - Q1[2] * Q2[1] + Q1[1] * Q2[2] + Q1[0] * Q2[3];
  198. }
  199. /**
  200. * @brief 四元数求逆
  201. *
  202. * @param Q
  203. * @param Q_inv
  204. */
  205. void Quaternion_Inversed(const float Q[4], float Q_inv[4])
  206. {
  207. float q_norm = Vector_GetNorm(Q, 4);
  208. Q_inv[0] = Q[0] / q_norm;
  209. Q_inv[1] = -Q[1] / q_norm;
  210. Q_inv[2] = -Q[2] / q_norm;
  211. Q_inv[3] = -Q[3] / q_norm;
  212. }
  213. /**
  214. * @brief 将四元数求逆
  215. *
  216. * @param Q
  217. */
  218. void Quaternion_Invert(float Q[4])
  219. {
  220. float Q_inv[4];
  221. Quaternion_Inversed(Q, Q_inv);
  222. for (int i = 0; i < 4; ++i)
  223. {
  224. Q[i] = Q_inv[i];
  225. }
  226. }
  227. /**
  228. * @brief 根据 frame1 的角速率, 求 q21 的微分
  229. * 比如 frame1 为机体坐标系, frame2 为东北天坐标系
  230. * V1 为向量在 frame1 的坐标, V2 为向量在 fram2 的坐标
  231. * [0, V2] = q21 * [0, V1] * q21^-1
  232. * q21_deriv = q21 * [0, 0.5 * angle_rate1]
  233. *
  234. * @param q21 当前四元数
  235. * @param angle_rate1 frame 1 下的三轴角速率
  236. * @param q21_deriv q21 的微分
  237. */
  238. void Quaternion_Derivative1(const float q21[4], const float angle_rate1[3], float q21_deriv[4])
  239. {
  240. float v[4] = { 0,
  241. 0.5f * angle_rate1[0],
  242. 0.5f * angle_rate1[1],
  243. 0.5f * angle_rate1[2] };
  244. Quaternion_Multiplication(q21, v, q21_deriv);
  245. }
  246. /**
  247. * @brief 根据 frame2 的角速率, 求 q21 的微分
  248. * 比如 frame1 为机体坐标系, frame2 为东北天坐标系
  249. * V1 为向量在 frame1 的坐标, V2 为向量在 fram2 的坐标
  250. * q21 为 [0,V2] = q21 * [0,V1] * q21^-1
  251. * q21_deriv = [0, 0.5 * angle_rate1] * q21
  252. *
  253. * @param q21 当前四元数
  254. * @param angle_rate1 frame 1 下的三轴角速率
  255. * @param q21_deriv q21 的微分
  256. */
  257. void Quaternion_Derivative2(const float q21[4], const float angle_rate2[3], float q21_deriv[4])
  258. {
  259. float v[4] = { 0,
  260. 0.5f * angle_rate2[0],
  261. 0.5f * angle_rate2[1],
  262. 0.5f * angle_rate2[2] };
  263. Quaternion_Multiplication(v, q21, q21_deriv);
  264. }
  265. /**
  266. * @brief 将四元数按照轴角进行旋转
  267. *
  268. * @param axisAngle 轴角向量
  269. * @param Q 四元数
  270. */
  271. void Quaternion_RotateByAxisAngle(const float axisAngle[3], float Q[4])
  272. {
  273. /* 根据轴角向量计算旋转四元数 */
  274. float q_rot[4], q_temp[4];
  275. Quaternion_ByAxisAngle(axisAngle, q_rot);
  276. Quaternion_Multiplication(q_rot, Q, q_temp);
  277. for (int i = 0; i < 4; ++i)
  278. {
  279. Q[i] = q_temp[i];
  280. }
  281. }
  282. /**
  283. * @brief 通过四元数将 frame1 下的 V1 转到 frame2 下的 V2
  284. *
  285. * @param Q 四元数
  286. * @param V1
  287. * @param V2
  288. */
  289. void Quaternion_Conj(const float Q[4], const float V1[3], float V2[3])
  290. {
  291. float v_temp1[4] = { 0, V1[0], V1[1], V1[2] };
  292. float v_temp2[4], v_temp3[4];
  293. Quaternion_Multiplication(Q, v_temp1, v_temp2);
  294. Quaternion_Inversed(Q, v_temp1);
  295. Quaternion_Multiplication(v_temp2, v_temp1, v_temp3);
  296. V2[0] = v_temp3[1];
  297. V2[1] = v_temp3[2];
  298. V2[2] = v_temp3[3];
  299. }
  300. /**
  301. * @brief 通过四元数将 frame2 下的 V2 转到 frame1 下的 V1
  302. *
  303. * @param Q 四元数
  304. * @param V1
  305. * @param V2
  306. */
  307. void Quaternion_ConjInv(const float Q[4], const float V2[3], float V1[3])
  308. {
  309. float v_temp1[4] = { 0, V2[0], V2[1], V2[2] };
  310. float v_temp2[4], v_temp3[4];
  311. Quaternion_Multiplication(v_temp1, Q, v_temp2);
  312. Quaternion_Inversed(Q, v_temp1);
  313. Quaternion_Multiplication(v_temp1, v_temp2, v_temp3);
  314. V1[0] = v_temp3[1];
  315. V1[1] = v_temp3[2];
  316. V1[2] = v_temp3[3];
  317. }
  318. /**
  319. * @brief 通过四元数求其对应的旋转矩阵的 Z 轴
  320. * 可参考由四元数构造旋转矩阵
  321. *
  322. * @param Q 四元数
  323. * @param dcm_z 旋转矩阵 z 轴
  324. */
  325. void Quaternion_GetDcmZ(const float Q[4], float dcm_z[3])
  326. {
  327. float a = Q[0];
  328. float b = Q[1];
  329. float c = Q[2];
  330. float d = Q[3];
  331. dcm_z[0] = 2 * (a * c + b * d);
  332. dcm_z[1] = 2 * (c * d - a * b);
  333. dcm_z[2] = a * a - b * b - c * c + d * d;
  334. }