硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3859|回复: 5
收起左侧

[DSP] 【安富莱DSP教程】第9章 BasicMathFunctions的使用(二)

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2015-3-19 10:30:13 | 显示全部楼层 |阅读模式
特别说明:完整45期数字信号处理教程,原创高性能示波器代码全开源地址:链接
第9章 BasicMathFunctions的使用(二)


    本期教程主要讲基本函数中的相反数,偏移,位移,减法和比例因子。
    9.1 相反数(Vector Negate)
    9.2 求和(Vector Offset)
    9.3 点乘(Vector Shift)
    9.4 减法(Vector Sub)
    9.5 比例因子(Vector Scale)
    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. * @return 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. static q31_t pSrc1;
  14. static q31_t pDst1;
  15. static q15_t pSrc2;
  16. static q15_t pDst2;
  17. static q7_t pSrc3 = 127; /* 为了说明问题,在这里设置初始值为127,然后查看0x80是否饱和为0x7F */
  18. static q7_t pDst3;
  19. pSrc -= 1.23f;
  20. arm_negate_f32(&pSrc, &pDst, 1);
  21. printf("arm_negate_f32 = %f\r\n", pDst);
  22. pSrc1 -= 1;
  23. arm_negate_q31(&pSrc1, &pDst1, 1);
  24. printf("arm_negate_q31 = %d\r\n", pDst1);
  25. pSrc2 -= 1;
  26. arm_negate_q15(&pSrc2, &pDst2, 1);
  27. printf("arm_negate_q15 = %d\r\n", pDst2);
  28. pSrc3 += 1;
  29. arm_negate_q7(&pSrc3, &pDst3, 1);
  30. printf("arm_negate_q7 = %d\r\n", pDst3);
  31. printf("***********************************\r\n");
  32. }
复制代码
9.1.png
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2015-3-19 10:37:10 | 显示全部楼层
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光盘里面有此软件)查看打印信息现象如下:
9.2.png

程序设计:
  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. static q31_t  pSrcA1;  
  15. static q31_t  Offset1 = 0;  
  16. static q31_t  pDst1;  
  17. static q15_t  pSrcA2;  
  18. static q15_t  Offset2 = 0;  
  19. static q15_t  pDst2;
  20. static q7_t  pSrcA3;
  21. static q7_t  Offset3 = 0;  
  22. static q7_t  pDst3;  
  23. Offset--;
  24. arm_offset_f32(&pSrcA, Offset, &pDst, 1);
  25. printf("arm_add_f32 = %frn", pDst);
  26. Offset1--;
  27. arm_offset_q31(&pSrcA1, Offset1, &pDst1, 1);
  28. printf("arm_add_q31 = %drn", pDst1);
  29. Offset2--;
  30. arm_offset_q15(&pSrcA2, Offset2, &pDst2, 1);
  31. printf("arm_add_q15 = %drn", pDst2);
  32. Offset3--;
  33. arm_offset_q7(&pSrcA3, Offset3, &pDst3, 1);
  34. printf("arm_add_q7 = %drn", pDst3);
  35. printf("***********************************rn");
  36. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2015-3-19 10:42:31 | 显示全部楼层
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
  94.       *__SIMD32(pDst)++ = __PKHBT((in1 >> -shiftBits),
  95.                                   (in2 >> -shiftBits), 16);
  96. #else
  97.       *__SIMD32(pDst)++ = __PKHBT((in2 >> -shiftBits),                                             
  98.                                   (in1 >> -shiftBits), 16);
  99. #endif /* #ifndef  ARM_MATH_BIG_ENDIAN    */
  100.       /* Decrement the loop counter */
  101.       blkCnt--;
  102.     }
  103.     /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  104.      ** No loop unrolling is used. */
  105.     blkCnt = blockSize % 0x4u;
  106.     while(blkCnt > 0u)
  107.     {
  108.       /* C = A >> shiftBits */
  109.       /* Shift the inputs and then store the results in the destination buffer. */
  110.       *pDst++ = (*pSrc++ >> -shiftBits);
  111.       /* Decrement the loop counter */
  112.       blkCnt--;
  113.     }
  114.   }
  115. #else
  116.   /* Run the below code for Cortex-M0 */
  117.   /* Getting the sign of shiftBits */
  118.   sign = (shiftBits & 0x80);
  119.   /* If the shift value is positive then do right shift else left shift */
  120.   if(sign == 0u)
  121.   {
  122.     /* Initialize blkCnt with number of samples */
  123.     blkCnt = blockSize;
  124.     while(blkCnt > 0u)
  125.     {
  126.       /* C = A << shiftBits */
  127.       /* Shift and then store the results in the destination buffer. */
  128.       *pDst++ = __SSAT(((q31_t) * pSrc++ << shiftBits), 16);
  129.       /* Decrement the loop counter */
  130.       blkCnt--;
  131.     }
  132.   }
  133.   else
  134.   {
  135.     /* Initialize blkCnt with number of samples */
  136.     blkCnt = blockSize;
  137.     while(blkCnt > 0u)
  138.     {
  139.       /* C = A >> shiftBits */
  140.       /* Shift the inputs and then store the results in the destination buffer. */
  141.       *pDst++ = (*pSrc++ >> -shiftBits);
  142.       /* Decrement the loop counter */
  143.       blkCnt--;
  144.     }
  145.   }
  146. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  147. }
复制代码
1. 如果函数的参数shiftBits是正数那么表示左移,如果参数shiftBits是负数那么就是右移。
2. 这个函数使用了饱和运算。
    饱和运算数值0x8000变成0x7FFF
3. 获取偏移值是正数还是负数。
4. 通过调用一次__PKHBT实现两个Q15格式数据的计算。
5. 剩余几个数值的计算。
6. 如果位移值为负数,那么就是右移。
7. 将位移值取反以后,通过调用一次__PKHBT实现两个Q15格式数据的计算。

