微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 第9章 BasicMathFunctions的使用(二)

第9章 BasicMathFunctions的使用(二)

时间:10-02 整理:3721RD 点击:
第9章  BasicMathFunctions的使用(二)

    本期教程主要讲基本函数中的相反数,偏移,位移,减法和比例因子。

    9.1 相反数(VectorNegate)

    9.2 求和(VectorOffset)

    9.3 点乘(VectorShift)

    9.4 减法(VectorSub)

    9.5 比例因子(VectorScale)

    9.6 BasicMathFunctions的重要说明

    9.7 总结


9.1  相反数(Vector Negate)

    这部分函数主要用于求相反数,公式描述如下:

      pDst[n] = -pSrc[n],   0 <= n < blockSize.   

    特别注意,这部分函数支持目标指针和源指针指向相同的缓冲区。


9.1.1  arm_negate_f32

    这个函数用于求32位浮点数的相反数,源代码分析如下:

  1. /**      
  2. * @brief  Negates the elements of a floating-point vector.      
  3. * @param[in]  *pSrc points to the input vector      
  4. * @param[out]  *pDst points to the output vector      
  5. * @param[in]  blockSize number of samples in the vector      
  6. * [url=home.php?mod=space&uid=1141835]@Return[/url] none.      
  7. */

  8. void arm_negate_f32(
  9.   float32_t * pSrc,
  10.   float32_t * pDst,
  11.   uint32_t blockSize)
  12. {
  13.   uint32_t blkCnt;                               /* loop counter */


  14. #ifndef ARM_MATH_CM0_FAMILY

  15. /* Run the below code for Cortex-M4 and Cortex-M3 */
  16.   float32_t in1, in2, in3, in4;                  /* temporary variables */

  17.   /*loop Unrolling */
  18.   blkCnt = blockSize >> 2u;

  19.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.      
  20.    ** a second loop below computes the remaining 1 to 3 samples. */
  21.   while(blkCnt > 0u)
  22.   {
  23.     /* read inputs from source */
  24.     in1 = *pSrc;
  25.     in2 = *(pSrc + 1);
  26.     in3 = *(pSrc + 2);
  27.     in4 = *(pSrc + 3);

  28.     /* negate the input */                                                                            (1)
  29.     in1 = -in1;
  30.     in2 = -in2;
  31.     in3 = -in3;
  32.     in4 = -in4;

  33.     /* store the result to destination */
  34.     *pDst = in1;
  35.     *(pDst + 1) = in2;
  36.     *(pDst + 2) = in3;
  37.     *(pDst + 3) = in4;

  38.     /* update pointers to process next samples */
  39.     pSrc += 4u;
  40.     pDst += 4u;

  41.     /* Decrement the loop counter */
  42.     blkCnt--;
  43.   }

  44.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.      
  45.    ** No loop unrolling is used. */
  46.   blkCnt = blockSize % 0x4u;

  47. #else

  48.   /* Run the below code for Cortex-M0 */

  49.   /* Initialize blkCnt with number of samples */
  50.   blkCnt = blockSize;

  51. #endif /* #ifndef ARM_MATH_CM0_FAMILY */

  52.   while(blkCnt > 0u)
  53.   {
  54.     /* C = -A */
  55.     /* Negate and then store the results in the destination buffer. */
  56.     *pDst++ = -*pSrc++;

  57.     /* Decrement the loop counter */
  58.     blkCnt--;
  59.   }
  60. }

复制代码

1.     浮点数的相反数求解比较简单,直接在相应的变量前加上负号即可。


9.1.2  arm_negate_q31

    这个函数用于求32位定点数的相反数,源代码分析如下:

  1. /**   
  2. * @brief  Negates the elements of a Q31 vector.   
  3. * @param[in]  *pSrc points to the input vector   
  4. * @param[out]  *pDst points to the output vector   
  5. * @param[in]  blockSize number of samples in the vector   
  6. * @return none.   
  7. *   
  8. * <b>Scaling and Overflow Behavior:</b>                                                             (1)
  9. * \par   
  10. * The function uses saturating arithmetic.   
  11. * The Q31 value -1 (0x80000000) will be saturated to the maximum allowable positive value 0x7FFFFFFF.   
  12. */

  13. void arm_negate_q31(
  14.   q31_t * pSrc,
  15.   q31_t * pDst,
  16.   uint32_t blockSize)
  17. {
  18.   q31_t in;                                      /* Temporary variable */
  19.   uint32_t blkCnt;                               /* loop counter */

  20. #ifndef ARM_MATH_CM0_FAMILY

  21. /* Run the below code for Cortex-M4 and Cortex-M3 */
  22.   q31_t in1, in2, in3, in4;

  23.   /*loop Unrolling */
  24.   blkCnt = blockSize >> 2u;

  25.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  26.    ** a second loop below computes the remaining 1 to 3 samples. */
  27.   while(blkCnt > 0u)
  28.   {
  29.     /* C = -A */
  30.     /* Negate and then store the results in the destination buffer. */
  31.     in1 = *pSrc++;
  32.     in2 = *pSrc++;
  33.     in3 = *pSrc++;
  34.     in4 = *pSrc++;

  35.     *pDst++ = __QSUB(0, in1);                                                                      (2)
  36.     *pDst++ = __QSUB(0, in2);
  37.     *pDst++ = __QSUB(0, in3);
  38.     *pDst++ = __QSUB(0, in4);

  39.     /* Decrement the loop counter */
  40.     blkCnt--;
  41.   }

  42.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  43.    ** No loop unrolling is used. */
  44.   blkCnt = blockSize % 0x4u;

  45. #else

  46.   /* Run the below code for Cortex-M0 */

  47.   /* Initialize blkCnt with number of samples */
  48.   blkCnt = blockSize;

  49. #endif /* #ifndef ARM_MATH_CM0_FAMILY */


  50.   while(blkCnt > 0u)
  51.   {
  52.     /* C = -A */
  53.     /* Negate and then store the result in the destination buffer. */
  54.     in = *pSrc++;
  55.     *pDst++ = (in == INT32_MIN) ? INT32_MAX : -in;

  56.     /* Decrement the loop counter */
  57.     blkCnt--;
  58.   }
  59. }

