特别说明:完整45期数字信号处理教程,原创高性能示波器代码全开源地址:链接
: u. Q( B/ P& [! ~$ E( I第8章 BasicMathFunctions的使用(一)
0 _$ z$ W, ^ V& K, X 本期教程开始学习ARM官方的DSP库,这里我们先从基本数学函数开始。本期教程主要讲绝对值,加法,点乘和乘法四种运算。 8.1 绝对值(Vector Absolute Value) 8.2 求和(Vector Addition) 8.3 点乘(Vector Dot Product) 8.4 乘法(Vector Multiplication) 5 q6 u/ S- I. Z
8.1 绝对值(Vector Absolute Value) 这部分函数主要用于求绝对值,公式描述如下: pDst[n] = abs(pSrc[n]), 0 <= n < blockSize. 特别注意,这部分函数支持目标指针和源指针指向相同的缓冲区。 8.1.1 arm_abs_f32 这个函数用于求32位浮点数的绝对值,源代码分析如下: - /** / c+ V* t5 X! p, W+ C( m; }
- * @brief Floating-point vector absolute value. (1)" j1 {; `; y k2 T4 t
- * @param[in] *pSrc points to the input buffer
2 l( p( ?3 t4 O) c- S" c - * @param[out] *pDst points to the output buffer 9 z) A& ~5 K, ?4 I0 g9 A2 k& C
- * @param[in] blockSize number of samples in each vector ( f* F5 Z6 Q! ^% M' a2 b. m; [0 X
- * @return none. " Y: T" C+ K! Z0 \ X3 H! w+ L
- */" s& Y1 W7 X9 f' N' @0 Z
-
0 p/ Y& D/ p: K& j: F. H" o - void arm_abs_f32( (2)$ S( r# }9 V( `' P
- float32_t * pSrc,0 J! K' J, a1 k/ M4 y# E0 Y
- float32_t * pDst,, |- v! s9 Q( |: B% V( ]7 Y
- uint32_t blockSize)' K+ } }; s/ I% v
- {
' R* i% i O% |6 b8 R3 v( u - uint32_t blkCnt; /* loop counter */( Q% Z4 R/ Y0 E# x4 g
- ) Q0 g, K$ G2 ~8 r
- #ifndef ARM_MATH_CM0_FAMILY (3). D3 e1 x( r. N
-
5 A, `% N! g$ }3 Y: | - /* Run the below code for Cortex-M4 and Cortex-M3 */
# g/ d$ p% B+ {0 ~2 f; V - float32_t in1, in2, in3, in4; /* temporary variables */: `1 v9 S. d( P" y* a# o$ n
- ; H* D$ Z y0 A1 a# U
- /*loop Unrolling */9 O+ L! |' a( h( e9 w2 O" G+ `
- blkCnt = blockSize >> 2u; (4)/ q, I. Q7 f& C, N2 h# I; y1 m# f }6 u
-
# k |* X: C6 _0 z: I8 M2 E - /* First part of the processing with loop unrolling. Compute 4 outputs at a time. 4 C7 F$ j9 U! X
- ** a second loop below computes the remaining 1 to 3 samples. */0 P- J4 ]5 _$ ?/ v6 I* y
- while(blkCnt > 0u)3 H; a' e) p! b o# ^* Q
- {
4 ]7 m2 j7 h% q5 _. `7 s/ r - /* C = |A| */
6 o- \. A+ H1 @) ~4 Q - /* Calculate absolute and then store the results in the destination buffer. */% P1 ?6 d1 [( Y
- /* read sample from source */
0 W( U; P0 a1 r6 v" ?- X - in1 = *pSrc;/ A% K+ c P1 j+ w6 T0 l7 P
- in2 = *(pSrc + 1);
3 k' X7 F0 m1 g6 C7 x, V - in3 = *(pSrc + 2);6 \0 F+ T. j) q* K+ M' p9 N. N
- 1 q5 ~+ [* e* a0 [' l
- /* find absolute value */1 f8 B% }$ p3 l0 ?6 q, I
- in1 = fabsf(in1); (5)1 k2 ]; z' ?2 [0 l/ e
-
# ^! E) d' D+ J. F D) K" K - /* read sample from source */
& o$ U. T: X! V7 p7 y - in4 = *(pSrc + 3);' I. D5 \9 V5 f8 y
- 4 d2 X* ` e2 W) _8 R& q
- /* find absolute value */( F' [. v, @0 D1 d! J" t+ K/ U
- in2 = fabsf(in2);2 b0 {& ]5 [; G$ z2 ?2 o4 X/ j
- $ a3 @9 K8 c: r- A- J, p2 Q8 c
- /* read sample from source */. h# ?; y2 z2 q* i
- *pDst = in1;- ] _) v# v( [5 k0 I$ w$ F/ o! D
- 4 a' L9 N! z) G' ^
- /* find absolute value */) U4 B% [0 [ {4 j; W
- in3 = fabsf(in3);
4 H' g ~* I6 i- K -
% @' l5 }$ G' B9 H - /* find absolute value */
$ o2 \/ F/ _9 x! b# K - in4 = fabsf(in4);
' j7 l; v4 Z1 T. X# _ -
5 S* z0 Q1 G$ h% d) u - /* store result to destination */8 r* ~/ { L* R" p" P
- *(pDst + 1) = in2;9 k1 K/ t5 ?6 Z" B {
-
2 f4 D0 U( u( o1 n% h1 E - /* store result to destination */; q. `- x' Y8 Z. H
- *(pDst + 2) = in3;! V4 u- {" L8 ?- B
- / P, P1 [( X# \+ P* ?
- /* store result to destination */! G& C0 s1 t# f6 z
- *(pDst + 3) = in4;
8 g0 s7 l$ ~: U7 U. A( t/ s; k -
8 V; n8 k, Z1 V& o3 d - 0 W% Z- T9 m3 l! w! w) j
- /* Update source pointer to process next sampels */ (6)$ `1 e/ h. J( v# l2 U, [
- pSrc += 4u;" H+ e! B; F. \
- / P5 q* H, h6 e! S N
- /* Update destination pointer to process next sampels */
* q2 o. _' W* p+ Q - pDst += 4u;
7 P' ?1 `/ _1 S- U8 p - & q6 c, h _! ^
- /* Decrement the loop counter */
' ]7 H, ?. t1 y4 p - blkCnt--;" t. i0 i: n O5 x, @
- }
! A9 R. i/ X& `0 o: c2 K1 ^ - 1 u6 x- K0 ^; _
- /* If the blockSize is not a multiple of 4, compute any remaining output samples here. ' j3 B% Q) P* c7 ]' g$ ~! w
- ** No loop unrolling is used. */
* r1 [: T8 r5 M9 q) D5 f - blkCnt = blockSize % 0x4u;
! |; U7 ?5 h9 Z: v! A -
" n9 m& J4 U& U2 D! b- H0 Y3 A - #else (7)
8 ?* q: Q, _( k& Y4 s: j -
1 R7 S! K5 ^- N9 \" M" V* G4 L1 b - /* Run the below code for Cortex-M0 */
5 n) E1 a+ S4 {# S; I6 Y - 5 i/ ]- g% r) e3 o
- /* Initialize blkCnt with number of samples */
0 [/ X8 a& j- F3 b1 N8 e/ t8 k. K6 G - blkCnt = blockSize;
0 \. o5 E0 I, y! \! _8 B S: m - 2 z0 p% S" T$ g
- #endif /* #ifndef ARM_MATH_CM0_FAMILY */
0 Y# [2 D- o6 t -
+ q" q# m. R$ v - while(blkCnt > 0u) (8)
- C) x* |1 L0 J5 i4 a - {
+ e* S' z( r4 u7 O/ v - /* C = |A| */5 V' @# W( `* X# x) r# t
- /* Calculate absolute and then store the results in the destination buffer. */
. b N2 @# q4 C( z6 P! a% } - *pDst++ = fabsf(*pSrc++);/ h; O$ `. }9 |# o# N
-
: v6 ?+ q. y* y) Y7 i/ H - /* Decrement the loop counter */
) H5 e. c0 v1 C- _) M - blkCnt--;
) Z, a( Q1 y- J4 a5 b" C6 q7 S) ~5 O - }1 |# o* W% d3 M0 E& O
- }
复制代码1. 在这里简单的跟大家介绍一下DSP库中函数的通用格式,后面就不再赘述了。 (1) 基本所有的函数都是可重入的。 (2) 大部分函数都支持一组数的计算,比如这个函数arm_abs_f32就可以计算一组数的绝对值。所以如果只是就几个数的绝对值,用这个库函数就没有什么优势了。 (3) 库函数基本是CM0,CM3和CM4都支持的(最新的DSP库已经添加CM7的支持)。 (4) 每组数据基本上都是以4个数为一个单位进行计算,不够四个再单独计算。 (5) 大部分函数都是配有f32,Q31,Q15和Q7四种格式。 2. 函数参数,支持输入一个数组进行计算绝对值。 3. 这部分代码是用于CM3和CM4内核。 4. 左移两位从而实现每4个数据为一组进行计算。 5. fabsf:这个函数不是用Cortex-M4F支持的DSP指令实现的,而是用C语言实现的,这个函数是被MDK封装起来的。 6. 切换到下一组数据。 7. 这部分代码用于CM0. 8. 用于不够4个数据的计算或者CM0内核。 8.1.2 arm_abs_q31 这个函数用于求32位定点数的绝对值,源代码分析如下: - /**
: F1 w6 j$ ]' P: ^, L - * @brief Q31 vector absolute value.
) ~2 ?! Q" ?- h8 p+ X/ y - * @param[in] *pSrc points to the input buffer . S, F; m8 Z9 U9 X/ V
- * @param[out] *pDst points to the output buffer 1 S0 g& H7 t; b$ r
- * @param[in] blockSize number of samples in each vector
/ R5 l. Y! e' G. ^. ]! u9 r0 ] - * @return none. 6 @% i$ j" ^/ W; ^" u& N8 w" ~. U2 `2 a
- *
8 q" s( X' I! u. l1 [- O3 f+ @ - * <b>Scaling and Overflow Behavior:</b> (1)/ h. x) I+ a6 o: j2 Q [
- * \par
: ]' \8 T5 p/ H - * The function uses saturating arithmetic.
/ G5 P4 @# V2 r' |* K( i - * The Q31 value -1 (0x80000000) will be saturated to the maximum allowable positive value 0x7FFFFFFF.
4 ]$ O1 n. F$ O, ?6 w4 U% @& ? - */3 C. m* N3 [7 r5 f% {: K9 q
- ; v2 ~4 G) [- j9 F
- void arm_abs_q31(
' o, U) Q f9 l& x) K/ ? - q31_t * pSrc,; Q6 v! @' t# H
- q31_t * pDst,
# k, S' r m7 D7 ^% V - uint32_t blockSize)
8 g W* F1 M7 [( h3 p0 O - {
; O# r& R0 X; B5 }" a- f i% L - uint32_t blkCnt; /* loop counter */ f) l) U# Y. x2 W4 w
- q31_t in; /* Input value */
" o: {% q) ^" C4 l/ u& s' h; g6 x4 w -
: D* R9 w( t: R* A3 o, Q - #ifndef ARM_MATH_CM0_FAMILY
- Z T' ]2 |0 i2 ]+ t - + K |1 A/ L v! C
- /* Run the below code for Cortex-M4 and Cortex-M3 */: m$ J/ q3 R5 h+ C
- q31_t in1, in2, in3, in4;- T" A: I7 x; g& C
-
1 h) E# N. E* f& X6 n2 o4 t - /*loop Unrolling */+ K3 M5 d$ ~' b, {/ \. f; Y1 w
- blkCnt = blockSize >> 2u;
2 `' z& B. R, X2 c/ H; o -
( {; e" M7 j( ^! u - /* First part of the processing with loop unrolling. Compute 4 outputs at a time. 6 J6 b/ W$ K, f# A2 `, S# e
- ** a second loop below computes the remaining 1 to 3 samples. */
y; c6 s. a9 p2 q( n - while(blkCnt > 0u); P. J; N3 l. h7 h" g3 t$ S
- {( a# D2 t7 ?$ v1 d/ {- A Y. ~4 c
- /* C = |A| */3 F% ?/ c, y6 |2 a- b
- /* Calculate absolute of input (if -1 then saturated to 0x7fffffff) and then store the results in the destination buffer. */" |5 V0 n# E9 g% ~ {: S( @
- in1 = *pSrc++;0 ^& m b! Y d- m
- in2 = *pSrc++;
; `" L9 z `6 }1 L7 T; u, ~ - in3 = *pSrc++;/ U. Z" {" [9 V
- in4 = *pSrc++;) g0 l. c8 ^+ \3 n, ?
-
+ W h( k& q% @0 W/ i4 `; _( I0 c - *pDst++ = (in1 > 0) ? in1 : (q31_t)__QSUB(0, in1); (2)
1 W/ K6 S9 Y: c! Z2 Y - *pDst++ = (in2 > 0) ? in2 : (q31_t)__QSUB(0, in2);1 @6 K A1 a' r3 @; Y5 T: A1 P
- *pDst++ = (in3 > 0) ? in3 : (q31_t)__QSUB(0, in3);
: d/ F2 J2 v# m) J0 ?/ i - *pDst++ = (in4 > 0) ? in4 : (q31_t)__QSUB(0, in4);& Q5 j- j# y, }. C S; m
- . M O2 M. X6 R( P
- /* Decrement the loop counter */
1 `" Q# [- C" U1 y - blkCnt--;
+ Z% P: b. e+ |+ V- n `* ~" K - }; u3 ?; c1 y1 ^" A
-
7 P6 T8 l# d) p- i$ x - /* If the blockSize is not a multiple of 4, compute any remaining output samples here. * H6 ?% J% i2 H0 J/ ]/ Z3 p7 T
- ** No loop unrolling is used. */
# {. G0 \7 v6 Y# U6 y - blkCnt = blockSize % 0x4u;4 E4 _9 O% \* u0 `6 f+ _
-
, U4 O; ?3 J& B - #else( U9 E, e* S. x7 d
- / F Q: ?, q0 h# D4 _
- /* Run the below code for Cortex-M0 */
& a& M: i0 W6 O y3 l; I# Y3 Y - " o, n( c3 _# O0 O7 a8 ~3 k. @1 U
- /* Initialize blkCnt with number of samples */7 u e9 Y0 @2 R( W/ Z& [
- blkCnt = blockSize;3 ?& z5 P; `) ^! G* e$ d& q! H
-
( w8 e$ L5 ^8 o# H- \6 l4 W( f5 U - #endif /* #ifndef ARM_MATH_CM0_FAMILY */8 u# e4 q. u# U
- & c1 l" \" f' @- {
- while(blkCnt > 0u)
& g4 K$ K. u& Y# v- ~ - {; I/ H3 k$ Q8 T; M! E( O6 D
- /* C = |A| */
$ J! W. q2 y/ n. `7 v/ j - /* Calculate absolute value of the input (if -1 then saturated to 0x7fffffff) and then store the results in the destination buffer. */
7 [2 m. l2 ^( ]' e; b% J - in = *pSrc++;
9 B) m# T5 ~7 e+ r4 o/ O - *pDst++ = (in > 0) ? in : ((in == INT32_MIN) ? INT32_MAX : -in);$ }% t; y" e( O" |+ X
- ! a A! i: u# U/ R
- /* Decrement the loop counter */" G0 x) A% z* g) u7 B
- blkCnt--;; V8 c0 V9 j O1 K( i1 ~1 }1 L
- }
+ H2 I/ b0 ~0 h% B' ] y - : R( i1 Z6 N6 l1 p) h* C
- }
复制代码1. 这个函数使用了饱和运算,其实不光这个函数,后面很多函数都是使用了饱和运算的,关于什么是饱和运算,大家看Cortex-M3权威指南中文版的4.3.6 小节:汇编语言:饱和运算即可。 对于Q31格式的数据,饱和运算会使得数据0x80000000变成0x7fffffff(这个数比较特殊,算是特殊处理,记住即可)。 2. 这里重点说一下函数__QSUB,其实这个函数算是Cortex-M4/M3的一个指令,用于实现饱和减法。 比如函数:__QSUB(0, in1) 的作用就是实现0 – in1并返回结果。这里__QSUB实现的是32位数的饱和减法。还有__QSUB16和__QSUB8实现的是16位和8位数的减法。 8.1.3 arm_abs_q15 这个函数用于求15位定点数的绝对值,源代码分析如下: - /** + ?- W- h$ W3 V7 [
- * @brief Q15 vector absolute value.
+ e! K% N6 z; @. E - * @param[in] *pSrc points to the input buffer
0 g4 V1 c, X E3 D - * @param[out] *pDst points to the output buffer
* p( P6 Q* A# H ~! T - * @param[in] blockSize number of samples in each vector
( |: N- Z, c' {+ r% b - * @return none.
3 c( v9 ]" J- a* Q - * 4 G" o' u: w8 e5 X" c6 R) A
- * <b>Scaling and Overflow Behavior:</b>
M) U! q% L# K' F# s9 Q$ Q9 Y - * \par 5 F2 Q0 D- m; T' C
- * The function uses saturating arithmetic.
# z ~2 S; e; y: i( l8 n - * The Q15 value -1 (0x8000) will be saturated to the maximum allowable positive value 0x7FFF. (1)9 |" L( a2 S! X- w: H& d0 I( ^
- */
8 ~6 M& A, \- V5 P - : j7 U. a- v6 o5 t6 s# t- l
- void arm_abs_q15(
& p" D8 N5 i ^: y - q15_t * pSrc,
8 J' Y: G- t( ]% z, W& i3 n$ I - q15_t * pDst,
! Q. x9 `, ?6 |5 A - uint32_t blockSize) q( a |6 L, y- p
- {. B# `8 h; V9 `) `% @9 k9 P9 p6 u& e
- uint32_t blkCnt; /* loop counter */8 h/ x3 E' V5 ]+ C! ]( U, g6 M1 n
-
% Y/ W5 w. E3 I' S" K( | - #ifndef ARM_MATH_CM0_FAMILY! s: o- ], u6 I# T/ e. R* o
- __SIMD32_TYPE *simd; (2)
: ^7 x- O3 \- \, R - " M- Z4 T( N2 W% B) q+ q' @, F
- /* Run the below code for Cortex-M4 and Cortex-M3 */+ x3 z2 f9 ]% Z, b8 o+ j
-
+ v6 v& |* V2 E/ @# X' H - q15_t in1; /* Input value1 */
3 U9 L) w3 Z& Z( T1 g8 Q1 o - q15_t in2; /* Input value2 */
4 A# ]% V0 x( ~# f - ) y/ l9 b0 ^/ \8 O3 v
-
; i) i, ^: z1 {2 j6 Q - /*loop Unrolling */
9 t+ ^( T( B% X- ? - blkCnt = blockSize >> 2u;' S) [+ R. K$ N9 Q- I- H) h
-
5 Z6 [5 v) }3 C5 N) _' ?/ ]& G2 J3 C+ n - /* First part of the processing with loop unrolling. Compute 4 outputs at a time. 0 b- W9 k2 o$ y- L( H' E7 ^3 y
- ** a second loop below computes the remaining 1 to 3 samples. */3 j1 G6 H# c; K# m. |* j
- simd = __SIMD32_CONST(pDst); (3)! V6 Z1 @0 H- d7 J( b
- while(blkCnt > 0u)) v6 n8 k' t7 V/ @* i
- {& {1 G; P$ s# D6 a a
- /* C = |A| */
( D+ g% H& }- e+ G: U8 r7 J. } - /* Read two inputs */
4 C' I- f3 m' a2 \) H5 `0 ~! o - in1 = *pSrc++;
9 [1 U1 ]- [- {6 @8 |8 c8 A% E - in2 = *pSrc++;) |0 z A1 T# y" J& v2 B
-
3 |4 Q) b1 D9 \. n - 5 O- X3 _5 i9 ?4 k* C+ l# f
- /* Store the Absolute result in the destination buffer by packing the two values, in a single cycle */
4 {" C0 J) }' ^' b% R0 a - #ifndef ARM_MATH_BIG_ENDIAN" H2 o0 G: o% a
- *simd++ =
- F0 w1 l, N. X& Z7 ^ p - __PKHBT(((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)), (4), P: K* {/ J8 U5 }' N: L
- ((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)), 16);9 p9 O; I. J Q- u: R
-
4 j% Z) w O u6 E - #else; V% t' e* s3 P6 n! F
- ; e- I/ ^; s. \; j% X
- 4 h1 _2 n/ @" L! _) j8 d2 f R( y8 w
- *simd++ =
! c/ O$ y# b1 z2 T% U8 d - __PKHBT(((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)),& _ ~. g! e, P- R$ n' b6 [5 v
- ((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)), 16);( D: W5 a3 S! W% M9 L1 w; [ F
-
+ g5 o% G; P ?% U# \ - #endif /* #ifndef ARM_MATH_BIG_ENDIAN */+ S1 D) z$ e/ y/ f9 R& `
-
$ Y U, n4 t) n% h# E) d% f - in1 = *pSrc++;
E C) O7 U; O& j4 Z% {8 t - in2 = *pSrc++;' k4 @" [' U" E+ c0 }: d
-
! i6 \ ]5 R, o2 [2 S( J' S; b -
) W) j, p+ B, P% X9 w# a - #ifndef ARM_MATH_BIG_ENDIAN5 U* q4 [2 m5 y) u
-
1 `. [ r3 J5 K2 N - *simd++ =
% V1 E; W% w4 z1 k0 A8 Q+ Z - __PKHBT(((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)),# c+ n" ~. k! D3 T! h
- ((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)), 16);
9 A" V! ?- _+ V9 r9 Z -
; t; W$ I# P& ~/ p/ E - #else# z5 L8 Y7 N/ f, c
- & A D( [/ k3 L6 s4 e0 y( A
- 6 Y* O0 z4 F/ K3 B. ]0 @
- *simd++ =# r/ Q! B2 h+ ~
- __PKHBT(((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)),
/ U4 a) F+ g5 R9 r+ h, _ - ((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)), 16);
# \& z9 I% v6 W7 j% `. z4 E -
6 H0 R# G: k8 J4 {: ]! j - #endif /* #ifndef ARM_MATH_BIG_ENDIAN */* j2 R9 y( Y% s$ L8 R; O" T
- . v4 N3 {( p o! `- [8 g. u, N
- /* Decrement the loop counter */
1 t6 {& S; Z n" U - blkCnt--;' O$ _ ~: w3 {3 M. y2 I0 e
- }6 q R+ F) I! v# D
- pDst = (q15_t *)simd;
k7 D$ I4 _+ f& I1 e - /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
/ m) M i9 H2 i4 Q; J/ O4 c% k - ** No loop unrolling is used. */
4 v5 \8 b. N" t" B7 m, d - blkCnt = blockSize % 0x4u;
3 T+ t' m! B' |: B* J k7 v - , t! u, }# ^) d0 f5 ^+ W
- while(blkCnt > 0u)2 R" H0 O2 M5 I
- {# S: Q* n* n! `, J" ?8 o: A
- /* C = |A| */
i0 k* B O- W+ y - /* Read the input */
0 r' L( }, A: o; C( s5 ` - in1 = *pSrc++;8 h9 g# R' w0 X
- % Q( |- x# ~' k4 ~* }# z
- /* Calculate absolute value of input and then store the result in the destination buffer. */1 D) M/ L' o& X2 X+ }* X0 b, g$ k
- *pDst++ = (in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1);
6 _5 [0 k3 ^' U: V* j, O% h -
: _8 N X1 K* l: R4 _; E/ ^" b - /* Decrement the loop counter */- Q$ T) f) f4 h0 r
- blkCnt--;
# ^. G* { o& P6 l" [2 L- {. x - }% K. K# D- W- o( p4 W( X
- $ w& W; m4 D+ P6 O: ^( _5 E
- #else! \6 J1 U) w# Z; ?/ Q
- & R( _4 l( @9 ?
- /* Run the below code for Cortex-M0 */
3 |: h; K+ U3 {. ^8 [" o# N - $ v, o3 T' u1 w: X# V# d
- q15_t in; /* Temporary input variable */
) W r5 } n: k$ z - ' s; R" p; R% T/ ?1 ?; |4 Z# ^
- /* Initialize blkCnt with number of samples */- F" i# ?/ d! z+ |# g+ q
- blkCnt = blockSize;
* K: T! s' g# j7 V- y -
" I* o5 \9 E8 `. i9 p& f, ] - while(blkCnt > 0u)6 N- S0 e% K' R
- {
0 g w i+ o$ }5 W4 I - /* C = |A| */. U; H( H( \0 J" D* N" r/ i0 U
- /* Read the input */
1 v4 R* M* F+ z9 C( t2 V) o - in = *pSrc++;( a1 D: |% {$ _
- ; o" h) H. X e% Y1 j0 \
- /* Calculate absolute value of input and then store the result in the destination buffer. */
# J* V7 n; y# e& i5 c S8 q - *pDst++ = (in > 0) ? in : ((in == (q15_t) 0x8000) ? 0x7fff : -in);
' _3 W& {. t' M% U - 0 {8 _+ ^3 }; ?3 {# G4 E
- /* Decrement the loop counter *// ]4 V8 v4 q; N: O
- blkCnt--;$ q1 `9 V! x% Y0 k5 N( x1 D
- }
& x/ v4 K0 h( ? U F4 J -
, K- a2 K0 k4 e0 r - #endif /* #ifndef ARM_MATH_CM0_FAMILY */
! a- N: S2 r7 n' \ h, } -
# L, M5 T8 b L+ B - }
复制代码1. 对于Q15格式的数据,饱和运算会使得数据0x8000变成0x7fff。 2. __SIMD32_TYPE的定义在文件arm_math.h中,具体定义如下: #define __SIMD32_TYPE int32_t __packed SIMD就是咱们上期教程所将的单指令多数据流。简单的理解就是__SIMD32_TYPE就是定义了一个int32_t类型的数据,__packed的含义就是实现字节的对齐功能,方便两个16位数据的都存入到这个数据类型中。 3. 函数__SIMD32_CONST的定义如下: #define __SIMD32_CONST(addr) ((__SIMD32_TYPE *)(addr)) 4. 函数__PKHBT的定义在文件core_cm4_simd.h,定义如下: #define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) 这个宏定义的作用就是将将两个16位的数据合并成32位数据。但是有一点要特别说明__PKHBT也是CM4内核支持的SIMD指令,上面的宏定义的C函数会被MDK自动识别并调用相应的PKHBT指令。 __QSUB16用于实现16位数据的饱和减法。 8.1.4 arm_abs_q7 这个函数用于求8位定点数的绝对值,源代码分析如下: - /** 8 t0 ~' l# W6 s( B& d# M3 U& q l9 y
- * @brief Q7 vector absolute value.
0 i+ D3 c c l5 ? - * @param[in] *pSrc points to the input buffer + g0 j' r: E9 X/ J" k. ~
- * @param[out] *pDst points to the output buffer
" ?/ d& ^' R" q9 r2 }0 p4 p - * @param[in] blockSize number of samples in each vector n" @/ F3 } c& f" k
- * @return none.
& V+ V- j+ b1 ?# F# [; x* G - *
, \% d& b6 w, |7 Z) G - * \par Conditions for optimum performance 6 q* L0 _+ ?/ m. Y/ u3 X6 h
- * Input and output buffers should be aligned by 32-bit
) i; J5 S* L+ |. { - * Q* x% j+ |3 g/ r9 s
- *
( [2 G' T0 `: a$ ]. S# d9 r - * <b>Scaling and Overflow Behavior:</b> (1)
" f$ N& G8 l, \8 Q - * \par 8 f) O9 O+ D- K; _" Z
- * The function uses saturating arithmetic. $ a3 G' @+ V4 |5 W. N- i
- * The Q7 value -1 (0x80) will be saturated to the maximum allowable positive value 0x7F.
" L8 |! \3 C7 B& \) J - */
( t5 b* l3 |" _+ U9 X8 P3 A -
* f; w0 L4 `5 l& z3 {+ c. E - void arm_abs_q7(
, ?( s3 D2 q0 r' r - q7_t * pSrc,. W& ]- S- c0 _& E8 L! J2 g4 M, T
- q7_t * pDst,
: o; \. t' h( D% n0 c - uint32_t blockSize)
" a' y3 ?; _. O7 Z2 L5 j5 ~ - {2 |- P5 v1 o3 G$ X' @/ h
- uint32_t blkCnt; /* loop counter */! X$ _$ s5 g; c
- q7_t in; /* Input value1 */0 O! N& C: C0 p: \8 x8 Z
-
- ~" w0 q0 a! ^% p& u+ j - #ifndef ARM_MATH_CM0_FAMILY
0 C+ T+ `) Y% E4 S -
9 {6 R9 p5 Z: x3 P - /* Run the below code for Cortex-M4 and Cortex-M3 */: d* B: v' k+ d* h4 K9 H- ^" C4 v0 y: a
- q31_t in1, in2, in3, in4; /* temporary input variables */+ n4 D/ J3 W5 \ t- T' d- V s, Q* H
- q31_t out1, out2, out3, out4; /* temporary output variables */
6 p& ]6 I$ s- h% j# j - - H+ I% E0 F4 a/ M3 r9 h& K/ |6 _" _7 X
- /*loop Unrolling */" f0 v, N& p3 [0 F, E% N2 b
- blkCnt = blockSize >> 2u;
B& F6 W" ~+ S+ x -
3 e! l; N/ K0 X, V5 k - /* First part of the processing with loop unrolling. Compute 4 outputs at a time. 5 a0 J4 A8 h- P, v
- ** a second loop below computes the remaining 1 to 3 samples. */
/ q+ Z# e4 e9 J6 A5 B, G9 [6 F9 ` - while(blkCnt > 0u)* I' R( V; {$ R- Y! i& }% Z
- {
( {3 @+ C* N0 t% q" { - /* C = |A| */ i8 D5 h! f( S5 D
- /* Read inputs */: J3 d& H; e, i/ T
- in1 = (q31_t) * pSrc;
+ `7 p$ H* ?1 ]- ^! g1 H; r - in2 = (q31_t) * (pSrc + 1);' q! |+ Z/ |; H1 z
- in3 = (q31_t) * (pSrc + 2);% V- N) y/ s- T% b" ~
-
5 w$ ?9 ?. T) z" F) O! O: S - /* find absolute value */
+ o. x7 T$ y2 m0 s4 J/ U6 x - out1 = (in1 > 0) ? in1 : (q31_t)__QSUB8(0, in1); (2)
: Z: {+ E2 B) r+ J* l -
9 u& X s# _2 w) ] - /* read input */& U: |3 L# x3 i/ C& N1 @5 d
- in4 = (q31_t) * (pSrc + 3);* k) z: g/ H$ O, G5 D
-
) p" K$ N& c$ V! o5 U+ } - /* find absolute value */+ T# i# M1 _7 m/ h3 d/ o
- out2 = (in2 > 0) ? in2 : (q31_t)__QSUB8(0, in2);# M$ `/ S( Y& a( R; c
- : ~! {1 I; G" j! ^1 p I
- /* store result to destination */* W5 [" g: z& S: }5 E& l
- *pDst = (q7_t) out1;' C" o$ u# @- o0 f' H
- 1 t2 Y+ q# j* [6 p, d+ F' s
- /* find absolute value */
B ?! e8 r- j$ l$ S3 L - out3 = (in3 > 0) ? in3 : (q31_t)__QSUB8(0, in3);$ O R% v+ _* g* Y( g3 f4 H5 _
- ! e) \7 D+ i8 {( ^; v: u# p
- /* find absolute value */: L. J7 e3 q' ^# {
- out4 = (in4 > 0) ? in4 : (q31_t)__QSUB8(0, in4);# }% y8 B; v7 {5 ^) _. x! B
-
0 d8 X% j7 Z# f! t @: [ - /* store result to destination */
7 H' h) q' I! a. h - *(pDst + 1) = (q7_t) out2;) [0 i C+ H7 I, b* k) \
- / y+ f( Z* A9 x5 V/ ^2 @- O2 G( C
- /* store result to destination */8 d0 T+ C& f2 }# t3 o
- *(pDst + 2) = (q7_t) out3;5 M9 n1 f) t, |1 N L$ X, |
- 8 C/ G6 C7 r, e" f% K
- /* store result to destination */
# G2 ]( j* D# N& _ - *(pDst + 3) = (q7_t) out4;" b. J; k/ _9 v9 ~
- : |: L. u: N9 E- R% D3 h
- /* update pointers to process next samples */! M4 r* e0 e- \: ^5 p0 R) `! b; Z
- pSrc += 4u;' n1 ?+ {/ ^! d0 ?4 h
- pDst += 4u;4 R# `/ |: R: u1 ~3 y: [* x/ k
-
- j% M( y2 d1 k$ w( {' |/ {1 y- _ - /* Decrement the loop counter */( P# ?" ~. @- r( ?
- blkCnt--;
$ }2 {( K) J2 y; [% E - }
5 H l! e7 @0 { - ; A) r l. E1 P1 c* W( I! k1 {4 j
- /* If the blockSize is not a multiple of 4, compute any remaining output samples here. & K; k3 f; y. p7 @# |- n
- ** No loop unrolling is used. */
1 I1 C t" ^+ B3 ], R - blkCnt = blockSize % 0x4u;
6 u: W4 t1 ]6 e8 N8 s% | - #else. v$ _. @4 {8 f- }% l
-
4 B9 v' W9 d3 K5 D+ T J2 v - /* Run the below code for Cortex-M0 */: Z) D+ n; X4 h/ X! f7 Q
- blkCnt = blockSize;
' e9 _$ `. p% _: s - $ p# i1 l3 f+ m( ? A! b- S: W& v
- #endif // #define ARM_MATH_CM0_FAMILY/ A3 ^/ s6 x K
-
% e2 G8 M9 d. m( p - while(blkCnt > 0u)
3 L ^, B* _* i. a* n: F- q - {" e3 F( ~, v0 K( i' x% c( v% ~) W
- /* C = |A| */' S/ N; z' d1 n! Y0 n( ?4 I% C2 y
- /* Read the input */
* W* F L/ f) @# y, }1 [1 w! Y - in = *pSrc++;
! }+ U! b0 z7 @8 t- t( k6 M. F -
0 H% H$ Y2 z: Y- B" J: u- m - /* Store the Absolute result in the destination buffer */
! ~% G3 M; h5 r L' I9 f7 [ - *pDst++ = (in > 0) ? in : ((in == (q7_t) 0x80) ? 0x7f : -in);
3 Q4 I {$ @8 H -
8 F# f) @2 g' g( O7 ^ - /* Decrement the loop counter */* J( d3 A/ d# ~$ d0 O! _; k
- blkCnt--;
, u2 w4 Y1 b* t. M6 X* n) H3 o6 m - }) Q( S/ B7 B; X2 Q
- }
复制代码1. 由于饱和运算,0x80求绝对值将变成数据0x7F。 2. __QSUB8用以实现8位数的饱和减法运算。 8.1.5 实例讲解实验目的: 1. 四种数据类型数据绝对值求解 实验内容: 1. 按下按键K1, 串口打印输出结果 实验现象: 通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下: 程序设计: - /*
# \8 H2 K. K" {3 S" a, [/ V - *********************************************************************************************************$ r+ J' Q# s+ B+ H1 a! Y1 h- S+ a% r
- * 函 数 名: DSP_ABS6 O/ S. v: Z, B; [
- * 功能说明: 求绝对值* _% j) G+ ]; q# v: c
- * 形 参:无. M- P h' d. z1 |# z
- * 返 回 值: 无
! c) V& w$ g* ~2 a3 r( N - *********************************************************************************************************
$ j" U U- a9 M) ^! | - */, V* f& d0 p$ E* Q
- static void DSP_ABS(void)
2 c3 B! b {1 u* a' i - {
, d7 c! l8 W( K* |9 g! ~( t - static float32_t pSrc;) |$ Q& ^( p3 w _3 J0 b
- static float32_t pDst;
* z$ v' t: J$ }& M% N6 T - static q31_t pSrc1;5 H% D+ K% r, F, e& |7 |/ w" e2 j
- static q31_t pDst1;% s" q. L7 L- a1 @
- static q15_t pSrc2;
6 Q: R/ L! T4 A2 s) g - static q15_t pDst2;
6 \" k% M, r& J7 O" b1 T - static q7_t pSrc3 = 127; /* 为了说明问题,在这里设置初始值为127,然后查看0x80是否饱和为0x7F */0 C) v0 Z: T6 Q, Y+ _( h
- static q7_t pDst3;% @0 r+ Q) U/ t, X
- pSrc -= 1.23f;( Q% j; P0 G; y+ ~
- arm_abs_f32(&pSrc, &pDst, 1); (1) Z. G7 J( @& ~" T* n. i$ w
- printf("arm_abs_f32 = %f\r\n", pDst);
9 W9 M( m- I4 B' H - 6 `3 x: g+ A2 M* G& F7 n
- pSrc1 -= 1; Y0 G7 `; Z! Q' k! G' f
- arm_abs_q31(&pSrc1, &pDst1, 1); (2)
7 j7 L9 t4 o) M$ S6 @ - printf("arm_abs_q31 = %d\r\n", pDst1);" Z; N h ]' A# p
- % [( Q- k- W* Q, J
- pSrc2 -= 1;9 C# |2 e1 k$ l. h0 a* W2 \
- arm_abs_q15(&pSrc2, &pDst2, 1); (3)
~, [7 i# O8 M. x4 n, D - printf("arm_abs_q15 = %d\r\n", pDst2);( q* U+ x. P# c5 ]+ @
-
7 }9 u( K# ]* @. L5 u( K& ? - pSrc3 += 1;
/ s3 Z) z# y/ b/ B - printf("pSrc3 = %d\r\n", pSrc3);
+ @ f4 X- J8 x% u - arm_abs_q7(&pSrc3, &pDst3, 1); (4)$ L" c1 W! g. I2 n1 A
- printf("arm_abs_q7 = %d\r\n", pDst3);
$ p8 [- e. x9 @7 L% M9 k - printf("***********************************\r\n");
" s5 a; {) o' ~7 W; @4 x - }
复制代码(1)到(4)实现相应格式下绝对值的求解。这里只求了一个数,大家可以尝试求解一个数组的绝对值。 ( \8 I/ E9 c) q' Q5 Q3 t8 U+ q" W
|
8.5 总结