9.3.3 arm_shift_q7

    这个函数用于求8位定点数的位移,源代码分析如下:
  1. /**        
  2. * @brief  Shifts the elements of a Q7 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. * par Conditions for optimum performance   
  11. *  Input and output buffers should be aligned by 32-bit   
  12. *   
  13. *        
  14. * <b>Scaling and Overflow Behavior:</b>                                                             (2)
  15. * par        
  16. * The function uses saturating arithmetic.        
  17. * Results outside of the allowable Q7 range [0x8 0x7F] will be saturated.        
  18. */
  19. void arm_shift_q7(
  20.   q7_t * pSrc,
  21.   int8_t shiftBits,
  22.   q7_t * pDst,
  23.   uint32_t blockSize)
  24. {
  25.   uint32_t blkCnt;                               /* loop counter */
  26.   uint8_t sign;                                  /* Sign of shiftBits */
  27. #ifndef ARM_MATH_CM0_FAMILY
  28. /* Run the below code for Cortex-M4 and Cortex-M3 */
  29.   q7_t in1;                                      /* Input value1 */
  30.   q7_t in2;                                      /* Input value2 */
  31.   q7_t in3;                                      /* Input value3 */
  32.   q7_t in4;                                      /* Input value4 */
  33.   /*loop Unrolling */
  34.   blkCnt = blockSize >> 2u;
  35.   /* Getting the sign of shiftBits */
  36.   sign = (shiftBits & 0x80);                                                                         (3)
  37.   /* If the shift value is positive then do right shift else left shift */
  38.   if(sign == 0u)
  39.   {
  40.     /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  41.      ** a second loop below computes the remaining 1 to 3 samples. */
  42.     while(blkCnt > 0u)
  43.     {
  44.       /* C = A << shiftBits */
  45.       /* Read 4 inputs */
  46.       in1 = *pSrc;
  47.       in2 = *(pSrc + 1);
  48.       in3 = *(pSrc + 2);
  49.       in4 = *(pSrc + 3);
  50.                                                                                                      (4)
  51.       /* Store the Shifted result in the destination buffer in single cycle by packing the outputs */
  52.       *__SIMD32(pDst)++ = __PACKq7(__SSAT((in1 << shiftBits), 8),
  53.                                    __SSAT((in2 << shiftBits), 8),
  54.                                    __SSAT((in3 << shiftBits), 8),
  55.                                    __SSAT((in4 << shiftBits), 8));
  56.       /* Update source pointer to process next sampels */
  57.       pSrc += 4u;
  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 */                                                                      (5)
  67.       /* Shift the input and then store the result in the destination buffer. */
  68.       *pDst++ = (q7_t) __SSAT((*pSrc++ << shiftBits), 8);
  69.       /* Decrement the loop counter */
  70.       blkCnt--;
  71.     }
  72.   }
  73.   else                                                                                              (6)
  74.   {
  75.     shiftBits = -shiftBits;
  76.     /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  77.      ** a second loop below computes the remaining 1 to 3 samples. */
  78.     while(blkCnt > 0u)
  79.     {
  80.       /* C = A >> shiftBits */
  81.       /* Read 4 inputs */
  82.       in1 = *pSrc;
  83.       in2 = *(pSrc + 1);
  84.       in3 = *(pSrc + 2);
  85.       in4 = *(pSrc + 3);
  86.       /* Store the Shifted result in the destination buffer in single cycle by packing the outputs */
  87.       *__SIMD32(pDst)++ = __PACKq7((in1 >> shiftBits), (in2 >> shiftBits),
  88.                                    (in3 >> shiftBits), (in4 >> shiftBits));
  89.       pSrc += 4u;
  90.       /* Decrement the loop counter */
  91.       blkCnt--;
  92.     }
  93.     /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  94.      ** No loop unrolling is used. */
  95.     blkCnt = blockSize % 0x4u;
  96.     while(blkCnt > 0u)
  97.     {
  98.       /* C = A >> shiftBits */
  99.       /* Shift the input and then store the result in the destination buffer. */
  100.       in1 = *pSrc++;
  101.       *pDst++ = (in1 >> shiftBits);
  102.       /* Decrement the loop counter */
  103.       blkCnt--;
  104.     }
  105.   }
  106. #else
  107.   /* Run the below code for Cortex-M0 */
  108.   /* Getting the sign of shiftBits */
  109.   sign = (shiftBits & 0x80);
  110.   /* If the shift value is positive then do right shift else left shift */
  111.   if(sign == 0u)
  112.   {
  113.     /* Initialize blkCnt with number of samples */
  114.     blkCnt = blockSize;
  115.     while(blkCnt > 0u)
  116.     {
  117.       /* C = A << shiftBits */
  118.       /* Shift the input and then store the result in the destination buffer. */
  119.       *pDst++ = (q7_t) __SSAT(((q15_t) * pSrc++ << shiftBits), 8);
  120.       /* Decrement the loop counter */
  121.       blkCnt--;
  122.     }
  123.   }
  124.   else
  125.   {
  126.     /* Initialize blkCnt with number of samples */
  127.     blkCnt = blockSize;
  128.     while(blkCnt > 0u)
  129.     {
  130.       /* C = A >> shiftBits */
  131.       /* Shift the input and then store the result in the destination buffer. */
  132.       *pDst++ = (*pSrc++ >> -shiftBits);
  133.       /* Decrement the loop counter */
  134.       blkCnt--;
  135.     }
  136.   }
  137. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  138. }
复制代码
1. 如果函数的参数shiftBits是正数那么表示左移,如果参数shiftBits是负数那么就是右移。
2. 这个函数使用了饱和运算。
    饱和运算数值0x80变成0x7F
3. 获取偏移值是正数还是负数。
4. 通过调用一次__PACKq7实现四个Q7格式数据的位移。
5. 剩余几不足4个数据的位移求解。
6. 如果移位值是负数,那么就是右移。

9.3.4 实例讲解

实验目的:
    1. 三种类型数据的位移。
实验内容:
    1. 按下K3键, 串口打印输出结果
实验现象:
    通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:
9.3.png