复制代码

1.     这个函数使用了饱和运算。

    饱和运算数值0x80000000将变成0x7FFFFFFF。

2.     饱和运算__QSUB我们在上一章已经详细讲述了,这就就是实现数值0减去相应的参数变量。


9.1.3  arm_negate_q15

    这个函数用于求16位定点数的相反数,源代码分析如下:

  1. /**      
  2. * @brief  Negates the elements of a Q15 vector.      
  3. * @param[in]  *pSrc points to the input vector      
  4. * @param[out]  *pDst points to the output vector      
  5. * @param[in]  blockSize number of samples in the vector      
  6. * @return none.      
  7. *   
  8. * \par Conditions for optimum performance   
  9. *  Input and output buffers should be aligned by 32-bit   
  10. *   
  11. *      
  12. * <b>Scaling and Overflow Behavior:</b>                                                             (1)
  13. * \par      
  14. * The function uses saturating arithmetic.      
  15. * The Q15 value -1 (0x8000) will be saturated to the maximum allowable positive value 0x7FFF.      
  16. */

  17. void arm_negate_q15(
  18.   q15_t * pSrc,
  19.   q15_t * pDst,
  20.   uint32_t blockSize)
  21. {
  22.   uint32_t blkCnt;                               /* loop counter */
  23.   q15_t in;

  24. #ifndef ARM_MATH_CM0_FAMILY

  25. /* Run the below code for Cortex-M4 and Cortex-M3 */

  26.   q31_t in1, in2;                                /* Temporary variables */


  27.   /*loop Unrolling */
  28.   blkCnt = blockSize >> 2u;

  29.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.      
  30.    ** a second loop below computes the remaining 1 to 3 samples. */
  31.   while(blkCnt > 0u)
  32.   {
  33.     /* C = -A */
  34.     /* Read two inputs at a time */                                                                  (2)
  35.     in1 = _SIMD32_OFFSET(pSrc);
  36.     in2 = _SIMD32_OFFSET(pSrc + 2);

  37.     /* negate two samples at a time */                                                               (3)
  38.     in1 = __QSUB16(0, in1);

  39.     /* negate two samples at a time */
  40.     in2 = __QSUB16(0, in2);

  41.     /* store the result to destination 2 samples at a time */                                        (4)
  42.     _SIMD32_OFFSET(pDst) = in1;
  43.     /* store the result to destination 2 samples at a time */
  44.     _SIMD32_OFFSET(pDst + 2) = in2;


  45.     /* update pointers to process next samples */
  46.     pSrc += 4u;
  47.     pDst += 4u;

  48.     /* Decrement the loop counter */
  49.     blkCnt--;
  50.   }

  51.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.      
  52.    ** No loop unrolling is used. */
  53.   blkCnt = blockSize % 0x4u;

  54. #else

  55.   /* Run the below code for Cortex-M0 */

  56.   /* Initialize blkCnt with number of samples */
  57.   blkCnt = blockSize;

  58. #endif /* #ifndef ARM_MATH_CM0_FAMILY */

  59.   while(blkCnt > 0u)
  60.   {
  61.     /* C = -A */
  62.     /* Negate and then store the result in the destination buffer. */
  63.     in = *pSrc++;
  64.     *pDst++ = (in == (q15_t) 0x8000) ? 0x7fff : -in;

  65.     /* Decrement the loop counter */
  66.     blkCnt--;
  67.   }
  68. }

复制代码

1.     这个函数使用了饱和运算。

    饱和运算数值0x8000将变成0x7FFF。

2.     一次读取两个Q15格式的数据。

3.     由于__QSUB是SIMD指令,这里可以实现一次计算两个Q15数据的相反数。

4.     这里实现一次赋值两个Q15数据。


