CMSIS-DSP: Added scalar f32 quaternion functions.

Some correction for RFFT Fast f32 in Python wrapper
pull/19/head
Christophe Favergeon 5 years ago
parent 25a524baad
commit 4357c9e947

@ -45,6 +45,7 @@
* - Support Vector Machine functions (SVM) * - Support Vector Machine functions (SVM)
* - Bayes classifier functions * - Bayes classifier functions
* - Distance functions * - Distance functions
* - Quaternion functions
* *
* The library has generally separate functions for operating on 8-bit integers, 16-bit integers, * The library has generally separate functions for operating on 8-bit integers, 16-bit integers,
* 32-bit integer and 32-bit floating-point values. * 32-bit integer and 32-bit floating-point values.
@ -223,6 +224,7 @@
#include "dsp/fast_math_functions.h" #include "dsp/fast_math_functions.h"
#include "dsp/transform_functions.h" #include "dsp/transform_functions.h"
#include "dsp/filtering_functions.h" #include "dsp/filtering_functions.h"
#include "dsp/quaternion_math_functions.h"

@ -0,0 +1,155 @@
/******************************************************************************
* @file quaternion_math_functions.h
* @brief Public header file for CMSIS DSP Library
******************************************************************************/
/*
* Copyright (c) 2010-2021 Arm Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _QUATERNION_MATH_FUNCTIONS_H_
#define _QUATERNION_MATH_FUNCTIONS_H_
#include "arm_math_types.h"
#include "arm_math_memory.h"
#include "dsp/none.h"
#include "dsp/utils.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @defgroup groupQuaternionMath Quaternion Math Functions
* Functions to operates on quaternions and convert between a
* rotation and quaternion representation.
*/
/**
@brief Floating-point quaternion Norm.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pNorms points to the output vector of norms
@param[in] nbQuaternions number of quaternions in each vector
@return none
*/
void arm_quaternion_norm_f32(const float32_t *pInputQuaternions,
float32_t *pNorms,
uint32_t nbQuaternions);
/**
@brief Floating-point quaternion inverse.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pInverseQuaternions points to the output vector of inverse quaternions
@param[in] nbQuaternions number of quaternions in each vector
@return none
*/
void arm_quaternion_inverse_f32(const float32_t *pInputQuaternions,
float32_t *pInverseQuaternions,
uint32_t nbQuaternions);
/**
@brief Floating-point quaternion conjugates.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pConjugateQuaternions points to the output vector of conjugate quaternions
@param[in] nbQuaternions number of quaternions in each vector
@return none
*/
void arm_quaternion_conjugate_f32(const float32_t *inputQuaternions,
float32_t *pConjugateQuaternions,
uint32_t nbQuaternions);
/**
@brief Floating-point normalization of quaternions.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pNormalizedQuaternions points to the output vector of normalized quaternions
@param[in] nbQuaternions number of quaternions in each vector
@return none
*/
void arm_quaternion_normalize_f32(const float32_t *inputQuaternions,
float32_t *pNormalizedQuaternions,
uint32_t nbQuaternions);
/**
@brief Floating-point product of two quaternions.
@param[in] qa First quaternion
@param[in] qb Second quaternion
@param[out] r Product of two quaternions
@return none
*/
void arm_quaternion_product_single_f32(const float32_t *qa,
const float32_t *qb,
float32_t *r);
/**
@brief Floating-point elementwise product two quaternions.
@param[in] qa First array of quaternions
@param[in] qb Second array of quaternions
@param[out] r Elementwise product of quaternions
@param[in] nbQuaternions Number of quaternions in the array
@return none
*/
void arm_quaternion_product_f32(const float32_t *qa,
const float32_t *qb,
float32_t *r,
uint32_t nbQuaternions);
/**
* @brief Conversion of quaternion to equivalent rotation matrix.
* @param[in] pInputQuaternions points to an array of normalized quaternions
* @param[out] pOutputRotations points to an array of 3x3 rotations (in row order)
* @param[in] nbQuaternions in the array
* @return none.
*
* <b>Format of rotation matrix</b>
* \par
* The quaternion a + ib + jc + kd is converted into rotation matrix:
* a^2 + b^2 - c^2 - d^2 2bc - 2ad 2bd + 2ac
* 2bc + 2ad a^2 - b^2 + c^2 - d^2 2cd - 2ab
* 2bd - 2ac 2cd + 2ab a^2 - b^2 - c^2 + d^2
*
* Rotation matrix is saved in row order : R00 R01 R02 R10 R11 R12 R20 R21 R22
*/
void arm_quaternion2rotation_f32(const float32_t *pInputQuaternions,
float32_t *pOutputRotations,
uint32_t nbQuaternions);
/**
* @brief Conversion of a rotation matrix to equivalent quaternion.
* @param[in] pInputRotations points to an array 3x3 rotation matrix (in row order)
* @param[out] pOutputQuaternions points to an array of quaternions
* @param[in] nbQuaternions in the array
* @return none.
*/
void arm_rotation2quaternion_f32(const float32_t *pInputRotations,
float32_t *pOutputQuaternions,
uint32_t nbQuaternions);
#ifdef __cplusplus
}
#endif
#endif /* ifndef _QUATERNION_MATH_FUNCTIONS_H_ */

