api.rst 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. API
  2. ===
  3. .. highlight:: python
  4. The idea is to follow as closely as possible the CMSIS-DSP API to ease the migration to the final implementation on a board.
  5. First you need to import the module::
  6. import cmsisdsp as dsp
  7. If you use numpy::
  8. import numpy as np
  9. If you use scipy signal processing functions::
  10. from scipy import signal
  11. Standard APIs
  12. *************
  13. .. code-block:: C
  14. void arm_add_f32(
  15. const float32_t * pSrcA,
  16. const float32_t * pSrcB,
  17. float32_t * pDst,
  18. uint32_t blockSize);
  19. .. py:function:: dsp.arm_add_f32(pSrcA,pSrcB)
  20. Return a list of random ingredients as strings.
  21. :param pSrcA: array.
  22. :type pSrcA: NumPy array
  23. :param pSrcB: array.
  24. :type pSrcB: NumPy array
  25. :return: array.
  26. :rtype: NumPy array
  27. Example::
  28. import cmsisdsp as dsp
  29. r = dsp.arm_add_f32([1.,2,3],[4.,5,7])
  30. You can use a CMSIS-DSP function with numpy arrays: ::
  31. r = dsp.arm_add_f32(np.array([1.,2,3]),np.array([4.,5,7]))
  32. The result of a CMSIS-DSP function will always be a numpy array whatever the arguments were (numpy array or list).
  33. Functions with instance arguments
  34. *********************************
  35. When the CMSIS-DSP function is requiring an instance data structure, it is just a bit more complex to use it:
  36. First you need to create this instance::
  37. import cmsisdsp as dsp
  38. firf32 = dsp.arm_fir_instance_f32()
  39. .. code-block:: C
  40. void arm_fir_init_f32(
  41. arm_fir_instance_f32 * S,
  42. uint16_t numTaps,
  43. const float32_t * pCoeffs,
  44. float32_t * pState,
  45. uint32_t blockSize);
  46. .. py:function:: dsp.arm_fir_init_f32(S,numTaps,pCoeffs,pState)
  47. Return a list of random ingredients as strings.
  48. :param S: f32 instance.
  49. :type S: int
  50. :param pCoeffs: array.
  51. :type pCoeffs: NumPy array
  52. :param pState: array.
  53. :type pState: NumPy array
  54. :return: array.
  55. :rtype: NumPy array
  56. Example of use::
  57. dsp.arm_fir_init_f32(firf32,3,[1.,2,3],[0,0,0,0,0,0,0])
  58. 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.
  59. Since the goal is to be as close as possible to the C API, the API is forcing the use of this argument.
  60. 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.
  61. Now, you can check that the instance was initialized correctly::
  62. .. code-block:: python
  63. print(firf32.numTaps())
  64. The filter can then be called:
  65. .. code-block:: C
  66. void arm_fir_f32(
  67. const arm_fir_instance_f32 * S,
  68. const float32_t * pSrc,
  69. float32_t * pDst,
  70. uint32_t blockSize);
  71. .. py:function:: dsp.arm_fir_f32(S,pSrc)
  72. Return a list of random ingredients as strings.
  73. :param S: f32 instance.
  74. :type S: int
  75. :param pSrc: array of input samples.
  76. :type pSrc: NumPy array
  77. :return: array.
  78. :rtype: NumPy array
  79. Then, you can filter with CMSIS-DSP::
  80. print(dsp.arm_fir_f32(firf32,[1,2,3,4,5]))
  81. 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.
  82. 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::
  83. print(dsp.arm_fir_f32(firf32,[6,7,8,9,10]))
  84. If you want to compare with scipy it is easy but warning : coefficients for the filter are in opposite order in scipy ::
  85. filtered_x = signal.lfilter([3,2,1.], 1.0, [1,2,3,4,5,6,7,8,9,10])
  86. print(filtered_x)
  87. FFT
  88. ***
  89. The CMSIS-DSP cfft is requiring complex signals with a specific layout in memory.
  90. 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. A function like the bewlo one can be used::
  91. def imToReal1D(a):
  92. ar=np.zeros(np.array(a.shape) * 2)
  93. ar[0::2]=a.real
  94. ar[1::2]=a.imag
  95. return(ar)
  96. In 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::
  97. def realToIm1D(ar):
  98. return(ar[0::2] + 1j * ar[1::2])
  99. Then, the utilisation of the API si very similar to what was done for the FIR example:
  100. Then, you create the FFT instance with::
  101. cfftf32=dsp.arm_cfft_instance_f32()
  102. You initialize the instance with the init function ::
  103. status=dsp.arm_cfft_init_f32(cfftf32, nb)
  104. print(status)
  105. You convert the complex signal to the format expected by the wrapper::
  106. signalR = imToReal1D(signal)
  107. You compute the FFT of the signal with::
  108. resultR = dsp.arm_cfft_f32(cfftf32,signalR,0,1)
  109. You convert back to a complex format to compare with scipy::
  110. resultI = realToIm1D(resultR)
  111. print(resultI)
  112. Matrix
  113. ******
  114. 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).
  115. So to use a CMSIS-DSP matrix function, it is very simple::
  116. a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]])
  117. b=np.array([[1.,2,3],[5.1,6,7],[9.1,10,11],[5,8,4]])
  118. Numpy result as reference::
  119. print(np.dot(a , b))
  120. CMSIS-DSP result::
  121. v=dsp.arm_mat_mult_f32(a,b)
  122. print(v)
  123. 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.
  124. The C API is:
  125. .. code-block:: C
  126. arm_status arm_mat_mult_f32(
  127. const arm_matrix_instance_f32 * pSrcA,
  128. const arm_matrix_instance_f32 * pSrcB,
  129. arm_matrix_instance_f32 * pDst);
  130. The Python API is:
  131. .. py:function:: dsp.arm_mat_mult_f32(pSrcA,pSrcB)
  132. Return the matrix product pSrcA * pSrcB
  133. :param pSrcA: array of input samples.
  134. :type pSrcA: NumPy array
  135. :param pSrcB: array of input samples.
  136. :type pSrcB: NumPy array
  137. :return: the matrix product.
  138. :rtype: NumPy array