9.1.4  arm_negate_q7

    这个函数用于求8位定点数的相反数,源代码分析如下:

  1. /**   
  2. * @brief  Negates the elements of a Q7 vector.   
  3. * @param[in]  *pSrc points to the input vector   
  4. * @param[out]  *pDst points to the output vector   
  5. * @param[in]  blockSize number of samples in the vector   
  6. * @return none.   
  7. *   
  8. * <b>Scaling and Overflow Behavior:</b>                                                              (1)
  9. * \par   
  10. * The function uses saturating arithmetic.   
  11. * The Q7 value -1 (0x80) will be saturated to the maximum allowable positive value 0x7F.   
  12. */

  13. void arm_negate_q7(
  14.   q7_t * pSrc,
  15.   q7_t * pDst,
  16.   uint32_t blockSize)
  17. {
  18.   uint32_t blkCnt;                               /* loop counter */
  19.   q7_t in;

  20. #ifndef ARM_MATH_CM0_FAMILY

  21. /* Run the below code for Cortex-M4 and Cortex-M3 */
  22.   q31_t input;                                   /* Input values1-4 */
  23.   q31_t zero = 0x00000000;                                                                           (2)


  24.   /*loop Unrolling */
  25.   blkCnt = blockSize >> 2u;

  26.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  27.    ** a second loop below computes the remaining 1 to 3 samples. */
  28.   while(blkCnt > 0u)
  29.   {
  30.     /* C = -A */
  31.     /* Read four inputs */
  32.     input = *__SIMD32(pSrc)++;                                                                        (3)

  33.     /* Store the Negated results in the destination buffer in a single cycle by packing the results */
  34.     *__SIMD32(pDst)++ = __QSUB8(zero, input);                                                         (4)

  35.     /* Decrement the loop counter */
  36.     blkCnt--;
  37.   }

  38.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  39.    ** No loop unrolling is used. */
  40.   blkCnt = blockSize % 0x4u;

  41. #else

  42.   /* Run the below code for Cortex-M0 */

  43.   /* Initialize blkCnt with number of samples */
  44.   blkCnt = blockSize;

  45. #endif /* #ifndef ARM_MATH_CM0_FAMILY */

  46.   while(blkCnt > 0u)
  47.   {
  48.     /* C = -A */
  49.     /* Negate and then store the results in the destination buffer. */ \
  50.       in = *pSrc++;
  51.     *pDst++ = (in == (q7_t) 0x80) ? 0x7f : -in;

  52.     /* Decrement the loop counter */
  53.     blkCnt--;
  54.   }
  55. }

复制代码

1.     这个函数使用了饱和运算。

    饱和运算数值0x80将变成0x7F。

2.     给局部变量赋初值,防止默认初始值不是0,所以从某种意义上来说,给变量赋初值是很有必要的。

3.     一次读取4个Q7格式的数据到input里面。

4.     通过__QSUB8实现一次计算四个Q7格式数据的相反数。


9.1.5  实例讲解

实验目的:

    1. 四种类型数据的相反数。

实验内容:

    1. 按下K1键, 串口打印输出结果

实验现象:

           通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:




程序设计:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DSP_Negate
  4. *    功能说明: 求相反数
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DSP_Negate(void)
  10. {
  11.      static float32_t pSrc;
  12.     static float32_t pDst;
  13.    
  14.      static q31_t pSrc1;
  15.      static q31_t pDst1;
  16.    
  17.      static q15_t pSrc2;
  18.      static q15_t pDst2;
  19.    
  20.      static q7_t pSrc3 = 127; /* 为了说明问题,在这里设置初始值为127,然后查看0x80是否饱和为0x7F */
  21.      static q7_t pDst3;
  22.    
  23.    
  24.      pSrc -= 1.23f;
  25.      arm_negate_f32(&pSrc, &pDst, 1);
  26.      printf("arm_negate_f32 = %f\r\n", pDst);

  27.      pSrc1 -= 1;
  28.      arm_negate_q31(&pSrc1, &pDst1, 1);
  29.      printf("arm_negate_q31 = %d\r\n", pDst1);

  30.      pSrc2 -= 1;
  31.      arm_negate_q15(&pSrc2, &pDst2, 1);
  32.      printf("arm_negate_q15 = %d\r\n", pDst2);

  33.      pSrc3 += 1;
  34.      arm_negate_q7(&pSrc3, &pDst3, 1);
  35.      printf("arm_negate_q7 = %d\r\n", pDst3);
  36.      printf("***********************************\r\n");
  37. }

复制代码



9.2  偏移(Vector Offset)

    这部分函数主要用于求相反数,公式描述如下:

      pDst[n] = pSrc[n] + offset,   0 <= n < blockSize.

        注意,这部分函数支持目标指针和源指针指向相同的缓冲区。