@ -7914,7 +7914,7 @@ cmsis_arm_rfft_f32(PyObject *obj, PyObject *args)
arm_rfft_f32(selfS->instance,pSrc_converted,pDst); arm_rfft_f32(selfS->instance,pSrc_converted,pDst);
FLOATARRAY1(pDstOBJ,2*selfS->instance->fftLenReal,pDst); FLOATARRAY1(pDstOBJ,selfS->instance->fftLenReal+1,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ); PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -8412,11 +8412,11 @@ cmsis_arm_rfft_fast_f32(PyObject *obj, PyObject *args)
ml_arm_rfft_fast_instance_f32Object *selfS = (ml_arm_rfft_fast_instance_f32Object *)S; ml_arm_rfft_fast_instance_f32Object *selfS = (ml_arm_rfft_fast_instance_f32Object *)S;
GETARGUMENT(p,NPY_DOUBLE,double,float32_t); GETARGUMENT(p,NPY_DOUBLE,double,float32_t);
pOut=PyMem_Malloc(sizeof(float32_t)*2*selfS->instance->fftLenRFFT); pOut=PyMem_Malloc(sizeof(float32_t)*(selfS->instance->fftLenRFFT));
arm_rfft_fast_f32(selfS->instance,p_converted,pOut,(uint8_t)ifftFlag); arm_rfft_fast_f32(selfS->instance,p_converted,pOut,(uint8_t)ifftFlag);
FLOATARRAY1(pOutOBJ,2*selfS->instance->fftLenRFFT,pOut); FLOATARRAY1(pOutOBJ,(selfS->instance->fftLenRFFT),pOut);
PyObject *pythonResult = Py_BuildValue("O",pOutOBJ); PyObject *pythonResult = Py_BuildValue("O",pOutOBJ);

@ -0,0 +1,27 @@
import cmsisdsp as dsp
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
import scipy.fft
def chop(A, eps = 1e-6):
B = np.copy(A)
B[np.abs(A) < eps] = 0
return B
nb = 32
signal = np.cos(2 * np.pi * np.arange(nb) / nb)*np.cos(0.2*2 * np.pi * np.arange(nb) / nb)
#print("{")
#for x in signal:
# print("%f," % x)
#print("}")
result1=scipy.fft.rfft(signal)
print(chop(result1))
rfftf32=dsp.arm_rfft_fast_instance_f32()
status=dsp.arm_rfft_fast_init_f32(rfftf32,nb)
print(status)
resultI = dsp.arm_rfft_fast_f32(rfftf32,signal,0)
print(chop(resultI))

@ -41,6 +41,7 @@ option(SVM "Support Vector Machine Functions" ON)
option(BAYES "Bayesian Estimators" ON) option(BAYES "Bayesian Estimators" ON)
option(DISTANCE "Distance Functions" ON) option(DISTANCE "Distance Functions" ON)
option(INTERPOLATION "Interpolation Functions" ON) option(INTERPOLATION "Interpolation Functions" ON)
option(QUATERNIONMATH "Quaternion Math Functions" ON)
# When OFF it is the default behavior : all tables are included. # When OFF it is the default behavior : all tables are included.
option(CONFIGTABLE "Configuration of table allowed" OFF) option(CONFIGTABLE "Configuration of table allowed" OFF)
@ -201,6 +202,11 @@ if (COMPLEXMATH)
target_link_libraries(CMSISDSP INTERFACE CMSISDSPComplexMath) target_link_libraries(CMSISDSP INTERFACE CMSISDSPComplexMath)
endif() endif()
if (QUATERNIONMATH)
add_subdirectory(QuaternionMathFunctions)
target_link_libraries(CMSISDSP INTERFACE CMSISDSPQuaternionMath)
endif()
if (CONTROLLER) if (CONTROLLER)
add_subdirectory(ControllerFunctions) add_subdirectory(ControllerFunctions)
# Fast tables inclusion is allowed # Fast tables inclusion is allowed

@ -0,0 +1,31 @@
cmake_minimum_required (VERSION 3.14)
project(CMSISDSPQuaternionMath)
include(configLib)
include(configDsp)
add_library(CMSISDSPQuaternionMath STATIC arm_quaternion_norm_f32.c)
target_sources(CMSISDSPQuaternionMath PRIVATE arm_quaternion_inverse_f32.c)
target_sources(CMSISDSPQuaternionMath PRIVATE arm_quaternion_conjugate_f32.c)
target_sources(CMSISDSPQuaternionMath PRIVATE arm_quaternion_normalize_f32.c)
target_sources(CMSISDSPQuaternionMath PRIVATE arm_quaternion_product_single_f32.c)
target_sources(CMSISDSPQuaternionMath PRIVATE arm_quaternion_product_f32.c)
target_sources(CMSISDSPQuaternionMath PRIVATE arm_quaternion2rotation_f32.c)
target_sources(CMSISDSPQuaternionMath PRIVATE arm_rotation2quaternion_f32.c)
if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16))
endif()
configLib(CMSISDSPQuaternionMath ${ROOT})
configDsp(CMSISDSPQuaternionMath ${ROOT})
### Includes
target_include_directories(CMSISDSPQuaternionMath PUBLIC "${DSP}/Include")

