arm_float_to_q31.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /* ----------------------------------------------------------------------
  2. * Project: CMSIS DSP Library
  3. * Title: arm_float_to_q31.c
  4. * Description: Converts the elements of the floating-point vector to Q31 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. #include "dsp/support_functions.h"
  29. /**
  30. @ingroup groupSupport
  31. */
  32. /**
  33. * @defgroup float_to_x Convert 32-bit floating point value
  34. */
  35. /**
  36. @addtogroup float_to_x
  37. @{
  38. */
  39. /**
  40. @brief Converts the elements of the floating-point vector to Q31 vector.
  41. @param[in] pSrc points to the floating-point input vector
  42. @param[out] pDst points to the Q31 output vector
  43. @param[in] blockSize number of samples in each vector
  44. @par Details
  45. The equation used for the conversion process is:
  46. <pre>
  47. pDst[n] = (q31_t)(pSrc[n] * 2147483648); 0 <= n < blockSize.
  48. </pre>
  49. @par Scaling and Overflow Behavior
  50. The function uses saturating arithmetic.
  51. Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] are saturated.
  52. @note
  53. In order to apply rounding, the library should be rebuilt with the ROUNDING macro
  54. defined in the preprocessor section of project options.
  55. @note If the input float values are very big (2**32) then the function
  56. won't be able to saturate to the right values.
  57. If you expect very big float values in the input array then you
  58. should force those values to +1 or -1 before calling this function.
  59. For reasonable float values (< 2**32), the function will saturate correctly.
  60. */
  61. #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
  62. void arm_float_to_q31(
  63. const float32_t * pSrc,
  64. q31_t * pDst,
  65. uint32_t blockSize)
  66. {
  67. uint32_t blkCnt;
  68. float32_t maxQ = (float32_t) Q31_MAX;
  69. f32x4_t vecDst;
  70. #ifdef ARM_MATH_ROUNDING
  71. float32_t in;
  72. #endif
  73. blkCnt = blockSize >> 2U;
  74. /* Compute 4 outputs at a time. */
  75. while (blkCnt > 0U)
  76. {
  77. vecDst = vldrwq_f32(pSrc);
  78. /* C = A * 2147483648 */
  79. /* convert from float to Q31 and then store the results in the destination buffer */
  80. vecDst = vmulq(vecDst, maxQ);
  81. vstrwq_s32(pDst, vcvtaq_s32_f32(vecDst));
  82. /*
  83. * Decrement the blockSize loop counter
  84. * Advance vector source and destination pointers
  85. */
  86. pSrc += 4;
  87. pDst += 4;
  88. blkCnt --;
  89. }
  90. blkCnt = blockSize & 3;
  91. while (blkCnt > 0U)
  92. {
  93. /* C = A * 2147483648 */
  94. /* convert from float to Q31 and store result in destination buffer */
  95. #ifdef ARM_MATH_ROUNDING
  96. in = (*pSrc++ * 2147483648.0f);
  97. in += in > 0.0f ? 0.5f : -0.5f;
  98. *pDst++ = clip_q63_to_q31((q63_t) (in));
  99. #else
  100. /* C = A * 2147483648 */
  101. /* Convert from float to Q31 and then store the results in the destination buffer */
  102. *pDst++ = clip_q63_to_q31((q63_t) (*pSrc++ * 2147483648.0f));
  103. #endif /* #ifdef ARM_MATH_ROUNDING */
  104. /* Decrement loop counter */
  105. blkCnt--;
  106. }
  107. }
  108. #else
  109. #if defined(ARM_MATH_NEON)
  110. void arm_float_to_q31(
  111. const float32_t * pSrc,
  112. q31_t * pDst,
  113. uint32_t blockSize)
  114. {
  115. const float32_t *pIn = pSrc; /* Src pointer */
  116. uint32_t blkCnt; /* loop counter */
  117. float32x4_t inV;
  118. #ifdef ARM_MATH_ROUNDING
  119. float32_t in;
  120. float32x4_t zeroV = vdupq_n_f32(0.0f);
  121. float32x4_t pHalf = vdupq_n_f32(0.5f / 2147483648.0f);
  122. float32x4_t mHalf = vdupq_n_f32(-0.5f / 2147483648.0f);
  123. float32x4_t r;
  124. uint32x4_t cmp;
  125. #endif
  126. int32x4_t outV;
  127. blkCnt = blockSize >> 2U;
  128. /* Compute 4 outputs at a time.
  129. ** a second loop below computes the remaining 1 to 3 samples. */
  130. while (blkCnt > 0U)
  131. {
  132. #ifdef ARM_MATH_ROUNDING
  133. /* C = A * 32768 */
  134. /* Convert from float to Q31 and then store the results in the destination buffer */
  135. inV = vld1q_f32(pIn);
  136. cmp = vcgtq_f32(inV,zeroV);
  137. r = vbslq_f32(cmp,pHalf,mHalf);
  138. inV = vaddq_f32(inV, r);
  139. pIn += 4;
  140. outV = vcvtq_n_s32_f32(inV,31);
  141. vst1q_s32(pDst, outV);
  142. pDst += 4;
  143. #else
  144. /* C = A * 2147483648 */
  145. /* Convert from float to Q31 and then store the results in the destination buffer */
  146. inV = vld1q_f32(pIn);
  147. outV = vcvtq_n_s32_f32(inV,31);
  148. vst1q_s32(pDst, outV);
  149. pDst += 4;
  150. pIn += 4;
  151. #endif /* #ifdef ARM_MATH_ROUNDING */
  152. /* Decrement the loop counter */
  153. blkCnt--;
  154. }
  155. /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
  156. ** No loop unrolling is used. */
  157. blkCnt = blockSize & 3;
  158. while (blkCnt > 0U)
  159. {
  160. #ifdef ARM_MATH_ROUNDING
  161. /* C = A * 2147483648 */
  162. /* Convert from float to Q31 and then store the results in the destination buffer */
  163. in = *pIn++;
  164. in = (in * 2147483648.0f);
  165. in += in > 0.0f ? 0.5f : -0.5f;
  166. *pDst++ = clip_q63_to_q31((q63_t) (in));
  167. #else
  168. /* C = A * 2147483648 */
  169. /* Convert from float to Q31 and then store the results in the destination buffer */
  170. *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
  171. #endif /* #ifdef ARM_MATH_ROUNDING */
  172. /* Decrement the loop counter */
  173. blkCnt--;
  174. }
  175. }
  176. #else
  177. void arm_float_to_q31(
  178. const float32_t * pSrc,
  179. q31_t * pDst,
  180. uint32_t blockSize)
  181. {
  182. uint32_t blkCnt; /* Loop counter */
  183. const float32_t *pIn = pSrc; /* Source pointer */
  184. #ifdef ARM_MATH_ROUNDING
  185. float32_t in;
  186. #endif /* #ifdef ARM_MATH_ROUNDING */
  187. #if defined (ARM_MATH_LOOPUNROLL)
  188. /* Loop unrolling: Compute 4 outputs at a time */
  189. blkCnt = blockSize >> 2U;
  190. while (blkCnt > 0U)
  191. {
  192. /* C = A * 2147483648 */
  193. /* convert from float to Q31 and store result in destination buffer */
  194. #ifdef ARM_MATH_ROUNDING
  195. in = (*pIn++ * 2147483648.0f);
  196. in += in > 0.0f ? 0.5f : -0.5f;
  197. *pDst++ = clip_q63_to_q31((q63_t) (in));
  198. in = (*pIn++ * 2147483648.0f);
  199. in += in > 0.0f ? 0.5f : -0.5f;
  200. *pDst++ = clip_q63_to_q31((q63_t) (in));
  201. in = (*pIn++ * 2147483648.0f);
  202. in += in > 0.0f ? 0.5f : -0.5f;
  203. *pDst++ = clip_q63_to_q31((q63_t) (in));
  204. in = (*pIn++ * 2147483648.0f);
  205. in += in > 0.0f ? 0.5f : -0.5f;
  206. *pDst++ = clip_q63_to_q31((q63_t) (in));
  207. #else
  208. /* C = A * 2147483648 */
  209. /* Convert from float to Q31 and then store the results in the destination buffer */
  210. *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
  211. *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
  212. *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
  213. *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
  214. #endif /* #ifdef ARM_MATH_ROUNDING */
  215. /* Decrement loop counter */
  216. blkCnt--;
  217. }
  218. /* Loop unrolling: Compute remaining outputs */
  219. blkCnt = blockSize % 0x4U;
  220. #else
  221. /* Initialize blkCnt with number of samples */
  222. blkCnt = blockSize;
  223. #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
  224. while (blkCnt > 0U)
  225. {
  226. /* C = A * 2147483648 */
  227. /* convert from float to Q31 and store result in destination buffer */
  228. #ifdef ARM_MATH_ROUNDING
  229. in = (*pIn++ * 2147483648.0f);
  230. in += in > 0.0f ? 0.5f : -0.5f;
  231. *pDst++ = clip_q63_to_q31((q63_t) (in));
  232. #else
  233. /* C = A * 2147483648 */
  234. /* Convert from float to Q31 and then store the results in the destination buffer */
  235. *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
  236. #endif /* #ifdef ARM_MATH_ROUNDING */
  237. /* Decrement loop counter */
  238. blkCnt--;
  239. }
  240. }
  241. #endif /* #if defined(ARM_MATH_NEON) */
  242. #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
  243. /**
  244. @} end of float_to_x group
  245. */