9.2.1  arm_offset_f32

    这个函数用于求32位浮点数的偏移,源代码分析如下:

  1. /**      
  2. * @brief  Adds a constant offset to a floating-point vector.      
  3. * @param[in]  *pSrc points to the input vector      
  4. * @param[in]  offset is the offset to be added      
  5. * @param[out]  *pDst points to the output vector      
  6. * @param[in]  blockSize number of samples in the vector      
  7. * @return none.      
  8. */
  9. void arm_offset_f32(
  10.   float32_t * pSrc,
  11.   float32_t offset,
  12.   float32_t * pDst,
  13.   uint32_t blockSize)
  14. {
  15.   uint32_t blkCnt;                               /* loop counter */

  16. #ifndef ARM_MATH_CM0_FAMILY

  17. /* Run the below code for Cortex-M4 and Cortex-M3 */
  18.   float32_t in1, in2, in3, in4;

  19.   /*loop Unrolling */
  20.   blkCnt = blockSize >> 2u;

  21.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.      
  22.    ** a second loop below computes the remaining 1 to 3 samples. */
  23.   while(blkCnt > 0u)
  24.   {
  25.     /* C = A + offset */                                                                            (1)
  26.     /* Add offset and then store the results in the destination buffer. */
  27.     /* read samples from source */
  28.     in1 = *pSrc;
  29.     in2 = *(pSrc + 1);

  30.     /* add offset to input */
  31.     in1 = in1 + offset;

  32.     /* read samples from source */
  33.     in3 = *(pSrc + 2);

  34.     /* add offset to input */
  35.     in2 = in2 + offset;

  36.     /* read samples from source */
  37.     in4 = *(pSrc + 3);

  38.     /* add offset to input */
  39.     in3 = in3 + offset;

  40.     /* store result to destination */
  41.     *pDst = in1;

  42.     /* add offset to input */
  43.     in4 = in4 + offset;

  44.     /* store result to destination */
  45.     *(pDst + 1) = in2;

  46.     /* store result to destination */
  47.     *(pDst + 2) = in3;

  48.     /* store result to destination */
  49.     *(pDst + 3) = in4;

  50.     /* update pointers to process next samples */
  51.     pSrc += 4u;
  52.     pDst += 4u;

  53.     /* Decrement the loop counter */
  54.     blkCnt--;
  55.   }

  56.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.      
  57.    ** No loop unrolling is used. */
  58.   blkCnt = blockSize % 0x4u;

  59. #else

  60.   /* Run the below code for Cortex-M0 */

  61.   /* Initialize blkCnt with number of samples */
  62.   blkCnt = blockSize;

  63. #endif /* #ifndef ARM_MATH_CM0_FAMILY */

  64.   while(blkCnt > 0u)
  65.   {
  66.     /* C = A + offset */
  67.     /* Add offset and then store the result in the destination buffer. */
  68.     *pDst++ = (*pSrc++) + offset;

  69.     /* Decrement the loop counter */
  70.     blkCnt--;
  71.   }
  72. }

复制代码

1.     浮点数的偏移值求解比较简单,加上相应的偏移值并赋值给目标变量即可。


9.2.2  arm_offset_q31

    这个函数用于求32位定点数的偏移值,源代码分析如下:

  1. /**   
  2. * @brief  Adds a constant offset to a Q31 vector.   
  3. * @param[in]  *pSrc points to the input vector   
  4. * @param[in]  offset is the offset to be added   
  5. * @param[out]  *pDst points to the output vector   
  6. * @param[in]  blockSize number of samples in the vector   
  7. * @return none.   
  8. *   
  9. * <b>Scaling and Overflow Behavior:</b>                                                               (1)
  10. * \par   
  11. * The function uses saturating arithmetic.   
  12. * Results outside of the allowable Q31 range [0x80000000 0x7FFFFFFF] are saturated.   
  13. */

  14. void arm_offset_q31(
  15.   q31_t * pSrc,
  16.   q31_t offset,
  17.   q31_t * pDst,
  18.   uint32_t blockSize)
  19. {
  20.   uint32_t blkCnt;                               /* loop counter */

  21. #ifndef ARM_MATH_CM0_FAMILY

  22. /* Run the below code for Cortex-M4 and Cortex-M3 */
  23.   q31_t in1, in2, in3, in4;


  24.   /*loop Unrolling */
  25.   blkCnt = blockSize >> 2u;

  26.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  27.    ** a second loop below computes the remaining 1 to 3 samples. */
  28.   while(blkCnt > 0u)
  29.   {
  30.     /* C = A + offset */
  31.     /* Add offset and then store the results in the destination buffer. */
  32.     in1 = *pSrc++;
  33.     in2 = *pSrc++;
  34.     in3 = *pSrc++;
  35.     in4 = *pSrc++;

  36.     *pDst++ = __QADD(in1, offset);                                                                   (2)
  37.     *pDst++ = __QADD(in2, offset);
  38.     *pDst++ = __QADD(in3, offset);
  39.     *pDst++ = __QADD(in4, offset);

  40.     /* Decrement the loop counter */
  41.     blkCnt--;
  42.   }

  43.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  44.    ** No loop unrolling is used. */
  45.   blkCnt = blockSize % 0x4u;

  46.   while(blkCnt > 0u)
  47.   {
  48.     /* C = A + offset */
  49.     /* Add offset and then store the result in the destination buffer. */
  50.     *pDst++ = __QADD(*pSrc++, offset);

  51.     /* Decrement the loop counter */
  52.     blkCnt--;
  53.   }

  54. #else

  55.   /* Run the below code for Cortex-M0 */

  56.   /* Initialize blkCnt with number of samples */
  57.   blkCnt = blockSize;

  58.   while(blkCnt > 0u)
  59.   {
  60.     /* C = A + offset */
  61.     /* Add offset and then store the result in the destination buffer. */
  62.     *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrc++ + offset);

  63.     /* Decrement the loop counter */
  64.     blkCnt--;
  65.   }

  66. #endif /* #ifndef ARM_MATH_CM0_FAMILY */

  67. }

