Improvement to the Python wrapper

Corrected issues with arm_fir_decimate and arm_fir_interpolate
Corrected issues with real FFTs in the wrapper
Added a customization option for the FIFO class in compute graph.
Added Python tests for the corrected functions.
pull/67/head
Christophe Favergeon 3 years ago
parent 0705c67568
commit 3d1a7f7ff4

@ -319,7 +319,17 @@ Horizontal or vertical layout for the graph.
By default, the graph is displaying the FIFO sizes. If you want to know with FIFO variable is used in the code, you can set this option to true and the graph will display the FIFO variable names.
### Options for connections
It is now possible to write something like:
```python
g.connect(src.o,b.i,fifoClass="FIFOSource")
```
The `fifoClass` argument allows to choose a specific FIFO class in the generated C++ or Python.
Only the `FIFO` class is provided by default. Any new implementation must inherit from `FIFObase<T>`
## How to build the examples

@ -109,7 +109,7 @@ toMono [label=<
</TABLE>>];
srcDelay [label=<
srctoMonoDelay [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">10</TD>
@ -117,10 +117,10 @@ srcDelay [label=<
</TABLE>>];
src:i -> srcDelay:i [label="",taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >320</FONT>
src:i -> srctoMonoDelay:i [label="",taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >320</FONT>
</TD></TR></TABLE>>]
srcDelay:i -> toMono:i [label="f32(330)"
srctoMonoDelay:i -> toMono:i [label="f32(330)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >320</FONT>
</TD></TR></TABLE>>]

@ -18,7 +18,7 @@ src=WavSource("src",NBCHANNELS*AUDIO_INTERRUPT_LENGTH)
src.addLiteralArg(True)
src.addLiteralArg("test_stereo.wav")
toMono=StereoToMono("toMono",q15Type,AUDIO_INTERRUPT_LENGTH)
toMono=InterleavedStereoToMono("toMono",q15Type,AUDIO_INTERRUPT_LENGTH)
slidingAudio=SlidingBuffer("audioWin",q15Type,FFTSize,AudioOverlap)
slidingMFCC=SlidingBuffer("mfccWin",q15Type,numOfDctOutputs*nbMFCCOutputs,numOfDctOutputs*nbMFCCOutputs>>1)

@ -74,7 +74,7 @@ def scheduler(mfccConfig,dispbuf):
mfccWin = SlidingBuffer(754,377,fifo3,fifo4)
sink = NumpySink(754,fifo4,dispbuf)
src = WavSource(384,fifo0,True,"test_stereo.wav")
toMono = StereoToMono(384,192,fifo0,fifo1)
toMono = InterleavedStereoToMono(384,192,fifo0,fifo1)
while((cgStaticError==0) and (debugCounter > 0)):
nbSchedule = nbSchedule + 1

@ -47,7 +47,7 @@ src [label=<
toMono [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">toMono<BR/>(StereoToMono)</TD>
<TD ALIGN="CENTER" PORT="i">toMono<BR/>(InterleavedStereoToMono)</TD>
</TR>
</TABLE>>];

@ -60,7 +60,7 @@ dup0 -> sink:i [label="f32(5)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>
]
dup0Delay [label=<
dup0filterDelay [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">5</TD>
@ -69,9 +69,9 @@ dup0Delay [label=<
dup0 -> dup0Delay:i [label=""]
dup0 -> dup0filterDelay:i [label=""]
dup0Delay:i -> filter:ib [label="f32(5)"
dup0filterDelay:i -> filter:ib [label="f32(5)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>]

@ -4711,6 +4711,7 @@ cmsis_arm_fir_decimate_f32(PyObject *obj, PyObject *args)
float32_t *pSrc_converted=NULL; // input
float32_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
@ -4718,12 +4719,13 @@ cmsis_arm_fir_decimate_f32(PyObject *obj, PyObject *args)
dsp_arm_fir_decimate_instance_f32Object *selfS = (dsp_arm_fir_decimate_instance_f32Object *)S;
GETARGUMENT(pSrc,NPY_DOUBLE,double,float32_t);
blockSize = arraySizepSrc ;
outBlockSize = arraySizepSrc / selfS->instance->M;
pDst=PyMem_Malloc(sizeof(float32_t)*blockSize);
pDst=PyMem_Malloc(sizeof(float32_t)*outBlockSize);
arm_fir_decimate_f32(selfS->instance,pSrc_converted,pDst,blockSize);
FLOATARRAY1(pDstOBJ,blockSize,pDst);
FLOATARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -4779,19 +4781,21 @@ cmsis_arm_fir_decimate_q15(PyObject *obj, PyObject *args)
q15_t *pSrc_converted=NULL; // input
q15_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
dsp_arm_fir_decimate_instance_q15Object *selfS = (dsp_arm_fir_decimate_instance_q15Object *)S;
GETARGUMENT(pSrc,NPY_INT16,int16_t,int16_t);
blockSize = arraySizepSrc ;
blockSize = arraySizepSrc;
outBlockSize = arraySizepSrc / selfS->instance->M;
pDst=PyMem_Malloc(sizeof(q15_t)*blockSize);
pDst=PyMem_Malloc(sizeof(q15_t)*outBlockSize);
arm_fir_decimate_q15(selfS->instance,pSrc_converted,pDst,blockSize);
INT16ARRAY1(pDstOBJ,blockSize,pDst);
INT16ARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -4813,6 +4817,7 @@ cmsis_arm_fir_decimate_fast_q15(PyObject *obj, PyObject *args)
q15_t *pSrc_converted=NULL; // input
q15_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
@ -4820,12 +4825,13 @@ cmsis_arm_fir_decimate_fast_q15(PyObject *obj, PyObject *args)
dsp_arm_fir_decimate_instance_q15Object *selfS = (dsp_arm_fir_decimate_instance_q15Object *)S;
GETARGUMENT(pSrc,NPY_INT16,int16_t,int16_t);
blockSize = arraySizepSrc ;
outBlockSize = arraySizepSrc / selfS->instance->M;
pDst=PyMem_Malloc(sizeof(q15_t)*blockSize);
pDst=PyMem_Malloc(sizeof(q15_t)*outBlockSize);
arm_fir_decimate_fast_q15(selfS->instance,pSrc_converted,pDst,blockSize);
INT16ARRAY1(pDstOBJ,blockSize,pDst);
INT16ARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -4881,6 +4887,7 @@ cmsis_arm_fir_decimate_q31(PyObject *obj, PyObject *args)
q31_t *pSrc_converted=NULL; // input
q31_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
@ -4888,12 +4895,13 @@ cmsis_arm_fir_decimate_q31(PyObject *obj, PyObject *args)
dsp_arm_fir_decimate_instance_q31Object *selfS = (dsp_arm_fir_decimate_instance_q31Object *)S;
GETARGUMENT(pSrc,NPY_INT32,int32_t,int32_t);
blockSize = arraySizepSrc ;
outBlockSize = arraySizepSrc / selfS->instance->M;
pDst=PyMem_Malloc(sizeof(q31_t)*blockSize);
pDst=PyMem_Malloc(sizeof(q31_t)*outBlockSize);
arm_fir_decimate_q31(selfS->instance,pSrc_converted,pDst,blockSize);
INT32ARRAY1(pDstOBJ,blockSize,pDst);
INT32ARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -4915,19 +4923,21 @@ cmsis_arm_fir_decimate_fast_q31(PyObject *obj, PyObject *args)
q31_t *pSrc_converted=NULL; // input
q31_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
dsp_arm_fir_decimate_instance_q31Object *selfS = (dsp_arm_fir_decimate_instance_q31Object *)S;
GETARGUMENT(pSrc,NPY_INT32,int32_t,int32_t);
blockSize = arraySizepSrc ;
blockSize = arraySizepSrc;
outBlockSize = arraySizepSrc / selfS->instance->M;
pDst=PyMem_Malloc(sizeof(q31_t)*blockSize);
pDst=PyMem_Malloc(sizeof(q31_t)*outBlockSize);
arm_fir_decimate_fast_q31(selfS->instance,pSrc_converted,pDst,blockSize);
INT32ARRAY1(pDstOBJ,blockSize,pDst);
INT32ARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -4983,6 +4993,7 @@ cmsis_arm_fir_interpolate_q15(PyObject *obj, PyObject *args)
q15_t *pSrc_converted=NULL; // input
q15_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
@ -4990,12 +5001,13 @@ cmsis_arm_fir_interpolate_q15(PyObject *obj, PyObject *args)
dsp_arm_fir_interpolate_instance_q15Object *selfS = (dsp_arm_fir_interpolate_instance_q15Object *)S;
GETARGUMENT(pSrc,NPY_INT16,int16_t,int16_t);
blockSize = arraySizepSrc ;
outBlockSize = arraySizepSrc * selfS->instance->L;
pDst=PyMem_Malloc(sizeof(q15_t)*blockSize);
pDst=PyMem_Malloc(sizeof(q15_t)*outBlockSize);
arm_fir_interpolate_q15(selfS->instance,pSrc_converted,pDst,blockSize);
INT16ARRAY1(pDstOBJ,blockSize,pDst);
INT16ARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -5051,6 +5063,7 @@ cmsis_arm_fir_interpolate_q31(PyObject *obj, PyObject *args)
q31_t *pSrc_converted=NULL; // input
q31_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
@ -5058,12 +5071,13 @@ cmsis_arm_fir_interpolate_q31(PyObject *obj, PyObject *args)
dsp_arm_fir_interpolate_instance_q31Object *selfS = (dsp_arm_fir_interpolate_instance_q31Object *)S;
GETARGUMENT(pSrc,NPY_INT32,int32_t,int32_t);
blockSize = arraySizepSrc ;
outBlockSize = arraySizepSrc * selfS->instance->L;
pDst=PyMem_Malloc(sizeof(q31_t)*blockSize);
pDst=PyMem_Malloc(sizeof(q31_t)*outBlockSize);
arm_fir_interpolate_q31(selfS->instance,pSrc_converted,pDst,blockSize);
INT32ARRAY1(pDstOBJ,blockSize,pDst);
INT32ARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -5119,19 +5133,21 @@ cmsis_arm_fir_interpolate_f32(PyObject *obj, PyObject *args)
float32_t *pSrc_converted=NULL; // input
float32_t *pDst=NULL; // output
uint32_t blockSize; // input
uint32_t outBlockSize; // input
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
dsp_arm_fir_interpolate_instance_f32Object *selfS = (dsp_arm_fir_interpolate_instance_f32Object *)S;
GETARGUMENT(pSrc,NPY_DOUBLE,double,float32_t);
blockSize = arraySizepSrc ;
blockSize = arraySizepSrc;
outBlockSize = arraySizepSrc * selfS->instance->L;
pDst=PyMem_Malloc(sizeof(float32_t)*blockSize);
pDst=PyMem_Malloc(sizeof(float32_t)*outBlockSize);
arm_fir_interpolate_f32(selfS->instance,pSrc_converted,pDst,blockSize);
FLOATARRAY1(pDstOBJ,blockSize,pDst);
FLOATARRAY1(pDstOBJ,outBlockSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);

@ -880,7 +880,6 @@ cmsis_arm_barycenter_f32(PyObject *obj, PyObject *args)
if (PyArg_ParseTuple(args,"OOkk",&pSrcA,&pSrcB,&nbVectors,&vecDim))
{
GETARGUMENT(pSrcA,NPY_DOUBLE,double,float32_t);
GETARGUMENT(pSrcB,NPY_DOUBLE,double,float32_t);

@ -1817,8 +1817,8 @@ void typeRegistration(PyObject *module) {
ADDTYPE(arm_cfft_instance_f32);
ADDTYPE(arm_rfft_instance_q15);
ADDTYPE(arm_rfft_instance_q31);
ADDTYPE(arm_rfft_instance_f32);
ADDTYPE(arm_rfft_fast_instance_f32);
ADDTYPE(arm_rfft_fast_instance_f64);
ADDTYPE(arm_dct4_instance_f32);
ADDTYPE(arm_dct4_instance_q31);
ADDTYPE(arm_dct4_instance_q15);
@ -2206,7 +2206,7 @@ cmsis_arm_cfft_f64(PyObject *obj, PyObject *args)
GETARGUMENT(p1,NPY_DOUBLE,double,float64_t);
arm_cfft_f64(selfS->instance,p1_converted,(uint8_t)ifftFlag,(uint8_t)bitReverseFlag);
FLOATARRAY1(p1OBJ,2*selfS->instance->fftLen,p1_converted);
FLOAT64ARRAY1(p1OBJ,2*selfS->instance->fftLen,p1_converted);
PyObject *pythonResult = Py_BuildValue("O",p1OBJ);
@ -2283,15 +2283,28 @@ cmsis_arm_rfft_q15(PyObject *obj, PyObject *args)
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
int inputSize;
int outputSize;
dsp_arm_rfft_instance_q15Object *selfS = (dsp_arm_rfft_instance_q15Object *)S;
inputSize=selfS->instance->fftLenReal;
if (selfS->instance->ifftFlagR)
{
outputSize = inputSize-2;
}
else
{
outputSize = 2*inputSize+2;
}
dsp_arm_rfft_instance_q15Object *selfS = (dsp_arm_rfft_instance_q15Object *)S;
GETARGUMENT(pSrc,NPY_INT16,int16_t,int16_t);
pDst=PyMem_Malloc(sizeof(q15_t)*2*selfS->instance->fftLenReal);
pDst=PyMem_Malloc(sizeof(q15_t)*outputSize);
arm_rfft_q15(selfS->instance,pSrc_converted,pDst);
INT16ARRAY1(pDstOBJ,2*selfS->instance->fftLenReal,pDst);
INT16ARRAY1(pDstOBJ,outputSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -2340,17 +2353,32 @@ cmsis_arm_rfft_q31(PyObject *obj, PyObject *args)
q31_t *pSrc_converted=NULL; // input
q31_t *pDst=NULL; // output
if (PyArg_ParseTuple(args,"OO",&S,&pSrc))
{
dsp_arm_rfft_instance_q31Object *selfS = (dsp_arm_rfft_instance_q31Object *)S;
int inputSize;
int outputSize;
dsp_arm_rfft_instance_q31Object *selfS = (dsp_arm_rfft_instance_q31Object *)S;
inputSize=selfS->instance->fftLenReal;
if (selfS->instance->ifftFlagR)
{
outputSize = inputSize-2;
}
else
{
outputSize = 2*inputSize+2;
}
GETARGUMENT(pSrc,NPY_INT32,int32_t,int32_t);
pDst=PyMem_Malloc(sizeof(q31_t)*2*selfS->instance->fftLenReal);
pDst=PyMem_Malloc(sizeof(q31_t)*outputSize);
arm_rfft_q31(selfS->instance,pSrc_converted,pDst);
INT32ARRAY1(pDstOBJ,2*selfS->instance->fftLenReal,pDst);
INT32ARRAY1(pDstOBJ,outputSize,pDst);
PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
@ -2465,11 +2493,11 @@ cmsis_arm_rfft_fast_f64(PyObject *obj, PyObject *args)
dsp_arm_rfft_fast_instance_f64Object *selfS = (dsp_arm_rfft_fast_instance_f64Object *)S;
GETARGUMENT(p,NPY_DOUBLE,double,float64_t);
pOut=PyMem_Malloc(sizeof(float64_t)*2*selfS->instance->fftLenRFFT);
pOut=PyMem_Malloc(sizeof(float64_t)*selfS->instance->fftLenRFFT);
arm_rfft_fast_f64(selfS->instance,p_converted,pOut,(uint8_t)ifftFlag);
FLOATARRAY1(pOutOBJ,2*selfS->instance->fftLenRFFT,pOut);
FLOAT64ARRAY1(pOutOBJ,selfS->instance->fftLenRFFT,pOut);
PyObject *pythonResult = Py_BuildValue("O",pOutOBJ);
@ -3139,9 +3167,8 @@ static PyMethodDef CMSISDSPMethods[] = {
{"arm_rfft_q15", cmsis_arm_rfft_q15, METH_VARARGS,""},
{"arm_rfft_init_q31", cmsis_arm_rfft_init_q31, METH_VARARGS,""},
{"arm_rfft_q31", cmsis_arm_rfft_q31, METH_VARARGS,""},
{"arm_rfft_init_f32", cmsis_arm_rfft_init_f32, METH_VARARGS,""},
{"arm_rfft_f32", cmsis_arm_rfft_f32, METH_VARARGS,""},
{"arm_rfft_fast_init_f64", cmsis_arm_rfft_fast_init_f64, METH_VARARGS,""},
{"arm_rfft_fast_f64", cmsis_arm_rfft_fast_f64, METH_VARARGS,""},
{"arm_rfft_fast_f32", cmsis_arm_rfft_fast_f32, METH_VARARGS,""},
{"arm_rfft_fast_init_f32", cmsis_arm_rfft_fast_init_f32, METH_VARARGS,""},
{"arm_rfft_fast_f32", cmsis_arm_rfft_fast_f32, METH_VARARGS,""},

@ -0,0 +1,163 @@
# Bug corrections for version 1.9
import cmsisdsp as dsp
import cmsisdsp.fixedpoint as f
import numpy as np
import math
import colorama
from colorama import init,Fore, Back, Style
from numpy.testing import assert_allclose
import matplotlib.pyplot as plt
from scipy import signal
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("Decimate")
test_length_seconds = 0.1
signal_frequency = 100
sampling_freq = 8000
nbSamples = int(test_length_seconds*sampling_freq)
wave = np.sin(2*np.pi*signal_frequency*np.linspace(0,test_length_seconds,nbSamples))
#plt.plot(wave)
#plt.show()
decimationFactor = 4
numTaps = 9
downsamplingFilter = signal.firwin(numTaps,1.0 / decimationFactor)
block_size = 160
assert(block_size % decimationFactor == 0)
ds_state = np.zeros(block_size + len(downsamplingFilter)-1)
decimator = dsp.arm_fir_decimate_instance_f32()
status = dsp.arm_fir_decimate_init_f32(decimator,numTaps,decimationFactor, downsamplingFilter, ds_state)
def processSignal(sig,dec,f):
result = []
for blockNb in range(len(sig) // block_size):
s = blockNb * block_size
e = s + block_size
r = f(dec,sig[s:e])
result.append(r)
output = np.hstack(result)
return(output)
ref = processSignal(wave,decimator,dsp.arm_fir_decimate_f32)
#plt.plot(ref)
#plt.show()
printSubTitle("Decimate Q31")
waveQ31 = f.toQ31(wave)
downsamplingFilterQ31 = f.toQ31(downsamplingFilter)
stateQ31 = np.zeros(block_size + len(downsamplingFilter)-1)
decimatorQ31 = dsp.arm_fir_decimate_instance_q31()
status = dsp.arm_fir_decimate_init_q31(decimatorQ31,numTaps,decimationFactor,
downsamplingFilterQ31, stateQ31)
outputQ31 = processSignal(waveQ31,decimatorQ31,dsp.arm_fir_decimate_q31)
outputF32 = f.Q31toF32(outputQ31)
printSubTitle("Decimate Fast Q31")
waveQ31 = f.toQ31(wave)
downsamplingFilterQ31 = f.toQ31(downsamplingFilter)
stateQ31 = np.zeros(block_size + len(downsamplingFilter)-1)
decimatorQ31 = dsp.arm_fir_decimate_instance_q31()
status = dsp.arm_fir_decimate_init_q31(decimatorQ31,numTaps,decimationFactor,
downsamplingFilterQ31, stateQ31)
outputQ31 = processSignal(waveQ31,decimatorQ31,dsp.arm_fir_decimate_fast_q31)
outputF32 = f.Q31toF32(outputQ31)
printSubTitle("Decimate Q15")
waveQ15 = f.toQ15(wave)
downsamplingFilterQ15 = f.toQ15(downsamplingFilter)
stateQ15 = np.zeros(block_size + len(downsamplingFilter)-1)
decimatorQ15 = dsp.arm_fir_decimate_instance_q15()
status = dsp.arm_fir_decimate_init_q15(decimatorQ15,numTaps,decimationFactor,
downsamplingFilterQ15, stateQ15)
outputQ15 = processSignal(waveQ15,decimatorQ15,dsp.arm_fir_decimate_q15)
outputF32 = f.Q15toF32(outputQ15)
#plt.plot(outputF32)
#plt.show()
assert_allclose(ref,outputF32,rtol=2e-3,atol=1e-3)
printSubTitle("Decimate Fast Q15")
waveQ15 = f.toQ15(wave)
downsamplingFilterQ15 = f.toQ15(downsamplingFilter)
stateQ15 = np.zeros(block_size + len(downsamplingFilter)-1)
decimatorQ15 = dsp.arm_fir_decimate_instance_q15()
status = dsp.arm_fir_decimate_init_q15(decimatorQ15,numTaps,decimationFactor,
downsamplingFilterQ15, stateQ15)
outputQ15 = processSignal(waveQ15,decimatorQ15,dsp.arm_fir_decimate_fast_q15)
outputF32 = f.Q15toF32(outputQ15)
#plt.plot(outputF32)
#plt.show()
assert_allclose(ref,outputF32,rtol=2e-3,atol=1e-3)
printTitle("Interpolate")
upsamplingFactor = 4
numTaps = 16
upsamplingFilter = signal.firwin(numTaps,1.0 / upsamplingFactor)
assert(numTaps % upsamplingFactor == 0)
block_size = 40
printSubTitle("Interpolate F32")
state = np.zeros(block_size + len(upsamplingFilter)//upsamplingFactor-1)
interpolator = dsp.arm_fir_interpolate_instance_f32()
status = dsp.arm_fir_interpolate_init_f32(interpolator,upsamplingFactor,numTaps,
upsamplingFilter, state)
output = processSignal(ref,interpolator,dsp.arm_fir_interpolate_f32)
output = output / np.max(output)
#t = range(nbSamples)
#plt.plot(t,wave,t[:-11],output[11:])
#plt.show()
d = 11
assert_allclose(wave[:-d],output[d:],atol=0.1)
printSubTitle("Interpolate Q31")
upsamplingFilterQ31 = f.toQ31(upsamplingFilter)
stateQ31 = np.zeros(block_size + len(upsamplingFilter)//upsamplingFactor-1)
interpolatorQ31 = dsp.arm_fir_interpolate_instance_q31()
status = dsp.arm_fir_interpolate_init_q31(interpolatorQ31,upsamplingFactor,numTaps,
upsamplingFilterQ31, stateQ31)
outputQ31 = processSignal(outputQ31,interpolatorQ31,dsp.arm_fir_interpolate_q31)
outputF32 = f.Q31toF32(outputQ31)
outputF32 = outputF32 / np.max(outputF32)
assert_allclose(wave[:-d],outputF32[d:],atol=0.1)
printSubTitle("Interpolate Q15")
upsamplingFilterQ15 = f.toQ15(upsamplingFilter)
stateQ15 = np.zeros(block_size + len(upsamplingFilter)//upsamplingFactor-1)
interpolatorQ15 = dsp.arm_fir_interpolate_instance_q15()
status = dsp.arm_fir_interpolate_init_q15(interpolatorQ15,upsamplingFactor,numTaps,
upsamplingFilterQ15, stateQ15)
outputQ15 = processSignal(outputQ15,interpolatorQ15,dsp.arm_fir_interpolate_q15)
outputF32 = f.Q15toF32(outputQ15)
outputF32 = outputF32 / np.max(outputF32)
assert_allclose(wave[:-d],outputF32[d:],atol=0.1)

@ -71,9 +71,10 @@ assert i==-10
print("Barycenter")
a=[0] * 12
w=np.array([[2] * 12])
w[0,11]=3
a=np.zeros((12,3))
w=np.array([[2.0] * 12])[0]
w[0]=3
w[11]=3
a[0] =[0., 0., -0.951057]
a[1] =[0., 0., 0.951057]
a[2] =[-0.850651, 0., -0.425325]
@ -87,15 +88,19 @@ a[9] =[-0.262866, 0.809017, -0.425325]
a[10]=[0.262866, -0.809017, 0.425325]
a[11]=[0.262866, 0.809017, 0.425325]
scaled=a * w.T
scaled= np.dot(a.T , w)
ref=np.sum(scaled,axis=0)/np.sum(w)
print(ref)
#print(ref)
points = np.array(a).reshape(12*3)
weights = w.reshape(12)
#print(points)
#print(weights)
result=dsp.arm_barycenter_f32(points,weights,12,3)
print(result)
#print(result)
assert_allclose(ref,result,1e-6)

@ -0,0 +1,146 @@
import cmsisdsp as dsp
import cmsisdsp.fixedpoint as f
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
import scipy.fft
import colorama
from colorama import init,Fore, Back, Style
from numpy.testing import assert_allclose
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)
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)
ref=scipy.fft.rfft(signal)
invref = scipy.fft.irfft(ref)
# Convert ref to CMSIS-DSP format
referenceFloat=np.zeros(nb)
# Replace complex datatype by real datatype
referenceFloat[0::2] = np.real(ref)[:-1]
referenceFloat[1::2] = np.imag(ref)[:-1]
# Copy Nyquist frequency value into first
# sample.This is just a storage trick so that the
# output of the RFFT has same length as input
# It is legacy behavior that we need to keep
# for backward compatibility but it is not
# very pretty
referenceFloat[1] = np.real(ref[-1])
printTitle("RFFT FAST F64")
printSubTitle("RFFT")
rfftf64=dsp.arm_rfft_fast_instance_f64()
status=dsp.arm_rfft_fast_init_f64(rfftf64,nb)
result = dsp.arm_rfft_fast_f64(rfftf64,signal,0)
assert_allclose(referenceFloat,result)
printSubTitle("RIFFT")
rifftf64=dsp.arm_rfft_fast_instance_f64()
status=dsp.arm_rfft_fast_init_f64(rifftf64,nb)
result = dsp.arm_rfft_fast_f64(rifftf64,referenceFloat,1)
assert_allclose(invref,result,atol=1e-15)
printTitle("RFFT FAST F32")
printSubTitle("RFFT")
rfftf32=dsp.arm_rfft_fast_instance_f32()
status=dsp.arm_rfft_fast_init_f32(rfftf32,nb)
result = dsp.arm_rfft_fast_f32(rfftf32,signal,0)
assert_allclose(referenceFloat,result,rtol=3e-6)
printSubTitle("RIFFT")
rifftf32=dsp.arm_rfft_fast_instance_f32()
status=dsp.arm_rfft_fast_init_f32(rifftf32,nb)
result = dsp.arm_rfft_fast_f32(rifftf32,referenceFloat,1)
assert_allclose(invref,result,atol=1e-7)
# Fixed point
# Reference from fixed point arithmetric.
# The RFFT are not packing the Nyquist frequency
# real value in sample 0
referenceFloat=np.zeros(nb+2)
# Replace complex datatype by real datatype
referenceFloat[0::2] = np.real(ref)
referenceFloat[1::2] = np.imag(ref)
printTitle("RFFT Q31")
printSubTitle("RFFT")
signalQ31 = f.toQ31(signal)
rfftQ31=dsp.arm_rfft_instance_q31()
status=dsp.arm_rfft_init_q31(rfftQ31,nb,0,1)
resultQ31 = dsp.arm_rfft_q31(rfftQ31,signalQ31)
# Drop the conjugate part which is not computed by scipy
resultQ31 = resultQ31[:nb+2]
resultF = f.Q31toF32(resultQ31) * nb
assert_allclose(referenceFloat,resultF,rtol=1e-6,atol=1e-6)
printSubTitle("RIFFT")
rifftQ31=dsp.arm_rfft_instance_q31()
status=dsp.arm_rfft_init_q31(rifftQ31,nb,1,1)
# Apply CMSIS-DSP scaling
referenceQ31 = f.toQ31(referenceFloat / nb)
resultQ31 = dsp.arm_rfft_q31(rifftQ31,referenceFloat)
resultF = f.Q31toF32(resultQ31)
assert_allclose(invref,result,atol=1e-6)
printTitle("RFFT Q15")
printSubTitle("RFFT")
signalQ15 = f.toQ15(signal)
rfftQ15=dsp.arm_rfft_instance_q15()
status=dsp.arm_rfft_init_q15(rfftQ15,nb,0,1)
resultQ15 = dsp.arm_rfft_q15(rfftQ15,signalQ15)
# Drop the conjugate part which is not computed by scipy
resultQ15 = resultQ15[:nb+2]
resultF = f.Q15toF32(resultQ15) * nb
assert_allclose(referenceFloat,resultF,rtol=1e-6,atol=1e-2)
printSubTitle("RIFFT")
rifftQ15=dsp.arm_rfft_instance_q15()
status=dsp.arm_rfft_init_q15(rifftQ15,nb,1,1)
# Apply CMSIS-DSP scaling
referenceQ15 = f.toQ15(referenceFloat / nb)
resultQ15 = dsp.arm_rfft_q15(rifftQ15,referenceFloat)
resultF = f.Q15toF32(resultQ15)
assert_allclose(invref,result,atol=1e-2)

@ -1,27 +0,0 @@
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))

@ -239,6 +239,12 @@ The wrapper is now containing the compute graph Python scripts and you should re
# Change history
## Version 1.9.3:
* Corrected real FFTs in the wrapper
* Corrected arm_fir_decimate and arm_fir_interpolate
* Possibility to customize the FIFO class on a connection for the Python wrapper
## Version 1.9.2:
* New customization options for the compute graph:

@ -121,7 +121,7 @@
@param[in] S points to an instance of the floating-point FIR decimator structure
@param[in] pSrc points to the block of input data
@param[out] pDst points to the block of output data
@param[in] blockSize number of samples to process
@param[in] blockSize number of input samples to process
@return none
*/
#if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)

@ -42,7 +42,7 @@
@param[in] S points to an instance of the Q31 FIR decimator structure
@param[in] pSrc points to the block of input data
@param[out] pDst points to the block of output data
@param[in] blockSize number of samples to process
@param[in] blockSize number of input samples to process
@return none
@par Scaling and Overflow Behavior

@ -125,7 +125,7 @@
@param[in] S points to an instance of the floating-point FIR interpolator structure
@param[in] pSrc points to the block of input data
@param[out] pDst points to the block of output data
@param[in] blockSize number of samples to process
@param[in] blockSize number of input samples to process
@return none
*/

@ -42,7 +42,7 @@
@param[in] S points to an instance of the Q15 FIR interpolator structure
@param[in] pSrc points to the block of input data
@param[out] pDst points to the block of output data
@param[in] blockSize number of samples to process
@param[in] blockSize number of input samples to process
@return none
@par Scaling and Overflow Behavior

@ -42,7 +42,7 @@
@param[in] S points to an instance of the Q31 FIR interpolator structure
@param[in] pSrc points to the block of input data
@param[out] pDst points to the block of output data
@param[in] blockSize number of samples to process
@param[in] blockSize number of input samples to process
@return none
@par Scaling and Overflow Behavior

@ -93,11 +93,12 @@ void arm_split_rifft_q15(
| 8192 | 1.15 | 13.3 | 0 |
@par
If the input buffer is of length N, the output buffer must have length 2*N.
If the input buffer is of length N (fftLenReal), the output buffer must have length 2N + 2
since it is containing the conjugate part. (N/2 + 1 + N/2 complex samples)
The input buffer is modified by this function.
@par
For the RIFFT, the source buffer must at least have length
fftLenReal + 2.
For the RIFFT, the source buffer must have at least length
fftLenReal + 2 which is (N/2 + 1 complex samples). It is not using the conjugate part.
The last two elements must be equal to what would be generated
by the RFFT:
(pSrc[0] - pSrc[1]) >> 1 and 0

@ -93,11 +93,12 @@ void arm_split_rifft_q31(
| 8192 | 1.31 | 13.19 | 0 |
@par
If the input buffer is of length N, the output buffer must have length 2*N.
If the input buffer is of length N (fftLenReal), the output buffer must have length 2N + 2
since it is containing the conjugate part. (N/2 + 1 + N/2 complex samples)
The input buffer is modified by this function.
@par
For the RIFFT, the source buffer must at least have length
fftLenReal + 2.
For the RIFFT, the source buffer must have at least length
fftLenReal + 2 which is (N/2 + 1 complex samples). It is not using the conjugate part.
The last two elements must be equal to what would be generated
by the RFFT:
(pSrc[0] - pSrc[1]) >> 1 and 0

@ -19,15 +19,15 @@ from cmsisdsp_svm import *
__version__ = cmsisdsp.version.__version__
# CMSIS-DSP Version used to build the wrapper
cmsis_dsp_version="1.14.1"
cmsis_dsp_version="1.14.2"
# CMSIS-DSP Commit hash used to build the wrapper
commit_hash="8ed2ef7a7e2c6fce29c59d18ba7ee0f9f66027c2"
commit_hash="0705c6756809e0dac25ac2986f455c2088dad5c2"
# True if development version of CMSIS-DSP used
# (So several CMSIS-DSP versions may have same version number hence the commit hash)
developmentVersion=False
developmentVersion=True
__all__ = ["datatype", "fixedpoint", "mfcc"]

@ -90,6 +90,7 @@ class FIFODesc:
self.dst = None
# FIFO delay
self.delay=0
self.fifoClass = "FIFO"
# Used for liveliness analysis
# To share buffers between FIFO in memory optimization
@ -169,6 +170,7 @@ class Graph():
self._totalMemory=0
self._allFIFOs = None
self._allBuffers = None
self._FIFOClasses = {}
# Topological sorting of nodes
# computed during topology matrix
# and used for some scheduling
@ -211,11 +213,11 @@ class Graph():
#print(self._topologicalSort)
def connectDup(self,destination,outputIO,theId):
def connectDup(self,destination,outputIO,theId,fifoClass="FIFO"):
if (destination[theId][1]!=0):
self.connectWithDelay(outputIO,destination[theId][0],destination[theId][1],dupAllowed=False)
self.connectWithDelay(outputIO,destination[theId][0],destination[theId][1],dupAllowed=False,fifoClass=destination[theId][2])
else:
self.connect(outputIO,destination[theId][0],dupAllowed=False)
self.connect(outputIO,destination[theId][0],dupAllowed=False,fifoClass=destination[theId][2])
@ -287,12 +289,17 @@ class Graph():
nodea = f[0]
nodeb = f[1]
fifoClass = "FIFO"
if (nodea,nodeb) in self._FIFOClasses:
fifoClass = self._FIFOClasses[(nodea,nodeb)]
if (nodea,nodeb) in self._delays:
delay = self._delays[(nodea,nodeb)]
else:
delay = 0
destinations.append((nodeb,delay))
destinations.append((nodeb,delay,fifoClass))
nodea.fifo=None
nodeb.fifo=None
@ -309,6 +316,8 @@ class Graph():
if self._g.has_edge(nodea.owner,nodeb.owner):
self._g.remove_edge(nodea.owner,nodeb.owner)
del self._edges[(nodea,nodeb)]
if (nodea,nodeb) in self._FIFOClasses:
del self._FIFOClasses[(nodea,nodeb)]
if (nodea,nodeb) in self._delays:
del self._delays[(nodea,nodeb)]
@ -333,7 +342,7 @@ class Graph():
def connect(self,nodea,nodeb,dupAllowed=True):
def connect(self,nodea,nodeb,dupAllowed=True,fifoClass="FIFO"):
# When connecting to a constant node we do nothing
# since there is no FIFO in this case
# and it does not participate to the scheduling.
@ -353,6 +362,7 @@ class Graph():
nodea.fifo=(nodea,nodeb)
nodeb.fifo=(nodea,nodeb)
self._edges[(nodea,nodeb)]=True
self._FIFOClasses[(nodea,nodeb)] = fifoClass
if not (nodea.owner in self._nodes):
self._nodes[nodea.owner]=True
if not (nodeb.owner in self._nodes):
@ -360,12 +370,12 @@ class Graph():
else:
raise IncompatibleIO
def connectWithDelay(self,nodea,nodeb,delay,dupAllowed=True):
def connectWithDelay(self,nodea,nodeb,delay,dupAllowed=True,fifoClass="FIFO"):
# We cannot connect with delay to a constant node
if (isinstance(nodea,Constant)):
raise CannotDelayConstantError
else:
self.connect(nodea,nodeb,dupAllowed=dupAllowed)
self.connect(nodea,nodeb,dupAllowed=dupAllowed,fifoClass=fifoClass)
self._delays[(nodea,nodeb)] = delay
def __str__(self):
@ -384,6 +394,9 @@ class Graph():
edge = self._sortedEdges[fifo.fifoID]
fifo.length = fifoLengths[fifo.fifoID]
src,dst = edge
if edge in self._FIFOClasses:
fifoClass = self._FIFOClasses[edge]
fifo.fifoClass = fifoClass
fifo.src=src
fifo.dst=dst
fifo.delay=self.getDelay(edge)

@ -50,9 +50,9 @@ def {{config.schedName}}({{optionalargs()}}):
#
{% for id in range(nbFifos) %}
{% if fifos[id].hasDelay %}
fifo{{id}}=FIFO(FIFOSIZE{{id}},{{config.prefix}}buf{{id}},delay={{fifos[id].delay}})
fifo{{id}}={{fifos[id].fifoClass}}(FIFOSIZE{{id}},{{config.prefix}}buf{{id}},delay={{fifos[id].delay}})
{% else %}
fifo{{id}}=FIFO(FIFOSIZE{{id}},{{config.prefix}}buf{{id}})
fifo{{id}}={{fifos[id].fifoClass}}(FIFOSIZE{{id}},{{config.prefix}}buf{{id}})
{% endif %}
{% endfor %}

@ -101,9 +101,9 @@ uint32_t {{config.schedName}}(int *error{{optionalargs()}})
*/
{% for id in range(nbFifos) %}
{% if fifos[id].hasDelay %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}},{{fifos[id].delay}});
{{fifos[id].fifoClass}}<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}},{{fifos[id].delay}});
{% else %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}});
{{fifos[id].fifoClass}}<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}});
{% endif %}
{% endfor %}

@ -66,9 +66,9 @@ uint32_t {{config.schedName}}(int *error{{optionalargs()}})
*/
{% for id in range(nbFifos) %}
{% if fifos[id].hasDelay %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}},{{fifos[id].delay}});
{{fifos[id].fifoClass}}<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}},{{fifos[id].delay}});
{% else %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}});
{{fifos[id].fifoClass}}<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}});
{% endif %}
{% endfor %}

@ -15,7 +15,7 @@
{{constEdges[theID][1].owner.nodeID}}:{{constEdges[theID][1].name}}
{% endmacro -%}
{% macro delayBoxID(id) -%}{{fifos[id].src.owner.nodeID}}Delay{%- endmacro %}
{% macro delayBoxID(id) -%}{{fifos[id].src.owner.nodeID}}{{fifos[id].dst.owner.nodeID}}Delay{%- endmacro %}
{% macro delayBox(edge) -%}
{% if fifos[edge].hasDelay %}

@ -1,2 +1,2 @@
# Python wrapper version
__version__ = "1.9.2"
__version__ = "1.9.3"

Loading…
Cancel
Save