特别说明:完整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位浮点数的相反数,源代码分析如下: - /**
- * @brief Negates the elements of a floating-point vector.
- * @param[in] *pSrc points to the input vector
- * @param[out] *pDst points to the output vector
- * @param[in] blockSize number of samples in the vector
- * @return none.
- */
-
- void arm_negate_f32(
- float32_t * pSrc,
- float32_t * pDst,
- uint32_t blockSize)
- {
- uint32_t blkCnt; /* loop counter */
-
-
- #ifndef ARM_MATH_CM0_FAMILY
-
- /* Run the below code for Cortex-M4 and Cortex-M3 */
- float32_t in1, in2, in3, in4; /* temporary variables */
-
- /*loop Unrolling */
- blkCnt = blockSize >> 2u;
-
- /* First part of the processing with loop unrolling. Compute 4 outputs at a time.
- ** a second loop below computes the remaining 1 to 3 samples. */
- while(blkCnt > 0u)
- {
- /* read inputs from source */
- in1 = *pSrc;
- in2 = *(pSrc + 1);
- in3 = *(pSrc + 2);
- in4 = *(pSrc + 3);
-
- /* negate the input */ (1)
- in1 = -in1;
- in2 = -in2;
- in3 = -in3;
- in4 = -in4;
-
- /* store the result to destination */
- *pDst = in1;
- *(pDst + 1) = in2;
- *(pDst + 2) = in3;
- *(pDst + 3) = in4;
-
- /* update pointers to process next samples */
- pSrc += 4u;
- pDst += 4u;
-
- /* Decrement the loop counter */
- blkCnt--;
- }
-
- /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
- ** No loop unrolling is used. */
- blkCnt = blockSize % 0x4u;
-
- #else
-
- /* Run the below code for Cortex-M0 */
-
- /* Initialize blkCnt with number of samples */
- blkCnt = blockSize;
-
- #endif /* #ifndef ARM_MATH_CM0_FAMILY */
-
- while(blkCnt > 0u)
- {
- /* C = -A */
- /* Negate and then store the results in the destination buffer. */
- *pDst++ = -*pSrc++;
-
- /* Decrement the loop counter */
- blkCnt--;
- }
- }
复制代码1. 浮点数的相反数求解比较简单,直接在相应的变量前加上负号即可。
9.1.2 arm_negate_q31 这个函数用于求32位定点数的相反数,源代码分析如下: - /**
- * @brief Negates the elements of a Q31 vector.
- * @param[in] *pSrc points to the input vector
- * @param[out] *pDst points to the output vector
- * @param[in] blockSize number of samples in the vector
- * @return none.
- *
- * <b>Scaling and Overflow Behavior:</b> (1)
- * \par
- * The function uses saturating arithmetic.
- * The Q31 value -1 (0x80000000) will be saturated to the maximum allowable positive value 0x7FFFFFFF.
- */
-
- void arm_negate_q31(
- q31_t * pSrc,
- q31_t * pDst,
- uint32_t blockSize)
- {
- q31_t in; /* Temporary variable */
- uint32_t blkCnt; /* loop counter */
-
- #ifndef ARM_MATH_CM0_FAMILY
-
- /* Run the below code for Cortex-M4 and Cortex-M3 */
- q31_t in1, in2, in3, in4;
-
- /*loop Unrolling */
- blkCnt = blockSize >> 2u;
-
- /* First part of the processing with loop unrolling. Compute 4 outputs at a time.
- ** a second loop below computes the remaining 1 to 3 samples. */
- while(blkCnt > 0u)
- {
- /* C = -A */
- /* Negate and then store the results in the destination buffer. */
- in1 = *pSrc++;
- in2 = *pSrc++;
- in3 = *pSrc++;
- in4 = *pSrc++;
-
- *pDst++ = __QSUB(0, in1); (2)
- *pDst++ = __QSUB(0, in2);
- *pDst++ = __QSUB(0, in3);
- *pDst++ = __QSUB(0, in4);
-
- /* Decrement the loop counter */
- blkCnt--;
- }
-
- /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
- ** No loop unrolling is used. */
- blkCnt = blockSize % 0x4u;
-
- #else
-
- /* Run the below code for Cortex-M0 */
-
- /* Initialize blkCnt with number of samples */
- blkCnt = blockSize;
-
- #endif /* #ifndef ARM_MATH_CM0_FAMILY */
-
-
- while(blkCnt > 0u)
- {
- /* C = -A */
- /* Negate and then store the result in the destination buffer. */
- in = *pSrc++;
- *pDst++ = (in == INT32_MIN) ? INT32_MAX : -in;
-
- /* Decrement the loop counter */
- blkCnt--;
- }
- }
复制代码1. 这个函数使用了饱和运算。 饱和运算数值0x80000000将变成0x7FFFFFFF。 2. 饱和运算__QSUB我们在上一章已经详细讲述了,这就就是实现数值0减去相应的参数变量。
9.1.3 arm_negate_q15 这个函数用于求16位定点数的相反数,源代码分析如下: - /**
- * @brief Negates the elements of a Q15 vector.
- * @param[in] *pSrc points to the input vector
- * @param[out] *pDst points to the output vector
- * @param[in] blockSize number of samples in the vector
- * @return none.
- *
- * \par Conditions for optimum performance
- * Input and output buffers should be aligned by 32-bit
- *
- *
- * <b>Scaling and Overflow Behavior:</b> (1)
- * \par
- * The function uses saturating arithmetic.
- * The Q15 value -1 (0x8000) will be saturated to the maximum allowable positive value 0x7FFF.
- */
-
- void arm_negate_q15(
- q15_t * pSrc,
- q15_t * pDst,
- uint32_t blockSize)
- {
- uint32_t blkCnt; /* loop counter */
- q15_t in;
-
- #ifndef ARM_MATH_CM0_FAMILY
-
- /* Run the below code for Cortex-M4 and Cortex-M3 */
-
- q31_t in1, in2; /* Temporary variables */
-
-
- /*loop Unrolling */
- blkCnt = blockSize >> 2u;
-
- /* First part of the processing with loop unrolling. Compute 4 outputs at a time.
- ** a second loop below computes the remaining 1 to 3 samples. */
- while(blkCnt > 0u)
- {
- /* C = -A */
- /* Read two inputs at a time */ (2)
- in1 = _SIMD32_OFFSET(pSrc);
- in2 = _SIMD32_OFFSET(pSrc + 2);
-
- /* negate two samples at a time */ (3)
- in1 = __QSUB16(0, in1);
-
- /* negate two samples at a time */
- in2 = __QSUB16(0, in2);
-
- /* store the result to destination 2 samples at a time */ (4)
- _SIMD32_OFFSET(pDst) = in1;
- /* store the result to destination 2 samples at a time */
- _SIMD32_OFFSET(pDst + 2) = in2;
-
-
- /* update pointers to process next samples */
- pSrc += 4u;
- pDst += 4u;
-
- /* Decrement the loop counter */
- blkCnt--;
- }
-
- /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
- ** No loop unrolling is used. */
- blkCnt = blockSize % 0x4u;
-
- #else
-
- /* Run the below code for Cortex-M0 */
-
- /* Initialize blkCnt with number of samples */
- blkCnt = blockSize;
-
- #endif /* #ifndef ARM_MATH_CM0_FAMILY */
-
- while(blkCnt > 0u)
- {
- /* C = -A */
- /* Negate and then store the result in the destination buffer. */
- in = *pSrc++;
- *pDst++ = (in == (q15_t) 0x8000) ? 0x7fff : -in;
-
- /* Decrement the loop counter */
- blkCnt--;
- }
- }
复制代码1. 这个函数使用了饱和运算。 饱和运算数值0x8000将变成0x7FFF。 2. 一次读取两个Q15格式的数据。 3. 由于__QSUB是SIMD指令,这里可以实现一次计算两个Q15数据的相反数。 4. 这里实现一次赋值两个Q15数据。
9.1.4 arm_negate_q7 这个函数用于求8位定点数的相反数,源代码分析如下: - /**
- * @brief Negates the elements of a Q7 vector.
- * @param[in] *pSrc points to the input vector
- * @param[out] *pDst points to the output vector
- * @param[in] blockSize number of samples in the vector
- * @return none.
- *
- * <b>Scaling and Overflow Behavior:</b> (1)
- * \par
- * The function uses saturating arithmetic.
- * The Q7 value -1 (0x80) will be saturated to the maximum allowable positive value 0x7F.
- */
-
- void arm_negate_q7(
- q7_t * pSrc,
- q7_t * pDst,
- uint32_t blockSize)
- {
- uint32_t blkCnt; /* loop counter */
- q7_t in;
-
- #ifndef ARM_MATH_CM0_FAMILY
-
- /* Run the below code for Cortex-M4 and Cortex-M3 */
- q31_t input; /* Input values1-4 */
- q31_t zero = 0x00000000; (2)
-
-
- /*loop Unrolling */
- blkCnt = blockSize >> 2u;
-
- /* First part of the processing with loop unrolling. Compute 4 outputs at a time.
- ** a second loop below computes the remaining 1 to 3 samples. */
- while(blkCnt > 0u)
- {
- /* C = -A */
- /* Read four inputs */
- input = *__SIMD32(pSrc)++; (3)
-
- /* Store the Negated results in the destination buffer in a single cycle by packing the results */
- *__SIMD32(pDst)++ = __QSUB8(zero, input); (4)
-
- /* Decrement the loop counter */
- blkCnt--;
- }
-
- /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
- ** No loop unrolling is used. */
- blkCnt = blockSize % 0x4u;
-
- #else
-
- /* Run the below code for Cortex-M0 */
-
- /* Initialize blkCnt with number of samples */
- blkCnt = blockSize;
-
- #endif /* #ifndef ARM_MATH_CM0_FAMILY */
-
- while(blkCnt > 0u)
- {
- /* C = -A */
- /* Negate and then store the results in the destination buffer. */ \
- in = *pSrc++;
- *pDst++ = (in == (q7_t) 0x80) ? 0x7f : -in;
-
- /* Decrement the loop counter */
- blkCnt--;
- }
- }
复制代码1. 这个函数使用了饱和运算。 饱和运算数值0x80将变成0x7F。 2. 给局部变量赋初值,防止默认初始值不是0,所以从某种意义上来说,给变量赋初值是很有必要的。 3. 一次读取4个Q7格式的数据到input里面。 4. 通过__QSUB8实现一次计算四个Q7格式数据的相反数。
9.1.5 实例讲解实验目的: 1. 四种类型数据的相反数。 实验内容: 1. 按下K1键, 串口打印输出结果 实验现象: 通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下: 程序设计: - /*
- *********************************************************************************************************
- * 函 数 名: DSP_Negate
- * 功能说明: 求相反数
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void DSP_Negate(void)
- {
- static float32_t pSrc;
- static float32_t pDst;
- static q31_t pSrc1;
- static q31_t pDst1;
- static q15_t pSrc2;
- static q15_t pDst2;
- static q7_t pSrc3 = 127; /* 为了说明问题,在这里设置初始值为127,然后查看0x80是否饱和为0x7F */
- static q7_t pDst3;
- pSrc -= 1.23f;
- arm_negate_f32(&pSrc, &pDst, 1);
- printf("arm_negate_f32 = %f\r\n", pDst);
-
- pSrc1 -= 1;
- arm_negate_q31(&pSrc1, &pDst1, 1);
- printf("arm_negate_q31 = %d\r\n", pDst1);
-
- pSrc2 -= 1;
- arm_negate_q15(&pSrc2, &pDst2, 1);
- printf("arm_negate_q15 = %d\r\n", pDst2);
-
- pSrc3 += 1;
- arm_negate_q7(&pSrc3, &pDst3, 1);
- printf("arm_negate_q7 = %d\r\n", pDst3);
- printf("***********************************\r\n");
- }
复制代码
|
9.2.2 arm_offset_q31
9.2.3 arm_offset_q15
9.2.4 arm_offset_q7
9.2.5 实例讲解
9.3.2 arm_shift_q15
9.3.4 实例讲解
9.4.2 arm_sub_q31
9.4.3 arm_sub_q15
9.4.4 arm_sub_q7
9.4.5 实例讲解
9.5.2 arm_scale_q31
9.5.3 arm_scale_q15
9.5.5 实例讲解
9.7 总结