@ -0,0 +1,34 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: QuaternionMathFunctions.c
* Description: Combination of all quaternion math function source files.
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2019-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "arm_quaternion_norm_f32.c"
#include "arm_quaternion_inverse_f32.c"
#include "arm_quaternion_conjugate_f32.c"
#include "arm_quaternion_normalize_f32.c"
#include "arm_quaternion_product_single_f32.c"
#include "arm_quaternion_product_f32.c"
#include "arm_quaternion2rotation_f32.c"
#include "arm_rotation2quaternion_f32.c"

@ -0,0 +1,109 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_quaternion2rotation_f32.c
* Description: Floating-point quaternion 2 rotation conversion
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
/**
@ingroup groupQuaternionMath
*/
/**
@defgroup QuatConv Quaternion conversions
Conversions between quaternion and rotation representations.
*/
/**
@ingroup QuatConv
*/
/**
@defgroup QuatRot Quaternion to Rotation
Conversions from quaternion to rotation.
*/
/**
@addtogroup QuatRot
@{
*/
/**
@brief Conversion of quaternion to equivalent rotation matrix.
@param[in] pInputQuaternions points to an array of normalized quaternions
@param[out] pOutputRotations points to an array of 3x3 rotations (in row order)
@param[in] nbQuaternions number of quaternions in the array
@return none.
@par
Format of rotation matrix
The quaternion a + ib + jc + kd is converted into rotation matrix:
<pre>
a^2 + b^2 - c^2 - d^2 2bc - 2ad 2bd + 2ac
2bc + 2ad a^2 - b^2 + c^2 - d^2 2cd - 2ab
2bd - 2ac 2cd + 2ab a^2 - b^2 - c^2 + d^2
</pre>
Rotation matrix is saved in row order : R00 R01 R02 R10 R11 R12 R20 R21 R22
*/
void arm_quaternion2rotation_f32(const float32_t *pInputQuaternions,
float32_t *pOutputRotations,
uint32_t nbQuaternions)
{
for(uint32_t nb=0; nb < nbQuaternions; nb++)
{
float32_t q00 = SQ(pInputQuaternions[0 + nb * 4]);
float32_t q11 = SQ(pInputQuaternions[1 + nb * 4]);
float32_t q22 = SQ(pInputQuaternions[2 + nb * 4]);
float32_t q33 = SQ(pInputQuaternions[3 + nb * 4]);
float32_t q01 = pInputQuaternions[0 + nb * 4]*pInputQuaternions[1 + nb * 4];
float32_t q02 = pInputQuaternions[0 + nb * 4]*pInputQuaternions[2 + nb * 4];
float32_t q03 = pInputQuaternions[0 + nb * 4]*pInputQuaternions[3 + nb * 4];
float32_t q12 = pInputQuaternions[1 + nb * 4]*pInputQuaternions[2 + nb * 4];
float32_t q13 = pInputQuaternions[1 + nb * 4]*pInputQuaternions[3 + nb * 4];
float32_t q23 = pInputQuaternions[2 + nb * 4]*pInputQuaternions[3 + nb * 4];
float32_t xx = q00 + q11 - q22 - q33;
float32_t yy = q00 - q11 + q22 - q33;
float32_t zz = q00 - q11 - q22 + q33;
float32_t xy = 2*(q12 - q03);
float32_t xz = 2*(q13 + q02);
float32_t yx = 2*(q12 + q03);
float32_t yz = 2*(q23 - q01);
float32_t zx = 2*(q13 - q02);
float32_t zy = 2*(q23 + q01);
pOutputRotations[0 + nb * 9] = xx; pOutputRotations[1 + nb * 9] = xy; pOutputRotations[2 + nb * 9] = xz;
pOutputRotations[3 + nb * 9] = yx; pOutputRotations[4 + nb * 9] = yy; pOutputRotations[5 + nb * 9] = yz;
pOutputRotations[6 + nb * 9] = zx; pOutputRotations[7 + nb * 9] = zy; pOutputRotations[8 + nb * 9] = zz;
}
}
/**
@} end of QuatRot group
*/

@ -0,0 +1,68 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_quaternion_conjugate_f32.c
* Description: Floating-point quaternion conjugate
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
/**
@ingroup groupQuaternionMath
*/
/**
@defgroup QuatConjugate Quaternion Conjugate
Compute the conjugate of a quaternion.
*/
/**
@addtogroup QuatConjugate
@{
*/
/**
@brief Floating-point quaternion conjugates.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pConjugateQuaternions points to the output vector of conjugate quaternions
@param[in] nbQuaternions number of quaternions in each vector
@return none
*/
void arm_quaternion_conjugate_f32(const float32_t *pInputQuaternions,
float32_t *pConjugateQuaternions,
uint32_t nbQuaternions)
{
for(uint32_t i=0; i < nbQuaternions; i++)
{
pConjugateQuaternions[4 * i + 0] = pInputQuaternions[4 * i + 0];
pConjugateQuaternions[4 * i + 1] = -pInputQuaternions[4 * i + 1];
pConjugateQuaternions[4 * i + 2] = -pInputQuaternions[4 * i + 2];
pConjugateQuaternions[4 * i + 3] = -pInputQuaternions[4 * i + 3];
}
}
/**
@} end of QuatConjugate group
*/