程序设计:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DSP_Shift
  4. *    功能说明: 位移
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DSP_Shift(void)
  10. {
  11. static q31_t  pSrcA1 = 0x88886666;  
  12. static q31_t  pDst1;  
  13. static q15_t  pSrcA2 = 0x8866;  
  14. static q15_t  pDst2;
  15. static q7_t  pSrcA3 = 0x86;
  16. static q7_t  pDst3;  
  17. arm_shift_q31(&pSrcA1, 3, &pDst1, 1);
  18. printf("arm_shift_q31 = %8xrn", pDst1);
  19. arm_shift_q15(&pSrcA2, -3, &pDst2, 1);
  20. printf("arm_shift_q15 = %4xrn", pDst2);
  21. arm_shift_q7(&pSrcA3, 3, &pDst3, 1);
  22. printf("arm_shift_q7 = %2xrn", pDst3);
  23. printf("***********************************rn");
  24. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2015-3-19 10:47:29 | 显示全部楼层
9.4 减法(Vector Sub)

    这部分函数主要用于实现减法,公式描述如下:
     pDst[n] = pSrcA[n] - pSrcB[n],   0 <= n < blockSize.     

9.4.1 arm_sub_f32

    这个函数用于求32位浮点数的减法,源代码分析如下:
  1. /**        
  2. * @brief Floating-point vector subtraction.        
  3. * @param[in]       *pSrcA points to the first input vector        
  4. * @param[in]       *pSrcB points to the second input vector        
  5. * @param[out]      *pDst points to the output vector        
  6. * @param[in]       blockSize number of samples in each vector        
  7. * @return none.        
  8. */
  9. void arm_sub_f32(
  10.   float32_t * pSrcA,
  11.   float32_t * pSrcB,
  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 inA1, inA2, inA3, inA4;              /* temporary variables */
  19.   float32_t inB1, inB2, inB3, inB4;              /* temporary variables */
  20.   /*loop Unrolling */
  21.   blkCnt = blockSize >> 2u;
  22.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.        
  23.    ** a second loop below computes the remaining 1 to 3 samples. */
  24.   while(blkCnt > 0u)
  25.   {
  26.     /* C = A - B */
  27.     /* Subtract and then store the results in the destination buffer. */
  28.     /* Read 4 input samples from sourceA and sourceB */
  29.     inA1 = *pSrcA;
  30.     inB1 = *pSrcB;
  31.     inA2 = *(pSrcA + 1);
  32.     inB2 = *(pSrcB + 1);
  33.     inA3 = *(pSrcA + 2);
  34.     inB3 = *(pSrcB + 2);
  35.     inA4 = *(pSrcA + 3);
  36.     inB4 = *(pSrcB + 3);
  37.     /* dst = srcA - srcB */
  38.     /* subtract and store the result */                                                              (1)
  39.     *pDst = inA1 - inB1;
  40.     *(pDst + 1) = inA2 - inB2;
  41.     *(pDst + 2) = inA3 - inB3;
  42.     *(pDst + 3) = inA4 - inB4;
  43.     /* Update pointers to process next sampels */
  44.     pSrcA += 4u;
  45.     pSrcB += 4u;
  46.     pDst += 4u;
  47.     /* Decrement the loop counter */
  48.     blkCnt--;
  49.   }
  50.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.        
  51.    ** No loop unrolling is used. */
  52.   blkCnt = blockSize % 0x4u;
  53. #else
  54.   /* Run the below code for Cortex-M0 */
  55.   /* Initialize blkCnt with number of samples */
  56.   blkCnt = blockSize;
  57. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  58.   while(blkCnt > 0u)
  59.   {
  60.     /* C = A - B */
  61.     /* Subtract and then store the results in the destination buffer. */
  62.     *pDst++ = (*pSrcA++) - (*pSrcB++);
  63.     /* Decrement the loop counter */
  64.     blkCnt--;
  65.   }
  66. }
复制代码
1. 浮点数的减法运算比较简单,直接两个数值相减即可。

9.4.2 arm_sub_q31

    这个函数用于求32位定点数的减法,源代码分析如下:
  1. /**   
  2. * @brief Q31 vector subtraction.   
  3. * @param[in]       *pSrcA points to the first input vector   
  4. * @param[in]       *pSrcB points to the second input vector   
  5. * @param[out]      *pDst points to the output vector   
  6. * @param[in]       blockSize number of samples in each 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] will be saturated.   
  13. */
  14. void arm_sub_q31(
  15.   q31_t * pSrcA,
  16.   q31_t * pSrcB,
  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 inA1, inA2, inA3, inA4;
  24.   q31_t inB1, inB2, inB3, inB4;
  25.   /*loop Unrolling */
  26.   blkCnt = blockSize >> 2u;
  27.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  28.    ** a second loop below computes the remaining 1 to 3 samples. */
  29.   while(blkCnt > 0u)
  30.   {
  31.     /* C = A - B */
  32.     /* Subtract and then store the results in the destination buffer. */
  33.     inA1 = *pSrcA++;
  34.     inA2 = *pSrcA++;
  35.     inB1 = *pSrcB++;
  36.     inB2 = *pSrcB++;
  37.     inA3 = *pSrcA++;
  38.     inA4 = *pSrcA++;
  39.     inB3 = *pSrcB++;
  40.     inB4 = *pSrcB++;
  41.     *pDst++ = __QSUB(inA1, inB1);                                                                    (2)
  42.     *pDst++ = __QSUB(inA2, inB2);
  43.     *pDst++ = __QSUB(inA3, inB3);
  44.     *pDst++ = __QSUB(inA4, inB4);
  45.     /* Decrement the loop counter */
  46.     blkCnt--;
  47.   }
  48.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  49.    ** No loop unrolling is used. */
  50.   blkCnt = blockSize % 0x4u;
  51.   while(blkCnt > 0u)
  52.   {
  53.     /* C = A - B */
  54.     /* Subtract and then store the result in the destination buffer. */
  55.     *pDst++ = __QSUB(*pSrcA++, *pSrcB++);
  56.     /* Decrement the loop counter */
  57.     blkCnt--;
  58.   }
  59. #else
  60.   /* Run the below code for Cortex-M0 */
  61.   /* Initialize blkCnt with number of samples */
  62.   blkCnt = blockSize;
  63.   while(blkCnt > 0u)
  64.   {
  65.     /* C = A - B */
  66.     /* Subtract and then store the result in the destination buffer. */
  67.     *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrcA++ - *pSrcB++);
  68.     /* Decrement the loop counter */
  69.     blkCnt--;
  70.   }
  71. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  72. }
