arm_float_to_q15.c
1 /* ---------------------------------------------------------------------- 2 * Project: CMSIS DSP Library 3 * Title: arm_float_to_q15.c 4 * Description: Converts the elements of the floating-point vector to 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/support_functions.h" 30 31 /** 32 @ingroup groupSupport 33 */ 34 35 /** 36 @addtogroup float_to_x 37 @{ 38 */ 39 40 /** 41 @brief Converts the elements of the floating-point vector to Q15 vector. 42 @param[in] pSrc points to the floating-point input vector 43 @param[out] pDst points to the Q15 output vector 44 @param[in] blockSize number of samples in each vector 45 @return none 46 47 @par Details 48 The equation used for the conversion process is: 49 <pre> 50 pDst[n] = (q15_t)(pSrc[n] * 32768); 0 <= n < blockSize. 51 </pre> 52 53 @par Scaling and Overflow Behavior 54 The function uses saturating arithmetic. 55 Results outside of the allowable Q15 range [0x8000 0x7FFF] are saturated. 56 57 @note 58 In order to apply rounding, the library should be rebuilt with the ROUNDING macro 59 defined in the preprocessor section of project options. 60 */ 61 62 #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) 63 void arm_float_to_q15( 64 const float32_t * pSrc, 65 q15_t * pDst, 66 uint32_t blockSize) 67 { 68 uint32_t blkCnt; 69 float32_t maxQ = (float32_t) Q15_MAX; 70 f32x4x2_t tmp; 71 q15x8_t vecDst; 72 #ifdef ARM_MATH_ROUNDING 73 float32_t in; 74 #endif 75 76 77 blkCnt = blockSize >> 3; 78 while (blkCnt > 0U) 79 { 80 /* C = A * 32768 */ 81 /* convert from float to q15 and then store the results in the destination buffer */ 82 tmp = vld2q(pSrc); 83 84 tmp.val[0] = vmulq(tmp.val[0], maxQ); 85 tmp.val[1] = vmulq(tmp.val[1], maxQ); 86 87 vecDst = vqmovnbq(vecDst, vcvtaq_s32_f32(tmp.val[0])); 88 vecDst = vqmovntq(vecDst, vcvtaq_s32_f32(tmp.val[1])); 89 vst1q(pDst, vecDst); 90 /* 91 * Decrement the blockSize loop counter 92 */ 93 blkCnt--; 94 pDst += 8; 95 pSrc += 8; 96 } 97 98 blkCnt = blockSize & 7; 99 while (blkCnt > 0U) 100 { 101 /* C = A * 32768 */ 102 103 /* convert from float to Q15 and store result in destination buffer */ 104 #ifdef ARM_MATH_ROUNDING 105 106 in = (*pSrc++ * 32768.0f); 107 in += in > 0.0f ? 0.5f : -0.5f; 108 *pDst++ = (q15_t) (__SSAT((q31_t) (in), 16)); 109 110 #else 111 112 /* C = A * 32768 */ 113 /* Convert from float to q15 and then store the results in the destination buffer */ 114 *pDst++ = (q15_t) __SSAT((q31_t) (*pSrc++ * 32768.0f), 16); 115 116 #endif /* #ifdef ARM_MATH_ROUNDING */ 117 118 /* Decrement loop counter */ 119 blkCnt--; 120 } 121 } 122 123 #else 124 #if defined(ARM_MATH_NEON_EXPERIMENTAL) 125 void arm_float_to_q15( 126 const float32_t * pSrc, 127 q15_t * pDst, 128 uint32_t blockSize) 129 { 130 const float32_t *pIn = pSrc; /* Src pointer */ 131 uint32_t blkCnt; /* loop counter */ 132 133 float32x4_t inV; 134 #ifdef ARM_MATH_ROUNDING 135 float32x4_t zeroV = vdupq_n_f32(0.0f); 136 float32x4_t pHalf = vdupq_n_f32(0.5f / 32768.0f); 137 float32x4_t mHalf = vdupq_n_f32(-0.5f / 32768.0f); 138 float32x4_t r; 139 uint32x4_t cmp; 140 float32_t in; 141 #endif 142 143 int32x4_t cvt; 144 int16x4_t outV; 145 146 blkCnt = blockSize >> 2U; 147 148 /* Compute 4 outputs at a time. 149 ** a second loop below computes the remaining 1 to 3 samples. */ 150 while (blkCnt > 0U) 151 { 152 153 #ifdef ARM_MATH_ROUNDING 154 /* C = A * 32768 */ 155 /* Convert from float to q15 and then store the results in the destination buffer */ 156 inV = vld1q_f32(pIn); 157 cmp = vcgtq_f32(inV,zeroV); 158 r = vbslq_f32(cmp,pHalf,mHalf); 159 inV = vaddq_f32(inV, r); 160 161 pIn += 4; 162 163 cvt = vcvtq_n_s32_f32(inV,15); 164 outV = vqmovn_s32(cvt); 165 166 vst1_s16(pDst, outV); 167 pDst += 4; 168 169 #else 170 171 /* C = A * 32768 */ 172 /* Convert from float to q15 and then store the results in the destination buffer */ 173 inV = vld1q_f32(pIn); 174 175 cvt = vcvtq_n_s32_f32(inV,15); 176 outV = vqmovn_s32(cvt); 177 178 vst1_s16(pDst, outV); 179 pDst += 4; 180 pIn += 4; 181 182 #endif /* #ifdef ARM_MATH_ROUNDING */ 183 184 /* Decrement the loop counter */ 185 blkCnt--; 186 } 187 188 /* If the blockSize is not a multiple of 4, compute any remaining output samples here. 189 ** No loop unrolling is used. */ 190 blkCnt = blockSize & 3; 191 192 while (blkCnt > 0U) 193 { 194 195 #ifdef ARM_MATH_ROUNDING 196 /* C = A * 32768 */ 197 /* Convert from float to q15 and then store the results in the destination buffer */ 198 in = *pIn++; 199 in = (in * 32768.0f); 200 in += in > 0.0f ? 0.5f : -0.5f; 201 *pDst++ = (q15_t) (__SSAT((q31_t) (in), 16)); 202 203 #else 204 205 /* C = A * 32768 */ 206 /* Convert from float to q15 and then store the results in the destination buffer */ 207 *pDst++ = (q15_t) __SSAT((q31_t) (*pIn++ * 32768.0f), 16); 208 209 #endif /* #ifdef ARM_MATH_ROUNDING */ 210 211 /* Decrement the loop counter */ 212 blkCnt--; 213 } 214 } 215 #else 216 void arm_float_to_q15( 217 const float32_t * pSrc, 218 q15_t * pDst, 219 uint32_t blockSize) 220 { 221 uint32_t blkCnt; /* Loop counter */ 222 const float32_t *pIn = pSrc; /* Source pointer */ 223 224 #ifdef ARM_MATH_ROUNDING 225 float32_t in; 226 #endif /* #ifdef ARM_MATH_ROUNDING */ 227 228 #if defined (ARM_MATH_LOOPUNROLL) 229 230 /* Loop unrolling: Compute 4 outputs at a time */ 231 blkCnt = blockSize >> 2U; 232 233 while (blkCnt > 0U) 234 { 235 /* C = A * 32768 */ 236 237 /* convert from float to Q15 and store result in destination buffer */ 238 #ifdef ARM_MATH_ROUNDING 239 240 in = (*pIn++ * 32768.0f); 241 in += in > 0.0f ? 0.5f : -0.5f; 242 *pDst++ = (q15_t) (__SSAT((q31_t) (in), 16)); 243 244 in = (*pIn++ * 32768.0f); 245 in += in > 0.0f ? 0.5f : -0.5f; 246 *pDst++ = (q15_t) (__SSAT((q31_t) (in), 16)); 247 248 in = (*pIn++ * 32768.0f); 249 in += in > 0.0f ? 0.5f : -0.5f; 250 *pDst++ = (q15_t) (__SSAT((q31_t) (in), 16)); 251 252 in = (*pIn++ * 32768.0f); 253 in += in > 0.0f ? 0.5f : -0.5f; 254 *pDst++ = (q15_t) (__SSAT((q31_t) (in), 16)); 255 256 #else 257 258 *pDst++ = (q15_t) __SSAT((q31_t) (*pIn++ * 32768.0f), 16); 259 *pDst++ = (q15_t) __SSAT((q31_t) (*pIn++ * 32768.0f), 16); 260 *pDst++ = (q15_t) __SSAT((q31_t) (*pIn++ * 32768.0f), 16); 261 *pDst++ = (q15_t) __SSAT((q31_t) (*pIn++ * 32768.0f), 16); 262 263 #endif /* #ifdef ARM_MATH_ROUNDING */ 264 265 /* Decrement loop counter */ 266 blkCnt--; 267 } 268 269 /* Loop unrolling: Compute remaining outputs */ 270 blkCnt = blockSize % 0x4U; 271 272 #else 273 274 /* Initialize blkCnt with number of samples */ 275 blkCnt = blockSize; 276 277 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */ 278 279 while (blkCnt > 0U) 280 { 281 /* C = A * 32768 */ 282 283 /* convert from float to Q15 and store result in destination buffer */ 284 #ifdef ARM_MATH_ROUNDING 285 286 in = (*pIn++ * 32768.0f); 287 in += in > 0.0f ? 0.5f : -0.5f; 288 *pDst++ = (q15_t) (__SSAT((q31_t) (in), 16)); 289 290 #else 291 292 /* C = A * 32768 */ 293 /* Convert from float to q15 and then store the results in the destination buffer */ 294 *pDst++ = (q15_t) __SSAT((q31_t) (*pIn++ * 32768.0f), 16); 295 296 #endif /* #ifdef ARM_MATH_ROUNDING */ 297 298 /* Decrement loop counter */ 299 blkCnt--; 300 } 301 302 } 303 #endif /* #if defined(ARM_MATH_NEON) */ 304 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */ 305 306 /** 307 @} end of float_to_x group 308 */