quaternion.c 9.6 KB

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