复制代码
1. 这个函数使用了饱和运算。
    饱和运算数值0x80000000变成0x7FFFFFFF
2. __QSUB也是SIMD指令,这里可以用这个指令实现两个Q31格式数据的饱和减法。

9.4.3 arm_sub_q15

    这个函数用于求16位定点数的减法,源代码分析如下:
  1. /**   
  2. * @brief Q15 vector subtraction.   
  3. * @param[in]       *pSrcA points to the first input vector   
  4. * @param[in]       *pSrcB points to the second input vector   
  5. * @param[out]      *pDst points to the output vector   
  6. * @param[in]       blockSize number of samples in each vector   
  7. * @return none.   
  8. *   
  9. * <b>Scaling and Overflow Behavior:</b>   
  10. * par   
  11. * The function uses saturating arithmetic.   
  12. * Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.   
  13. */
  14. void arm_sub_q15(
  15.   q15_t * pSrcA,
  16.   q15_t * pSrcB,
  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 inA1, inA2;
  24.   q31_t inB1, inB2;
  25.   /*loop Unrolling */
  26.   blkCnt = blockSize >> 2u;
  27.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
  28.    ** a second loop below computes the remaining 1 to 3 samples. */
  29.   while(blkCnt > 0u)
  30.   {
  31.     /* C = A - B */
  32.     /* Subtract and then store the results in the destination buffer two samples at a time. */
  33.     inA1 = *__SIMD32(pSrcA)++;                                                                      (1)
  34.     inA2 = *__SIMD32(pSrcA)++;
  35.     inB1 = *__SIMD32(pSrcB)++;
  36.     inB2 = *__SIMD32(pSrcB)++;
  37.     *__SIMD32(pDst)++ = __QSUB16(inA1, inB1);                                                       (2)
  38.     *__SIMD32(pDst)++ = __QSUB16(inA2, inB2);
  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.   while(blkCnt > 0u)
  46.   {
  47.     /* C = A - B */
  48.     /* Subtract and then store the result in the destination buffer. */
  49.     *pDst++ = (q15_t) __QSUB16(*pSrcA++, *pSrcB++);
  50.     /* Decrement the loop counter */
  51.     blkCnt--;
  52.   }
  53. #else
  54.   /* Run the below code for Cortex-M0 */
  55.   /* Initialize blkCnt with number of samples */
  56.   blkCnt = blockSize;
  57.   while(blkCnt > 0u)
  58.   {
  59.     /* C = A - B */
  60.     /* Subtract and then store the result in the destination buffer. */
  61.     *pDst++ = (q15_t) __SSAT(((q31_t) * pSrcA++ - *pSrcB++), 16);
  62.     /* Decrement the loop counter */
  63.     blkCnt--;
  64.   }
  65. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  66. }
复制代码
1. 这里一次读取两个Q15格式的数据。
2. 由于__QSUB16是SIMD指令,在这里调用一次__QSUB16可以实现两次减法运算。

9.4.4 arm_sub_q7

    这个函数用于求8位定点数的减法,源代码分析如下:
  1. /**   
  2. * @brief Q7 vector subtraction.   
  3. * @param[in]       *pSrcA points to the first input vector   
  4. * @param[in]       *pSrcB points to the second input vector   
  5. * @param[out]      *pDst points to the output vector   
  6. * @param[in]       blockSize number of samples in each vector   
  7. * @return none.   
  8. *   
  9. * <b>Scaling and Overflow Behavior:</b>   
  10. * par   
  11. * The function uses saturating arithmetic.   
  12. * Results outside of the allowable Q7 range [0x80 0x7F] will be saturated.   
  13. */
  14. void arm_sub_q7(
  15.   q7_t * pSrcA,
  16.   q7_t * pSrcB,
  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.   /*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 - B */
  30.     /* Subtract and then store the results in the destination buffer 4 samples at a time. */
  31.     *__SIMD32(pDst)++ = __QSUB8(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++);                              (1)
  32.     /* Decrement the loop counter */
  33.     blkCnt--;
  34.   }
  35.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  36.    ** No loop unrolling is used. */
  37.   blkCnt = blockSize % 0x4u;
  38.   while(blkCnt > 0u)
  39.   {
  40.     /* C = A - B */
  41.     /* Subtract and then store the result in the destination buffer. */
  42.     *pDst++ = __SSAT(*pSrcA++ - *pSrcB++, 8);
  43.     /* Decrement the loop counter */
  44.     blkCnt--;
  45.   }
  46. #else
  47.   /* Run the below code for Cortex-M0 */
  48.   /* Initialize blkCnt with number of samples */
  49.   blkCnt = blockSize;
  50.   while(blkCnt > 0u)
  51.   {
  52.     /* C = A - B */
  53.     /* Subtract and then store the result in the destination buffer. */
  54.     *pDst++ = (q7_t) __SSAT((q15_t) * pSrcA++ - *pSrcB++, 8);
  55.     /* Decrement the loop counter */
  56.     blkCnt--;
  57.   }
  58. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  59. }
复制代码
1. __QSUB8也是SIMD指令,调用一次就能实现4个Q7格式数据的减法运算。

9.4.5 实例讲解

实验目的:
    1. 四种种类型数据的减法。
实验内容:
    1. 按下按键UP, 串口打印输出结果
实验现象:
    通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:
9.4.png

