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  */
60 
61 #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
62 
63 #include "arm_helium_utils.h"
arm_absmin_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)64 void arm_absmin_f32(
65   const float32_t * pSrc,
66         uint32_t blockSize,
67         float32_t * pResult,
68         uint32_t * pIndex)
69 {
70     int32_t  blkCnt;           /* loop counters */
71     f32x4_t vecSrc;
72     float32_t const *pSrcVec;
73     f32x4_t curExtremValVec = vdupq_n_f32(F32_ABSMAX);
74     float32_t minValue = F32_ABSMAX;
75     uint32_t  idx = blockSize;
76     uint32x4_t indexVec;
77     uint32x4_t curExtremIdxVec;
78     mve_pred16_t p0;
79 
80 
81     indexVec = vidupq_u32((uint32_t)0, 1);
82     curExtremIdxVec = vdupq_n_u32(0);
83 
84     pSrcVec = (float32_t const *) pSrc;
85     blkCnt = blockSize >> 2;
86     while (blkCnt > 0)
87     {
88         vecSrc = vldrwq_f32(pSrcVec);
89         pSrcVec += 4;
90         vecSrc = vabsq(vecSrc);
91         /*
92          * Get current max per lane and current index per lane
93          * when a max is selected
94          */
95         p0 = vcmpleq(vecSrc, curExtremValVec);
96         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
97         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
98 
99         indexVec = indexVec +  4;
100         /*
101          * Decrement the blockSize loop counter
102          */
103         blkCnt--;
104     }
105     /*
106      * tail
107      * (will be merged thru tail predication)
108      */
109     blkCnt = blockSize & 3;
110     if (blkCnt > 0)
111     {
112         p0 = vctp32q(blkCnt);
113 
114         vecSrc = vldrwq_f32(pSrcVec);
115         pSrcVec += 4;
116         vecSrc = vabsq(vecSrc);
117         /*
118          * Get current max per lane and current index per lane
119          * when a max is selected
120          */
121         p0 = vcmpleq_m(vecSrc, curExtremValVec, p0);
122         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
123         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
124     }
125     /*
126      * Get min value across the vector
127      */
128     minValue = vminnmvq(minValue, curExtremValVec);
129     /*
130      * set index for lower values to max possible index
131      */
132     p0 = vcmpleq(curExtremValVec, minValue);
133     indexVec = vpselq(curExtremIdxVec, vdupq_n_u32(blockSize), p0);
134     /*
135      * Get min index which is thus for a max value
136      */
137     idx = vminvq(idx, indexVec);
138     /*
139      * Save result
140      */
141     *pIndex = idx;
142     *pResult = minValue;
143 }
144 
145 #else
146 #if defined(ARM_MATH_LOOPUNROLL)
arm_absmin_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)147 void arm_absmin_f32(
148   const float32_t * pSrc,
149         uint32_t blockSize,
150         float32_t * pResult,
151         uint32_t * pIndex)
152 {
153         float32_t cur_absmin, out;                     /* Temporary variables to store the output value. */\
154         uint32_t blkCnt, outIndex;                     /* Loop counter */                                   \
155         uint32_t index;                                /* index of maximum value */                         \
156                                                                                                             \
157   /* Initialize index value to zero. */                                                                     \
158   outIndex = 0U;                                                                                            \
159   /* Load first input value that act as reference value for comparision */                                  \
160   out = *pSrc++;                                                                                            \
161   out = (out > 0.0f) ? out : -out;                                                                             \
162   /* Initialize index of extrema value. */                                                                  \
163   index = 0U;                                                                                               \
164                                                                                                             \
165   /* Loop unrolling: Compute 4 outputs at a time */                                                         \
166   blkCnt = (blockSize - 1U) >> 2U;                                                                          \
167                                                                                                             \
168   while (blkCnt > 0U)                                                                                       \
169   {                                                                                                         \
170     /* Initialize cur_absmin to next consecutive values one by one */                                         \
171     cur_absmin = *pSrc++;                                                                                     \
172     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
173     /* compare for the extrema value */                                                                     \
174     if (cur_absmin < out)                                                                         \
175     {                                                                                                       \
176       /* Update the extrema value and it's index */                                                         \
177       out = cur_absmin;                                                                                       \
178       outIndex = index + 1U;                                                                                \
179     }                                                                                                       \
180                                                                                                             \
181     cur_absmin = *pSrc++;                                                                                     \
182     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
183     if (cur_absmin < out)                                                                         \
184     {                                                                                                       \
185       out = cur_absmin;                                                                                       \
186       outIndex = index + 2U;                                                                                \
187     }                                                                                                       \
188                                                                                                             \
189     cur_absmin = *pSrc++;                                                                                     \
190     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
191     if (cur_absmin < out)                                                                          \
192     {                                                                                                       \
193       out = cur_absmin;                                                                                       \
194       outIndex = index + 3U;                                                                                \
195     }                                                                                                       \
196                                                                                                             \
197     cur_absmin = *pSrc++;                                                                                     \
198     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
199     if (cur_absmin < out)                                                                          \
200     {                                                                                                       \
201       out = cur_absmin;                                                                                       \
202       outIndex = index + 4U;                                                                                \
203     }                                                                                                       \
204                                                                                                             \
205     index += 4U;                                                                                            \
206                                                                                                             \
207     /* Decrement loop counter */                                                                            \
208     blkCnt--;                                                                                               \
209   }                                                                                                         \
210                                                                                                             \
211   /* Loop unrolling: Compute remaining outputs */                                                           \
212   blkCnt = (blockSize - 1U) % 4U;                                                                           \
213                                                                                                             \
214                                                                                                             \
215   while (blkCnt > 0U)                                                                                       \
216   {                                                                                                         \
217     cur_absmin = *pSrc++;                                                                                     \
218     cur_absmin = (cur_absmin > 0.0f) ? cur_absmin : -cur_absmin;                                                                 \
219     if (cur_absmin < out)                                                                         \
220     {                                                                                                       \
221       out = cur_absmin;                                                                                       \
222       outIndex = blockSize - blkCnt;                                                                        \
223     }                                                                                                       \
224                                                                                                             \
225     /* Decrement loop counter */                                                                            \
226     blkCnt--;                                                                                               \
227   }                                                                                                         \
228                                                                                                             \
229   /* Store the extrema value and it's index into destination pointers */                                    \
230   *pResult = out;                                                                                           \
231   *pIndex = outIndex;
232 }
233 #else
arm_absmin_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)234 void arm_absmin_f32(
235   const float32_t * pSrc,
236         uint32_t blockSize,
237         float32_t * pResult,
238         uint32_t * pIndex)
239 {
240        float32_t minVal, out;                         /* Temporary variables to store the output value. */
241        uint32_t blkCnt, outIndex;                     /* Loop counter */
242 
243   /* Initialise index value to zero. */
244   outIndex = 0U;
245 
246   /* Load first input value that act as reference value for comparision */
247   out = fabsf(*pSrc++);
248 
249   /* Initialize blkCnt with number of samples */
250   blkCnt = (blockSize - 1U);
251 
252   while (blkCnt > 0U)
253   {
254     /* Initialize minVal to the next consecutive values one by one */
255     minVal = fabsf(*pSrc++);
256 
257     /* compare for the minimum value */
258     if (out > minVal)
259     {
260       /* Update the minimum value and it's index */
261       out = minVal;
262       outIndex = blockSize - blkCnt;
263     }
264 
265     /* Decrement loop counter */
266     blkCnt--;
267   }
268 
269   /* Store the minimum value and it's index into destination pointers */
270   *pResult = out;
271   *pIndex = outIndex;
272 }
273 
274 #endif /* defined(ARM_MATH_LOOPUNROLL) */
275 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
276 /**
277   @} end of AbsMin group
278  */
279