1API 2=== 3 4.. highlight:: python 5 6The idea is to follow as closely as possible the CMSIS-DSP API to ease the migration to the final implementation on a board. 7 8First you need to import the module:: 9 10 import cmsisdsp as dsp 11 12If you use numpy:: 13 14 import numpy as np 15 16If you use scipy signal processing functions:: 17 18 from scipy import signal 19 20 21Standard APIs 22************* 23 24.. code-block:: C 25 26 void arm_add_f32( 27 const float32_t * pSrcA, 28 const float32_t * pSrcB, 29 float32_t * pDst, 30 uint32_t blockSize); 31 32.. py:function:: dsp.arm_add_f32(pSrcA,pSrcB) 33 34 Return a list of random ingredients as strings. 35 36 :param pSrcA: array. 37 :type pSrcA: NumPy array 38 :param pSrcB: array. 39 :type pSrcB: NumPy array 40 :return: array. 41 :rtype: NumPy array 42 43Example:: 44 45 import cmsisdsp as dsp 46 47 r = dsp.arm_add_f32([1.,2,3],[4.,5,7]) 48 49You can use a CMSIS-DSP function with numpy arrays: :: 50 51 r = dsp.arm_add_f32(np.array([1.,2,3]),np.array([4.,5,7])) 52 53The result of a CMSIS-DSP function will always be a numpy array whatever the arguments were (numpy array or list). 54 55Functions with instance arguments 56********************************* 57 58When the CMSIS-DSP function is requiring an instance data structure, it is just a bit more complex to use it: 59 60First you need to create this instance:: 61 62 import cmsisdsp as dsp 63 64 firf32 = dsp.arm_fir_instance_f32() 65 66.. code-block:: C 67 68 void arm_fir_init_f32( 69 arm_fir_instance_f32 * S, 70 uint16_t numTaps, 71 const float32_t * pCoeffs, 72 float32_t * pState, 73 uint32_t blockSize); 74 75 76.. py:function:: dsp.arm_fir_init_f32(S,numTaps,pCoeffs,pState) 77 78 Return a list of random ingredients as strings. 79 80 :param S: f32 instance. 81 :type S: int 82 :param pCoeffs: array. 83 :type pCoeffs: NumPy array 84 :param pState: array. 85 :type pState: NumPy array 86 :return: array. 87 :rtype: NumPy array 88 89Example of use:: 90 91 dsp.arm_fir_init_f32(firf32,3,[1.,2,3],[0,0,0,0,0,0,0]) 92 93The 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. 94 95Since the goal is to be as close as possible to the C API, the API is forcing the use of this argument. 96 97The 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. 98 99Now, you can check that the instance was initialized correctly:: 100 101.. code-block:: python 102 103 print(firf32.numTaps()) 104 105The filter can then be called: 106 107.. code-block:: C 108 109 void arm_fir_f32( 110 const arm_fir_instance_f32 * S, 111 const float32_t * pSrc, 112 float32_t * pDst, 113 uint32_t blockSize); 114 115.. py:function:: dsp.arm_fir_f32(S,pSrc) 116 117 Return a list of random ingredients as strings. 118 119 :param S: f32 instance. 120 :type S: int 121 :param pSrc: array of input samples. 122 :type pSrc: NumPy array 123 :return: array. 124 :rtype: NumPy array 125 126Then, you can filter with CMSIS-DSP:: 127 128 print(dsp.arm_fir_f32(firf32,[1,2,3,4,5])) 129 130The 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. 131 132If 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:: 133 134 print(dsp.arm_fir_f32(firf32,[6,7,8,9,10])) 135 136If you want to compare with scipy it is easy but warning : coefficients for the filter are in opposite order in scipy :: 137 138 filtered_x = signal.lfilter([3,2,1.], 1.0, [1,2,3,4,5,6,7,8,9,10]) 139 print(filtered_x) 140 141FFT 142*** 143 144The CMSIS-DSP cfft is requiring complex signals with a specific layout in memory. 145 146To 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. A function like the bewlo one can be used:: 147 148 def imToReal1D(a): 149 ar=np.zeros(np.array(a.shape) * 2) 150 ar[0::2]=a.real 151 ar[1::2]=a.imag 152 return(ar) 153 154In the same way, the return array from the CMSIS-DSP FFT will not be containing complex Python scalars. It must be converted back with a function like:: 155 156 def realToIm1D(ar): 157 return(ar[0::2] + 1j * ar[1::2]) 158 159Then, the utilisation of the API si very similar to what was done for the FIR example: 160 161Then, you create the FFT instance with:: 162 163 cfftf32=dsp.arm_cfft_instance_f32() 164 165You initialize the instance with the init function :: 166 167 status=dsp.arm_cfft_init_f32(cfftf32, nb) 168 print(status) 169 170You convert the complex signal to the format expected by the wrapper:: 171 172 signalR = imToReal1D(signal) 173 174You compute the FFT of the signal with:: 175 176 resultR = dsp.arm_cfft_f32(cfftf32,signalR,0,1) 177 178You convert back to a complex format to compare with scipy:: 179 180 resultI = realToIm1D(resultR) 181 print(resultI) 182 183Matrix 184****** 185 186For 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). 187 188So to use a CMSIS-DSP matrix function, it is very simple:: 189 190 a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]]) 191 b=np.array([[1.,2,3],[5.1,6,7],[9.1,10,11],[5,8,4]]) 192 193Numpy result as reference:: 194 195 print(np.dot(a , b)) 196 197CMSIS-DSP result:: 198 199 v=dsp.arm_mat_mult_f32(a,b) 200 print(v) 201 202In a real C code, a pointer to a data structure for the result v would have to be passed as argument of the function. 203 204The C API is: 205 206.. code-block:: C 207 208 arm_status arm_mat_mult_f32( 209 const arm_matrix_instance_f32 * pSrcA, 210 const arm_matrix_instance_f32 * pSrcB, 211 arm_matrix_instance_f32 * pDst); 212 213The Python API is: 214 215 216.. py:function:: dsp.arm_mat_mult_f32(pSrcA,pSrcB) 217 218 Return the matrix product pSrcA * pSrcB 219 220 :param pSrcA: array of input samples. 221 :type pSrcA: NumPy array 222 :param pSrcB: array of input samples. 223 :type pSrcB: NumPy array 224 :return: the matrix product. 225 :rtype: NumPy array