程序设计:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DSP_Sub
  4. *    功能说明: 减法
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DSP_Sub(void)
  10. {
  11. static float32_t   pSrcA[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};
  12. static float32_t   pSrcB[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};  
  13. static float32_t   pDst[5];  
  14. static q31_t  pSrcA1[5] = {1,1,1,1,1};  
  15. static q31_t  pSrcB1[5] = {1,1,1,1,1};  
  16. static q31_t  pDst1[5];   
  17. static q15_t  pSrcA2[5] = {1,1,1,1,1};  
  18. static q15_t  pSrcB2[5] = {1,1,1,1,1};  
  19. static q15_t  pDst2[5];   
  20. static q7_t  pSrcA3[5] = {0x70,1,1,1,1};
  21. static q7_t  pSrcB3[5] = {0x7f,1,1,1,1};  
  22. static q7_t pDst3[5];  
  23. pSrcA[0] += 1.1f;
  24. arm_sub_f32(pSrcA, pSrcB, pDst, 5);
  25. printf("arm_sub_f32 = %frn", pDst[0]);
  26. pSrcA1[0] += 1;
  27. arm_sub_q31(pSrcA1, pSrcB1, pDst1, 5);
  28. printf("arm_sub_q31 = %drn", pDst1[0]);
  29. pSrcA2[0] += 1;
  30. arm_sub_q15(pSrcA2, pSrcB2, pDst2, 5);
  31. printf("arm_sub_q15 = %drn", pDst2[0]);
  32. pSrcA3[0] += 1;
  33. arm_sub_q7(pSrcA3, pSrcB3, pDst3, 5);
  34. printf("arm_sub_q7 = %drn", pDst3[0]);
  35. printf("***********************************rn");
  36. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2015-3-19 10:54:22 | 显示全部楼层
9.5 比例因子(Vector Scale)

    这部分函数主要用于实现数据的比例放大和缩小,浮点数据公式描述如下:
      pDst[n] = pSrc[n] * scale,   0 <= n < blockSize.        
    如果是Q31,Q15,Q7格式的数据,公式描述如下:
      pDst[n] = (pSrc[n] * scaleFract) << shift,   0 <= n < blockSize.   
    这种情况下,比例因子就是:
      scale = scaleFract * 2^shift.      
      注意,这部分函数支持目标指针和源指针指向相同的缓冲区。

9.5.1 arm_scale_f32

    这个函数用于求32位浮点数的比例放缩,源代码分析如下:
  1. /**        
  2. * @brief Multiplies a floating-point vector by a scalar.        
  3. * @param[in]       *pSrc points to the input vector        
  4. * @param[in]       scale scale factor to be applied        
  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_scale_f32(
  10.   float32_t * pSrc,
  11.   float32_t scale,
  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;                  /* temporary variabels */
  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 * scale */
  26.     /* Scale the input and then store the results in the destination buffer. */
  27.     /* read input samples from source */
  28.     in1 = *pSrc;
  29.     in2 = *(pSrc + 1);
  30.     /* multiply with scaling factor */                                                               (1)
  31.     in1 = in1 * scale;
  32.     /* read input sample from source */
  33.     in3 = *(pSrc + 2);
  34.     /* multiply with scaling factor */
  35.     in2 = in2 * scale;
  36.     /* read input sample from source */
  37.     in4 = *(pSrc + 3);
  38.     /* multiply with scaling factor */
  39.     in3 = in3 * scale;
  40.     in4 = in4 * scale;
  41.     /* store the result to destination */
  42.     *pDst = in1;
  43.     *(pDst + 1) = in2;
  44.     *(pDst + 2) = in3;
  45.     *(pDst + 3) = in4;
  46.     /* update pointers to process next samples */
  47.     pSrc += 4u;
  48.     pDst += 4u;
  49.     /* Decrement the loop counter */
  50.     blkCnt--;
  51.   }
  52.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.        
  53.    ** No loop unrolling is used. */
  54.   blkCnt = blockSize % 0x4u;
  55. #else
  56.   /* Run the below code for Cortex-M0 */
  57.   /* Initialize blkCnt with number of samples */
  58.   blkCnt = blockSize;
  59. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  60.   while(blkCnt > 0u)
  61.   {
  62.     /* C = A * scale */
  63.     /* Scale the input and then store the result in the destination buffer. */
  64.     *pDst++ = (*pSrc++) * scale;
  65.     /* Decrement the loop counter */
  66.     blkCnt--;
  67.   }
  68. }
复制代码
1. 浮点数据的比例因子计算比较简单,源浮点数相应相应的比例因子即可。

