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