From 1eb1a2ef43151a9fb936a32624f76ec918933518 Mon Sep 17 00:00:00 2001 From: Christophe Favergeon Date: Mon, 25 Apr 2022 08:38:35 +0200 Subject: [PATCH] CMSIS-DSP: Added new functions to Python wrapper --- .../cmsisdsp_pkg/src/cmsisdsp_fastmath.c | 80 ++++++++ .../cmsisdsp_pkg/src/cmsisdsp_statistics.c | 185 ++++++++++++++++++ PythonWrapper/examples/example_1_4.py | 116 +++++++++++ Source/FastMathFunctions/arm_atan2_f16.c | 4 +- Source/FastMathFunctions/arm_atan2_f32.c | 4 +- Source/FastMathFunctions/arm_atan2_q15.c | 6 +- Source/FastMathFunctions/arm_atan2_q31.c | 4 +- cmsisdsp/__init__.py | 7 +- setup.py | 8 +- 9 files changed, 397 insertions(+), 17 deletions(-) create mode 100755 PythonWrapper/examples/example_1_4.py diff --git a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_fastmath.c b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_fastmath.c index 0096a4bd..460f3dc4 100755 --- a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_fastmath.c +++ b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_fastmath.c @@ -512,6 +512,83 @@ cmsis_arm_vlog_f64(PyObject *obj, PyObject *args) return(NULL); } +static PyObject * +cmsis_arm_atan2_q31(PyObject *obj, PyObject *args) +{ + + q31_t x,y; // input + q31_t pOut; + + if (PyArg_ParseTuple(args,"ii",&y,&x)) + { + + + + arm_status returnValue = arm_atan2_q31(y,x,&pOut); + PyObject* theReturnOBJ=Py_BuildValue("i",returnValue); + PyObject* pOutOBJ=Py_BuildValue("i",pOut); + + PyObject *pythonResult = Py_BuildValue("OO",theReturnOBJ,pOutOBJ); + + Py_DECREF(theReturnOBJ); + Py_DECREF(pOutOBJ); + return(pythonResult); + + } + return(NULL); +} + +static PyObject * +cmsis_arm_atan2_q15(PyObject *obj, PyObject *args) +{ + + q15_t x,y; // input + q15_t pOut; + + if (PyArg_ParseTuple(args,"hh",&y,&x)) + { + + + + arm_status returnValue = arm_atan2_q15(y,x,&pOut); + PyObject* theReturnOBJ=Py_BuildValue("i",returnValue); + PyObject* pOutOBJ=Py_BuildValue("h",pOut); + + PyObject *pythonResult = Py_BuildValue("OO",theReturnOBJ,pOutOBJ); + + Py_DECREF(theReturnOBJ); + Py_DECREF(pOutOBJ); + return(pythonResult); + + } + return(NULL); +} + +static PyObject * +cmsis_arm_atan2_f32(PyObject *obj, PyObject *args) +{ + + float32_t x,y; // input + float32_t pOut; + + if (PyArg_ParseTuple(args,"ff",&y,&x)) + { + + + + arm_status returnValue = arm_atan2_f32(y,x,&pOut); + PyObject* theReturnOBJ=Py_BuildValue("i",returnValue); + PyObject* pOutOBJ=Py_BuildValue("f",pOut); + + PyObject *pythonResult = Py_BuildValue("OO",theReturnOBJ,pOutOBJ); + + Py_DECREF(theReturnOBJ); + Py_DECREF(pOutOBJ); + return(pythonResult); + + } + return(NULL); +} static PyMethodDef CMSISDSPMethods[] = { @@ -538,6 +615,9 @@ static PyMethodDef CMSISDSPMethods[] = { {"arm_vlog_f32", cmsis_arm_vlog_f32, METH_VARARGS,""}, {"arm_vexp_f64", cmsis_arm_vexp_f64, METH_VARARGS,""}, {"arm_vlog_f64", cmsis_arm_vlog_f64, METH_VARARGS,""}, +{"arm_atan2_f32", cmsis_arm_atan2_f32, METH_VARARGS,""}, +{"arm_atan2_q31", cmsis_arm_atan2_q31, METH_VARARGS,""}, +{"arm_atan2_q15", cmsis_arm_atan2_q15, METH_VARARGS,""}, {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_statistics.c b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_statistics.c index e774d1ce..38745f24 100755 --- a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_statistics.c +++ b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_statistics.c @@ -2082,6 +2082,186 @@ cmsis_arm_logsumexp_dot_prod_f32(PyObject *obj, PyObject *args) return(NULL); } +static PyObject * +cmsis_arm_mse_q7(PyObject *obj, PyObject *args) +{ + + PyObject *pSrcA=NULL; // input + q7_t *pSrcA_converted=NULL; // input + PyObject *pSrcB=NULL; // input + q7_t *pSrcB_converted=NULL; // input + + uint32_t blockSize; // input + q7_t pResult; // output + + if (PyArg_ParseTuple(args,"OO",&pSrcA,&pSrcB)) + { + + GETARGUMENT(pSrcA,NPY_BYTE,int8_t,q7_t); + GETARGUMENT(pSrcB,NPY_BYTE,int8_t,q7_t); + + blockSize = arraySizepSrcA ; + + + arm_mse_q7(pSrcA_converted,pSrcB_converted, blockSize,&pResult); + PyObject* pResultOBJ=Py_BuildValue("i",pResult); + + PyObject *pythonResult = Py_BuildValue("O",pResultOBJ); + + FREEARGUMENT(pSrcA_converted); + FREEARGUMENT(pSrcB_converted); + + Py_DECREF(pResultOBJ); + return(pythonResult); + + } + return(NULL); +} + +static PyObject * +cmsis_arm_mse_q15(PyObject *obj, PyObject *args) +{ + + PyObject *pSrcA=NULL; // input + q15_t *pSrcA_converted=NULL; // input + PyObject *pSrcB=NULL; // input + q15_t *pSrcB_converted=NULL; // input + + uint32_t blockSize; // input + q15_t pResult; // output + + if (PyArg_ParseTuple(args,"OO",&pSrcA,&pSrcB)) + { + + GETARGUMENT(pSrcA,NPY_INT16,int16_t,q15_t); + GETARGUMENT(pSrcB,NPY_INT16,int16_t,q15_t); + + blockSize = arraySizepSrcA ; + + + arm_mse_q15(pSrcA_converted,pSrcB_converted,blockSize,&pResult); + PyObject* pResultOBJ=Py_BuildValue("i",pResult); + + PyObject *pythonResult = Py_BuildValue("O",pResultOBJ); + + FREEARGUMENT(pSrcA_converted); + FREEARGUMENT(pSrcB_converted); + + Py_DECREF(pResultOBJ); + return(pythonResult); + + } + return(NULL); +} + +static PyObject * +cmsis_arm_mse_q31(PyObject *obj, PyObject *args) +{ + + PyObject *pSrcA=NULL; // input + q31_t *pSrcA_converted=NULL; // input + PyObject *pSrcB=NULL; // input + q31_t *pSrcB_converted=NULL; // input + + uint32_t blockSize; // input + q31_t pResult; // output + + if (PyArg_ParseTuple(args,"OO",&pSrcA,&pSrcB)) + { + + GETARGUMENT(pSrcA,NPY_INT32,int32_t,q31_t); + GETARGUMENT(pSrcB,NPY_INT32,int32_t,q31_t); + + blockSize = arraySizepSrcA ; + + + arm_mse_q31(pSrcA_converted,pSrcB_converted,blockSize,&pResult); + PyObject* pResultOBJ=Py_BuildValue("i",pResult); + + PyObject *pythonResult = Py_BuildValue("O",pResultOBJ); + + FREEARGUMENT(pSrcA_converted); + FREEARGUMENT(pSrcB_converted); + + Py_DECREF(pResultOBJ); + return(pythonResult); + + } + return(NULL); +} + +static PyObject * +cmsis_arm_mse_f32(PyObject *obj, PyObject *args) +{ + + PyObject *pSrcA=NULL; // input + float32_t *pSrcA_converted=NULL; // input + PyObject *pSrcB=NULL; // input + float32_t *pSrcB_converted=NULL; // input + + uint32_t blockSize; // input + float32_t pResult; // output + + if (PyArg_ParseTuple(args,"OO",&pSrcA,&pSrcB)) + { + + GETARGUMENT(pSrcA,NPY_DOUBLE,double,float32_t); + GETARGUMENT(pSrcB,NPY_DOUBLE,double,float32_t); + + blockSize = arraySizepSrcA ; + + + arm_mse_f32(pSrcA_converted,pSrcB_converted,blockSize,&pResult); + PyObject* pResultOBJ=Py_BuildValue("f",pResult); + + PyObject *pythonResult = Py_BuildValue("O",pResultOBJ); + + FREEARGUMENT(pSrcA_converted); + FREEARGUMENT(pSrcB_converted); + + Py_DECREF(pResultOBJ); + return(pythonResult); + + } + return(NULL); +} + +static PyObject * +cmsis_arm_mse_f64(PyObject *obj, PyObject *args) +{ + + PyObject *pSrcA=NULL; // input + float64_t *pSrcA_converted=NULL; // input + PyObject *pSrcB=NULL; // input + float64_t *pSrcB_converted=NULL; // input + + uint32_t blockSize; // input + float64_t pResult; // output + + if (PyArg_ParseTuple(args,"OO",&pSrcA,&pSrcB)) + { + + GETARGUMENT(pSrcA,NPY_DOUBLE,double,float64_t); + GETARGUMENT(pSrcB,NPY_DOUBLE,double,float64_t); + + blockSize = arraySizepSrcA ; + + + arm_mse_f64(pSrcA_converted,pSrcB_converted,blockSize,&pResult); + PyObject* pResultOBJ=Py_BuildValue("d",pResult); + + PyObject *pythonResult = Py_BuildValue("O",pResultOBJ); + + FREEARGUMENT(pSrcA_converted); + FREEARGUMENT(pSrcB_converted); + + Py_DECREF(pResultOBJ); + return(pythonResult); + + } + return(NULL); +} + static PyMethodDef CMSISDSPMethods[] = { @@ -2160,6 +2340,11 @@ static PyMethodDef CMSISDSPMethods[] = { {"arm_logsumexp_f32", cmsis_arm_logsumexp_f32, METH_VARARGS,""}, {"arm_logsumexp_dot_prod_f32", cmsis_arm_logsumexp_dot_prod_f32, METH_VARARGS,""}, +{"arm_mse_q7", cmsis_arm_mse_q7, METH_VARARGS,""}, +{"arm_mse_q15", cmsis_arm_mse_q15, METH_VARARGS,""}, +{"arm_mse_q31", cmsis_arm_mse_q31, METH_VARARGS,""}, +{"arm_mse_f32", cmsis_arm_mse_f32, METH_VARARGS,""}, +{"arm_mse_f64", cmsis_arm_mse_f64, METH_VARARGS,""}, {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL}, diff --git a/PythonWrapper/examples/example_1_4.py b/PythonWrapper/examples/example_1_4.py new file mode 100755 index 00000000..273bf405 --- /dev/null +++ b/PythonWrapper/examples/example_1_4.py @@ -0,0 +1,116 @@ +# New functions for version 1.4 of the Python wrapper +import cmsisdsp as dsp +import cmsisdsp.fixedpoint as f +import numpy as np +import math +import colorama +from colorama import init,Fore, Back, Style + +init() + +def printTitle(s): + print("\n" + Fore.GREEN + Style.BRIGHT + s + Style.RESET_ALL) + +def printSubTitle(s): + print("\n" + Style.BRIGHT + s + Style.RESET_ALL) + +printTitle("ArcTan2") + +angles=[0, +math.pi/4, +math.pi/2, +3*math.pi/4, +math.pi, +5*math.pi/4, +3*math.pi/2, +7*math.pi/4 +] + +x = np.cos(angles) +y = np.sin(angles) + +vals=list(zip(y,x)) + +printSubTitle("Atan2 Referebce") +ref=np.array([np.arctan2(yv,xv) for (yv,xv) in vals])/math.pi*180 +print(ref) + +printSubTitle("Atan2 F32") +resf32=np.array([dsp.arm_atan2_f32(yv,xv)[1] for (yv,xv) in vals])/math.pi*180 +print(resf32) +print(np.isclose(ref,resf32,1e-6,1e-6)) + +printSubTitle("Atan2 Q31") +xQ31=f.toQ31(x) +yQ31=f.toQ31(y) +valsQ31=list(zip(yQ31,xQ31)) + +resq31=4*f.Q31toF32(np.array([dsp.arm_atan2_q31(yv,xv)[1] for (yv,xv) in valsQ31]))/math.pi*180 +print(resq31) +print(np.isclose(ref,resq31,1e-8,1e-8)) + +printSubTitle("Atan2 Q15") +xQ15=f.toQ15(x) +yQ15=f.toQ15(y) +valsQ15=list(zip(yQ15,xQ15)) + +resq15=4*f.Q15toF32(np.array([dsp.arm_atan2_q15(yv,xv)[1] for (yv,xv) in valsQ15]))/math.pi*180 +print(resq15) +print(np.isclose(ref,resq15,1e-3,1e-3)) + +printTitle("MSE") + +NBSAMPLES = 50 + +def mse(a,b): + err = a - b + return(np.dot(err,err) / len(a)) + +a=np.random.randn(NBSAMPLES) +a = a / np.max(np.abs(a)) + +b=np.random.randn(NBSAMPLES) +b = b / np.max(np.abs(b)) + +printSubTitle("MSE Reference") +ref = mse(a,b) +print(ref) + +printSubTitle("MSE f64") +resf64= dsp.arm_mse_f64(a,b) +print(resf64) +print(np.isclose(ref,resf64,1e-14,1e-14)) + +printSubTitle("MSE f32") +resf32 = dsp.arm_mse_f32(a,b) +print(resf32) +print(np.isclose(ref,resf32,1e-7,1e-7)) + +printSubTitle("MSE Q31") +aQ31 = f.toQ31(a) +bQ31 = f.toQ31(b) + +resQ31 = f.Q31toF32(dsp.arm_mse_q31(aQ31,bQ31)) +print(resQ31) +print(np.isclose(ref,resQ31,1e-7,1e-7)) + +aQ15 = f.toQ15(a) +bQ15 = f.toQ15(b) + +printSubTitle("MSE Q15") +resQ15 = dsp.arm_mse_q15(aQ15,bQ15) +print("%04X" % resQ15) +resQ15 = f.Q15toF32(resQ15) +print(resQ15) +print(np.isclose(ref,resQ15,1e-4,1e-4)) + +aQ7 = f.toQ7(a) +bQ7 = f.toQ7(b) + +printSubTitle("MSE Q7") +resQ7 = dsp.arm_mse_q7(aQ7,bQ7) +print("%04X" % resQ7) +resQ7 = f.Q7toF32(resQ7) +print(resQ7) +print(np.isclose(ref,resQ7,1e-2,1e-2)) + diff --git a/Source/FastMathFunctions/arm_atan2_f16.c b/Source/FastMathFunctions/arm_atan2_f16.c index 20313111..b4a03a4b 100755 --- a/Source/FastMathFunctions/arm_atan2_f16.c +++ b/Source/FastMathFunctions/arm_atan2_f16.c @@ -3,13 +3,13 @@ * Title: arm_atan2_f16.c * Description: float16 Arc tangent of y/x * - * $Date: 06 July 2021 + * $Date: 22 April 2022 * $Revision: V1.10.0 * * Target Processor: Cortex-M and Cortex-A cores * -------------------------------------------------------------------- */ /* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. + * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * diff --git a/Source/FastMathFunctions/arm_atan2_f32.c b/Source/FastMathFunctions/arm_atan2_f32.c index 862001df..3e398f78 100755 --- a/Source/FastMathFunctions/arm_atan2_f32.c +++ b/Source/FastMathFunctions/arm_atan2_f32.c @@ -3,13 +3,13 @@ * Title: arm_atan2_f32.c * Description: float32 Arc tangent of y/x * - * $Date: 06 July 2021 + * $Date: 22 April 2022 * $Revision: V1.10.0 * * Target Processor: Cortex-M and Cortex-A cores * -------------------------------------------------------------------- */ /* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. + * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * diff --git a/Source/FastMathFunctions/arm_atan2_q15.c b/Source/FastMathFunctions/arm_atan2_q15.c index f77cd6c7..ddf98d8c 100755 --- a/Source/FastMathFunctions/arm_atan2_q15.c +++ b/Source/FastMathFunctions/arm_atan2_q15.c @@ -3,13 +3,13 @@ * Title: arm_atan2_q15.c * Description: float32 Arc tangent of y/x * - * $Date: 06 July 2021 + * $Date: 22 April 2022 * $Revision: V1.10.0 * * Target Processor: Cortex-M and Cortex-A cores * -------------------------------------------------------------------- */ /* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. + * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -55,8 +55,6 @@ static const q15_t atan2_coefs_q15[ATAN2_NB_COEFS_Q15]={0x0000 ,0xfbdb }; -#include - __STATIC_FORCEINLINE q15_t arm_atan_limited_q15(q15_t x) { q31_t res=(q31_t)atan2_coefs_q15[ATAN2_NB_COEFS_Q15-1]; diff --git a/Source/FastMathFunctions/arm_atan2_q31.c b/Source/FastMathFunctions/arm_atan2_q31.c index 415c25c0..1c83e436 100755 --- a/Source/FastMathFunctions/arm_atan2_q31.c +++ b/Source/FastMathFunctions/arm_atan2_q31.c @@ -3,13 +3,13 @@ * Title: arm_atan2_q31.c * Description: float32 Arc tangent of y/x * - * $Date: 06 July 2021 + * $Date: 22 April 2022 * $Revision: V1.10.0 * * Target Processor: Cortex-M and Cortex-A cores * -------------------------------------------------------------------- */ /* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. + * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * diff --git a/cmsisdsp/__init__.py b/cmsisdsp/__init__.py index 05444fe8..252a0535 100755 --- a/cmsisdsp/__init__.py +++ b/cmsisdsp/__init__.py @@ -22,10 +22,11 @@ __version__ = cmsisdsp.version.__version__ cmsis_dsp_version="1.10.0" -# Commit hash used to build the wrapper -commit_hash="7106010d41b3bf810403e954c36c2643d98c58e7" +# CMSIS-DSP Commit hash used to build the wrapper +commit_hash="244e279d7989057d0eef417dfefa806062ec9afd" -# True if development version used +# True if development version of CMSIS-DSP used +# (So several CMSIS-DSP versions may have same version number hence the commit hash) developmentVersion=True __all__ = ["datatype", "fixedpoint", "mfcc"] \ No newline at end of file diff --git a/setup.py b/setup.py index 8d7cca84..043a24de 100644 --- a/setup.py +++ b/setup.py @@ -129,18 +129,18 @@ except: transformMod = transform + common + basic + complexf + fastmath + matrix + statistics statisticsMod = statistics + common + fastmath + basic interpolationMod = interpolation + common -filteringMod = filtering + common + support + fastmath +filteringMod = filtering + common + support + fastmath + basic controllerMod = controller + common matrixMod = matrix supportMod = support -complexfMod = complexf + fastmath + common +complexfMod = complexf + fastmath + common + basic basicMod = basic quaternionMod = quaternion -fastmathMod = fastmath + common +fastmathMod = basic + fastmath + common distanceMod = distance + common + basic + statistics + fastmath bayesMod = bayes + fastmath + common + statistics + basic -svmMod = svm + fastmath + common +svmMod = svm + fastmath + common + basic filteringMod.append(os.path.join("PythonWrapper","cmsisdsp_pkg","src","cmsisdsp_filtering.c"))