9.5.2 arm_scale_q31

    这个函数用于求32位定点数的比例放缩,源代码分析如下:
  1. /**      
  2. * @brief Multiplies a Q31 vector by a scalar.      
  3. * @param[in]       *pSrc points to the input vector      
  4. * @param[in]       scaleFract fractional portion of the scale value      
  5. * @param[in]       shift number of bits to shift the result by      
  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>                                                             (1)
  11. * par      
  12. * The input data <code>*pSrc</code> and <code>scaleFract</code> are in 1.31 format.      
  13. * These are multiplied to yield a 2.62 intermediate result and this is shifted with saturation to 1.31 format.      
  14. */
  15. void arm_scale_q31(
  16.   q31_t * pSrc,
  17.   q31_t scaleFract,
  18.   int8_t shift,
  19.   q31_t * pDst,
  20.   uint32_t blockSize)
  21. {
  22.   int8_t kShift = shift + 1;                     /* Shift to apply after scaling */                 (2)
  23.   int8_t sign = (kShift & 0x80);
  24.   uint32_t blkCnt;                               /* loop counter */
  25.   q31_t in, out;
  26. #ifndef ARM_MATH_CM0_FAMILY
  27. /* Run the below code for Cortex-M4 and Cortex-M3 */
  28.   q31_t in1, in2, in3, in4;                      /* temporary input variables */
  29.   q31_t out1, out2, out3, out4;                  /* temporary output variabels */
  30.   /*loop Unrolling */
  31.   blkCnt = blockSize >> 2u;
  32.   if(sign == 0u)                                                                                    (3)
  33.   {
  34.     /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.      
  35.      ** a second loop below computes the remaining 1 to 3 samples. */
  36.     while(blkCnt > 0u)
  37.     {
  38.       /* read four inputs from source */
  39.       in1 = *pSrc;
  40.       in2 = *(pSrc + 1);
  41.       in3 = *(pSrc + 2);
  42.       in4 = *(pSrc + 3);
  43.       /* multiply input with scaler value */                                                        (4)
  44.       in1 = ((q63_t) in1 * scaleFract) >> 32;
  45.       in2 = ((q63_t) in2 * scaleFract) >> 32;
  46.       in3 = ((q63_t) in3 * scaleFract) >> 32;
  47.       in4 = ((q63_t) in4 * scaleFract) >> 32;
  48.       /* apply shifting */
  49.       out1 = in1 << kShift;
  50.       out2 = in2 << kShift;
  51.       /* saturate the results. */
  52.       if(in1 != (out1 >> kShift))                                                                   (5)
  53.         out1 = 0x7FFFFFFF ^ (in1 >> 31);
  54.       if(in2 != (out2 >> kShift))
  55.         out2 = 0x7FFFFFFF ^ (in2 >> 31);
  56.       out3 = in3 << kShift;
  57.       out4 = in4 << kShift;
  58.       *pDst = out1;
  59.       *(pDst + 1) = out2;
  60.       if(in3 != (out3 >> kShift))
  61.         out3 = 0x7FFFFFFF ^ (in3 >> 31);
  62.       if(in4 != (out4 >> kShift))
  63.         out4 = 0x7FFFFFFF ^ (in4 >> 31);
  64.       /* Store result destination */
  65.       *(pDst + 2) = out3;
  66.       *(pDst + 3) = out4;
  67.       /* Update pointers to process next sampels */
  68.       pSrc += 4u;
  69.       pDst += 4u;
  70.       /* Decrement the loop counter */
  71.       blkCnt--;
  72.     }
  73.   }
  74.   else                                                                                               {
  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 four inputs from source */
  80.       in1 = *pSrc;
  81.       in2 = *(pSrc + 1);
  82.       in3 = *(pSrc + 2);
  83.       in4 = *(pSrc + 3);
  84.       /* multiply input with scaler value */
  85.       in1 = ((q63_t) in1 * scaleFract) >> 32;
  86.       in2 = ((q63_t) in2 * scaleFract) >> 32;
  87.       in3 = ((q63_t) in3 * scaleFract) >> 32;
  88.       in4 = ((q63_t) in4 * scaleFract) >> 32;
  89.       /* apply shifting */                                                                           (6)
  90.       out1 = in1 >> -kShift;
  91.       out2 = in2 >> -kShift;
  92.       out3 = in3 >> -kShift;
  93.       out4 = in4 >> -kShift;
  94.       /* Store result destination */
  95.       *pDst = out1;
  96.       *(pDst + 1) = out2;
  97.       *(pDst + 2) = out3;
  98.       *(pDst + 3) = out4;
  99.       /* Update pointers to process next sampels */
  100.       pSrc += 4u;
  101.       pDst += 4u;
  102.       /* Decrement the loop counter */
  103.       blkCnt--;
  104.     }
  105.   }
  106.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.      
  107.    ** No loop unrolling is used. */
  108.   blkCnt = blockSize % 0x4u;
  109. #else
  110.   /* Run the below code for Cortex-M0 */
  111.   /* Initialize blkCnt with number of samples */
  112.   blkCnt = blockSize;
  113. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  114.   if(sign == 0)
  115.   {
  116.   while(blkCnt > 0u)
  117.   {
  118. /* C = A * scale */
  119. /* Scale the input and then store the result in the destination buffer. */
  120. in = *pSrc++;
  121. in = ((q63_t) in * scaleFract) >> 32;
  122. out = in << kShift;
  123. if(in != (out >> kShift))
  124. out = 0x7FFFFFFF ^ (in >> 31);
  125. *pDst++ = out;
  126. /* Decrement the loop counter */
  127. blkCnt--;
  128.   }
  129.   }
  130.   else
  131.   {
  132.   while(blkCnt > 0u)
  133.   {
  134. /* C = A * scale */
  135. /* Scale the input and then store the result in the destination buffer. */
  136. in = *pSrc++;
  137. in = ((q63_t) in * scaleFract) >> 32;
  138. out = in >> -kShift;
  139. *pDst++ = out;
  140. /* Decrement the loop counter */
  141. blkCnt--;
  142.   }
  143.   
  144.   }
  145. }
复制代码
1. 源数据和比例因子都是Q31格式。这样他们的乘积就是1.31 * 1.31 = 2.62格式。由于输出结果也是Q31格式,那么源数据和比例因子的乘积需要右移32位,并且输出结果需要饱和处理。
2. 这里不清楚为什么要加1操作,留作以后解决。
3. 如果位移是正值,那么就是左移位,否则就是右移位。
4. 将源数据和比例因子的乘积左移32位,保证结果也是Q31格式。
5. 这里是对结果的饱和处理。
6. 数值的右移不存在饱和问题,这里直接取反即可。

