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