1 /* ----------------------------------------------------------------------
2 * Project: CMSIS DSP Library
3 * Title: arm_absmin_q15.c
4 * Description: Minimum value of absolute values of a Q15 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 /**
32 @ingroup groupStats
33 */
34
35
36 /**
37 @addtogroup AbsMin
38 @{
39 */
40
41 /**
42 @brief Minimum value of absolute values of a Q15 vector.
43 @param[in] pSrc points to the input vector
44 @param[in] blockSize number of samples in input vector
45 @param[out] pResult minimum value returned here
46 @param[out] pIndex index of minimum value returned here
47 */
48 #if defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE)
49
50 #include "arm_helium_utils.h"
51
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)52 ARM_DSP_ATTRIBUTE void arm_absmin_q15(
53 const q15_t * pSrc,
54 uint32_t blockSize,
55 q15_t * pResult,
56 uint32_t * pIndex)
57 {
58 uint16_t blkCnt; /* loop counters */
59 q15x8_t vecSrc;
60 q15_t const *pSrcVec;
61 q15x8_t curExtremValVec = vdupq_n_s16(Q15_ABSMAX);
62 q15_t minValue = Q15_ABSMAX;
63 uint16_t idx = blockSize;
64 uint16x8_t indexVec;
65 uint16x8_t curExtremIdxVec;
66 uint32_t startIdx = 0;
67 mve_pred16_t p0;
68
69
70 indexVec = vidupq_wb_u16(&startIdx, 1);
71 curExtremIdxVec = vdupq_n_u16(0);
72
73 pSrcVec = (q15_t const *) pSrc;
74 blkCnt = blockSize >> 3;
75 while (blkCnt > 0U)
76 {
77 vecSrc = vld1q(pSrcVec);
78 pSrcVec += 8;
79 vecSrc = vabsq(vecSrc);
80 /*
81 * Get current min per lane and current index per lane
82 * when a min is selected
83 */
84 p0 = vcmpleq(vecSrc, curExtremValVec);
85 curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
86 curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
87
88 indexVec = vidupq_wb_u16(&startIdx, 1);
89 /*
90 * Decrement the blockSize loop counter
91 */
92 blkCnt--;
93 }
94 /*
95 * tail
96 * (will be merged thru tail predication)
97 */
98 blkCnt = blockSize & 7;
99 if (blkCnt > 0U)
100 {
101 vecSrc = vld1q(pSrcVec);
102 pSrcVec += 8;
103 vecSrc = vabsq(vecSrc);
104
105 p0 = vctp16q(blkCnt);
106 /*
107 * Get current min per lane and current index per lane
108 * when a min is selected
109 */
110 p0 = vcmpleq_m(vecSrc, curExtremValVec, p0);
111 curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
112 curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
113 }
114 /*
115 * Get min value across the vector
116 */
117 minValue = vminvq(minValue, curExtremValVec);
118 /*
119 * set index for lower values to min possible index
120 */
121 p0 = vcmpleq(curExtremValVec, minValue);
122 indexVec = vpselq(curExtremIdxVec, vdupq_n_u16(blockSize), p0);
123 /*
124 * Get min index which is thus for a min value
125 */
126 idx = vminvq(idx, indexVec);
127 /*
128 * Save result
129 */
130 *pIndex = idx;
131 *pResult = minValue;
132 }
133
134 #else
135 #if defined(ARM_MATH_DSP)
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)136 ARM_DSP_ATTRIBUTE void arm_absmin_q15(
137 const q15_t * pSrc,
138 uint32_t blockSize,
139 q15_t * pResult,
140 uint32_t * pIndex)
141 {
142 q15_t cur_absmin, out; /* Temporary variables to store the output value. */\
143 uint32_t blkCnt, outIndex; /* Loop counter */ \
144 uint32_t index; /* index of maximum value */ \
145 \
146 /* Initialize index value to zero. */ \
147 outIndex = 0U; \
148 /* Load first input value that act as reference value for comparision */ \
149 out = *pSrc++; \
150 out = (out > 0) ? out : (q15_t)__QSUB16(0, out); \
151 /* Initialize index of extrema value. */ \
152 index = 0U; \
153 \
154 /* Loop unrolling: Compute 4 outputs at a time */ \
155 blkCnt = (blockSize - 1U) >> 2U; \
156 \
157 while (blkCnt > 0U) \
158 { \
159 /* Initialize cur_absmin to next consecutive values one by one */ \
160 cur_absmin = *pSrc++; \
161 cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin); \
162 /* compare for the extrema value */ \
163 if (cur_absmin < out) \
164 { \
165 /* Update the extrema value and it's index */ \
166 out = cur_absmin; \
167 outIndex = index + 1U; \
168 } \
169 \
170 cur_absmin = *pSrc++; \
171 cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin); \
172 if (cur_absmin < out) \
173 { \
174 out = cur_absmin; \
175 outIndex = index + 2U; \
176 } \
177 \
178 cur_absmin = *pSrc++; \
179 cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin); \
180 if (cur_absmin < out) \
181 { \
182 out = cur_absmin; \
183 outIndex = index + 3U; \
184 } \
185 \
186 cur_absmin = *pSrc++; \
187 cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin); \
188 if (cur_absmin < out) \
189 { \
190 out = cur_absmin; \
191 outIndex = index + 4U; \
192 } \
193 \
194 index += 4U; \
195 \
196 /* Decrement loop counter */ \
197 blkCnt--; \
198 } \
199 \
200 /* Loop unrolling: Compute remaining outputs */ \
201 blkCnt = (blockSize - 1U) % 4U; \
202 \
203 \
204 while (blkCnt > 0U) \
205 { \
206 cur_absmin = *pSrc++; \
207 cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin); \
208 if (cur_absmin < out) \
209 { \
210 out = cur_absmin; \
211 outIndex = blockSize - blkCnt; \
212 } \
213 \
214 /* Decrement loop counter */ \
215 blkCnt--; \
216 } \
217 \
218 /* Store the extrema value and it's index into destination pointers */ \
219 *pResult = out; \
220 *pIndex = outIndex;
221 }
222 #else
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)223 ARM_DSP_ATTRIBUTE void arm_absmin_q15(
224 const q15_t * pSrc,
225 uint32_t blockSize,
226 q15_t * pResult,
227 uint32_t * pIndex)
228 {
229 q15_t minVal, out; /* Temporary variables to store the output value. */
230 uint32_t blkCnt, outIndex; /* Loop counter */
231
232
233 /* Initialise index value to zero. */
234 outIndex = 0U;
235 /* Load first input value that act as reference value for comparision */
236 out = (*pSrc > 0) ? *pSrc : ((*pSrc == (q15_t) 0x8000) ? 0x7fff : -*pSrc);
237 pSrc++;
238
239 /* Initialize blkCnt with number of samples */
240 blkCnt = (blockSize - 1U);
241
242 while (blkCnt > 0U)
243 {
244 /* Initialize minVal to the next consecutive values one by one */
245 minVal = (*pSrc > 0) ? *pSrc : ((*pSrc == (q15_t) 0x8000) ? 0x7fff : -*pSrc);
246 pSrc++;
247
248 /* compare for the minimum value */
249 if (out > minVal)
250 {
251 /* Update the minimum value and it's index */
252 out = minVal;
253 outIndex = blockSize - blkCnt;
254 }
255
256 /* Decrement loop counter */
257 blkCnt--;
258 }
259
260 /* Store the minimum value and it's index into destination pointers */
261 *pResult = out;
262 *pIndex = outIndex;
263 }
264 #endif /* defined(ARM_MATH_DSP) */
265 #endif /* defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE) */
266 /**
267 @} end of AbsMin group
268 */
269