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