hermespy-rt

Minimalistic signal processing ray-tracer in C
git clone https://git.ea.contact/hermespy-rt
Log | Files | Refs

commit f127614a581359c9620e7a3c78188f339ad2cf0e
parent bdae618a2bfe358310f5cc00b295da7610f68947
Author: Egor Achkasov <eaachkasov@edu.hse.ru>
Date:   Wed,  2 Apr 2025 21:44:33 +0200

Fix bindings

Diffstat:
Mcompute_paths_pybind11.cpp | 132+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Minc/scene.h | 21+++++++++++++++++++++
Atest/__init__.py | 0
Mtest/test.py | 9++++++---
4 files changed, 112 insertions(+), 50 deletions(-)

diff --git a/compute_paths_pybind11.cpp b/compute_paths_pybind11.cpp @@ -7,10 +7,13 @@ #ifdef _WIN32 extern "C" { - #include "compute_paths.h" +#endif + #include "inc/compute_paths.h" + #include "inc/scene.h" + #include "inc/vec3.h" + #include "inc/ray.h" +#ifdef _WIN32 } -#else -#include "compute_paths.h" #endif namespace py = pybind11; @@ -38,7 +41,7 @@ py::array_t<std::complex<float>> make_complex_array( ); } -class PathsInfoPython { +class ChannelInfoPython { public: size_t num_paths; py::array_t<float> directions_rx; @@ -48,40 +51,52 @@ public: py::array_t<float> tau; py::array_t<float> freq_shift; - PathsInfoPython(const PathsInfo& paths, size_t num_rx, size_t num_tx) { - num_paths = paths.num_paths; + ChannelInfoPython(const ChannelInfo& chanInfo, size_t num_rx, size_t num_tx) { + num_paths = chanInfo.num_rays; auto capsule_deleter = [](void* ptr) { delete[] static_cast<float*>(ptr); }; directions_rx = py::array_t<float>( - std::vector<size_t>{num_rx, num_tx, (size_t)paths.num_paths, 3}, - paths.directions_rx, - py::capsule(paths.directions_rx, capsule_deleter) + std::vector<size_t>{num_rx, num_tx, (size_t)chanInfo.num_rays, 3}, + (float*)chanInfo.directions_rx, + py::capsule(chanInfo.directions_rx, capsule_deleter) ); directions_tx = py::array_t<float>( - std::vector<size_t>{num_rx, num_tx, (size_t)paths.num_paths, 3}, - paths.directions_tx, - py::capsule(paths.directions_tx, capsule_deleter) + std::vector<size_t>{num_rx, num_tx, (size_t)chanInfo.num_rays, 3}, + (float*)chanInfo.directions_tx, + py::capsule(chanInfo.directions_tx, capsule_deleter) ); - a_te = make_complex_array(paths.a_te_re, paths.a_te_im, num_rx, num_tx, paths.num_paths); - a_tm = make_complex_array(paths.a_tm_re, paths.a_tm_im, num_rx, num_tx, paths.num_paths); + a_te = make_complex_array( + chanInfo.a_te_re, + chanInfo.a_te_im, + num_rx, + num_tx, + chanInfo.num_rays + ); + a_tm = make_complex_array( + chanInfo.a_tm_re, + chanInfo.a_tm_im, + num_rx, + num_tx, + chanInfo.num_rays + ); tau = py::array_t<float>( - {num_rx, num_tx, (size_t)paths.num_paths}, - paths.tau, - py::capsule(paths.tau, capsule_deleter) + {num_rx, num_tx, (size_t)chanInfo.num_rays}, + chanInfo.tau, + py::capsule(chanInfo.tau, capsule_deleter) ); freq_shift = py::array_t<float>( - {num_rx, num_tx, (size_t)paths.num_paths}, - paths.freq_shift, - py::capsule(paths.freq_shift, capsule_deleter) + {num_rx, num_tx, (size_t)chanInfo.num_rays}, + chanInfo.freq_shift, + py::capsule(chanInfo.freq_shift, capsule_deleter) ); } }; -std::tuple<PathsInfoPython, PathsInfoPython> +std::tuple<ChannelInfoPython, ChannelInfoPython> compute_paths_wrapper( const std::string &mesh_filepath, py::array_t<float> rx_positions, @@ -100,11 +115,14 @@ compute_paths_wrapper( py::buffer_info rx_vel_info = rx_velocities.request(); py::buffer_info tx_vel_info = tx_velocities.request(); - // Output - PathsInfo los = { - .num_paths = 1, - .directions_rx = new float[num_rx * num_tx * 3], - .directions_tx = new float[num_rx * num_tx * 3], + // Load the scene + Scene scene = scene_load(mesh_filepath.c_str()); + + // Output channel information + ChannelInfo chanInfo_los = { + .num_rays = 1, + .directions_rx = new Vec3[num_rx * num_tx], + .directions_tx = new Vec3[num_rx * num_tx], .a_te_re = new float[num_rx * num_tx], .a_te_im = new float[num_rx * num_tx], .a_tm_re = new float[num_rx * num_tx], @@ -112,10 +130,10 @@ compute_paths_wrapper( .tau = new float[num_rx * num_tx], .freq_shift = new float[num_rx * num_tx] }; - PathsInfo scatter = { - .num_paths = (uint32_t)(num_bounces * num_paths), - .directions_rx = new float[num_rx * num_tx * num_bounces * num_paths * 3], - .directions_tx = new float[num_rx * num_tx * num_bounces * num_paths * 3], + ChannelInfo chanInfo_scat = { + .num_rays = (uint32_t)(num_bounces * num_paths), + .directions_rx = new Vec3[num_rx * num_tx * num_bounces * num_paths], + .directions_tx = new Vec3[num_rx * num_tx * num_bounces * num_paths], .a_te_re = new float[num_rx * num_tx * num_bounces * num_paths], .a_te_im = new float[num_rx * num_tx * num_bounces * num_paths], .a_tm_re = new float[num_rx * num_tx * num_bounces * num_paths], @@ -123,39 +141,59 @@ compute_paths_wrapper( .tau = new float[num_rx * num_tx * num_bounces * num_paths], .freq_shift = new float[num_rx * num_tx * num_bounces * num_paths] }; + // Output rays information + RaysInfo raysInfo_los = { + .rays = new Ray[num_rx * num_tx], + .rays_active = new uint8_t[num_rx * num_tx / 8 + 1] + }; + RaysInfo raysInfo_scat = { + .rays = new Ray[num_rx * num_tx * (num_bounces + 1) * num_paths], + .rays_active = new uint8_t[num_rx * num_tx * (num_bounces + 1) * num_paths / 8 + 1] + }; // Call the C function compute_paths( - mesh_filepath.c_str(), - (const float*)rx_pos_info.ptr, // Rx positions - (const float*)tx_pos_info.ptr, // Tx positions - (const float*)rx_vel_info.ptr, // Rx velocities - (const float*)tx_vel_info.ptr, // Tx velocities + &scene, // Scene + (Vec3*)rx_pos_info.ptr, // Rx positions + (Vec3*)tx_pos_info.ptr, // Tx positions + (Vec3*)rx_vel_info.ptr, // Rx velocities + (Vec3*)tx_vel_info.ptr, // Tx velocities carrier_frequency, // Carrier frequency in GHz (size_t)num_rx, (size_t)num_tx, (size_t)num_paths, (size_t)num_bounces, - &los, - &scatter + &chanInfo_los, // Channel info for LOS + &raysInfo_los, // Rays info for LOS + &chanInfo_scat, // Channel info for scatter + &raysInfo_scat // Rays info for scatter ); + // Free the rays info (TODO remove when RaysInfo is made optional in compute_paths) + delete[] raysInfo_los.rays; + delete[] raysInfo_los.rays_active; + delete[] raysInfo_scat.rays; + delete[] raysInfo_scat.rays_active; + + // Free the scene + free_scene(&scene); + // Wrap the results into Python objects return std::make_tuple( - PathsInfoPython(los, num_rx, num_tx), - PathsInfoPython(scatter, num_rx, num_tx) + ChannelInfoPython(chanInfo_los, num_rx, num_tx), + ChannelInfoPython(chanInfo_scat, num_rx, num_tx) ); } PYBIND11_MODULE(rt, m) { - py::class_<PathsInfoPython>(m, "PathsInfo") - .def_readonly("num_paths", &PathsInfoPython::num_paths) - .def_readonly("directions_rx", &PathsInfoPython::directions_rx) - .def_readonly("directions_tx", &PathsInfoPython::directions_tx) - .def_readonly("a_te", &PathsInfoPython::a_te) - .def_readonly("a_tm", &PathsInfoPython::a_tm) - .def_readonly("tau", &PathsInfoPython::tau) - .def_readonly("freq_shift", &PathsInfoPython::freq_shift); + py::class_<ChannelInfoPython>(m, "PathsInfo") + .def_readonly("num_paths", &ChannelInfoPython::num_paths) + .def_readonly("directions_rx", &ChannelInfoPython::directions_rx) + .def_readonly("directions_tx", &ChannelInfoPython::directions_tx) + .def_readonly("a_te", &ChannelInfoPython::a_te) + .def_readonly("a_tm", &ChannelInfoPython::a_tm) + .def_readonly("tau", &ChannelInfoPython::tau) + .def_readonly("freq_shift", &ChannelInfoPython::freq_shift); // TODO write a proper docstring m.def("compute_paths", &compute_paths_wrapper, "Compute gains and delays", diff --git a/inc/scene.h b/inc/scene.h @@ -5,6 +5,7 @@ #include "vec3.h" /* for Vec3 */ #include <stdint.h> /* for uint32_t */ +#include <stdlib.h> /* for free */ typedef struct { /* Number of vertices */ @@ -64,6 +65,26 @@ typedef struct { uint8_t s3_alpha; } Material; +/** Free the memory allocated for a mesh fields. + * + * \param mesh pointer to the mesh to free + */ +static inline void free_mesh(Mesh* mesh) { + free(mesh->vs); + free(mesh->is); + free(mesh->ns); +} +/** Deep free the scene. Frees all the meshes. + * + * \param scene pointer to the scene to free + */ +static inline void free_scene(Scene* scene) { + for (uint32_t i = 0; i < scene->num_meshes; i++) { + free_mesh(&scene->meshes[i]); + } + free(scene->meshes); +} + /** Save a scene to a HRT file. (See README for details) * * NOTE: This function does not save the normals of the triangles (Mesh.ns field). diff --git a/test/__init__.py b/test/__init__.py diff --git a/test/test.py b/test/test.py @@ -1,8 +1,11 @@ import numpy as np -from rt import compute_paths + +import sys, os +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +import rt # Define inputs -mesh_filepath = __file__[:__file__.rfind('/') + 1] + 'scenes/simple_reflector.hrt' +mesh_filepath = __file__[:__file__.rfind('/') + 1] + '../scenes/simple_reflector.hrt' rx_positions = np.array([[0., 0., .15]], dtype=np.float64) tx_positions = np.array([[0., 0., .151]], dtype=np.float64) rx_velocities = np.array([[0., 0., 0.]], dtype=np.float64) @@ -14,7 +17,7 @@ num_paths = 10000 num_bounces = 3 # Call compute_paths -los, scatter = compute_paths( +los, scatter = rt.compute_paths( mesh_filepath, rx_positions, tx_positions,