复制代码

1.     这个函数使用了饱和运算。

    饱和运算数值0x80000000将变成0x7FFFFFFF。

2.     指令__QADD我们在上章教程中已经讲解过,这里是实现两个参数相加。


9.2.3  arm_offset_q15

    这个函数用于求16位定点数的偏移,源代码分析如下:

  1. /**   
  2. * @brief  Adds a constant offset to a Q15 vector.   
  3. * @param[in]  *pSrc points to the input vector   
  4. * @param[in]  offset is the offset to be added   
  5. * @param[out]  *pDst points to the output vector   
  6. * @param[in]  blockSize number of samples in the vector   
  7. * @return none.   
  8. *   
  9. * <b>Scaling and Overflow Behavior:</b>                                                             (1)
  10. * \par   
  11. * The function uses saturating arithmetic.   
  12. * Results outside of the allowable Q15 range [0x8000 0x7FFF] are saturated.   
  13. */

  14. void arm_offset_q15(
  15.   q15_t * pSrc,
  16.   q15_t offset,
  17.   q15_t * pDst,
  18.   uint32_t blockSize)
  19. {
  20.   uint32_t blkCnt;                               /* loop counter */

  21. #ifndef ARM_MATH_CM0_FAMILY

  22. /* Run the below code for Cortex-M4 and Cortex-M3 */
  23.   q31_t offset_packed;                           /* Offset packed to 32 bit */


  24.   /*loop Unrolling */
  25.   blkCnt = blockSize >> 2u;

  26.   /* Offset is packed to 32 bit in order to use SIMD32 for addition */
  27.   offset_packed = __PKHBT(offset, offset, 16);                                                       (2)

  28.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  29.    ** a second loop below computes the remaining 1 to 3 samples. */
  30.   while(blkCnt > 0u)
  31.   {
  32.     /* C = A + offset */
  33.     /* Add offset and then store the results in the destination buffer, 2 samples at a time. */
  34.     *__SIMD32(pDst)++ = __QADD16(*__SIMD32(pSrc)++, offset_packed);                                  (3)
  35.     *__SIMD32(pDst)++ = __QADD16(*__SIMD32(pSrc)++, offset_packed);

  36.     /* Decrement the loop counter */
  37.     blkCnt--;
  38.   }

  39.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  40.    ** No loop unrolling is used. */
  41.   blkCnt = blockSize % 0x4u;

  42.   while(blkCnt > 0u)
  43.   {
  44.     /* C = A + offset */
  45.     /* Add offset and then store the results in the destination buffer. */
  46.     *pDst++ = (q15_t) __QADD16(*pSrc++, offset);

  47.     /* Decrement the loop counter */
  48.     blkCnt--;
  49.   }

  50. #else

  51.   /* Run the below code for Cortex-M0 */

  52.   /* Initialize blkCnt with number of samples */
  53.   blkCnt = blockSize;

  54.   while(blkCnt > 0u)
  55.   {
  56.     /* C = A + offset */
  57.     /* Add offset and then store the results in the destination buffer. */
  58.     *pDst++ = (q15_t) __SSAT(((q31_t) * pSrc++ + offset), 16);

  59.     /* Decrement the loop counter */
  60.     blkCnt--;
  61.   }

  62. #endif /* #ifndef ARM_MATH_CM0_FAMILY */

  63. }

复制代码

1.     这个函数使用了饱和运算。

    饱和运算数值0x8000将变成0x7FFF。

2.     将两个Q15格式的变量合并成一个Q31格式的数据,方便指令__QADD16的调用。

3.     由于__QADD16是SIMD指令,这里调用一次就能实现两个Q15格式数据的计算。


