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