加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

【安富莱DSP教程】第8章 BasicMathFunctions的使用(一)Vector Multiplication

(2015-03-18 11:24:08)
标签:

ucos-iii

ucgui

emwin

dsp

arm_mult_f32

分类: 数字信号处理
特别说明:完整45期数字信号处理教程,原创高性能示波器代码全开源地址:链接

第8章  BasicMathFunctions的使用(一)

8.4  乘法(Vector Multiplication

这部分函数主要用于乘法,公式描述如下:

pDst[n] pSrcA[n] pSrcB[n],   <= blockSize.    

8.4.1 arm_mult_f32

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

 

 

void arm_mult_f32(

  float32_t pSrcA,

  float32_t pSrcB,

  float32_t pDst,

  uint32_t blockSize)

{

  uint32_t blkCnt;                               

#ifndef ARM_MATH_CM0_FAMILY

 

  

  float32_t inA1, inA2, inA3, inA4;              

  float32_t inB1, inB2, inB3, inB4;              

  float32_t out1, out2, out3, out4;              

 

  

  blkCnt blockSize >> 2u;

 

  

  while(blkCnt 0u)

  {

    

                                     (1)

    

    inA1 *pSrcA;

    

    inB1 *pSrcB;

    

    inA2 *(pSrcA 1);

    

    inB2 *(pSrcB 1);

 

    

    out1 inA1 inB1;

 

    

    inA3 *(pSrcA 2);

    

    inB3 *(pSrcB 2);

 

    

    out2 inA2 inB2;

 

    

    inA4 *(pSrcA 3);

 

    

    *pDst out1;

 

    

    inB4 *(pSrcB 3);

 

    

    out3 inA3 inB3;

 

    

    *(pDst 1) out2;

 

    

    out4 inA4 inB4;

    

    *(pDst 2) out3;

    

    *(pDst 3) out4;

 

 

    

    pSrcA += 4u;

    pSrcB += 4u;

    pDst += 4u;

 

    

    blkCnt--;

  }

 

  

  blkCnt blockSize 0x4u;

 

#else

 

  

 

  

  blkCnt blockSize;

 

#endif 

 

  while(blkCnt 0u)

  {

    

    

    *pDst++ (*pSrcA++) (*pSrcB++);

 

    

    blkCnt--;

  }

}

1.  浮点的32位乘法比较简单,这里依然是以4次的计算为一组。

8.4.2 arm_mult_q31

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

 

 

void arm_mult_q31(

  q31_t pSrcA,

  q31_t pSrcB,

  q31_t pDst,

  uint32_t blockSize)

{

  uint32_t blkCnt;                               

 

#ifndef ARM_MATH_CM0_FAMILY

 

 

  q31_t inA1, inA2, inA3, inA4;                  

  q31_t inB1, inB2, inB3, inB4;                  

  q31_t out1, out2, out3, out4;                  

 

  

  blkCnt blockSize >> 2u;

 

  

  while(blkCnt 0u)

  {

    

    

    inA1 *pSrcA++;

    inA2 *pSrcA++;

    inA3 *pSrcA++;

    inA4 *pSrcA++;

    inB1 *pSrcB++;

    inB2 *pSrcB++;

    inB3 *pSrcB++;

    inB4 *pSrcB++;

 

    out1 ((q63_t) inA1 inB1) >> 32;                                                              (2)

    out2 ((q63_t) inA2 inB2) >> 32;

    out3 ((q63_t) inA3 inB3) >> 32;

    out4 ((q63_t) inA4 inB4) >> 32;

 

    out1 __SSAT(out1, 31);                                                                         (3)

    out2 __SSAT(out2, 31);

    out3 __SSAT(out3, 31);

    out4 __SSAT(out4, 31);

 

    *pDst++ out1 << 1u;                                                                            (4)

    *pDst++ out2 << 1u;

    *pDst++ out3 << 1u;

    *pDst++ out4 << 1u;

 

    

    blkCnt--;

  }

 

  

  blkCnt blockSize 0x4u;

 

#else

 

  

 

  

  blkCnt blockSize;

 

#endif 

 

  while(blkCnt 0u)

  {

    

    

    *pDst++ =

      (q31_t) clip_q63_to_q31(((q63_t) (*pSrcA++) (*pSrcB++)) >> 31);

 

    

    blkCnt--;

  }

}

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

所得结果是Q31格式,范围Q31 range[0x80000000 0x7FFFFFFF]

2. 所得乘积左移32位。

3. 实现31位精度的饱和运算。

4. 右移一位,保证所得结果是Q31格式。

8.4.3 arm_mult_q15

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

 

 

void arm_mult_q15(

  q15_t pSrcA,

  q15_t pSrcB,

  q15_t pDst,

  uint32_t blockSize)

{

  uint32_t blkCnt;                               

 

#ifndef ARM_MATH_CM0_FAMILY

 

 

  q31_t inA1, inA2, inB1, inB2;                  

  q15_t out1, out2, out3, out4;                  

  q31_t mul1, mul2, mul3, mul4;                  

 

  

  blkCnt blockSize >> 2u;

 

  

  while(blkCnt 0u)

  {

    

    inA1 *__SIMD32(pSrcA)++;                                                                     (2)

    

    inB1 *__SIMD32(pSrcB)++;

    

    inA2 *__SIMD32(pSrcA)++;

    

    inB2 *__SIMD32(pSrcB)++;

 

    

    mul1 (q31_t) ((q15_t) (inA1 >> 16) (q15_t) (inB1 >> 16));                                  (3)

    mul2 (q31_t) ((q15_t) inA1 (q15_t) inB1);

    mul3 (q31_t) ((q15_t) (inA2 >> 16) (q15_t) (inB2 >> 16));

    mul4 (q31_t) ((q15_t) inA2 (q15_t) inB2);

 

    

    out1 (q15_t) __SSAT(mul1 >> 15, 16);                                                         (4)

    out2 (q15_t) __SSAT(mul2 >> 15, 16);

    out3 (q15_t) __SSAT(mul3 >> 15, 16);

    out4 (q15_t) __SSAT(mul4 >> 15, 16);

 

    

#ifndef ARM_MATH_BIG_ENDIAN

 

    *__SIMD32(pDst)++ __PKHBT(out2, out1, 16);                                                   (5)

    *__SIMD32(pDst)++ __PKHBT(out4, out3, 16);

 

#else

 

    *__SIMD32(pDst)++ __PKHBT(out2, out1, 16);

    *__SIMD32(pDst)++ __PKHBT(out4, out3, 16);

 

#endif //      #ifndef ARM_MATH_BIG_ENDIAN

 

    

    blkCnt--;

  }

 

  

  blkCnt blockSize 0x4u;

 

#else

 

  

 

  

  blkCnt blockSize;

 

#endif 

 

 

  while(blkCnt 0u)

  {

    

    

    *pDst++ (q15_t) __SSAT((((q31_t) (*pSrcA++) (*pSrcB++)) >> 15), 16);

 

    

    blkCnt--;

  }

}

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

所得结果是Q15格式,范围 [0x8000  0x7FFF]

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

3. 将四组数的乘积保存到Q31格式的变量mul1,mul2,mul3,mul4。

4. 丢弃32位数据的低15位,并把最终结果饱和到16位精度。

5. 通过SIMD指令__PKHBT将两个Q15格式的数据保存的结果数组中,从而一个指令周期就能完成两个数据的存储。

8.4.4 arm_mult_q7

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

 

 

void arm_mult_q7(

  q7_t pSrcA,

  q7_t pSrcB,

  q7_t pDst,

  uint32_t blockSize)

{

  uint32_t blkCnt;                               

 

#ifndef ARM_MATH_CM0_FAMILY

 

 

  q7_t out1, out2, out3, out4;                   

 

  

  blkCnt blockSize >> 2u;

 

  

  while(blkCnt 0u)

  {

    

                              (2)

    out1 (q7_t) __SSAT((((q15_t) (*pSrcA++) (*pSrcB++)) >> 7), 8);

    out2 (q7_t) __SSAT((((q15_t) (*pSrcA++) (*pSrcB++)) >> 7), 8);

    out3 (q7_t) __SSAT((((q15_t) (*pSrcA++) (*pSrcB++)) >> 7), 8);

    out4 (q7_t) __SSAT((((q15_t) (*pSrcA++) (*pSrcB++)) >> 7), 8);

 

    

    *__SIMD32(pDst)++ __PACKq7(out1, out2, out3, out4);                                          (3)

 

    

    blkCnt--;

  }

 

  

  blkCnt blockSize 0x4u;

 

#else

 

  

 

  

  blkCnt blockSize;

 

#endif 

 

 

  while(blkCnt 0u)

  {

    

    

    *pDst++ (q7_t) __SSAT((((q15_t) (*pSrcA++) (*pSrcB++)) >> 7), 8);

 

    

    blkCnt--;

  }

}

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

所得结果是Q7格式,范围 [0x80  0x7F]

2. 将两个Q7格式的数据乘积左移7位,也就是丢掉低7位的数据,并将所得结果饱和到8位精度。

3. __PACKq7函数可以在一个时钟周期就能完成相应操作。

8.4.5 实例讲解

实验目的:

1. 四种类型数据的乘法。

实验内容:

1. 按下摇杆的UP键, 串口打印输出结果

实验现象:

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

【安富莱DSP教程】第8章 <wbr>BasicMathFunctions的使用(一)Vector <wbr>Multiplication

程序设计:

 

static void DSP_Multiplication(void)

{

static float32_t   pSrcA[5] {1.0f,1.0f,1.0f,1.0f,1.0f};

static float32_t   pSrcB[5] {1.0f,1.0f,1.0f,1.0f,1.0f};  

static float32_t   pDst[5];  

 

static q31_t  pSrcA1[5] {1,1,1,1,1};  

static q31_t  pSrcB1[5] {1,1,1,1,1};  

static q31_t  pDst1[5];   

 

static q15_t  pSrcA2[5] {1,1,1,1,1};  

static q15_t  pSrcB2[5] {1,1,1,1,1};  

static q15_t  pDst2[5];   

 

static q7_t  pSrcA3[5] {0x70,1,1,1,1}; 

static q7_t  pSrcB3[5] {0x7f,1,1,1,1};  

static q7_t pDst3[5];  

 

 

pSrcA[0] += 1.1f;

arm_mult_f32(pSrcA, pSrcB, pDst, 5);

printf("arm_mult_f32 %f\r\n", pDst[0]);

 

pSrcA1[0] += 1;

arm_mult_q31(pSrcA1, pSrcB1, pDst1, 5);

printf("arm_mult_q31 %d\r\n", pDst1[0]);

 

pSrcA2[0] += 1;

arm_mult_q15(pSrcA2, pSrcB2, pDst2, 5);

printf("arm_mult_q15 %d\r\n", pDst2[0]);

 

pSrcA3[0] += 1;

arm_mult_q7(pSrcA3, pSrcB3, pDst3, 5);

printf("arm_mult_q7 %d\r\n", pDst3[0]);

printf("***********************************\r\n");

}

8.5  总结

本期教程就跟大家讲这么多,还是那句话,可以自己写些代码调用本期教程中讲的这几个函数,如果可以的话,可以自己尝试直接调用这些DSP指令。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有