9.2.4  arm_offset_q7

    这个函数用于求8位定点数的偏移,源代码分析如下:

  1. /**   
  2. * @brief  Adds a constant offset to a Q7 vector.   
  3. * @param[in]  *pSrc points to the input vector   
  4. * @param[in]  offset is the offset to be added   
  5. * @param[out]  *pDst points to the output vector   
  6. * @param[in]  blockSize number of samples in the vector   
  7. * @return none.   
  8. *   
  9. * <b>Scaling and Overflow Behavior:</b>                                                              (1)
  10. * \par   
  11. * The function uses saturating arithmetic.   
  12. * Results outside of the allowable Q7 range [0x80 0x7F] are saturated.   
  13. */

  14. void arm_offset_q7(
  15.   q7_t * pSrc,
  16.   q7_t offset,
  17.   q7_t * pDst,
  18.   uint32_t blockSize)
  19. {
  20.   uint32_t blkCnt;                               /* loop counter */

  21. #ifndef ARM_MATH_CM0_FAMILY

  22. /* Run the below code for Cortex-M4 and Cortex-M3 */
  23.   q31_t offset_packed;                           /* Offset packed to 32 bit */


  24.   /*loop Unrolling */
  25.   blkCnt = blockSize >> 2u;

  26.   /* Offset is packed to 32 bit in order to use SIMD32 for addition */                               (2)
  27.   offset_packed = __PACKq7(offset, offset, offset, offset);

  28.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  29.    ** a second loop below computes the remaining 1 to 3 samples. */
  30.   while(blkCnt > 0u)
  31.   {
  32.     /* C = A + offset */
  33.     /* Add offset and then store the results in the destination bufferfor 4 samples at a time. */
  34.     *__SIMD32(pDst)++ = __QADD8(*__SIMD32(pSrc)++, offset_packed);                                   (3)

  35.     /* Decrement the loop counter */
  36.     blkCnt--;
  37.   }

  38.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  39.    ** No loop unrolling is used. */
  40.   blkCnt = blockSize % 0x4u;

  41.   while(blkCnt > 0u)
  42.   {
  43.     /* C = A + offset */
  44.     /* Add offset and then store the result in the destination buffer. */
  45.     *pDst++ = (q7_t) __SSAT(*pSrc++ + offset, 8);

  46.     /* Decrement the loop counter */
  47.     blkCnt--;
  48.   }

  49. #else

  50.   /* Run the below code for Cortex-M0 */

  51.   /* Initialize blkCnt with number of samples */
  52.   blkCnt = blockSize;

  53.   while(blkCnt > 0u)
  54.   {
  55.     /* C = A + offset */
  56.     /* Add offset and then store the result in the destination buffer. */
  57.     *pDst++ = (q7_t) __SSAT((q15_t) * pSrc++ + offset, 8);

  58.     /* Decrement the loop counter */
  59.     blkCnt--;
  60.   }

  61. #endif /* #ifndef ARM_MATH_CM0_FAMILY */

  62. }

复制代码

1.     这个函数使用了饱和运算。

    饱和运算数值0x80将变成0x7F。

2.     通过__PACKq7将4个Q7格式的数据合并成一个Q31格式的数据。

3.     由于__QADD8是SIMD指令,这里调用一次就能实现四个Q8格式数据的计算。


9.2.5  实例讲解

实验目的:

    1. 四种类型数据的相反数。

实验内容:

    1. 按下K2键, 串口打印输出结果

实验现象:

           通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:




程序设计:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DSP_Offset
  4. *    功能说明: 偏移
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DSP_Offset(void)
  10. {
  11.      static float32_t   pSrcA;
  12.      static float32_t   Offset = 0.0f;
  13.      static float32_t   pDst;
  14.    
  15.      static q31_t  pSrcA1;
  16.      static q31_t  Offset1 = 0;
  17.      static q31_t  pDst1;

  18.      static q15_t  pSrcA2;
  19.      static q15_t  Offset2 = 0;
  20.      static q15_t  pDst2;

  21.      static q7_t  pSrcA3;
  22.      static q7_t  Offset3 = 0;
  23.      static q7_t  pDst3;

  24.    
  25.      Offset--;
  26.      arm_offset_f32(&pSrcA, Offset, &pDst, 1);
  27.      printf("arm_add_f32 = %f\r\n", pDst);

  28.      Offset1--;
  29.      arm_offset_q31(&pSrcA1, Offset1, &pDst1, 1);
  30.      printf("arm_add_q31 = %d\r\n", pDst1);

  31.      Offset2--;
  32.      arm_offset_q15(&pSrcA2, Offset2, &pDst2, 1);
  33.      printf("arm_add_q15 = %d\r\n", pDst2);

  34.      Offset3--;
  35.      arm_offset_q7(&pSrcA3, Offset3, &pDst3, 1);
  36.      printf("arm_add_q7 = %d\r\n", pDst3);
  37.      printf("***********************************\r\n");
  38. }

复制代码



9.3  位移(Vector Shift)

    这部分函数主要用于实现位移,公式描述如下:

      pDst[n] = pSrc[n] << shift,   0 <= n < blockSize.  

    注意,这部分函数支持目标指针和源指针指向相同的缓冲区。