9.5.3 arm_scale_q15

    这个函数用于求16位定点数的比例放缩,源代码分析如下:
  1. /**   
  2. * @brief Multiplies a Q15 vector by a scalar.   
  3. * @param[in]       *pSrc points to the input vector   
  4. * @param[in]       scaleFract fractional portion of the scale value   
  5. * @param[in]       shift number of bits to shift the result by   
  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>                                                               (1)
  11. * par   
  12. * The input data <code>*pSrc</code> and <code>scaleFract</code> are in 1.15 format.   
  13. * These are multiplied to yield a 2.30 intermediate result and this is shifted with saturation to 1.15 format.   
  14. */
  15. void arm_scale_q15(
  16.   q15_t * pSrc,
  17.   q15_t scaleFract,
  18.   int8_t shift,
  19.   q15_t * pDst,
  20.   uint32_t blockSize)
  21. {
  22.   int8_t kShift = 15 - shift;                    /* shift to apply after scaling */                   (2)
  23.   uint32_t blkCnt;                               /* loop counter */
  24. #ifndef ARM_MATH_CM0_FAMILY
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */
  26.   q15_t in1, in2, in3, in4;
  27.   q31_t inA1, inA2;                              /* Temporary variables */
  28.   q31_t out1, out2, out3, out4;
  29.   /*loop Unrolling */
  30.   blkCnt = blockSize >> 2u;
  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.     /* Reading 2 inputs from memory */
  36.     inA1 = *__SIMD32(pSrc)++;                                                                       (3)
  37.     inA2 = *__SIMD32(pSrc)++;
  38.     /* C = A * scale */
  39.     /* Scale the inputs and then store the 2 results in the destination buffer        
  40.      * in single cycle by packing the outputs */
  41.     out1 = (q31_t) ((q15_t) (inA1 >> 16) * scaleFract);                                             (4)
  42.     out2 = (q31_t) ((q15_t) inA1 * scaleFract);
  43.     out3 = (q31_t) ((q15_t) (inA2 >> 16) * scaleFract);
  44.     out4 = (q31_t) ((q15_t) inA2 * scaleFract);
  45.     /* apply shifting */
  46.     out1 = out1 >> kShift;
  47.     out2 = out2 >> kShift;
  48.     out3 = out3 >> kShift;
  49.     out4 = out4 >> kShift;
  50.     /* saturate the output */
  51.     in1 = (q15_t) (__SSAT(out1, 16));                                                               (5)
  52.     in2 = (q15_t) (__SSAT(out2, 16));
  53.     in3 = (q15_t) (__SSAT(out3, 16));
  54.     in4 = (q15_t) (__SSAT(out4, 16));
  55.     /* store the result to destination */                                                           (6)
  56.     *__SIMD32(pDst)++ = __PKHBT(in2, in1, 16);
  57.     *__SIMD32(pDst)++ = __PKHBT(in4, in3, 16);
  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 * scale */
  67.     /* Scale the input and then store the result in the destination buffer. */
  68.     *pDst++ = (q15_t) (__SSAT(((*pSrc++) * scaleFract) >> kShift, 16));
  69.     /* Decrement the loop counter */
  70.     blkCnt--;
  71.   }
  72. #else
  73.   /* Run the below code for Cortex-M0 */
  74.   /* Initialize blkCnt with number of samples */
  75.   blkCnt = blockSize;
  76.   while(blkCnt > 0u)
  77.   {
  78.     /* C = A * scale */
  79.     /* Scale the input and then store the result in the destination buffer. */
  80.     *pDst++ = (q15_t) (__SSAT(((q31_t) * pSrc++ * scaleFract) >> kShift, 16));
  81.     /* Decrement the loop counter */
  82.     blkCnt--;
  83.   }
  84. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  85. }
复制代码
1. 源数据和比例因子的数据格式都是Q15,这样的话,输出结果就是1.15 * 1.15 = 2.30格式,由于输出结果也是Q15格式,所以输出结果需要饱和处理。
2. 这个变量设计很巧妙,这样下面处理正数左移和负数右移就很方面了,可以直接使用一个右移就可以实现。
3. 读取两个Q15格式的数据。
4. 将源数据乘以比例因子后赋值给Q31格式的变量。
5. 对输出结果做饱和处理。
6. 通过调用一次__PKHBT指令,将两个Q15格式的数据都赋值给目的变量。

9.5.4 arm_scale_q7

    这个函数用于求8位定点数的比例放缩,源代码分析如下:
  1. /**   
  2. * @brief Multiplies a Q7 vector by a scalar.   
  3. * @param[in]       *pSrc points to the input vector   
  4. * @param[in]       scaleFract fractional portion of the scale value   
  5. * @param[in]       shift number of bits to shift the result by   
  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>                                                              (1)
  11. * par   
  12. * The input data <code>*pSrc</code> and <code>scaleFract</code> are in 1.7 format.            
  13. * These are multiplied to yield a 2.14 intermediate result and this is shifted with saturation to 1.7 format.   
  14. */
  15. void arm_scale_q7(
  16.   q7_t * pSrc,
  17.   q7_t scaleFract,
  18.   int8_t shift,
  19.   q7_t * pDst,
  20.   uint32_t blockSize)
  21. {
  22.   int8_t kShift = 7 - shift;                     /* shift to apply after scaling */                   (2)
  23.   uint32_t blkCnt;                               /* loop counter */
  24. #ifndef ARM_MATH_CM0_FAMILY
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */
  26.   q7_t in1, in2, in3, in4, out1, out2, out3, out4;      /* Temporary variables to store input & output */
  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.     /* Reading 4 inputs from memory */
  34.     in1 = *pSrc++;
  35.     in2 = *pSrc++;
  36.     in3 = *pSrc++;
  37.     in4 = *pSrc++;
  38.     /* C = A * scale */
  39.     /* Scale the inputs and then store the results in the temporary variables. */
  40.     out1 = (q7_t) (__SSAT(((in1) * scaleFract) >> kShift, 8));                                        (3)
  41.     out2 = (q7_t) (__SSAT(((in2) * scaleFract) >> kShift, 8));
  42.     out3 = (q7_t) (__SSAT(((in3) * scaleFract) >> kShift, 8));
  43.     out4 = (q7_t) (__SSAT(((in4) * scaleFract) >> kShift, 8));
  44.     /* Packing the individual outputs into 32bit and storing in   
  45.      * destination buffer in single write */
  46.     *__SIMD32(pDst)++ = __PACKq7(out1, out2, out3, out4);                                             (4)
  47.     /* Decrement the loop counter */
  48.     blkCnt--;
  49.   }
  50.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
  51.    ** No loop unrolling is used. */
  52.   blkCnt = blockSize % 0x4u;
  53.   while(blkCnt > 0u)
  54.   {
  55.     /* C = A * scale */
  56.     /* Scale the input and then store the result in the destination buffer. */
  57.     *pDst++ = (q7_t) (__SSAT(((*pSrc++) * scaleFract) >> kShift, 8));
  58.     /* Decrement the loop counter */
  59.     blkCnt--;
  60.   }
  61. #else
  62.   /* Run the below code for Cortex-M0 */
  63.   /* Initialize blkCnt with number of samples */
  64.   blkCnt = blockSize;
  65.   while(blkCnt > 0u)
  66.   {
  67.     /* C = A * scale */
  68.     /* Scale the input and then store the result in the destination buffer. */
  69.     *pDst++ = (q7_t) (__SSAT((((q15_t) * pSrc++ * scaleFract) >> kShift), 8));
  70.     /* Decrement the loop counter */
  71.     blkCnt--;
  72.   }
  73. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
  74. }
