From b8db1e48efff44b32ced7fdff3c6dc2da8b37ac5 Mon Sep 17 00:00:00 2001 From: Christophe Favergeon Date: Mon, 17 Jun 2024 13:15:27 +0200 Subject: [PATCH] Fixes to Python wrapper examples. Changes to work with Python 3.12 --- PythonWrapper/build/create.bat | 2 +- .../cmsisdsp_pkg/src/cmsisdsp_module.h | 2 +- PythonWrapper/examples/debug.py | 107 +++++++++--------- PythonWrapper/examples/example_1_11.py | 34 +++--- PythonWrapper/examples/testdistance.py | 14 ++- PythonWrapper/examples/testdsp6.py | 6 +- PythonWrapper/examples/testmfcc.py | 2 +- PythonWrapper/examples/testmfccq15.py | 2 +- PythonWrapper/examples/testmfccq31.py | 2 +- PythonWrapper_README.md | 3 + cmsisdsp/version.py | 2 +- setup.py | 24 ++-- 12 files changed, 108 insertions(+), 92 deletions(-) diff --git a/PythonWrapper/build/create.bat b/PythonWrapper/build/create.bat index 298fb13ee..747e861ea 100644 --- a/PythonWrapper/build/create.bat +++ b/PythonWrapper/build/create.bat @@ -1,7 +1,7 @@ cmake -DHOST=YES ^ -DLOOPUNROLL=ON ^ -DWRAPPER=YES ^ - -DCMSISDSP=".." ^ + -DCMSISDSP="path to CMSIS-DSP folder" ^ -DCMAKE_C_FLAGS_RELEASE="-std=c11 -Ofast -ffast-math -DNDEBUG -Wall -Wextra" ^ -DCMAKE_CXX_FLAGS_RELEASE="-fno-rtti -std=c++11 -Ofast -ffast-math -DNDEBUG -Wall -Wextra -Wno-unused-parameter" ^ -G "Unix Makefiles" .. diff --git a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_module.h b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_module.h index f322e6d2b..b19f38525 100644 --- a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_module.h +++ b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_module.h @@ -32,7 +32,7 @@ #include // API version used on google colab -// List in https://github.com/numpy/numpy numpyconfig.h +// https://github.com/numpy/numpy/blob/main/numpy/_core/include/numpy/numpyconfig.h #if (NPY_API_VERSION != 0x0000000F ) //#error("Error building with wrong NumPy API version") #endif diff --git a/PythonWrapper/examples/debug.py b/PythonWrapper/examples/debug.py index 7e6b483b5..0ab597510 100755 --- a/PythonWrapper/examples/debug.py +++ b/PythonWrapper/examples/debug.py @@ -9,6 +9,7 @@ import colorama from colorama import init,Fore, Back, Style from numpy.testing import assert_allclose +import scipy.spatial.distance as d init() @@ -19,63 +20,61 @@ 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 +def packset(a): + b = np.packbits(a) + newSize = int(np.ceil(b.shape[0] / 4.0)) * 4 + c = np.copy(b).astype(np.uint32) + c.resize(newSize) + #print(c) + vecSize = round(newSize/4) + c=c.reshape(vecSize,4) + #print(c) + r = np.zeros(vecSize) + result = [] + for i in range(0,vecSize): + print(c[i,:]) + #print("%X %X %X %X" % (c[i,0],c[i,1],c[i,2],c[i,3])) + d = (c[i,0] << 24) | (c[i,1] << 16) | (c[i,2] << 8) | c[i,3] + result.append(np.uint32(d)) + return(result) -nb = 32 -signal = np.cos(2 * np.pi * np.arange(nb) / nb)*np.cos(0.2*2 * np.pi * np.arange(nb) / nb) +nb = 34 +#va = np.random.choice([0,1],nb) +# Array of word32 containing all of our bits +#pva = packset(va) -ref=scipy.fft.rfft(signal) -invref = scipy.fft.irfft(ref) -print(f"ref length = {len(ref)}") -print(ref) +#vb = np.random.choice([0,1],nb) +# Array of word32 containing all of our bits +#pvb = packset(vb) +# +va=[1, 0, 1, 0, 1, 1, 1, 0 ,0, 1, 1, 0, 1, 0, 0, 0, 0, 1,0,0,0,1,1,0,1,0,1,0,0,1,1,1,1,1] +vb=[0,1,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,1,0,0,0,1,0] + +va = np.array(va) +vb = np.array(vb) + +pva=packset(va) +pvb=packset(vb) + +#pva = [np.uint32(167), np.uint32(0)] +#pvb = [np.uint32(152), np.uint32(0)] + +#print(va,pva) +#print(vb,pvb) + +ctt=1.0*np.count_nonzero((va==1) & (vb==1)) +ctf=1.0*np.count_nonzero((va==1) & (vb==0)) +cft=1.0*np.count_nonzero((va==0) & (vb==1)) + +res=(cft+ctf)/(2*ctt+cft+ctf) -# Convert ref to CMSIS-DSP format -referenceFloat=np.zeros(2*len(ref)) -print(f"referenceFloat length = {len(referenceFloat)}") -# Replace complex datatype by real datatype -referenceFloat[0::2] = np.real(ref) -referenceFloat[1::2] = np.imag(ref) -# 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]) - -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,referenceQ31) -resultF = f.Q31toF32(resultQ31) - -print(f"resultF length = {len(resultF)}") -assert_allclose(invref/nb,resultF,atol=1e-6) - -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) -print(len(resultQ31)) -print(2*nb) -resultF = f.Q31toF32(resultQ31) * nb - -def compareWithConjugatePart(r): - res = r[0::2] + 1j * r[1::2] - conjPart = res[nb:nb//2:-1].conj() - refPart = res[1:nb//2] - assert(np.equal(refPart , conjPart).all()) - -compareWithConjugatePart(resultF) - -res = resultF[0::2] + 1j * resultF[1::2] print(res) -print(res[0:nb//2+1]) -print(res[0:nb//2+1].shape) \ No newline at end of file + +print("\nDice") +ref=d.dice(va,vb) +res=dsp.arm_dice_distance(pva,pvb,nb) +print(ref) +print(res) +assert_allclose(ref,res,1e-6) diff --git a/PythonWrapper/examples/example_1_11.py b/PythonWrapper/examples/example_1_11.py index 91ddf1208..88b85ea2a 100644 --- a/PythonWrapper/examples/example_1_11.py +++ b/PythonWrapper/examples/example_1_11.py @@ -122,26 +122,28 @@ def printSubTitle(s): printSubTitle("With a window") +nan = np.nan + referenceDistance = 0.617099940776825 -referenceCost=np.array([[9.1612804e-01, 9.9920368e-01, np.NAN, np.NAN, - np.NAN], - [1.2353053e+00, 1.6792301e+00, np.NAN, np.NAN, - np.NAN], - [1.3028694e+00, 2.3696373e+00, 4.4372001e+00, np.NAN, - np.NAN], - [np.NAN, 3.0795674e+00, 4.9687119e+00, np.NAN, - np.NAN], - [np.NAN, 3.5039051e+00, 4.9290380e+00, 5.3565612e+00, - np.NAN], - [np.NAN, np.NAN, 4.8520918e+00, 5.1756082e+00, - np.NAN], - [np.NAN, np.NAN, 5.0427418e+00, 5.8497019e+00, +referenceCost=np.array([[9.1612804e-01, 9.9920368e-01, nan, nan, + nan], + [1.2353053e+00, 1.6792301e+00, nan, nan, + nan], + [1.3028694e+00, 2.3696373e+00, 4.4372001e+00, nan, + nan], + [nan, 3.0795674e+00, 4.9687119e+00, nan, + nan], + [nan, 3.5039051e+00, 4.9290380e+00, 5.3565612e+00, + nan], + [nan, nan, 4.8520918e+00, 5.1756082e+00, + nan], + [nan, nan, 5.0427418e+00, 5.8497019e+00, 7.6590457e+00], - [np.NAN, np.NAN, np.NAN, 6.7571073e+00, + [nan, nan, nan, 6.7571073e+00, 8.6668968e+00], - [np.NAN, np.NAN, np.NAN, 7.3949833e+00, + [nan, nan, nan, 7.3949833e+00, 9.0352430e+00], - [np.NAN, np.NAN, np.NAN, np.NAN, + [nan, nan, nan, nan, 9.2564993e+00]], dtype=np.float32) diff --git a/PythonWrapper/examples/testdistance.py b/PythonWrapper/examples/testdistance.py index d6e406666..c1425b4fa 100755 --- a/PythonWrapper/examples/testdistance.py +++ b/PythonWrapper/examples/testdistance.py @@ -6,6 +6,14 @@ a=[1,2,3] b=[1,5,2] +def kulsinski(va,vb): + n = len(va) + ctt=1.0*np.count_nonzero((va==1) & (vb==1)) + ctf=1.0*np.count_nonzero((va==1) & (vb==0)) + cft=1.0*np.count_nonzero((va==0) & (vb==1)) + return(1.0*(ctf + cft - ctt+n)/(cft + ctf + n)) + + print("\nBray-Curtis") ref=d.braycurtis(a,b) res=dsp.arm_braycurtis_distance_f32(a,b) @@ -96,7 +104,7 @@ def packset(a): b = np.packbits(a) newSize = int(np.ceil(b.shape[0] / 4.0)) * 4 - c = np.copy(b) + c = np.copy(b).astype(np.uint32) c.resize(newSize) #print(c) vecSize = round(newSize/4) @@ -105,7 +113,7 @@ def packset(a): r = np.zeros(vecSize) result = [] for i in range(0,vecSize): - #print(c[i,:]) + print(c[i,:]) #print("%X %X %X %X" % (c[i,0],c[i,1],c[i,2],c[i,3])) d = (c[i,0] << 24) | (c[i,1] << 16) | (c[i,2] << 8) | c[i,3] result.append(np.uint32(d)) @@ -143,7 +151,7 @@ def packset(a): assert_allclose(ref,res,1e-6) print("\nKulsinski") -ref=d.kulsinski(va,vb) +ref=kulsinski(va,vb) res=dsp.arm_kulsinski_distance(pva,pvb,nb) print(ref) print(res) diff --git a/PythonWrapper/examples/testdsp6.py b/PythonWrapper/examples/testdsp6.py index 51754eb2d..636ed0e2b 100755 --- a/PythonWrapper/examples/testdsp6.py +++ b/PythonWrapper/examples/testdsp6.py @@ -169,10 +169,14 @@ supportVectors = supportVectors.reshape(nbSupportVectors * VECDIM) svmInst=dsp.arm_svm_polynomial_instance_f32() + + dsp.arm_svm_polynomial_init_f32(svmInst,nbSupportVectors,vectorDimensions, - intercept,dualCoefs,supportVectors, + intercept[0],dualCoefs,supportVectors, [0,1],degree,coef0,gamma) +exit(0) + test1 = np.array([0.4,0.1]) predicted1 = dsp.arm_svm_polynomial_predict_f32(svmInst,test1) print(predicted1) diff --git a/PythonWrapper/examples/testmfcc.py b/PythonWrapper/examples/testmfcc.py index 14859a854..c0e5d48b7 100755 --- a/PythonWrapper/examples/testmfcc.py +++ b/PythonWrapper/examples/testmfcc.py @@ -17,7 +17,7 @@ freq_high = sample_rate / 2 numOfMelFilters = 20 -window = sig.hamming(FFTSize, sym=False) +window = sig.windows.hamming(FFTSize, sym=False) filtLen,filtPos,packedFilters = mfcc.melFilterMatrix(F32,freq_min, freq_high, numOfMelFilters,sample_rate,FFTSize) diff --git a/PythonWrapper/examples/testmfccq15.py b/PythonWrapper/examples/testmfccq15.py index a48a807f9..853f38536 100755 --- a/PythonWrapper/examples/testmfccq15.py +++ b/PythonWrapper/examples/testmfccq15.py @@ -17,7 +17,7 @@ freq_high = sample_rate / 2 numOfMelFilters = 20 -windowQ15 = dt.convert(sig.hamming(FFTSize, sym=False),Q15) +windowQ15 = dt.convert(sig.windows.hamming(FFTSize, sym=False),Q15) filtLen,filtPos,packedFiltersQ15 = mfcc.melFilterMatrix(Q15,freq_min, freq_high, numOfMelFilters,sample_rate,FFTSize) dctMatrixFiltersQ15 = mfcc.dctMatrix(Q15,numOfDctOutputs, numOfMelFilters) diff --git a/PythonWrapper/examples/testmfccq31.py b/PythonWrapper/examples/testmfccq31.py index 686dc6d74..08e31e473 100755 --- a/PythonWrapper/examples/testmfccq31.py +++ b/PythonWrapper/examples/testmfccq31.py @@ -17,7 +17,7 @@ freq_high = sample_rate / 2 numOfMelFilters = 20 -windowQ31 = dt.convert(sig.hamming(FFTSize, sym=False),Q31) +windowQ31 = dt.convert(sig.windows.hamming(FFTSize, sym=False),Q31) filtLen,filtPos,packedFiltersQ31 = mfcc.melFilterMatrix(Q31,freq_min, freq_high, numOfMelFilters,sample_rate,FFTSize) dctMatrixFiltersQ31 = mfcc.dctMatrix(Q31,numOfDctOutputs, numOfMelFilters) diff --git a/PythonWrapper_README.md b/PythonWrapper_README.md index 1447070d1..fe7172150 100644 --- a/PythonWrapper_README.md +++ b/PythonWrapper_README.md @@ -234,6 +234,9 @@ MEL filters are represented as 3 arrays to encode a sparse array. # Change history +## Version 1.9.9: +* Supports Python 3.12 + ## Version 1.9.8: * Compute graph API has been removed * Dependency on numpy 1.22 has been lifted, tested through numpy 1.26 diff --git a/cmsisdsp/version.py b/cmsisdsp/version.py index f92aee219..d357a33f1 100755 --- a/cmsisdsp/version.py +++ b/cmsisdsp/version.py @@ -1,2 +1,2 @@ # Python wrapper version -__version__ = "1.9.8" +__version__ = "1.9.9" diff --git a/setup.py b/setup.py index c725e65e3..aa576848f 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #from distutils.core import setup, Extension from setuptools import setup, Extension,find_packages -from distutils.util import convert_path +import io import glob import numpy import sys @@ -14,6 +14,15 @@ ROOT = here ROOT="" +PYTHON_MOD = os.path.join(ROOT,"cmsisdsp") +version_path = os.path.join(PYTHON_MOD,"version.py") + +__version__ = re.search( + r'__version__\s*=\s*[\'"]([^\'"]*)[\'"]', # It excludes inline comment too + io.open(version_path, encoding='utf_8_sig').read() + ).group(1) + + includes = [os.path.join(ROOT,"Include"),os.path.join(ROOT,"PrivateInclude"),os.path.join("PythonWrapper","cmsisdsp_pkg","src")] if sys.platform == 'win32': @@ -153,13 +162,8 @@ def build(): print('setup.py: Error: This package only supports Python 3.', file=sys.stderr) sys.exit(1) - main_ns = {} - ver_path = convert_path(os.path.join("cmsisdsp","version.py")) - with open(ver_path) as ver_file: - exec(ver_file.read(), main_ns) - setup (name = 'cmsisdsp', - version = main_ns['__version__'], + version = __version__, packages=["cmsisdsp"], description = 'CMSIS-DSP Python API', long_description=open("PythonWrapper_README.md").read(), @@ -181,7 +185,7 @@ def build(): moduleWindow ], include_package_data=True, - author = 'Copyright (C) 2010-2023 ARM Limited or its affiliates. All rights reserved.', + author = 'Copyright (C) 2010-2024 ARM Limited or its affiliates. All rights reserved.', author_email = 'christophe.favergeon@arm.com', url="https://github.com/ARM-software/CMSIS-DSP", python_requires='>=3.7', @@ -202,10 +206,6 @@ def build(): keywords=['development','dsp','cmsis','cmsis-dsp','Arm','signal processing','maths','ml','cortex-m','cortex-a'], install_requires=[ 'numpy>=1.22', - 'networkx>=3.0', - 'jinja2>= 3.1.2, <4.0', - 'sympy>=1.7.1', - 'MarkupSafe>=2.1.2, <3.0' ], project_urls={ # Optional 'Bug Reports': 'https://github.com/ARM-software/CMSIS-DSP/issues',