9.3.1  arm_shift_q31

    这个函数用于求32位定点数的位移,源代码分析如下:

  1. /**      
  2. * @brief  Shifts the elements of a Q31 vector a specified number of bits.      
  3. * @param[in]  *pSrc points to the input vector      
  4. * @param[in]  shiftBits number of bits to shift.
  5. *              A positive value shifts left; a negative value shifts right.                           (1)
  6. * @param[out]  *pDst points to the output vector      
  7. * @param[in]  blockSize number of samples in the vector      
  8. * @return none.      
  9. *      
  10. *      
  11. * <b>Scaling and Overflow Behavior:</b>                                                              (2)
  12. * \par      
  13. * The function uses saturating arithmetic.      
  14. * Results outside of the allowable Q31 range [0x80000000 0x7FFFFFFF] will be saturated.      
  15. */

  16. void arm_shift_q31(
  17.   q31_t * pSrc,
  18.   int8_t shiftBits,
  19.   q31_t * pDst,
  20.   uint32_t blockSize)
  21. {
  22.   uint32_t blkCnt;                               /* loop counter */
  23.   uint8_t sign = (shiftBits & 0x80);             /* Sign of shiftBits */                              (3)

  24. #ifndef ARM_MATH_CM0_FAMILY

  25.   q31_t in1, in2, in3, in4;                      /* Temporary input variables */
  26.   q31_t out1, out2, out3, out4;                  /* Temporary output variables */

  27.   /*loop Unrolling */
  28.   blkCnt = blockSize >> 2u;


  29.   if(sign == 0u)                                                                                     (4)
  30.   {
  31.     /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  32.      ** a second loop below computes the remaining 1 to 3 samples. */
  33.     while(blkCnt > 0u)
  34.     {
  35.       /* C = A  << shiftBits */
  36.       /* Shift the input and then store the results in the destination buffer. */
  37.       in1 = *pSrc;
  38.       in2 = *(pSrc + 1);
  39.       out1 = in1 << shiftBits;
  40.       in3 = *(pSrc + 2);
  41.       out2 = in2 << shiftBits;
  42.       in4 = *(pSrc + 3);
  43.       if(in1 != (out1 >> shiftBits))                                                                (5)
  44.         out1 = 0x7FFFFFFF ^ (in1 >> 31);

  45.       if(in2 != (out2 >> shiftBits))
  46.         out2 = 0x7FFFFFFF ^ (in2 >> 31);

  47.       *pDst = out1;
  48.       out3 = in3 << shiftBits;
  49.       *(pDst + 1) = out2;
  50.       out4 = in4 << shiftBits;

  51.       if(in3 != (out3 >> shiftBits))
  52.         out3 = 0x7FFFFFFF ^ (in3 >> 31);

  53.       if(in4 != (out4 >> shiftBits))
  54.         out4 = 0x7FFFFFFF ^ (in4 >> 31);

  55.       *(pDst + 2) = out3;
  56.       *(pDst + 3) = out4;

  57.       /* Update destination pointer to process next sampels */
  58.       pSrc += 4u;
  59.       pDst += 4u;

  60.       /* Decrement the loop counter */
  61.       blkCnt--;
  62.     }
  63.   }
  64.   else                                                                                              (6)
  65.   {

  66.     /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  67.      ** a second loop below computes the remaining 1 to 3 samples. */
  68.     while(blkCnt > 0u)
  69.     {
  70.       /* C = A >>  shiftBits */
  71.       /* Shift the input and then store the results in the destination buffer. */
  72.       in1 = *pSrc;
  73.       in2 = *(pSrc + 1);
  74.       in3 = *(pSrc + 2);
  75.       in4 = *(pSrc + 3);

  76.       *pDst = (in1 >> -shiftBits);                                                                  (7)
  77.       *(pDst + 1) = (in2 >> -shiftBits);
  78.       *(pDst + 2) = (in3 >> -shiftBits);
  79.       *(pDst + 3) = (in4 >> -shiftBits);


  80.       pSrc += 4u;
  81.       pDst += 4u;

  82.       blkCnt--;
  83.     }

  84.   }

  85.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  86.    ** No loop unrolling is used. */
  87.   blkCnt = blockSize % 0x4u;

  88. #else

  89.   /* Run the below code for Cortex-M0 */


  90.   /* Initialize blkCnt with number of samples */
  91.   blkCnt = blockSize;

  92. #endif /* #ifndef ARM_MATH_CM0_FAMILY */


  93.   while(blkCnt > 0u)
  94.   {
  95.     /* C = A (>> or <<) shiftBits */
  96.     /* Shift the input and then store the result in the destination buffer. */                       (8)
  97.     *pDst++ = (sign == 0u) ? clip_q63_to_q31((q63_t) * pSrc++ << shiftBits) :
  98.       (*pSrc++ >> -shiftBits);

  99.     /* Decrement the loop counter */
  100.     blkCnt--;
  101.   }


  102. }

复制代码

1.     如果函数的参数shiftBits是正数那么表示左移,如果参数shiftBits是负数那么就是右移。

2.     这个函数使用了饱和运算。

    饱和运算数值0x80000000将变成0x7FFFFFFF。

3.     获取偏移值shiftBits是正数还是负数。

4.     如果移位值是正数,那么就是左移。

5.     数值的左移仅支持将其左移后再右移相应的位数后数值不变的情况,如果不满足这个条件,那么输出结果只有两种结果(这里就是实现输出结果的饱和运算)。

      out =0x7FFFFFFF & 0xFFFFFFFF =0x80000000

      out =0x7FFFFFFF & 0x0000000 =0x7FFFFFFF