@ -0,0 +1,78 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_quaternion_inverse_f32.c
* Description: Floating-point quaternion inverse
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
/**
@ingroup groupQuaternionMath
*/
/**
@defgroup QuatInverse Quaternion Inverse
Compute the inverse of a quaternion.
*/
/**
@addtogroup QuatInverse
@{
*/
/**
@brief Floating-point quaternion inverse.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pInverseQuaternions points to the output vector of inverse quaternions
@param[in] nbQuaternions number of quaternions in each vector
@return none
*/
void arm_quaternion_inverse_f32(const float32_t *pInputQuaternions,
float32_t *pInverseQuaternions,
uint32_t nbQuaternions)
{
float32_t temp;
for(uint32_t i=0; i < nbQuaternions; i++)
{
temp = SQ(pInputQuaternions[4 * i + 0]) +
SQ(pInputQuaternions[4 * i + 1]) +
SQ(pInputQuaternions[4 * i + 2]) +
SQ(pInputQuaternions[4 * i + 3]);
pInverseQuaternions[4 * i + 0] = pInputQuaternions[4 * i + 0] / temp;
pInverseQuaternions[4 * i + 1] = -pInputQuaternions[4 * i + 1] / temp;
pInverseQuaternions[4 * i + 2] = -pInputQuaternions[4 * i + 2] / temp;
pInverseQuaternions[4 * i + 3] = -pInputQuaternions[4 * i + 3] / temp;
}
}
/**
@} end of QuatInverse group
*/

@ -0,0 +1,73 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_quaternion_norm_f32.c
* Description: Floating-point quaternion Norm
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
/**
@ingroup groupQuaternionMath
*/
/**
@defgroup QuatNorm Quaternion Norm
Compute the norm of a quaternion.
*/
/**
@addtogroup QuatNorm
@{
*/
/**
@brief Floating-point quaternion Norm.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pNorms points to the output vector of norms
@param[in] nbQuaternions number of quaternions in the input vector
@return none
*/
void arm_quaternion_norm_f32(const float32_t *pInputQuaternions,
float32_t *pNorms,
uint32_t nbQuaternions)
{
float32_t temp;
for(uint32_t i=0; i < nbQuaternions; i++)
{
temp = SQ(pInputQuaternions[4 * i + 0]) +
SQ(pInputQuaternions[4 * i + 1]) +
SQ(pInputQuaternions[4 * i + 2]) +
SQ(pInputQuaternions[4 * i + 3]);
pNorms[i] = sqrtf(temp);
}
}
/**
@} end of QuatNorm group
*/

@ -0,0 +1,75 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_quaternion_normalize_f32.c
* Description: Floating-point quaternion normalization
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
/**
@ingroup groupQuaternionMath
*/
/**
@defgroup QuatNormalized Quaternion normalization
Compute a normalized quaternion.
*/
/**
@addtogroup QuatNormalized
@{
*/
/**
@brief Floating-point normalization of quaternions.
@param[in] pInputQuaternions points to the input vector of quaternions
@param[out] pNormalizedQuaternions points to the output vector of normalized quaternions
@param[in] nbQuaternions number of quaternions in each vector
@return none
*/
void arm_quaternion_normalize_f32(const float32_t *pInputQuaternions,
float32_t *pNormalizedQuaternions,
uint32_t nbQuaternions)
{
float32_t temp;
for(uint32_t i=0; i < nbQuaternions; i++)
{
temp = SQ(pInputQuaternions[4 * i + 0]) +
SQ(pInputQuaternions[4 * i + 1]) +
SQ(pInputQuaternions[4 * i + 2]) +
SQ(pInputQuaternions[4 * i + 3]);
temp = sqrtf(temp);
pNormalizedQuaternions[4 * i + 0] = pInputQuaternions[4 * i + 0] / temp;
pNormalizedQuaternions[4 * i + 1] = pInputQuaternions[4 * i + 1] / temp;
pNormalizedQuaternions[4 * i + 2] = pInputQuaternions[4 * i + 2] / temp;
pNormalizedQuaternions[4 * i + 3] = pInputQuaternions[4 * i + 3] / temp;
}
}
/**
@} end of QuatNormalized group
*/

