11#include < fmt/core.h>
2+ #include < algorithm>
23#include < cmath>
34#include < complex>
5+ #include < cstdint>
46#include < cstdlib>
57#include < iostream>
68#include < vector>
79
8- typedef std::complex <float > cmplxf;
10+ /*
11+ * These type definitions are in line with our C definitions.
12+ *
13+ * Alternativele, we could go with the NumPy scheme:
14+ * np.complex64 aka std::complex<float>
15+ * np.complex128 aka std::complex<double>
16+ * The underlying types are probably defined like Ctypes.
17+ * This is about the idea.
18+ */
19+ typedef std::complex <int8_t > ic8;
20+ typedef std::complex <int16_t > ic16;
21+ typedef std::complex <int32_t > ic32;
22+ typedef std::complex <int64_t > ic64;
23+ typedef std::complex <float > fc32;
24+ typedef std::complex <double > fc64;
925
1026#include < volk/volk.h>
1127#include < volk/volk_alloc.hh>
1228
29+ /* C++ Interface requirements
30+ *
31+ * 1. Make C++ STL types usable `std::vector`, `std::complex`.
32+ * 2. Make aligned vectors aka `volk::vector` usable.
33+ * 3. Allow call-by-pointer for GR buffer interface usage etc.
34+ *
35+ * These requirements result in at least 3 functions.
36+ * We might want to think about fancy new C++ features e.g. concepts to consolidate these.
37+ */
1338
14- void cppmultiply (volk::vector<cmplxf>& result,
15- volk::vector<cmplxf>& input0,
16- volk::vector<cmplxf>& input1)
39+ namespace volk {
40+
41+ /*
42+ * Start of wrapper for volk_32fc_s32fc_multiply_32fc
43+ */
44+ void cppscalarmultiply_pointers (fc32* result,
45+ const fc32* input0,
46+ const fc32 scalar,
47+ const unsigned int num_points)
48+ {
49+ volk_32fc_s32fc_multiply_32fc (reinterpret_cast <lv_32fc_t *>(result),
50+ reinterpret_cast <const lv_32fc_t *>(input0),
51+ lv_32fc_t { scalar.real (), scalar.imag () },
52+ num_points);
53+ }
54+
55+ void cppscalarmultiply_stl_vector (std::vector<fc32>& result,
56+ const std::vector<fc32>& input0,
57+ const fc32 scalar)
58+ {
59+ unsigned int num_points = std::min ({ result.size (), input0.size () });
60+ cppscalarmultiply_pointers (result.data (), input0.data (), scalar, num_points);
61+ }
62+
63+ void cppscalarmultiply_aligned_vector (volk::vector<fc32>& result,
64+ const volk::vector<fc32>& input0,
65+ const fc32 scalar)
66+ {
67+ unsigned int num_points = std::min ({ result.size (), input0.size () });
68+ cppscalarmultiply_pointers (result.data (), input0.data (), scalar, num_points);
69+ }
70+
71+ /*
72+ * Start of wrapper for volk_32fc_x2_multiply_32fc
73+ */
74+ void cppmultiply_pointers (fc32* result,
75+ const fc32* input0,
76+ const fc32* input1,
77+ const unsigned int num_points)
78+ {
79+ volk_32fc_x2_multiply_32fc (reinterpret_cast <lv_32fc_t *>(result),
80+ reinterpret_cast <const lv_32fc_t *>(input0),
81+ reinterpret_cast <const lv_32fc_t *>(input1),
82+ num_points);
83+ }
84+
85+ void cppmultiply_stl_vector (std::vector<fc32>& result,
86+ const std::vector<fc32>& input0,
87+ const std::vector<fc32>& input1)
88+ {
89+ unsigned int num_points = std::min ({ result.size (), input0.size (), input1.size () });
90+ cppmultiply_pointers (result.data (), input0.data (), input1.data (), num_points);
91+ }
92+
93+ void cppmultiply_aligned_vector (volk::vector<fc32>& result,
94+ const volk::vector<fc32>& input0,
95+ const volk::vector<fc32>& input1)
1796{
18- volk_32fc_x2_multiply_32fc (reinterpret_cast <lv_32fc_t *>(result.data ()),
19- reinterpret_cast <lv_32fc_t *>(input0.data ()),
20- reinterpret_cast <lv_32fc_t *>(input1.data ()),
21- input0.size ());
97+ unsigned int num_points = std::min ({ result.size (), input0.size (), input1.size () });
98+ cppmultiply_pointers (result.data (), input0.data (), input1.data (), num_points);
2299}
23100
24- void function_test (int num_points)
101+ } // namespace volk
102+
103+
104+ std::vector<fc32> fill_vector (int num_points, float step_value)
25105{
26- volk::vector<cmplxf> in0 (num_points);
27- volk::vector<cmplxf> in1 (num_points);
28- volk::vector<cmplxf> out (num_points);
106+ std::vector<fc32> vec (num_points);
29107
30108 for (unsigned int ii = 0 ; ii < num_points; ++ii) {
31- // Generate two tones
32- float real_1 = std::cos (0 .3f * (float )ii);
33- float imag_1 = std::sin (0 .3f * (float )ii);
34- in0[ii] = cmplxf (real_1, imag_1);
35- float real_2 = std::cos (0 .1f * (float )ii);
36- float imag_2 = std::sin (0 .1f * (float )ii);
37- in1[ii] = cmplxf (real_2, imag_2);
109+ float real_1 = std::cos (step_value * (float )ii);
110+ float imag_1 = std::sin (step_value * (float )ii);
111+ vec[ii] = fc32 (real_1, imag_1);
38112 }
113+ return vec;
114+ }
115+
116+ void function_test_vectors (int num_points)
117+ {
118+ std::vector<fc32> uin0 (fill_vector (num_points, 0 .3f ));
119+ volk::vector<fc32> in0 (uin0.begin (), uin0.end ());
120+ std::vector<fc32> uin1 (fill_vector (num_points, 0 .1f ));
121+ volk::vector<fc32> in1 (uin1.begin (), uin1.end ());
122+ std::vector<fc32> uout (num_points);
123+ volk::vector<fc32> out (num_points);
124+
125+ volk::cppmultiply_aligned_vector (out, in0, in1);
39126
40- cppmultiply (out, in0, in1);
127+ volk::cppmultiply_stl_vector (uout, uin0, uin1);
128+ volk::cppmultiply_pointers (uout.data (), in0.data (), in1.data (), num_points);
41129
42130 for (int ii = 0 ; ii < num_points; ++ii) {
43- cmplxf v0 = in0[ii];
44- cmplxf v1 = in1[ii];
45- cmplxf o = out[ii];
131+ fc32 v0 = in0[ii];
132+ fc32 v1 = in1[ii];
133+ fc32 o = out[ii];
46134
47135 fmt::print (
48136 " in0=({:+.1f}{:+.1f}j), in1=({:+.1f}{:+.1f}j), out=({:+.1f}{:+.1f}j)\n " ,
@@ -55,10 +143,40 @@ void function_test(int num_points)
55143 }
56144}
57145
146+ void function_test_with_scalar (int num_points)
147+ {
148+ std::vector<fc32> uin0 (fill_vector (num_points, 0 .3f ));
149+ volk::vector<fc32> in0 (uin0.begin (), uin0.end ());
150+ fc32 scalar{ 0 .5f , 4 .3f };
151+ std::vector<fc32> uout (num_points);
152+ volk::vector<fc32> out (num_points);
153+
154+ volk::cppscalarmultiply_aligned_vector (out, in0, scalar);
155+
156+ volk::cppscalarmultiply_stl_vector (uout, uin0, scalar);
157+ volk::cppscalarmultiply_pointers (uout.data (), in0.data (), scalar, num_points);
158+
159+ fmt::print (" scalar=({:+.1f}{:+.1f}j)\n " , std::real (scalar), std::imag (scalar));
160+ for (int ii = 0 ; ii < num_points; ++ii) {
161+ fc32 v0 = in0[ii];
162+ fc32 o = out[ii];
163+
164+ fmt::print (" in0=({:+.1f}{:+.1f}j), out=({:+.1f}{:+.1f}j)\n " ,
165+ std::real (v0),
166+ std::imag (v0),
167+ std::real (o),
168+ std::imag (o));
169+ }
170+ }
58171
59172int main (int argc, char * argv[])
60173{
61- function_test (32 );
174+ fmt::print (" Vector function test\n " );
175+ function_test_vectors (16 );
176+
177+ fmt::print (" Scalar function test\n " );
178+ function_test_with_scalar (16 );
179+
62180 lv_32fc_t fc_cpl[4 ];
63181 fmt::print (" float={}, complex float={}, complex float array[4]={}\n " ,
64182 sizeof (float ),
0 commit comments