1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_absmin_f32.c
4  * Description:  Minimum value of absolute values of a floating-point vector
5  *
6  * $Date:        23 April 2021
7  * $Revision:    V1.9.0
8  *
9  * Target Processor: Cortex-M and Cortex-A cores
10  * -------------------------------------------------------------------- */
11 /*
12  * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the License); you may
17  * not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  * www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  */
28 
29 #include "dsp/statistics_functions.h"
30 
31 #if (defined(ARM_MATH_NEON) || defined(ARM_MATH_MVEF)) && !defined(ARM_MATH_AUTOVECTORIZE)
32 #include <limits.h>
33 #endif
34 
35 
36 /**
37   @ingroup groupStats
38  */
39 
40 /**
41   @defgroup AbsMin Absolute Minimum
42 
43   Computes the minimum value of absolute values of an array of data.
44   The function returns both the minimum value and its position within the array.
45   There are separate functions for floating-point, Q31, Q15, and Q7 data types.
46  */
47 
48 /**
49   @addtogroup AbsMin
50   @{
51  */
52 
53 /**
54   @brief         Minimum value of absolute values of a floating-point vector.
55   @param[in]     pSrc       points to the input vector
56   @param[in]     blockSize  number of samples in input vector
57   @param[out]    pResult    minimum value returned here
58   @param[out]    pIndex     index of minimum value returned here
59   @return        none
60  */
61 
62 #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
63 
64 #include "arm_helium_utils.h"
arm_absmin_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)65 void arm_absmin_f32(
66   const float32_t * pSrc,
67         uint32_t blockSize,
68         float32_t * pResult,
69         uint32_t * pIndex)
70 {
71     int32_t  blkCnt;           /* loop counters */
72     f32x4_t vecSrc;
73     float32_t const *pSrcVec;
74     f32x4_t curExtremValVec = vdupq_n_f32(F32_ABSMAX);
75     float32_t minValue = F32_ABSMAX;
76     uint32_t  idx = blockSize;
77     uint32x4_t indexVec;
78     uint32x4_t curExtremIdxVec;
79     mve_pred16_t p0;
80 
81 
82     indexVec = vidupq_u32((uint32_t)0, 1);
83     curExtremIdxVec = vdupq_n_u32(0);
84 
85     pSrcVec = (float32_t const *) pSrc;
86     blkCnt = blockSize >> 2;
87     while (blkCnt > 0)
88     {
89         vecSrc = vldrwq_f32(pSrcVec);
90         pSrcVec += 4;
91         vecSrc = vabsq(vecSrc);
92         /*
93          * Get current max per lane and current index per lane
94          * when a max is selected
95          */
96         p0 = vcmpleq(vecSrc, curExtremValVec);
97         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
98         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
99 
100         indexVec = indexVec +  4;
101         /*
102          * Decrement the blockSize loop counter
103          */
104         blkCnt--;
105     }
106     /*
107      * tail
108      * (will be merged thru tail predication)
109      */
110     blkCnt = blockSize & 3;
111     if (blkCnt > 0)
112     {
113         p0 = vctp32q(blkCnt);
114 
115         vecSrc = vldrwq_f32(pSrcVec);
116         pSrcVec += 4;
117         vecSrc = vabsq(vecSrc);
118         /*
119          * Get current max per lane and current index per lane
120          * when a max is selected
121          */
122         p0 = vcmpleq_m(vecSrc, curExtremValVec, p0);
123         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
124         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
125     }
126     /*
127      * Get min value across the vector
128      */
129     minValue = vminnmvq(minValue, curExtremValVec);
130     /*
131      * set index for lower values to max possible index
132      */
133     p0 = vcmpleq(curExtremValVec, minValue);
134     indexVec = vpselq(curExtremIdxVec, vdupq_n_u32(blockSize), p0);
135     /*
136      * Get min index which is thus for a max value
137      */
138     idx = vminvq(idx, indexVec);
139     /*
140      * Save result
141      */
142     *pIndex = idx;
143     *pResult = minValue;
144 }
145 
146 #else
147 #if defined(ARM_MATH_LOOPUNROLL)
arm_absmin_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)148 void arm_absmin_f32(
149   const float32_t * pSrc,
150         uint32_t blockSize,
151         float32_t * pResult,
152         uint32_t * pIndex)
153 {
154         float32_t cur_absmin, out;                     /* Temporary variables to store the output value. */\
155         uint32_t blkCnt, outIndex;                     /* Loop counter */                                   \
156         uint32_t index;                                /* index of maximum value */                         \
157                                                                                                             \
158   /* Initialize index value to zero. */                                                                     \
159   outIndex = 0U;                                                                                            \
160   /* Load first input value that act as reference value for comparision */                                  \
161   out = *pSrc++;                                                                                            \
162   out = (out > 0.0f) ? out : -out;                                                                             \
163   /* Initialize index of extrema value. */                                                                  \
164   index = 0U;                                                                                               \
165                                                                                                             \
166   /* Loop unrolling: Compute 4 outputs at a time */                                                         \
167   blkCnt = (blockSize - 1U) >> 2U;                                                                          \
168                                                                                                             \
169   while (blkCnt > 0U)                                                                                       \
170   {                                                                                                         \
171     /* Initialize cur_absmin to next consecutive values one by one */                                         \
172     cur_absmin = *pSrc++;                                                                                     \
173     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
174     /* compare for the extrema value */                                                                     \
175     if (cur_absmin < out)                                                                         \
176     {                                                                                                       \
177       /* Update the extrema value and it's index */                                                         \
178       out = cur_absmin;                                                                                       \
179       outIndex = index + 1U;                                                                                \
180     }                                                                                                       \
181                                                                                                             \
182     cur_absmin = *pSrc++;                                                                                     \
183     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
184     if (cur_absmin < out)                                                                         \
185     {                                                                                                       \
186       out = cur_absmin;                                                                                       \
187       outIndex = index + 2U;                                                                                \
188     }                                                                                                       \
189                                                                                                             \
190     cur_absmin = *pSrc++;                                                                                     \
191     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
192     if (cur_absmin < out)                                                                          \
193     {                                                                                                       \
194       out = cur_absmin;                                                                                       \
195       outIndex = index + 3U;                                                                                \
196     }                                                                                                       \
197                                                                                                             \
198     cur_absmin = *pSrc++;                                                                                     \
199     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
200     if (cur_absmin < out)                                                                          \
201     {                                                                                                       \
202       out = cur_absmin;                                                                                       \
203       outIndex = index + 4U;                                                                                \
204     }                                                                                                       \
205                                                                                                             \
206     index += 4U;                                                                                            \
207                                                                                                             \
208     /* Decrement loop counter */                                                                            \
209     blkCnt--;                                                                                               \
210   }                                                                                                         \
211                                                                                                             \
212   /* Loop unrolling: Compute remaining outputs */                                                           \
213   blkCnt = (blockSize - 1U) % 4U;                                                                           \
214                                                                                                             \
215                                                                                                             \
216   while (blkCnt > 0U)                                                                                       \
217   {                                                                                                         \
218     cur_absmin = *pSrc++;                                                                                     \
219     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
220     if (cur_absmin < out)                                                                         \
221     {                                                                                                       \
222       out = cur_absmin;                                                                                       \
223       outIndex = blockSize - blkCnt;                                                                        \
224     }                                                                                                       \
225                                                                                                             \
226     /* Decrement loop counter */                                                                            \
227     blkCnt--;                                                                                               \
228   }                                                                                                         \
229                                                                                                             \
230   /* Store the extrema value and it's index into destination pointers */                                    \
231   *pResult = out;                                                                                           \
232   *pIndex = outIndex;
233 }
234 #else
arm_absmin_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)235 void arm_absmin_f32(
236   const float32_t * pSrc,
237         uint32_t blockSize,
238         float32_t * pResult,
239         uint32_t * pIndex)
240 {
241        float32_t minVal, out;                         /* Temporary variables to store the output value. */
242        uint32_t blkCnt, outIndex;                     /* Loop counter */
243 
244   /* Initialise index value to zero. */
245   outIndex = 0U;
246 
247   /* Load first input value that act as reference value for comparision */
248   out = fabsf(*pSrc++);
249 
250   /* Initialize blkCnt with number of samples */
251   blkCnt = (blockSize - 1U);
252 
253   while (blkCnt > 0U)
254   {
255     /* Initialize minVal to the next consecutive values one by one */
256     minVal = fabsf(*pSrc++);
257 
258     /* compare for the minimum value */
259     if (out > minVal)
260     {
261       /* Update the minimum value and it's index */
262       out = minVal;
263       outIndex = blockSize - blkCnt;
264     }
265 
266     /* Decrement loop counter */
267     blkCnt--;
268   }
269 
270   /* Store the minimum value and it's index into destination pointers */
271   *pResult = out;
272   *pIndex = outIndex;
273 }
274 
275 #endif /* defined(ARM_MATH_LOOPUNROLL) */
276 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
277 /**
278   @} end of AbsMin group
279  */
280