| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- #include "quaternion.h"
- #include "matrix.h"
- #include "float.h"
- #include "math.h"
- #include "helpler_funtions.h"
- ///\ @brief 四元数的简单构造
- void Quaternion(float q[4])
- {
- q[0] = 1.0f;
- for (int i = 1; i < 4; ++i)
- {
- q[i] = 0.0f;
- }
- }
- ///\ @brief 四元数归一化为单位四元数
- void Quaternion_Normalize(float Q[4])
- {
- float q_norm = Vector_GetNorm(Q, 4);
- Vector_DotProductRealNum(Q, 1.0F / q_norm, 4);
- }
- /**
- * @brief 四元数规范化 保证实部不小于0
- *
- */
- void Quaternion_Canonicalize(float Q[4])
- {
- for (int i = 0; i < 4; ++i)
- {
- if (fabsf(Q[i]) > FLT_EPSILON)
- {
- Vector_DotProductRealNum(Q, sign(Q[i]), 4);
- return;
- }
- }
- }
- /**
- * @brief 使用旋转矩阵构造四元数
- *
- * @param Q 四元数
- * @param R 旋转矩阵
- */
- void Quaternion_ByDcm(const float R[3][3], float Q[4])
- {
- float t = Matrix_GetTrace(&R[0][0], 3);
- if (t > 0.0f)
- {
- t = sqrtf(1.0f + t);
- Q[0] = 0.5f * t;
- t = 0.5f / t;
- Q[1] = (R[2][1] - R[1][2]) * t;
- Q[2] = (R[0][2] - R[2][0]) * t;
- Q[3] = (R[1][0] - R[0][1]) * t;
- }
- else if (R[0][0] > R[0][1] && R[0][0] > R[2][2])
- {
- t = sqrtf(1.0f + R[0][0] - R[1][1] - R[2][2]);
- Q[1] = 0.5F * t;
- t = 0.5f / t;
- Q[0] = (R[2][1] - R[1][2]) * t;
- Q[2] = (R[1][0] + R[0][1]) * t;
- Q[3] = (R[0][2] + R[2][0]) * t;
- }
- else if (R[1][1] > R[2][2])
- {
- t = sqrtf(1.0f - R[0][0] + R[1][1] - R[2][2]);
- Q[2] = 0.5F * t;
- t = 0.5f / t;
- Q[0] = (R[0][2] - R[2][0]) * t;
- Q[1] = (R[1][0] + R[0][1]) * t;
- Q[3] = (R[2][1] + R[1][2]) * t;
- }
- else
- {
- t = sqrtf(1.0f - R[0][0] - R[1][1] + R[2][2]);
- Q[3] = 0.5F * t;
- t = 0.5f / t;
- Q[0] = (R[1][0] - R[0][1]) * t;
- Q[1] = (R[0][2] + R[2][0]) * t;
- Q[2] = (R[2][1] + R[1][2]) * t;
- }
- }
- /**
- * @brief 使用欧拉角构造四元数
- *
- * @param euler 欧拉角, 顺序必须为 航向—>俯仰->横滚, 单位 rad
- * @param Q 四元数
- */
- void Quaternion_ByEuler(float yaw, float pitch, float roll, float Q[4])
- {
- Q[0] = (cosf(yaw / 2) * cosf(pitch / 2) * cosf(roll / 2) -
- sinf(yaw / 2) * sinf(pitch / 2) * sinf(roll / 2));
- Q[1] = (cosf(yaw / 2) * sinf(pitch / 2) * cosf(roll / 2) -
- sinf(yaw / 2) * cosf(pitch / 2) * sinf(roll / 2));
- Q[2] = (cosf(yaw / 2) * cosf(pitch / 2) * sinf(roll / 2) +
- sinf(yaw / 2) * sinf(pitch / 2) * cosf(roll / 2));
- Q[3] = (cosf(yaw / 2) * sinf(pitch / 2) * sinf(roll / 2) +
- sinf(yaw / 2) * cosf(pitch / 2) * cosf(roll / 2));
- }
- /**
- * @brief 使用轴角构造四元数
- *
- * @param anxisAngle 旋转轴角向量, 模为转角 rad, 方向为转轴
- * @param Q 四元数
- */
- void Quaternion_ByAxisAngle(const float anxisAngle[3], float Q[4])
- {
- float angle = Vector_GetNorm(anxisAngle, 3);
- if (angle < 1e-10)
- {
- /* 如果 angle 太小, 相当于没转 */
- Quaternion(Q);
- }
- else
- {
- float axis[3] = { anxisAngle[0], anxisAngle[1], anxisAngle[2] };
- Vector_DotProductRealNum(axis, 1.0f / angle, 3);
- float magnitude = sinf(angle * 0.5f);
- Q[0] = cosf(angle * 0.5f);
- for (int i = 0; i < 3; i++)
- {
- Q[i + 1] = axis[i] * magnitude;
- }
- }
- }
- /**
- * @brief 使用向量, 构造由 V1->V2 的最短旋转四元数
- *
- * @param Vsrc 旋转前的向量
- * @param Vdst 旋转后的向量
- * @param Q V1->V2 的最速旋转四元数
- */
- void Quaternion_ByTwoVectors(const float Vsrc[3], const float Vdst[3], float Q[4])
- {
- float Vcr[3], dot;
- const float eps = 1e-5;
- Vector_CrossProduct_3D(Vsrc, Vdst, Vcr);
- dot = Vector_DotProduct(Vsrc, Vdst, 3);
- if (dot < 0.0f && Vector_GetNorm(Vcr, 3) < eps)
- {
- /* 判断 Vsrc Vdst 是接近 180 度 */
- float Vtmp[3] = { fabsf(Vcr[0]), fabsf(Vcr[1]), fabsf(Vcr[2]) };
- if (Vtmp[0] < Vtmp[1])
- {
- if (Vtmp[0] < Vtmp[2])
- {
- Vtmp[0] = 1;
- Vtmp[1] = 0;
- Vtmp[2] = 0;
- }
- else
- {
- Vtmp[0] = 0;
- Vtmp[1] = 0;
- Vtmp[2] = 1;
- }
- }
- else
- {
- if (Vtmp[1] < Vtmp[2])
- {
- Vtmp[0] = 0;
- Vtmp[1] = 1;
- Vtmp[2] = 0;
- }
- else
- {
- Vtmp[0] = 0;
- Vtmp[1] = 0;
- Vtmp[2] = 1;
- }
- }
- Q[0] = 0;
- Vector_CrossProduct_3D(Vsrc, Vtmp, Vcr);
- }
- else
- {
- Q[0] = dot +
- sqrt(Vector_DotProduct(Vsrc, Vsrc, 3) * Vector_DotProduct(Vdst, Vdst, 3));
- }
- Q[1] = Vcr[0];
- Q[2] = Vcr[1];
- Q[3] = Vcr[2];
- Quaternion_Normalize(Q);
- }
- /**
- * @brief 单位四元数乘法
- *
- * @param Q1
- * @param Q2
- * @param Q Q1 X Q2
- */
- void Quaternion_Multiplication(const float Q1[4], const float Q2[4], float Q[4])
- {
- Q[0] = Q1[0] * Q2[0] - Q1[1] * Q2[1] - Q1[2] * Q2[2] - Q1[3] * Q2[3];
- Q[1] = Q1[1] * Q2[0] + Q1[0] * Q2[1] - Q1[3] * Q2[2] + Q1[2] * Q2[3];
- Q[2] = Q1[2] * Q2[0] + Q1[3] * Q2[1] + Q1[0] * Q2[2] - Q1[1] * Q2[3];
- Q[3] = Q1[3] * Q2[0] - Q1[2] * Q2[1] + Q1[1] * Q2[2] + Q1[0] * Q2[3];
- }
- /**
- * @brief 四元数求逆
- *
- * @param Q
- * @param Q_inv
- */
- void Quaternion_Inversed(const float Q[4], float Q_inv[4])
- {
- float q_norm = Vector_GetNorm(Q, 4);
- Q_inv[0] = Q[0] / q_norm;
- Q_inv[1] = -Q[1] / q_norm;
- Q_inv[2] = -Q[2] / q_norm;
- Q_inv[3] = -Q[3] / q_norm;
- }
- /**
- * @brief 将四元数求逆
- *
- * @param Q
- */
- void Quaternion_Invert(float Q[4])
- {
- float Q_inv[4];
- Quaternion_Inversed(Q, Q_inv);
- for (int i = 0; i < 4; ++i)
- {
- Q[i] = Q_inv[i];
- }
- }
- /**
- * @brief 根据 frame1 的角速率, 求 q21 的微分
- * 比如 frame1 为机体坐标系, frame2 为东北天坐标系
- * V1 为向量在 frame1 的坐标, V2 为向量在 fram2 的坐标
- * [0, V2] = q21 * [0, V1] * q21^-1
- * q21_deriv = q21 * [0, 0.5 * angle_rate1]
- *
- * @param q21 当前四元数
- * @param angle_rate1 frame 1 下的三轴角速率
- * @param q21_deriv q21 的微分
- */
- void Quaternion_Derivative1(const float q21[4], const float angle_rate1[3], float q21_deriv[4])
- {
- float v[4] = { 0,
- 0.5f * angle_rate1[0],
- 0.5f * angle_rate1[1],
- 0.5f * angle_rate1[2] };
- Quaternion_Multiplication(q21, v, q21_deriv);
- }
- /**
- * @brief 根据 frame2 的角速率, 求 q21 的微分
- * 比如 frame1 为机体坐标系, frame2 为东北天坐标系
- * V1 为向量在 frame1 的坐标, V2 为向量在 fram2 的坐标
- * q21 为 [0,V2] = q21 * [0,V1] * q21^-1
- * q21_deriv = [0, 0.5 * angle_rate1] * q21
- *
- * @param q21 当前四元数
- * @param angle_rate1 frame 1 下的三轴角速率
- * @param q21_deriv q21 的微分
- */
- void Quaternion_Derivative2(const float q21[4], const float angle_rate2[3], float q21_deriv[4])
- {
- float v[4] = { 0,
- 0.5f * angle_rate2[0],
- 0.5f * angle_rate2[1],
- 0.5f * angle_rate2[2] };
- Quaternion_Multiplication(v, q21, q21_deriv);
- }
- /**
- * @brief 将四元数按照轴角进行旋转
- *
- * @param axisAngle 轴角向量
- * @param Q 四元数
- */
- void Quaternion_RotateByAxisAngle(const float axisAngle[3], float Q[4])
- {
- /* 根据轴角向量计算旋转四元数 */
- float q_rot[4], q_temp[4];
- Quaternion_ByAxisAngle(axisAngle, q_rot);
- Quaternion_Multiplication(q_rot, Q, q_temp);
- for (int i = 0; i < 4; ++i)
- {
- Q[i] = q_temp[i];
- }
- }
- /**
- * @brief 通过四元数将 frame1 下的 V1 转到 frame2 下的 V2
- *
- * @param Q 四元数
- * @param V1
- * @param V2
- */
- void Quaternion_Conj(const float Q[4], const float V1[3], float V2[3])
- {
- float v_temp1[4] = { 0, V1[0], V1[1], V1[2] };
- float v_temp2[4], v_temp3[4];
- Quaternion_Multiplication(Q, v_temp1, v_temp2);
- Quaternion_Inversed(Q, v_temp1);
- Quaternion_Multiplication(v_temp2, v_temp1, v_temp3);
- V2[0] = v_temp3[1];
- V2[1] = v_temp3[2];
- V2[2] = v_temp3[3];
- }
- /**
- * @brief 通过四元数将 frame2 下的 V2 转到 frame1 下的 V1
- *
- * @param Q 四元数
- * @param V1
- * @param V2
- */
- void Quaternion_ConjInv(const float Q[4], const float V2[3], float V1[3])
- {
- float v_temp1[4] = { 0, V2[0], V2[1], V2[2] };
- float v_temp2[4], v_temp3[4];
- Quaternion_Multiplication(v_temp1, Q, v_temp2);
- Quaternion_Inversed(Q, v_temp1);
- Quaternion_Multiplication(v_temp1, v_temp2, v_temp3);
- V1[0] = v_temp3[1];
- V1[1] = v_temp3[2];
- V1[2] = v_temp3[3];
- }
- /**
- * @brief 通过四元数求其对应的旋转矩阵的 Z 轴
- * 可参考由四元数构造旋转矩阵
- *
- * @param Q 四元数
- * @param dcm_z 旋转矩阵 z 轴
- */
- void Quaternion_GetDcmZ(const float Q[4], float dcm_z[3])
- {
- float a = Q[0];
- float b = Q[1];
- float c = Q[2];
- float d = Q[3];
- dcm_z[0] = 2 * (a * c + b * d);
- dcm_z[1] = 2 * (c * d - a * b);
- dcm_z[2] = a * a - b * b - c * c + d * d;
- }
|