GNU Radio Manual and C++ API Reference  3.7.7
The Free & Open Software Radio Ecosystem
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
volk_32f_x2_s32f_interleave_16ic.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2012, 2014 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /*!
24  * \page volk_32f_x2_s32f_interleave_16ic
25  *
26  * \b Overview
27  *
28  * Takes input vector iBuffer as the real (inphase) part and input
29  * vector qBuffer as the imag (quadrature) part and combines them into
30  * a complex output vector. The output is scaled by the input scalar
31  * value and convert to a 16-bit short comlex number.
32  *
33  * <b>Dispatcher Prototype</b>
34  * \code
35  * void volk_32f_x2_s32f_interleave_16ic(lv_16sc_t* complexVector, const float* iBuffer, const float* qBuffer, const float scalar, unsigned int num_points)
36  * \endcode
37  *
38  * \b Inputs
39  * \li iBuffer: Input vector of samples for the real part.
40  * \li qBuffer: Input vector of samples for the imaginary part.
41  * \;i scalar: The scalar value used to scale the values before converting to shorts.
42  * \li num_points: The number of values in both input vectors.
43  *
44  * \b Outputs
45  * \li complexVector: The output vector of complex numbers.
46  *
47  * \b Example
48  * Generate points around the unit circle and convert to complex integers.
49  * \code
50  * int N = 10;
51  * unsigned int alignment = volk_get_alignment();
52  * float* imag = (float*)volk_malloc(sizeof(float)*N, alignment);
53  * float* real = (float*)volk_malloc(sizeof(float)*N, alignment);
54  * lv_16sc_t* out = (lv_16sc_t*)volk_malloc(sizeof(lv_16sc_t)*N, alignment);
55  *
56  * for(unsigned int ii = 0; ii < N; ++ii){
57  * real[ii] = 2.f * ((float)ii / (float)N) - 1.f;
58  * imag[ii] = std::sqrt(1.f - real[ii] * real[ii]);
59  * }
60  * // Normalize by smallest delta (0.02 in this example)
61  * float scale = 50.f;
62  *
63  * volk_32f_x2_s32f_interleave_16ic(out, imag, real, scale, N);
64  *
65  * for(unsigned int ii = 0; ii < N; ++ii){
66  * printf("out[%u] = %i + %ij\n", ii, std::real(out[ii]), std::imag(out[ii]));
67  * }
68  *
69  * volk_free(imag);
70  * volk_free(real);
71  * volk_free(out);
72  * \endcode
73  */
74 
75 #ifndef INCLUDED_volk_32f_x2_s32f_interleave_16ic_a_H
76 #define INCLUDED_volk_32f_x2_s32f_interleave_16ic_a_H
77 
78 #include <volk/volk_common.h>
79 #include <inttypes.h>
80 #include <stdio.h>
81 
82 #ifdef LV_HAVE_SSE2
83 #include <emmintrin.h>
84 
85 static inline void
86 volk_32f_x2_s32f_interleave_16ic_a_sse2(lv_16sc_t* complexVector, const float* iBuffer,
87  const float* qBuffer, const float scalar, unsigned int num_points)
88 {
89  unsigned int number = 0;
90  const float* iBufferPtr = iBuffer;
91  const float* qBufferPtr = qBuffer;
92 
93  __m128 vScalar = _mm_set_ps1(scalar);
94 
95  const unsigned int quarterPoints = num_points / 4;
96 
97  __m128 iValue, qValue, cplxValue1, cplxValue2;
98  __m128i intValue1, intValue2;
99 
100  int16_t* complexVectorPtr = (int16_t*)complexVector;
101 
102  for(;number < quarterPoints; number++){
103  iValue = _mm_load_ps(iBufferPtr);
104  qValue = _mm_load_ps(qBufferPtr);
105 
106  // Interleaves the lower two values in the i and q variables into one buffer
107  cplxValue1 = _mm_unpacklo_ps(iValue, qValue);
108  cplxValue1 = _mm_mul_ps(cplxValue1, vScalar);
109 
110  // Interleaves the upper two values in the i and q variables into one buffer
111  cplxValue2 = _mm_unpackhi_ps(iValue, qValue);
112  cplxValue2 = _mm_mul_ps(cplxValue2, vScalar);
113 
114  intValue1 = _mm_cvtps_epi32(cplxValue1);
115  intValue2 = _mm_cvtps_epi32(cplxValue2);
116 
117  intValue1 = _mm_packs_epi32(intValue1, intValue2);
118 
119  _mm_store_si128((__m128i*)complexVectorPtr, intValue1);
120  complexVectorPtr += 8;
121 
122  iBufferPtr += 4;
123  qBufferPtr += 4;
124  }
125 
126  number = quarterPoints * 4;
127  complexVectorPtr = (int16_t*)(&complexVector[number]);
128  for(; number < num_points; number++){
129  *complexVectorPtr++ = (int16_t)(*iBufferPtr++ * scalar);
130  *complexVectorPtr++ = (int16_t)(*qBufferPtr++ * scalar);
131  }
132 }
133 #endif /* LV_HAVE_SSE2 */
134 
135 
136 #ifdef LV_HAVE_SSE
137 #include <xmmintrin.h>
138 
139 static inline void
140 volk_32f_x2_s32f_interleave_16ic_a_sse(lv_16sc_t* complexVector, const float* iBuffer,
141  const float* qBuffer, const float scalar, unsigned int num_points)
142 {
143  unsigned int number = 0;
144  const float* iBufferPtr = iBuffer;
145  const float* qBufferPtr = qBuffer;
146 
147  __m128 vScalar = _mm_set_ps1(scalar);
148 
149  const unsigned int quarterPoints = num_points / 4;
150 
151  __m128 iValue, qValue, cplxValue;
152 
153  int16_t* complexVectorPtr = (int16_t*)complexVector;
154 
155  __VOLK_ATTR_ALIGNED(16) float floatBuffer[4];
156 
157  for(;number < quarterPoints; number++){
158  iValue = _mm_load_ps(iBufferPtr);
159  qValue = _mm_load_ps(qBufferPtr);
160 
161  // Interleaves the lower two values in the i and q variables into one buffer
162  cplxValue = _mm_unpacklo_ps(iValue, qValue);
163  cplxValue = _mm_mul_ps(cplxValue, vScalar);
164 
165  _mm_store_ps(floatBuffer, cplxValue);
166 
167  *complexVectorPtr++ = (int16_t)(floatBuffer[0]);
168  *complexVectorPtr++ = (int16_t)(floatBuffer[1]);
169  *complexVectorPtr++ = (int16_t)(floatBuffer[2]);
170  *complexVectorPtr++ = (int16_t)(floatBuffer[3]);
171 
172  // Interleaves the upper two values in the i and q variables into one buffer
173  cplxValue = _mm_unpackhi_ps(iValue, qValue);
174  cplxValue = _mm_mul_ps(cplxValue, vScalar);
175 
176  _mm_store_ps(floatBuffer, cplxValue);
177 
178  *complexVectorPtr++ = (int16_t)(floatBuffer[0]);
179  *complexVectorPtr++ = (int16_t)(floatBuffer[1]);
180  *complexVectorPtr++ = (int16_t)(floatBuffer[2]);
181  *complexVectorPtr++ = (int16_t)(floatBuffer[3]);
182 
183  iBufferPtr += 4;
184  qBufferPtr += 4;
185  }
186 
187  number = quarterPoints * 4;
188  complexVectorPtr = (int16_t*)(&complexVector[number]);
189  for(; number < num_points; number++){
190  *complexVectorPtr++ = (int16_t)(*iBufferPtr++ * scalar);
191  *complexVectorPtr++ = (int16_t)(*qBufferPtr++ * scalar);
192  }
193 }
194 #endif /* LV_HAVE_SSE */
195 
196 
197 #ifdef LV_HAVE_GENERIC
198 
199 static inline void
200 volk_32f_x2_s32f_interleave_16ic_generic(lv_16sc_t* complexVector, const float* iBuffer,
201  const float* qBuffer, const float scalar, unsigned int num_points)
202 {
203  int16_t* complexVectorPtr = (int16_t*)complexVector;
204  const float* iBufferPtr = iBuffer;
205  const float* qBufferPtr = qBuffer;
206  unsigned int number = 0;
207 
208  for(number = 0; number < num_points; number++){
209  *complexVectorPtr++ = (int16_t)(*iBufferPtr++ * scalar);
210  *complexVectorPtr++ = (int16_t)(*qBufferPtr++ * scalar);
211  }
212 }
213 #endif /* LV_HAVE_GENERIC */
214 
215 
216 #endif /* INCLUDED_volk_32f_x2_s32f_interleave_16ic_a_H */
short complex lv_16sc_t
Definition: volk_complex.h:53
signed short int16_t
Definition: stdint.h:76
#define __VOLK_ATTR_ALIGNED(x)
Definition: volk_common.h:27