[原创] 在 SensorTile 中使用 CMSIS DSP 库加速科学计算

sigue_vivo   2017-4-10 13:46 楼主
我们的题目核心是使用 SensorTile 实现音频处理。

在音频处理、电机控制等很多应用中经常会用到一些常见的正余弦,矩阵计算,FFT等一些DSP函数。提到DSP库,通常会想到使用ARM 公司提供的 CMSIS 库。CMSIS 库是ARM和一些半导体厂家针对Cortex-M系列制定的一套接口标准,包括针对内核操作的CMSIS-CORE API,针对DSP应用的CMSIS-DSP Library,针对RTOS的CMSIS-RTOS API,与外设接口的CMSIS-SVD以及提供Debug访问接口的CMSIS-DAP。 其中,又以DSP应用的CMSIS-DSP 库的应用最为广泛。针对Cortex-M4中的DSP功能,CMSIS-DSP部分提供了超过60多种功能的DSP算法库,尤其是随着Cortex-M4中集成了FPU硬件单元,CMSIS-DSP 库的应用也越来越广泛。

在KEIL 中集成了对CMSIS的支持,以下将阐述如何在 Keil uv5 项目中引入 DSP 库,以及开始使用。
1. 引入 CMSIS-DSP .lib 文件

Keil uv5 已经简化了许多步骤,只需要从运行时环境管理界面里,勾选 CMSIS DSP 就可以。
如果使用的是老版本 Keil,则手动找到并引入 arm_cortexM4lf_math.lib 即可。

1.jpg

2.jpg

2. 设置宏定义。

在项目选项窗口→C/C++→Define 中添加: ARM_MATH_CM4,__FPU_PRESENT=1
这段的意思是使用 Cortex-M4 的 指令集加速计算。此外,由于 SensorTile 采用的 STM32L4 含有 FPU(浮点数硬件加速单元),可以用此大大提升浮点数的计算速度。
注意分隔符(逗号)!
3.jpg


3. 开发程序

编写算法代码时,需要引入两个头文件(第二个主要是为 FFT 准备的,若不需要,可以省略):

  1. #include <arm_math.h>
  2. #include <arm_const_structs.h>


如果是使用第一步中的方法引入的 DSP 库,则能够自动解决头文件路径问题,否则……自己把头文件路径添加到工程选项里吧。

接下来就可以愉快地使用 CMSIS DSP 库快速地完成一些科学运算了。
在 Keil 安装文件夹下有一个 CMSIS\DSP_Lib\Examples,可以找到一些使用例子。
https://www.keil.com/pack/doc/CMSIS/DSP/html/modules.html 可以找到API使用手册。

