完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
8个回答
|
|
第12章DSP基础函数-相反数,
12.1初学者重要提示 这里简单的跟大家介绍一下DSP中函数的通用格式,就不用库就不再赘述了。 这些函数基本都是支持重入的。 基本每个函数都有四种数据类型,F32,Q31,Q15,Q7。 函数中数值的处理是4个,基本的原因是F32,Q31,Q1,Q7就统一采用一个程序设计架构,便于管理。更重要的是可以在Q15和Q7处理中很好的发挥SIMD的作用(因为4个为指令的话,可以用SIMD说明处理2个Q15或4个Q7数据)。 部分功能是目标路径和源头实现支持。 为什么定点DSP运算输出的时候容易出现结果为0的情况。mod=viewthread&tid=95194 12.2 DSP基础运算指令 绕组基础实验指令: 相反数函数QSUB,QSUB16和QSUB8。 偏移函数QADD,QADD16QADD8。 转移函数PKHBT和SSAT。 减法函数QSUB,QSUB1和QSUB8。 比例函数函数PKHBT和SSAT。 这里特别注意饱和运算问题,在第11章的第2小节有详细说明。 12.3相反数(向量取反) 这部分函数主要用于求相反数,公式描述如下: pDst [N] = -pSrc [n]的, 0=n 《 blockSize 注意,这部分函数支持目标路径和源目标。《 12.3.1 函数arm_negate_f32 函数基础: void arm_negate_f32 ( 2. const float32_t * pSrc , 3. float32_t * pDst , 4. uint32_t blockSize ) 5. { 6. uint32_t blkCnt ; /*循环循环*/ 7. 8. #如果定义( ARM_MATH_NEON_EXPERIMENTAL ) 9. float32x4_t vec1 ; 10. float32x4_t res ; 11. 12. /* 一次计算 4 个输出 */ 13. blkCnt =块大小》》 2 U ; 14. 15. 而(blkCnt 》 0 U) 16 { 17 / * Ç = -甲* / 18 19 / *求反然后将结果存入目标缓冲区。* / 20 VEC1 = vld1q_f32(PSRC ) ; 21. res = vnegq_f32 ( vec1 ) ; 22. vst1q_f32 ( pDst , res ) ; 23. 24. /* 向上跳跃 */ 25. pSrc += 4 ; 26. pDst += 4 ; 27. 28. / *减少循环计数器* / 29 blkCnt - ; 30. } 31. 32. / *尾* / 33 blkCnt = BLOCKSIZE& 0x3 ; 34. 35. # else 36. #如果已定义 ( ARM_MATH_LOOPUNROLL ) 37. 38. /* 循环展开:一次计算 4 个输出 */ 39. blkCnt = blockSize 》》 2 ü ; 40. 41. 而(blkCnt 》 0 U) 42 { 43 / * Ç = -甲* / 44 45 / *取反并将结果存储在目标缓冲区中。* / 46 * pDst ++ = - * PSRC + +; 47. 48. * pDst++ = - * pSrc ++; 49. 50. * pDst ++ = - * pSrc ++; 51. 52. * pDst ++ = - * pSrc ++; 53. 54. /*递减循环*/ 55 。 blkCnt -- ; 56. } 57. 58. /* 循环展开:计算消费输出*/ 59. blkCnt = blockSize % 0 x4U ; 60. 61. #其他 62. 63. /* 用样本数初始化 blkCnt */ 64. blkCnt = blockSize ; 65. 66. #endif /* #if 已定义 (ARM_MATH_LOOPUNROLL) */ 67. #endif /* #if defined(ARM_MATH_NEON_EXPERIMENTAL) */ 68. 69. while ( blkCnt 》 0 U ) 70. { 71. /* C = -A * / 72 73 / *必然转换结果存储在缓冲目标* / 74 * pDst ++ = - * PSRC ++; 75. 76./*递减循环数*/ 77。 78. } 79. 80. } 函数描述: 这个函数用于求32位浮点数的相反数。 函数解析: 第8到35行,用于NEON指令集,当前的CM内核不支持。 第36到61行,实现四次为一组计数,结果是戏剧执行速度,同时降低循环占用时间。 浮点数的相反数求解比较,直接在各自的变量前简单加上数字识别。 第 69 到 7 行,四个为一组数据的处理或不采用四个为一组时数据处理。 函数参数: 第 1 个参数是原数据地址。 第 2 个参数是求相反数后目的数据地址。 第3个参数转换的数据个数,这里是指的浮点数。 12.3.2函数arm_negate _q31 函数原型: void arm_negate_q31 ( 2. const q31_t * pSrc , 3. q31_t * pDst , 4. uint32_t blockSize ) 5. { 6. uint32_t blkCnt ; /*循环循环*/ 7. q31_t in ; /* 临时输入变量 */ 8. 9. # if defined ( ARM_MATH_LOOPUNROLL ) 10. 11. /* 循环展开:一次计算 4 个输出 */ 12. blkCnt =块大小》》 2 U ; 13.14 。 而( blkCnt 》 0 û ) 15 { 16 / * C = - A * / 17, 18 / *取反授权结果存储在目标偶中。* / 19,在 = * PSRC ++ ; 20. #如果已定义 ( ARM_MATH_DSP ) 21. * pDst ++ = __QSUB ( 0 , in ) ; 22. # else 23. * pDst ++ = (在 == INT32_MIN中) ? INT32_MAX : -在; 24. #endif 25. 26. in = * pSrc ++ ; 27. #如果已定义 ( ARM_MATH_DSP ) 28. * pDst ++ = __QSUB ( 0 , in ) ; 29. # else 30. * pDst ++ = (在== INT32_MIN中) ?INT32_MAX : -在; 31. #endif 32. 33. in = * pSrc ++ ; 34. #如果已定义 ( ARM_MATH_DSP ) 35. * pDst ++ = __QSUB ( 0 , in ) ; 36. # else 37. * pDst ++ = ( in == INT32_MIN ) ? INT32_MAX : -在; 38. #endif 39. 40. in = * pSrc ++ ; 41. #如果已定义 ( ARM_MATH_DSP ) 42. * pDst ++ = __QSUB ( 0 , in ) ; 43. # else 44. * pDst ++ = ( in == INT32_MIN ) ? INT32_MAX : -在; 45. #endif 46. 47. /*递减循环周期*/ 48. blkCnt -- ; 49. } 50. 51. /* 循环展开:计算消费输出*/ 52. blkCnt = blockSize % 0 x4U ; 53. 54. # else 55. 56. /* 用样本数初始化 blkCnt */ 57. blkCnt = blockSize ; 58. 59. #endif /* #if 定义 (ARM_MATH_LOOPUNROLL) */ 60. 61. while ( blkCnt 》 0 U ) 62. { 63. /* C = -A */ 64. 65. /*取反签结果存储在目标棉花中。*/ 66. in = * pSrc ++ ; 67. #如果已定义 ( ARM_MATH_DSP ) 68. * pDst ++ = __QSUB ( 0 , in ) ; 69. # else 70. * pDst ++ = ( in == INT32_MIN ) ? INT32_MAX : -在; 71. #endif 72. 73. /*递减循环周期*/ 74. blkCnt -- ; 75. } 76. 77. } 函数描述: 用于求32位定点数的相反数。 函数解析: 第 9 到 54 行,实现了四个为一组进行计数,优点是执行速度,同时降低循环占用时间。 第 61 到 7 行,四个为一组数据的处理或者不采用一组为一组时数据处理。 对于已经Q31格式的数据,学习脑会写数据0x800x7ffffff因为,最小负数0x80000000(对应浮点数-1),求相反数后,是个正的0x800000000(对应浮点数正1),Q31触发表示的声音0x7ffffff,因此会被处理为正数意见0x7ffffffff。 这里重点说一下函数__QSUB,实际上这个Cortex-M7,M4/M3的一个指令,用于实现函数减法。例如:函数__QSUB(0,in1)的作用就是实现0 – in1并返回结果。 __QSUB实现的是32位QSUB16和__SUB8的减法。 函数参数: 第 1 个参数是原数据地址。 第 2 个参数是求相反数后目的数据地址。 第3个参数转换的数据个数,这里是指的定点个数。 12.3.3 函数arm_negate_q15 函数原型: void arm_negate_q15 ( 2. const q15_t * pSrc , 3. q15_t * pDst , 4. uint32_t blockSize ) 5. { 6. uint32_t blkCnt ; /* 循环计数器 */ 7. q15_t in ; /* 临时输入变量 */ 8. 9. # if defined ( ARM_MATH_LOOPUNROLL ) 10. 11. # if defined ( ARM_MATH_DSP) 12. q31_t in1 ; /* 临时输入变量 */ 13. #endif 14. 15. /* 循环展开:一次计算 4 个输出 */ 16. blkCnt = blockSize 》》 2 U ; 17. 18. while ( blkCnt 》 0 U ) 19. { 20. /* C = -A */ 21. 22. # if defined ( ARM_MATH_DSP ) 23. /* 取反并将结果存储在目标缓冲区中(每次2个样本时间)。*/ 24。 in1 = read_q15x2_ia ( ( q15_t ** ) & pSrc ) ; 25. write_q15x2_ia ( & pDst , __QSUB16 ( 0 , in1 ) ) ; 26. 27. in1 = read_q15x2_ia ( ( q15_t ** ) & pSrc ) ; 28. write_q15x2_ia ( & pDst , __QSUB16 ( 0 , in1 )) ; 29. # else 30. in = * pSrc ++ ; 31. * pDst ++ = ( in == ( q15_t ) 0x8000 ) ? ( q15_t ) 0x7fff : -在; 32. 33. in = * pSrc ++ ; 34. * pDst ++ = ( in == ( q15_t ) 0x8000 ) ? ( q15_t ) 0x7fff : -在; 35. 36. in = * pSrc ++ ; 37. * pDst ++ = ( in == ( q15_t ) 0x8000 ) ? ( q15_t ) 0x7fff : -在; 38. 39. in = * pSrc ++ ; 40. * pDst ++ = ( in == ( q15_t) 0x8000 ) ? ( q15_t ) 0x7fff : -在; 41. #endif 42. 43. /* 递减循环计数器 */ 44. blkCnt -- ; 45. } 46. 47. /* 循环展开:计算剩余输出 */ 48. blkCnt = blockSize % 0 x4U ; 49. 50. # else 51. 52. /* 用样本数初始化 blkCnt */ 53. blkCnt =块大小; 54. 55. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 56. 57. while ( blkCnt 》 0 U ) 58. { 59. /* C = -A */ 60. 61. /* 否定并存储结果在目标缓冲区中。*/ 62. in = * pSrc ++ ; 63. * pDst ++ = ( in == ( q15_t ) 0x8000 ) ? ( q15_t ) 0x7fff : -在; 64. 65. /* 递减循环计数器 */ 66. blkCnt -- ; 67. } 68. 69. } 函数描述: 用于求16位定点数的绝对值。 函数解析: 第 9 到 50 行,实现了四个为一组进行计数,优点是执行速度,同时降低循环占用时间。 第 57 到 6 行,四个为一组数据的处理或不采用一组为一组时数据处理。 Q15格式的数据,学习数学会写入数据0x000求对应数后回复为0x7fff。因为最小负数为0x7fff。因为最小负数(对应浮点数-1),求对应数后,是个正的0x8000(对应浮点数正1),已经超过Q15引发的表示结果0x7fff,因此会被处理为正数报告0x7fff。 __QSUB16用于实现16位数据的减减法。 函数参数: 第 1 个参数是原数据地址。 第 2 个参数是求相反数后目的数据地址。 第3个参数转换的数据个数,这里是指的定点个数。 12.3.4 函数arm_negate_q7 函数原型: void arm_negate_q7 ( 2. const q7_t * pSrc , 3. q7_t * pDst , 4. uint32_t blockSize ) 5. { 6. uint32_t blkCnt ; /* 循环计数器 */ 7. q7_t in ; /* 临时输入变量 */ 8. 9. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 10. 11. #如果已 定义 ( ARM_MATH_DSP ) 12. q31_t in1 ; /* 临时输入变量 */ 13. #endif 14. 15. /* 循环展开:一次计算 4 个输出 */ 16. blkCnt = blockSize 》》 2 U ; 17. 18. while ( blkCnt 》 0 U ) 19. { 20. /* C = -A */ 21. 22. # if defined ( ARM_MATH_DSP ) 23. /* 取反并将结果存储在目标缓冲区中(每次4个样本时间)。*/ 24。 in1 = read_q7x4_ia ( ( q7_t ** ) & pSrc ) ; 25. write_q7x4_ia ( & pDst , __QSUB8 ( 0 , in1 ) ) ; 26. # else 27. in = * pSrc ++ ; 28. * pDst ++ = ( in == ( q7_t ) 0x80 ) ? ( q7_t ) 0x7f : -在; 29. 30. in = * pSrc ++ ; 31. * pDst ++ = ( in == ( q7_t ) 0x80 ) ? ( q7_t ) 0x7f : -在; 32. 33. in = * pSrc ++ ; 34. * pDst ++ = ( in == ( q7_t ) 0x80 ) ? (q7_t ) 0x7f : -在; 35. 36. in = * pSrc ++ ; 37. * pDst ++ = ( in == ( q7_t ) 0x80 ) ? ( q7_t ) 0x7f : -在; 38. #endif 39. 40. /* 递减循环计数器 */ 41. blkCnt -- ; 42. } 43. 44. /* 循环展开:计算剩余输出 */ 45. blkCnt = blockSize % 0 x4U ; 46. 47. # else 48. 49. /* 用样本数初始化 blkCnt */ 50. blkCnt = blockSize ; 51. 52. #endif /* #if 定义 (ARM_MATH_LOOPUNROLL) */ 53. 54. while ( blkCnt 》 0 U ) 55. { 56. /* C = -A */ 57. 58. /* 否定并将结果存储在目标缓冲区中。*/ 59. in = * pSrc ++ ; 60. 61. #如果已 定义 ( ARM_MATH_DSP ) 62. * pDst ++ = ( q7_t ) __QSUB ( 0 , in ) ; 63. # else 64. * pDst ++ = ( in == ( q7_t ) 0x80 ) ? ( q7_t ) 0x7f : -在; 65. #endif 66. 67. /* 递减循环计数器 */ 68. blkCnt -- ; 69. } 70. 71. } 函数描述: 用于求8位定点数的相反数, 函数解析: 第 9 到 47 行,实现了四个为一组进行计数,优点是执行速度,同时降低循环占用时间。 第 54 到 6 行,四个为一组数据的处理或者不采用四个为一组时数据处理。 因为最小负数0x80(对应浮点数为0x80),所以对应的数后,是个正的0x80(对应浮点数正1),已经超过Q7引发了表示的回头0x7f,因此会被处理为正数的意见0x7f。 __QSUB8用于实现8位数据的减法。 函数参数: 第 1 个参数是原数据地址。 第 2 个参数是求相反数后目的数据地址。 第3个参数转换的数据个数,这里是指的定点个数。 12.3.5 使用举例 程序设计: /* ****************************************************** ****************************************************** ***** * 函数数名:DSP_Negate * 功能说明:求相反数 *形参:无 * 返回值:无 ****************************************************** ****************************************************** ***** */ 静态 无效 DSP_Negate (无效) { float32_t pSrc = 0.0 f ; float32_t pDst ; q31_t pSrc1 = 0 ; q31_t pDst1 ; q15_t pSrc2 = 0 ; q15_t pDst2 ; q7_t pSrc3 = 0 ; q7_t pDst3 ; /*求相反数************************************/ pSrc -= 1.23 f ; arm_negate_f32 ( & pSrc , & pDst , 1 ) ; printf ( “arm_negate_f32 = %frn” , pDst ) ; pSrc1 -= 1 ; arm_negate_q31 ( & pSrc1 , & pDst1 , 1 ) ; printf ( “arm_negate_q31 = %drn” , pDst1 ) ; pSrc2 -= 1 ; arm_negate_q15 ( & pSrc2 , & pDst2 , 1 ) ; printf ( “arm_negate_q15 = %drn” , pDst2 ) ; pSrc3 += 1 ; arm_negate_q7 ( & pSrc3 , & pDst3 , 1 ) ; printf ( “arm_negate_q7 = %drn” , pDst3 ) ; printf ( “***********************************rn” ) ; } 实验现象: |
|
|
|
12.4偏移(矢量偏移)
这部分主要用于求偏移,公式描述函数如下: pDst[n] = pSrc[n] + offset, 0 《= n 《 blockSize. 注意,这部分功能支持目标。指针和源指针指向相同的缓冲区 12.4.1函数arm_offset_f32 函数原型: void arm_offset_f32 ( 2. const float32_t * pSrc , 3. float32_t offset , 4. float32_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /*循环循环*/ 8. 9. #如果已定义( ARM_MATH_NEON_EXPERIMENTAL ) 10. float32x4_t vec1 ; 11. float32x4_t res ; 12. 13. /* 一次计算 4 个输出 */ 14. blkCnt = blockSize 》》 2 U ; 15. 16. 而 ( blkCnt 》 0 û ) 17 { 18 / * C = A +偏移量* / 19, 20 / *添加偏移量,然后将结果存入目标缓冲区。* / 21 VEC1 = vld1q_f32 ( pSrc ) ; 22. RES = vaddq_f32 ( VEC1 , vdupq_n_f32 (偏移)) ; 23. vst1q_f32 ( pDst , res ) ; 24. 25. /* 向上传送 */ 26. pSrc += 4 ; 27. pDst += 4 ; 28. 29. /*递减循环表决*/ 30. blkCnt -- ; 31. } 32. 33. / *尾部* / 34 blkCnt = BLOCKSIZE & 0x3 ; 35. 36. #其他 37. #如果已定义 ( ARM_MATH_LOOPUNROLL ) 38. 39. /* 循环展开:一次计算 4 个输出 */ 40. blkCnt = blockSize 》》 2 U ; 41. 42. 而 ( blkCnt 》 0 û ) 43. { 44. / * C = A +偏移量* / 45 46 / *添加偏移量并将结果存储在目标缓冲区中。* / 47 * pDst ++ = ( * pSrc ++ ) +偏移; 48. 49. * pDst ++ = ( * pSrc ++ ) +偏移量; 50. 51. * pDst ++ = ( * pSrc ++ ) +偏移量; 52. 53. * pDst ++ = ( * pSrc ++ ) +偏移量; 54. 55. /* 递减循环算法 */ 56. blkCnt -- ; 57. } 58. 59. /* 循环展开:计算消费输出*/ 60. blkCnt = blockSize % 0 x4U ; 61. 62. # else 63. 64. /* 用样本数初始化 blkCnt */ 65. blkCnt = blockSize ; 66. 67. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 68. #endif /* #if defined(ARM_MATH_NEON_EXPERIMENTAL) */ 69. 70. while ( blkCnt 》 0 U ) 71. { 72. /* C = A +偏移量* / 73 74 / *添加偏移量并将结果存储在目标缓冲区中。* / 75 * pDst ++ = ( * PSRC ++ ) +偏移量; 76 。 /*递减 77循环决策*/ 78. blkCnt -- ; 79. } 80. 81. } 函数描述: 这个函数用于求32位浮点数的偏移。 函数解析: 第9到36行,用于NEON指令集,当前的CM内核不支持。 第37到62行,实现四次为一组进行计数,好处是戏剧执行速度,同时降低循环占用时间。 第 70 到 7 行,四个为一组数据的处理或者不采用四个为一组时数据处理。 函数参数: 第 1 个参数是源数据地址。 第2个参数是偏移量。 第3个参数是转换后的目的地址。 4个参数是浮点数个数,实际上就是出现的次数。 12.4.2函数arm_offset_q31 函数原型: void arm_offset_q31 ( 2. const q31_t * pSrc , 3. q31_t offset , 4. q31_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. 9. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 10. 11. /* 循环展开:一次计算 4 个输出 */ 12. blkCnt = blockSize》》 2 U ; 13. 14. while ( blkCnt 》 0 U ) 15. { 16. /* C = A + offset */ 17. 18. /* 添加偏移量并将结果存储在目标缓冲区中。*/ 19. #如果 定义 ( ARM_MATH_DSP ) 20. * pDst ++ = __QADD ( * pSrc ++ , offset ) ; 21. # else 22. * pDst ++ = (q31_t) clip_q63_to_q31 (( q63_t ) * PSRC ++ +偏移量); 23. #endif 24. 25. #如果已 定义 ( ARM_MATH_DSP ) 26. * pDst ++ = __QADD ( * pSrc ++ , offset ) ; 27. # else 28. * pDst ++ = ( q31_t ) clip_q63_to_q31 ( (q63_t ) * pSrc ++ +偏移量) ; 29. #endif 30. 31. #如果已 定义 ( ARM_MATH_DSP ) 32. * pDst ++ = __QADD ( * pSrc ++ , offset ) ; 33. # else 34. * pDst ++ = ( q31_t ) clip_q63_to_q31 ( ( q63_t ) * pSrc ++ +偏移量); 35. #endif 36. 37. #如果已 定义 ( ARM_MATH_DSP ) 38. * pDst ++ = __QADD ( * pSrc ++ , offset ) ; 39. # else 40. * pDst ++ = ( q31_t ) clip_q63_to_q31 ( ( q63_t ) * pSrc ++ + offset ) ; 41. #endif 42. 43. /* 递减循环计数器 */ 44. blkCnt -- ; 45. } 46. 47. /* 循环展开:计算剩余输出 */ 48. blkCnt = blockSize % 0 x4U ; 49. 50. # else 51. 52. /* 用样本数初始化 blkCnt */ 53. blkCnt = blockSize ; 54. 55. #endif /* #if 已定义 (ARM_MATH_LOOPUNROLL) */ 56. 57. while ( blkCnt》 0 U ) 58. { 59. /* C = A + offset */ 60. 61. /* 添加偏移量并将结果存储在目标缓冲区中。*/ 62. #如果 定义 ( ARM_MATH_DSP ) 63. * pDst ++ = __QADD ( * pSrc ++ , offset ) ; 64. # else 65. * pDst ++ = ( q31_t ) clip_q63_to_q31 ( ( q63_t ) *PSRC ++ +偏移量); 66. #endif 67. 68. /* 递减循环计数器 */ 69. blkCnt -- ; 70. } 71. 72. } 函数描述: 这个函数用于求两个32位定点数的偏移 函数解析: 第 9 到 50 行,实现了四个为一组进行计数,优点是执行速度,同时降低循环占用时间。 第 57 到 70 行,四个为一组数据的处理或者不采用一组为一组时数据处理。 __QADD实现32个原因的加法处理。输出的结果[0x80000000 0x7FFFFFF],这个结果将产生结果,负数产生到0x80000000,正数得到到0x7FFFFFF。 函数参数: 第 1 个参数是源数据地址。 第2个参数是偏移量。 第3个参数是转换后的目的地址。 4个参数是定点数个数,实际上就是执行第几次的次数。 12.4.3 函数arm_offset_q15 函数原型: void arm_offset_q15 ( 2. const q15_t * pSrc , 3. q15_t offset , 4. q15_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. 9. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 10. 11. #如果已 定义 ( ARM_MATH_DSP ) 12. q31_t offset_packed ; /* 偏移量打包为 32 位 */ 13. 14. /* 偏移量打包为 32 位以便使用 SIMD32 进行加法 */ 15. offset_packed = __PKHBT ( offset , offset , 16 ) ; 16. #endif 17. 18. /* 循环展开:一次计算 4 个输出 */ 19. blkCnt = blockSize 》》 2 U ; 20. 21. while ( blkCnt 》 0 U ) 22. { 23. /* C = A + offset */ 24. 25. # if defined ( ARM_MATH_DSP ) 26. /* 添加偏移量并将结果存储在目标缓冲区中(一次 2 个样本)。*/ 27. write_q15x2_ia ( & pDst , __QADD16 ( read_q15x2_ia ( ( q15_t ** ) & pSrc ) , offset_packed ) ) ; 28. write_q15x2_ia ( & pDst , __QADD16 ( read_q15x2_ia ( (q15_t ** ) & pSrc ) , offset_packed ) ) ; 29. # else 30. * pDst ++ = ( q15_t ) __SSAT ( ( ( q31_t ) * pSrc ++ + offset ) , 16 ) ; 31. * pDst ++ = ( q15_t ) __SSAT ( ( ( q31_t ) * pSrc ++ +偏移量) , 16 ) ; 32. * pDst ++ = ( q15_t ) __SSAT ( ( ( q31_t ) * pSrc ++ + offset ) , 16 ) ; 33. * pDst ++ = ( q15_t ) __SSAT ( ( ( q31_t ) * pSrc ++ + offset ) , 16 ) ; 34. #endif 35. 36. /* 递减循环计数器 */ 37. blkCnt -- ; 38. } 39. 40. /* 循环展开:计算剩余输出 */ 41. blkCnt = blockSize % 0 x4U ; 42. 43. # else 44. 45. /* 用样本数初始化 blkCnt */ 46. blkCnt = blockSize ; 47. 48. #endif /* #if 已定义 (ARM_MATH_LOOPUNROLL) */ 49. 50. while (blkCnt 》 0 U ) 51. { 52. /* C = A + offset */ 53. 54. /* 添加偏移量并将结果存储在目标缓冲区中。*/ 55. #如果 定义 ( ARM_MATH_DSP ) 56. * pDst ++ = ( q15_t ) __QADD16 ( * pSrc ++ , offset ) ; 57. # else 58. * pDst ++ = ( q15_t ) __SSAT ((( q31_t ) * PSRC ++ +偏移), 16 ); 59. #endif 60. 61. /* 递减循环计数器 */ 62. blkCnt -- ; 63. } 64. 65. } 函数描述: 这个函数用于求16位定点数的偏移。 函数解析: 第 9 到 43 行,实现了四个为一组进行计数,优点是执行速度,同时降低循环占用时间。 第 50 到 6 行,四个为一组数据的处理或者不采用一组为一组时数据处理。 函数__PKHBT也是SIMD指令,作用是将两个16位的数据合并成32位数据。用C实现的话,: 的#define __PKHBT(ARG1 , ARG2 , ARG3 ) ( ((( int32_t )(ARG1 ) 《《 0 ) & ( int32_t )0x0000FFFF ) | ((( int32_t )(ARG2 ) 《《 ARG3 ) & ( int32_t )0xFFFF0000地址) ) 函数read_q15x2_ia的原型如下: __STATIC_FORCEINLINE q31_t read_q15x2_ia ( q15_t ** pQ15 ) { q31_t val ; memcpy ( & val , * pQ15 , 4 ) ; * pQ15 += 2 ; 返回 ( val ) ; } 作用是读取16位数据,返回一个32位数据,指明数据地址,方便下次读取。 __QA16实现真实16DD的加法运算输出的范围[0x8000 0x7FFF],这个结果将产生产生产生结果,负数产生结果到0x8000,正数产生到0x7FFF。 __SSAT 也是 SIMD 指令,这里是将结果引发到 16 位精度。 函数参数: 第 1 个参数是源数据地址。 第2个参数是偏移量。 第3个参数是转换后的目的地址。 4个参数是定点数个数,实际上就是执行第几次的次数。 12.4.4 函数arm_offset_q7 函数原型: void arm_offset_q7 ( 2. const q7_t * pSrc , 3. q7_t offset , 4. q7_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. 9. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 10. 11. #如果已 定义 ( ARM_MATH_DSP ) 12. q31_t offset_packed ; /* 偏移量打包为 32 位 */ 13. 14. /* 偏移量打包为 32 位以便使用 SIMD32 进行加法 */ 15. offset_packed = __PACKq7 ( offset , offset , offset , offset ) ; 16. #endif 17. 18. /* 循环展开:一次计算 4 个输出 */ 19. blkCnt = blockSize 》》 2 U ; 20. 21. while ( blkCnt 》 0 U) 22. { 23. /* C = A + offset */ 24. 25. # if defined ( ARM_MATH_DSP ) 26. /* 添加偏移量并将结果存储在目标缓冲区中(一次 4 个样本)。*/ 27. write_q7x4_ia ( & pDst , __QADD8 ( read_q7x4_ia ( ( q7_t ** ) & pSrc ) , offset_packed ) ) ; 28. # else 29. * pDst ++ = ( q7_t) __SSAT (* PSRC ++ +偏移, 8 ); 30. * pDst ++ = ( q7_t ) __SSAT ( * pSrc ++ + offset , 8 ) ; 31. * pDst ++ = ( q7_t ) __SSAT ( * pSrc ++ + offset , 8 ) ; 32. * pDst ++ = (q7_t) __SSAT (* PSRC ++ +偏移, 8 ); 33. #endif 34. 35. /* 递减循环计数器 */ 36. blkCnt -- ; 37. } 38. 39. /* 循环展开:计算剩余输出 */ 40. blkCnt = blockSize % 0 x4U ; 41. 42. # else 43. 44. /* 用样本数初始化 blkCnt */ 45. blkCnt =块大小; 46. 47. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 48. 49. while ( blkCnt 》 0 U ) 50. { 51. /* C = A + offset */ 52. 53. /* 添加偏移量和将结果存储在目标缓冲区中。*/ 54. * pDst ++ = ( q7_t ) __SSAT ( ( q15_t ) * pSrc ++ + offset , 8 ) ; 55. 56. /* 递减循环计数器 */ 57. blkCnt -- ; 58. } 59. 60. } 函数描述: 这个函数用于求两个8位定点数的偏移。 函数解析: 第 9 到 42 行,实现了四个为一组进行计数,好处是执行速度,同时降低循环占用时间。 第 49 到 5 行,四个为一组数据的处理或者不采用四个为一组时数据处理。 函数write_q7x4_ia的原型如下: __STATIC_FORCEINLINE void write_q7x4_ia ( q7_t ** pQ7 , q31_t value ) { q31_t val = value ; memcpy ( * pQ7 , & val , 4 ) ; * pQ7 += 4 ; } 作用是写数据,标明数据次地址+8位,下次继续写。 ____88实现四次8概率的加法交互。输出的范围[0x80 0x7F],超出这个结果将产生产生结果,数QA到0x80,正数到0x7F。 函数参数: 第 1 个参数是源数据地址。 第2个参数是偏移量。 第3个参数是转换后的目的地址。 4个参数是定点数个数,实际上就是执行第几次的次数。 12.4.5 使用举例 程序设计: /* ****************************************************** ****************************************************** ***** * 函数数名:DSP_Offset * 功能说明:偏移 *形参:无 * 返回值:无 ****************************************************** ****************************************************** ***** */ 静态 无效 DSP_Offset (无效) { float32_t pSrcA = 0.0 f ; float32_t 偏移= 0.0 f ; float32_t pDst ; q31_t pSrcA1 = 0 ; q31_t Offset1 = 0 ; q31_t pDst1 ; q15_t pSrcA2 = 0 ; q15_t Offset2 = 0 ; q15_t pDst2 ; q7_t pSrcA3 = 0 ; q7_t Offset3 = 0 ; q7_t pDst3 ; /*求 偏移************************************/偏移-- ; arm_offset_f32 ( & pSrcA , Offset , & pDst , 1 ) ; printf ( “arm_offset_f32 = %frn” , pDst ) ; 偏移量 1 -- ; arm_offset_q31 (& pSrcA1 ,偏移1 , & pDst1 , 1 ); printf ( “arm_offset_q31 = %drn” , pDst1 ) ; 偏移量2 -- ; arm_offset_q15 (& pSrcA2 ,偏移2 , & pDst2 , 1 ); printf ( “arm_offset_q15 = %drn” , pDst2 ) ; 偏移量3 -- ; arm_offset_q7 ( & pSrcA3 , Offset3 , & pDst3 , 1 ) ; printf ( “arm_offset_q7 = %drn” , pDst3 ) ; printf ( “***********************************rn” ) ; } 实验现象: |
|
|
|
12.5 丢失(Vector Shift)
这部分功能主要用于实现调用,公式描述如下: pDst[n] = pSrc[n] 《《 shift, 0 《= n 《 blockSize. 注意,这部分功能支持目标指针和源指针指向相同的 arm12.5.1 函数原型: void arm_shift_q31 ( 2. const q31_t * pSrc , 3. int8_t shiftBits , 4. q31_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /*循环循环*/ 8. uint8_t sign = ( shiftBits & 0x80 ) ; /* shiftBits 的符号 */ 9. 10. #如果已定义 ( ARM_MATH_LOOPUNROLL ) 11. 12. q31_t输入,输出; /*临时变量*/ 13. 14. /*循环展开:一次计算4个输出*/ 15. blkCnt = blockSize 》》 2 U ; 16. 17. /* 如果是正则则右移左移*/ 18. if ( sign == 0 U ) 19. { 20. while ( blkCnt 》 0 U ) 21. { 22. /* C = A 《《 shiftBits * / 23 24 / *移位输入并将结果存储在目标缓冲区中。* / 25, 在 = * pSrc ++ ; 26. out = in 《《 shiftBits ; 27. if ( in != ( out 》》 shiftBits ) ) 28. out = 0x7FFFFFFFF ^ ( in 》》 31 ) ; 29. * pDst ++ =输出; 30. 31. in = * pSrc ++ ; 32. 出= 入 《《移位位; 33. if ( in != ( out 》》 shiftBits ) ) 34. out = 0x7FFFFFFF ^ ( in 》》 31 ) ; 35. * pDst ++ =输出; 36. 37. in = * pSrc ++ ; 38. out = in 《《 shiftBits ; 39. 如果 ( 在 != (out 》》 shiftBits ) ) 40. out = 0x7FFFFFFF ^ ( in 》》 31 ) ; 41. * pDst ++ =输出; 42. 43. in = * pSrc ++ ; 44. out = in 《《 shiftBits ; 45. 如果(in != ( out 》》 shiftBits ) ) 46. out = 0x7FFFFFFF ^ ( 在 》》 31 中 ) ; 47. * pDst ++ =输出; 48. 49. /*递减循环决策*/ 50. blkCnt -- ; 51. } 52. } 53. else 54. { 55. while ( blkCnt 》 0 U ) 56. { 57. /* C = A 》》 shiftBits */ 58. 59. /* 输入输入结果存储在*/ 60. * pDst ++ = ( *pSrc ++ 》》 - shiftBits ); 61. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 62. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 63. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 64. 65. /*递减循环表决*/ 66. blkCnt -- ; 67. } 68. } 69. 70. /* 循环展开:计算计算输出 */ 71. blkCnt = blockSize % 0 x4U ; 72. 73. # else 74. 75. /* 用样本数初始化 blkCnt */ 76. blkCnt = blockSize ; 77. 78. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 79. 80. /* 如果是正则,则右移,否则左移 */ 81. if ( sign == 0 U ) 82. { 83. 同时 ( blkCnt 》 0 û ) 84 { 85 / * C = A 《《 shiftBits * / 86 87 / *移位输入并将结果存储在目标缓冲区中。* / 88。 * pDst ++ = clip_q63_to_q31 ( ( q63_t ) * pSrc ++ 《《 shiftBits ) ; 89. 90. /*递减循环表决*/ 91. blkCnt -- ; 92. } 93. } 94. 其他 95. { 96. 同时 ( blkCnt 》 0 û ) 97 { 98 / * C = A 》》 shiftBits * / 99 100 / *移位输入并将结果存储到目标缓冲区。*/ 101. * pDst ++ = ( * pSrc ++ 》》 -失去位) ; 102. 103. /*递减循环数*/ 104. blkCnt -- ; 105. } 106. } 107. 108. } 函数描述: 这个函数用于求32位定点数的左移或右移。 函数解析: 第 10 到 73 行,实现四个为一组进行计数,结果是戏剧执行速度,同时降低循环占用时间。 第18到52行,如果参数shiftBits是正数,执行左移。 第53到68行,如果蚕食shiftBits是负数,执行右移。 第28行,数值的左移仅支持将其左移如果再右移相应的概率后不变的,不满足这个条件,那么要对输出结果做出动作,这里分两种情况: OUT = ^为0x7FFFFFFF(在》》 31)(在是正数) = ^为0x7FFFFFFF 00000000 = 0x7FFFFFFF的 OUT = ^为0x7FFFFFFF(在》》 31)(在是负数) = ^为0x7FFFFFFF 0xFFFFFFFF的 = 0x80000000的 第 81 到 106 行,四个采用了一个特定的数据的处理或者不四个为一个时数据处理。 第88行,函数clip_q63_to_q31的原型如下: __STATIC_FORCEINLINE q31_t clip_q63_to_q31 ( q63_t x ) { return ( ( q31_t ) ( x 》》 32 ) != ( ( q31_t ) x 》》 31 ) ) ? ((为0x7FFFFFFF ^ (( q31_t ) ( X 》》 63 )))) : ( q31_t ) X ; } 函数参数: 第 1 个参数是源数据地址。 第2个参数是左移或右移数,正数是左移,负数是右移。 第 3 个参数是取消后数据地址。 第4个参数是定点数,实际上就是执行左移或右移的次数。 12.5.2 函数arm_shift_q15 函数原型: void arm_shift_q15 ( 2. const q15_t * pSrc , 3. int8_t shiftBits , 4. q15_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. uint8_t sign = ( shiftBits & 0x80 ) ; /* shiftBits 的符号 */ 9. 10. #如果已 定义 (ARM_MATH_LOOPUNROLL ) 11. 12. #如果已 定义 ( ARM_MATH_DSP ) 13. q15_t in1 , in2 ; /* 临时输入变量 */ 14. #endif 15. 16. /* 循环展开:一次计算 4 个输出 */ 17. blkCnt = blockSize 》》 2 U ; 18. 19. /* 如果移位值为正则右移否则左移 */ 20. if ( sign == 0 U ) 21. { 22. while ( blkCnt 》 0 U ) 23. { 24. /* C = A 《《 shiftBits */ 25. 26. # if defined ( ARM_MATH_DSP ) 27. /* 从源读取 2 个样本 */ 28. in1 = * psrc ++ ; 29. in2 = * pSrc ++ ; 30. 31. /* 移动输入,然后将结果存储在目标缓冲区中。*/ 32. #ifndef ARM_MATH_BIG_ENDIAN 33. write_q15x2_ia ( & pDst , __PKHBT ( __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 34. __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 16 ) ) ; 35. # else 36. write_q15x2_ia ( & pDst , __PKHBT ( __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 37. __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 16 ) ) ; 38. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 39. 40. /* 从源中读取 2 个样本 */ 41. in1 = * pSrc ++ ; 42. in2 = * pSrc ++ ; 43. 44. #ifndef ARM_MATH_BIG_ENDIAN 45. write_q15x2_ia ( &pDst , __PKHBT ( __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 46. __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 16 ) ) ; 47. # else 48. write_q15x2_ia ( & pDst , __PKHBT ( __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 49. __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 16 ) ) ; 50. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 51. 52. # else 53. * pDst ++ = __SSAT ( ( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 54. * pDst ++ = __SSAT ( ( (q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 55. * pDst ++ = __SSAT ( ( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 56. * pDst ++ = __SSAT ( ( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 57. #endif 58. 59. /* 递减循环计数器 */ 60. blkCnt -- ; 61. } 62. } 63. else 64. { 65. while ( blkCnt 》 0 U ) 66. { 67. /* C = A 》》 shiftBits */ 68. 69. # if defined ( ARM_MATH_DSP ) 70. /*从源中读取 2 个样本 */ 71. in1 = * pSrc ++ ; 72. in2= * pSrc ++ ; 73. 74. /* 移动输入,然后将结果存储在目标缓冲区中。*/ 75. #ifndef ARM_MATH_BIG_ENDIAN 76. write_q15x2_ia ( & pDst , __PKHBT ( ( in1 》》 - shiftBits ) , 77. ( in2 》》 - shiftBits ) , 16 ) ) ; 78. # else 79. write_q15x2_ia ( & pDst , __PKHBT ( ( in2 》》 - shiftBits ) , 80. ( in1 》》 - shiftBits ) , 16 ) ) ; 81. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 82. 83. /* 从源中读取 2 个样本 */ 84. in1 = * pSrc ++ ; 85. in2 = * pSrc ++ ; 86. 87. #ifndef ARM_MATH_BIG_ENDIAN 88. write_q15x2_ia ( & pDst , __PKHBT ( ( in1 》》 - shiftBits ) , 89. ( in2 》》 - shiftBits ) , 16 ) ) ; 90. # else 91. write_q15x2_ia ( & pDst , __PKHBT ( ( in2 》》 - shiftBits ) , 92. ( in1 》》 - shiftBits ) , 16 ) ); 93. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 94. 95. # else 96. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 97. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 98. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 99. * pDst++ = ( * pSrc ++ 》》 - shiftBits ) ; 100. #endif 101. 102. /* 递减循环计数器 */ 103. blkCnt -- ; 104. } 105. } 106. 107. /* 循环展开:计算剩余输出 */ 108. blkCnt = blockSize % 0 x4U ; 109. 110. # else 111. 112. /* 用样本数初始化 blkCnt */ 113. blkCnt=块大小; 114. 115. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 116. 117. /* 如果移位值为正则右移否则左移*/ 118. if ( sign == 0 U ) 119. { 120. while ( blkCnt 》 0 U ) 121. { 122. /* C = A 《《 shiftBits */ 123. 124. /* 移位输入并将结果存储在目标缓冲区中。*/ 125. * pDst ++ = __SSAT (( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 126. 127. /* 递减循环计数器 */ 128. blkCnt -- ; 129. } 130. } 131. else 132. { 133. while ( blkCnt 》 0 U ) 134. { 135. /* C = A 》》 shiftBits */ 136. 137. /* 移位输入并将结果存储到目标缓冲区。 */ 138. * pDst++ = ( * pSrc ++ 》》 - shiftBits ) ; 139. 140. /* 递减循环计数器 */ 141. blkCnt -- ; 142. } 143. } 144. 145. } 函数描述: 这个函数用于求16位定点数的左移或右移。 函数解析: 第10到5行,实现了4个循环11组计算,结果是性能执行速度,同时降低占用时间。 第20到62行,如果参数shiftBits是正数,执行左移。 第63到105行,如果蚕食shiftBits是负数,执行右移。 第79行,函数write_q15x2_ia的原型如下,用于实现将两个Q15组合合并成一个Q31。 __STATIC_FORCEINLINE void write_q15x2_ia ( q15_t ** pQ15 , q31_t value ) { q31_t val = value ; memcpy ( * pQ15 , & val , 4 ) ; * pQ15 += 2 ; } 函数__PKHBT也是SIMD语句,作用是将两个16位的数据合并成32位数据。用C实现的话,如下: 的#define __PKHBT(ARG1 , ARG2 , ARG3 ) ( ((( int32_t )(ARG1 ) 《《 0 ) & ( int32_t )0x0000FFFF ) | ((( int32_t )(ARG2 ) 《《 ARG3 ) & ( int32_t )0xFFFF0000地址) ) 118 到第 143 行,四个为第一个数据的处理或者不四个为一个时数据处理。 函数参数: 第 1 个参数是源数据地址。 第2个参数是左移或右移数,正数是左移,负数是右移。 第 3 个参数是取消后数据地址。 第4个参数是定点数,实际上就是执行左移或右移的次数。 |
|
|
|
12.5.3 函数arm_shift_q7
函数原型: void arm_shift_q7 ( 2. const q7_t * pSrc , 3. int8_t shiftBits , 4. q7_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. uint8_t sign = ( shiftBits & 0x80 ) ; /* shiftBits 的符号 */ 9. 10. #如果已 定义 ( ARM_MATH_LOOPUNROLL) 11. 12. #如果 定义 (ARM_MATH_DSP ) 13. q7_t IN1 , IN2 , IN3 , IN4 ; /* 临时输入变量 */ 14. #endif 15. 16. /* 循环展开:一次计算 4 个输出 */ 17. blkCnt = blockSize 》》 2 U ; 18. 19. /* 如果移位值为正,则右移否则左移 */ 20. if ( sign == 0 U ) 21. { 22. while ( blkCnt 》 0 U ) 23. { 24. /* C = A 《《 shiftBits */ 25. 26. # if defined ( ARM_MATH_DSP ) 27. /* 读取4个输入*/ 28. in1 = * pSrc ++ ; 29. in2 = * pSrc ++ ; 30. in3 = * pSrc ++ ; 31. in4 = *psrc ++ ; 32. 33. /* 将结果打包并存储在目标缓冲区中(单次写入)*/ 34. write_q7x4_ia ( & pDst , __PACKq7 ( __SSAT ( ( in1 《《 shiftBits ) , 8 ) , 35. __SSAT ( ( in2 《《 shiftBits ) ), 8 ), 36 __SSAT (( IN3 《《 shiftBits ), 8 ), 37。 __SSAT(( IN4 《《 shiftBits ), 8 ) )); 38. # else 39. * pDst ++ = ( q7_t ) __SSAT ( ( ( q15_t ) * pSrc ++ 《《 shiftBits ) , 8 ) ; 40. * pDst ++ = ( q7_t ) __SSAT ( ( ( q15_t ) *pSrc ++ 《《 shiftBits ) , 8 ) ; 41. * pDst ++ = ( q7_t ) __SSAT ( ( ( q15_t ) * pSrc ++ 《《 shiftBits ) , 8 ) ; 42. * pDst ++ = ( q7_t ) __SSAT ( ( ( q15_t ) * pSrc ++ 《《 shiftBits ) , 8) ; 43. #endif 44. 45. /* 递减循环计数器 */ 46. blkCnt -- ; 47. } 48. } 49. else 50. { 51. while ( blkCnt 》 0 U ) 52. { 53. /* C = A 》》 shiftBits */ 54. 55. # if defined ( ARM_MATH_DSP ) 56. /*读取 4 个输入 */ 57. in1 = * pSrc ++ ; 58. in2 = * pSrc ++ ; 59. in3 = * pSrc ++ ; 60. in4 = * pSrc ++ ; 61. 62. /* 将结果打包并存储在目标缓冲区中(单次写入)*/ 63. write_q7x4_ia ( & pDst , __PACKq7 ( ( in1 》》 - shiftBits ) , 64. ( in2 》》 - shiftBits ) , 65. ( IN3 》》 - shiftBits ), 66 ( IN4 》》 - shiftBits ) )); 67. # else 68. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 69. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 70. * pDst ++ = ( *pSrc ++ 》》 - shiftBits ) ; 71. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 72. #endif 73. 74. /* 递减循环计数器 */ 75. blkCnt -- ; 76. } 77. } 78. 79. /* 循环展开:计算剩余输出 */ 80. blkCnt = blockSize % 0 x4U ; 81. 82. #else 83. 84. /* 用样本数初始化 blkCnt */ 85. blkCnt = blockSize ; 86. 87. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 88. 89. /* 如果移位值为正则右移否则左移*/ 90. if ( sign == 0 U ) 91. { 92. while ( blkCnt 》 0 U ) 93. { 94. /* C = A 《《 shiftBits */ 95. 96. /* 移位输入并将结果存储在目标缓冲区中。*/ 97. * pDst ++ = ( q7_t ) __SSAT ( ( ( q15_t ) * pSrc ++ 《《 shiftBits ) , 8 ) ; 98. 99. /* 递减循环计数器 */ 100. blkCnt -- ; 101. } 102. } 103. else 104. { 105. while ( blkCnt 》 0 U ) 106. { 107. /* C = A 》》 shiftBits */ 108. 109. /* 移位输入并将结果存储在目标缓冲区中。*/ 110. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 111. 112. /* 递减循环计数器 */ 113. blkCnt -- ; 114. } 115. } 116. 117. } 函数描述: 这个函数用于求8位定点数的左移或右移。 函数解析: 第10到87行,实现四次为一组进行计数,结果是戏剧执行速度,同时降低循环占用时间。 第20到48行,如果参数shiftBits是正数,执行左移。 第49到77行,如果蚕食shiftBits是负数,执行右移。 第79,函数write_q7x4_ia的底层,作用是写入4次8位数据,可以使数据行地址,方便快捷地写入数据。 __STATIC_FORCEINLINE void write_q7x4_ia ( q7_t ** pQ7 , q31_t value ) { q31_t val = value ; memcpy ( * pQ7 , & val , 4 ) ; * pQ7 += 4 ; } 函数__PACKq7作用是将4个8位的数据合并成32位数据,实现代码: 的#define __PACKq7( V0 , V1 , V2 , V3 ) ( ((( int32_t )( V0 ) 《《 0 ) & ( int32_t )0x000000FF ) | ((( int32_t )( V1 ) 《《 8 ) & ( int32_t )0x0000FF00 ) | (( ( int32_t ) ( v2 ) 《《 16 ) & ( int32_t ) 0x00FF0000 ) | ( ( ( ( int32_t ) ( v3 ) 《《 24 ) & ( int32_t ) 0xFF000000 ) ) 第 90 到 115 行,四个采用为一个特定数据的处理或不四个为一组时数据处理。 函数参数: 第 1 个参数是源数据地址。 第2个参数是左移或者右移位数,正数是左移,负数是右移。 第3个参数是移位后数据地址。 第4个参数是定点数个数,其实就是执行左移或者右移的次数 12.5.4 使用举例 程序设计: /* ****************************************************** ****************************************************** ***** * 函数数名:DSP_Shift * 功能说明:取消 *形参:无 * 返回值:无 ****************************************************** ****************************************************** ***** */ 静态 无效 DSP_Shift (无效) { q31_t pSrcA1 = 0x88886666 ; q31_t pDst1 ; q15_t pSrcA2 = 0x8866 ; q15_t pDst2 ; q7_t pSrcA3 = 0x86 ; q7_t pDst3 ; /*求放弃************************************/ arm_shift_q31 ( & pSrcA1 , 3 , & pDst1 , 1 ) ; printf ( “arm_shift_q31 = %8xrn” , pDst1 ) ; arm_shift_q15 ( & pSrcA2 , - 3 , & pDst2 , 1 ) ; printf ( “arm_shift_q15 = %4xrn” , pDst2 ) ; arm_shift_q7 ( & pSrcA3 , 3 , & pDst3 , 1 ) ; printf ( “arm_shift_q7 = %2xrn” , pDst3 ) ; printf ( “***********************************rn” ) ; } 这里特别注意Q31和Q7的计算结果,表示负数已经饱和到了最小值。另外注意,对于负数来说,右移时,右侧补1,左移时,左侧补0 12.6减法(向量子) 这部分函数主要用于实现减法,描述如下: pDst[n] = pSrcA[n] - pSrcB[n], 0 《= n 《 blockSize。 12.6.1 函数 arm_sub_f32 函数原型: void arm_sub_f32 ( 2. const float32_t * pSrcA , 3. const float32_t * pSrcB , 4. float32_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /*循环循环*/ 8. 9. #如果定义( ARM_MATH_NEON ) 10. float32x4_t vec1 ; 11. float32x4_t vec2 ; 12. float32x4_t res ; 13. 14. /* 一次计算 4 个输出 */ 15. blkCnt = blockSize 》》 2 U ; 16. 17. 而 ( blkCnt 》 0 û ) 18 { 19 / * C = A - B * / 20 21 / *减去然后将结果存储在目标缓冲区中* / 22 VEC1 = vld1q_f32 ( pSrcA ) ; 23. vec2 = vld1q_f32 ( pSrcB ) ; 24. 资源= vsubq_f32 ( vec1 , vec2 ) ; 25. vst1q_f32 ( pDst , res ) ; 26. 27. /* 向上传送 */ 28. pSrcA += 4 ; 29. pSrcB += 4 ; 30. pDst += 4 ; 31. 32. /*递减循环表决*/ 33. blkCnt -- ; 34. } 35. 36. / *尾部* / 37 blkCnt=块大小& 0x3 ; 38. 39. # else 40. # if defined ( ARM_MATH_LOOPUNROLL ) 41. 42. /* 循环展开:一次计算 4 个输出 */ 43. blkCnt = blockSize 》》 2 U ; 44. 45. 而 ( blkCnt 》 0 û ) 46 { 47 / * C = A - B * / 48 49 / *减去结果并将结果存储在目标缓冲区中* / 50 * pDst ++ = ( * pSrcA ++ ) - ( * pSrcB ++ ); 51. 52. * pDst ++ = ( * pSrcA ++ ) - ( * pSrcB ++ ); 53. 54. * pDst ++ = ( * pSrcA + + ) - ( * pSrcB ++ ) ; 55. 56. * pDst ++ = ( *pSrcA ++ ) - ( * pSrcB ++ ); 57. 58. /*递减循环决策 */ 59. blkCnt -- ; 60. } 61. 62. /* 循环展开:计算消费输出*/ 63. blkCnt = blockSize % 0 x4U ; 64. 65. #其他 66. 67. /* 用样本数初始化 blkCnt */ 68. blkCnt = blockSize ; 69. 70. #endif /* #if 已定义 (ARM_MATH_LOOPUNROLL) */ 71. #endif /* #if defined(ARM_MATH_NEON) */ 72. 73. while ( blkCnt 》 0 U ) 74. { 75. /* C = A - B */ 76. 77. /* 采购采购结果存储在*/ 78. * pDst ++ = ( * pSrcA ++ ) - ( * pSrcB ++ ) ; 79. 80. /*递减循环表决*/ 81. blkCnt -- ; 82. } 83. 84. } 函数描述: 这个函数用于求32位浮点数的减法。 函数解析: 第9到39行,用于NEON指令集,当前的CM内核不支持。 第40到65行,实现四个为一组进行计数,结果是戏剧执行速度,同时降低循环占用时间。 第 73 到 8 行,四个为一组数据的处理或者不采用一组为一组时数据处理。 函数参数: 第 1 个参数是减数地址。 第2个参数是被减数地址。 第 3 个参数是结果地址。 第 4 个参数是数据块大小,实际上就是执行加法的次数。 |
|
|
|
12.6.2函数arm_sub_q31
函数原型: void arm_sub_q31 ( 2. const q31_t * pSrcA , 3. const q31_t * pSrcB , 4. q31_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. 9. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 10. 11. /* 循环展开:一次计算 4 个输出 */ 12. blkCnt =块尺寸》》 2 U ; 13. 14. while ( blkCnt 》 0 U ) 15. { 16. /* C = A - B */ 17. 18. /* 减去并存储结果到目标缓冲区。*/ 19. * pDst ++ = __QSUB ( * pSrcA ++ , * pSrcB ++ ) ; 20. 21. * pDst ++ = __QSUB ( * pSrcA ++ , * pSrcB++ ) ; 22. 23. * pDst ++ = __QSUB ( * pSrcA ++ , * pSrcB ++ ) ; 24. 25. * pDst ++ = __QSUB ( * pSrcA ++ , * pSrcB ++ ) ; 26. 27. /* 递减循环计数器 */ 28. blkCnt -- ; 29. } 30. 31. /* 循环展开:计算剩余输出 */ 32. blkCnt =块大小% 0 x4U ; 33. 34. # else 35. 36. /* 用样本数初始化 blkCnt */ 37. blkCnt = blockSize ; 38. 39. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 40. 41. while ( blkCnt 》 0 U ) 42. { 43. /* C = A - B */ 44. 45. /* 减法和存储导致目标缓冲区。*/ 46. * pDst ++ = __QSUB ( * pSrcA ++ , * pSrcB ++ ) ; 47. 48. /* 递减循环计数器 */ 49. blkCnt -- ; 50. } 51. 52. } 函数描述: 这个函数用于求32位定点数的减法。 函数解析: 函数这个使用了收益减法__QSUB,是Q31格式,范围[0x80000000 0x7FFFFFFF]。 第 9 到 34 行,实现了四个为一组进行了统计,结果是性能执行速度,同时降低了循环占用时间。 第 41 到 5 行,四个为一组数据的处理或者不采用一组为一组时数据处理。 函数参数: 第 1 个参数是减数地址。 第2个参数是被减数地址。 第 3 个参数是结果地址。 第 4 个参数是数据块大小,实际上就是执行加法的次数。 12.6.3 函数arm_sub_q15 函数原型: void arm_sub_q15 ( 2. const q15_t * pSrcA , 3. const q15_t * pSrcB , 4. q15_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. 9. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 10. 11. #如果已 定义 ( ARM_MATH_DSP ) 12. q31_t inA1 , inA2 ; 13. q31_t inB1 , inB2 ; 14. #endif 15. 16. /* 循环展开:一次计算 4 个输出 */ 17. blkCnt = blockSize 》》 2 U ; 18. 19. while ( blkCnt 》 0 U ) 20. { 21. /* C = A - B */ 22. 23. # if defined ( ARM_MATH_DSP ) 24. /* 从 sourceA 一次读取 2 次 2 个样本 */ 25. inA1 = read_q15x2_ia ( ( q15_t ** ) & pSrcA ) ; 26. inA2 = read_q15x2_ia ( ( q15_t ** ) & pSrcA ) ; 27. /* 一次从 sourceB 读取 2 次 2 个样本 */ 28. inB1 = read_q15x2_ia ( ( q15_t ** ) & pSrcB ) ; 29. inB2 = read_q15x2_ia ( ( q15_t ** ) & pSrcB ) ; 30. 31. /* 一次减去并存储 2 次 2 个样本 */ 32. write_q15x2_ia ( & pDst , __QSUB16 ( inA1 , inB1 ) ) ; 33. write_q15x2_ia ( & pDst , __QSUB16 ( inA2 , inB2 ) ) ; 34. # else 35. * pDst ++ = (q15_t) __SSAT ((( q31_t ) * pSrcA ++ - * pSrcB ++ ), 16 ); 36. * pDst ++ = ( q15_t ) __SSAT ( ( ( q31_t ) * pSrcA ++ - * pSrcB ++ ) , 16 ) ; 37. * pDst ++ = ( q15_t ) __SSAT (( ( q31_t ) * pSrcA ++ - * pSrcB ++ ) , 16 ) ; 38. * pDst ++ = ( q15_t ) __SSAT ( ( ( q31_t ) * pSrcA ++ - * pSrcB ++ ) , 16 ) ; 39. #endif 40. 41. /* 递减循环计数器 */ 42. blkCnt -- ; 43. } 44. 45. /* 循环展开:计算剩余输出 */ 46. blkCnt = blockSize % 0 x4U ; 47. 48. # else 49. 50. /* 用样本数初始化 blkCnt */ 51. blkCnt = blockSize ; 52. 53. #endif /* #if 定义 (ARM_MATH_LOOPUNROLL) */ 54. 55. while ( blkCnt 》 0 U ) 56. { 57. /* C = A - B */ 58. 59. /* 减去并将结果存储在目标缓冲区中。*/ 60. #如果 定义 ( ARM_MATH_DSP ) 61. * pDst ++ = ( q15_t ) __QSUB16 ( * pSrcA ++ , * pSrcB ++ ) ; 62. # else 63. * pDst ++ = ( q15_t ) __SSAT ( ( ( q31_t ) * pSrcA ++ - * pSrcB ++) , 16 ) ; 64. #endif 65. 66. /* 递减循环计数器 */ 67. blkCnt -- ; 68. } 69. 70. } 函数描述: 这个函数用于求16位定点数的减法。 函数解析: 第 9 到 48 行,实现了四个为一组进行计数,优点是执行速度,同时降低循环占用时间。 第25行,函数read_q15x2_ia一次读取两个Q15格式的数据,组成一个Q31格式。 第32行,函数write_q15x2_ia一次写入两个Q15格式的数据,获得一个Q31格式的数据。 第3章,函数__QSUB16实现游戏16bit的减法。 第 55 到 6 行,四个为一组数据的处理或不采用四个为一组时数据处理。 函数参数: 第 1 个参数是减数地址。 第2个参数是被减数地址。 第 3 个参数是结果地址。 第 4 个参数是数据块大小,实际上就是执行加法的次数。 12.6.4 函数原型 arm_sub_q7: void arm_sub_q7 ( 2. const q7_t * pSrcA , 3. const q7_t * pSrcB , 4. q7_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. 9. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 10. 11. /* 循环展开:一次计算 4 个输出 */ 12. blkCnt =块尺寸》》 2 U ; 13. 14. while ( blkCnt 》 0 U ) 15. { 16. /* C = A - B */ 17. 18. # if defined ( ARM_MATH_DSP ) 19. /* 减去结果并将结果存储在目标缓冲区中(4个样本在一段时间)。*/ 20. write_q7x4_ia ( & pDst , __QSUB8 ( read_q7x4_ia ( ( q7_t ** ) & pSrcA ) , read_q7x4_ia ( ( q7_t ** ) & pSrcB ) ) ) ; 21. # else 22. * pDst ++ = ( q7_t ) __SSAT ( ( q15_t ) * pSrcA ++ - * pSrcB ++ , 8 ) ; 23. * pDst ++ = ( q7_t ) __SSAT ( ( q15_t ) * pSrcA ++ - *pSrcB ++ , 8 ) ; 24. * pDst ++ = ( q7_t ) __SSAT ( ( q15_t ) * pSrcA ++ - * pSrcB ++ , 8 ) ; 25. * pDst ++ = ( q7_t ) __SSAT ( ( q15_t ) * pSrcA ++ - * pSrcB ++ , 8 ) ; 26. #endif 27. 28. /* 递减循环计数器 */ 29. blkCnt -- ; 30. } 31. 32. /* 循环展开:计算剩余输出 */ 33. blkCnt = blockSize % 0 x4U ; 34. 35. # else 36. 37. /* 用样本数初始化 blkCnt */ 38. blkCnt = blockSize ; 39. 40. #endif /* #if 已定义 (ARM_MATH_LOOPUNROLL) */ 41. 42. while ( blkCnt》 0 U ) 43. { 44. /* C = A - B */ 45. 46. /* 减去结果并将结果存储在目标缓冲区中。*/ 47. * pDst ++ = ( q7_t ) __SSAT ( ( q15_t ) * pSrcA ++ - * pSrcB ++ , 8 ) ; 48. 49. /* 递减循环计数器 */ 50. blkCnt -- ; 51. } 52. 53. } 函数描述: 这个函数用于求8位定点数的乘法。 函数解析: 第 9 到 35 行,实现了四个为一组进行计数,优点是执行速度,同时降低循环占用时间。 第20行,函数write_q7x4_ia实现数据一次写入4个Q7格式到Q31各种中。 函数__QSUB8实现一次计算4个Q7格式减法。 第 42 到 5 行,四个为一组数据的处理或者不采用一组为一组时数据处理。 函数参数: 第 1 个参数是减数地址。 第2个参数是被减数地址。 第 3 个参数是结果地址。 第 4 个参数是数据块大小,实际上就是执行加法的次数。 |
|
|
|
12.6.5 使用举例
程序设计: /* ****************************************************** ****************************************************** ***** * 函数数名:DSP_Sub * 功能说明:减法 *形参:无 * 返回值:无 ****************************************************** ****************************************************** ***** */ static void DSP_Sub ( void ) { float32_t pSrcA [ 5 ] = { 1.0 f , 1.0 f , 1.0 f , 1.0 f , 1.0 f } ; float32_t pSrcB [ 5 ] = { 1.0 f , 1.0 f , 1.0 f , 1.0 f , 1.0 f } ; float32_t pDst [5 ] ; q31_t pSrcA1 [ 5 ] = { 1 , 1 , 1 , 1 , 1 } ; q31_t pSrcB1 [ 5 ] = { 1 , 1 , 1 , 1 , 1 } ; q31_t pDst1 [ 5 ] ; q15_t pSrcA2 [ 5 ] = { 1 , 1 , 1 , 1 , 1 } ; q15_t pSrcB2 [ 5 ] = { 1 , 1 , 1 , 1 , 1 } ; q15_t pDst2 [ 5 ] ; q7_t pSrcA3 [ 5 ] = { 0x70 , 1 , 1 , 1 , 1 } ; q7_t pSrcB3 [ 5 ] = { 0x7f , 1 , 1 , 1 , 1 } ; q7_t pDst3 [ 5 ] ; /*求减法*********************************/ pSrcA [ 0 ] += 1.1 f ; arm_sub_f32 ( pSrcA , pSrcB , pDst , 5 ) ; printf ( “arm_sub_f32 = %frn” , pDst [ 0 ] ) ; pSrcA1 [ 0 ] += 1 ; arm_sub_q31 ( pSrcA1 , pSrcB1 , pDst1 , 5 ) ; printf ( “arm_sub_q31 = %drn” , pDst1 [ 0 ] ) ; pSrcA2 [ 0 ] += 1 ; arm_sub_q15 ( pSrcA2 , pSrcB2 , pDst2 , 5 ) ; printf ( “arm_sub_q15 = %drn” , pDst2 [ 0 ] ) ; pSrcA3 [ 0 ] += 1 ; arm_sub_q7 ( pSrcA3 , pSrcB3 , pDst3 , 5 ) ; printf ( “arm_sub_q7 = %drn” , pDst3 [ 0 ] ) ; printf ( “***********************************rn” ) ; } 实验现象: 12.7 比例比例如下(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. 注意,这部分函数支持目标路径和源框架视图的 12.7.1函数arm_scale_f2 函数原型: void arm_scale_f32 ( 2. const float32_t * pSrc , 3. float32_t scale , 4. float32_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /*循环循环是否*/ 8. #已定义( ARM_MATH_NEON_EXPERIMENTAL ) 9. float32x4_t vec1 ; 10. float32x4_t res ; 11. 12. /* 一次计算 4 个输出 */ 13. blkCnt =块大小》》 2 U ; 14. 15. 而 ( blkCnt 》 0 û ) 16 { 17 / * C = A *规模* / 18 19 / *缩放输入,然后将结果存储在目标缓冲区中。* / 20 VEC1 = vld1q_f32 ( pSrc ) ; 21. res = vmulq_f32 ( vec1 , vdupq_n_f32 ( scale ) ) ; 22. vst1q_f32 ( pDst,资源) ; 23. 24. /* 向上传送 */ 25. pSrc += 4 ; 26. pDst += 4 ; 27. 28. / *减少循环计数器* / 29 blkCnt - ; 30. } 31. 32. / *尾部* / 33 blkCnt = BLOCKSIZE & 0x3 ; 34. 35. #其他 36. #如果已定义 ( ARM_MATH_LOOPUNROLL ) 37. 38. /* 循环展开:一次计算 4 个输出 */ 39. blkCnt = blockSize 》》 2 U ; 40. 41. 而 ( blkCnt 》 0 û ) 42 { 43 / * C = A *规模* / 44 45 / *缩放输入并将结果存储在目标缓冲区中。* / 46 * pDst + + = ( * pSrc ++ ) *比例; 47. 48. * pDst ++ = ( * pSrc ++ ) *比例; 49. 50. * pDst ++ = ( * PSRC ++ ) *比例; 51. 52. * pDst ++ = ( * PSRC ++ ) *比例; 53. 54. / *递减循环计数器* / 55 blkCnt -- ; 56. } 57. 58. /* 循环展开:计算消费输出*/ 59. blkCnt = blockSize % 0 x4U ; 60. 61. #其他 62. 63. /* 用样本数初始化 blkCnt */ 64. blkCnt = blockSize ; 65. 66. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 67. #endif /* #if defined(ARM_MATH_NEON_EXPERIMENTAL) */ 68. 69. while ( blkCnt 》 0 U ) 70. { 71. /* C = A *规模* / 72 73 / *缩放输入并将结果存储在目标缓冲区中* /。 74. * pDst ++ = ( * PSRC ++ ) *比例; 75. 76。 /* 递减循环算法 */ 77. blkCnt -- ; 78. } 79. 80. } 函数描述: 这个函数用于求32位浮点数的比例计算。 函数解析: 第8到35行,用于NEON指令集,当前的CM内核不支持。 第36到61行,实现四次为一组计数,结果是戏剧执行速度,同时降低循环占用时间。 第 69 到 7 行,四个为一组数据的处理或不采用四个为一组时数据处理。 函数参数: 第 1 个参数是数据源地址。 第2个参数是比例因子 第 3 个参数是结果地址。 第4个是数据块大小,实际上就是执行比例计算的次数参数。 12.7.2函数arm_scale_q31 函数原型: 空隙 arm_scale_q31 ( 2. 常量q31_t * PSRC , 3. q31_t scaleFract , 4 中int8_t移, 5. q31_t * pDst , 6. uint32_t的BLOCKSIZE ) 7. { 8. uint32_t的blkCnt ; /* 循环计数器 */ 9. q31_t in , out ; /* 临时变量 */ 10. int8_t kShift = shift + 1; /* 缩放后应用的移位 */ 11. int8_t sign = ( kShift & 0x80 ) ; 12. 13. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 14. 15. /* 循环展开:一次计算 4 个输出 */ 16. blkCnt = blockSize 》》 2 U ; 17. 18. if ( sign == 0 U ) 19. { 20. while ( blkCnt 》 0U ) 21. { 22. /* C = A * scale */ 23. 24. /* 缩放输入并将结果存储在目标缓冲区中。*/ 25. in = * pSrc ++ ; /* 从源读取输入 */ 26. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; /* 输入乘以定标器值 */ 27. out = in 《《 kShift ; /* 应用移位 */ 28. if ( in != ( out 》》 kShift ) ) /* 使结果饱和 */ 29. out = 0x7FFFFFFF ^ ( in 》》 31 ) ; 30. * pDst ++ =输出; /* 存储结果目标 */ 31. 32. in = * pSrc ++ ; 33. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; 34. 出= 在 《《 kShift 中; 35. if ( in != ( out 》》 kShift ) ) 36. out = 0x7FFFFFFF ^ ( in 》》 31 ) ; 37. * pDst ++ =输出; 38. 39. in = * pSrc ++ ; 40. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; 41. out = in 《《 kShift ; 42. if ( in != ( out 》》 kShift ) ) 43. out = 0x7FFFFFFF ^ ( in 》》 31 ) ; 44. * pDst ++ =输出; 45. 46. in = * pSrc ++ ; 47. in = ( ( q63_t ) in * scaleFract) 》》 32 ; 48. out = in 《《 kShift ; 49. if ( in != ( out 》》 kShift ) ) 50. out = 0x7FFFFFFF ^ ( in 》》 31 ) ; 51. * pDst ++ =输出; 52. 53. /* 递减循环计数器 */ 54. blkCnt -- ; 55. } 56. } 57. else 58. { 59. while ( blkCnt 》 0 U ) 60. { 61. /* C = A * scale */ 62. 63. /* 缩放输入并将结果存储在目标缓冲区中。*/ 64. in = * pSrc ++ ; /* 从源中读取四个输入 */ 65. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; /* 输入乘以定标器值 */ 66. out = in 》》 - kShift ; /* 应用移位 */ 67. * pDst ++ = out ; /* 存储结果目标 */ 68. 69. in = * pSrc ++ ; 70. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; 71. out = in 》》 - kShift ; 72. * pDst ++ =输出; 73. 74. 在 = * pSrc ++ ; 75. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; 76. out = in 》》 - kShift ; 77. * pDst ++ =输出; 78. 79. in = * pSrc ++ ; 80. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; 81. out = in 》》 - kShift ; 82. * pDst ++ =输出; 83. 84. /* 递减循环计数器 */ 85. blkCnt -- ; 86. } 87. } 88. 89. /* 循环展开:计算剩余输出 */ 90. blkCnt = blockSize % 0 x4U ; 91. 92. #其他 93. 94. /* 用样本数初始化 blkCnt */ 95. blkCnt = blockSize ; 96. 97. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 98. 99. if ( sign == 0 U ) 100. { 101. while ( blkCnt 》 0 U ) 102. { 103. /* C = A * scale */ 104. 105. /* 缩放输入并将结果存储在目标缓冲区中。*/ 106. in = * pSrc ++ ; 107. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; 108. out = in 《《 kShift ; 109. if ( in != ( out 》》 kShift ) ) 110. out = 0x7FFFFFFFF ^ ( in 》》 31 ) ; 111. * pDst ++ =输出; 112. 113. /* 递减循环计数器 */ 114. blkCnt -- ; 115. } 116. } 117. else 118. { 119. while ( blkCnt 》 0 U ) 120. { 121. /* C = A * scale */ 122. 123. /* 缩放输入并将结果存储在目标缓冲区中。*/ 124. in = * pSrc ++ ; 125. in = ( ( q63_t ) in * scaleFract ) 》》 32 ; 126. out = in 》》 - kShift ; 127. * pDst ++ =输出; 128. 129. /* 递减循环计数器 */ 130. blkCnt -- ; 131. } 132. } 133. 134. } 函数描述: 这个函数用于求32位定点数的比例计算。 函数解析: 第 13 到 92 行,实现四个为一组进行计数,结果是戏剧执行速度,同时降低循环占用时间。 18行到第6行,如果函数的退出形参移位是正数,那么执行左移。 57行到第87行,如果函数的退出形参移位是负数,那么执行右移。 这里特别一点,两个Q31相乘是2.62格式,而函数的结果函数可能是Q31格式的,所以程序里面可以说明处理。 第26行,左移32位,那么结果就是2.30格式。 第27行,kShift = shift + 1,也就是out = in 《《(shift + 1)多执行了一次左移操作。 相当于2.30格式,转换为2.31格式。 第28到29行,还有一个Q31的处理,也就是将2.31格式转换为1.31。 左移支持将右移以后再适当的相应的情况,如果这个时间以后一直不变的情况不满足条件,那么就要对输出做结果恢复其智力,这里分两种情况 out = 0x7FFFFFF ^ (in 》》 31) (in是正数) = 0x7FFFFFFFF ^ 0x00000000 = 0x7FFFFFFF out = 0x7FFFFFFF ^ (in 》》 31) (in是正数) = 0x7FFFFFFFF ^ 0xFFFFFFFF = 0x8000000 第 99 到 132 行,四个采用为一个特定数据的处理或者不四个为一组时数据处理。 函数参数: 第 1 个参数是数据源地址。 第2个参数是比例因子。 第3个参数是缺少参数,正数表示左移右移,负数表示。 第4参数是结果地址。 第5参数是数据块大小,其实就是执行比例因子计算的次数。 |
|
|
|
12.7.3 函数arm_scale_q15
函数原型: void arm_shift_q15 ( 2. const q15_t * pSrc , 3. int8_t shiftBits , 4. q15_t * pDst , 5. uint32_t blockSize ) 6. { 7. uint32_t blkCnt ; /* 循环计数器 */ 8. uint8_t sign = ( shiftBits & 0x80 ) ; /* shiftBits 的符号 */ 9. 10. #如果已 定义 (ARM_MATH_LOOPUNROLL ) 11. 12. #如果已 定义 ( ARM_MATH_DSP ) 13. q15_t in1 , in2 ; /* 临时输入变量 */ 14. #endif 15. 16. /* 循环展开:一次计算 4 个输出 */ 17. blkCnt = blockSize 》》 2 U ; 18. 19. /* 如果移位值为正则右移否则左移 */ 20. if ( sign == 0 U ) 21. { 22. while ( blkCnt 》 0 U ) 23. { 24. /* C = A 《《 shiftBits */ 25. 26. # if defined ( ARM_MATH_DSP ) 27. /* 从源读取 2 个样本 */ 28. in1 = * psrc ++ ; 29. in2 = * pSrc ++ ; 30. 31. /* 移动输入,然后将结果存储在目标缓冲区中。*/ 32. #ifndef ARM_MATH_BIG_ENDIAN 33. write_q15x2_ia ( & pDst , __PKHBT ( __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 34. __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 16 ) ) ; 35. # else 36. write_q15x2_ia ( & pDst , __PKHBT ( __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 37. __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 16 ) ) ; 38. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 39. 40. /* 从源中读取 2 个样本 */ 41. in1 = * pSrc ++ ; 42. in2 = * pSrc ++ ; 43. 44. #ifndef ARM_MATH_BIG_ENDIAN 45. write_q15x2_ia ( &pDst , __PKHBT ( __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 46. __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 16 ) ) ; 47. # else 48. write_q15x2_ia ( & pDst , __PKHBT ( __SSAT ( ( in2 《《 shiftBits ) , 16 ) , 49. __SSAT ( ( in1 《《 shiftBits ) , 16 ) , 16 ) ) ; 50. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 51. 52. # else 53. * pDst ++ = __SSAT ( ( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 54. * pDst ++ = __SSAT ( ( (q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 55. * pDst ++ = __SSAT ( ( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 56. * pDst ++ = __SSAT ( ( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 57. #endif 58. 59. /* 递减循环计数器 */ 60. blkCnt -- ; 61. } 62. } 63. else 64. { 65. while ( blkCnt 》 0 U ) 66. { 67. /* C = A 》》 shiftBits */ 68. 69. # if defined ( ARM_MATH_DSP ) 70. /*从源中读取 2 个样本 */ 71. in1 = * pSrc ++ ; 72. in2= * pSrc ++ ; 73. 74. /* 移动输入,然后将结果存储在目标缓冲区中。*/ 75. #ifndef ARM_MATH_BIG_ENDIAN 76. write_q15x2_ia ( & pDst , __PKHBT ( ( in1 》》 - shiftBits ) , 77. ( in2 》》 - shiftBits ) , 16 ) ) ; 78. # else 79. write_q15x2_ia ( & pDst , __PKHBT ( ( in2 》》 - shiftBits ) , 80. ( in1 》》 - shiftBits ) , 16 ) ) ; 81. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 82. 83. /* 从源中读取 2 个样本 */ 84. in1 = * pSrc ++ ; 85. in2 = * pSrc ++ ; 86. 87. #ifndef ARM_MATH_BIG_ENDIAN 88. write_q15x2_ia ( & pDst , __PKHBT ( ( in1 》》 - shiftBits ) , 89. ( in2 》》 - shiftBits ) , 16 ) ) ; 90. # else 91. write_q15x2_ia ( & pDst , __PKHBT ( ( in2 》》 - shiftBits ) , 92. ( in1 》》 - shiftBits ) , 16 ) ); 93. #endif /* #ifndef ARM_MATH_BIG_ENDIAN */ 94. 95. # else 96. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 97. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 98. * pDst ++ = ( * pSrc ++ 》》 - shiftBits ) ; 99. * pDst++ = ( * pSrc ++ 》》 - shiftBits ) ; 100. #endif 101. 102. /* 递减循环计数器 */ 103. blkCnt -- ; 104. } 105. } 106. 107. /* 循环展开:计算剩余输出 */ 108. blkCnt = blockSize % 0 x4U ; 109. 110. # else 111. 112. /* 用样本数初始化 blkCnt */ 113. blkCnt=块大小; 114. 115. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 116. 117. /* 如果移位值为正则右移否则左移*/ 118. if ( sign == 0 U ) 119. { 120. while ( blkCnt 》 0 U ) 121. { 122. /* C = A 《《 shiftBits */ 123. 124. /* 移位输入并将结果存储在目标缓冲区中。*/ 125. * pDst ++ = __SSAT (( ( q31_t ) * pSrc ++ 《《 shiftBits ) , 16 ) ; 126. 127. /* 递减循环计数器 */ 128. blkCnt -- ; 129. } 130. } 131. else 132. { 133. while ( blkCnt 》 0 U ) 134. { 135. /* C = A 》》 shiftBits */ 136. 137. /* 移位输入并将结果存储到目标缓冲区。 */ 138. * pDst++ = ( * pSrc ++ 》》 - shiftBits ) ; 139. 140. /* 递减循环计数器 */ 141. blkCnt -- ; 142. } 143. } 144. 145. } 函数描述: 这个函数用于求16位定点数的比例计算。 函数解析: 第10到第10行,实现了4个循环11组计算,结果是性能执行速度,同时降低占用时间。 第20到2行,如果函数的调用正形参shiftBits是数,执行左移。 63到105行,如果函数的调用形参shiftBits负数,执行右移。 第33行,函数__PKHBT也是SIMD语句,作用是将两个16位的数据合并成32位数据。用C实现的话,如下: 的#define __PKHBT(ARG1 , ARG2 , ARG3 ) ( ((( int32_t )(ARG1 ) 《《 0 ) & ( int32_t )0x0000FFFF ) | ((( int32_t )(ARG2 ) 《《 ARG3 ) & ( int32_t )0xFFFF0000地址) ) 函数write_q15x2_ia的原型如下: __STATIC_FORCEINLINE void write_q15x2_ia ( q15_t ** pQ15 , q31_t value ) { q31_t val = value ; memcpy ( * pQ15 , & val , 4 ) ; * pQ15 += 2 ; } 作用是写入封装Q15格式数据,构成一个Q31格式数据,修改数据地址,方便打开。 118 到第 143 行,四个为第一个数据的处理或者不四个为一个时数据处理 函数参数: 第 1 个参数是数据源地址。 第2个参数是比例因子。 第3个参数是缺少参数,正数表示左移右移,负数表示。 第 4 条参数是结果地址。 第5条是数据块大小,实际上就是执行比例统计的次数参数。 12.7.4 函数arm_scale_q7 函数原型: void arm_scale_q7 ( 2. const q7_t * pSrc , 3. q7_t scaleFract , 4. int8_t shift , 5. q7_t * pDst , 6. uint32_t blockSize ) 7. { 8. uint32_t blkCnt ; /* 循环计数器 */ 9. int8_t kShift = 7 - shift ; /* 缩放后应用 */ 10. 11. #如果已 定义 ( ARM_MATH_LOOPUNROLL ) 12 13 #如果 定义 (ARM_MATH_DSP ) 14. q7_t IN1 , IN2 , IN3 , IN4 ; /* 临时输入变量 */ 15. q7_t out1 , out2 , out3 , out4 ; /* 临时输出变量 */ 16. #endif 17. 18. /* 循环展开:一次计算 4 个输出 */ 19. blkCnt = blockSize 》》 2 U; 20. 21. while ( blkCnt 》 0 U ) 22. { 23. /* C = A * scale */ 24. 25. # if defined ( ARM_MATH_DSP ) 26. /* 从内存中读取 4 个输入 */ 27. in1 = * pSrc ++ ; 28. in2 = * pSrc ++ ; 29. in3 = * pSrc ++ ; 30. in4 = *psrc ++ ; 31. 32. /* 缩放输入并将结果存储在临时变量中。*/ 33. out1 = ( q7_t ) ( __SSAT ( ( ( in1 ) * scaleFract ) 》》 kShift , 8 ) ) ; 34. out2 = ( q7_t ) ( __SSAT ( ( ( in2 ) * scaleFract ) 》》 kShift , 8 )) ; 35. OUT3 = ( q7_t ) (__SSAT ((( IN3 ) * scaleFract ) 》》 kShift , 8 )); 36. OUT4 = ( q7_t ) (__SSAT ((( IN4 ) * scaleFract ) 》》 kShift , 8 )); 37. 38. /* 将结果打包并存储在目标缓冲区中(单次写入)*/ 39. write_q7x4_ia ( & pDst , __PACKq7 ( out1 , out2 , out3 , out4 ) ) ; 40. # else 41. * pDst ++ = ( q7_t ) ( __SSAT ( ( ( ( q15_t ) * pSrc ++ * scaleFract ) 》》 kShift ) , 8 )) ; 42. * pDst ++ = ( q7_t ) ( __SSAT ( ( ( ( q15_t ) * pSrc ++ * scaleFract ) 》》 kShift ) , 8 ) ) ; 43. * pDst ++ = ( q7_t ) ( __SSAT ( ( ( ( q15_t ) * pSrc ++ * scaleFract ) 》》kShift ) , 8 ) ) ; 44. * pDst ++ = ( q7_t ) ( __SSAT ( ( ( ( q15_t ) * pSrc ++ * scaleFract ) 》》 kShift ) , 8 ) ) ; 45. #endif 46. 47. /* 递减循环计数器 */ 48. blkCnt -- ; 49. } 50. 51. /* 循环展开:计算剩余输出 */ 52. blkCnt = blockSize % 0 x4U ; 53. 54. # else 55. 56. /* 用样本数初始化 blkCnt */ 57. blkCnt = blockSize ; 58. 59. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 60. 61. while ( blkCnt 》 0 U ) 62. { 63. /* C = A * scale */ 64. 65. /* 缩放输入并将结果存储在目标缓冲区中。*/ 66. * pDst ++ = ( q7_t ) ( __SSAT ( ( ( ( q15_t ) * pSrc ++ * scaleFract ) 》》 kShift ) , 8 ) ) ; 67. 68. /* 递减循环计数器 */ 69. blkCnt -- ; 70. } 71. 72. } 函数描述: 这个函数用于求8位定点数的比例计算。 函数解析: 第9行,这个变量设计很巧妙,这样下面处理正数的右移和负数的右移就可以了,可以直接使用一个右移就可以实现。 第 11 到 54 行,实现四个为一组进行计数,结果是戏剧执行速度,同时降低循环占用时间。 33到36行,对输入的数据做8位的处理。 (in1 * scaleFract) 》》 kShift = (in1 * scaleFract) * 2^(shift - 7) = ((in1 * scaleFract) 》》7)*(2^shift) 源数据in1格式Q7乘以比例因子scaleFract格式Q7,也就是2.14格式,再右移7bit就是2.7格式,此时 如果是正数,那么就是当前结果左移移位,如果是负数,那么就是结果当前右移位。最终结果通过__SSAT做个学习智力。 第 61 到 70 行,四个为一组数据的处理或者不采用一组为一组时数据处理。 函数参数: 第 1 个参数是数据源地址。 第2个参数是比例因子。 第3个参数是缺少参数,正数表示左移右移,负数表示。 第 4 条参数是结果地址。 第5条是数据块大小,实际上就是执行比例统计的次数参数。 12.7.5 使用举例 程序设计: /* ****************************************************** ****************************************************** ***** * 函数数名:DSP_Scale * 功能说明:比例因子 *形参:无 * 返回值:无 ****************************************************** ****************************************************** ***** */ static void DSP_Scale ( void ) { float32_t pSrcA [ 5 ] = { 1.0 f , 1.0 f , 1.0 f , 1.0 f , 1.0 f } ; float32_t 比例= 0.0 f ; float32_t pDst [ 5 ] ; q31_t pSrcA1 [ 5 ] = { 0x6fffffff , 1 , 1 , 1 , 1 } ; q31_t scale1 = 0x6ffffffff ; q31_t pDst1 [ 5 ] ; q15_t pSrcA2 [ 5 ] = { 0x6fff , 1 , 1 , 1 , 1 } ; q15_t scale2 = 0x6fff ; q15_t pDst2 [ 5 ] ; q7_t pSrcA3 [ 5 ] = { 0x70 , 1 , 1 , 1 , 1 } ; q7_t scale3 = 0x6f ; q7_t pDst3 [ 5 ] ; /*求比例因子计算************************************/ scale += 0.1 f ; arm_scale_f32 ( pSrcA , scale , pDst , 5 ) ; printf ( “arm_scale_f32 = %frn” , pDst [ 0 ] ) ; 比例1 += 1 ; arm_scale_q31 ( pSrcA1 , scale1 , 0 , pDst1 , 5 ) ; printf ( “arm_scale_q31 = %xrn” , pDst1 [ 0 ] ) ; 比例 2 += 1 ; arm_scale_q15 ( pSrcA2 , scale2 , 0 , pDst2 , 5 ) ; printf ( “arm_scale_q15 = %xrn” , pDst2 [ 0 ] ) ; 比例 3 += 1 ; arm_scale_q7 ( pSrcA3 , scale3 , 0 , pDst3 , 5 ) ; printf ( “arm_scale_q7 = %xrn” , pDst3 [ 0 ] ) ; printf ( “***********************************rn” ) ; } 实验现象: 12.8 实验例说明(MDK) 配套例子: V - 2-07_DSP基础运算(相反数,偏移,衰减,减法和比例因子) 实验目的: 学习基础运算(相反数,偏移,减少法和比例符号) 实验内容: 启动一个自动重装软件定时器,每100ms萤光一次LED2。 点击按钮K1,DSP求逆数运算。 点击按钮K2, DSP 求爱玩。 点按K3, DSP 求索操作。 按下摇杆OK键,DSP求减法运算键。 按下摇杆上键,DSP图标计算。 使用AC6注意事项 特别注意附件章节C的问题 上电后连线打印的信息: 波特率15200,数据位8,奇偶位无,停止位1。 查看附件的3.5,4.5,5.4和6.5小节。 程序设计: 系统大小分配: |
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1641 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1562 浏览 1 评论
990 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
691 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1610 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
655浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
525浏览 3评论
541浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
514浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-26 16:23 , Processed in 1.033178 second(s), Total 95, Slave 77 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号