复制代码
1. 源数据和比例因子的数据格式都是Q7,这样的话,输出结果就是1.7 * 1.7 = 2.14格式,由于输出结果也是Q7格式,所以输出结果需要饱和处理。
2. 这个变量设计很巧妙,这样下面处理正数左移和负数右移就很方面了,可以直接使用一个右移就可以实现。
3. 对源数据和比例因子的输出结果做8位精度的饱和处理。

9.5.5 实例讲解

实验目的:
    1. 四种种类型数据的比例放缩。
实验内容:
    1. 按下按键DOWN 串口打印输出结果
实验现象:
    通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:
9.5.png

程序设计:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DSP_Scale
  4. *    功能说明: 比例因子
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DSP_Scale(void)
  10. {
  11. static float32_t   pSrcA[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};
  12. static float32_t   scale = 0.0f;  
  13. static float32_t   pDst[5];  
  14. static q31_t  pSrcA1[5] = {0x6fffffff,1,1,1,1};  
  15. static q31_t  scale1 = 0x6fffffff;  
  16. static q31_t  pDst1[5];   
  17. static q15_t  pSrcA2[5] = {0x6fff,1,1,1,1};  
  18. static q15_t  scale2 = 0x6fff;  
  19. static q15_t  pDst2[5];   
  20. static q7_t  pSrcA3[5] = {0x70,1,1,1,1};
  21. static q7_t  scale3 = 0x6f;  
  22. static q7_t pDst3[5];  
  23. scale += 0.1f;
  24. arm_scale_f32(pSrcA, scale, pDst, 5);
  25. printf("arm_sub_f32 = %frn", pDst[0]);
  26. scale1 += 1;
  27. arm_scale_q31(pSrcA1, scale1, 0, pDst1, 5);
  28. printf("arm_scale_q31 = %xrn", pDst1[0]);
  29. scale2 += 1;
  30. arm_scale_q15(pSrcA2, scale2, 0, pDst2, 5);
  31. printf("arm_scale_q15 = %xrn", pDst2[0]);
  32. scale3 += 1;
  33. arm_scale_q7(pSrcA3, scale3, 0, pDst3, 5);
  34. printf("arm_scale_q7 = %xrn", pDst3[0]);
  35. printf("***********************************rn");
  36. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2015-3-19 10:58:11 | 显示全部楼层
9.6 BasicMathFunctions的重要说明

    截至到这里,BasicMathFunctions函数已经讲解完了,也许大家也发现了这些函数的一些共同点,在前面第8章的时候我们简单的阐述过,这里再进一步的阐述一下:
l 这些函数基本都是支持重入的。
l 基本每个函数都有四种数据类型,F32,Q31,Q15,Q7。
l 函数中数值的处理基本都是4个为一组,这么做的原因是F32,Q31,Q15,Q7就可以统一采用一个程序设计架构,便于管理。更重要的是可以在Q15和Q7数据处理中很好的发挥SIMD指令的作用(因为4个为一组的话,可以用SIMD指令正好处理2个Q15数据或者4个Q7数据)。
l 部分函数支持目标指针和源指针指向相同的缓冲区。
    关于这个的使用,我们没有在前面的讲解中举例子,下面举一个简单的例子进行说明,这里就以9.5小节中scale函数进行说明:
  1. static void DSP_Scale(void)
  2. {
  3. static float32_t   pSrcA[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};
  4. static float32_t   scale = 0.0f;  
  5. static q31_t  pSrcA1[5] = {0x6fffffff,1,1,1,1};  
  6. static q31_t  scale1 = 0x6fffffff;  
  7. static q15_t  pSrcA2[5] = {0x6fff,1,1,1,1};  
  8. static q15_t  scale2 = 0x6fff;  
  9. static q7_t  pSrcA3[5] = {0x70,1,1,1,1};
  10. static q7_t  scale3 = 0x6f;  
  11. scale += 0.1f;
  12. arm_scale_f32(pSrcA, scale, pSrcA, 5);              (1)
  13. printf("arm_sub_f32 = %frn", pSrcA[0]);
  14. scale1 += 1;
  15. arm_scale_q31(pSrcA1, scale1, 0, pSrcA1, 5);        (2)
  16. printf("arm_scale_q31 = %xrn", pSrcA1[0]);
  17. scale2 += 1;
  18. arm_scale_q15(pSrcA2, scale2, 0, pSrcA2, 5);        (3)
  19. printf("arm_scale_q15 = %xrn", pSrcA2[0]);
  20. scale3 += 1;
  21. arm_scale_q7(pSrcA3, scale3, 0, pSrcA3, 5);         (4)
  22. printf("arm_scale_q7 = %xrn", pSrcA3[0]);
  23. printf("***********************************rn");
  24. }
复制代码
上面代码的(1)至(4)目标指针和源指针指向相同的缓冲区。

9.7 总结

    BasicMathFunctions函数就跟大家讲这么多,希望初学的同学多多的联系,并在自己以后的项目中多多使用,效果必将事半功倍。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-5 03:33 , Processed in 0.317444 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表