以下是一个简单的矩阵运算例子,涉及到了矩阵的 转置、求逆、类似MATLAB的“点乘” 以及 DSP矩阵的初始化:

  1. /** \example arm_matrix_example_f32.c
  2.   */

  3. #include "arm_math.h"
  4. #include "math_helper.h"

  5. #define SNR_THRESHOLD   90

  6. /* --------------------------------------------------------------------------------
  7. * Test input data(Cycles) taken from FIR Q15 module for differant cases of blockSize
  8. * and tapSize
  9. * --------------------------------------------------------------------------------- */

  10. const float32_t B_f32[4] =
  11. {
  12.   782.0, 7577.0, 470.0, 4505.0
  13. };

  14. /* --------------------------------------------------------------------------------
  15. * Formula to fit is  C1 + C2 * numTaps + C3 * blockSize + C4 * numTaps * blockSize
  16. * -------------------------------------------------------------------------------- */

  17. const float32_t A_f32[16] =
  18. {
  19.   /* Const,   numTaps,   blockSize,   numTaps*blockSize */
  20.   1.0,     32.0,      4.0,     128.0,
  21.   1.0,     32.0,     64.0,    2048.0,
  22.   1.0,     16.0,      4.0,      64.0,
  23.   1.0,     16.0,     64.0,    1024.0,
  24. };


  25. /* ----------------------------------------------------------------------
  26. * Temporary buffers  for storing intermediate values
  27. * ------------------------------------------------------------------- */
  28. /* Transpose of A Buffer */
  29. float32_t AT_f32[16];
  30. /* (Transpose of A * A) Buffer */
  31. float32_t ATMA_f32[16];
  32. /* Inverse(Transpose of A * A)  Buffer */
  33. float32_t ATMAI_f32[16];
  34. /* Test Output Buffer */
  35. float32_t X_f32[4];

  36. /* ----------------------------------------------------------------------
  37. * Reference ouput buffer C1, C2, C3 and C4 taken from MATLAB
  38. * ------------------------------------------------------------------- */
  39. const float32_t xRef_f32[4] = {73.0, 8.0, 21.25, 2.875};

  40. float32_t snr;


  41. /* ----------------------------------------------------------------------
  42. * Max magnitude FFT Bin test
  43. * ------------------------------------------------------------------- */

  44. int32_t main(void)
  45. {

  46.   arm_matrix_instance_f32 A;      /* Matrix A Instance */
  47.   arm_matrix_instance_f32 AT;     /* Matrix AT(A transpose) instance */
  48.   arm_matrix_instance_f32 ATMA;   /* Matrix ATMA( AT multiply with A) instance */
  49.   arm_matrix_instance_f32 ATMAI;  /* Matrix ATMAI(Inverse of ATMA) instance */
  50.   arm_matrix_instance_f32 B;      /* Matrix B instance */
  51.   arm_matrix_instance_f32 X;      /* Matrix X(Unknown Matrix) instance */

  52.   uint32_t srcRows, srcColumns;  /* Temporary variables */
  53.   arm_status status;

  54.   /* Initialise A Matrix Instance with numRows, numCols and data array(A_f32) */
  55.   srcRows = 4;
  56.   srcColumns = 4;
  57.   arm_mat_init_f32(&A, srcRows, srcColumns, (float32_t *)A_f32);

  58.   /* Initialise Matrix Instance AT with numRows, numCols and data array(AT_f32) */
  59.   srcRows = 4;
  60.   srcColumns = 4;
  61.   arm_mat_init_f32(&AT, srcRows, srcColumns, AT_f32);

  62.   /* calculation of A transpose */
  63.   status = arm_mat_trans_f32(&A, &AT);


  64.   /* Initialise ATMA Matrix Instance with numRows, numCols and data array(ATMA_f32) */
  65.   srcRows = 4;
  66.   srcColumns = 4;
  67.   arm_mat_init_f32(&ATMA, srcRows, srcColumns, ATMA_f32);

  68.   /* calculation of AT Multiply with A */
  69.   status = arm_mat_mult_f32(&AT, &A, &ATMA);

  70.   /* Initialise ATMAI Matrix Instance with numRows, numCols and data array(ATMAI_f32) */
  71.   srcRows = 4;
  72.   srcColumns = 4;
  73.   arm_mat_init_f32(&ATMAI, srcRows, srcColumns, ATMAI_f32);

  74.   /* calculation of Inverse((Transpose(A) * A) */
  75.   status = arm_mat_inverse_f32(&ATMA, &ATMAI);

  76.   /* calculation of (Inverse((Transpose(A) * A)) *  Transpose(A)) */
  77.   status = arm_mat_mult_f32(&ATMAI, &AT, &ATMA);

  78.   /* Initialise B Matrix Instance with numRows, numCols and data array(B_f32) */
  79.   srcRows = 4;
  80.   srcColumns = 1;
  81.   arm_mat_init_f32(&B, srcRows, srcColumns, (float32_t *)B_f32);

  82.   /* Initialise X Matrix Instance with numRows, numCols and data array(X_f32) */
  83.   srcRows = 4;
  84.   srcColumns = 1;
  85.   arm_mat_init_f32(&X, srcRows, srcColumns, X_f32);

  86.   /* calculation ((Inverse((Transpose(A) * A)) *  Transpose(A)) * B) */
  87.   status = arm_mat_mult_f32(&ATMA, &B, &X);

  88.   /* Comparison of reference with test output */
  89.   snr = arm_snr_f32((float32_t *)xRef_f32, X_f32, 4);

  90.   /*------------------------------------------------------------------------------
  91.   *            Initialise status depending on SNR calculations
  92.   *------------------------------------------------------------------------------*/
  93.   if( snr > SNR_THRESHOLD)
  94.   {
  95.     status = ARM_MATH_SUCCESS;
  96.   }
  97.   else
  98.   {
  99.     status = ARM_MATH_TEST_FAILURE;
  100.   }


  101.   /* ----------------------------------------------------------------------
  102.   ** Loop here if the signals fail the PASS check.
  103.   ** This denotes a test failure
  104.   ** ------------------------------------------------------------------- */
  105.   if( status != ARM_MATH_SUCCESS)
  106.   {
  107.     while(1);
  108.   }

  109.   while(1);                             /* main function does not return */
  110. }

回复评论 (3)

感觉你发的帖子与众不同,看看你做的项目原来是蝴蝶结变声器,是类似柯南的那个吗?
点赞  2017-4-11 08:12
高端啊,长见识!!
点赞  2017-4-11 14:26
引用: nmg 发表于 2017-4-11 08:12
感觉你发的帖子与众不同,看看你做的项目原来是蝴蝶结变声器,是类似柯南的那个吗?

目标是那个效果,但是还是有点偏差,只能实现一部分了……
点赞  2017-4-12 00:03
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复