6.     如果移位值是负数,那么就是右移。

7.     将偏移值取反然后左移即可。

8.     用于实现剩余数值偏移的计算。


9.3.2  arm_shift_q15

    这个函数用于求16位定点数的位移,源代码分析如下:

  1. /**   
  2. * @brief  Shifts the elements of a Q15 vector a specified number of bits.   
  3. * @param[in]  *pSrc points to the input vector   
  4. * @param[in]  shiftBits number of bits to shift.
  5. *            A positive value shifts left; a negative value shifts right.                           (1)
  6. * @param[out]  *pDst points to the output vector   
  7. * @param[in]  blockSize number of samples in the vector   
  8. * @return none.   
  9. *   
  10. * <b>Scaling and Overflow Behavior:</b>                                                             (2)
  11. * \par   
  12. * The function uses saturating arithmetic.   
  13. * Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.   
  14. */

  15. void arm_shift_q15(
  16.   q15_t * pSrc,
  17.   int8_t shiftBits,
  18.   q15_t * pDst,
  19.   uint32_t blockSize)
  20. {
  21.   uint32_t blkCnt;                               /* loop counter */
  22.   uint8_t sign;                                  /* Sign of shiftBits */

  23. #ifndef ARM_MATH_CM0_FAMILY

  24. /* Run the below code for Cortex-M4 and Cortex-M3 */

  25.   q15_t in1, in2;                                /* Temporary variables */


  26.   /*loop Unrolling */
  27.   blkCnt = blockSize >> 2u;

  28.   /* Getting the sign of shiftBits */
  29.   sign = (shiftBits & 0x80);                                                                        (3)

  30.   /* If the shift value is positive then do right shift else left shift */
  31.   if(sign == 0u)
  32.   {
  33.     /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  34.      ** a second loop below computes the remaining 1 to 3 samples. */
  35.     while(blkCnt > 0u)
  36.     {
  37.       /* Read 2 inputs */
  38.       in1 = *pSrc++;
  39.       in2 = *pSrc++;
  40.       /* C = A << shiftBits */
  41.       /* Shift the inputs and then store the results in the destination buffer. */
  42. #ifndef  ARM_MATH_BIG_ENDIAN

  43.       *__SIMD32(pDst)++ = __PKHBT(__SSAT((in1 << shiftBits), 16),
  44.                                   __SSAT((in2 << shiftBits), 16), 16);

  45. #else

  46.       *__SIMD32(pDst)++ = __PKHBT(__SSAT((in2 << shiftBits), 16),                                   (4)
  47.                                   __SSAT((in1 << shiftBits), 16), 16);

  48. #endif /* #ifndef  ARM_MATH_BIG_ENDIAN    */

  49.       in1 = *pSrc++;
  50.       in2 = *pSrc++;

  51. #ifndef  ARM_MATH_BIG_ENDIAN

  52.       *__SIMD32(pDst)++ = __PKHBT(__SSAT((in1 << shiftBits), 16),
  53.                                   __SSAT((in2 << shiftBits), 16), 16);

  54. #else

  55.       *__SIMD32(pDst)++ = __PKHBT(__SSAT((in2 << shiftBits), 16),                                 
  56.                                   __SSAT((in1 << shiftBits), 16), 16);

  57. #endif /* #ifndef  ARM_MATH_BIG_ENDIAN    */

  58.       /* Decrement the loop counter */
  59.       blkCnt--;
  60.     }

  61.     /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  62.      ** No loop unrolling is used. */
  63.     blkCnt = blockSize % 0x4u;

  64.     while(blkCnt > 0u)
  65.     {
  66.       /* C = A << shiftBits */
  67.       /* Shift and then store the results in the destination buffer. */
  68.       *pDst++ = __SSAT((*pSrc++ << shiftBits), 16);                                                 (5)

  69.       /* Decrement the loop counter */
  70.       blkCnt--;
  71.     }
  72.   }
  73.   else                                                                                              (6)
  74.   {
  75.     /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  76.      ** a second loop below computes the remaining 1 to 3 samples. */
  77.     while(blkCnt > 0u)
  78.     {
  79.       /* Read 2 inputs */
  80.       in1 = *pSrc++;
  81.       in2 = *pSrc++;

  82.       /* C = A >> shiftBits */
  83.       /* Shift the inputs and then store the results in the destination buffer. */
  84. #ifndef  ARM_MATH_BIG_ENDIAN

  85.       *__SIMD32(pDst)++ = __PKHBT((in1 >> -shiftBits),
  86.                                   (in2 >> -shiftBits), 16);

  87. #else

  88.       *__SIMD32(pDst)++ = __PKHBT((in2 >> -shiftBits),                                              (7)
  89.                                   (in1 >> -shiftBits), 16);

  90. #endif /* #ifndef  ARM_MATH_BIG_ENDIAN    */

  91.       in1 = *pSrc++;
  92.       in2 = *pSrc++;

  93. #ifndef  ARM_MATH_BIG_ENDIAN

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top