Official ARM version: v5.6.0
This commit is contained in:
parent
9f95ff5b6b
commit
96d6da4e25
2939 changed files with 339304 additions and 113320 deletions
220
DSP/PythonWrapper/README.md
Normal file
220
DSP/PythonWrapper/README.md
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
# README
|
||||
|
||||
This Python wrapper for CMSIS-DSP is compatible with numpy.
|
||||
|
||||
It is a very experimental wrapper with lots of limitations as described in the corresponding section below.
|
||||
|
||||
But even with those limitations, it can be very useful to test a CMSIS-DSP implemention of an algorithm with all the power of numpy and scipy.
|
||||
|
||||
# How to build and install
|
||||
|
||||
## Tested configurations
|
||||
|
||||
The building of this package has been tested on Windows with the Python install from python.org and Microsoft Visual 2017.
|
||||
|
||||
It has also been tested with cygwin. In that case, python-devel must be installed too. To run the examples, scipy and matplotlib must also be installed in cygwin.
|
||||
|
||||
On Linux, it worked with standard installation.
|
||||
|
||||
Other configurations should work but the setup.py file would have to be improved. It is a first version and the build process will have to be improved.
|
||||
|
||||
The package is working with Python 2 and 3.
|
||||
|
||||
## Building
|
||||
|
||||
The build is using a customized arm_math.h in folder cmsisdsp_pkg/src to be able to compile on windows.
|
||||
|
||||
As a consequence, if you build on an ARM computer, you won't get the optimizations of the CMSIS library. It is possible to get them by replacing the customized arm_math.h by the official one.
|
||||
|
||||
Since the CMSIS-DSP wrapper is using numpy, you must first install it if not already done. So, for instance to install it locally you could do:
|
||||
|
||||
> pip install numpy --user
|
||||
|
||||
Once numpy is installed, you can build the CMSIS-DSP python wrapper. Go to folder CMSIS/DSP/PythonWrapper.
|
||||
|
||||
Following command will build in place if you have the right compiler and if Python can find it.
|
||||
|
||||
> python setup.py build_ext --inplace
|
||||
|
||||
Then, if you launch Python from same directory you'll be able to play with the test scripts. You'll need to install a few additional Python packages to run the examples (scipy and matplotlib). See below.
|
||||
|
||||
If you want to install the cmsisdsp package, it is advised to install it into a virtualenv
|
||||
|
||||
With Python 3 you could:
|
||||
|
||||
Create a folder for this virtual environment. For instance : cmsisdsp_tests
|
||||
|
||||
Go to this folder.
|
||||
|
||||
Type:
|
||||
|
||||
> python -m venv env
|
||||
|
||||
Activate the environment:
|
||||
|
||||
> env\Scripts\activate
|
||||
|
||||
Install some packages to be able to run the examples
|
||||
|
||||
> pip install numpy
|
||||
> pip install scipy
|
||||
> pip install matplotlib
|
||||
|
||||
Now, you can install the cmsisdsp package in editable mode:
|
||||
|
||||
> pip install -e "Path To The Folder Containing setup.py"
|
||||
|
||||
Then you can copy the scripts testdsp.py and example.py and try to run them from this virtual environment. example.y is requiring a data file to be downloaded from the web. See below in this document for the link.
|
||||
|
||||
# Usage
|
||||
|
||||
You can look at testdsp.py and example.py for some examples.
|
||||
|
||||
The idea is to follow as closely as possible the CMSIS-DSP API to ease the migration to the final implementation on a board.
|
||||
|
||||
First you need to import the module
|
||||
|
||||
> import cmsisdsp as dsp
|
||||
|
||||
If you use numpy:
|
||||
|
||||
> import numpy as np
|
||||
|
||||
If you use scipy signal processing functions:
|
||||
|
||||
> from scipy import signal
|
||||
|
||||
## Functions with no instance arguments
|
||||
|
||||
You can use a CMSIS-DSP function with numpy arrays:
|
||||
|
||||
> r = dsp.arm_add_f32(np.array([1.,2,3]),np.array([4.,5,7]))
|
||||
|
||||
The function can also be called more simply with
|
||||
|
||||
> r = dsp.arm_add_f32([1.,2,3],[4.,5,7])
|
||||
|
||||
The result of a CMSIS-DSP function will always be a numpy array whatever the arguments were (numpy array or list).
|
||||
|
||||
## Functions with instance arguments
|
||||
|
||||
When the CMSIS-DSP function is requiring an instance data structure, it is just a bit more complex to use it:
|
||||
|
||||
First you need to create this instance:
|
||||
|
||||
> firf32 = dsp.arm_fir_instance_f32()
|
||||
|
||||
Although the initialization function on Python side can also be used to initialize some of the fields of the corresponding instance using named arguments, it is not advised to do so. In CMSIS-DSP there are initialization functions for this and they may do some additional processing.
|
||||
|
||||
So, you need to call an init function:
|
||||
|
||||
> dsp.arm_fir_init_f32(firf32,3,[1.,2,3],[0,0,0,0,0,0,0])
|
||||
|
||||
The third argument in this function is the state. Since all arguments (except the instance ones) are read-only in this Python API, this state will never be changed ! It is just used to communicate the length of the state array which must be allocated by the init function. This argument is required because it is present in the CMSIS-DSP API and in the final C implementation you'll need to allocate a state array with the right dimension.
|
||||
|
||||
Since the goal is to be as close as possible to the C API, the API is forcing the use of this argument.
|
||||
|
||||
The only change compared to the C API is that the size variables (like blockSize for filter) are computed automatically from the other arguments. This choice was made to make it a bit easier the use of numpy array with the API.
|
||||
|
||||
Now, you can check that the instance was initialized correctly.
|
||||
|
||||
> print(firf32.numTaps())
|
||||
|
||||
Then, you can filter with CMSIS-DSP.:
|
||||
|
||||
> print(dsp.arm_fir_f32(firf32,[1,2,3,4,5]))
|
||||
|
||||
The size of this signal should be blockSize. blockSize was inferred from the size of the state array : numTaps + blockSize - 1 according to CMSIS-DSP. So here the signal must have 5 samples.
|
||||
|
||||
If you want to filter more than 5 samples, then you can just call the function again. The state variable inside firf32 will ensure that it works like in the CMSIS-DSP C code.
|
||||
|
||||
> print(dsp.arm_fir_f32(firf32,[6,7,8,9,10]))
|
||||
|
||||
If you want to compare with scipy it is easy but warning : coefficients for the filter are in opposite order in scipy :
|
||||
|
||||
> filtered_x = signal.lfilter([3,2,1.], 1.0, [1,2,3,4,5,6,7,8,9,10])
|
||||
> print(filtered_x)
|
||||
|
||||
The principles are the same for all other APIs.
|
||||
|
||||
## FFT
|
||||
|
||||
For Fourier transforms there are no init functions in the CMSIS-DSP for the instance variables. They must be initialized from a C struct. To make it simpler to use them from Python, the wrapper is introducing its own init functions.
|
||||
|
||||
Here is an example for using FFT from the Python interface:
|
||||
|
||||
Let's define a signal you will use for the FFT.
|
||||
|
||||
> nb = 16
|
||||
> signal = np.cos(2 * np.pi * np.arange(nb) / nb)
|
||||
|
||||
The CMSIS-DSP cfft is requiring complex signals with a specific layout in memory.
|
||||
|
||||
To remain as close as possible to the C API, we are not using complex numbers in the wrapper. So a complex signal must be converted into a real one. The function imToReal1D is defined in testdsp.py
|
||||
|
||||
> signalR = imToReal1D(signal)
|
||||
|
||||
Then, you create the FFT instance with:
|
||||
|
||||
> cfftf32=dsp.arm_cfft_instance_f32()
|
||||
|
||||
You initialize the instance with the init function provided by the wrapper:
|
||||
|
||||
> status=dsp.arm_cfft_init_f32(cfftf32, nb)
|
||||
> print(status)
|
||||
|
||||
You compute the FFT of the signal with:
|
||||
|
||||
> resultR = dsp.arm_cfft_f32(cfftf32,signalR,0,1)
|
||||
|
||||
You convert back to a complex format to compare with scipy:
|
||||
|
||||
> resultI = realToIm1D(resultR)
|
||||
> print(resultI)
|
||||
|
||||
## Matrix
|
||||
|
||||
For matrix, the instance variables are masked by the Python API. We decided that for matrix only there was no use for having the CMSIS-DSP instance visibles since they contain the same information as the numpy array (samples and dimension).
|
||||
|
||||
So to use a CMSIS-DSP matrix function, it is very simple:
|
||||
|
||||
> a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]])
|
||||
> b=np.array([[1.,2,3],[5.1,6,7],[9.1,10,11],[5,8,4]])
|
||||
|
||||
Numpy result as reference:
|
||||
|
||||
> print(np.dot(a , b))
|
||||
|
||||
CMSIS-DSP result:
|
||||
|
||||
> v=dsp.arm_mat_mult_f32(a,b)
|
||||
> print(v)
|
||||
|
||||
In a real C code, a pointer to a data structure for the result v would have to be passed as argument of the function.
|
||||
|
||||
## example.py
|
||||
|
||||
This example depends on a data file which can be downloaded here:
|
||||
|
||||
https://www.physionet.org/pn3/ecgiddb/Person_87/rec_2.dat
|
||||
|
||||
This signal was created for a master thesis:
|
||||
|
||||
Lugovaya T.S. Biometric human identification based on electrocardiogram. [Master's thesis] Faculty of Computing Technologies and Informatics, Electrotechnical University "LETI", Saint-Petersburg, Russian Federation; June 2005.
|
||||
|
||||
and it is part of the PhysioNet database
|
||||
|
||||
Goldberger AL, Amaral LAN, Glass L, Hausdorff JM, Ivanov PCh, Mark RG, Mietus JE, Moody GB, Peng C-K, Stanley HE. PhysioBank, PhysioToolkit, and PhysioNet: Components of a New Research Resource for Complex Physiologic Signals. Circulation 101(23):e215-e220 [Circulation Electronic Pages; http://circ.ahajournals.org/cgi/content/full/101/23/e215]; 2000 (June 13).
|
||||
|
||||
|
||||
# LIMITATIONS
|
||||
|
||||
Due to the high number of functions in the CMSIS-DSP, the first version of the wrapper was generated automatically from a custom script.
|
||||
|
||||
Only a subset of the functions has been tested.
|
||||
|
||||
It is likely that some problems are present. The API is quite regular in CMSIS-DSP but there are a few exceptions and the generation script is not managing all of them.
|
||||
|
||||
So, the API may crash due to unallocated variables or wrong data conversions.
|
||||
|
||||
The generated C code is a first version for bootstrapping the process. Now that this C file exists, the improvements will be done on the C code rather than on the generation script.
|
||||
408
DSP/PythonWrapper/cmsisdsp_pkg/src/cmsismodule.c
Normal file
408
DSP/PythonWrapper/cmsisdsp_pkg/src/cmsismodule.c
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Python Wrapper
|
||||
* Title: cmsismodule.c
|
||||
* Description: C code for the CMSIS-DSP Python wrapper
|
||||
*
|
||||
* $Date: 25. March 2019
|
||||
* $Revision: V0.0.1
|
||||
*
|
||||
* Target Processor: Cortex-M cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2019 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.
|
||||
*/
|
||||
#define NPY_NO_DEPRECATED_API NPY_1_15_API_VERSION
|
||||
|
||||
#ifdef WIN
|
||||
#pragma warning( disable : 4013 )
|
||||
#pragma warning( disable : 4244 )
|
||||
#endif
|
||||
|
||||
#include <Python.h>
|
||||
#define MAX(A,B) (A) < (B) ? (B) : (A)
|
||||
|
||||
#define CAT1(A,B) A##B
|
||||
#define CAT(A,B) CAT1(A,B)
|
||||
|
||||
|
||||
#ifdef CMSISDSP
|
||||
#include "arm_math.h"
|
||||
#define MODNAME "cmsisdsp"
|
||||
#define MODINITNAME cmsisdsp
|
||||
#endif
|
||||
|
||||
#include <numpy/arrayobject.h>
|
||||
#include <numpy/ndarraytypes.h>
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define IS_PY3K
|
||||
#endif
|
||||
|
||||
struct module_state {
|
||||
PyObject *error;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
||||
#else
|
||||
#define GETSTATE(m) (&_state)
|
||||
static struct module_state _state;
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
error_out(PyObject *m) {
|
||||
struct module_state *st = GETSTATE(m);
|
||||
PyErr_SetString(st->error, "something bad happened");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MLTYPE(name,thenewfunc,deallocfunc,initfunc,methods)\
|
||||
static PyTypeObject ml_##name##Type = { \
|
||||
PyVarObject_HEAD_INIT(NULL, 0) \
|
||||
.tp_name=MODNAME".##name", \
|
||||
.tp_basicsize = sizeof(ml_##name##Object), \
|
||||
.tp_itemsize = 0, \
|
||||
.tp_dealloc = (destructor)deallocfunc, \
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT, \
|
||||
.tp_doc = #name, \
|
||||
.tp_init = (initproc)initfunc, \
|
||||
.tp_new = (newfunc)thenewfunc, \
|
||||
.tp_methods = methods \
|
||||
};
|
||||
|
||||
|
||||
#define MEMCPY(DST,SRC,NB,FORMAT) \
|
||||
for(memCpyIndex = 0; memCpyIndex < (NB) ; memCpyIndex++)\
|
||||
{ \
|
||||
(DST)[memCpyIndex] = (FORMAT)(SRC)[memCpyIndex]; \
|
||||
}
|
||||
|
||||
#define GETFIELD(NAME,FIELD,FORMAT) \
|
||||
static PyObject * \
|
||||
Method_##NAME##_##FIELD(ml_##NAME##Object *self, PyObject *ignored)\
|
||||
{ \
|
||||
return(Py_BuildValue(FORMAT,self->instance->FIELD)); \
|
||||
}
|
||||
|
||||
#define GETFIELDARRAY(NAME,FIELD,FORMAT) \
|
||||
static PyObject * \
|
||||
Method_##NAME##_##FIELD(ml_##NAME##Object *self, PyObject *ignored)\
|
||||
{ \
|
||||
return(specific_##NAME##_##FIELD(self->instance)); \
|
||||
}
|
||||
|
||||
#define INITARRAYFIELD(FIELD,FORMAT,SRCFORMAT,DSTFORMAT) \
|
||||
if (FIELD) \
|
||||
{ \
|
||||
PyArray_Descr *desct=PyArray_DescrFromType(FORMAT); \
|
||||
PyArrayObject *FIELD##c = (PyArrayObject *)PyArray_FromAny(FIELD,desct,\
|
||||
1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST, \
|
||||
NULL); \
|
||||
if (FIELD##c) \
|
||||
{ \
|
||||
uint32_t memCpyIndex; \
|
||||
SRCFORMAT *f=(SRCFORMAT*)PyArray_DATA(FIELD##c); \
|
||||
uint32_t n = PyArray_SIZE(FIELD##c); \
|
||||
self->instance->FIELD =PyMem_Malloc(sizeof(DSTFORMAT)*n); \
|
||||
MEMCPY(self->instance->FIELD ,f,n,DSTFORMAT); \
|
||||
Py_DECREF(FIELD##c); \
|
||||
} \
|
||||
}
|
||||
#define GETCARRAY(PYVAR,CVAR,FORMAT,SRCFORMAT,DSTFORMAT) \
|
||||
if (PYVAR) \
|
||||
{ \
|
||||
PyArray_Descr *desct=PyArray_DescrFromType(FORMAT); \
|
||||
PyArrayObject *PYVAR##c = (PyArrayObject *)PyArray_FromAny(PYVAR,desct,\
|
||||
1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST, \
|
||||
NULL); \
|
||||
if (PYVAR##c) \
|
||||
{ \
|
||||
uint32_t memCpyIndex; \
|
||||
SRCFORMAT *f=(SRCFORMAT*)PyArray_DATA(PYVAR##c); \
|
||||
uint32_t n = PyArray_SIZE(PYVAR##c); \
|
||||
CVAR =PyMem_Malloc(sizeof(DSTFORMAT)*n); \
|
||||
MEMCPY(CVAR ,f,n,DSTFORMAT); \
|
||||
Py_DECREF(PYVAR##c); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GETARGUMENT(FIELD,FORMAT,SRCFORMAT,DSTFORMAT) \
|
||||
uint32_t arraySize##FIELD=0; \
|
||||
if (FIELD) \
|
||||
{ \
|
||||
PyArray_Descr *desct=PyArray_DescrFromType(FORMAT); \
|
||||
PyArrayObject *FIELD##c = (PyArrayObject *)PyArray_FromAny(FIELD,desct, \
|
||||
1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST, \
|
||||
NULL); \
|
||||
if (FIELD##c) \
|
||||
{ \
|
||||
uint32_t memCpyIndex; \
|
||||
SRCFORMAT *f=(SRCFORMAT*)PyArray_DATA(FIELD##c); \
|
||||
arraySize##FIELD = PyArray_SIZE(FIELD##c); \
|
||||
FIELD##_converted =PyMem_Malloc(sizeof(DSTFORMAT)*arraySize##FIELD);\
|
||||
MEMCPY(FIELD##_converted ,f,arraySize##FIELD,DSTFORMAT); \
|
||||
Py_DECREF(FIELD##c); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FREEARGUMENT(FIELD) \
|
||||
PyMem_Free(FIELD)
|
||||
|
||||
#ifdef IS_PY3K
|
||||
#define ADDTYPE(name) \
|
||||
if (PyType_Ready(&ml_##name##Type) < 0) \
|
||||
return; \
|
||||
\
|
||||
Py_INCREF(&ml_##name##Type); \
|
||||
PyModule_AddObject(module, #name, (PyObject *)&ml_##name##Type);
|
||||
#else
|
||||
#define ADDTYPE(name) \
|
||||
if (PyType_Ready(&ml_##name##Type) < 0) \
|
||||
return; \
|
||||
\
|
||||
Py_INCREF(&ml_##name##Type); \
|
||||
PyModule_AddObject(module, #name, (PyObject *)&ml_##name##Type);
|
||||
#endif
|
||||
|
||||
#define FLOATARRAY2(OBJ,NB1,NB2,DATA) \
|
||||
npy_intp dims[2]; \
|
||||
dims[0]=NB1; \
|
||||
dims[1]=NB2; \
|
||||
const int ND=2; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NPY_FLOAT, DATA);
|
||||
|
||||
#define FLOATARRAY1(OBJ,NB1,DATA) \
|
||||
npy_intp dims[1]; \
|
||||
dims[0]=NB1; \
|
||||
const int ND=1; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NPY_FLOAT, DATA);
|
||||
|
||||
#define FLOAT64ARRAY1(OBJ,NB1,DATA) \
|
||||
npy_intp dims[1]; \
|
||||
dims[0]=NB1; \
|
||||
const int ND=1; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NPY_DOUBLE, DATA);
|
||||
|
||||
#define UINT32ARRAY1(OBJ,NB1,DATA) \
|
||||
npy_intp dims[1]; \
|
||||
dims[0]=NB1; \
|
||||
const int ND=1; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NPY_UINT32, DATA);
|
||||
|
||||
#define INT32ARRAY1(OBJ,NB1,DATA) \
|
||||
npy_intp dims[1]; \
|
||||
dims[0]=NB1; \
|
||||
const int ND=1; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NPY_INT32, DATA);
|
||||
|
||||
#define INT16ARRAY1(OBJ,NB1,DATA) \
|
||||
npy_intp dims[1]; \
|
||||
dims[0]=NB1; \
|
||||
const int ND=1; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NPY_INT16, DATA);
|
||||
|
||||
#define INT8ARRAY1(OBJ,NB1,DATA) \
|
||||
npy_intp dims[1]; \
|
||||
dims[0]=NB1; \
|
||||
const int ND=1; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NPY_BYTE, DATA);
|
||||
|
||||
|
||||
#define MATRIXFROMNUMPY(EXT,TYP,SRCTYPE,NUMPYTYPE) \
|
||||
arm_matrix_instance_##EXT *EXT##MatrixFromNumpy(PyObject *o) \
|
||||
{ \
|
||||
arm_matrix_instance_##EXT *s; \
|
||||
\
|
||||
s=PyMem_Malloc(sizeof(arm_matrix_instance_##EXT)); \
|
||||
s->pData=NULL; \
|
||||
s->numRows=0; \
|
||||
s->numCols=0; \
|
||||
\
|
||||
PyArray_Descr *desct=PyArray_DescrFromType(NUMPYTYPE); \
|
||||
PyArrayObject *cdata = (PyArrayObject *)PyArray_FromAny(o,desct, \
|
||||
1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST, \
|
||||
NULL); \
|
||||
if (cdata) \
|
||||
{ \
|
||||
uint32_t memCpyIndex; \
|
||||
SRCTYPE *f=(SRCTYPE*)PyArray_DATA(cdata); \
|
||||
s->numRows=PyArray_DIM(cdata,0); \
|
||||
s->numCols=PyArray_DIM(cdata,1); \
|
||||
uint32_t nb = PyArray_SIZE(cdata); \
|
||||
s->pData = PyMem_Malloc(sizeof(TYP)*nb); \
|
||||
MEMCPY(s->pData ,f,nb,TYP); \
|
||||
Py_DECREF(cdata); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
return(s); \
|
||||
\
|
||||
}
|
||||
|
||||
MATRIXFROMNUMPY(f32,float32_t,double,NPY_DOUBLE);
|
||||
MATRIXFROMNUMPY(f64,float64_t,double,NPY_DOUBLE);
|
||||
MATRIXFROMNUMPY(q31,q31_t,int32_t,NPY_INT32);
|
||||
MATRIXFROMNUMPY(q15,q15_t,int16_t,NPY_INT16);
|
||||
|
||||
#define CREATEMATRIX(EXT,TYP) \
|
||||
arm_matrix_instance_##EXT *create##EXT##Matrix(uint32_t r,uint32_t c)\
|
||||
{ \
|
||||
arm_matrix_instance_##EXT *s; \
|
||||
\
|
||||
s=PyMem_Malloc(sizeof(arm_matrix_instance_##EXT)); \
|
||||
s->pData=PyMem_Malloc(sizeof(TYP)*r*c); \
|
||||
s->numRows=r; \
|
||||
s->numCols=c; \
|
||||
return(s); \
|
||||
}
|
||||
|
||||
CREATEMATRIX(f32,float32_t);
|
||||
CREATEMATRIX(f64,float64_t);
|
||||
CREATEMATRIX(q31,q31_t);
|
||||
CREATEMATRIX(q15,q15_t);
|
||||
|
||||
#define NUMPYARRAYFROMMATRIX(EXT,NUMPYTYPE_FROMC) \
|
||||
PyObject *NumpyArrayFrom##EXT##Matrix(arm_matrix_instance_##EXT *mat) \
|
||||
{ \
|
||||
npy_intp dims[2]; \
|
||||
dims[0]=mat->numRows; \
|
||||
dims[1]=mat->numCols; \
|
||||
const int ND=2; \
|
||||
PyObject *OBJ=PyArray_SimpleNewFromData(ND, dims, NUMPYTYPE_FROMC, mat->pData);\
|
||||
return(OBJ); \
|
||||
}
|
||||
|
||||
NUMPYARRAYFROMMATRIX(f32,NPY_FLOAT);
|
||||
NUMPYARRAYFROMMATRIX(f64,NPY_DOUBLE);
|
||||
NUMPYARRAYFROMMATRIX(q31,NPY_INT32);
|
||||
NUMPYARRAYFROMMATRIX(q15,NPY_INT16);
|
||||
|
||||
//#include "specific.h"
|
||||
#include "cmsismodule.h"
|
||||
|
||||
#if 0
|
||||
static PyObject *cmsisml_test(PyObject *obj, PyObject *args)
|
||||
{
|
||||
ml_arm_svm_linear_instance_f32Object *self=NULL;
|
||||
PyObject *svm, *vector=NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OO", &svm,&vector))
|
||||
return NULL;
|
||||
|
||||
self=(ml_arm_svm_linear_instance_f32Object*)svm;
|
||||
if (self)
|
||||
{
|
||||
if (self->instance)
|
||||
{
|
||||
int result;
|
||||
float32_t *input=NULL;
|
||||
GETCARRAY(vector,input,NPY_DOUBLE,double,float32_t);
|
||||
|
||||
arm_svm_linear_predict_f32(self->instance,input,&result);
|
||||
/*
|
||||
printf("Dual\n");
|
||||
for(int i = 0 ; i < self->instance->nbOfSupportVectors ; i++)
|
||||
{
|
||||
printf("%f\n",self->instance->dualCoefficients[i]);
|
||||
}
|
||||
printf("Vectors\n");
|
||||
int k=0;
|
||||
for(int i = 0 ; i < self->instance->nbOfSupportVectors ; i++)
|
||||
{
|
||||
printf("Vector %d\n",i);
|
||||
for(int j = 0 ; j < self->instance->vectorDimension ; j++)
|
||||
{
|
||||
printf("%f\n",self->instance->supportVectors[k]);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
printf("Classes\n");
|
||||
for(int i = 0 ; i < 2 ; i++)
|
||||
{
|
||||
printf("%d\n",self->instance->classes[i]);
|
||||
}
|
||||
printf("Intercept %f\n",self->instance->intercept);
|
||||
*/
|
||||
PyMem_Free(input);
|
||||
return(Py_BuildValue("i",result));
|
||||
}
|
||||
}
|
||||
return(Py_BuildValue("i",-1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_PY3K
|
||||
static int cmsisml_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||
Py_VISIT(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmsisml_clear(PyObject *m) {
|
||||
Py_CLEAR(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
MODNAME,
|
||||
NULL,
|
||||
sizeof(struct module_state),
|
||||
CMSISMLMethods,
|
||||
NULL,
|
||||
cmsisml_traverse,
|
||||
cmsisml_clear,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
|
||||
PyMODINIT_FUNC
|
||||
CAT(PyInit_,MODINITNAME)(void)
|
||||
|
||||
|
||||
#else
|
||||
#define INITERROR return
|
||||
|
||||
void CAT(init,MODINITNAME)(void)
|
||||
#endif
|
||||
{
|
||||
import_array();
|
||||
|
||||
#ifdef IS_PY3K
|
||||
PyObject *module = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *module = Py_InitModule(MODNAME, CMSISMLMethods);
|
||||
#endif
|
||||
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
struct module_state *st = GETSTATE(module);
|
||||
|
||||
st->error = PyErr_NewException(MODNAME".Error", NULL, NULL);
|
||||
if (st->error == NULL) {
|
||||
Py_DECREF(module);
|
||||
INITERROR;
|
||||
}
|
||||
|
||||
|
||||
typeRegistration(module);
|
||||
|
||||
#ifdef IS_PY3K
|
||||
return module;
|
||||
#endif
|
||||
}
|
||||
15360
DSP/PythonWrapper/cmsisdsp_pkg/src/cmsismodule.h
Normal file
15360
DSP/PythonWrapper/cmsisdsp_pkg/src/cmsismodule.h
Normal file
File diff suppressed because it is too large
Load diff
262
DSP/PythonWrapper/cmsisdsp_pkg/src/fftinit.c
Normal file
262
DSP/PythonWrapper/cmsisdsp_pkg/src/fftinit.c
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Python Wrapper
|
||||
* Title: fftinit.c
|
||||
* Description: FFT init functions for the Python wrapper
|
||||
*
|
||||
* $Date: 25. March 2019
|
||||
* $Revision: V0.0.1
|
||||
*
|
||||
* Target Processor: Cortex-M cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2019 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_math.h"
|
||||
#include "arm_common_tables.h"
|
||||
#include "arm_const_structs.h"
|
||||
|
||||
#define FFTINIT(SIZE) \
|
||||
S->bitRevLength = arm_cfft_sR_f32_len##SIZE.bitRevLength; \
|
||||
S->pBitRevTable = arm_cfft_sR_f32_len##SIZE.pBitRevTable; \
|
||||
S->pTwiddle = arm_cfft_sR_f32_len##SIZE.pTwiddle;
|
||||
|
||||
#define FFTFXTINIT(EXT,SIZE) \
|
||||
S->bitRevLength = arm_cfft_sR_##EXT##_len##SIZE.bitRevLength; \
|
||||
S->pBitRevTable = arm_cfft_sR_##EXT##_len##SIZE.pBitRevTable; \
|
||||
S->pTwiddle = arm_cfft_sR_##EXT##_len##SIZE.pTwiddle;
|
||||
|
||||
arm_status arm_cfft_init_f32(
|
||||
arm_cfft_instance_f32 * S,
|
||||
uint16_t fftLen)
|
||||
{
|
||||
/* Initialise the default arm status */
|
||||
arm_status status = ARM_MATH_SUCCESS;
|
||||
|
||||
/* Initialise the FFT length */
|
||||
S->fftLen = fftLen;
|
||||
|
||||
/* Initialise the Twiddle coefficient pointer */
|
||||
S->pTwiddle = (float32_t *)twiddleCoef_4096;
|
||||
|
||||
|
||||
/* Initializations of Instance structure depending on the FFT length */
|
||||
switch (S->fftLen) {
|
||||
/* Initializations of structure parameters for 4096 point FFT */
|
||||
case 4096U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTINIT(4096);
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 2048 point FFT */
|
||||
case 2048U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTINIT(2048);
|
||||
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 1024 point FFT */
|
||||
case 1024U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTINIT(1024);
|
||||
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 512 point FFT */
|
||||
case 512U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTINIT(512);
|
||||
break;
|
||||
|
||||
case 256U:
|
||||
FFTINIT(256);
|
||||
break;
|
||||
|
||||
case 128U:
|
||||
FFTINIT(128);
|
||||
break;
|
||||
|
||||
case 64U:
|
||||
FFTINIT(64);
|
||||
break;
|
||||
|
||||
case 32U:
|
||||
FFTINIT(32);
|
||||
break;
|
||||
|
||||
case 16U:
|
||||
/* Initializations of structure parameters for 16 point FFT */
|
||||
FFTINIT(16);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* Reporting argument error if fftSize is not valid value */
|
||||
status = ARM_MATH_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
arm_status arm_cfft_init_q31(
|
||||
arm_cfft_instance_q31 * S,
|
||||
uint16_t fftLen)
|
||||
{
|
||||
/* Initialise the default arm status */
|
||||
arm_status status = ARM_MATH_SUCCESS;
|
||||
|
||||
/* Initialise the FFT length */
|
||||
S->fftLen = fftLen;
|
||||
|
||||
/* Initialise the Twiddle coefficient pointer */
|
||||
S->pTwiddle = (float32_t *)twiddleCoef_4096;
|
||||
|
||||
|
||||
/* Initializations of Instance structure depending on the FFT length */
|
||||
switch (S->fftLen) {
|
||||
/* Initializations of structure parameters for 4096 point FFT */
|
||||
case 4096U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q31,4096);
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 2048 point FFT */
|
||||
case 2048U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q31,2048);
|
||||
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 1024 point FFT */
|
||||
case 1024U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q31,1024);
|
||||
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 512 point FFT */
|
||||
case 512U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q31,512);
|
||||
break;
|
||||
|
||||
case 256U:
|
||||
FFTFXTINIT(q31,256);
|
||||
break;
|
||||
|
||||
case 128U:
|
||||
FFTFXTINIT(q31,128);
|
||||
break;
|
||||
|
||||
case 64U:
|
||||
FFTFXTINIT(q31,64);
|
||||
break;
|
||||
|
||||
case 32U:
|
||||
FFTFXTINIT(q31,32);
|
||||
break;
|
||||
|
||||
case 16U:
|
||||
/* Initializations of structure parameters for 16 point FFT */
|
||||
FFTFXTINIT(q31,16);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* Reporting argument error if fftSize is not valid value */
|
||||
status = ARM_MATH_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
arm_status arm_cfft_init_q15(
|
||||
arm_cfft_instance_q15 * S,
|
||||
uint16_t fftLen)
|
||||
{
|
||||
/* Initialise the default arm status */
|
||||
arm_status status = ARM_MATH_SUCCESS;
|
||||
|
||||
/* Initialise the FFT length */
|
||||
S->fftLen = fftLen;
|
||||
|
||||
/* Initialise the Twiddle coefficient pointer */
|
||||
S->pTwiddle = (float32_t *)twiddleCoef_4096;
|
||||
|
||||
|
||||
/* Initializations of Instance structure depending on the FFT length */
|
||||
switch (S->fftLen) {
|
||||
/* Initializations of structure parameters for 4096 point FFT */
|
||||
case 4096U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q15,4096);
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 2048 point FFT */
|
||||
case 2048U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q15,2048);
|
||||
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 1024 point FFT */
|
||||
case 1024U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q15,1024);
|
||||
|
||||
break;
|
||||
|
||||
/* Initializations of structure parameters for 512 point FFT */
|
||||
case 512U:
|
||||
/* Initialise the bit reversal table modifier */
|
||||
FFTFXTINIT(q15,512);
|
||||
break;
|
||||
|
||||
case 256U:
|
||||
FFTFXTINIT(q15,256);
|
||||
break;
|
||||
|
||||
case 128U:
|
||||
FFTFXTINIT(q15,128);
|
||||
break;
|
||||
|
||||
case 64U:
|
||||
FFTFXTINIT(q15,64);
|
||||
break;
|
||||
|
||||
case 32U:
|
||||
FFTFXTINIT(q15,32);
|
||||
break;
|
||||
|
||||
case 16U:
|
||||
/* Initializations of structure parameters for 16 point FFT */
|
||||
FFTFXTINIT(q15,16);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* Reporting argument error if fftSize is not valid value */
|
||||
status = ARM_MATH_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return (status);
|
||||
}
|
||||
12
DSP/PythonWrapper/config.py
Normal file
12
DSP/PythonWrapper/config.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
CMSISDSP = 1
|
||||
|
||||
ROOT=".."
|
||||
|
||||
config = CMSISDSP
|
||||
|
||||
if config == CMSISDSP:
|
||||
extensionName = 'cmsisdsp'
|
||||
setupName = 'CMSISDSP'
|
||||
setupDescription = 'CMSIS-DSP Python API'
|
||||
cflags="-DCMSISDSP"
|
||||
|
||||
79
DSP/PythonWrapper/example.py
Normal file
79
DSP/PythonWrapper/example.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import cmsisdsp as dsp
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
from pylab import figure, clf, plot, xlabel, ylabel, xlim, ylim, title, grid, axes, show,semilogx, semilogy
|
||||
# Data file from https://www.physionet.org/pn3/ecgiddb/Person_87/rec_2.dat
|
||||
|
||||
def q31sat(x):
|
||||
if x > 0x7FFFFFFF:
|
||||
return(np.int32(0x7FFFFFFF))
|
||||
elif x < -0x80000000:
|
||||
return(np.int32(0x80000000))
|
||||
else:
|
||||
return(np.int32(x))
|
||||
|
||||
q31satV=np.vectorize(q31sat)
|
||||
|
||||
def toQ31(x):
|
||||
return(q31satV(np.round(x * (1<<31))))
|
||||
|
||||
def Q31toF32(x):
|
||||
return(1.0*x / 2**31)
|
||||
|
||||
filename = 'rec_2.dat'
|
||||
|
||||
f = open(filename,"r")
|
||||
sig = np.fromfile(f, dtype=np.int16)
|
||||
f.closed
|
||||
|
||||
sig = 1.0*sig / (1 << 12)
|
||||
|
||||
|
||||
p0 = np.exp(1j*0.05) * 0.98
|
||||
p1 = np.exp(1j*0.25) * 0.9
|
||||
p2 = np.exp(1j*0.45) * 0.97
|
||||
|
||||
z0 = np.exp(1j*0.02)
|
||||
z1 = np.exp(1j*0.65)
|
||||
z2 = np.exp(1j*1.0)
|
||||
|
||||
g = 0.02
|
||||
|
||||
nb = 300
|
||||
|
||||
sos = signal.zpk2sos(
|
||||
[z0,np.conj(z0),z1,np.conj(z1),z2,np.conj(z2)]
|
||||
,[p0, np.conj(p0),p1, np.conj(p1),p2, np.conj(p2)]
|
||||
,g)
|
||||
|
||||
res=signal.sosfilt(sos,sig)
|
||||
figure()
|
||||
plot(sig[1:nb])
|
||||
figure()
|
||||
plot(res[1:nb])
|
||||
|
||||
|
||||
|
||||
|
||||
biquadQ31 = dsp.arm_biquad_casd_df1_inst_q31()
|
||||
numStages=3
|
||||
state=np.zeros(numStages*4)
|
||||
# For use in CMSIS, denominator coefs must be negated
|
||||
# and first a0 coef wihich is always 1 must be removed
|
||||
coefs=np.reshape(np.hstack((sos[:,:3],-sos[:,4:])),15)
|
||||
coefs = coefs / 4.0
|
||||
coefsQ31 = toQ31(coefs)
|
||||
postshift = 2
|
||||
dsp.arm_biquad_cascade_df1_init_q31(biquadQ31,numStages,coefsQ31,state,postshift)
|
||||
sigQ31=toQ31(sig)
|
||||
nbSamples=sigQ31.shape[0]
|
||||
# Here we demonstrate how we can process a long sequence of samples per block
|
||||
# and thus check that the state of the biquad is well updated and preserved
|
||||
# between the calls.
|
||||
half = int(round(nbSamples / 2))
|
||||
res2a=dsp.arm_biquad_cascade_df1_q31(biquadQ31,sigQ31[1:half])
|
||||
res2b=dsp.arm_biquad_cascade_df1_q31(biquadQ31,sigQ31[half+1:nbSamples])
|
||||
res2=Q31toF32(np.hstack((res2a,res2b)))
|
||||
figure()
|
||||
plot(res2[1:nb])
|
||||
show()#
|
||||
85
DSP/PythonWrapper/setup.py
Normal file
85
DSP/PythonWrapper/setup.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
from distutils.core import setup, Extension
|
||||
import glob
|
||||
import numpy
|
||||
import config
|
||||
import sys
|
||||
import os
|
||||
from config import ROOT
|
||||
|
||||
includes = [os.path.join(ROOT,"Include"),os.path.join("cmsisdsp_pkg","src")]
|
||||
|
||||
if sys.platform == 'win32':
|
||||
cflags = ["-DWIN",config.cflags,"-DUNALIGNED_SUPPORT_DISABLE"]
|
||||
# Custom because a customized arm_math.h is required to build on windows
|
||||
# since the visual compiler and the win platform are
|
||||
# not supported by default in arm_math.h
|
||||
else:
|
||||
cflags = ["-Wno-unused-variable","-Wno-implicit-function-declaration",config.cflags]
|
||||
|
||||
transform = glob.glob(os.path.join(ROOT,"Source","TransformFunctions","*.c"))
|
||||
#transform.remove(os.path.join(ROOT,"Source","TransformFunctions","arm_dct4_init_q15.c"))
|
||||
#transform.remove(os.path.join(ROOT,"Source","TransformFunctions","arm_rfft_init_q15.c"))
|
||||
transform.remove(os.path.join(ROOT,"Source","TransformFunctions","TransformFunctions.c"))
|
||||
|
||||
support = glob.glob(os.path.join(ROOT,"Source","SupportFunctions","*.c"))
|
||||
support.remove(os.path.join(ROOT,"Source","SupportFunctions","SupportFunctions.c"))
|
||||
|
||||
fastmath = glob.glob(os.path.join(ROOT,"Source","FastMathFunctions","*.c"))
|
||||
fastmath.remove(os.path.join(ROOT,"Source","FastMathFunctions","FastMathFunctions.c"))
|
||||
|
||||
filtering = glob.glob(os.path.join(ROOT,"Source","FilteringFunctions","*.c"))
|
||||
filtering.remove(os.path.join(ROOT,"Source","FilteringFunctions","FilteringFunctions.c"))
|
||||
|
||||
matrix = glob.glob(os.path.join(ROOT,"Source","MatrixFunctions","*.c"))
|
||||
matrix.remove(os.path.join(ROOT,"Source","MatrixFunctions","MatrixFunctions.c"))
|
||||
|
||||
statistics = glob.glob(os.path.join(ROOT,"Source","StatisticsFunctions","*.c"))
|
||||
statistics.remove(os.path.join(ROOT,"Source","StatisticsFunctions","StatisticsFunctions.c"))
|
||||
|
||||
complexf = glob.glob(os.path.join(ROOT,"Source","ComplexMathFunctions","*.c"))
|
||||
complexf.remove(os.path.join(ROOT,"Source","ComplexMathFunctions","ComplexMathFunctions.c"))
|
||||
|
||||
basic = glob.glob(os.path.join(ROOT,"Source","BasicMathFunctions","*.c"))
|
||||
basic.remove(os.path.join(ROOT,"Source","BasicMathFunctions","BasicMathFunctions.c"))
|
||||
|
||||
controller = glob.glob(os.path.join(ROOT,"Source","ControllerFunctions","*.c"))
|
||||
controller.remove(os.path.join(ROOT,"Source","ControllerFunctions","ControllerFunctions.c"))
|
||||
|
||||
common = glob.glob(os.path.join(ROOT,"Source","CommonTables","*.c"))
|
||||
common.remove(os.path.join(ROOT,"Source","CommonTables","CommonTables.c"))
|
||||
|
||||
#modulesrc = glob.glob(os.path.join("cmsisdsp_pkg","src","*.c"))
|
||||
modulesrc = []
|
||||
modulesrc.append(os.path.join("cmsisdsp_pkg","src","fftinit.c"))
|
||||
modulesrc.append(os.path.join("cmsisdsp_pkg","src","cmsismodule.c"))
|
||||
|
||||
module1 = Extension(config.extensionName,
|
||||
sources = (support
|
||||
+ fastmath
|
||||
+ filtering
|
||||
+ matrix
|
||||
+ statistics
|
||||
+ complexf
|
||||
+ basic
|
||||
+ controller
|
||||
+ transform
|
||||
+ modulesrc
|
||||
+ common
|
||||
)
|
||||
,
|
||||
include_dirs = includes + [numpy.get_include()],
|
||||
#extra_compile_args = ["-Wno-unused-variable","-Wno-implicit-function-declaration",config.cflags]
|
||||
extra_compile_args = cflags
|
||||
)
|
||||
|
||||
setup (name = config.setupName,
|
||||
version = '0.0.1',
|
||||
description = config.setupDescription,
|
||||
ext_modules = [module1],
|
||||
author = 'Copyright (C) 2010-2019 ARM Limited or its affiliates. All rights reserved.',
|
||||
url="https://github.com/ARM-software/CMSIS_5",
|
||||
classifiers=[
|
||||
"Programming Language :: Python",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Operating System :: OS Independent",
|
||||
])
|
||||
363
DSP/PythonWrapper/testdsp.py
Normal file
363
DSP/PythonWrapper/testdsp.py
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
import cmsisdsp as dsp
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
#import matplotlib.pyplot as plt
|
||||
#from scipy.fftpack import dct
|
||||
|
||||
#r = dsp.arm_add_f32(np.array([1.,2,3]),np.array([4.,5,7]))
|
||||
#print(r)
|
||||
|
||||
#r = dsp.arm_add_q31([1,2,3],[4,5,7])
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_add_q15([1,2,3],[4,5,7])
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_add_q7([-1,2,3],[4,127,7])
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_scale_f32([1.,2,3],2)
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_scale_q31([0x7FFF,0x3FFF,0x1FFF],1 << 20,2)
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_scale_q15([0x7FFF,0x3FFF,0x1FFF],1 << 10,2)
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_scale_q7([0x7F,0x3F,0x1F],1 << 5,2)
|
||||
#print(r)
|
||||
#
|
||||
#
|
||||
#r = dsp.arm_negate_f32([1.,2,3])
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_negate_q31([1,2,3])
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_negate_q15([1,2,3])
|
||||
#print(r)
|
||||
#
|
||||
#r = dsp.arm_negate_q7(np.array([0x80,0x81,0x82]))
|
||||
#print(r)
|
||||
|
||||
#r = dsp.arm_cmplx_conj_f32([1.,2,3,4])
|
||||
#print(r)
|
||||
|
||||
#r = dsp.arm_cmplx_conj_q31([1,2,3,4])
|
||||
#print(r)
|
||||
|
||||
#r = dsp.arm_cmplx_conj_q15([1,2,3,4])
|
||||
#print(r)
|
||||
|
||||
#r = dsp.arm_cmplx_dot_prod_f32([1.,2,3,4],[1.,2,3,4])
|
||||
#print(r)
|
||||
|
||||
#r = dsp.arm_cmplx_dot_prod_q31([0x1FFF,0x3FFF,0x1FFF,0x3FFF],[0x1FFF,0x3FFF,0x1FFF,0x3FFF])
|
||||
#print(r)
|
||||
|
||||
#r = dsp.arm_cmplx_mult_real_f32([1.0,2,3,4],[5.,5.,5.,5.])
|
||||
#print(r)
|
||||
|
||||
#pidf32 = dsp.arm_pid_instance_f32(Kp=1.0,Ki=1.2,Kd=0.4)
|
||||
#print(pidf32.Kp())
|
||||
#print(pidf32.Ki())
|
||||
#print(pidf32.Kd())
|
||||
#print(pidf32.A0())
|
||||
#
|
||||
#dsp.arm_pid_init_f32(pidf32,0)
|
||||
#print(pidf32.A0())
|
||||
|
||||
#print(dsp.arm_cos_f32(3.14/4.))
|
||||
|
||||
#print(dsp.arm_sqrt_q31(0x7FFF))
|
||||
|
||||
firf32 = dsp.arm_fir_instance_f32()
|
||||
dsp.arm_fir_init_f32(firf32,3,[1.,2,3],[0,0,0,0,0,0,0])
|
||||
print(firf32.numTaps())
|
||||
filtered_x = signal.lfilter([3,2,1.], 1.0, [1,2,3,4,5,1,2,3,4,5])
|
||||
print(filtered_x)
|
||||
print(dsp.arm_fir_f32(firf32,[1,2,3,4,5]))
|
||||
print(dsp.arm_fir_f32(firf32,[1,2,3,4,5]))
|
||||
|
||||
def q31sat(x):
|
||||
if x > 0x7FFFFFFF:
|
||||
return(np.int32(0x7FFFFFFF))
|
||||
elif x < -0x80000000:
|
||||
return(np.int32(0x80000000))
|
||||
else:
|
||||
return(np.int32(x))
|
||||
|
||||
q31satV=np.vectorize(q31sat)
|
||||
|
||||
def toQ31(x):
|
||||
return(q31satV(np.round(x * (1<<31))))
|
||||
|
||||
def q15sat(x):
|
||||
if x > 0x7FFF:
|
||||
return(np.int16(0x7FFF))
|
||||
elif x < -0x8000:
|
||||
return(np.int16(0x8000))
|
||||
else:
|
||||
return(np.int16(x))
|
||||
|
||||
q15satV=np.vectorize(q15sat)
|
||||
|
||||
def toQ15(x):
|
||||
return(q15satV(np.round(x * (1<<15))))
|
||||
|
||||
def q7sat(x):
|
||||
if x > 0x7F:
|
||||
return(np.int8(0x7F))
|
||||
elif x < -0x80:
|
||||
return(np.int8(0x80))
|
||||
else:
|
||||
return(np.int8(x))
|
||||
|
||||
q7satV=np.vectorize(q7sat)
|
||||
|
||||
def toQ7(x):
|
||||
return(q7satV(np.round(x * (1<<7))))
|
||||
|
||||
def Q31toF32(x):
|
||||
return(1.0*x / 2**31)
|
||||
|
||||
def Q15toF32(x):
|
||||
return(1.0*x / 2**15)
|
||||
|
||||
def Q7toF32(x):
|
||||
return(1.0*x / 2**7)
|
||||
|
||||
#firq31 = dsp.arm_fir_instance_q31()
|
||||
#x=np.array([1,2,3,4,5])/10.0
|
||||
#taps=np.array([1,2,3])/10.0
|
||||
#xQ31=toQ31(x)
|
||||
#tapsQ31=toQ31(taps)
|
||||
#dsp.arm_fir_init_q31(firq31,3,tapsQ31,[0,0,0,0,0,0,0])
|
||||
#print(firq31.numTaps())
|
||||
#resultQ31=dsp.arm_fir_q31(firq31,xQ31)
|
||||
#result=Q31toF32(resultQ31)
|
||||
#print(result)
|
||||
|
||||
#a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]])
|
||||
#b=np.array([[1.,2,3,4],[5.1,6,7,8],[9.1,10,11,12]])
|
||||
#print(a+b)
|
||||
#v=dsp.arm_mat_add_f32(a,b)
|
||||
#print(v)
|
||||
|
||||
#a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]])
|
||||
#b=np.array([[1.,2,3],[5.1,6,7],[9.1,10,11],[5,8,4]])
|
||||
#print(np.dot(a , b))
|
||||
#v=dsp.arm_mat_mult_f32(a,b)
|
||||
#print(v)
|
||||
|
||||
def imToReal2D(a):
|
||||
ar=np.zeros(np.array(a.shape) * [1,2])
|
||||
ar[::,0::2]=a.real
|
||||
ar[::,1::2]=a.imag
|
||||
return(ar)
|
||||
|
||||
def realToIm2D(ar):
|
||||
return(ar[::,0::2] + 1j * ar[::,1::2])
|
||||
|
||||
#a=np.array([[1. + 2j,3 + 4j],[5 + 6j,7 + 8j],[9 + 10j,11 + 12j]])
|
||||
#b=np.array([[1. + 2j, 3 + 5.1j ,6 + 7j],[9.1 + 10j,11 + 5j,8 +4j]])
|
||||
#print(np.dot(a , b))
|
||||
#
|
||||
# Convert complex array to real array for use in CMSIS DSP
|
||||
#ar = imToReal2D(a)
|
||||
#br = imToReal2D(b)
|
||||
#
|
||||
#v=dsp.arm_mat_cmplx_mult_f32(ar,br)
|
||||
#print(v)
|
||||
|
||||
#a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]]) / 30.0
|
||||
#b=np.array([[1.,2,3,4],[5.1,6,7,8],[9.1,10,11,12]]) / 30.0
|
||||
#print(a+b)
|
||||
#
|
||||
#aQ31=toQ31(a)
|
||||
#bQ31=toQ31(b)
|
||||
#v=dsp.arm_mat_add_q31(aQ31,bQ31)
|
||||
#rQ31=v[1]
|
||||
#r=Q31toF32(rQ31)
|
||||
#print(r)#
|
||||
|
||||
#a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]])
|
||||
#print(np.transpose(a))
|
||||
#print(dsp.arm_mat_trans_f32(a))
|
||||
|
||||
#a = np.array([[1., 2.], [3., 4.]])
|
||||
#print(np.linalg.inv(a))
|
||||
#print(dsp.arm_mat_inverse_f32(a))
|
||||
|
||||
#a = np.array([[1., 2.], [3., 4.]])
|
||||
#print(np.linalg.inv(a))
|
||||
#print(dsp.arm_mat_inverse_f64(a))
|
||||
|
||||
#a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]])
|
||||
#print(2.5*a)
|
||||
#print(dsp.arm_mat_scale_f32(a,2.5))
|
||||
|
||||
#a=np.array([1.,2,3,4,5,6,7,8,9,10,11,12])
|
||||
#print(np.max(a))
|
||||
#print(np.argmax(a))
|
||||
#print(dsp.arm_max_f32(a))
|
||||
#
|
||||
#print(np.mean(a))
|
||||
#print(dsp.arm_mean_f32(a))
|
||||
#
|
||||
#print(np.dot(a,a))
|
||||
#print(dsp.arm_power_f32(a))
|
||||
#
|
||||
|
||||
def imToReal1D(a):
|
||||
ar=np.zeros(np.array(a.shape) * 2)
|
||||
ar[0::2]=a.real
|
||||
ar[1::2]=a.imag
|
||||
return(ar)
|
||||
|
||||
def realToIm1D(ar):
|
||||
return(ar[0::2] + 1j * ar[1::2])
|
||||
|
||||
#nb = 16
|
||||
#signal = np.cos(2 * np.pi * np.arange(nb) / nb)
|
||||
|
||||
#result=np.fft.fft(signal)
|
||||
#print(result)
|
||||
#signalR = imToReal1D(signal)
|
||||
#cfftf32=dsp.arm_cfft_instance_f32()
|
||||
#status=dsp.arm_cfft_init_f32(cfftf32,nb)
|
||||
#print(status)
|
||||
#resultR = dsp.arm_cfft_f32(cfftf32,signalR,0,1)
|
||||
#resultI = realToIm1D(resultR)
|
||||
#print(resultI)
|
||||
|
||||
#signal = signal / 10.0
|
||||
#result=np.fft.fft(signal)
|
||||
#print(result)
|
||||
#
|
||||
#signalR = imToReal1D(signal)
|
||||
#signalRQ31=toQ31(signalR)
|
||||
#cfftq31=dsp.arm_cfft_instance_q31()
|
||||
#status=dsp.arm_cfft_init_q31(cfftq31,nb)
|
||||
#print(status)
|
||||
#resultR = dsp.arm_cfft_q31(cfftq31,signalRQ31,0,1)
|
||||
#resultI = realToIm1D(Q31toF32(resultR))*16
|
||||
#print(resultI)
|
||||
|
||||
#signal = signal / 10.0
|
||||
#result=np.fft.fft(signal)
|
||||
#print(result)
|
||||
##
|
||||
#signalR = imToReal1D(signal)
|
||||
#signalRQ15=toQ15(signalR)
|
||||
#cfftq15=dsp.arm_cfft_instance_q15()
|
||||
#status=dsp.arm_cfft_init_q15(cfftq15,nb)
|
||||
#print(status)
|
||||
#resultR = dsp.arm_cfft_q15(cfftq15,signalRQ15,0,1)
|
||||
#resultR=Q15toF32(resultR)
|
||||
#resultI = realToIm1D(resultR)*16
|
||||
#print(resultI)
|
||||
|
||||
#nb = 128
|
||||
#signal = np.cos(2 * np.pi * np.arange(nb) / nb)
|
||||
#
|
||||
#result=np.fft.fft(signal)
|
||||
##print(result)
|
||||
#cfftradix4f32=dsp.arm_cfft_radix4_instance_f32()
|
||||
#rfftf32=dsp.arm_rfft_instance_f32()
|
||||
#status=dsp.arm_rfft_init_f32(rfftf32,cfftradix4f32,nb,0,1)
|
||||
#print(status)
|
||||
#resultI = dsp.arm_rfft_f32(rfftf32,signal)
|
||||
#print(result)
|
||||
|
||||
#nb = 128
|
||||
#signal = np.cos(2 * np.pi * np.arange(nb) / nb)
|
||||
#signalRQ31=toQ31(signal)
|
||||
#
|
||||
#result=np.fft.fft(signal)
|
||||
##print(result)
|
||||
#rfftq31=dsp.arm_rfft_instance_q31()
|
||||
#status=dsp.arm_rfft_init_q31(rfftq31,nb,0,1)
|
||||
#print(status)
|
||||
#resultI = dsp.arm_rfft_q31(rfftq31,signalRQ31)
|
||||
#resultI=Q31toF32(resultI)*(1 << 7)
|
||||
##print(result)
|
||||
|
||||
#nb = 128
|
||||
#signal = np.cos(2 * np.pi * np.arange(nb) / nb)
|
||||
#signalRQ15=toQ15(signal)
|
||||
#
|
||||
#result=np.fft.fft(signal)
|
||||
##print(result)
|
||||
#rfftq15=dsp.arm_rfft_instance_q15()
|
||||
#status=dsp.arm_rfft_init_q15(rfftq15,nb,0,1)
|
||||
#print(status)
|
||||
#resultI = dsp.arm_rfft_q15(rfftq15,signalRQ15)
|
||||
#resultI=Q15toF32(resultI)*(1 << 7)
|
||||
#print(result)
|
||||
|
||||
|
||||
#nb = 128
|
||||
#nb2=64
|
||||
#signal = np.cos(2 * np.pi * np.arange(nb) / nb)
|
||||
#result=dct(signal,4,norm='ortho')
|
||||
##print(result)
|
||||
|
||||
#cfftradix4f32=dsp.arm_cfft_radix4_instance_f32()
|
||||
#rfftf32=dsp.arm_rfft_instance_f32()
|
||||
#dct4f32=dsp.arm_dct4_instance_f32()
|
||||
#status=dsp.arm_dct4_init_f32(dct4f32,rfftf32,cfftradix4f32,nb,nb2,0.125)
|
||||
#print(status)
|
||||
#state=np.zeros(2*nb)
|
||||
#resultI = dsp.arm_dct4_f32(dct4f32,state,signal)
|
||||
##print(resultI)
|
||||
|
||||
|
||||
#signal = signal / 10.0
|
||||
#result=dct(signal,4,norm='ortho')
|
||||
#signalQ31=toQ31(signal)
|
||||
#cfftradix4q31=dsp.arm_cfft_radix4_instance_q31()
|
||||
#rfftq31=dsp.arm_rfft_instance_q31()
|
||||
#dct4q31=dsp.arm_dct4_instance_q31()
|
||||
#status=dsp.arm_dct4_init_q31(dct4q31,rfftq31,cfftradix4q31,nb,nb2,0x10000000)
|
||||
#print(status)
|
||||
#state=np.zeros(2*nb)
|
||||
#resultI = dsp.arm_dct4_q31(dct4q31,state,signalQ31)
|
||||
#resultI=Q31toF32(resultI)*(1 << 7)
|
||||
|
||||
#nb = 128
|
||||
#nb2=64
|
||||
#signal = np.cos(2 * np.pi * np.arange(nb) / nb)
|
||||
#signal = signal / 10.0
|
||||
#result=dct(signal,4,norm='ortho')
|
||||
#signalQ15=toQ15(signal)
|
||||
#cfftradix4q15=dsp.arm_cfft_radix4_instance_q15()
|
||||
#rfftq15=dsp.arm_rfft_instance_q15()
|
||||
#dct4q15=dsp.arm_dct4_instance_q15()
|
||||
#status=dsp.arm_dct4_init_q15(dct4q15,rfftq15,cfftradix4q15,nb,nb2,0x1000)
|
||||
#print(status)
|
||||
#state=np.zeros(2*nb)
|
||||
#resultI = dsp.arm_dct4_q15(dct4q15,state,signalQ15)
|
||||
#resultI=Q15toF32(resultI)*(1 << 7)
|
||||
#
|
||||
#
|
||||
#from pylab import figure, clf, plot, xlabel, ylabel, xlim, ylim, title, grid, axes, show
|
||||
#figure(1)
|
||||
#plot(np.absolute(signal))
|
||||
#t = np.arange(nb)
|
||||
#freq = np.fft.fftfreq(t.shape[-1])
|
||||
#resultmag=np.absolute(result)
|
||||
#figure(2)
|
||||
#plot(resultmag)
|
||||
#figure(3)
|
||||
#cmsigmag=np.absolute(resultI)
|
||||
#plot(cmsigmag)
|
||||
#show()##
|
||||
|
||||
#biquadf32 = dsp.arm_biquad_casd_df1_inst_f32()
|
||||
#numStages=1
|
||||
#state=np.zeros(numStages*4)
|
||||
#coefs=[1.,2,3,4,5]
|
||||
#dsp.arm_biquad_cascade_df1_init_f32(biquadf32,1,coefs,state)
|
||||
#print(dsp.arm_biquad_cascade_df1_f32(biquadf32,[1,2,3,4,5]))#
|
||||
Loading…
Add table
Add a link
Reference in a new issue