@ -0,0 +1,70 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_quaternion_product_f32.c
* Description: Floating-point quaternion product
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
/**
@ingroup groupQuaternionMath
*/
/**
@defgroup QuatProd Quaternion Product
Compute the product of quaternions.
*/
/**
@addtogroup QuatProd
@{
*/
/**
@brief Floating-point elementwise product two quaternions.
@param[in] qa first array of quaternions
@param[in] qb second array of quaternions
@param[out] r elementwise product of quaternions
@param[in] nbQuaternions number of quaternions in the array
@return none
*/
void arm_quaternion_product_f32(const float32_t *qa,
const float32_t *qb,
float32_t *r,
uint32_t nbQuaternions)
{
for(uint32_t i=0; i < nbQuaternions; i++)
{
arm_quaternion_product_single_f32(qa, qb, r);
qa += 4;
qb += 4;
r += 4;
}
}
/**
@} end of QuatProd group
*/

@ -0,0 +1,64 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_quaternion_product_single_f32.c
* Description: Floating-point quaternion product
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
/**
@ingroup groupQuaternionMath
*/
/**
@defgroup QuatProd Quaternion Product
Compute the product of quaternions.
*/
/**
@addtogroup QuatProdSingle
@{
*/
/**
@brief Floating-point product of two quaternions.
@param[in] qa first quaternion
@param[in] qb second quaternion
@param[out] r product of two quaternions
@return none
*/
void arm_quaternion_product_single_f32(const float32_t *qa,
const float32_t *qb,
float32_t *r)
{
r[0] = qa[0] * qb[0] - qa[1] * qb[1] - qa[2] * qb[2] - qa[3] * qb[3];
r[1] = qa[0] * qb[1] + qa[1] * qb[0] + qa[2] * qb[3] - qa[3] * qb[2];
r[2] = qa[0] * qb[2] + qa[2] * qb[0] + qa[3] * qb[1] - qa[1] * qb[3];
r[3] = qa[0] * qb[3] + qa[3] * qb[0] + qa[1] * qb[2] - qa[2] * qb[1];
}
/**
@} end of QuatProdSingle group
*/

@ -0,0 +1,117 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: arm_rotation2quaternion_f32.c
* Description: Floating-point rotation to quaternion conversion
*
*
* Target Processor: Cortex-M cores
* -------------------------------------------------------------------- */
/*
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dsp/quaternion_math_functions.h"
#include <math.h>
#define RI(x,y) r[(3*(x) + (y))]
/**
@ingroup QuatConv
*/
/**
@defgroup RotQuat Rotation to Quaternion
Conversions from rotation to quaternion.
*/
/**
@addtogroup RotQuat
@{
*/
/**
* @brief Conversion of a rotation matrix to an equivalent quaternion.
* @param[in] pInputRotations points to an array 3x3 rotation matrix (in row order)
* @param[out] pOutputQuaternions points to an array quaternions
* @param[in] nbQuaternions number of quaternions in the array
* @return none.
*
* q and -q are representing the same rotation. This ambiguity must be taken into
* account when using the output of this function.
*
*/
void arm_rotation2quaternion_f32(const float32_t *pInputRotations,
float32_t *pOutputQuaternions,
uint32_t nbQuaternions)
{
for(uint32_t nb=0; nb < nbQuaternions; nb++)
{
const float32_t *r=&pInputRotations[nb*9];
float32_t *q=&pOutputQuaternions[nb*4];
float32_t trace = RI(0,0) + RI(1,1) + RI(2,2);
float32_t doubler;
float32_t s;
if (trace > 0)
{
doubler = sqrtf(trace + 1.0) * 2; // invs=4*qw
s = 1.0 / doubler;
q[0] = 0.25 * doubler;
q[1] = (RI(2,1) - RI(1,2)) * s;
q[2] = (RI(0,2) - RI(2,0)) * s;
q[3] = (RI(1,0) - RI(0,1)) * s;
}
else if ((RI(0,0) > RI(1,1)) && (RI(0,0) > RI(2,2)) )
{
doubler = sqrtf(1.0 + RI(0,0) - RI(1,1) - RI(2,2)) * 2; // invs=4*qx
s = 1.0 / doubler;
q[0] = (RI(2,1) - RI(1,2)) * s;
q[1] = 0.25 * doubler;
q[2] = (RI(0,1) + RI(1,0)) * s;
q[3] = (RI(0,2) + RI(2,0)) * s;
}
else if (RI(1,1) > RI(2,2))
{
doubler = sqrtf(1.0 + RI(1,1) - RI(0,0) - RI(2,2)) * 2; // invs=4*qy
s = 1.0 / doubler;
q[0] = (RI(0,2) - RI(2,0)) * s;
q[1] = (RI(0,1) + RI(1,0)) * s;
q[2] = 0.25 * doubler;
q[3] = (RI(1,2) + RI(2,1)) * s;
}
else
{
doubler = sqrtf(1.0 + RI(2,2) - RI(0,0) - RI(1,1)) * 2; // invs=4*qz
s = 1.0 / doubler;
q[0] = (RI(1,0) - RI(0,1)) * s;
q[1] = (RI(0,2) + RI(2,0)) * s;
q[2] = (RI(1,2) + RI(2,1)) * s;
q[3] = 0.25 * doubler;
}
}
}
/**
@} end of RotQuat group
*/

