/ Drivers / CMSIS / DSP / Source / SupportFunctions / arm_float_to_q15.c
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   */