diff --git a/main.cc b/main.cc index 83117827b..10c9389f5 100644 --- a/main.cc +++ b/main.cc @@ -1,48 +1,136 @@ #include +#include #include #include +#include #include #include #include -typedef std::complex cmplxf; +/* + * These type definitions are in line with our C definitions. + * + * Alternativele, we could go with the NumPy scheme: + * np.complex64 aka std::complex + * np.complex128 aka std::complex + * The underlying types are probably defined like Ctypes. + * This is about the idea. + */ +typedef std::complex ic8; +typedef std::complex ic16; +typedef std::complex ic32; +typedef std::complex ic64; +typedef std::complex fc32; +typedef std::complex fc64; #include #include +/* C++ Interface requirements + * + * 1. Make C++ STL types usable `std::vector`, `std::complex`. + * 2. Make aligned vectors aka `volk::vector` usable. + * 3. Allow call-by-pointer for GR buffer interface usage etc. + * + * These requirements result in at least 3 functions. + * We might want to think about fancy new C++ features e.g. concepts to consolidate these. + */ -void cppmultiply(volk::vector& result, - volk::vector& input0, - volk::vector& input1) +namespace volk { + +/* + * Start of wrapper for volk_32fc_s32fc_multiply_32fc + */ +void cppscalarmultiply_pointers(fc32* result, + const fc32* input0, + const fc32 scalar, + const unsigned int num_points) +{ + volk_32fc_s32fc_multiply_32fc(reinterpret_cast(result), + reinterpret_cast(input0), + lv_32fc_t{ scalar.real(), scalar.imag() }, + num_points); +} + +void cppscalarmultiply_stl_vector(std::vector& result, + const std::vector& input0, + const fc32 scalar) +{ + unsigned int num_points = std::min({ result.size(), input0.size() }); + cppscalarmultiply_pointers(result.data(), input0.data(), scalar, num_points); +} + +void cppscalarmultiply_aligned_vector(volk::vector& result, + const volk::vector& input0, + const fc32 scalar) +{ + unsigned int num_points = std::min({ result.size(), input0.size() }); + cppscalarmultiply_pointers(result.data(), input0.data(), scalar, num_points); +} + +/* + * Start of wrapper for volk_32fc_x2_multiply_32fc + */ +void cppmultiply_pointers(fc32* result, + const fc32* input0, + const fc32* input1, + const unsigned int num_points) +{ + volk_32fc_x2_multiply_32fc(reinterpret_cast(result), + reinterpret_cast(input0), + reinterpret_cast(input1), + num_points); +} + +void cppmultiply_stl_vector(std::vector& result, + const std::vector& input0, + const std::vector& input1) +{ + unsigned int num_points = std::min({ result.size(), input0.size(), input1.size() }); + cppmultiply_pointers(result.data(), input0.data(), input1.data(), num_points); +} + +void cppmultiply_aligned_vector(volk::vector& result, + const volk::vector& input0, + const volk::vector& input1) { - volk_32fc_x2_multiply_32fc(reinterpret_cast(result.data()), - reinterpret_cast(input0.data()), - reinterpret_cast(input1.data()), - input0.size()); + unsigned int num_points = std::min({ result.size(), input0.size(), input1.size() }); + cppmultiply_pointers(result.data(), input0.data(), input1.data(), num_points); } -void function_test(int num_points) +} // namespace volk + + +std::vector fill_vector(int num_points, float step_value) { - volk::vector in0(num_points); - volk::vector in1(num_points); - volk::vector out(num_points); + std::vector vec(num_points); for (unsigned int ii = 0; ii < num_points; ++ii) { - // Generate two tones - float real_1 = std::cos(0.3f * (float)ii); - float imag_1 = std::sin(0.3f * (float)ii); - in0[ii] = cmplxf(real_1, imag_1); - float real_2 = std::cos(0.1f * (float)ii); - float imag_2 = std::sin(0.1f * (float)ii); - in1[ii] = cmplxf(real_2, imag_2); + float real_1 = std::cos(step_value * (float)ii); + float imag_1 = std::sin(step_value * (float)ii); + vec[ii] = fc32(real_1, imag_1); } + return vec; +} + +void function_test_vectors(int num_points) +{ + std::vector uin0(fill_vector(num_points, 0.3f)); + volk::vector in0(uin0.begin(), uin0.end()); + std::vector uin1(fill_vector(num_points, 0.1f)); + volk::vector in1(uin1.begin(), uin1.end()); + std::vector uout(num_points); + volk::vector out(num_points); + + volk::cppmultiply_aligned_vector(out, in0, in1); - cppmultiply(out, in0, in1); + volk::cppmultiply_stl_vector(uout, uin0, uin1); + volk::cppmultiply_pointers(uout.data(), in0.data(), in1.data(), num_points); for (int ii = 0; ii < num_points; ++ii) { - cmplxf v0 = in0[ii]; - cmplxf v1 = in1[ii]; - cmplxf o = out[ii]; + fc32 v0 = in0[ii]; + fc32 v1 = in1[ii]; + fc32 o = out[ii]; fmt::print( "in0=({:+.1f}{:+.1f}j), in1=({:+.1f}{:+.1f}j), out=({:+.1f}{:+.1f}j)\n", @@ -55,10 +143,40 @@ void function_test(int num_points) } } +void function_test_with_scalar(int num_points) +{ + std::vector uin0(fill_vector(num_points, 0.3f)); + volk::vector in0(uin0.begin(), uin0.end()); + fc32 scalar{ 0.5f, 4.3f }; + std::vector uout(num_points); + volk::vector out(num_points); + + volk::cppscalarmultiply_aligned_vector(out, in0, scalar); + + volk::cppscalarmultiply_stl_vector(uout, uin0, scalar); + volk::cppscalarmultiply_pointers(uout.data(), in0.data(), scalar, num_points); + + fmt::print("scalar=({:+.1f}{:+.1f}j)\n", std::real(scalar), std::imag(scalar)); + for (int ii = 0; ii < num_points; ++ii) { + fc32 v0 = in0[ii]; + fc32 o = out[ii]; + + fmt::print("in0=({:+.1f}{:+.1f}j), out=({:+.1f}{:+.1f}j)\n", + std::real(v0), + std::imag(v0), + std::real(o), + std::imag(o)); + } +} int main(int argc, char* argv[]) { - function_test(32); + fmt::print("Vector function test\n"); + function_test_vectors(16); + + fmt::print("Scalar function test\n"); + function_test_with_scalar(16); + lv_32fc_t fc_cpl[4]; fmt::print("float={}, complex float={}, complex float array[4]={}\n", sizeof(float),