@ -249,6 +249,11 @@ if (BASICMATH)
Source/Tests/BasicTestsQ7.cpp) Source/Tests/BasicTestsQ7.cpp)
endif() endif()
if (QUATERNIONMATH)
set(QUATERNIONMATHSRC Source/Tests/QuaternionTestsF32.cpp
)
endif()
if (COMPLEXMATH) if (COMPLEXMATH)
set(COMPLEXMATHSRC Source/Tests/ComplexTestsF32.cpp set(COMPLEXMATHSRC Source/Tests/ComplexTestsF32.cpp
Source/Tests/ComplexTestsQ31.cpp Source/Tests/ComplexTestsQ31.cpp
@ -336,6 +341,13 @@ if (DISTANCE)
Source/Tests/DistanceTestsU32.cpp) Source/Tests/DistanceTestsU32.cpp)
endif() endif()
if (INTERPOLATION)
set(INTERPOLATIONSRC Source/Tests/InterpolationTestsF32.cpp
Source/Tests/InterpolationTestsQ31.cpp
Source/Tests/InterpolationTestsQ15.cpp
Source/Tests/InterpolationTestsQ7.cpp)
endif()
set(TESTSRC set(TESTSRC
${BASICMATHSRC} ${BASICMATHSRC}
${COMPLEXMATHSRC} ${COMPLEXMATHSRC}
@ -349,14 +361,12 @@ set(TESTSRC
${SVMSRC} ${SVMSRC}
${BAYESSRC} ${BAYESSRC}
${DISTANCESRC} ${DISTANCESRC}
Source/Tests/InterpolationTestsF32.cpp ${QUATERNIONMATHSRC}
Source/Tests/InterpolationTestsQ31.cpp ${INTERPOLATIONSRC}
Source/Tests/InterpolationTestsQ15.cpp #Source/Tests/ExampleCategoryF32.cpp
Source/Tests/InterpolationTestsQ7.cpp #Source/Tests/ExampleCategoryQ31.cpp
Source/Tests/ExampleCategoryF32.cpp #Source/Tests/ExampleCategoryQ15.cpp
Source/Tests/ExampleCategoryQ31.cpp #Source/Tests/ExampleCategoryQ7.cpp
Source/Tests/ExampleCategoryQ15.cpp
Source/Tests/ExampleCategoryQ7.cpp
) )

@ -0,0 +1,20 @@
#include "Test.h"
#include "Pattern.h"
#include "dsp/quaternion_math_functions.h"
class QuaternionTestsF32:public Client::Suite
{
public:
QuaternionTestsF32(Testing::testID_t id);
virtual void setUp(Testing::testID_t,std::vector<Testing::param_t>& params,Client::PatternMgr *mgr);
virtual void tearDown(Testing::testID_t,Client::PatternMgr *mgr);
private:
#include "QuaternionTestsF32_decl.h"
Client::Pattern<float32_t> input1;
Client::Pattern<float32_t> input2;
Client::LocalPattern<float32_t> output;
// Reference patterns are not loaded when we are in dump mode
Client::RefPattern<float32_t> ref;
};

@ -0,0 +1,82 @@
81
1
1
1
1
1
3
1
1
5
1
3
1
1
3
3
1
3
5
1
5
1
1
5
3
1
5
5
3
1
1
3
1
3
3
1
5
3
3
1
3
3
3
3
3
5
3
5
1
3
5
3
3
5
5
5
1
1
5
1
3
5
1
5
5
3
1
5
3
3
5
3
5
5
5
1
5
5
3
5
5
5

@ -0,0 +1,79 @@
import os.path
import numpy as np
import itertools
import Tools
from pyquaternion import Quaternion
# mult, multvec, inverse, conjugate, normalize rot2quat, quat2rot , norm
def flattenQuat(l):
return(np.array([list(x) for x in l]).reshape(4*len(l)))
def flattenRot(l):
return(np.array([list(x) for x in l]).reshape(9*len(l)))
# q and -q are representing the same rotation.
# So there is an ambiguity for the tests.
# We force the real part of be positive.
def mkQuaternion(mat):
q=Quaternion(matrix=mat)
if q.scalar < 0:
return(-q)
else:
return(q)
def writeTests(config,format):
NBSAMPLES=128
a=[Quaternion.random() for x in range(NBSAMPLES)]
b=[Quaternion.random() for x in range(NBSAMPLES)]
config.writeInput(1, flattenQuat(a))
config.writeInput(2, flattenQuat(b))
normTest = [x.norm for x in a]
config.writeReference(1, normTest)
inverseTest = [x.inverse for x in a]
config.writeReference(2, flattenQuat(inverseTest))
conjugateTest = [x.conjugate for x in a]
config.writeReference(3, flattenQuat(conjugateTest))
normalizeTest = [x.normalised for x in a]
config.writeReference(4, flattenQuat(normalizeTest))
multTest = [a[i] * b[i] for i in range(NBSAMPLES)]
config.writeReference(5, flattenQuat(multTest))
quat2RotTest = [x.rotation_matrix for x in a]
config.writeReference(6, flattenRot(quat2RotTest))
config.writeInput(7, flattenRot(quat2RotTest))
rot2QuatTest = [mkQuaternion(x) for x in quat2RotTest]
config.writeReference(7, flattenQuat(rot2QuatTest))
def generatePatterns():
PATTERNDIR = os.path.join("Patterns","DSP","QuaternionMaths","QuaternionMaths")
PARAMDIR = os.path.join("Parameters","DSP","QuaternionMaths","QuaternionMaths")
configf32=Tools.Config(PATTERNDIR,PARAMDIR,"f32")
configf16=Tools.Config(PATTERNDIR,PARAMDIR,"f16")
writeTests(configf32,0)
writeTests(configf16,16)
# Params just as example
someLists=[[1,3,5],[1,3,5],[1,3,5]]
r=np.array([element for element in itertools.product(*someLists)])
configf32.writeParam(1, r.reshape(81))
if __name__ == '__main__':
generatePatterns()

@ -0,0 +1,258 @@
H
128
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00
// 1.000000
0x3c00

@ -0,0 +1,258 @@
W
128
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000
// 1.000000
0x3f800000

@ -0,0 +1,234 @@
#include "QuaternionTestsF32.h"
#include <stdio.h>
#include "Error.h"
#define SNR_THRESHOLD 120
/*
Reference patterns are generated with
a double precision computation.
*/
#define REL_ERROR (1.0e-6)
#define ABS_ERROR (1.0e-7)
void QuaternionTestsF32::test_quaternion_norm_f32()
{
const float32_t *inp1=input1.ptr();
float32_t *outp=output.ptr();
arm_quaternion_norm_f32(inp1,outp,output.nbSamples());
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::test_quaternion_inverse_f32()
{
const float32_t *inp1=input1.ptr();
float32_t *outp=output.ptr();
arm_quaternion_inverse_f32(inp1,outp,input1.nbSamples() >> 2);
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::test_quaternion_conjugate_f32()
{
const float32_t *inp1=input1.ptr();
float32_t *outp=output.ptr();
arm_quaternion_conjugate_f32(inp1,outp,input1.nbSamples() >> 2);
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::test_quaternion_normalize_f32()
{
const float32_t *inp1=input1.ptr();
float32_t *outp=output.ptr();
arm_quaternion_normalize_f32(inp1,outp,input1.nbSamples() >> 2);
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::test_quaternion_prod_single_f32()
{
const float32_t *inp1=input1.ptr();
const float32_t *inp2=input2.ptr();
float32_t *outp=output.ptr();
for(uint32_t i=0; i < input1.nbSamples() >> 2; i++)
{
arm_quaternion_product_single_f32(inp1,inp2,outp);
outp += 4;
inp1 += 4;
inp2 += 4;
}
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::test_quaternion_product_f32()
{
const float32_t *inp1=input1.ptr();
const float32_t *inp2=input2.ptr();
float32_t *outp=output.ptr();
arm_quaternion_product_f32(inp1,inp2,outp,input1.nbSamples() >> 2);
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::test_quaternion2rotation_f32()
{
const float32_t *inp1=input1.ptr();
float32_t *outp=output.ptr();
arm_quaternion2rotation_f32(inp1,outp,input1.nbSamples() >> 2);
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::test_rotation2quaternion_f32()
{
const float32_t *inp1=input1.ptr();
float32_t *outp=output.ptr();
/*
q and -q are representing the same rotation.
To remove the ambiguity we force the real part ot be positive.
Same convention followed in Python script.
*/
arm_rotation2quaternion_f32(inp1,outp,output.nbSamples() >> 2);
/* Remove ambiguity */
for(uint32_t i=0; i < output.nbSamples() >> 2 ; i++)
{
if (outp[0] < 0.0f)
{
outp[0] = -outp[0];
outp[1] = -outp[1];
outp[2] = -outp[2];
outp[3] = -outp[3];
}
outp += 4;
}
ASSERT_EMPTY_TAIL(output);
ASSERT_SNR(output,ref,(float32_t)SNR_THRESHOLD);
ASSERT_CLOSE_ERROR(output,ref,ABS_ERROR,REL_ERROR);
}
void QuaternionTestsF32::setUp(Testing::testID_t id,std::vector<Testing::param_t>& params,Client::PatternMgr *mgr)
{
(void)params;
Testing::nbSamples_t nb=MAX_NB_SAMPLES;
switch(id)
{
case QuaternionTestsF32::TEST_QUATERNION_NORM_F32_1:
input1.reload(QuaternionTestsF32::INPUT1_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_NORM_F32_ID,mgr,nb);
break;
case QuaternionTestsF32::TEST_QUATERNION_INVERSE_F32_2:
input1.reload(QuaternionTestsF32::INPUT1_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_INVERSE_F32_ID,mgr,nb);
break;
case QuaternionTestsF32::TEST_QUATERNION_CONJUGATE_F32_3:
input1.reload(QuaternionTestsF32::INPUT1_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_CONJUGATE_F32_ID,mgr,nb);
break;
case QuaternionTestsF32::TEST_QUATERNION_NORMALIZE_F32_4:
input1.reload(QuaternionTestsF32::INPUT1_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_NORMALIZE_F32_ID,mgr,nb);
break;
case QuaternionTestsF32::TEST_QUATERNION_PROD_SINGLE_F32_5:
input1.reload(QuaternionTestsF32::INPUT1_F32_ID,mgr,nb);
input2.reload(QuaternionTestsF32::INPUT2_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_MULT_F32_ID,mgr,nb);
break;
case QuaternionTestsF32::TEST_QUATERNION_PRODUCT_F32_6:
input1.reload(QuaternionTestsF32::INPUT1_F32_ID,mgr,nb);
input2.reload(QuaternionTestsF32::INPUT2_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_MULT_F32_ID,mgr,nb);
break;
case QuaternionTestsF32::TEST_QUATERNION2ROTATION_F32_7:
input1.reload(QuaternionTestsF32::INPUT1_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_QUAT2ROT_F32_ID,mgr,nb);
break;
case QuaternionTestsF32::TEST_ROTATION2QUATERNION_F32_8:
input1.reload(QuaternionTestsF32::INPUT7_F32_ID,mgr,nb);
ref.reload(QuaternionTestsF32::REF_ROT2QUAT_F32_ID,mgr,nb);
break;
}
output.create(ref.nbSamples(),QuaternionTestsF32::OUT_SAMPLES_F32_ID,mgr);
}
void QuaternionTestsF32::tearDown(Testing::testID_t id,Client::PatternMgr *mgr)
{
(void)id;
output.dump(mgr);
}

@ -585,6 +585,42 @@ group Root {
} }
} }
group Quaternion Tests {
class = QuaternionTests
folder = QuaternionMaths
suite Quaternion Tests F32{
class = QuaternionTestsF32
folder = QuaternionMathsF32
Pattern INPUT1_F32_ID : Input1_f32.txt
Pattern INPUT2_F32_ID : Input2_f32.txt
Pattern INPUT7_F32_ID : Input7_f32.txt
Pattern REF_NORM_F32_ID : Reference1_f32.txt
Pattern REF_INVERSE_F32_ID : Reference2_f32.txt
Pattern REF_CONJUGATE_F32_ID : Reference3_f32.txt
Pattern REF_NORMALIZE_F32_ID : Reference4_f32.txt
Pattern REF_MULT_F32_ID : Reference5_f32.txt
Pattern REF_QUAT2ROT_F32_ID : Reference6_f32.txt
Pattern REF_ROT2QUAT_F32_ID : Reference7_f32.txt
Output OUT_SAMPLES_F32_ID : Output
Functions {
Test arm_quaternion_norm_f32:test_quaternion_norm_f32
Test arm_quaternion_inverse_f32:test_quaternion_inverse_f32
Test arm_quaternion_conjugate_f32:test_quaternion_conjugate_f32
Test arm_quaternion_normalize_f32:test_quaternion_normalize_f32
Test arm_quaternion_prod_single_f32:test_quaternion_prod_single_f32
Test arm_quaternion_product_f32:test_quaternion_product_f32
Test arm_quaternion2rotation_f32:test_quaternion2rotation_f32
Test arm_rotation2quaternion_f32:test_rotation2quaternion_f32
}
}
}
group Basic Tests { group Basic Tests {
class = BasicTests class = BasicTests
folder = BasicMaths folder = BasicMaths

@ -56,6 +56,7 @@ config["SVM"]=True
config["BAYES"]=True config["BAYES"]=True
config["DISTANCE"]=True config["DISTANCE"]=True
config["INTERPOLATION"]=True config["INTERPOLATION"]=True
config["QUATERNIONMATH"]=True
config["LOOPUNROLL"]=True config["LOOPUNROLL"]=True
config["ROUNDING"]=False config["ROUNDING"]=False
@ -91,6 +92,8 @@ defaulton["SVM"]=True
defaulton["BAYES"]=True defaulton["BAYES"]=True
defaulton["DISTANCE"]=True defaulton["DISTANCE"]=True
defaulton["INTERPOLATION"]=True defaulton["INTERPOLATION"]=True
defaulton["QUATERNIONMATH"]=True
CFFTSIZE=[16,32,64,128,256,512,1024,2048,4096] CFFTSIZE=[16,32,64,128,256,512,1024,2048,4096]
CFFTDATATYPE=['F64','F32','F16','Q31','Q15'] CFFTDATATYPE=['F64','F32','F16','Q31','Q15']
@ -479,7 +482,7 @@ def configCMake(config):
"SVM", "SVM",
"BAYES", "BAYES",
"DISTANCE", "DISTANCE",
"INTERPOLATION"]) "INTERPOLATION","QUATERNIONMATH"])
configMake(config) configMake(config)
genconfig(config,"CFFT",CFFTSIZE,CFFTDATATYPE) genconfig(config,"CFFT",CFFTSIZE,CFFTDATATYPE)
Loading…
Cancel
Save