mirror of https://github.com/rusefi/bldc.git
471 lines
17 KiB
C
471 lines
17 KiB
C
/**
|
|
* @file FusionTypes.h
|
|
* @author Seb Madgwick
|
|
* @brief Common types and their associated operations.
|
|
*
|
|
* Static inline implementations are used to optimise for increased execution
|
|
* speed.
|
|
*/
|
|
|
|
#ifndef FUSION_TYPES_H
|
|
#define FUSION_TYPES_H
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Includes
|
|
|
|
#include <math.h> // M_PI, sqrtf, atan2f, asinf
|
|
#include <stdint.h> // int32_t
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Definitions
|
|
|
|
/**
|
|
* @brief Three-dimensional spacial vector.
|
|
*/
|
|
typedef union {
|
|
float array[3];
|
|
|
|
struct {
|
|
float x;
|
|
float y;
|
|
float z;
|
|
} axis;
|
|
} FusionVector3;
|
|
|
|
/**
|
|
* @brief Quaternion. This library uses the conversion of placing the 'w'
|
|
* element as the first element. Other implementations may place the 'w'
|
|
* element as the last element.
|
|
*/
|
|
typedef union {
|
|
float array[4];
|
|
|
|
struct {
|
|
float w;
|
|
float x;
|
|
float y;
|
|
float z;
|
|
} element;
|
|
} FusionQuaternion;
|
|
|
|
/**
|
|
* @brief Rotation matrix in row-major order.
|
|
* See http://en.wikipedia.org/wiki/Row-major_order
|
|
*/
|
|
typedef union {
|
|
float array[9];
|
|
|
|
struct {
|
|
float xx;
|
|
float xy;
|
|
float xz;
|
|
float yx;
|
|
float yy;
|
|
float yz;
|
|
float zx;
|
|
float zy;
|
|
float zz;
|
|
} element;
|
|
} FusionRotationMatrix;
|
|
|
|
/**
|
|
* @brief Euler angles union. The Euler angles are in the Aerospace sequence
|
|
* also known as the ZYX sequence.
|
|
*/
|
|
typedef union {
|
|
float array[3];
|
|
|
|
struct {
|
|
float roll;
|
|
float pitch;
|
|
float yaw;
|
|
} angle;
|
|
} FusionEulerAngles;
|
|
|
|
/**
|
|
* @brief Zero-length vector definition.
|
|
*/
|
|
#define FUSION_VECTOR3_ZERO ((FusionVector3){ .array = {0.0f, 0.0f, 0.0f} })
|
|
|
|
/**
|
|
* @brief Quaternion identity definition to represent an aligned of
|
|
* orientation.
|
|
*/
|
|
#define FUSION_QUATERNION_IDENTITY ((FusionQuaternion){ .array = {1.0f, 0.0f, 0.0f, 0.0f} })
|
|
|
|
/**
|
|
* @brief Rotation matrix identity definition to represent an aligned of
|
|
* orientation.
|
|
*/
|
|
#define FUSION_ROTATION_MATRIX_IDENTITY ((FusionRotationMatrix){ .array = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f} })
|
|
|
|
/**
|
|
* @brief Euler angles zero definition to represent an aligned of orientation.
|
|
*/
|
|
#define FUSION_EULER_ANGLES_ZERO ((FusionEulerAngles){ .array = {0.0f, 0.0f, 0.0f} })
|
|
|
|
/**
|
|
* @brief Definition of M_PI. Some compilers may not define this in math.h.
|
|
*/
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Inline functions - Degrees and radians conversion
|
|
|
|
/**
|
|
* @brief Converts degrees to radians.
|
|
* @param degrees Degrees.
|
|
* @return Radians.
|
|
*/
|
|
static inline __attribute__((always_inline)) float FusionDegreesToRadians(const float degrees) {
|
|
return degrees * ((float) M_PI / 180.0f);
|
|
}
|
|
|
|
/**
|
|
* @brief Converts radians to degrees.
|
|
* @param radians Radians.
|
|
* @return Degrees.
|
|
*/
|
|
static inline __attribute__((always_inline)) float FusionRadiansToDegrees(const float radians) {
|
|
return radians * (180.0f / (float) M_PI);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Inline functions - Fast inverse square root
|
|
|
|
/**
|
|
* @brief Calculates the reciprocal of the square root.
|
|
* See http://en.wikipedia.org/wiki/Fast_inverse_square_root
|
|
* @param x Operand.
|
|
* @return Reciprocal of the square root of x.
|
|
*/
|
|
static inline __attribute__((always_inline)) float FusionFastInverseSqrt(const float x) {
|
|
if (x == 0.0) {
|
|
return 1.0;
|
|
}
|
|
return 1.0 / sqrtf(x);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Inline functions - Vector operations
|
|
|
|
/**
|
|
* @brief Adds two vectors.
|
|
* @param vectorA First vector of the operation.
|
|
* @param vectorB Second vector of the operation.
|
|
* @return Sum of vectorA and vectorB.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionVectorAdd(const FusionVector3 vectorA, const FusionVector3 vectorB) {
|
|
FusionVector3 result;
|
|
result.axis.x = vectorA.axis.x + vectorB.axis.x;
|
|
result.axis.y = vectorA.axis.y + vectorB.axis.y;
|
|
result.axis.z = vectorA.axis.z + vectorB.axis.z;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Subtracts two vectors.
|
|
* @param vectorA First vector of the operation.
|
|
* @param vectorB Second vector of the operation.
|
|
* @return vectorB subtracted from vectorA.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionVectorSubtract(const FusionVector3 vectorA, const FusionVector3 vectorB) {
|
|
FusionVector3 result;
|
|
result.axis.x = vectorA.axis.x - vectorB.axis.x;
|
|
result.axis.y = vectorA.axis.y - vectorB.axis.y;
|
|
result.axis.z = vectorA.axis.z - vectorB.axis.z;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Multiplies vector by a scalar.
|
|
* @param vector Vector to be multiplied.
|
|
* @param scalar Scalar to be multiplied.
|
|
* @return Vector multiplied by scalar.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionVectorMultiplyScalar(const FusionVector3 vector, const float scalar) {
|
|
FusionVector3 result;
|
|
result.axis.x = vector.axis.x * scalar;
|
|
result.axis.y = vector.axis.y * scalar;
|
|
result.axis.z = vector.axis.z * scalar;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculates the Hadamard product (element-wise multiplication) of two
|
|
* vectors.
|
|
* @param vectorA First vector of the operation.
|
|
* @param vectorB Second vector of the operation.
|
|
* @return Hadamard product of vectorA and vectorB.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionVectorHadamardProduct(const FusionVector3 vectorA, const FusionVector3 vectorB) {
|
|
FusionVector3 result;
|
|
result.axis.x = vectorA.axis.x * vectorB.axis.x;
|
|
result.axis.y = vectorA.axis.y * vectorB.axis.y;
|
|
result.axis.z = vectorA.axis.z * vectorB.axis.z;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculates the cross-product of two vectors.
|
|
* @param vectorA First vector of the operation.
|
|
* @param vectorB Second vector of the operation.
|
|
* @return Cross-product of vectorA and vectorB.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionVectorCrossProduct(const FusionVector3 vectorA, const FusionVector3 vectorB) {
|
|
#define A vectorA.axis // define shorthand labels for more readable code
|
|
#define B vectorB.axis
|
|
FusionVector3 result;
|
|
result.axis.x = A.y * B.z - A.z * B.y;
|
|
result.axis.y = A.z * B.x - A.x * B.z;
|
|
result.axis.z = A.x * B.y - A.y * B.x;
|
|
return result;
|
|
#undef A // undefine shorthand labels
|
|
#undef B
|
|
}
|
|
|
|
/**
|
|
* @brief Calculates the vector magnitude squared.
|
|
* @param vector Vector of the operation.
|
|
* @return Vector magnitude squared.
|
|
*/
|
|
static inline __attribute__((always_inline)) float FusionVectorMagnitudeSquared(const FusionVector3 vector) {
|
|
#define V vector.axis // define shorthand label for more readable code
|
|
return V.x * V.x + V.y * V.y + V.z * V.z;
|
|
#undef V // undefine shorthand label
|
|
}
|
|
|
|
/**
|
|
* @brief Calculates the magnitude of a vector.
|
|
* @param vector Vector to be used in calculation.
|
|
* @return Vector magnitude.
|
|
*/
|
|
static inline __attribute__((always_inline)) float FusionVectorMagnitude(const FusionVector3 vector) {
|
|
return sqrtf(FusionVectorMagnitudeSquared(vector));
|
|
}
|
|
|
|
/**
|
|
* @brief Normalises a vector to be of unit magnitude.
|
|
* @param vector Vector to be normalised.
|
|
* @return Normalised vector.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionVectorNormalise(const FusionVector3 vector) {
|
|
const float magnitudeReciprocal = 1.0f / sqrtf(FusionVectorMagnitudeSquared(vector));
|
|
return FusionVectorMultiplyScalar(vector, magnitudeReciprocal);
|
|
}
|
|
|
|
/**
|
|
* @brief Normalises a vector to be of unit magnitude using the fast inverse
|
|
* square root approximation.
|
|
* @param vector Vector to be normalised.
|
|
* @return Normalised vector.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionVectorFastNormalise(const FusionVector3 vector) {
|
|
const float magnitudeReciprocal = FusionFastInverseSqrt(FusionVectorMagnitudeSquared(vector));
|
|
return FusionVectorMultiplyScalar(vector, magnitudeReciprocal);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Inline functions - Quaternion operations
|
|
|
|
/**
|
|
* @brief Adds two quaternions.
|
|
* @param quaternionA First quaternion of the operation.
|
|
* @param quaternionB Second quaternion of the operation.
|
|
* @return Sum of quaternionA and quaternionB.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionQuaternion FusionQuaternionAdd(const FusionQuaternion quaternionA, const FusionQuaternion quaternionB) {
|
|
FusionQuaternion result;
|
|
result.element.w = quaternionA.element.w + quaternionB.element.w;
|
|
result.element.x = quaternionA.element.x + quaternionB.element.x;
|
|
result.element.y = quaternionA.element.y + quaternionB.element.y;
|
|
result.element.z = quaternionA.element.z + quaternionB.element.z;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Multiplies two quaternions.
|
|
* @param quaternionA First quaternion of the operation.
|
|
* @param quaternionB Second quaternion of the operation.
|
|
* @return quaternionA multiplied by quaternionB.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionQuaternion FusionQuaternionMultiply(const FusionQuaternion quaternionA, const FusionQuaternion quaternionB) {
|
|
#define A quaternionA.element // define shorthand labels for more readable code
|
|
#define B quaternionB.element
|
|
FusionQuaternion result;
|
|
result.element.w = A.w * B.w - A.x * B.x - A.y * B.y - A.z * B.z;
|
|
result.element.x = A.w * B.x + A.x * B.w + A.y * B.z - A.z * B.y;
|
|
result.element.y = A.w * B.y - A.x * B.z + A.y * B.w + A.z * B.x;
|
|
result.element.z = A.w * B.z + A.x * B.y - A.y * B.x + A.z * B.w;
|
|
return result;
|
|
#undef A // undefine shorthand labels
|
|
#undef B
|
|
}
|
|
|
|
/**
|
|
* @brief Multiplies quaternion by a vector. This is a normal quaternion
|
|
* multiplication where the vector is treated a quaternion with a 'w' element
|
|
* value of 0. The quaternion is post multiplied by the vector.
|
|
* @param quaternion Quaternion to be multiplied.
|
|
* @param vector Vector to be multiplied.
|
|
* @return Quaternion multiplied by vector.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionQuaternion FusionQuaternionMultiplyVector(const FusionQuaternion quaternion, const FusionVector3 vector) {
|
|
#define Q quaternion.element // define shorthand labels for more readable code
|
|
#define V vector.axis
|
|
FusionQuaternion result;
|
|
result.element.w = -Q.x * V.x - Q.y * V.y - Q.z * V.z;
|
|
result.element.x = Q.w * V.x + Q.y * V.z - Q.z * V.y;
|
|
result.element.y = Q.w * V.y - Q.x * V.z + Q.z * V.x;
|
|
result.element.z = Q.w * V.z + Q.x * V.y - Q.y * V.x;
|
|
return result;
|
|
#undef Q // undefine shorthand labels
|
|
#undef V
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the quaternion conjugate.
|
|
* @param quaternion Quaternion to be conjugated.
|
|
* @return Conjugated quaternion.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionQuaternion FusionQuaternionConjugate(const FusionQuaternion quaternion) {
|
|
FusionQuaternion conjugate;
|
|
conjugate.element.w = quaternion.element.w;
|
|
conjugate.element.x = -1.0f * quaternion.element.x;
|
|
conjugate.element.y = -1.0f * quaternion.element.y;
|
|
conjugate.element.z = -1.0f * quaternion.element.z;
|
|
return conjugate;
|
|
}
|
|
|
|
/**
|
|
* @brief Normalises a quaternion to be of unit magnitude.
|
|
* @param quaternion Quaternion to be normalised.
|
|
* @return Normalised quaternion.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionQuaternion FusionQuaternionNormalise(const FusionQuaternion quaternion) {
|
|
#define Q quaternion.element // define shorthand label for more readable code
|
|
const float magnitudeReciprocal = 1.0f / sqrtf(Q.w * Q.w + Q.x * Q.x + Q.y * Q.y + Q.z * Q.z);
|
|
FusionQuaternion normalisedQuaternion;
|
|
normalisedQuaternion.element.w = Q.w * magnitudeReciprocal;
|
|
normalisedQuaternion.element.x = Q.x * magnitudeReciprocal;
|
|
normalisedQuaternion.element.y = Q.y * magnitudeReciprocal;
|
|
normalisedQuaternion.element.z = Q.z * magnitudeReciprocal;
|
|
return normalisedQuaternion;
|
|
#undef Q // undefine shorthand label
|
|
}
|
|
|
|
/**
|
|
* @brief Normalises a quaternion to be of unit magnitude using the fast inverse
|
|
* square root approximation.
|
|
* @param quaternion Quaternion to be normalised.
|
|
* @return Normalised quaternion.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionQuaternion FusionQuaternionFastNormalise(const FusionQuaternion quaternion) {
|
|
#define Q quaternion.element // define shorthand label for more readable code
|
|
const float magnitudeReciprocal = FusionFastInverseSqrt(Q.w * Q.w + Q.x * Q.x + Q.y * Q.y + Q.z * Q.z);
|
|
FusionQuaternion normalisedQuaternion;
|
|
normalisedQuaternion.element.w = Q.w * magnitudeReciprocal;
|
|
normalisedQuaternion.element.x = Q.x * magnitudeReciprocal;
|
|
normalisedQuaternion.element.y = Q.y * magnitudeReciprocal;
|
|
normalisedQuaternion.element.z = Q.z * magnitudeReciprocal;
|
|
return normalisedQuaternion;
|
|
#undef Q // undefine shorthand label
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Inline functions - Rotation matrix operations
|
|
|
|
/**
|
|
* @brief Multiplies two rotation matrices.
|
|
* @param rotationMatrixA First rotation matrix of the operation.
|
|
* @param rotationMatrixB Second rotation matrix of the operation.
|
|
* @return rotationMatrixA with rotationMatrixB.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionRotationMatrix FusionRotationMatrixMultiply(const FusionRotationMatrix rotationMatrixA, const FusionRotationMatrix rotationMatrixB) {
|
|
#define A rotationMatrixA.element // define shorthand label for more readable code
|
|
#define B rotationMatrixB.element
|
|
FusionRotationMatrix result;
|
|
result.element.xx = A.xx * B.xx + A.xy * B.yx + A.xz * B.zx;
|
|
result.element.xy = A.xx * B.xy + A.xy * B.yy + A.xz * B.zy;
|
|
result.element.xz = A.xx * B.xz + A.xy * B.yz + A.xz * B.zz;
|
|
result.element.yx = A.yx * B.xx + A.yy * B.yx + A.yz * B.zx;
|
|
result.element.yy = A.yx * B.xy + A.yy * B.yy + A.yz * B.zy;
|
|
result.element.yz = A.yx * B.xz + A.yy * B.yz + A.yz * B.zz;
|
|
result.element.zx = A.zx * B.xx + A.zy * B.yx + A.zz * B.zx;
|
|
result.element.zy = A.zx * B.xy + A.zy * B.yy + A.zz * B.zy;
|
|
result.element.zz = A.zx * B.xz + A.zy * B.yz + A.zz * B.zz;
|
|
return result;
|
|
#undef A // undefine shorthand label
|
|
#undef B
|
|
}
|
|
|
|
/**
|
|
* @brief Multiplies rotation matrix with scalar.
|
|
* @param rotationMatrix Rotation matrix to be multiplied.
|
|
* @param vector Vector to be multiplied.
|
|
* @return Rotation matrix multiplied with scalar.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionVector3 FusionRotationMatrixMultiplyVector(const FusionRotationMatrix rotationMatrix, const FusionVector3 vector) {
|
|
#define R rotationMatrix.element // define shorthand label for more readable code
|
|
FusionVector3 result;
|
|
result.axis.x = R.xx * vector.axis.x + R.xy * vector.axis.y + R.xz * vector.axis.z;
|
|
result.axis.y = R.yx * vector.axis.x + R.yy * vector.axis.y + R.yz * vector.axis.z;
|
|
result.axis.z = R.zx * vector.axis.x + R.zy * vector.axis.y + R.zz * vector.axis.z;
|
|
return result;
|
|
#undef R // undefine shorthand label
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Inline functions - Conversion operations
|
|
|
|
/**
|
|
* @brief Converts a quaternion to a rotation matrix.
|
|
* @param quaternion Quaternion to be converted.
|
|
* @return Rotation matrix.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionRotationMatrix FusionQuaternionToRotationMatrix(const FusionQuaternion quaternion) {
|
|
#define Q quaternion.element // define shorthand label for more readable code
|
|
const float qwqw = Q.w * Q.w; // calculate common terms to avoid repeated operations
|
|
const float qwqx = Q.w * Q.x;
|
|
const float qwqy = Q.w * Q.y;
|
|
const float qwqz = Q.w * Q.z;
|
|
const float qxqy = Q.x * Q.y;
|
|
const float qxqz = Q.x * Q.z;
|
|
const float qyqz = Q.y * Q.z;
|
|
FusionRotationMatrix rotationMatrix;
|
|
rotationMatrix.element.xx = 2.0f * (qwqw - 0.5f + Q.x * Q.x);
|
|
rotationMatrix.element.xy = 2.0f * (qxqy + qwqz);
|
|
rotationMatrix.element.xz = 2.0f * (qxqz - qwqy);
|
|
rotationMatrix.element.yx = 2.0f * (qxqy - qwqz);
|
|
rotationMatrix.element.yy = 2.0f * (qwqw - 0.5f + Q.y * Q.y);
|
|
rotationMatrix.element.yz = 2.0f * (qyqz + qwqx);
|
|
rotationMatrix.element.zx = 2.0f * (qxqz + qwqy);
|
|
rotationMatrix.element.zy = 2.0f * (qyqz - qwqx);
|
|
rotationMatrix.element.zz = 2.0f * (qwqw - 0.5f + Q.z * Q.z);
|
|
return rotationMatrix;
|
|
#undef Q // undefine shorthand label
|
|
}
|
|
|
|
/**
|
|
* @brief Converts a quaternion to Euler angles in degrees.
|
|
* @param quaternion Quaternion to be converted.
|
|
* @return Euler angles in degrees.
|
|
*/
|
|
static inline __attribute__((always_inline)) FusionEulerAngles FusionQuaternionToEulerAngles(const FusionQuaternion quaternion) {
|
|
#define Q quaternion.element // define shorthand label for more readable code
|
|
const float qwqwMinusHalf = Q.w * Q.w - 0.5f; // calculate common terms to avoid repeated operations
|
|
FusionEulerAngles eulerAngles;
|
|
eulerAngles.angle.roll = FusionRadiansToDegrees(atan2f(Q.y * Q.z - Q.w * Q.x, qwqwMinusHalf + Q.z * Q.z));
|
|
eulerAngles.angle.pitch = FusionRadiansToDegrees(-1.0f * asinf(2.0f * (Q.x * Q.z + Q.w * Q.y)));
|
|
eulerAngles.angle.yaw = FusionRadiansToDegrees(atan2f(Q.x * Q.y - Q.w * Q.z, qwqwMinusHalf + Q.x * Q.x));
|
|
return eulerAngles;
|
|
#undef Q // undefine shorthand label
|
|
}
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
// End of file
|